diff --git a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift index 8355bdbe..fc4f0512 100644 --- a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift +++ b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift @@ -15,6 +15,7 @@ struct AccountDetailHeaderView: View { let isCurrentUser: Bool let account: Account let relationship: Relationshionship? + let scrollViewProxy: ScrollViewProxy? @Binding var scrollOffset: CGFloat @@ -83,7 +84,13 @@ struct AccountDetailHeaderView: View { } Spacer() Group { - makeCustomInfoLabel(title: "Posts", count: account.statusesCount) + Button { + withAnimation { + scrollViewProxy?.scrollTo("status", anchor: .top) + } + } label: { + makeCustomInfoLabel(title: "Posts", count: account.statusesCount) + } NavigationLink(value: RouteurDestinations.following(id: account.id)) { makeCustomInfoLabel(title: "Following", count: account.followingCount) } @@ -139,6 +146,7 @@ struct AccountDetailHeaderView_Previews: PreviewProvider { AccountDetailHeaderView(isCurrentUser: false, account: .placeholder(), relationship: .placeholder(), + scrollViewProxy: nil, scrollOffset: .constant(0)) } } diff --git a/Packages/Account/Sources/Account/AccountDetailView.swift b/Packages/Account/Sources/Account/AccountDetailView.swift index 5d221865..1c930a0e 100644 --- a/Packages/Account/Sources/Account/AccountDetailView.swift +++ b/Packages/Account/Sources/Account/AccountDetailView.swift @@ -34,34 +34,39 @@ public struct AccountDetailView: View { } public var body: some View { - ScrollViewOffsetReader { offset in - self.scrollOffset = offset - } content: { - LazyVStack(alignment: .leading) { - headerView - familliarFollowers - .offset(y: -36) - featuredTagsView - .offset(y: -36) - if isCurrentUser { - Picker("", selection: $viewModel.selectedTab) { - ForEach(AccountDetailViewModel.Tab.allCases, id: \.self) { tab in - Text(tab.title).tag(tab) + ScrollViewReader { proxy in + ScrollViewOffsetReader { offset in + self.scrollOffset = offset + } content: { + LazyVStack(alignment: .leading) { + makeHeaderView(proxy: proxy) + familliarFollowers + .offset(y: -36) + featuredTagsView + .offset(y: -36) + Group { + if isCurrentUser { + Picker("", selection: $viewModel.selectedTab) { + ForEach(AccountDetailViewModel.Tab.allCases, id: \.self) { tab in + Text(tab.title).tag(tab) + } + } + .pickerStyle(.segmented) + .padding(.horizontal, DS.Constants.layoutPadding) + .offset(y: -20) + } else { + Divider() + .offset(y: -20) } } - .pickerStyle(.segmented) - .padding(.horizontal, DS.Constants.layoutPadding) - .offset(y: -20) - } else { - Divider() - .offset(y: -20) - } - - switch viewModel.tabState { - case .statuses: - StatusesListView(fetcher: viewModel) - case let .followedTags(tags): - makeTagsListView(tags: tags) + .id("status") + + switch viewModel.tabState { + case .statuses: + StatusesListView(fetcher: viewModel) + case let .followedTags(tags): + makeTagsListView(tags: tags) + } } } } @@ -90,18 +95,20 @@ public struct AccountDetailView: View { } @ViewBuilder - private var headerView: some View { + private func makeHeaderView(proxy: ScrollViewProxy?) -> some View { switch viewModel.accountState { case .loading: AccountDetailHeaderView(isCurrentUser: isCurrentUser, account: .placeholder(), relationship: .placeholder(), + scrollViewProxy: proxy, scrollOffset: $scrollOffset) .redacted(reason: .placeholder) case let .data(account): AccountDetailHeaderView(isCurrentUser: isCurrentUser, account: account, relationship: viewModel.relationship, + scrollViewProxy: proxy, scrollOffset: $scrollOffset) case let .error(error): Text("Error: \(error.localizedDescription)") diff --git a/Packages/DesignSystem/Sources/DesignSystem/AccountExt.swift b/Packages/DesignSystem/Sources/DesignSystem/AccountExt.swift index eed9d5a0..5caef409 100644 --- a/Packages/DesignSystem/Sources/DesignSystem/AccountExt.swift +++ b/Packages/DesignSystem/Sources/DesignSystem/AccountExt.swift @@ -6,11 +6,16 @@ import Models @MainActor extension Account { + private struct Part: Identifiable { + let id = UUID().uuidString + let value: Substring + } + public var displayNameWithEmojis: some View { - let splittedDisplayName = displayName.split(separator: ":") + let splittedDisplayName = displayName.split(separator: ":").map{ Part(value: $0) } return HStack(spacing: 0) { - ForEach(splittedDisplayName, id: \.self) { part in - if let emoji = emojis.first(where: { $0.shortcode == part }) { + ForEach(splittedDisplayName, id: \.id) { part in + if let emoji = emojis.first(where: { $0.shortcode == part.value }) { LazyImage(url: emoji.url) { state in if let image = state.image { image @@ -24,7 +29,7 @@ extension Account { .processors([ImageProcessors.Resize(size: .init(width: 20, height: 20))]) .frame(width: 20, height: 20) } else { - Text(part) + Text(part.value) } } } diff --git a/Packages/Status/Sources/Status/Row/StatusRowView.swift b/Packages/Status/Sources/Status/Row/StatusRowView.swift index 4345961b..6f89cc01 100644 --- a/Packages/Status/Sources/Status/Row/StatusRowView.swift +++ b/Packages/Status/Sources/Status/Row/StatusRowView.swift @@ -41,6 +41,9 @@ public struct StatusRowView: View { } } } + .contextMenu { + contextMenu + } } @ViewBuilder diff --git a/Packages/Timeline/Sources/Timeline/TimelineView.swift b/Packages/Timeline/Sources/Timeline/TimelineView.swift index ad0eff0e..3b020258 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineView.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineView.swift @@ -75,7 +75,9 @@ public struct TimelineView: View { if !viewModel.pendingStatuses.isEmpty { Button { proxy.scrollTo(Constants.scrollToTop) - viewModel.displayPendingStatuses() + withAnimation { + viewModel.displayPendingStatuses() + } } label: { Text(viewModel.pendingStatusesButtonTitle) }