Recently opened for sidebar navigation

This commit is contained in:
Arkadiusz Fal
2021-09-19 13:06:54 +02:00
parent 8571822f23
commit ee1cb924c9
16 changed files with 291 additions and 291 deletions

View File

@@ -1,5 +1,21 @@
import Defaults
extension Defaults.Keys {
#if os(tvOS)
static let layout = Key<ListingLayout>("listingLayout", default: .cells)
#endif
static let searchSortOrder = Key<SearchQuery.SortOrder>("searchSortOrder", default: .relevance)
static let searchDate = Key<SearchQuery.Date?>("searchDate")
static let searchDuration = Key<SearchQuery.Duration?>("searchDuration")
static let selectedPlaylistID = Key<String?>("selectedPlaylistID")
static let showingAddToPlaylist = Key<Bool>("showingAddToPlaylist", default: false)
static let videoIDToAddToPlaylist = Key<String?>("videoIDToAddToPlaylist")
static let recentlyOpened = Key<[RecentItem]>("recentlyOpened", default: [])
}
enum ListingLayout: String, CaseIterable, Identifiable, Defaults.Serializable {
case list, cells
@@ -16,18 +32,3 @@ enum ListingLayout: String, CaseIterable, Identifiable, Defaults.Serializable {
}
}
}
extension Defaults.Keys {
#if os(tvOS)
static let layout = Key<ListingLayout>("listingLayout", default: .cells)
#endif
static let searchQuery = Key<String>("searchQuery", default: "")
static let searchSortOrder = Key<SearchQuery.SortOrder>("searchSortOrder", default: .relevance)
static let searchDate = Key<SearchQuery.Date?>("searchDate")
static let searchDuration = Key<SearchQuery.Duration?>("searchDuration")
static let selectedPlaylistID = Key<String?>("selectedPlaylistID")
static let showingAddToPlaylist = Key<Bool>("showingAddToPlaylist", default: false)
static let videoIDToAddToPlaylist = Key<String?>("videoIDToAddToPlaylist")
}

View File

