mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +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,
|
||||
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 {
|
||||
|
@ -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 {
|
||||
|
@ -78,6 +78,7 @@ final class SearchModel: ObservableObject {
|
||||
|
||||
func loadSuggestions(_ query: String) {
|
||||
guard !query.isEmpty else {
|
||||
querySuggestions.replace([])
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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)"))
|
||||
}
|
||||
|
@ -88,6 +88,6 @@ struct RecentNavigationLink<DestinationContent: View>: View {
|
||||
}
|
||||
|
||||
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) {
|
||||
LazyView(ChannelVideosView(channel: channel))
|
||||
} label: {
|
||||
Label(channel.name, systemImage: AppSidebarNavigation.symbolSystemImage(channel.name))
|
||||
Label(channel.name, systemImage: RecentsModel.symbolSystemImage(channel.name))
|
||||
}
|
||||
.contextMenu {
|
||||
Button("Unsubscribe") {
|
||||
|
@ -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)
|
||||
}
|
||||
)
|
||||
|
@ -21,6 +21,8 @@ struct SearchView: View {
|
||||
@Environment(\.navigationStyle) private var navigationStyle
|
||||
|
||||
@EnvironmentObject<AccountsModel> private var accounts
|
||||
@EnvironmentObject<NavigationModel> private var navigation
|
||||
@EnvironmentObject<PlayerModel> private var player
|
||||
@EnvironmentObject<RecentsModel> private var recents
|
||||
@EnvironmentObject<SearchModel> 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 {
|
||||
|
@ -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";
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user