mirror of
https://github.com/yattee/yattee.git
synced 2025-08-06 10:44:06 +00:00
Recently opened for sidebar navigation
This commit is contained in:
@@ -3,12 +3,11 @@ import SwiftUI
|
||||
|
||||
final class NavigationState: ObservableObject {
|
||||
enum TabSelection: Hashable {
|
||||
case watchNow, subscriptions, popular, trending, playlists, channel(String), playlist(String), search
|
||||
case watchNow, subscriptions, popular, trending, playlists, channel(String), playlist(String), recentlyOpened(String), search
|
||||
}
|
||||
|
||||
@Published var tabSelection: TabSelection = .watchNow
|
||||
|
||||
@Published var showingVideoDetails = false
|
||||
@Published var showingVideo = false
|
||||
@Published var video: Video?
|
||||
|
||||
@@ -20,56 +19,14 @@ final class NavigationState: ObservableObject {
|
||||
@Published var presentingUnsubscribeAlert = false
|
||||
@Published var channelToUnsubscribe: Channel!
|
||||
|
||||
@Published var openChannels = Set<Channel>()
|
||||
@Published var isChannelOpen = false
|
||||
@Published var sidebarSectionChanged = false
|
||||
|
||||
func openChannel(_ channel: Channel) {
|
||||
openChannels.insert(channel)
|
||||
|
||||
isChannelOpen = true
|
||||
}
|
||||
|
||||
func closeChannel(_ channel: Channel) {
|
||||
guard openChannels.remove(channel) != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
isChannelOpen = !openChannels.isEmpty
|
||||
|
||||
if tabSelection == .channel(channel.id) {
|
||||
tabSelection = .subscriptions
|
||||
}
|
||||
}
|
||||
|
||||
func showOpenChannel(_ id: Channel.ID) -> Bool {
|
||||
if case .channel = tabSelection {
|
||||
return false
|
||||
} else {
|
||||
return !openChannels.contains { $0.id == id }
|
||||
}
|
||||
}
|
||||
|
||||
func openVideoDetails(_ video: Video) {
|
||||
self.video = video
|
||||
showingVideoDetails = true
|
||||
}
|
||||
|
||||
func closeVideoDetails() {
|
||||
showingVideoDetails = false
|
||||
video = nil
|
||||
}
|
||||
|
||||
func playVideo(_ video: Video) {
|
||||
self.video = video
|
||||
showingVideo = true
|
||||
}
|
||||
|
||||
func showVideoDetailsIfNeeded() {
|
||||
showingVideoDetails = returnToDetails
|
||||
returnToDetails = false
|
||||
}
|
||||
|
||||
var tabSelectionOptionalBinding: Binding<TabSelection?> {
|
||||
Binding<TabSelection?>(
|
||||
get: {
|
||||
|
116
Model/Recents.swift
Normal file
116
Model/Recents.swift
Normal file
@@ -0,0 +1,116 @@
|
||||
import Defaults
|
||||
import Foundation
|
||||
|
||||
final class Recents: ObservableObject {
|
||||
@Default(.recentlyOpened) var items
|
||||
|
||||
var isEmpty: Bool {
|
||||
items.isEmpty
|
||||
}
|
||||
|
||||
func clear() {
|
||||
items = []
|
||||
}
|
||||
|
||||
func clearQueries() {
|
||||
items.removeAll { $0.type == .query }
|
||||
}
|
||||
|
||||
func open(_ item: RecentItem) {
|
||||
if !items.contains(where: { $0.id == item.id }) {
|
||||
items.append(item)
|
||||
}
|
||||
}
|
||||
|
||||
func close(_ item: RecentItem) {
|
||||
if let index = items.firstIndex(where: { $0.id == item.id }) {
|
||||
items.remove(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
var presentedChannel: Channel? {
|
||||
if let recent = items.last(where: { $0.type == .channel }) {
|
||||
return recent.channel
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
struct RecentItem: Defaults.Serializable, Identifiable {
|
||||
static var bridge = RecentItemBridge()
|
||||
|
||||
enum ItemType: String {
|
||||
case channel, query
|
||||
}
|
||||
|
||||
var type: ItemType
|
||||
var id: String
|
||||
var title: String
|
||||
|
||||
var tag: String {
|
||||
"recent\(type.rawValue.capitalized)\(id)"
|
||||
}
|
||||
|
||||
var query: SearchQuery? {
|
||||
guard type == .query else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return SearchQuery(query: title)
|
||||
}
|
||||
|
||||
var channel: Channel? {
|
||||
guard type == .channel else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return Channel(id: id, name: title)
|
||||
}
|
||||
|
||||
init(type: ItemType, identifier: String, title: String) {
|
||||
self.type = type
|
||||
id = identifier
|
||||
self.title = title
|
||||
}
|
||||
|
||||
init(from channel: Channel) {
|
||||
type = .channel
|
||||
id = channel.id
|
||||
title = channel.name
|
||||
}
|
||||
}
|
||||
|
||||
struct RecentItemBridge: Defaults.Bridge {
|
||||
typealias Value = RecentItem
|
||||
typealias Serializable = [String: String]
|
||||
|
||||
func serialize(_ value: Value?) -> Serializable? {
|
||||
guard let value = value else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return [
|
||||
"type": value.type.rawValue,
|
||||
"identifier": value.id,
|
||||
"title": value.title
|
||||
]
|
||||
}
|
||||
|
||||
func deserialize(_ object: Serializable?) -> RecentItem? {
|
||||
guard
|
||||
let object = object,
|
||||
let type = object["type"],
|
||||
let identifier = object["identifier"],
|
||||
let title = object["title"]
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return RecentItem(
|
||||
type: .init(rawValue: type)!,
|
||||
identifier: identifier,
|
||||
title: title
|
||||
)
|
||||
}
|
||||
}
|
@@ -8,14 +8,11 @@ final class SearchState: ObservableObject {
|
||||
|
||||
@Published var querySuggestions = Store<[String]>()
|
||||
|
||||
@Default(.searchQuery) private var queryText
|
||||
|
||||
private var previousResource: Resource?
|
||||
private var resource: Resource!
|
||||
|
||||
init() {
|
||||
let newQuery = query
|
||||
newQuery.query = queryText
|
||||
query = newQuery
|
||||
|
||||
resource = InvidiousAPI.shared.search(newQuery)
|
||||
@@ -53,7 +50,23 @@ final class SearchState: ObservableObject {
|
||||
previousResource?.removeObservers(ownedBy: store)
|
||||
previousResource = newResource
|
||||
|
||||
queryText = query.query
|
||||
resource = newResource
|
||||
resource.addObserver(store)
|
||||
loadResourceIfNeededAndReplaceStore()
|
||||
}
|
||||
|
||||
func resetQuery(_ query: SearchQuery) {
|
||||
self.query = query
|
||||
|
||||
let newResource = InvidiousAPI.shared.search(query)
|
||||
guard newResource != previousResource else {
|
||||
return
|
||||
}
|
||||
|
||||
store.replace([])
|
||||
|
||||
previousResource?.removeObservers(ownedBy: store)
|
||||
previousResource = newResource
|
||||
|
||||
resource = newResource
|
||||
resource.addObserver(store)
|
||||
|
Reference in New Issue
Block a user