From a959ea36061c7364790154580d2e943085f6778f Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Sun, 12 Feb 2023 16:13:57 +0100 Subject: [PATCH] Transition profile to List container --- .../Account/AccountDetailHeaderView.swift | 46 +++++--- .../Sources/Account/AccountDetailView.swift | 105 +++++++----------- .../Status/List/StatusesListView.swift | 14 +-- 3 files changed, 73 insertions(+), 92 deletions(-) diff --git a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift index dfca35b0..04ccefa2 100644 --- a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift +++ b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift @@ -7,6 +7,10 @@ import Shimmer import SwiftUI struct AccountDetailHeaderView: View { + enum Constants { + static let headerHeight: CGFloat = 200 + } + @EnvironmentObject private var theme: Theme @EnvironmentObject private var quickLook: QuickLook @EnvironmentObject private var routerPath: RouterPath @@ -17,16 +21,10 @@ struct AccountDetailHeaderView: View { let account: Account let scrollViewProxy: ScrollViewProxy? - @Binding var scrollOffset: CGFloat - - private var bannerHeight: CGFloat { - 200 + (scrollOffset > 0 ? scrollOffset * 2 : 0) - } - var body: some View { VStack(alignment: .leading) { Rectangle() - .frame(height: 200) + .frame(height: Constants.headerHeight) .overlay { headerImageView } @@ -39,7 +37,7 @@ struct AccountDetailHeaderView: View { if reasons.contains(.placeholder) { Rectangle() .foregroundColor(theme.secondaryBackgroundColor) - .frame(height: bannerHeight) + .frame(height: Constants.headerHeight) } else { LazyImage(url: account.header) { state in if let image = state.image { @@ -48,14 +46,14 @@ struct AccountDetailHeaderView: View { .overlay(account.haveHeader ? .black.opacity(0.50) : .clear) } else if state.isLoading { theme.secondaryBackgroundColor - .frame(height: bannerHeight) + .frame(height: Constants.headerHeight) .shimmering() } else { theme.secondaryBackgroundColor - .frame(height: bannerHeight) + .frame(height: Constants.headerHeight) } } - .frame(height: bannerHeight) + .frame(height: Constants.headerHeight) } if viewModel.relationship?.followedBy == true { @@ -69,8 +67,7 @@ struct AccountDetailHeaderView: View { } } .background(theme.secondaryBackgroundColor) - .frame(height: bannerHeight) - .offset(y: scrollOffset > 0 ? -scrollOffset : 0) + .frame(height: Constants.headerHeight) .contentShape(Rectangle()) .onTapGesture { guard account.haveHeader else { @@ -102,16 +99,26 @@ struct AccountDetailHeaderView: View { } label: { makeCustomInfoLabel(title: "account.posts", count: account.statusesCount) } - NavigationLink(value: RouterDestinations.following(id: account.id)) { + .buttonStyle(.borderless) + + Button { + routerPath.navigate(to: .following(id: account.id)) + } label: { makeCustomInfoLabel(title: "account.following", count: account.followingCount) } - NavigationLink(value: RouterDestinations.followers(id: account.id)) { + .buttonStyle(.borderless) + + Button { + routerPath.navigate(to: .followers(id: account.id)) + } label: { makeCustomInfoLabel( title: "account.followers", count: account.followersCount, needsBadge: currentAccount.account?.id == account.id && !currentAccount.followRequests.isEmpty ) } + .buttonStyle(.borderless) + }.offset(y: 20) } } @@ -123,6 +130,12 @@ struct AccountDetailHeaderView: View { VStack(alignment: .leading, spacing: 0) { EmojiTextApp(.init(stringValue: account.safeDisplayName), emojis: account.emojis) .font(.scaledHeadline) + .onDisappear { + print("DISPEAR") + } + .onAppear { + print("APPEAR") + } Text("@\(account.acct)") .font(.scaledCallout) .foregroundColor(.gray) @@ -189,7 +202,6 @@ struct AccountDetailHeaderView_Previews: PreviewProvider { static var previews: some View { AccountDetailHeaderView(viewModel: .init(account: .placeholder()), account: .placeholder(), - scrollViewProxy: nil, - scrollOffset: .constant(0)) + scrollViewProxy: nil) } } diff --git a/Packages/Account/Sources/Account/AccountDetailView.swift b/Packages/Account/Sources/Account/AccountDetailView.swift index 2d8c9f6a..f8b4b094 100644 --- a/Packages/Account/Sources/Account/AccountDetailView.swift +++ b/Packages/Account/Sources/Account/AccountDetailView.swift @@ -19,7 +19,6 @@ public struct AccountDetailView: View { @EnvironmentObject private var routerPath: RouterPath @StateObject private var viewModel: AccountDetailViewModel - @State private var scrollOffset: CGFloat = 0 @State private var isFieldsSheetDisplayed: Bool = false @State private var isCurrentUser: Bool = false @State private var isCreateListAlertPresented: Bool = false @@ -40,42 +39,46 @@ public struct AccountDetailView: View { public var body: some View { ScrollViewReader { proxy in - ScrollViewOffsetReader { offset in - self.scrollOffset = offset - } content: { - LazyVStack(alignment: .leading) { + List { + Group { makeHeaderView(proxy: proxy) familiarFollowers - .offset(y: -36) featuredTagsView - .offset(y: -36) - Group { - Picker("", selection: $viewModel.selectedTab) { - ForEach(isCurrentUser ? AccountDetailViewModel.Tab.currentAccountTabs : AccountDetailViewModel.Tab.accountTabs, - id: \.self) { tab in - Image(systemName: tab.iconName) - .tag(tab) - } - } - .pickerStyle(.segmented) - .padding(.horizontal, .layoutPadding) - .offset(y: -20) - } - .id("status") - - switch viewModel.tabState { - case .statuses: - if viewModel.selectedTab == .statuses { - pinnedPostsView - } - StatusesListView(fetcher: viewModel, isEmbdedInList: false) - case .followedTags: - tagsListView - case .lists: - listsListView + } + .listRowInsets(.init()) + .listRowSeparator(.hidden) + .listRowBackground(theme.primaryBackgroundColor) + + Picker("", selection: $viewModel.selectedTab) { + ForEach(isCurrentUser ? AccountDetailViewModel.Tab.currentAccountTabs : AccountDetailViewModel.Tab.accountTabs, + id: \.self) { tab in + Image(systemName: tab.iconName) + .tag(tab) } } + .pickerStyle(.segmented) + .padding(.layoutPadding) + .listRowSeparator(.hidden) + .listRowBackground(theme.primaryBackgroundColor) + .listRowInsets(.init()) + .id("status") + + switch viewModel.tabState { + case .statuses: + if viewModel.selectedTab == .statuses { + pinnedPostsView + .listRowInsets(.init()) + .listRowSeparator(.hidden) + .listRowBackground(theme.primaryBackgroundColor) + } + StatusesListView(fetcher: viewModel) + case .followedTags: + tagsListView + case .lists: + listsListView + } } + .listStyle(.plain) .scrollContentBackground(.hidden) .background(theme.primaryBackgroundColor) } @@ -138,14 +141,12 @@ public struct AccountDetailView: View { case .loading: AccountDetailHeaderView(viewModel: viewModel, account: .placeholder(), - scrollViewProxy: proxy, - scrollOffset: $scrollOffset) + scrollViewProxy: proxy) .redacted(reason: .placeholder) case let .data(account): AccountDetailHeaderView(viewModel: viewModel, account: account, - scrollViewProxy: proxy, - scrollOffset: $scrollOffset) + scrollViewProxy: proxy) case let .error(error): Text("Error: \(error.localizedDescription)") } @@ -270,8 +271,7 @@ public struct AccountDetailView: View { Spacer() Image(systemName: "chevron.right") } - .padding(.horizontal, .layoutPadding) - .padding(.vertical, 8) + .listRowBackground(theme.primaryBackgroundColor) } }.task { await currentAccount.fetchFollowedTags() @@ -282,16 +282,11 @@ public struct AccountDetailView: View { Group { ForEach(currentAccount.sortedLists) { list in NavigationLink(value: RouterDestinations.list(list: list)) { - HStack { - Text(list.title) - Spacer() - Image(systemName: "chevron.right") - } - .padding(.vertical, 8) - .padding(.horizontal, .layoutPadding) + Text(list.title) .font(.scaledHeadline) .foregroundColor(theme.labelColor) } + .listRowBackground(theme.primaryBackgroundColor) .contextMenu { Button("account.list.delete", role: .destructive) { Task { @@ -303,7 +298,9 @@ public struct AccountDetailView: View { Button("account.list.create") { isCreateListAlertPresented = true } - .padding(.horizontal, .layoutPadding) + .tint(theme.tintColor) + .buttonStyle(.borderless) + .listRowBackground(theme.primaryBackgroundColor) } .task { await currentAccount.fetchLists() @@ -348,18 +345,6 @@ public struct AccountDetailView: View { @ToolbarContentBuilder private var toolbarContent: some ToolbarContent { - ToolbarItem(placement: .principal) { - if scrollOffset < -170 { - switch viewModel.accountState { - case let .data(account): - EmojiTextApp(.init(stringValue: account.safeDisplayName), emojis: account.emojis) - .font(.scaledHeadline) - default: - EmptyView() - } - } - } - ToolbarItem(placement: .navigationBarTrailing) { Menu { if let account = viewModel.account { @@ -544,11 +529,7 @@ public struct AccountDetailView: View { } } } label: { - if scrollOffset < -5 { - Image(systemName: "ellipsis.circle") - } else { - Image(systemName: "ellipsis.circle.fill") - } + Image(systemName: "ellipsis.circle") } } } diff --git a/Packages/Status/Sources/Status/List/StatusesListView.swift b/Packages/Status/Sources/Status/List/StatusesListView.swift index f48047d0..3bc15c5b 100644 --- a/Packages/Status/Sources/Status/List/StatusesListView.swift +++ b/Packages/Status/Sources/Status/List/StatusesListView.swift @@ -9,12 +9,10 @@ public struct StatusesListView: View where Fetcher: StatusesFetcher { @ObservedObject private var fetcher: Fetcher private let isRemote: Bool - private let isEmbdedInList: Bool - public init(fetcher: Fetcher, isRemote: Bool = false, isEmbdedInList: Bool = true) { + public init(fetcher: Fetcher, isRemote: Bool = false) { self.fetcher = fetcher self.isRemote = isRemote - self.isEmbdedInList = isEmbdedInList } public var body: some View { @@ -22,12 +20,7 @@ public struct StatusesListView: View where Fetcher: StatusesFetcher { case .loading: ForEach(Status.placeholders()) { status in StatusRowView(viewModel: .init(status: status, isCompact: false)) - .padding(.horizontal, isEmbdedInList ? 0 : .layoutPadding) .redacted(reason: .placeholder) - if !isEmbdedInList { - Divider() - .padding(.vertical, .dividerPadding) - } } case .error: ErrorView(title: "status.error.title", @@ -45,7 +38,6 @@ public struct StatusesListView: View where Fetcher: StatusesFetcher { let viewModel = StatusRowViewModel(status: status, isCompact: false, isRemote: isRemote) if viewModel.filter?.filter.filterAction != .hide { StatusRowView(viewModel: viewModel) - .padding(.horizontal, isEmbdedInList ? 0 : .layoutPadding) .id(status.id) .onAppear { fetcher.statusDidAppear(status: status) @@ -53,10 +45,6 @@ public struct StatusesListView: View where Fetcher: StatusesFetcher { .onDisappear { fetcher.statusDidDisappear(status: status) } - if !isEmbdedInList { - Divider() - .padding(.vertical, .dividerPadding) - } } } switch nextPageState {