Timeline selection

This commit is contained in:
Justin Mazzocchi 2020-08-28 17:06:09 -07:00
parent c8b2defbb8
commit e5d7b0a12b
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
4 changed files with 101 additions and 26 deletions

View file

@ -38,3 +38,6 @@
"status.visibility.public" = "Public";
"status.visibility.unlisted" = "Unlisted";
"status.visibility.private" = "Private";
"timelines.home" = "Home";
"timelines.local" = "Local";
"timelines.federated" = "Federated";

View file

@ -2,7 +2,7 @@
import Foundation
enum Timeline {
enum Timeline: Identifiable {
case home
case local
case federated

View file

@ -6,7 +6,8 @@ import Combine
class TabNavigationViewModel: ObservableObject {
@Published private(set) var identity: Identity
@Published private(set) var recentIdentities = [Identity]()
@Published private(set) var timelineViewModel: StatusListViewModel
@Published private(set) var timeline = Timeline.home
@Published private(set) var timelinesAndLists = TabNavigationViewModel.timelines
@Published var presentingSecondaryNavigation = false
@Published var alertItem: AlertItem?
var selectedTab: Tab? = .timelines
@ -17,7 +18,6 @@ class TabNavigationViewModel: ObservableObject {
init(identityService: IdentityService) {
self.identityService = identityService
identity = identityService.identity
timelineViewModel = StatusListViewModel(statusListService: identityService.service(timeline: .home))
identityService.$identity.dropFirst().assign(to: &$identity)
identityService.recentIdentitiesObservation()
@ -27,6 +27,37 @@ class TabNavigationViewModel: ObservableObject {
}
extension TabNavigationViewModel {
var timelineSubtitle: String {
switch timeline {
case .home, .list:
return identity.handle
case .local, .federated:
return identity.instance?.uri ?? ""
}
}
func title(timeline: Timeline) -> String {
switch timeline {
case .home:
return NSLocalizedString("timelines.home", comment: "")
case .local:
return NSLocalizedString("timelines.local", comment: "")
case .federated:
return NSLocalizedString("timelines.federated", comment: "")
case let .list(list):
return list.title
}
}
func systemImageName(timeline: Timeline) -> String {
switch timeline {
case .home: return "house"
case .local: return "person.3"
case .federated: return "globe"
case .list: return "scroll"
}
}
func refreshIdentity() {
if identityService.isAuthorized {
identityService.verifyCredentials()
@ -51,6 +82,18 @@ extension TabNavigationViewModel {
func secondaryNavigationViewModel() -> SecondaryNavigationViewModel {
SecondaryNavigationViewModel(identityService: identityService)
}
func viewModel(timeline: Timeline) -> StatusListViewModel {
StatusListViewModel(statusListService: identityService.service(timeline: timeline))
}
func select(timeline: Timeline) {
self.timeline = timeline
}
}
private extension TabNavigationViewModel {
static let timelines: [Timeline] = [.home, .local, .federated]
}
extension TabNavigationViewModel {

View file

@ -40,36 +40,65 @@ private extension TabNavigationView {
func view(tab: TabNavigationViewModel.Tab) -> some View {
switch tab {
case .timelines:
StatusListView(viewModel: viewModel.timelineViewModel)
StatusListView(viewModel: viewModel.viewModel(timeline: viewModel.timeline))
.id(viewModel.timeline.id)
.edgesIgnoringSafeArea(.all)
.navigationBarTitle(viewModel.identity.handle, displayMode: .inline)
.navigationBarTitle(viewModel.title(timeline: viewModel.timeline), displayMode: .inline)
.toolbar {
ToolbarItem(placement: .principal) {
VStack {
Text(viewModel.title(timeline: viewModel.timeline))
.font(.headline)
Text(viewModel.timelineSubtitle)
.font(.footnote)
.foregroundColor(.secondary)
}
}
}
.navigationBarItems(
leading: Button {
viewModel.presentingSecondaryNavigation.toggle()
leading: secondaryNavigationButton,
trailing: Menu {
ForEach(viewModel.timelinesAndLists) { timeline in
Button {
viewModel.select(timeline: timeline)
} label: {
Label(viewModel.title(timeline: timeline),
systemImage: viewModel.systemImageName(timeline: timeline))
}
}
} label: {
KFImage(viewModel.identity.image,
options: .downsampled(dimension: 28, scaleFactor: displayScale))
.placeholder { Image(systemName: "gear") }
.renderingMode(.original)
.contextMenu(ContextMenu {
ForEach(viewModel.recentIdentities) { recentIdentity in
Button {
rootViewModel.newIdentitySelected(id: recentIdentity.id)
} label: {
Label(
title: { Text(recentIdentity.handle) },
icon: {
KFImage(recentIdentity.image,
options: .downsampled(dimension: 28, scaleFactor: displayScale))
.renderingMode(.original)
})
}
}
})
Image(systemName: viewModel.systemImageName(timeline: viewModel.timeline))
})
default: Text(tab.title)
}
}
@ViewBuilder
var secondaryNavigationButton: some View {
Button {
viewModel.presentingSecondaryNavigation.toggle()
} label: {
KFImage(viewModel.identity.image,
options: .downsampled(dimension: 28, scaleFactor: displayScale))
.placeholder { Image(systemName: "gear") }
.renderingMode(.original)
.contextMenu(ContextMenu {
ForEach(viewModel.recentIdentities) { recentIdentity in
Button {
rootViewModel.newIdentitySelected(id: recentIdentity.id)
} label: {
Label(
title: { Text(recentIdentity.handle) },
icon: {
KFImage(recentIdentity.image,
options: .downsampled(dimension: 28, scaleFactor: displayScale))
.renderingMode(.original)
})
}
}
})
}
}
}
#if DEBUG