Timeline selection
This commit is contained in:
parent
c8b2defbb8
commit
e5d7b0a12b
|
@ -38,3 +38,6 @@
|
||||||
"status.visibility.public" = "Public";
|
"status.visibility.public" = "Public";
|
||||||
"status.visibility.unlisted" = "Unlisted";
|
"status.visibility.unlisted" = "Unlisted";
|
||||||
"status.visibility.private" = "Private";
|
"status.visibility.private" = "Private";
|
||||||
|
"timelines.home" = "Home";
|
||||||
|
"timelines.local" = "Local";
|
||||||
|
"timelines.federated" = "Federated";
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum Timeline {
|
enum Timeline: Identifiable {
|
||||||
case home
|
case home
|
||||||
case local
|
case local
|
||||||
case federated
|
case federated
|
||||||
|
|
|
@ -6,7 +6,8 @@ import Combine
|
||||||
class TabNavigationViewModel: ObservableObject {
|
class TabNavigationViewModel: ObservableObject {
|
||||||
@Published private(set) var identity: Identity
|
@Published private(set) var identity: Identity
|
||||||
@Published private(set) var recentIdentities = [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 presentingSecondaryNavigation = false
|
||||||
@Published var alertItem: AlertItem?
|
@Published var alertItem: AlertItem?
|
||||||
var selectedTab: Tab? = .timelines
|
var selectedTab: Tab? = .timelines
|
||||||
|
@ -17,7 +18,6 @@ class TabNavigationViewModel: ObservableObject {
|
||||||
init(identityService: IdentityService) {
|
init(identityService: IdentityService) {
|
||||||
self.identityService = identityService
|
self.identityService = identityService
|
||||||
identity = identityService.identity
|
identity = identityService.identity
|
||||||
timelineViewModel = StatusListViewModel(statusListService: identityService.service(timeline: .home))
|
|
||||||
identityService.$identity.dropFirst().assign(to: &$identity)
|
identityService.$identity.dropFirst().assign(to: &$identity)
|
||||||
|
|
||||||
identityService.recentIdentitiesObservation()
|
identityService.recentIdentitiesObservation()
|
||||||
|
@ -27,6 +27,37 @@ class TabNavigationViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TabNavigationViewModel {
|
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() {
|
func refreshIdentity() {
|
||||||
if identityService.isAuthorized {
|
if identityService.isAuthorized {
|
||||||
identityService.verifyCredentials()
|
identityService.verifyCredentials()
|
||||||
|
@ -51,6 +82,18 @@ extension TabNavigationViewModel {
|
||||||
func secondaryNavigationViewModel() -> SecondaryNavigationViewModel {
|
func secondaryNavigationViewModel() -> SecondaryNavigationViewModel {
|
||||||
SecondaryNavigationViewModel(identityService: identityService)
|
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 {
|
extension TabNavigationViewModel {
|
||||||
|
|
|
@ -40,36 +40,65 @@ private extension TabNavigationView {
|
||||||
func view(tab: TabNavigationViewModel.Tab) -> some View {
|
func view(tab: TabNavigationViewModel.Tab) -> some View {
|
||||||
switch tab {
|
switch tab {
|
||||||
case .timelines:
|
case .timelines:
|
||||||
StatusListView(viewModel: viewModel.timelineViewModel)
|
StatusListView(viewModel: viewModel.viewModel(timeline: viewModel.timeline))
|
||||||
|
.id(viewModel.timeline.id)
|
||||||
.edgesIgnoringSafeArea(.all)
|
.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(
|
.navigationBarItems(
|
||||||
leading: Button {
|
leading: secondaryNavigationButton,
|
||||||
viewModel.presentingSecondaryNavigation.toggle()
|
trailing: Menu {
|
||||||
|
ForEach(viewModel.timelinesAndLists) { timeline in
|
||||||
|
Button {
|
||||||
|
viewModel.select(timeline: timeline)
|
||||||
|
} label: {
|
||||||
|
Label(viewModel.title(timeline: timeline),
|
||||||
|
systemImage: viewModel.systemImageName(timeline: timeline))
|
||||||
|
}
|
||||||
|
}
|
||||||
} label: {
|
} label: {
|
||||||
KFImage(viewModel.identity.image,
|
Image(systemName: viewModel.systemImageName(timeline: viewModel.timeline))
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
default: Text(tab.title)
|
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
|
#if DEBUG
|
||||||
|
|
Loading…
Reference in New Issue