mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-01-26 15:58:07 +00:00
Cleanup scrollToTop
This commit is contained in:
parent
7c2e8d6e80
commit
1ffb4ab901
12 changed files with 79 additions and 139 deletions
|
@ -19,9 +19,9 @@ extension View {
|
||||||
navigationDestination(for: RouterDestination.self) { destination in
|
navigationDestination(for: RouterDestination.self) { destination in
|
||||||
switch destination {
|
switch destination {
|
||||||
case let .accountDetail(id):
|
case let .accountDetail(id):
|
||||||
AccountDetailView(accountId: id, scrollToTopSignal: .constant(0))
|
AccountDetailView(accountId: id)
|
||||||
case let .accountDetailWithAccount(account):
|
case let .accountDetailWithAccount(account):
|
||||||
AccountDetailView(account: account, scrollToTopSignal: .constant(0))
|
AccountDetailView(account: account)
|
||||||
case let .accountSettingsWithAccount(account, appAccount):
|
case let .accountSettingsWithAccount(account, appAccount):
|
||||||
AccountSettingsView(account: account, appAccount: appAccount)
|
AccountSettingsView(account: account, appAccount: appAccount)
|
||||||
case let .statusDetail(id):
|
case let .statusDetail(id):
|
||||||
|
@ -36,19 +36,16 @@ extension View {
|
||||||
TimelineView(timeline: .constant(.hashtag(tag: tag, accountId: accountId)),
|
TimelineView(timeline: .constant(.hashtag(tag: tag, accountId: accountId)),
|
||||||
pinnedFilters: .constant([]),
|
pinnedFilters: .constant([]),
|
||||||
selectedTagGroup: .constant(nil),
|
selectedTagGroup: .constant(nil),
|
||||||
scrollToTopSignal: .constant(0),
|
|
||||||
canFilterTimeline: false)
|
canFilterTimeline: false)
|
||||||
case let .list(list):
|
case let .list(list):
|
||||||
TimelineView(timeline: .constant(.list(list: list)),
|
TimelineView(timeline: .constant(.list(list: list)),
|
||||||
pinnedFilters: .constant([]),
|
pinnedFilters: .constant([]),
|
||||||
selectedTagGroup: .constant(nil),
|
selectedTagGroup: .constant(nil),
|
||||||
scrollToTopSignal: .constant(0),
|
|
||||||
canFilterTimeline: false)
|
canFilterTimeline: false)
|
||||||
case let .linkTimeline(url, title):
|
case let .linkTimeline(url, title):
|
||||||
TimelineView(timeline: .constant(.link(url: url, title: title)),
|
TimelineView(timeline: .constant(.link(url: url, title: title)),
|
||||||
pinnedFilters: .constant([]),
|
pinnedFilters: .constant([]),
|
||||||
selectedTagGroup: .constant(nil),
|
selectedTagGroup: .constant(nil),
|
||||||
scrollToTopSignal: .constant(0),
|
|
||||||
canFilterTimeline: false)
|
canFilterTimeline: false)
|
||||||
case let .following(id):
|
case let .following(id):
|
||||||
AccountsListView(mode: .following(accountId: id))
|
AccountsListView(mode: .following(accountId: id))
|
||||||
|
@ -64,7 +61,6 @@ extension View {
|
||||||
TimelineView(timeline: .constant(.trending),
|
TimelineView(timeline: .constant(.trending),
|
||||||
pinnedFilters: .constant([]),
|
pinnedFilters: .constant([]),
|
||||||
selectedTagGroup: .constant(nil),
|
selectedTagGroup: .constant(nil),
|
||||||
scrollToTopSignal: .constant(0),
|
|
||||||
canFilterTimeline: false)
|
canFilterTimeline: false)
|
||||||
case let .trendingLinks(cards):
|
case let .trendingLinks(cards):
|
||||||
TrendingLinksListView(cards: cards)
|
TrendingLinksListView(cards: cards)
|
||||||
|
@ -74,8 +70,7 @@ extension View {
|
||||||
NotificationsRequestsListView()
|
NotificationsRequestsListView()
|
||||||
case let .notificationForAccount(accountId):
|
case let .notificationForAccount(accountId):
|
||||||
NotificationsListView(lockedType: nil,
|
NotificationsListView(lockedType: nil,
|
||||||
lockedAccountId: accountId,
|
lockedAccountId: accountId)
|
||||||
scrollToTopSignal: .constant(0))
|
|
||||||
case .blockedAccounts:
|
case .blockedAccounts:
|
||||||
AccountsListView(mode: .blocked)
|
AccountsListView(mode: .blocked)
|
||||||
case .mutedAccounts:
|
case .mutedAccounts:
|
||||||
|
|
|
@ -70,8 +70,10 @@ struct AppView: View {
|
||||||
selectedTab = newTab
|
selectedTab = newTab
|
||||||
})) {
|
})) {
|
||||||
ForEach(availableTabs) { tab in
|
ForEach(availableTabs) { tab in
|
||||||
|
Tab(value: tab) {
|
||||||
tab.makeContentView(selectedTab: $selectedTab)
|
tab.makeContentView(selectedTab: $selectedTab)
|
||||||
.tabItem {
|
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .tabBar)
|
||||||
|
} label: {
|
||||||
if userPreferences.showiPhoneTabLabel {
|
if userPreferences.showiPhoneTabLabel {
|
||||||
tab.label
|
tab.label
|
||||||
.environment(\.symbolVariants, tab == selectedTab ? .fill : .none)
|
.environment(\.symbolVariants, tab == selectedTab ? .fill : .none)
|
||||||
|
@ -79,9 +81,7 @@ struct AppView: View {
|
||||||
Image(systemName: tab.iconName)
|
Image(systemName: tab.iconName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tag(tab)
|
|
||||||
.badge(badgeFor(tab: tab))
|
.badge(badgeFor(tab: tab))
|
||||||
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .tabBar)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.id(appAccountsManager.currentClient.id)
|
.id(appAccountsManager.currentClient.id)
|
||||||
|
|
|
@ -13,11 +13,10 @@ struct ExploreTab: View {
|
||||||
@Environment(CurrentAccount.self) private var currentAccount
|
@Environment(CurrentAccount.self) private var currentAccount
|
||||||
@Environment(Client.self) private var client
|
@Environment(Client.self) private var client
|
||||||
@State private var routerPath = RouterPath()
|
@State private var routerPath = RouterPath()
|
||||||
@State private var scrollToTopSignal: Int = 0
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $routerPath.path) {
|
NavigationStack(path: $routerPath.path) {
|
||||||
ExploreView(scrollToTopSignal: $scrollToTopSignal)
|
ExploreView()
|
||||||
.withAppRouter()
|
.withAppRouter()
|
||||||
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
||||||
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
|
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
|
||||||
|
|
|
@ -15,11 +15,10 @@ struct MessagesTab: View {
|
||||||
@Environment(CurrentAccount.self) private var currentAccount
|
@Environment(CurrentAccount.self) private var currentAccount
|
||||||
@Environment(AppAccountsManager.self) private var appAccount
|
@Environment(AppAccountsManager.self) private var appAccount
|
||||||
@State private var routerPath = RouterPath()
|
@State private var routerPath = RouterPath()
|
||||||
@State private var scrollToTopSignal: Int = 0
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $routerPath.path) {
|
NavigationStack(path: $routerPath.path) {
|
||||||
ConversationsListView(scrollToTopSignal: $scrollToTopSignal)
|
ConversationsListView()
|
||||||
.withAppRouter()
|
.withAppRouter()
|
||||||
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
|
|
@ -20,7 +20,6 @@ struct NotificationsTab: View {
|
||||||
@Environment(UserPreferences.self) private var userPreferences
|
@Environment(UserPreferences.self) private var userPreferences
|
||||||
@Environment(PushNotificationsService.self) private var pushNotificationsService
|
@Environment(PushNotificationsService.self) private var pushNotificationsService
|
||||||
@State private var routerPath = RouterPath()
|
@State private var routerPath = RouterPath()
|
||||||
@State private var scrollToTopSignal: Int = 0
|
|
||||||
|
|
||||||
@Binding var selectedTab: AppTab
|
@Binding var selectedTab: AppTab
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ struct NotificationsTab: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $routerPath.path) {
|
NavigationStack(path: $routerPath.path) {
|
||||||
NotificationsListView(lockedType: lockedType, scrollToTopSignal: $scrollToTopSignal)
|
NotificationsListView(lockedType: lockedType)
|
||||||
.withAppRouter()
|
.withAppRouter()
|
||||||
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
|
|
@ -14,18 +14,17 @@ struct ProfileTab: View {
|
||||||
@Environment(Client.self) private var client
|
@Environment(Client.self) private var client
|
||||||
@Environment(CurrentAccount.self) private var currentAccount
|
@Environment(CurrentAccount.self) private var currentAccount
|
||||||
@State private var routerPath = RouterPath()
|
@State private var routerPath = RouterPath()
|
||||||
@State private var scrollToTopSignal: Int = 0
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $routerPath.path) {
|
NavigationStack(path: $routerPath.path) {
|
||||||
if let account = currentAccount.account {
|
if let account = currentAccount.account {
|
||||||
AccountDetailView(account: account, scrollToTopSignal: $scrollToTopSignal)
|
AccountDetailView(account: account)
|
||||||
.withAppRouter()
|
.withAppRouter()
|
||||||
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
||||||
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
|
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
|
||||||
.id(account.id)
|
.id(account.id)
|
||||||
} else {
|
} else {
|
||||||
AccountDetailView(account: .placeholder(), scrollToTopSignal: $scrollToTopSignal)
|
AccountDetailView(account: .placeholder())
|
||||||
.redacted(reason: .placeholder)
|
.redacted(reason: .placeholder)
|
||||||
.allowsHitTesting(false)
|
.allowsHitTesting(false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ struct TimelineTab: View {
|
||||||
@State private var didAppear: Bool = false
|
@State private var didAppear: Bool = false
|
||||||
@State private var timeline: TimelineFilter = .home
|
@State private var timeline: TimelineFilter = .home
|
||||||
@State private var selectedTagGroup: TagGroup?
|
@State private var selectedTagGroup: TagGroup?
|
||||||
@State private var scrollToTopSignal: Int = 0
|
|
||||||
|
|
||||||
@Query(sort: \LocalTimeline.creationDate, order: .reverse) var localTimelines: [LocalTimeline]
|
@Query(sort: \LocalTimeline.creationDate, order: .reverse) var localTimelines: [LocalTimeline]
|
||||||
@Query(sort: \TagGroup.creationDate, order: .reverse) var tagGroups: [TagGroup]
|
@Query(sort: \TagGroup.creationDate, order: .reverse) var tagGroups: [TagGroup]
|
||||||
|
@ -42,7 +41,6 @@ struct TimelineTab: View {
|
||||||
TimelineView(timeline: $timeline,
|
TimelineView(timeline: $timeline,
|
||||||
pinnedFilters: $pinnedFilters,
|
pinnedFilters: $pinnedFilters,
|
||||||
selectedTagGroup: $selectedTagGroup,
|
selectedTagGroup: $selectedTagGroup,
|
||||||
scrollToTopSignal: $scrollToTopSignal,
|
|
||||||
canFilterTimeline: canFilterTimeline)
|
canFilterTimeline: canFilterTimeline)
|
||||||
.withAppRouter()
|
.withAppRouter()
|
||||||
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
|
||||||
|
|
|
@ -28,18 +28,14 @@ public struct AccountDetailView: View {
|
||||||
|
|
||||||
@State private var displayTitle: Bool = false
|
@State private var displayTitle: Bool = false
|
||||||
|
|
||||||
@Binding var scrollToTopSignal: Int
|
|
||||||
|
|
||||||
/// When coming from a URL like a mention tap in a status.
|
/// When coming from a URL like a mention tap in a status.
|
||||||
public init(accountId: String, scrollToTopSignal: Binding<Int>) {
|
public init(accountId: String) {
|
||||||
_viewModel = .init(initialValue: .init(accountId: accountId))
|
_viewModel = .init(initialValue: .init(accountId: accountId))
|
||||||
_scrollToTopSignal = scrollToTopSignal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When the account is already fetched by the parent caller.
|
/// When the account is already fetched by the parent caller.
|
||||||
public init(account: Account, scrollToTopSignal: Binding<Int>) {
|
public init(account: Account) {
|
||||||
_viewModel = .init(initialValue: .init(account: account))
|
_viewModel = .init(initialValue: .init(account: account))
|
||||||
_scrollToTopSignal = scrollToTopSignal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
|
@ -89,11 +85,6 @@ public struct AccountDetailView: View {
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
.background(theme.primaryBackgroundColor)
|
.background(theme.primaryBackgroundColor)
|
||||||
#endif
|
#endif
|
||||||
.onChange(of: scrollToTopSignal) {
|
|
||||||
withAnimation {
|
|
||||||
proxy.scrollTo(ScrollToView.Constants.scrollToTop, anchor: .top)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
guard reasons != .placeholder else { return }
|
guard reasons != .placeholder else { return }
|
||||||
|
@ -403,6 +394,6 @@ extension View {
|
||||||
|
|
||||||
struct AccountDetailView_Previews: PreviewProvider {
|
struct AccountDetailView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
AccountDetailView(account: .placeholder(), scrollToTopSignal: .constant(0))
|
AccountDetailView(account: .placeholder())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,7 @@ public struct ConversationsListView: View {
|
||||||
|
|
||||||
@State private var viewModel = ConversationsListViewModel()
|
@State private var viewModel = ConversationsListViewModel()
|
||||||
|
|
||||||
@Binding var scrollToTopSignal: Int
|
public init() { }
|
||||||
|
|
||||||
public init(scrollToTopSignal: Binding<Int>) {
|
|
||||||
_scrollToTopSignal = scrollToTopSignal
|
|
||||||
}
|
|
||||||
|
|
||||||
private var conversations: Binding<[Conversation]> {
|
private var conversations: Binding<[Conversation]> {
|
||||||
if viewModel.isLoadingFirstPage {
|
if viewModel.isLoadingFirstPage {
|
||||||
|
@ -89,11 +85,6 @@ public struct ConversationsListView: View {
|
||||||
viewModel.handleEvent(event: latestEvent)
|
viewModel.handleEvent(event: latestEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: scrollToTopSignal) {
|
|
||||||
withAnimation {
|
|
||||||
proxy.scrollTo(ScrollToView.Constants.scrollToTop, anchor: .top)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.refreshable {
|
.refreshable {
|
||||||
// note: this Task wrapper should not be necessary, but it reportedly crashes without it
|
// note: this Task wrapper should not be necessary, but it reportedly crashes without it
|
||||||
// when refreshing on an empty list
|
// when refreshing on an empty list
|
||||||
|
|
|
@ -14,11 +14,7 @@ public struct ExploreView: View {
|
||||||
|
|
||||||
@State private var viewModel = ExploreViewModel()
|
@State private var viewModel = ExploreViewModel()
|
||||||
|
|
||||||
@Binding var scrollToTopSignal: Int
|
public init() { }
|
||||||
|
|
||||||
public init(scrollToTopSignal: Binding<Int>) {
|
|
||||||
_scrollToTopSignal = scrollToTopSignal
|
|
||||||
}
|
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
ScrollViewReader { proxy in
|
ScrollViewReader { proxy in
|
||||||
|
@ -111,15 +107,6 @@ public struct ExploreView: View {
|
||||||
.task(id: viewModel.searchQuery) {
|
.task(id: viewModel.searchQuery) {
|
||||||
await viewModel.search()
|
await viewModel.search()
|
||||||
}
|
}
|
||||||
.onChange(of: scrollToTopSignal) {
|
|
||||||
if viewModel.scrollToTopVisible {
|
|
||||||
viewModel.isSearchPresented.toggle()
|
|
||||||
} else {
|
|
||||||
withAnimation {
|
|
||||||
proxy.scrollTo(ScrollToView.Constants.scrollToTop, anchor: .top)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,18 +17,15 @@ public struct NotificationsListView: View {
|
||||||
|
|
||||||
@State private var viewModel = NotificationsViewModel()
|
@State private var viewModel = NotificationsViewModel()
|
||||||
@State private var isNotificationsPolicyPresented: Bool = false
|
@State private var isNotificationsPolicyPresented: Bool = false
|
||||||
@Binding var scrollToTopSignal: Int
|
|
||||||
|
|
||||||
let lockedType: Models.Notification.NotificationType?
|
let lockedType: Models.Notification.NotificationType?
|
||||||
let lockedAccountId: String?
|
let lockedAccountId: String?
|
||||||
|
|
||||||
public init(lockedType: Models.Notification.NotificationType? = nil,
|
public init(lockedType: Models.Notification.NotificationType? = nil,
|
||||||
lockedAccountId: String? = nil,
|
lockedAccountId: String? = nil)
|
||||||
scrollToTopSignal: Binding<Int>)
|
|
||||||
{
|
{
|
||||||
self.lockedType = lockedType
|
self.lockedType = lockedType
|
||||||
self.lockedAccountId = lockedAccountId
|
self.lockedAccountId = lockedAccountId
|
||||||
_scrollToTopSignal = scrollToTopSignal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
|
@ -44,11 +41,6 @@ public struct NotificationsListView: View {
|
||||||
.id(account.account?.id)
|
.id(account.account?.id)
|
||||||
.environment(\.defaultMinListRowHeight, 1)
|
.environment(\.defaultMinListRowHeight, 1)
|
||||||
.listStyle(.plain)
|
.listStyle(.plain)
|
||||||
.onChange(of: scrollToTopSignal) {
|
|
||||||
withAnimation {
|
|
||||||
proxy.scrollTo(ScrollToView.Constants.scrollToTop, anchor: .top)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .principal) {
|
ToolbarItem(placement: .principal) {
|
||||||
|
|
|
@ -27,7 +27,6 @@ public struct TimelineView: View {
|
||||||
@Binding var timeline: TimelineFilter
|
@Binding var timeline: TimelineFilter
|
||||||
@Binding var pinnedFilters: [TimelineFilter]
|
@Binding var pinnedFilters: [TimelineFilter]
|
||||||
@Binding var selectedTagGroup: TagGroup?
|
@Binding var selectedTagGroup: TagGroup?
|
||||||
@Binding var scrollToTopSignal: Int
|
|
||||||
|
|
||||||
@Query(sort: \TagGroup.creationDate, order: .reverse) var tagGroups: [TagGroup]
|
@Query(sort: \TagGroup.creationDate, order: .reverse) var tagGroups: [TagGroup]
|
||||||
|
|
||||||
|
@ -36,18 +35,15 @@ public struct TimelineView: View {
|
||||||
public init(timeline: Binding<TimelineFilter>,
|
public init(timeline: Binding<TimelineFilter>,
|
||||||
pinnedFilters: Binding<[TimelineFilter]>,
|
pinnedFilters: Binding<[TimelineFilter]>,
|
||||||
selectedTagGroup: Binding<TagGroup?>,
|
selectedTagGroup: Binding<TagGroup?>,
|
||||||
scrollToTopSignal: Binding<Int>,
|
|
||||||
canFilterTimeline: Bool)
|
canFilterTimeline: Bool)
|
||||||
{
|
{
|
||||||
_timeline = timeline
|
_timeline = timeline
|
||||||
_pinnedFilters = pinnedFilters
|
_pinnedFilters = pinnedFilters
|
||||||
_selectedTagGroup = selectedTagGroup
|
_selectedTagGroup = selectedTagGroup
|
||||||
_scrollToTopSignal = scrollToTopSignal
|
|
||||||
self.canFilterTimeline = canFilterTimeline
|
self.canFilterTimeline = canFilterTimeline
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
ScrollViewReader { proxy in
|
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
List {
|
List {
|
||||||
scrollToTopView
|
scrollToTopView
|
||||||
|
@ -108,12 +104,6 @@ public struct TimelineView: View {
|
||||||
viewModel.scrollToIndex = nil
|
viewModel.scrollToIndex = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: scrollToTopSignal) {
|
|
||||||
withAnimation {
|
|
||||||
proxy.scrollTo(ScrollToView.Constants.scrollToTop, anchor: .top)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
toolbarTitleView
|
toolbarTitleView
|
||||||
toolbarTagGroupButton
|
toolbarTagGroupButton
|
||||||
|
|
Loading…
Reference in a new issue