mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Show recent channels/playlists in search in tab navigation
This commit is contained in:
parent
f29dc792c2
commit
3495ecf693
@ -46,7 +46,8 @@ final class NavigationModel: ObservableObject {
|
|||||||
player: PlayerModel,
|
player: PlayerModel,
|
||||||
recents: RecentsModel,
|
recents: RecentsModel,
|
||||||
navigation: NavigationModel,
|
navigation: NavigationModel,
|
||||||
navigationStyle: NavigationStyle
|
navigationStyle: NavigationStyle,
|
||||||
|
delay: Bool = false
|
||||||
) {
|
) {
|
||||||
let recent = RecentItem(from: channel)
|
let recent = RecentItem(from: channel)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ -61,9 +62,48 @@ final class NavigationModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if navigationStyle == .tab {
|
if navigationStyle == .tab {
|
||||||
|
if delay {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
openRecent()
|
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 {
|
} else if navigationStyle == .sidebar {
|
||||||
openRecent()
|
openRecent()
|
||||||
navigation.sidebarSectionChanged.toggle()
|
navigation.sidebarSectionChanged.toggle()
|
||||||
|
@ -55,6 +55,15 @@ final class RecentsModel: ObservableObject {
|
|||||||
|
|
||||||
return nil
|
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 {
|
struct RecentItem: Defaults.Serializable, Identifiable {
|
||||||
|
@ -78,6 +78,7 @@ final class SearchModel: ObservableObject {
|
|||||||
|
|
||||||
func loadSuggestions(_ query: String) {
|
func loadSuggestions(_ query: String) {
|
||||||
guard !query.isEmpty else {
|
guard !query.isEmpty else {
|
||||||
|
querySuggestions.replace([])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,13 +120,4 @@ struct AppSidebarNavigation: View {
|
|||||||
return .automatic
|
return .automatic
|
||||||
#endif
|
#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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ struct AppSidebarPlaylists: View {
|
|||||||
NavigationLink(tag: TabSelection.playlist(playlist.id), selection: $navigation.tabSelection) {
|
NavigationLink(tag: TabSelection.playlist(playlist.id), selection: $navigation.tabSelection) {
|
||||||
LazyView(PlaylistVideosView(playlist))
|
LazyView(PlaylistVideosView(playlist))
|
||||||
} label: {
|
} label: {
|
||||||
Label(playlist.title, systemImage: AppSidebarNavigation.symbolSystemImage(playlist.title))
|
Label(playlist.title, systemImage: RecentsModel.symbolSystemImage(playlist.title))
|
||||||
.backport
|
.backport
|
||||||
.badge(Text("\(playlist.videos.count)"))
|
.badge(Text("\(playlist.videos.count)"))
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,6 @@ struct RecentNavigationLink<DestinationContent: View>: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var labelSystemImage: String {
|
var labelSystemImage: String {
|
||||||
systemImage != nil ? systemImage! : AppSidebarNavigation.symbolSystemImage(recent.title)
|
systemImage != nil ? systemImage! : RecentsModel.symbolSystemImage(recent.title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ struct AppSidebarSubscriptions: View {
|
|||||||
NavigationLink(tag: TabSelection.channel(channel.id), selection: $navigation.tabSelection) {
|
NavigationLink(tag: TabSelection.channel(channel.id), selection: $navigation.tabSelection) {
|
||||||
LazyView(ChannelVideosView(channel: channel))
|
LazyView(ChannelVideosView(channel: channel))
|
||||||
} label: {
|
} label: {
|
||||||
Label(channel.name, systemImage: AppSidebarNavigation.symbolSystemImage(channel.name))
|
Label(channel.name, systemImage: RecentsModel.symbolSystemImage(channel.name))
|
||||||
}
|
}
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
Button("Unsubscribe") {
|
Button("Unsubscribe") {
|
||||||
|
@ -15,6 +15,8 @@ struct AppTabNavigation: View {
|
|||||||
|
|
||||||
@Default(.visibleSections) private var visibleSections
|
@Default(.visibleSections) private var visibleSections
|
||||||
|
|
||||||
|
let persistenceController = PersistenceController.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TabView(selection: navigation.tabSelectionBinding) {
|
TabView(selection: navigation.tabSelectionBinding) {
|
||||||
if visibleSections.contains(.favorites) {
|
if visibleSections.contains(.favorites) {
|
||||||
@ -42,14 +44,11 @@ struct AppTabNavigation: View {
|
|||||||
.id(accounts.current?.id ?? "")
|
.id(accounts.current?.id ?? "")
|
||||||
.environment(\.navigationStyle, .tab)
|
.environment(\.navigationStyle, .tab)
|
||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingChannel, onDismiss: {
|
EmptyView().sheet(isPresented: $navigation.presentingChannel) {
|
||||||
if let channel = recents.presentedChannel {
|
|
||||||
recents.close(RecentItem(from: channel))
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
if let channel = recents.presentedChannel {
|
if let channel = recents.presentedChannel {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
ChannelVideosView(channel: channel)
|
ChannelVideosView(channel: channel)
|
||||||
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environment(\.inChannelView, true)
|
.environment(\.inChannelView, true)
|
||||||
.environment(\.inNavigationView, true)
|
.environment(\.inNavigationView, true)
|
||||||
.environmentObject(accounts)
|
.environmentObject(accounts)
|
||||||
@ -64,14 +63,11 @@ struct AppTabNavigation: View {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingPlaylist, onDismiss: {
|
EmptyView().sheet(isPresented: $navigation.presentingPlaylist) {
|
||||||
if let playlist = recents.presentedPlaylist {
|
|
||||||
recents.close(RecentItem(from: playlist))
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
if let playlist = recents.presentedPlaylist {
|
if let playlist = recents.presentedPlaylist {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
ChannelPlaylistView(playlist: playlist)
|
ChannelPlaylistView(playlist: playlist)
|
||||||
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environment(\.inNavigationView, true)
|
.environment(\.inNavigationView, true)
|
||||||
.environmentObject(accounts)
|
.environmentObject(accounts)
|
||||||
.environmentObject(navigation)
|
.environmentObject(navigation)
|
||||||
@ -87,6 +83,7 @@ struct AppTabNavigation: View {
|
|||||||
.background(
|
.background(
|
||||||
EmptyView().fullScreenCover(isPresented: $player.presentingPlayer) {
|
EmptyView().fullScreenCover(isPresented: $player.presentingPlayer) {
|
||||||
videoPlayer
|
videoPlayer
|
||||||
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environment(\.navigationStyle, .tab)
|
.environment(\.navigationStyle, .tab)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,8 @@ struct SearchView: View {
|
|||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
|
@EnvironmentObject<NavigationModel> private var navigation
|
||||||
|
@EnvironmentObject<PlayerModel> private var player
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
@EnvironmentObject<RecentsModel> private var recents
|
||||||
@EnvironmentObject<SearchModel> private var state
|
@EnvironmentObject<SearchModel> private var state
|
||||||
private var favorites = FavoritesModel.shared
|
private var favorites = FavoritesModel.shared
|
||||||
@ -255,14 +257,51 @@ struct SearchView: View {
|
|||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
ForEach(recentItems) { item in
|
ForEach(recentItems) { item in
|
||||||
Button(item.title) {
|
Button {
|
||||||
|
switch item.type {
|
||||||
|
case .query:
|
||||||
state.queryText = item.title
|
state.queryText = item.title
|
||||||
state.changeQuery { query in query.query = item.title }
|
state.changeQuery { query in query.query = item.title }
|
||||||
|
|
||||||
updateFavoriteItem()
|
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 {
|
.contextMenu {
|
||||||
deleteButton(item)
|
removeButton(item)
|
||||||
deleteAllButton
|
removeAllButton
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,21 +313,21 @@ struct SearchView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private func deleteButton(_ item: RecentItem) -> some View {
|
private func removeButton(_ item: RecentItem) -> some View {
|
||||||
Button {
|
Button {
|
||||||
recents.close(item)
|
recents.close(item)
|
||||||
recentsChanged.toggle()
|
recentsChanged.toggle()
|
||||||
} label: {
|
} label: {
|
||||||
Label("Delete", systemImage: "trash")
|
Label("Remove", systemImage: "trash")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var deleteAllButton: some View {
|
private var removeAllButton: some View {
|
||||||
Button {
|
Button {
|
||||||
recents.clearQueries()
|
recents.clearQueries()
|
||||||
recentsChanged.toggle()
|
recentsChanged.toggle()
|
||||||
} label: {
|
} label: {
|
||||||
Label("Delete All", systemImage: "trash.fill")
|
Label("Remove All", systemImage: "trash.fill")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +336,7 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var recentItems: [RecentItem] {
|
private var recentItems: [RecentItem] {
|
||||||
Defaults[.recentlyOpened].filter { $0.type == .query }.reversed()
|
Defaults[.recentlyOpened].reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var searchSortOrderPicker: some View {
|
private var searchSortOrderPicker: some View {
|
||||||
|
@ -2726,7 +2726,7 @@
|
|||||||
INFOPLIST_FILE = iOS/Info.plist;
|
INFOPLIST_FILE = iOS/Info.plist;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
INFOPLIST_KEY_UIRequiresFullScreen = NO;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
@ -2758,7 +2758,7 @@
|
|||||||
INFOPLIST_FILE = iOS/Info.plist;
|
INFOPLIST_FILE = iOS/Info.plist;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
INFOPLIST_KEY_UIRequiresFullScreen = NO;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
|
@ -67,7 +67,7 @@ struct InstancesSettings: View {
|
|||||||
"Are you sure you want to remove \(selectedAccount?.description ?? "") account?"
|
"Are you sure you want to remove \(selectedAccount?.description ?? "") account?"
|
||||||
),
|
),
|
||||||
message: Text("This cannot be undone"),
|
message: Text("This cannot be undone"),
|
||||||
primaryButton: .destructive(Text("Delete")) {
|
primaryButton: .destructive(Text("Remove")) {
|
||||||
AccountsModel.remove(selectedAccount!)
|
AccountsModel.remove(selectedAccount!)
|
||||||
},
|
},
|
||||||
secondaryButton: .cancel()
|
secondaryButton: .cancel()
|
||||||
|
Loading…
Reference in New Issue
Block a user