@@ -10,11 +10,7 @@ struct UnsubscribeAlertModifier: ViewModifier {
.alert(unsubscribeAlertTitle, isPresented: $navigationState.presentingUnsubscribeAlert) {
if let channel = navigationState.channelToUnsubscribe {
Button("Unsubscribe", role: .destructive) {
subscriptions.unsubscribe(channel.id) {
navigationState.openChannel(channel)
navigationState.tabSelection = .channel(channel.id)
navigationState.sidebarSectionChanged.toggle()
}
subscriptions.unsubscribe(channel.id)
}
}
}

View File

@@ -14,6 +14,7 @@ struct AppSidebarNavigation: View {
@EnvironmentObject<NavigationState> private var navigationState
@EnvironmentObject<Playlists> private var playlists
@EnvironmentObject<Recents> private var recents
@EnvironmentObject<SearchState> private var searchState
@EnvironmentObject<Subscriptions> private var subscriptions
@@ -66,6 +67,8 @@ struct AppSidebarNavigation: View {
query.query = self.searchQuery
}
recents.open(RecentItem(type: .query, identifier: self.searchQuery, title: self.searchQuery))
navigationState.tabSelection = .search
}
}
@@ -111,7 +114,7 @@ struct AppSidebarNavigation: View {
return Group {
mainNavigationLinks
AppSidebarRecentlyOpened(selection: selection)
AppSidebarRecents(selection: selection)
.id("recentlyOpened")
AppSidebarSubscriptions(selection: selection)
AppSidebarPlaylists(selection: selection)
@@ -130,7 +133,7 @@ struct AppSidebarNavigation: View {
}
NavigationLink(destination: LazyView(SubscriptionsView()), tag: TabSelection.subscriptions, selection: selection) {
Label("Subscriptions", systemImage: "star.circle.fill")
Label("Subscriptions", systemImage: "star.circle")
.accessibility(label: Text("Subscriptions"))
}

View File

@@ -1,54 +0,0 @@
import SwiftUI
struct AppSidebarRecentlyOpened: View {
@Binding var selection: TabSelection?
@EnvironmentObject<NavigationState> private var navigationState
@EnvironmentObject<Subscriptions> private var subscriptions
@State private var subscriptionsChanged = false
var body: some View {
Group {
if !recentlyOpened.isEmpty {
Section(header: Text("Recently Opened")) {
ForEach(recentlyOpened) { channel in
NavigationLink(tag: TabSelection.channel(channel.id), selection: $selection) {
LazyView(ChannelVideosView(channel))
} label: {
HStack {
Label(channel.name, systemImage: AppSidebarNavigation.symbolSystemImage(channel.name))
Spacer()
Button(action: { navigationState.closeChannel(channel) }) {
Image(systemName: "xmark.circle.fill")
}
.foregroundColor(.secondary)
.buttonStyle(.plain)
}
}
// force recalculating the view on change of subscriptions
.opacity(subscriptionsChanged ? 1 : 1)
.id(channel.id)
.contextMenu {
Button("Subscribe") {
subscriptions.subscribe(channel.id) {
navigationState.sidebarSectionChanged.toggle()
}
}
}
}
}
.onChange(of: subscriptions.all) { _ in
subscriptionsChanged.toggle()
}
}
}
}
var recentlyOpened: [Channel] {
navigationState.openChannels.filter { !subscriptions.all.contains($0) }
}
}

View File

@@ -0,0 +1,91 @@
import Defaults
import SwiftUI
struct AppSidebarRecents: View {
@Binding var selection: TabSelection?
@EnvironmentObject<NavigationState> private var navigationState
@EnvironmentObject<Recents> private var recents
@Default(.recentlyOpened) private var recentItems
var body: some View {
Group {
if !recentItems.isEmpty {
Section(header: Text("Recents")) {
ForEach(recentItems) { recent in
Group {
switch recent.type {
case .channel:
RecentNavigationLink(recent: recent, selection: $selection) {
LazyView(ChannelVideosView(Channel(id: recent.id, name: recent.title)))
}
case .query:
RecentNavigationLink(recent: recent, selection: $selection, systemImage: "magnifyingglass") {
LazyView(SearchView(recent.query!))
}
}
}
.contextMenu {
Button("Clear All Recents") {
recents.clear()
}
Button("Clear Search History") {
recents.clearQueries()
}
.disabled(!recentItems.contains { $0.type == .query })
}
}
}
}
}
}
}
struct RecentNavigationLink<DestinationContent: View>: View {
@EnvironmentObject<Recents> private var recents
var recent: RecentItem
@Binding var selection: TabSelection?
var systemImage: String?
let destination: DestinationContent
init(
recent: RecentItem,
selection: Binding<TabSelection?>,
systemImage: String? = nil,
@ViewBuilder destination: () -> DestinationContent
) {
self.recent = recent
_selection = selection
self.systemImage = systemImage
self.destination = destination()
}
var body: some View {
NavigationLink(tag: TabSelection.recentlyOpened(recent.tag), selection: $selection) {
destination
} label: {
HStack {
Label(recent.title, systemImage: labelSystemImage)
Spacer()
Button(action: {
recents.close(recent)
}) {
Image(systemName: "xmark.circle.fill")
}
.foregroundColor(.secondary)
.buttonStyle(.plain)
}
}
.id(recent.tag)
}
var labelSystemImage: String {
systemImage != nil ? systemImage! : AppSidebarNavigation.symbolSystemImage(recent.title)
}
}

View File

@@ -5,6 +5,8 @@ struct AppTabNavigation: View {
@EnvironmentObject<NavigationState> private var navigationState
@EnvironmentObject<SearchState> private var searchState
@EnvironmentObject<Recents> private var recents
@State private var searchQuery = ""
var body: some View {
@@ -82,18 +84,17 @@ struct AppTabNavigation: View {
.tag(TabSelection.search)
}
.sheet(isPresented: $navigationState.isChannelOpen, onDismiss: {
navigationState.closeChannel(presentedChannel)
if let channel = recents.presentedChannel {
let recent = RecentItem(from: channel)
recents.close(recent)
}
}) {
if presentedChannel != nil {
if recents.presentedChannel != nil {
NavigationView {
ChannelVideosView(presentedChannel)
ChannelVideosView(recents.presentedChannel!)
.environment(\.inNavigationView, true)
}
}
}
}
fileprivate var presentedChannel: Channel! {
navigationState.openChannels.first
}
}

View File

@@ -3,9 +3,10 @@ import SwiftUI
struct ContentView: View {
@StateObject private var navigationState = NavigationState()
@StateObject private var playbackState = PlaybackState()
@StateObject private var playlists = Playlists()
@StateObject private var recents = Recents()
@StateObject private var searchState = SearchState()
@StateObject private var subscriptions = Subscriptions()
@StateObject private var playlists = Playlists()
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@@ -44,9 +45,10 @@ struct ContentView: View {
#endif
.environmentObject(navigationState)
.environmentObject(playbackState)
.environmentObject(playlists)
.environmentObject(recents)
.environmentObject(searchState)
.environmentObject(subscriptions)
.environmentObject(playlists)
}
}

View File

@@ -85,8 +85,6 @@ struct VideoPlayerView: View {
.onDisappear {
resource.removeObservers(ownedBy: store)
resource.invalidate()
navigationState.showingVideoDetails = navigationState.returnToDetails
}
#if os(macOS)
.frame(maxWidth: 1000, minHeight: 700)

View File

@@ -3,13 +3,18 @@ import Siesta
import SwiftUI
struct SearchView: View {
@Default(.searchQuery) private var queryText
@Default(.searchSortOrder) private var searchSortOrder
@Default(.searchDate) private var searchDate
@Default(.searchDuration) private var searchDuration
@EnvironmentObject<SearchState> private var state
private var query: SearchQuery?
init(_ query: SearchQuery? = nil) {
self.query = query
}
var body: some View {
VStack {
VideosView(videos: state.store.collection)
@@ -27,11 +32,8 @@ struct SearchView: View {
}
}
.onAppear {
state.changeQuery { query in
query.query = queryText
query.sortBy = searchSortOrder
query.date = searchDate
query.duration = searchDuration
if query != nil {
state.resetQuery(query!)
}
}
.onChange(of: state.query.query) { queryText in

View File

@@ -3,6 +3,7 @@ import SwiftUI
struct VideoContextMenuView: View {
@EnvironmentObject<NavigationState> private var navigationState
@EnvironmentObject<Recents> private var recents
@EnvironmentObject<Subscriptions> private var subscriptions
let video: Video
@@ -14,15 +15,11 @@ struct VideoContextMenuView: View {
var body: some View {
Section {
if navigationState.showOpenChannel(video.channel.id) {
openChannelButton
}
openChannelButton
subscriptionButton
.opacity(subscribed ? 1 : 1)
openVideoDetailsButton
if navigationState.tabSelection == .playlists {
removeFromPlaylistButton
} else {
@@ -33,8 +30,10 @@ struct VideoContextMenuView: View {
var openChannelButton: some View {
Button("\(video.author) Channel") {
navigationState.openChannel(video.channel)
navigationState.tabSelection = .channel(video.channel.id)
let recent = RecentItem(from: video.channel)
recents.open(recent)
navigationState.tabSelection = .recentlyOpened(recent.tag)
navigationState.isChannelOpen = true
navigationState.sidebarSectionChanged.toggle()
}
}
@@ -59,12 +58,6 @@ struct VideoContextMenuView: View {
}
}
var openVideoDetailsButton: some View {
Button("Open video details") {
navigationState.openVideoDetails(video)
}
}
var addToPlaylistButton: some View {
Button("Add to playlist...") {
videoIDToAddToPlaylist = video.id