mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Search and trending menus for iOS
This commit is contained in:
parent
64146b26c2
commit
2e3454a18f
@ -21,6 +21,19 @@ enum TrendingCategory: String, CaseIterable, Identifiable, Defaults.Serializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var systemImage: String {
|
||||||
|
switch self {
|
||||||
|
case .default:
|
||||||
|
return "chart.bar"
|
||||||
|
case .music:
|
||||||
|
return "music.note"
|
||||||
|
case .gaming:
|
||||||
|
return "gamecontroller"
|
||||||
|
case .movies:
|
||||||
|
return "film"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var name: String {
|
var name: String {
|
||||||
id == "default" ? "Trending".localized() : title
|
id == "default" ? "Trending".localized() : title
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,6 @@ struct AppTabNavigation: View {
|
|||||||
private var searchNavigationView: some View {
|
private var searchNavigationView: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
LazyView(SearchView())
|
LazyView(SearchView())
|
||||||
.toolbar { toolbarContent }
|
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Search", systemImage: "magnifyingglass")
|
Label("Search", systemImage: "magnifyingglass")
|
||||||
|
@ -2,17 +2,9 @@ import Repeat
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SearchTextField: View {
|
struct SearchTextField: View {
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
|
||||||
|
|
||||||
private var navigation = NavigationModel.shared
|
private var navigation = NavigationModel.shared
|
||||||
@ObservedObject private var state = SearchModel.shared
|
@ObservedObject private var state = SearchModel.shared
|
||||||
|
|
||||||
@Binding var favoriteItem: FavoriteItem?
|
|
||||||
|
|
||||||
init(favoriteItem: Binding<FavoriteItem?>? = nil) {
|
|
||||||
_favoriteItem = favoriteItem ?? .constant(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ -41,19 +33,10 @@ struct SearchTextField: View {
|
|||||||
.textFieldStyle(.plain)
|
.textFieldStyle(.plain)
|
||||||
#else
|
#else
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
.padding(.leading)
|
.padding(.leading, 5)
|
||||||
.padding(.trailing, 15)
|
.padding(.trailing, 10)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if let favoriteItem {
|
|
||||||
#if os(iOS)
|
|
||||||
FavoriteButton(item: favoriteItem)
|
|
||||||
.id(favoriteItem.id)
|
|
||||||
.labelStyle(.iconOnly)
|
|
||||||
.padding(.trailing)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if !state.queryText.isEmpty {
|
if !state.queryText.isEmpty {
|
||||||
clearButton
|
clearButton
|
||||||
} else {
|
} else {
|
||||||
@ -64,7 +47,6 @@ struct SearchTextField: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, navigationStyle == .tab ? 10 : 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var fieldBorder: some View {
|
private var fieldBorder: some View {
|
||||||
@ -83,17 +65,16 @@ struct SearchTextField: View {
|
|||||||
self.state.queryText = ""
|
self.state.queryText = ""
|
||||||
}) {
|
}) {
|
||||||
Image(systemName: "xmark.circle.fill")
|
Image(systemName: "xmark.circle.fill")
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.frame(width: 14, height: 14)
|
.imageScale(.small)
|
||||||
#else
|
#else
|
||||||
.frame(width: 18, height: 18)
|
.imageScale(.medium)
|
||||||
#endif
|
#endif
|
||||||
.padding(.trailing, 3)
|
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
.padding(.trailing, 10)
|
#if os(macOS)
|
||||||
.opacity(0.7)
|
.padding(.trailing, 10)
|
||||||
|
#endif
|
||||||
|
.opacity(0.7)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -37,27 +37,9 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
BrowserPlayerControls(toolbar: {
|
BrowserPlayerControls {
|
||||||
#if os(iOS)
|
|
||||||
if accounts.app.supportsSearchFilters {
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
Menu("Sort: \(searchSortOrder.name)") {
|
|
||||||
searchSortOrderPicker
|
|
||||||
}
|
|
||||||
.transaction { t in t.animation = .none }
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
filtersMenu
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}) {
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
VStack {
|
VStack {
|
||||||
SearchTextField(favoriteItem: $favoriteItem)
|
|
||||||
|
|
||||||
if accounts.app.supportsSearchSuggestions, state.query.query != state.queryText {
|
if accounts.app.supportsSearchSuggestions, state.query.query != state.queryText {
|
||||||
SearchSuggestions()
|
SearchSuggestions()
|
||||||
.opacity(state.queryText.isEmpty ? 0 : 1)
|
.opacity(state.queryText.isEmpty ? 0 : 1)
|
||||||
@ -182,11 +164,61 @@ struct SearchView: View {
|
|||||||
.navigationTitle("Search")
|
.navigationTitle("Search")
|
||||||
#endif
|
#endif
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.navigationBarHidden(navigationBarHidden)
|
.toolbar {
|
||||||
|
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||||
|
if !navigationBarHidden {
|
||||||
|
Button(action: { NavigationModel.shared.presentingSettings = true }) {
|
||||||
|
Image(systemName: "gearshape.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolbarItem(placement: .principal) {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
if !state.query.isEmpty {
|
||||||
|
searchMenu
|
||||||
|
}
|
||||||
|
SearchTextField()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
var searchMenu: some View {
|
||||||
|
Menu {
|
||||||
|
if accounts.app.supportsSearchFilters {
|
||||||
|
searchSortOrderPicker
|
||||||
|
.pickerStyle(.menu)
|
||||||
|
|
||||||
|
Picker(selection: $searchDuration, label: Text("Duration")) {
|
||||||
|
ForEach(SearchQuery.Duration.allCases) { duration in
|
||||||
|
Text(duration.name).tag(duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pickerStyle(.menu)
|
||||||
|
|
||||||
|
Picker("Upload date", selection: $searchDate) {
|
||||||
|
ForEach(SearchQuery.Date.allCases) { date in
|
||||||
|
Text(date.name).tag(date)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pickerStyle(.menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
FavoriteButton(item: favoriteItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "chevron.down.circle.fill")
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
.imageScale(.medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private var navigationBarHidden: Bool {
|
private var navigationBarHidden: Bool {
|
||||||
if navigationStyle == .sidebar {
|
if navigationStyle == .sidebar {
|
||||||
return true
|
return true
|
||||||
|
@ -33,30 +33,7 @@ struct TrendingView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
BrowserPlayerControls(toolbar: {
|
BrowserPlayerControls {
|
||||||
HStack {
|
|
||||||
if accounts.app.supportsTrendingCategories {
|
|
||||||
categoryButton
|
|
||||||
.layoutPriority(1)
|
|
||||||
// only way to disable Menu animation is to
|
|
||||||
// force redraw of the view when it changes
|
|
||||||
.id(UUID())
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
|
|
||||||
if let favoriteItem {
|
|
||||||
FavoriteButton(item: favoriteItem, labelPadding: true)
|
|
||||||
.id(favoriteItem.id)
|
|
||||||
.labelStyle(.iconOnly)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
|
|
||||||
countryButton
|
|
||||||
}
|
|
||||||
.padding(.horizontal)
|
|
||||||
}) {
|
|
||||||
Section {
|
Section {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
@ -137,7 +114,12 @@ struct TrendingView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(RefreshControl.navigationBarTitleDisplayMode)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .principal) {
|
||||||
|
trendingMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||||
@ -174,6 +156,29 @@ struct TrendingView: View {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
var trendingMenu: some View {
|
||||||
|
Menu {
|
||||||
|
countryButton
|
||||||
|
if accounts.app.supportsTrendingCategories {
|
||||||
|
categoryButton
|
||||||
|
}
|
||||||
|
FavoriteButton(item: favoriteItem)
|
||||||
|
} label: {
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Text("\(country.flag) \(country.name)")
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
|
||||||
|
Image(systemName: "chevron.down.circle.fill")
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
.imageScale(.small)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: 320)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private var categoryButton: some View {
|
private var categoryButton: some View {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
Button(category.name) {
|
Button(category.name) {
|
||||||
@ -190,10 +195,9 @@ struct TrendingView: View {
|
|||||||
#else
|
#else
|
||||||
Picker(category.controlLabel, selection: $category) {
|
Picker(category.controlLabel, selection: $category) {
|
||||||
ForEach(TrendingCategory.allCases) { category in
|
ForEach(TrendingCategory.allCases) { category in
|
||||||
Text(category.controlLabel).tag(category)
|
Label(category.controlLabel, systemImage: category.systemImage).tag(category)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pickerStyle(.menu)
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +206,12 @@ struct TrendingView: View {
|
|||||||
presentingCountrySelection.toggle()
|
presentingCountrySelection.toggle()
|
||||||
resource.removeObservers(ownedBy: store)
|
resource.removeObservers(ownedBy: store)
|
||||||
}) {
|
}) {
|
||||||
Text("\(country.flag) \(country.id)")
|
#if os(iOS)
|
||||||
|
Label("Switch country...", systemImage: "flag")
|
||||||
|
#else
|
||||||
|
Text("\(country.flag) \(country.id)")
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +222,8 @@ struct TrendingView: View {
|
|||||||
|
|
||||||
struct TrendingView_Previews: PreviewProvider {
|
struct TrendingView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
TrendingView(Video.allFixtures)
|
NavigationView {
|
||||||
.injectFixtureEnvironmentObjects()
|
TrendingView(Video.allFixtures)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,8 +288,8 @@
|
|||||||
3744A96028B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */; };
|
3744A96028B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */; };
|
||||||
3744A96128B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */; };
|
3744A96128B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */; };
|
||||||
3744A96228B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */; };
|
3744A96228B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */; };
|
||||||
374710052755291C00CE0F87 /* SearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374710042755291C00CE0F87 /* SearchField.swift */; };
|
374710052755291C00CE0F87 /* SearchTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374710042755291C00CE0F87 /* SearchTextField.swift */; };
|
||||||
374710062755291C00CE0F87 /* SearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374710042755291C00CE0F87 /* SearchField.swift */; };
|
374710062755291C00CE0F87 /* SearchTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374710042755291C00CE0F87 /* SearchTextField.swift */; };
|
||||||
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
||||||
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
||||||
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
||||||
@ -1127,7 +1127,7 @@
|
|||||||
3743CA51270F284F00E4D32B /* View+Borders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Borders.swift"; sourceTree = "<group>"; };
|
3743CA51270F284F00E4D32B /* View+Borders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Borders.swift"; sourceTree = "<group>"; };
|
||||||
3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerControlsLayout.swift; sourceTree = "<group>"; };
|
3744A95F28B99ADD005DE0A7 /* PlayerControlsLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerControlsLayout.swift; sourceTree = "<group>"; };
|
||||||
3744F85C293CC9B800B09AB9 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
3744F85C293CC9B800B09AB9 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
374710042755291C00CE0F87 /* SearchField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchField.swift; sourceTree = "<group>"; };
|
374710042755291C00CE0F87 /* SearchTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTextField.swift; sourceTree = "<group>"; };
|
||||||
3748186526A7627F0084E870 /* Video+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Video+Fixtures.swift"; sourceTree = "<group>"; };
|
3748186526A7627F0084E870 /* Video+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Video+Fixtures.swift"; sourceTree = "<group>"; };
|
||||||
3748186926A764FB0084E870 /* Thumbnail+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thumbnail+Fixtures.swift"; sourceTree = "<group>"; };
|
3748186926A764FB0084E870 /* Thumbnail+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thumbnail+Fixtures.swift"; sourceTree = "<group>"; };
|
||||||
3748186D26A769D60084E870 /* DetailBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBadge.swift; sourceTree = "<group>"; };
|
3748186D26A769D60084E870 /* DetailBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBadge.swift; sourceTree = "<group>"; };
|
||||||
@ -2007,8 +2007,8 @@
|
|||||||
3782B95527557A2400990149 /* Search */ = {
|
3782B95527557A2400990149 /* Search */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
374710042755291C00CE0F87 /* SearchField.swift */,
|
|
||||||
3782B94E27553A6700990149 /* SearchSuggestions.swift */,
|
3782B94E27553A6700990149 /* SearchSuggestions.swift */,
|
||||||
|
374710042755291C00CE0F87 /* SearchTextField.swift */,
|
||||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||||
);
|
);
|
||||||
path = Search;
|
path = Search;
|
||||||
@ -2872,7 +2872,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
374710052755291C00CE0F87 /* SearchField.swift in Sources */,
|
374710052755291C00CE0F87 /* SearchTextField.swift in Sources */,
|
||||||
37494EA529200B14000DF176 /* DocumentsView.swift in Sources */,
|
37494EA529200B14000DF176 /* DocumentsView.swift in Sources */,
|
||||||
374DE88028BB896C0062BBF2 /* PlayerDragGesture.swift in Sources */,
|
374DE88028BB896C0062BBF2 /* PlayerDragGesture.swift in Sources */,
|
||||||
37ECED56289FE166002BC2C9 /* SafeArea.swift in Sources */,
|
37ECED56289FE166002BC2C9 /* SafeArea.swift in Sources */,
|
||||||
@ -3123,7 +3123,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
3727B74B27872B880021C15E /* VisualEffectBlur-macOS.swift in Sources */,
|
3727B74B27872B880021C15E /* VisualEffectBlur-macOS.swift in Sources */,
|
||||||
374710062755291C00CE0F87 /* SearchField.swift in Sources */,
|
374710062755291C00CE0F87 /* SearchTextField.swift in Sources */,
|
||||||
37F0F4EB286F397E00C06C2E /* SettingsModel.swift in Sources */,
|
37F0F4EB286F397E00C06C2E /* SettingsModel.swift in Sources */,
|
||||||
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
|
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
|
||||||
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
||||||
|
Loading…
Reference in New Issue
Block a user