diff --git a/Model/NavigationModel.swift b/Model/NavigationModel.swift index 11a85316..493448c0 100644 --- a/Model/NavigationModel.swift +++ b/Model/NavigationModel.swift @@ -46,7 +46,8 @@ final class NavigationModel: ObservableObject { player: PlayerModel, recents: RecentsModel, navigation: NavigationModel, - navigationStyle: NavigationStyle + navigationStyle: NavigationStyle, + delay: Bool = false ) { let recent = RecentItem(from: channel) #if os(macOS) @@ -61,7 +62,46 @@ final class NavigationModel: ObservableObject { } if navigationStyle == .tab { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + if delay { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + openRecent() + } + } else { + openRecent() + } + } else if navigationStyle == .sidebar { + openRecent() + navigation.sidebarSectionChanged.toggle() + navigation.tabSelection = .recentlyOpened(recent.tag) + } + } + + static func openChannelPlaylist( + _ playlist: ChannelPlaylist, + player: PlayerModel, + recents: RecentsModel, + navigation: NavigationModel, + navigationStyle: NavigationStyle, + delay: Bool = false + ) { + let recent = RecentItem(from: playlist) + #if os(macOS) + Windows.main.open() + #else + player.hide() + #endif + + let openRecent = { + recents.add(recent) + navigation.presentingPlaylist = true + } + + if navigationStyle == .tab { + if delay { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + openRecent() + } + } else { openRecent() } } else if navigationStyle == .sidebar { diff --git a/Model/RecentsModel.swift b/Model/RecentsModel.swift index 9412d699..3f2a9ddc 100644 --- a/Model/RecentsModel.swift +++ b/Model/RecentsModel.swift @@ -55,6 +55,15 @@ final class RecentsModel: ObservableObject { return nil } + + static func symbolSystemImage(_ name: String) -> String { + let firstLetter = name.first?.lowercased() + let regex = #"^[a-z0-9]$"# + + let symbolName = firstLetter?.range(of: regex, options: .regularExpression) != nil ? firstLetter! : "questionmark" + + return "\(symbolName).circle" + } } struct RecentItem: Defaults.Serializable, Identifiable { diff --git a/Model/Search/SearchModel.swift b/Model/Search/SearchModel.swift index 6419bdb6..3758a0c9 100644 --- a/Model/Search/SearchModel.swift +++ b/Model/Search/SearchModel.swift @@ -78,6 +78,7 @@ final class SearchModel: ObservableObject { func loadSuggestions(_ query: String) { guard !query.isEmpty else { + querySuggestions.replace([]) return } diff --git a/Shared/Navigation/AppSidebarNavigation.swift b/Shared/Navigation/AppSidebarNavigation.swift index 034b0ad9..ff8aa5e2 100644 --- a/Shared/Navigation/AppSidebarNavigation.swift +++ b/Shared/Navigation/AppSidebarNavigation.swift @@ -120,13 +120,4 @@ struct AppSidebarNavigation: View { return .automatic #endif } - - static func symbolSystemImage(_ name: String) -> String { - let firstLetter = name.first?.lowercased() - let regex = #"^[a-z0-9]$"# - - let symbolName = firstLetter?.range(of: regex, options: .regularExpression) != nil ? firstLetter! : "questionmark" - - return "\(symbolName).circle" - } } diff --git a/Shared/Navigation/AppSidebarPlaylists.swift b/Shared/Navigation/AppSidebarPlaylists.swift index 313155df..69342351 100644 --- a/Shared/Navigation/AppSidebarPlaylists.swift +++ b/Shared/Navigation/AppSidebarPlaylists.swift @@ -11,7 +11,7 @@ struct AppSidebarPlaylists: View { NavigationLink(tag: TabSelection.playlist(playlist.id), selection: $navigation.tabSelection) { LazyView(PlaylistVideosView(playlist)) } label: { - Label(playlist.title, systemImage: AppSidebarNavigation.symbolSystemImage(playlist.title)) + Label(playlist.title, systemImage: RecentsModel.symbolSystemImage(playlist.title)) .backport .badge(Text("\(playlist.videos.count)")) } diff --git a/Shared/Navigation/AppSidebarRecents.swift b/Shared/Navigation/AppSidebarRecents.swift index 513fc32a..e99ee77b 100644 --- a/Shared/Navigation/AppSidebarRecents.swift +++ b/Shared/Navigation/AppSidebarRecents.swift @@ -88,6 +88,6 @@ struct RecentNavigationLink: View { } var labelSystemImage: String { - systemImage != nil ? systemImage! : AppSidebarNavigation.symbolSystemImage(recent.title) + systemImage != nil ? systemImage! : RecentsModel.symbolSystemImage(recent.title) } } diff --git a/Shared/Navigation/AppSidebarSubscriptions.swift b/Shared/Navigation/AppSidebarSubscriptions.swift index 80063e11..2ad3aacd 100644 --- a/Shared/Navigation/AppSidebarSubscriptions.swift +++ b/Shared/Navigation/AppSidebarSubscriptions.swift @@ -11,7 +11,7 @@ struct AppSidebarSubscriptions: View { NavigationLink(tag: TabSelection.channel(channel.id), selection: $navigation.tabSelection) { LazyView(ChannelVideosView(channel: channel)) } label: { - Label(channel.name, systemImage: AppSidebarNavigation.symbolSystemImage(channel.name)) + Label(channel.name, systemImage: RecentsModel.symbolSystemImage(channel.name)) } .contextMenu { Button("Unsubscribe") { diff --git a/Shared/Navigation/AppTabNavigation.swift b/Shared/Navigation/AppTabNavigation.swift index 273aea20..160353e5 100644 --- a/Shared/Navigation/AppTabNavigation.swift +++ b/Shared/Navigation/AppTabNavigation.swift @@ -15,6 +15,8 @@ struct AppTabNavigation: View { @Default(.visibleSections) private var visibleSections + let persistenceController = PersistenceController.shared + var body: some View { TabView(selection: navigation.tabSelectionBinding) { if visibleSections.contains(.favorites) { @@ -42,14 +44,11 @@ struct AppTabNavigation: View { .id(accounts.current?.id ?? "") .environment(\.navigationStyle, .tab) .background( - EmptyView().sheet(isPresented: $navigation.presentingChannel, onDismiss: { - if let channel = recents.presentedChannel { - recents.close(RecentItem(from: channel)) - } - }) { + EmptyView().sheet(isPresented: $navigation.presentingChannel) { if let channel = recents.presentedChannel { NavigationView { ChannelVideosView(channel: channel) + .environment(\.managedObjectContext, persistenceController.container.viewContext) .environment(\.inChannelView, true) .environment(\.inNavigationView, true) .environmentObject(accounts) @@ -64,14 +63,11 @@ struct AppTabNavigation: View { } ) .background( - EmptyView().sheet(isPresented: $navigation.presentingPlaylist, onDismiss: { - if let playlist = recents.presentedPlaylist { - recents.close(RecentItem(from: playlist)) - } - }) { + EmptyView().sheet(isPresented: $navigation.presentingPlaylist) { if let playlist = recents.presentedPlaylist { NavigationView { ChannelPlaylistView(playlist: playlist) + .environment(\.managedObjectContext, persistenceController.container.viewContext) .environment(\.inNavigationView, true) .environmentObject(accounts) .environmentObject(navigation) @@ -87,6 +83,7 @@ struct AppTabNavigation: View { .background( EmptyView().fullScreenCover(isPresented: $player.presentingPlayer) { videoPlayer + .environment(\.managedObjectContext, persistenceController.container.viewContext) .environment(\.navigationStyle, .tab) } ) diff --git a/Shared/Search/SearchView.swift b/Shared/Search/SearchView.swift index 97da196b..6c5e0eaf 100644 --- a/Shared/Search/SearchView.swift +++ b/Shared/Search/SearchView.swift @@ -21,6 +21,8 @@ struct SearchView: View { @Environment(\.navigationStyle) private var navigationStyle @EnvironmentObject private var accounts + @EnvironmentObject private var navigation + @EnvironmentObject private var player @EnvironmentObject private var recents @EnvironmentObject private var state private var favorites = FavoritesModel.shared @@ -255,14 +257,51 @@ struct SearchView: View { .foregroundColor(.secondary) } ForEach(recentItems) { item in - Button(item.title) { - state.queryText = item.title - state.changeQuery { query in query.query = item.title } - updateFavoriteItem() + Button { + switch item.type { + case .query: + state.queryText = item.title + state.changeQuery { query in query.query = item.title } + + updateFavoriteItem() + recents.add(item) + case .channel: + guard let channel = item.channel else { + return + } + + NavigationModel.openChannel( + channel, + player: player, + recents: recents, + navigation: navigation, + navigationStyle: navigationStyle, + delay: false + ) + case .playlist: + guard let playlist = item.playlist else { + return + } + + NavigationModel.openChannelPlaylist( + playlist, + player: player, + recents: recents, + navigation: navigation, + navigationStyle: navigationStyle, + delay: false + ) + } + } label: { + let systemImage = item.type == .query ? "magnifyingglass" : + item.type == .channel ? RecentsModel.symbolSystemImage(item.title) : + "list.and.film" + Label(item.title, systemImage: systemImage) + .lineLimit(1) } .contextMenu { - deleteButton(item) - deleteAllButton + removeButton(item) + removeAllButton } } } @@ -274,21 +313,21 @@ struct SearchView: View { #endif } - private func deleteButton(_ item: RecentItem) -> some View { + private func removeButton(_ item: RecentItem) -> some View { Button { recents.close(item) recentsChanged.toggle() } label: { - Label("Delete", systemImage: "trash") + Label("Remove", systemImage: "trash") } } - private var deleteAllButton: some View { + private var removeAllButton: some View { Button { recents.clearQueries() recentsChanged.toggle() } label: { - Label("Delete All", systemImage: "trash.fill") + Label("Remove All", systemImage: "trash.fill") } } @@ -297,7 +336,7 @@ struct SearchView: View { } private var recentItems: [RecentItem] { - Defaults[.recentlyOpened].filter { $0.type == .query }.reversed() + Defaults[.recentlyOpened].reversed() } private var searchSortOrderPicker: some View { diff --git a/Yattee.xcodeproj/project.pbxproj b/Yattee.xcodeproj/project.pbxproj index 2965d0d2..83553f6a 100644 --- a/Yattee.xcodeproj/project.pbxproj +++ b/Yattee.xcodeproj/project.pbxproj @@ -2726,7 +2726,7 @@ INFOPLIST_FILE = iOS/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UIRequiresFullScreen = YES; + INFOPLIST_KEY_UIRequiresFullScreen = NO; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; @@ -2758,7 +2758,7 @@ INFOPLIST_FILE = iOS/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UIRequiresFullScreen = YES; + INFOPLIST_KEY_UIRequiresFullScreen = NO; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; diff --git a/macOS/InstancesSettings.swift b/macOS/InstancesSettings.swift index 0e505a6e..c773fb7f 100644 --- a/macOS/InstancesSettings.swift +++ b/macOS/InstancesSettings.swift @@ -67,7 +67,7 @@ struct InstancesSettings: View { "Are you sure you want to remove \(selectedAccount?.description ?? "") account?" ), message: Text("This cannot be undone"), - primaryButton: .destructive(Text("Delete")) { + primaryButton: .destructive(Text("Remove")) { AccountsModel.remove(selectedAccount!) }, secondaryButton: .cancel()