Adding search queries to favorites

This commit is contained in:
Arkadiusz Fal 2021-11-09 18:43:15 +01:00
parent afcefc2e54
commit ef5ac0ec65
6 changed files with 96 additions and 21 deletions

View File

@ -9,6 +9,7 @@ struct FavoriteItem: Codable, Equatable, Identifiable, Defaults.Serializable {
case channel(String, String)
case playlist(String)
case channelPlaylist(String, String)
case searchQuery(String, String, String, String)
var label: String {
switch self {
@ -24,6 +25,19 @@ struct FavoriteItem: Codable, Equatable, Identifiable, Defaults.Serializable {
return name
case let .channelPlaylist(_, name):
return name
case let .searchQuery(text, date, duration, order):
var label = "Search: \"\(text)\""
if !date.isEmpty, let date = SearchQuery.Date(rawValue: date), date != .any {
label += " from \(date == .today ? date.name : " this \(date.name)")"
}
if !order.isEmpty, let order = SearchQuery.SortOrder(rawValue: order), order != .relevance {
label += " by \(order.name)"
}
if !duration.isEmpty {
label += " (\(duration))"
}
return label
default:
return ""
}

View File

@ -36,7 +36,10 @@ extension Defaults.Keys {
static let sponsorBlockCategories = Key<Set<String>>("sponsorBlockCategories", default: Set(SponsorBlockAPI.categories))
static let favorites = Key<[FavoriteItem]>("favorites", default: [
.init(section: .trending("US", nil))
.init(section: .trending("US", nil)),
.init(section: .searchQuery("World Discoveries", "", "", "")),
.init(section: .searchQuery("Full Body Workout", "", "", "")),
.init(section: .searchQuery("Apple Pie Recipes", "", "", ""))
])
static let channelOnThumbnail = Key<Bool>("channelOnThumbnail", default: true)

View File

@ -105,6 +105,14 @@ struct FavoriteItemView: View {
case let .playlist(id):
return accounts.api.playlist(id)
case let .searchQuery(text, date, duration, order):
return accounts.api.search(.init(
query: text,
sortBy: SearchQuery.SortOrder(rawValue: order) ?? .uploadDate,
date: SearchQuery.Date(rawValue: date),
duration: SearchQuery.Duration(rawValue: duration)
))
}
return nil

View File

@ -2,21 +2,19 @@ import Foundation
import Siesta
final class FavoriteResourceObserver: ObservableObject, ResourceObserver {
@Published var videos = [Video]()
@Published var contentItems = [ContentItem]()
func resourceChanged(_ resource: Resource, event _: ResourceEvent) {
if let videos: [Video] = resource.typedContent() {
self.videos = videos
contentItems = videos.map { ContentItem(video: $0) }
} else if let channel: Channel = resource.typedContent() {
videos = channel.videos
contentItems = channel.videos.map { ContentItem(video: $0) }
} else if let playlist: ChannelPlaylist = resource.typedContent() {
videos = playlist.videos
contentItems = playlist.videos.map { ContentItem(video: $0) }
} else if let playlist: Playlist = resource.typedContent() {
videos = playlist.videos
contentItems = playlist.videos.map { ContentItem(video: $0) }
} else if let items: [ContentItem] = resource.typedContent() {
contentItems = items
}
}
var contentItems: [ContentItem] {
videos.map { ContentItem(video: $0) }
}
}

View File

@ -17,6 +17,8 @@ struct SearchView: View {
@State private var recentsDebounce = Debounce()
#endif
@State private var favoriteItem: FavoriteItem?
@Environment(\.navigationStyle) private var navigationStyle
@EnvironmentObject<AccountsModel> private var accounts
@ -42,10 +44,19 @@ struct SearchView: View {
} else {
#if os(tvOS)
ScrollView(.vertical, showsIndicators: false) {
HStack(spacing: 0) {
if accounts.app.supportsSearchFilters {
filtersHorizontalStack
}
if let favoriteItem = favoriteItem {
FavoriteButton(item: favoriteItem)
.id(favoriteItem.id)
.labelStyle(.iconOnly)
.font(.system(size: 25))
}
}
HorizontalCells(items: items)
}
.edgesIgnoringSafeArea(.horizontal)
@ -68,6 +79,13 @@ struct SearchView: View {
.toolbar {
#if !os(tvOS)
ToolbarItemGroup(placement: toolbarPlacement) {
#if os(macOS)
if let favoriteItem = favoriteItem {
FavoriteButton(item: favoriteItem)
.id(favoriteItem.id)
}
#endif
if accounts.app.supportsSearchFilters {
Section {
#if os(macOS)
@ -84,9 +102,20 @@ struct SearchView: View {
#endif
}
.transaction { t in t.animation = .none }
}
#if os(iOS)
Spacer()
if let favoriteItem = favoriteItem {
FavoriteButton(item: favoriteItem)
.id(favoriteItem.id)
}
Spacer()
#endif
if accounts.app.supportsSearchFilters {
filtersMenu
}
}
@ -96,6 +125,7 @@ struct SearchView: View {
if query != nil {
state.queryText = query!.query
state.resetQuery(query!)
updateFavoriteItem()
}
if !videos.isEmpty {
@ -120,7 +150,10 @@ struct SearchView: View {
recentsDebounce.invalidate()
searchDebounce.debouncing(2) {
state.changeQuery { query in query.query = newQuery }
state.changeQuery { query in
query.query = newQuery
updateFavoriteItem()
}
}
recentsDebounce.debouncing(10) {
@ -131,15 +164,25 @@ struct SearchView: View {
.onSubmit(of: .search) {
state.changeQuery { query in query.query = state.queryText }
recents.addQuery(state.queryText)
updateFavoriteItem()
}
.onChange(of: searchSortOrder) { order in
state.changeQuery { query in query.sortBy = order }
state.changeQuery { query in
query.sortBy = order
updateFavoriteItem()
}
}
.onChange(of: searchDate) { date in
state.changeQuery { query in query.date = date }
state.changeQuery { query in
query.date = date
updateFavoriteItem()
}
}
.onChange(of: searchDuration) { duration in
state.changeQuery { query in query.duration = duration }
state.changeQuery { query in
query.duration = duration
updateFavoriteItem()
}
}
#if !os(tvOS)
.navigationTitle("Search")
@ -192,6 +235,7 @@ struct SearchView: View {
Button(item.title) {
state.queryText = item.title
state.changeQuery { query in query.query = item.title }
updateFavoriteItem()
}
#if os(iOS)
.swipeActions(edge: .trailing) {
@ -312,21 +356,21 @@ struct SearchView: View {
.foregroundColor(.secondary)
searchSortOrderButton
}
.frame(maxWidth: .infinity, alignment: .trailing)
.frame(maxWidth: 300, alignment: .trailing)
HStack(spacing: 30) {
Text("Duration")
.foregroundColor(.secondary)
searchDurationButton
}
.frame(maxWidth: .infinity)
.frame(maxWidth: 300)
HStack(spacing: 30) {
Text("Date")
.foregroundColor(.secondary)
searchDateButton
}
.frame(maxWidth: .infinity, alignment: .leading)
.frame(maxWidth: 300, alignment: .leading)
}
.font(.system(size: 30))
}
@ -348,8 +392,16 @@ struct SearchView: View {
.foregroundColor(filtersActive ? .accentColor : .secondary)
.transaction { t in t.animation = .none }
}
#endif
private func updateFavoriteItem() {
favoriteItem = FavoriteItem(section: .searchQuery(
state.query.query,
state.query.date?.rawValue ?? "",
state.query.duration?.rawValue ?? "",
state.query.sortBy.rawValue
))
}
}
struct SearchView_Previews: PreviewProvider {

View File

@ -64,7 +64,7 @@ struct EditFavorites: View {
.padding(.trailing, 40)
HStack {
Text("Add more Channels and Playlists to your Favorites using button")
Text("Add Channels, Playlists and Searches to Favorites using")
Button {} label: {
Label("Add to Favorites", systemImage: "heart")
.labelStyle(.iconOnly)