From b324c87ae147e1ff9a66e2b3ce8e57881cc97ba3 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Sun, 1 Jan 2023 14:02:11 +0100 Subject: [PATCH] Timeline tab: Quick accounts switcher + new filter menu --- IceCubesApp/App/Tabs/TimelineTab.swift | 75 +++++++++++++++++-- .../Sources/Timeline/TimelineFilter.swift | 5 +- README.md | 2 +- 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/IceCubesApp/App/Tabs/TimelineTab.swift b/IceCubesApp/App/Tabs/TimelineTab.swift index eab33ab8..13ca6d0d 100644 --- a/IceCubesApp/App/Tabs/TimelineTab.swift +++ b/IceCubesApp/App/Tabs/TimelineTab.swift @@ -3,8 +3,11 @@ import Timeline import Env import Network import Combine +import DesignSystem struct TimelineTab: View { + @EnvironmentObject private var appAccounts: AppAccountsManager + @EnvironmentObject private var theme: Theme @EnvironmentObject private var currentAccount: CurrentAccount @EnvironmentObject private var client: Client @StateObject private var routeurPath = RouterPath() @@ -12,6 +15,7 @@ struct TimelineTab: View { @State private var timeline: TimelineFilter = .home @State private var scrollToTopSignal: Int = 0 @State private var isAddAccountSheetDisplayed = false + @State private var accountsViewModel: [AppAccountViewModel] = [] var body: some View { NavigationStack(path: $routeurPath.path) { @@ -19,11 +23,14 @@ struct TimelineTab: View { .withAppRouteur() .withSheetDestinations(sheetDestinations: $routeurPath.presentedSheet) .toolbar { + ToolbarItem(placement: .principal) { + timelineFilterButton + } if client.isAuth { - statusEditorToolbarItem(routeurPath: routeurPath) ToolbarItem(placement: .navigationBarLeading) { - timelineFilterButton + accountButton } + statusEditorToolbarItem(routeurPath: routeurPath) } else { ToolbarItem(placement: .navigationBarTrailing) { addAccountButton @@ -32,6 +39,9 @@ struct TimelineTab: View { } .id(currentAccount.account?.id) } + .sheet(isPresented: $isAddAccountSheetDisplayed) { + AddAccountView() + } .onAppear { routeurPath.client = client timeline = client.isAuth ? .home : .pub @@ -51,7 +61,7 @@ struct TimelineTab: View { private var timelineFilterButton: some View { Menu { - ForEach(TimelineFilter.availableTimeline(), id: \.self) { timeline in + ForEach(TimelineFilter.availableTimeline(client: client), id: \.self) { timeline in Button { self.timeline = timeline } label: { @@ -59,8 +69,62 @@ struct TimelineTab: View { } } } label: { - Image(systemName: "line.3.horizontal.decrease.circle") + HStack { + Text(timeline.title()) + Image(systemName: "chevron.down") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 12) + .offset(y: 2) + } + .font(.headline) + .foregroundColor(theme.labelColor) } + .menuStyle(.button) + } + + private var accountButton: some View { + Button { + if let account = currentAccount.account { + routeurPath.navigate(to: .accountDetailWithAccount(account: account)) + } + } label: { + if let avatar = currentAccount.account?.avatar { + AvatarView(url: avatar, size: .badge) + } + } + .onAppear { + if accountsViewModel.isEmpty || appAccounts.availableAccounts.count != accountsViewModel.count { + accountsViewModel = [] + for account in appAccounts.availableAccounts { + let viewModel: AppAccountViewModel = .init(appAccount: account) + accountsViewModel.append(viewModel) + Task { + await viewModel.fetchAccount() + } + } + } + } + .contextMenu { + ForEach(accountsViewModel, id: \.appAccount.id) { viewModel in + Button { + appAccounts.currentAccount = viewModel.appAccount + } label: { + HStack { + if viewModel.account?.id == currentAccount.account?.id { + Image(systemName: "checkmark.circle.fill") + } + Text("\(viewModel.account?.displayName ?? "")") + } + } + } + Button { + isAddAccountSheetDisplayed = true + } label: { + Label("Add Account", systemImage: "person.badge.plus") + } + } + } private var addAccountButton: some View { @@ -69,8 +133,5 @@ struct TimelineTab: View { } label: { Image(systemName: "person.badge.plus") } - .sheet(isPresented: $isAddAccountSheetDisplayed) { - AddAccountView() - } } } diff --git a/Packages/Timeline/Sources/Timeline/TimelineFilter.swift b/Packages/Timeline/Sources/Timeline/TimelineFilter.swift index 50a86de6..3d0c4ef9 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineFilter.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineFilter.swift @@ -10,7 +10,10 @@ public enum TimelineFilter: Hashable, Equatable { hasher.combine(title()) } - public static func availableTimeline() -> [TimelineFilter] { + public static func availableTimeline(client: Client) -> [TimelineFilter] { + if !client.isAuth { + return [.pub, .local] + } return [.pub, .local, .home] } diff --git a/README.md b/README.md index 2085795c..46db27bc 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For contributors and myself, here is a todo list of features that could be added - [X] Light theme - [ ] More themes - [ ] Honor & display server side features (filter, default visibility, etc...) -- [ ] Open remote status locally +- [X] Open remote status locally - [ ] More context menu everywhere - [ ] Support pinned posts - [ ] Support IceCubesApp://any mastodon links