diff --git a/Packages/Timeline/Sources/Timeline/View/TimelineHeaderView.swift b/Packages/Timeline/Sources/Timeline/View/TimelineHeaderView.swift new file mode 100644 index 00000000..a5541707 --- /dev/null +++ b/Packages/Timeline/Sources/Timeline/View/TimelineHeaderView.swift @@ -0,0 +1,22 @@ +import SwiftUI +import DesignSystem + +struct TimelineHeaderView: View { + @Environment(Theme.self) private var theme + + var content: () -> Content + + var body: some View { + VStack(alignment: .leading) { + Spacer() + content() + Spacer() + } + .listRowBackground(theme.secondaryBackgroundColor) + .listRowSeparator(.hidden) + .listRowInsets(.init(top: 8, + leading: .layoutPadding, + bottom: 8, + trailing: .layoutPadding)) + } +} diff --git a/Packages/Timeline/Sources/Timeline/View/TimelineTagGroupheaderView.swift b/Packages/Timeline/Sources/Timeline/View/TimelineTagGroupheaderView.swift new file mode 100644 index 00000000..01425ac1 --- /dev/null +++ b/Packages/Timeline/Sources/Timeline/View/TimelineTagGroupheaderView.swift @@ -0,0 +1,39 @@ +import SwiftUI +import Models +import Env + +struct TimelineTagGroupheaderView: View { + @Environment(RouterPath.self) private var routerPath + + @Binding var group: TagGroup? + @Binding var timeline: TimelineFilter + + var body: some View { + if let group { + TimelineHeaderView { + HStack { + ScrollView(.horizontal) { + HStack(spacing: 4) { + ForEach(group.tags, id: \.self) { tag in + Button { + routerPath.navigate(to: .hashTag(tag: tag, account: nil)) + } label: { + Text("#\(tag)") + .font(.scaledHeadline) + } + .buttonStyle(.plain) + } + } + } + .scrollIndicators(.hidden) + Button("status.action.edit") { + routerPath.presentedSheet = .editTagGroup(tagGroup: group, onSaved: { group in + timeline = .tagGroup(title: group.title, tags: group.tags) + }) + } + .buttonStyle(.bordered) + } + } + } + } +} diff --git a/Packages/Timeline/Sources/Timeline/View/TimelineTagHeaderView.swift b/Packages/Timeline/Sources/Timeline/View/TimelineTagHeaderView.swift new file mode 100644 index 00000000..49c7b861 --- /dev/null +++ b/Packages/Timeline/Sources/Timeline/View/TimelineTagHeaderView.swift @@ -0,0 +1,42 @@ +import SwiftUI +import Models +import DesignSystem +import Env + +struct TimelineTagHeaderView: View { + @Environment(CurrentAccount.self) private var account + + @Binding var tag: Tag? + + var body: some View { + if let tag { + TimelineHeaderView { + HStack { + TagChartView(tag: tag) + .padding(.top, 12) + + VStack(alignment: .leading, spacing: 4) { + Text("#\(tag.name)") + .font(.scaledHeadline) + Text("timeline.n-recent-from-n-participants \(tag.totalUses) \(tag.totalAccounts)") + .font(.scaledFootnote) + .foregroundStyle(.secondary) + } + .accessibilityElement(children: .combine) + Spacer() + Button { + Task { + if tag.following { + self.tag = await account.unfollowTag(id: tag.name) + } else { + self.tag = await account.followTag(id: tag.name) + } + } + } label: { + Text(tag.following ? "account.follow.following" : "account.follow.follow") + }.buttonStyle(.bordered) + } + } + } + } +} diff --git a/Packages/Timeline/Sources/Timeline/TimelineView.swift b/Packages/Timeline/Sources/Timeline/View/TimelineView.swift similarity index 75% rename from Packages/Timeline/Sources/Timeline/TimelineView.swift rename to Packages/Timeline/Sources/Timeline/View/TimelineView.swift index 3b8bf5c6..2b5daa0c 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineView.swift +++ b/Packages/Timeline/Sources/Timeline/View/TimelineView.swift @@ -48,8 +48,8 @@ public struct TimelineView: View { ZStack(alignment: .top) { List { scrollToTopView - tagGroupHeaderView - tagHeaderView + TimelineTagGroupheaderView(group: $selectedTagGroup, timeline: $viewModel.timeline) + TimelineTagHeaderView(tag: $viewModel.tag) switch viewModel.timeline { case .remoteLocal: StatusesListView(fetcher: viewModel, client: client, routerPath: routerPath, isRemote: true) @@ -157,86 +157,6 @@ public struct TimelineView: View { } } - @ViewBuilder - private var tagHeaderView: some View { - if let tag = viewModel.tag { - headerView { - HStack { - TagChartView(tag: tag) - .padding(.top, 12) - - VStack(alignment: .leading, spacing: 4) { - Text("#\(tag.name)") - .font(.scaledHeadline) - Text("timeline.n-recent-from-n-participants \(tag.totalUses) \(tag.totalAccounts)") - .font(.scaledFootnote) - .foregroundStyle(.secondary) - } - .accessibilityElement(children: .combine) - Spacer() - Button { - Task { - if tag.following { - viewModel.tag = await account.unfollowTag(id: tag.name) - } else { - viewModel.tag = await account.followTag(id: tag.name) - } - } - } label: { - Text(tag.following ? "account.follow.following" : "account.follow.follow") - }.buttonStyle(.bordered) - } - } - } - } - - @ViewBuilder - private var tagGroupHeaderView: some View { - if let group = selectedTagGroup { - headerView { - HStack { - ScrollView(.horizontal) { - HStack(spacing: 4) { - ForEach(group.tags, id: \.self) { tag in - Button { - routerPath.navigate(to: .hashTag(tag: tag, account: nil)) - } label: { - Text("#\(tag)") - .font(.scaledHeadline) - } - .buttonStyle(.plain) - } - } - } - .scrollIndicators(.hidden) - Button("status.action.edit") { - routerPath.presentedSheet = .editTagGroup(tagGroup: group, onSaved: { group in - viewModel.timeline = .tagGroup(title: group.title, tags: group.tags) - }) - } - .buttonStyle(.bordered) - } - } - } - } - - @ViewBuilder - private func headerView( - @ViewBuilder content: () -> some View - ) -> some View { - VStack(alignment: .leading) { - Spacer() - content() - Spacer() - } - .listRowBackground(theme.secondaryBackgroundColor) - .listRowSeparator(.hidden) - .listRowInsets(.init(top: 8, - leading: .layoutPadding, - bottom: 8, - trailing: .layoutPadding)) - } - @ToolbarContentBuilder private var toolbarTitleView: some ToolbarContent { ToolbarItem(placement: .principal) { diff --git a/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift b/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift similarity index 100% rename from Packages/Timeline/Sources/Timeline/TimelineViewModel.swift rename to Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift