mirror of
https://github.com/yattee/yattee.git
synced 2025-12-23 21:20:19 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
735e7d62b6 | ||
|
|
320c16fcc7 | ||
|
|
8c5c503df2 | ||
|
|
36738572da | ||
|
|
9a8ccc366c | ||
|
|
e9ca36f1db | ||
|
|
5b607687d9 | ||
|
|
e723bb9147 | ||
|
|
a3747a0975 | ||
|
|
bb2bd86c07 | ||
|
|
680ac9a8a0 | ||
|
|
c1b23d20f2 | ||
|
|
b8f6dabbc9 | ||
|
|
1c168bd982 | ||
|
|
42d53c30db | ||
|
|
a55adb2e65 | ||
|
|
cea296c4b7 |
@@ -8,6 +8,15 @@ disabled_rules:
|
|||||||
- multiline_arguments
|
- multiline_arguments
|
||||||
- implicit_return
|
- implicit_return
|
||||||
- closure_end_indentation
|
- closure_end_indentation
|
||||||
|
- discarded_notification_center_observer # Observer intentionally lives for app lifetime
|
||||||
|
# Disable deprecated rules in favor of their renamed versions
|
||||||
|
- operator_whitespace # renamed to function_name_whitespace
|
||||||
|
- redundant_optional_initialization # renamed to implicit_optional_initialization
|
||||||
|
|
||||||
|
opt_in_rules:
|
||||||
|
- function_name_whitespace
|
||||||
|
- implicit_optional_initialization
|
||||||
|
|
||||||
excluded:
|
excluded:
|
||||||
- Vendor
|
- Vendor
|
||||||
- Tests Apple TV
|
- Tests Apple TV
|
||||||
|
|||||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,7 +1,17 @@
|
|||||||
## Build 209
|
## Build 210
|
||||||
|
|
||||||
## What's Changed
|
## What's Changed
|
||||||
|
|
||||||
|
* Trending and Hide Shorts was disabled due to changes in the video apps API
|
||||||
|
* Fix iPad iOS 18 keyboard dismissal issue in search
|
||||||
|
* Fix audio session interrupting other apps on launch
|
||||||
|
* Fix thumbnail loading for video details
|
||||||
|
* Fix thumbnail aspect ratio to prevent stretching and layout jumps
|
||||||
|
* Fix keyboard shortcut conflict for Show Player command
|
||||||
|
|
||||||
|
## Previous builds
|
||||||
|
|
||||||
|
**Build 209:**
|
||||||
* Fix Now Playing controls for both MPV and AVPlayer backends
|
* Fix Now Playing controls for both MPV and AVPlayer backends
|
||||||
* Fix thumbnail sizing and aspect ratio issues in video cells (#896)
|
* Fix thumbnail sizing and aspect ratio issues in video cells (#896)
|
||||||
* Adjust tvOS video cell dimensions for better layout
|
* Adjust tvOS video cell dimensions for better layout
|
||||||
@@ -10,8 +20,6 @@
|
|||||||
* Simplify fullscreen handling for iOS
|
* Simplify fullscreen handling for iOS
|
||||||
* Add macOS-specific entitlements for MPV backend
|
* Add macOS-specific entitlements for MPV backend
|
||||||
|
|
||||||
## Previous builds
|
|
||||||
|
|
||||||
**Build 208:**
|
**Build 208:**
|
||||||
* Enable resizable windows on iPad
|
* Enable resizable windows on iPad
|
||||||
* Improve iPad UI behavior and settings layout
|
* Improve iPad UI behavior and settings layout
|
||||||
|
|||||||
5
Extensions/Notification+Names.swift
Normal file
5
Extensions/Notification+Names.swift
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension Notification.Name {
|
||||||
|
static let accountConfigurationComplete = Notification.Name("accountConfigurationComplete")
|
||||||
|
}
|
||||||
@@ -152,6 +152,10 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
FeedModel.shared.onAccountChange()
|
FeedModel.shared.onAccountChange()
|
||||||
SubscribedChannelsModel.shared.onAccountChange()
|
SubscribedChannelsModel.shared.onAccountChange()
|
||||||
PlaylistsModel.shared.onAccountChange()
|
PlaylistsModel.shared.onAccountChange()
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +164,9 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
guard !account.anonymous,
|
guard !account.anonymous,
|
||||||
(account.token?.isEmpty ?? true) || force
|
(account.token?.isEmpty ?? true) || force
|
||||||
else {
|
else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +179,9 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
title: "Account Error",
|
title: "Account Error",
|
||||||
message: "Remove and add your account again in Settings."
|
message: "Remove and add your account again in Settings."
|
||||||
)
|
)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +222,8 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.configure()
|
self.configure()
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,6 +174,9 @@ final class PeerTubeAPI: Service, ObservableObject, VideosAPI {
|
|||||||
guard !account.anonymous,
|
guard !account.anonymous,
|
||||||
(account.token?.isEmpty ?? true) || force
|
(account.token?.isEmpty ?? true) || force
|
||||||
else {
|
else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +189,9 @@ final class PeerTubeAPI: Service, ObservableObject, VideosAPI {
|
|||||||
title: "Account Error",
|
title: "Account Error",
|
||||||
message: "Remove and add your account again in Settings."
|
message: "Remove and add your account again in Settings."
|
||||||
)
|
)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,6 +200,7 @@ final class PeerTubeAPI: Service, ObservableObject, VideosAPI {
|
|||||||
title: "Account Error",
|
title: "Account Error",
|
||||||
message: message ?? "\(response?.response?.statusCode ?? -1) - \(response?.error?.errorDescription ?? "unknown")\nIf this issue persists, try removing and adding your account again in Settings."
|
message: message ?? "\(response?.response?.statusCode ?? -1) - \(response?.error?.errorDescription ?? "unknown")\nIf this issue persists, try removing and adding your account again in Settings."
|
||||||
)
|
)
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
AF
|
AF
|
||||||
@@ -226,6 +233,8 @@ final class PeerTubeAPI: Service, ObservableObject, VideosAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.configure()
|
self.configure()
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,10 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
|||||||
FeedModel.shared.onAccountChange()
|
FeedModel.shared.onAccountChange()
|
||||||
SubscribedChannelsModel.shared.onAccountChange()
|
SubscribedChannelsModel.shared.onAccountChange()
|
||||||
PlaylistsModel.shared.onAccountChange()
|
PlaylistsModel.shared.onAccountChange()
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +153,9 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
|||||||
let username,
|
let username,
|
||||||
let password
|
let password
|
||||||
else {
|
else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,11 +191,14 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
|||||||
|
|
||||||
self.configure()
|
self.configure()
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
|
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
NavigationModel.shared.presentAlert(
|
NavigationModel.shared.presentAlert(
|
||||||
title: "Account Error",
|
title: "Account Error",
|
||||||
message: error.localizedDescription
|
message: error.localizedDescription
|
||||||
)
|
)
|
||||||
|
NotificationCenter.default.post(name: .accountConfigurationComplete, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -532,7 +542,10 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
|||||||
|
|
||||||
let channelId = details["uploaderUrl"]?.string?.components(separatedBy: "/").last ?? "unknown"
|
let channelId = details["uploaderUrl"]?.string?.components(separatedBy: "/").last ?? "unknown"
|
||||||
|
|
||||||
let thumbnails: [Thumbnail] = Thumbnail.Quality.allCases.compactMap {
|
let qualities = [
|
||||||
|
Thumbnail.Quality.maxresdefault, .high, .medium, .default, .start, .middle, .end
|
||||||
|
]
|
||||||
|
let thumbnails: [Thumbnail] = qualities.compactMap {
|
||||||
if let url = buildThumbnailURL(from: content, quality: $0) {
|
if let url = buildThumbnailURL(from: content, quality: $0) {
|
||||||
return Thumbnail(url: url, quality: $0)
|
return Thumbnail(url: url, quality: $0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ final class FeedModel: ObservableObject, CacheModel {
|
|||||||
let watches = watchFetchRequestResult(videos, context: backgroundContext)
|
let watches = watchFetchRequestResult(videos, context: backgroundContext)
|
||||||
let watchesIDs = watches.map(\.videoID)
|
let watchesIDs = watches.map(\.videoID)
|
||||||
let unwatched = videos.filter { video in
|
let unwatched = videos.filter { video in
|
||||||
if Defaults[.hideShorts], video.short {
|
if FeatureFlags.hideShortsEnabled, Defaults[.hideShorts], video.short {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ final class NavigationModel: ObservableObject {
|
|||||||
func multipleTapHandler() {
|
func multipleTapHandler() {
|
||||||
switch tabSelection {
|
switch tabSelection {
|
||||||
case .search:
|
case .search:
|
||||||
search.focused = true
|
break
|
||||||
default:
|
default:
|
||||||
print("not implemented")
|
print("not implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,12 +135,6 @@ final class MPVClient: ObservableObject {
|
|||||||
|
|
||||||
checkError(mpv_initialize(mpv))
|
checkError(mpv_initialize(mpv))
|
||||||
|
|
||||||
#if !os(macOS)
|
|
||||||
// Set up audio session for Now Playing support
|
|
||||||
backend?.model.setupAudioSessionForNowPlaying()
|
|
||||||
backend?.model.updateNowPlayingInfo()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
let api = UnsafeMutableRawPointer(mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String)
|
let api = UnsafeMutableRawPointer(mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String)
|
||||||
var initParams = mpv_opengl_init_params(
|
var initParams = mpv_opengl_init_params(
|
||||||
get_proc_address: getProcAddress,
|
get_proc_address: getProcAddress,
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
|
|
||||||
// When switching away from AVPlayer, clear its current item to release Now Playing control
|
// When switching away from AVPlayer, clear its current item to release Now Playing control
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
if from == .appleAVPlayer && to == .mpv {
|
if from == .appleAVPlayer, to == .mpv {
|
||||||
avPlayerBackend.avPlayer.replaceCurrentItem(with: nil)
|
avPlayerBackend.avPlayer.replaceCurrentItem(with: nil)
|
||||||
|
|
||||||
// Clear Now Playing info entirely before MPV takes over
|
// Clear Now Playing info entirely before MPV takes over
|
||||||
@@ -1394,7 +1394,11 @@ final class PlayerModel: ObservableObject {
|
|||||||
func setAudioSessionActive(_ setActive: Bool) {
|
func setAudioSessionActive(_ setActive: Bool) {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
||||||
do {
|
do {
|
||||||
try AVAudioSession.sharedInstance().setActive(setActive)
|
let audioSession = AVAudioSession.sharedInstance()
|
||||||
|
if setActive {
|
||||||
|
try audioSession.setCategory(.playback, mode: .moviePlayback)
|
||||||
|
}
|
||||||
|
try audioSession.setActive(setActive)
|
||||||
} catch {
|
} catch {
|
||||||
self.logger.error("Error setting audio session to \(setActive): \(error)")
|
self.logger.error("Error setting audio session to \(setActive): \(error)")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,9 @@ final class SearchModel: ObservableObject {
|
|||||||
@Published var querySuggestions = [String]()
|
@Published var querySuggestions = [String]()
|
||||||
private var suggestionsDebouncer = Debouncer(.milliseconds(200))
|
private var suggestionsDebouncer = Debouncer(.milliseconds(200))
|
||||||
|
|
||||||
@Published var focused = false
|
|
||||||
|
|
||||||
@Default(.showSearchSuggestions) private var showSearchSuggestions
|
@Default(.showSearchSuggestions) private var showSearchSuggestions
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(macOS)
|
||||||
var textField: UITextField!
|
|
||||||
#elseif os(macOS)
|
|
||||||
var textField: NSTextField!
|
var textField: NSTextField!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -30,15 +26,9 @@ final class SearchModel: ObservableObject {
|
|||||||
private var resource: Resource!
|
private var resource: Resource!
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
#if os(iOS)
|
|
||||||
addKeyboardDidHideNotificationObserver()
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
#if os(iOS)
|
|
||||||
removeKeyboardDidHideNotificationObserver()
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isLoading: Bool {
|
var isLoading: Bool {
|
||||||
@@ -158,18 +148,4 @@ final class SearchModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
|
||||||
private func addKeyboardDidHideNotificationObserver() {
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDidHide), name: UIResponder.keyboardDidHideNotification, object: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func onKeyboardDidHide() {
|
|
||||||
focused = false
|
|
||||||
}
|
|
||||||
|
|
||||||
private func removeKeyboardDidHideNotificationObserver() {
|
|
||||||
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidHideNotification, object: nil)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
12
Shared/FeatureFlags.swift
Normal file
12
Shared/FeatureFlags.swift
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Feature flags for enabling/disabling functionality across the app
|
||||||
|
enum FeatureFlags {
|
||||||
|
/// Controls whether the "Hide Shorts" functionality is available
|
||||||
|
/// Set to false when the API changes prevent reliable detection of short videos
|
||||||
|
static let hideShortsEnabled = false
|
||||||
|
|
||||||
|
/// Controls whether the "Trending" section is available
|
||||||
|
/// Set to false to disable trending functionality across the app
|
||||||
|
static let trendingEnabled = false
|
||||||
|
}
|
||||||
@@ -50,9 +50,11 @@ struct FavoriteItemView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
if hideShorts || hideWatched {
|
if (FeatureFlags.hideShortsEnabled && hideShorts) || hideWatched {
|
||||||
AccentButton(text: "Disable filters", maxWidth: nil, verticalPadding: 0, minHeight: 30) {
|
AccentButton(text: "Disable filters", maxWidth: nil, verticalPadding: 0, minHeight: 30) {
|
||||||
hideShorts = false
|
if FeatureFlags.hideShortsEnabled {
|
||||||
|
hideShorts = false
|
||||||
|
}
|
||||||
hideWatched = false
|
hideWatched = false
|
||||||
reloadVisibleWatches()
|
reloadVisibleWatches()
|
||||||
}
|
}
|
||||||
@@ -107,7 +109,7 @@ struct FavoriteItemView: View {
|
|||||||
resource?.removeObservers(ownedBy: store)
|
resource?.removeObservers(ownedBy: store)
|
||||||
}
|
}
|
||||||
.onChange(of: player.currentVideo) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
|
.onChange(of: player.currentVideo) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
|
||||||
.onChange(of: hideShorts) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
|
.onChange(of: hideShorts) { _ in if !player.presentingPlayer && FeatureFlags.hideShortsEnabled { reloadVisibleWatches() } }
|
||||||
.onChange(of: hideWatched) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
|
.onChange(of: hideWatched) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
|
||||||
// Delay is necessary to update the list with the new items.
|
// Delay is necessary to update the list with the new items.
|
||||||
.onChange(of: favoritesChanged) { _ in if !player.presentingPlayer { Delay.by(1.0) { reloadVisibleWatches() } } }
|
.onChange(of: favoritesChanged) { _ in if !player.presentingPlayer { Delay.by(1.0) { reloadVisibleWatches() } } }
|
||||||
@@ -135,9 +137,9 @@ struct FavoriteItemView: View {
|
|||||||
|
|
||||||
var emptyItemsText: String {
|
var emptyItemsText: String {
|
||||||
var filterText = ""
|
var filterText = ""
|
||||||
if hideShorts && hideWatched {
|
if FeatureFlags.hideShortsEnabled && hideShorts && hideWatched {
|
||||||
filterText = "(watched and shorts hidden)"
|
filterText = "(watched and shorts hidden)"
|
||||||
} else if hideShorts {
|
} else if FeatureFlags.hideShortsEnabled && hideShorts {
|
||||||
filterText = "(shorts hidden)"
|
filterText = "(shorts hidden)"
|
||||||
} else if hideWatched {
|
} else if hideWatched {
|
||||||
filterText = "(watched hidden)"
|
filterText = "(watched hidden)"
|
||||||
@@ -227,7 +229,7 @@ struct FavoriteItemView: View {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
guard hideShorts, item.contentType == .video, let video = item.video else {
|
guard FeatureFlags.hideShortsEnabled, hideShorts, item.contentType == .video, let video = item.video else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,7 +353,7 @@ struct FavoriteItemView: View {
|
|||||||
case .history:
|
case .history:
|
||||||
return false
|
return false
|
||||||
case .trending:
|
case .trending:
|
||||||
return visibleSections.contains(.trending)
|
return FeatureFlags.trendingEnabled && visibleSections.contains(.trending)
|
||||||
case .subscriptions:
|
case .subscriptions:
|
||||||
return visibleSections.contains(.subscriptions) && accounts.signedIn
|
return visibleSections.contains(.subscriptions) && accounts.signedIn
|
||||||
case .popular:
|
case .popular:
|
||||||
|
|||||||
@@ -36,10 +36,12 @@ struct MenuCommands: Commands {
|
|||||||
.disabled(!AccountsModel.shared.app.supportsPopular)
|
.disabled(!AccountsModel.shared.app.supportsPopular)
|
||||||
.keyboardShortcut("3")
|
.keyboardShortcut("3")
|
||||||
|
|
||||||
Button("Trending") {
|
if FeatureFlags.trendingEnabled {
|
||||||
setTabSelection(.trending)
|
Button("Trending") {
|
||||||
|
setTabSelection(.trending)
|
||||||
|
}
|
||||||
|
.keyboardShortcut("4")
|
||||||
}
|
}
|
||||||
.keyboardShortcut("4")
|
|
||||||
|
|
||||||
Button("Search") {
|
Button("Search") {
|
||||||
setTabSelection(.search)
|
setTabSelection(.search)
|
||||||
@@ -76,7 +78,7 @@ struct MenuCommands: Commands {
|
|||||||
Button(togglePlayerLabel) {
|
Button(togglePlayerLabel) {
|
||||||
PlayerModel.shared.togglePlayer()
|
PlayerModel.shared.togglePlayer()
|
||||||
}
|
}
|
||||||
.keyboardShortcut("o")
|
.keyboardShortcut("p", modifiers: [.command, .shift])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ struct AppSidebarNavigation: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
content.introspect(.viewController, on: .iOS(.v15, .v16, .v17, .v18)) { viewController in
|
content.introspect(.viewController, on: .iOS(.v15, .v16, .v17, .v18, .v26)) { viewController in
|
||||||
// workaround for an empty supplementary view on launch
|
// workaround for an empty supplementary view on launch
|
||||||
// the supplementary view is determined by the default selection inside the
|
// the supplementary view is determined by the default selection inside the
|
||||||
// primary view, but the primary view is not loaded so its selection is not read
|
// primary view, but the primary view is not loaded so its selection is not read
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct AppTabNavigation: View {
|
|||||||
popularNavigationView
|
popularNavigationView
|
||||||
}
|
}
|
||||||
|
|
||||||
if visibleSections.contains(.trending) {
|
if FeatureFlags.trendingEnabled && visibleSections.contains(.trending) {
|
||||||
trendingNavigationView
|
trendingNavigationView
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ struct AppTabNavigation: View {
|
|||||||
.toolbar { toolbarContent }
|
.toolbar { toolbarContent }
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Popular", systemImage: "arrow.up.right.circle.fill")
|
Label("Popular", systemImage: "chart.bar.fill")
|
||||||
.accessibility(label: Text("Popular"))
|
.accessibility(label: Text("Popular"))
|
||||||
}
|
}
|
||||||
.tag(TabSelection.popular)
|
.tag(TabSelection.popular)
|
||||||
@@ -126,7 +126,7 @@ struct AppTabNavigation: View {
|
|||||||
LazyView(TrendingView())
|
LazyView(TrendingView())
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Trending", systemImage: "chart.bar.fill")
|
Label("Trending", systemImage: "arrow.up.right.circle.fill")
|
||||||
.accessibility(label: Text("Trending"))
|
.accessibility(label: Text("Trending"))
|
||||||
}
|
}
|
||||||
.tag(TabSelection.trending)
|
.tag(TabSelection.trending)
|
||||||
|
|||||||
@@ -95,15 +95,15 @@ struct Sidebar: View {
|
|||||||
|
|
||||||
if visibleSections.contains(.popular), accounts.app.supportsPopular {
|
if visibleSections.contains(.popular), accounts.app.supportsPopular {
|
||||||
NavigationLink(destination: LazyView(PopularView()), tag: TabSelection.popular, selection: $navigation.tabSelection) {
|
NavigationLink(destination: LazyView(PopularView()), tag: TabSelection.popular, selection: $navigation.tabSelection) {
|
||||||
Label("Popular", systemImage: "arrow.up.right.circle")
|
Label("Popular", systemImage: "chart.bar.fill")
|
||||||
.accessibility(label: Text("Popular"))
|
.accessibility(label: Text("Popular"))
|
||||||
}
|
}
|
||||||
.id("popular")
|
.id("popular")
|
||||||
}
|
}
|
||||||
|
|
||||||
if visibleSections.contains(.trending) {
|
if FeatureFlags.trendingEnabled && visibleSections.contains(.trending) {
|
||||||
NavigationLink(destination: LazyView(TrendingView()), tag: TabSelection.trending, selection: $navigation.tabSelection) {
|
NavigationLink(destination: LazyView(TrendingView()), tag: TabSelection.trending, selection: $navigation.tabSelection) {
|
||||||
Label("Trending", systemImage: "chart.bar")
|
Label("Trending", systemImage: "arrow.up.right.circle.fill")
|
||||||
.accessibility(label: Text("Trending"))
|
.accessibility(label: Text("Trending"))
|
||||||
}
|
}
|
||||||
.id("trending")
|
.id("trending")
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ struct OpenURLHandler {
|
|||||||
focusMainWindow()
|
focusMainWindow()
|
||||||
#endif
|
#endif
|
||||||
case .trending:
|
case .trending:
|
||||||
|
guard FeatureFlags.trendingEnabled else { return }
|
||||||
navigation.hideViewsAboveBrowser()
|
navigation.hideViewsAboveBrowser()
|
||||||
navigation.tabSelection = .trending
|
navigation.tabSelection = .trending
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
|
|||||||
@@ -3,27 +3,15 @@ import SwiftUI
|
|||||||
import SwiftUIIntrospect
|
import SwiftUIIntrospect
|
||||||
|
|
||||||
struct FocusableSearchTextField: View {
|
struct FocusableSearchTextField: View {
|
||||||
@ObservedObject private var state = SearchModel.shared
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
SearchTextField()
|
SearchTextField()
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.introspect(.textField, on: .macOS(.v12, .v13, .v14, .v15)) { textField in
|
.introspect(.textField, on: .macOS(.v12, .v13, .v14, .v15)) { textField in
|
||||||
state.textField = textField
|
SearchModel.shared.textField = textField
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
state.textField?.becomeFirstResponder()
|
SearchModel.shared.textField?.becomeFirstResponder()
|
||||||
}
|
|
||||||
}
|
|
||||||
#elseif os(iOS)
|
|
||||||
.introspect(.textField, on: .iOS(.v15, .v16, .v17, .v18)) { textField in
|
|
||||||
state.textField = textField
|
|
||||||
}
|
|
||||||
.onChange(of: state.focused) { newValue in
|
|
||||||
if newValue, let textField = state.textField, !textField.isFirstResponder {
|
|
||||||
textField.becomeFirstResponder()
|
|
||||||
textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -55,9 +55,9 @@ struct SearchTextField: View {
|
|||||||
TextField("Search...", text: $state.queryText) {
|
TextField("Search...", text: $state.queryText) {
|
||||||
state.changeQuery { query in
|
state.changeQuery { query in
|
||||||
query.query = state.queryText
|
query.query = state.queryText
|
||||||
navigation.hideKeyboard()
|
|
||||||
}
|
}
|
||||||
RecentsModel.shared.addQuery(state.queryText)
|
RecentsModel.shared.addQuery(state.queryText)
|
||||||
|
navigation.hideKeyboard()
|
||||||
}
|
}
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.textFieldStyle(.plain)
|
.textFieldStyle(.plain)
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ struct SearchView: View {
|
|||||||
.opacity(state.queryText.isEmpty ? 0 : 1)
|
.opacity(state.queryText.isEmpty ? 0 : 1)
|
||||||
} else {
|
} else {
|
||||||
results
|
results
|
||||||
|
.backport
|
||||||
|
.scrollDismissesKeyboardInteractively()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.backport
|
|
||||||
.scrollDismissesKeyboardInteractively()
|
|
||||||
}
|
}
|
||||||
.environment(\.listingStyle, searchListingStyle)
|
.environment(\.listingStyle, searchListingStyle)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
|||||||
@@ -258,11 +258,13 @@ struct BrowsingSettings: View {
|
|||||||
private var visibleSectionsSettings: some View {
|
private var visibleSectionsSettings: some View {
|
||||||
Section(header: SettingsHeader(text: "Sections".localized())) {
|
Section(header: SettingsHeader(text: "Sections".localized())) {
|
||||||
ForEach(VisibleSection.allCases, id: \.self) { section in
|
ForEach(VisibleSection.allCases, id: \.self) { section in
|
||||||
MultiselectRow(
|
if section != .trending || FeatureFlags.trendingEnabled {
|
||||||
title: section.title,
|
MultiselectRow(
|
||||||
selected: visibleSections.contains(section)
|
title: section.title,
|
||||||
) { value in
|
selected: visibleSections.contains(section)
|
||||||
toggleSection(section, value: value)
|
) { value in
|
||||||
|
toggleSection(section, value: value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,7 +281,9 @@ struct BrowsingSettings: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
Picker("Startup section", selection: $startupSection) {
|
Picker("Startup section", selection: $startupSection) {
|
||||||
ForEach(StartupSection.allCases, id: \.rawValue) { section in
|
ForEach(StartupSection.allCases, id: \.rawValue) { section in
|
||||||
Text(section.label).tag(section)
|
if section != .trending || FeatureFlags.trendingEnabled {
|
||||||
|
Text(section.label).tag(section)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modifier(SettingsPickerModifier())
|
.modifier(SettingsPickerModifier())
|
||||||
@@ -287,7 +291,9 @@ struct BrowsingSettings: View {
|
|||||||
#else
|
#else
|
||||||
Picker("Startup section", selection: $startupSection) {
|
Picker("Startup section", selection: $startupSection) {
|
||||||
ForEach(StartupSection.allCases, id: \.rawValue) { section in
|
ForEach(StartupSection.allCases, id: \.rawValue) { section in
|
||||||
Text(section.label).tag(section)
|
if section != .trending || FeatureFlags.trendingEnabled {
|
||||||
|
Text(section.label).tag(section)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modifier(SettingsPickerModifier())
|
.modifier(SettingsPickerModifier())
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ struct FeedView: View {
|
|||||||
var header: some View {
|
var header: some View {
|
||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
|
// swiftlint:disable:next deployment_target
|
||||||
if #available(tvOS 17.0, *) {
|
if #available(tvOS 17.0, *) {
|
||||||
Menu {
|
Menu {
|
||||||
accountsPicker
|
accountsPicker
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ struct ThumbnailView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var placeholder: some View {
|
var placeholder: some View {
|
||||||
Rectangle().fill(Color("PlaceholderColor"))
|
Rectangle()
|
||||||
|
.fill(Color("PlaceholderColor"))
|
||||||
|
.aspectRatio(Constants.aspectRatio16x9, contentMode: .fill)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -432,14 +432,11 @@ struct VideoCell: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var thumbnailImage: some View {
|
private var thumbnailImage: some View {
|
||||||
Group {
|
VideoCellThumbnail(video: video)
|
||||||
VideoCellThumbnail(video: video)
|
#if os(tvOS)
|
||||||
|
.frame(minHeight: 320)
|
||||||
#if os(tvOS)
|
#endif
|
||||||
.frame(minHeight: 320)
|
.mask(RoundedRectangle(cornerRadius: thumbnailRoundingCornerRadius))
|
||||||
#endif
|
|
||||||
}
|
|
||||||
.mask(RoundedRectangle(cornerRadius: thumbnailRoundingCornerRadius))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var time: String? {
|
private var time: String? {
|
||||||
@@ -477,11 +474,10 @@ struct VideoCellThumbnail: View {
|
|||||||
private var thumbnails: ThumbnailsModel { .shared }
|
private var thumbnails: ThumbnailsModel { .shared }
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let (url, quality) = thumbnails.best(video)
|
let (url, _) = thumbnails.best(video)
|
||||||
let aspectRatio = (quality == .default || quality == .high) ? Constants.aspectRatio4x3 : Constants.aspectRatio16x9
|
|
||||||
|
|
||||||
ThumbnailView(url: url)
|
ThumbnailView(url: url)
|
||||||
.aspectRatio(aspectRatio, contentMode: .fill)
|
.aspectRatio(Constants.aspectRatio16x9, contentMode: .fill)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ struct ContentItemView: View {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
guard hideShorts, item.contentType == .video, let video = item.video else {
|
guard FeatureFlags.hideShortsEnabled, hideShorts, item.contentType == .video, let video = item.video else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,22 +5,24 @@ struct HideShortsButtons: View {
|
|||||||
@Default(.hideShorts) private var hideShorts
|
@Default(.hideShorts) private var hideShorts
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
if FeatureFlags.hideShortsEnabled {
|
||||||
hideShorts.toggle()
|
Button {
|
||||||
} label: {
|
hideShorts.toggle()
|
||||||
Group {
|
} label: {
|
||||||
if hideShorts {
|
Group {
|
||||||
Label("Short videos: hidden", systemImage: "bolt.slash.fill")
|
if hideShorts {
|
||||||
.help("Short videos: hidden")
|
Label("Short videos: hidden", systemImage: "bolt.slash.fill")
|
||||||
} else {
|
.help("Short videos: hidden")
|
||||||
Label("Short videos: visible", systemImage: "bolt.fill")
|
} else {
|
||||||
.help("Short videos: visible")
|
Label("Short videos: visible", systemImage: "bolt.fill")
|
||||||
|
.help("Short videos: visible")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#if os(tvOS)
|
||||||
|
.font(.caption)
|
||||||
|
.imageScale(.small)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#if os(tvOS)
|
|
||||||
.font(.caption)
|
|
||||||
.imageScale(.small)
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ struct PopularView: View {
|
|||||||
} label: {
|
} label: {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
Image(systemName: "arrow.up.right.circle.fill")
|
Image(systemName: "chart.bar.fill")
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
.imageScale(.small)
|
.imageScale(.small)
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,23 @@ struct YatteeApp: App {
|
|||||||
|
|
||||||
SDWebImageManager.defaultImageCache = PINCache(name: "stream.yattee.app")
|
SDWebImageManager.defaultImageCache = PINCache(name: "stream.yattee.app")
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(
|
||||||
|
forName: .accountConfigurationComplete,
|
||||||
|
object: nil,
|
||||||
|
queue: .main
|
||||||
|
) { _ in
|
||||||
|
let startupSection = Defaults[.startupSection]
|
||||||
|
var section: TabSelection? = startupSection.tabSelection
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
if section == .playlists {
|
||||||
|
section = .search
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NavigationModel.shared.tabSelection = section ?? .search
|
||||||
|
}
|
||||||
|
|
||||||
if !Defaults[.lastAccountIsPublic] {
|
if !Defaults[.lastAccountIsPublic] {
|
||||||
AccountsModel.shared.configureAccount()
|
AccountsModel.shared.configureAccount()
|
||||||
}
|
}
|
||||||
@@ -180,17 +197,6 @@ struct YatteeApp: App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let startupSection = Defaults[.startupSection]
|
|
||||||
var section: TabSelection? = startupSection.tabSelection
|
|
||||||
|
|
||||||
#if os(macOS)
|
|
||||||
if section == .playlists {
|
|
||||||
section = .search
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NavigationModel.shared.tabSelection = section ?? .search
|
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
playlists.load()
|
playlists.load()
|
||||||
}
|
}
|
||||||
@@ -231,6 +237,10 @@ struct YatteeApp: App {
|
|||||||
self.migrateQualityProfiles()
|
self.migrateQualityProfiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async {
|
||||||
|
self.cleanupDisabledFeatures()
|
||||||
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
DispatchQueue.global(qos: .userInitiated).async {
|
DispatchQueue.global(qos: .userInitiated).async {
|
||||||
self.migrateRotateToLandscapeOnEnterFullScreen()
|
self.migrateRotateToLandscapeOnEnterFullScreen()
|
||||||
@@ -285,6 +295,34 @@ struct YatteeApp: App {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
func cleanupDisabledFeatures() {
|
||||||
|
// Remove trending from visible sections if feature flag is disabled
|
||||||
|
if !FeatureFlags.trendingEnabled {
|
||||||
|
var visibleSections = Defaults[.visibleSections]
|
||||||
|
if visibleSections.contains(.trending) {
|
||||||
|
visibleSections.remove(.trending)
|
||||||
|
Defaults[.visibleSections] = visibleSections
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset startup section if set to trending
|
||||||
|
if Defaults[.startupSection] == .trending {
|
||||||
|
Defaults[.startupSection] = .home
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trending favorites
|
||||||
|
let trendingFavorites = favorites.all.filter { item in
|
||||||
|
if case .trending = item.section {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for favorite in trendingFavorites {
|
||||||
|
favorites.remove(favorite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var navigationStyle: NavigationStyle {
|
var navigationStyle: NavigationStyle {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
return horizontalSizeClass == .compact ? .tab : .sidebar
|
return horizontalSizeClass == .compact ? .tab : .sidebar
|
||||||
|
|||||||
@@ -43,6 +43,9 @@
|
|||||||
/* End PBXAggregateTarget section */
|
/* End PBXAggregateTarget section */
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
1B81344D4D2A0B0363850A9E /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
|
2446210B2B03C320154634A5 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
|
3528A0FEB2B02A52B715041C /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
3700155B271B0D4D0049C794 /* PipedAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700155A271B0D4D0049C794 /* PipedAPI.swift */; };
|
3700155B271B0D4D0049C794 /* PipedAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700155A271B0D4D0049C794 /* PipedAPI.swift */; };
|
||||||
3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700155A271B0D4D0049C794 /* PipedAPI.swift */; };
|
3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700155A271B0D4D0049C794 /* PipedAPI.swift */; };
|
||||||
3700155D271B0D4D0049C794 /* PipedAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700155A271B0D4D0049C794 /* PipedAPI.swift */; };
|
3700155D271B0D4D0049C794 /* PipedAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700155A271B0D4D0049C794 /* PipedAPI.swift */; };
|
||||||
@@ -207,6 +210,9 @@
|
|||||||
37319F0627103F94004ECCD0 /* PlayerQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37319F0427103F94004ECCD0 /* PlayerQueue.swift */; };
|
37319F0627103F94004ECCD0 /* PlayerQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37319F0427103F94004ECCD0 /* PlayerQueue.swift */; };
|
||||||
37319F0727103F94004ECCD0 /* PlayerQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37319F0427103F94004ECCD0 /* PlayerQueue.swift */; };
|
37319F0727103F94004ECCD0 /* PlayerQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37319F0427103F94004ECCD0 /* PlayerQueue.swift */; };
|
||||||
3732BFD028B83763009F3F4D /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 3732BFCF28B83763009F3F4D /* KeychainAccess */; };
|
3732BFD028B83763009F3F4D /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 3732BFCF28B83763009F3F4D /* KeychainAccess */; };
|
||||||
|
3736882B2ECE7947006B1D1F /* Notification+Names.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3736882A2ECE7947006B1D1F /* Notification+Names.swift */; };
|
||||||
|
3736882C2ECE7947006B1D1F /* Notification+Names.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3736882A2ECE7947006B1D1F /* Notification+Names.swift */; };
|
||||||
|
3736882D2ECE7947006B1D1F /* Notification+Names.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3736882A2ECE7947006B1D1F /* Notification+Names.swift */; };
|
||||||
3738535429451DC800D2D0CB /* BookmarksCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */; };
|
3738535429451DC800D2D0CB /* BookmarksCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */; };
|
||||||
3738535529451DC800D2D0CB /* BookmarksCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */; };
|
3738535529451DC800D2D0CB /* BookmarksCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */; };
|
||||||
3738535629451DC800D2D0CB /* BookmarksCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */; };
|
3738535629451DC800D2D0CB /* BookmarksCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */; };
|
||||||
@@ -1071,6 +1077,8 @@
|
|||||||
37FFC440272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; };
|
37FFC440272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; };
|
||||||
37FFC441272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; };
|
37FFC441272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; };
|
||||||
37FFC442272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; };
|
37FFC442272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; };
|
||||||
|
4EDC5582D5232B58E0E6A3CD /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
|
C61471C67790128B7638173B /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
E24DC6582BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; };
|
E24DC6582BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; };
|
||||||
E24DC6592BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; };
|
E24DC6592BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; };
|
||||||
E24DC65A2BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; };
|
E24DC65A2BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; };
|
||||||
@@ -1086,6 +1094,9 @@
|
|||||||
E27568B92BFAAC2000BDF0AF /* LanguageCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27568B82BFAAC2000BDF0AF /* LanguageCodes.swift */; };
|
E27568B92BFAAC2000BDF0AF /* LanguageCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27568B82BFAAC2000BDF0AF /* LanguageCodes.swift */; };
|
||||||
E27568BA2BFAAC2000BDF0AF /* LanguageCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27568B82BFAAC2000BDF0AF /* LanguageCodes.swift */; };
|
E27568BA2BFAAC2000BDF0AF /* LanguageCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27568B82BFAAC2000BDF0AF /* LanguageCodes.swift */; };
|
||||||
E27568BB2BFAAC2000BDF0AF /* LanguageCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27568B82BFAAC2000BDF0AF /* LanguageCodes.swift */; };
|
E27568BB2BFAAC2000BDF0AF /* LanguageCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E27568B82BFAAC2000BDF0AF /* LanguageCodes.swift */; };
|
||||||
|
E69D11698A85867A28CD6A5A /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
|
F18DFC08B722DE4D5ACB791A /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
|
F3BFD18BABAA233ADA094AC6 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D886FD1371688A42060DF82 /* FeatureFlags.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -1215,6 +1226,7 @@
|
|||||||
373197D82732015300EF734F /* RelatedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelatedView.swift; sourceTree = "<group>"; };
|
373197D82732015300EF734F /* RelatedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelatedView.swift; sourceTree = "<group>"; };
|
||||||
37319F0427103F94004ECCD0 /* PlayerQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerQueue.swift; sourceTree = "<group>"; };
|
37319F0427103F94004ECCD0 /* PlayerQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerQueue.swift; sourceTree = "<group>"; };
|
||||||
37367E582B8F63C200436163 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
37367E582B8F63C200436163 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
|
3736882A2ECE7947006B1D1F /* Notification+Names.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Names.swift"; sourceTree = "<group>"; };
|
||||||
3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksCacheModel.swift; sourceTree = "<group>"; };
|
3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksCacheModel.swift; sourceTree = "<group>"; };
|
||||||
373C8FE3275B955100CB5936 /* CommentsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentsPage.swift; sourceTree = "<group>"; };
|
373C8FE3275B955100CB5936 /* CommentsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentsPage.swift; sourceTree = "<group>"; };
|
||||||
373CFACA26966264003CB2C6 /* SearchQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchQuery.swift; sourceTree = "<group>"; };
|
373CFACA26966264003CB2C6 /* SearchQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchQuery.swift; sourceTree = "<group>"; };
|
||||||
@@ -1558,6 +1570,7 @@
|
|||||||
3DA101AD287C30F50027D920 /* DEVELOPMENT_TEAM.template.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.template.xcconfig; sourceTree = "<group>"; };
|
3DA101AD287C30F50027D920 /* DEVELOPMENT_TEAM.template.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.template.xcconfig; sourceTree = "<group>"; };
|
||||||
3DA101AE287C30F50027D920 /* DEVELOPMENT_TEAM.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.xcconfig; sourceTree = "<group>"; };
|
3DA101AE287C30F50027D920 /* DEVELOPMENT_TEAM.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.xcconfig; sourceTree = "<group>"; };
|
||||||
3DA101AF287C30F50027D920 /* Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
3DA101AF287C30F50027D920 /* Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
||||||
|
5D886FD1371688A42060DF82 /* FeatureFlags.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = "<group>"; };
|
||||||
E24DC6572BFA124100BF6187 /* UserAgentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentManager.swift; sourceTree = "<group>"; };
|
E24DC6572BFA124100BF6187 /* UserAgentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentManager.swift; sourceTree = "<group>"; };
|
||||||
E25028AF2BF790F5002CB9FC /* HTTPStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStatus.swift; sourceTree = "<group>"; };
|
E25028AF2BF790F5002CB9FC /* HTTPStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStatus.swift; sourceTree = "<group>"; };
|
||||||
E258F3892BF61BD2005B8C28 /* URLTester.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLTester.swift; sourceTree = "<group>"; };
|
E258F3892BF61BD2005B8C28 /* URLTester.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLTester.swift; sourceTree = "<group>"; };
|
||||||
@@ -2240,6 +2253,7 @@
|
|||||||
37C7A9022679058300E721B4 /* Extensions */ = {
|
37C7A9022679058300E721B4 /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
3736882A2ECE7947006B1D1F /* Notification+Names.swift */,
|
||||||
379775922689365600DD52A8 /* Array+Next.swift */,
|
379775922689365600DD52A8 /* Array+Next.swift */,
|
||||||
37DCD3162A191A180059A470 /* AVPlayerViewController+FullScreen.swift */,
|
37DCD3162A191A180059A470 /* AVPlayerViewController+FullScreen.swift */,
|
||||||
376578842685429C00D4EA09 /* CaseIterable+Next.swift */,
|
376578842685429C00D4EA09 /* CaseIterable+Next.swift */,
|
||||||
@@ -2325,6 +2339,7 @@
|
|||||||
37D4B0C22671614700C925CA /* YatteeApp.swift */,
|
37D4B0C22671614700C925CA /* YatteeApp.swift */,
|
||||||
37D4B0C42671614800C925CA /* Assets.xcassets */,
|
37D4B0C42671614800C925CA /* Assets.xcassets */,
|
||||||
37BD07C42698ADEE003EBB87 /* Yattee.entitlements */,
|
37BD07C42698ADEE003EBB87 /* Yattee.entitlements */,
|
||||||
|
5D886FD1371688A42060DF82 /* FeatureFlags.swift */,
|
||||||
);
|
);
|
||||||
path = Shared;
|
path = Shared;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -2832,7 +2847,7 @@
|
|||||||
3765917827237D07009F956E /* XCRemoteSwiftPackageReference "PINCache" */,
|
3765917827237D07009F956E /* XCRemoteSwiftPackageReference "PINCache" */,
|
||||||
37CF8B8228535E4F00B71E37 /* XCRemoteSwiftPackageReference "SDWebImage" */,
|
37CF8B8228535E4F00B71E37 /* XCRemoteSwiftPackageReference "SDWebImage" */,
|
||||||
372AA40E286D067B0000B1DC /* XCRemoteSwiftPackageReference "Repeat" */,
|
372AA40E286D067B0000B1DC /* XCRemoteSwiftPackageReference "Repeat" */,
|
||||||
37EE6DC328A305AD00BFD632 /* XCRemoteSwiftPackageReference "Reachability" */,
|
37EE6DC328A305AD00BFD632 /* XCRemoteSwiftPackageReference "Reachability.swift" */,
|
||||||
3799AC0728B03CEC001376F9 /* XCRemoteSwiftPackageReference "ActiveLabel.swift" */,
|
3799AC0728B03CEC001376F9 /* XCRemoteSwiftPackageReference "ActiveLabel.swift" */,
|
||||||
375B8AAF28B57F4200397B31 /* XCRemoteSwiftPackageReference "KeychainAccess" */,
|
375B8AAF28B57F4200397B31 /* XCRemoteSwiftPackageReference "KeychainAccess" */,
|
||||||
3797104728D3D10600D5F53C /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */,
|
3797104728D3D10600D5F53C /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */,
|
||||||
@@ -3064,6 +3079,7 @@
|
|||||||
3762C46D2BF66CDD008E50B8 /* EnvironmentValues.swift in Sources */,
|
3762C46D2BF66CDD008E50B8 /* EnvironmentValues.swift in Sources */,
|
||||||
37095E82291DC85400301883 /* ShareViewController.swift in Sources */,
|
37095E82291DC85400301883 /* ShareViewController.swift in Sources */,
|
||||||
3762C47A2BF66F04008E50B8 /* Strings.swift in Sources */,
|
3762C47A2BF66F04008E50B8 /* Strings.swift in Sources */,
|
||||||
|
C61471C67790128B7638173B /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -3076,6 +3092,7 @@
|
|||||||
37C0C0FF28665EAC007F6F78 /* VideosApp.swift in Sources */,
|
37C0C0FF28665EAC007F6F78 /* VideosApp.swift in Sources */,
|
||||||
378FFBC92866018A009E3FBE /* URLParserTests.swift in Sources */,
|
378FFBC92866018A009E3FBE /* URLParserTests.swift in Sources */,
|
||||||
371B88F82A1A310100D57683 /* String+Format.swift in Sources */,
|
371B88F82A1A310100D57683 /* String+Format.swift in Sources */,
|
||||||
|
3528A0FEB2B02A52B715041C /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -3297,6 +3314,7 @@
|
|||||||
37BA794F26DC3E0E002A0235 /* Int+Format.swift in Sources */,
|
37BA794F26DC3E0E002A0235 /* Int+Format.swift in Sources */,
|
||||||
378E9C3C2945565500B2D696 /* SubscriptionsView.swift in Sources */,
|
378E9C3C2945565500B2D696 /* SubscriptionsView.swift in Sources */,
|
||||||
37D6025928C17375009E8D98 /* PlaybackStatsView.swift in Sources */,
|
37D6025928C17375009E8D98 /* PlaybackStatsView.swift in Sources */,
|
||||||
|
3736882D2ECE7947006B1D1F /* Notification+Names.swift in Sources */,
|
||||||
37F49BA326CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
37F49BA326CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
||||||
374C053B2724614F009BDDBE /* PlayerTVMenu.swift in Sources */,
|
374C053B2724614F009BDDBE /* PlayerTVMenu.swift in Sources */,
|
||||||
37A9965A26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
|
37A9965A26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
|
||||||
@@ -3403,6 +3421,7 @@
|
|||||||
37B795902771DAE0001CF27B /* OpenURLHandler.swift in Sources */,
|
37B795902771DAE0001CF27B /* OpenURLHandler.swift in Sources */,
|
||||||
37732FF02703A26300F04329 /* AccountValidationStatus.swift in Sources */,
|
37732FF02703A26300F04329 /* AccountValidationStatus.swift in Sources */,
|
||||||
37A7D72F2B681011009CB1ED /* OtherDataSettingsGroupImporter.swift in Sources */,
|
37A7D72F2B681011009CB1ED /* OtherDataSettingsGroupImporter.swift in Sources */,
|
||||||
|
2446210B2B03C320154634A5 /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -3644,6 +3663,7 @@
|
|||||||
37A81BFA294BD1440081D322 /* WatchView.swift in Sources */,
|
37A81BFA294BD1440081D322 /* WatchView.swift in Sources */,
|
||||||
3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */,
|
3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */,
|
||||||
376BE50C27349108009AD608 /* BrowsingSettings.swift in Sources */,
|
376BE50C27349108009AD608 /* BrowsingSettings.swift in Sources */,
|
||||||
|
3736882C2ECE7947006B1D1F /* Notification+Names.swift in Sources */,
|
||||||
3710A55629488C7D006F8025 /* PlaceholderListItem.swift in Sources */,
|
3710A55629488C7D006F8025 /* PlaceholderListItem.swift in Sources */,
|
||||||
37EBD8CB27AF26C200F1C24B /* MPVBackend.swift in Sources */,
|
37EBD8CB27AF26C200F1C24B /* MPVBackend.swift in Sources */,
|
||||||
37D4B19826717E1500C925CA /* Video.swift in Sources */,
|
37D4B19826717E1500C925CA /* Video.swift in Sources */,
|
||||||
@@ -3710,6 +3730,7 @@
|
|||||||
3769C02F2779F18600DDB3EA /* PlaceholderProgressView.swift in Sources */,
|
3769C02F2779F18600DDB3EA /* PlaceholderProgressView.swift in Sources */,
|
||||||
37BA794426DBA973002A0235 /* PlaylistsModel.swift in Sources */,
|
37BA794426DBA973002A0235 /* PlaylistsModel.swift in Sources */,
|
||||||
37A362BF29537AAA00BDF328 /* PlaybackSettings.swift in Sources */,
|
37A362BF29537AAA00BDF328 /* PlaybackSettings.swift in Sources */,
|
||||||
|
4EDC5582D5232B58E0E6A3CD /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -3718,6 +3739,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
37D4B0D92671614900C925CA /* Tests_iOS.swift in Sources */,
|
37D4B0D92671614900C925CA /* Tests_iOS.swift in Sources */,
|
||||||
|
F3BFD18BABAA233ADA094AC6 /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -3771,6 +3793,7 @@
|
|||||||
3766AFD2273DA97D00686348 /* Int+FormatTests.swift in Sources */,
|
3766AFD2273DA97D00686348 /* Int+FormatTests.swift in Sources */,
|
||||||
3774124F27387D2300423605 /* SubscribedChannelsModel.swift in Sources */,
|
3774124F27387D2300423605 /* SubscribedChannelsModel.swift in Sources */,
|
||||||
3774126127387D2D00423605 /* AccountsModel.swift in Sources */,
|
3774126127387D2D00423605 /* AccountsModel.swift in Sources */,
|
||||||
|
F18DFC08B722DE4D5ACB791A /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -3942,6 +3965,7 @@
|
|||||||
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
||||||
3756C2A82861131100E4B059 /* NetworkState.swift in Sources */,
|
3756C2A82861131100E4B059 /* NetworkState.swift in Sources */,
|
||||||
376578932685490700D4EA09 /* PlaylistsView.swift in Sources */,
|
376578932685490700D4EA09 /* PlaylistsView.swift in Sources */,
|
||||||
|
3736882B2ECE7947006B1D1F /* Notification+Names.swift in Sources */,
|
||||||
37E75CCD2B6AEB01003A6237 /* RecentlyOpenedExporter.swift in Sources */,
|
37E75CCD2B6AEB01003A6237 /* RecentlyOpenedExporter.swift in Sources */,
|
||||||
377FF891291A99580028EB0B /* HistoryView.swift in Sources */,
|
377FF891291A99580028EB0B /* HistoryView.swift in Sources */,
|
||||||
37CC3F47270CE30600608308 /* PlayerQueueItem.swift in Sources */,
|
37CC3F47270CE30600608308 /* PlayerQueueItem.swift in Sources */,
|
||||||
@@ -4064,6 +4088,7 @@
|
|||||||
3797758D2689345500DD52A8 /* Store.swift in Sources */,
|
3797758D2689345500DD52A8 /* Store.swift in Sources */,
|
||||||
37484C2F26FC844700287258 /* InstanceSettings.swift in Sources */,
|
37484C2F26FC844700287258 /* InstanceSettings.swift in Sources */,
|
||||||
37A7D7312B681011009CB1ED /* OtherDataSettingsGroupImporter.swift in Sources */,
|
37A7D7312B681011009CB1ED /* OtherDataSettingsGroupImporter.swift in Sources */,
|
||||||
|
1B81344D4D2A0B0363850A9E /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -4072,6 +4097,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
37D4B176267164B000C925CA /* YatteeUITests.swift in Sources */,
|
37D4B176267164B000C925CA /* YatteeUITests.swift in Sources */,
|
||||||
|
E69D11698A85867A28CD6A5A /* FeatureFlags.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -4142,7 +4168,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
|
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
|
||||||
@@ -4173,7 +4199,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
@@ -4204,7 +4230,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||||
@@ -4224,7 +4250,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||||
@@ -4388,7 +4414,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
|
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
@@ -4442,7 +4468,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
|
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
|
||||||
@@ -4496,7 +4522,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@@ -4535,7 +4561,7 @@
|
|||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
@@ -4570,7 +4596,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4593,7 +4619,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4618,7 +4644,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4642,7 +4668,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4668,7 +4694,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -4708,7 +4734,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -4748,7 +4774,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -4771,7 +4797,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 209;
|
CURRENT_PROJECT_VERSION = 210;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -5034,7 +5060,7 @@
|
|||||||
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git";
|
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMajorVersion;
|
kind = upToNextMajorVersion;
|
||||||
minimumVersion = 1.3.0;
|
minimumVersion = 26.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
37CF8B8228535E4F00B71E37 /* XCRemoteSwiftPackageReference "SDWebImage" */ = {
|
37CF8B8228535E4F00B71E37 /* XCRemoteSwiftPackageReference "SDWebImage" */ = {
|
||||||
@@ -5053,7 +5079,7 @@
|
|||||||
minimumVersion = 5.0.2;
|
minimumVersion = 5.0.2;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
37EE6DC328A305AD00BFD632 /* XCRemoteSwiftPackageReference "Reachability" */ = {
|
37EE6DC328A305AD00BFD632 /* XCRemoteSwiftPackageReference "Reachability.swift" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/ashleymills/Reachability.swift";
|
repositoryURL = "https://github.com/ashleymills/Reachability.swift";
|
||||||
requirement = {
|
requirement = {
|
||||||
@@ -5335,7 +5361,7 @@
|
|||||||
};
|
};
|
||||||
37EE6DC428A305AD00BFD632 /* Reachability */ = {
|
37EE6DC428A305AD00BFD632 /* Reachability */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 37EE6DC328A305AD00BFD632 /* XCRemoteSwiftPackageReference "Reachability" */;
|
package = 37EE6DC328A305AD00BFD632 /* XCRemoteSwiftPackageReference "Reachability.swift" */;
|
||||||
productName = Reachability;
|
productName = Reachability;
|
||||||
};
|
};
|
||||||
37FB2848272207F000A57617 /* SDWebImageWebPCoder */ = {
|
37FB2848272207F000A57617 /* SDWebImageWebPCoder */ = {
|
||||||
|
|||||||
@@ -168,8 +168,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
|
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "807f73ce09a9b9723f12385e592b4e0aaebd3336",
|
"revision" : "a08b87f96b41055577721a6e397562b21ad52454",
|
||||||
"version" : "1.3.0"
|
"version" : "26.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,13 +22,6 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
OrientationTracker.shared.startDeviceOrientationTracking()
|
OrientationTracker.shared.startDeviceOrientationTracking()
|
||||||
OrientationModel.shared.startOrientationUpdates()
|
OrientationModel.shared.startOrientationUpdates()
|
||||||
|
|
||||||
do {
|
|
||||||
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
|
|
||||||
try AVAudioSession.sharedInstance().setActive(true)
|
|
||||||
} catch {
|
|
||||||
logger.error("Failed to set audio session category: \(error)")
|
|
||||||
}
|
|
||||||
|
|
||||||
UIApplication.shared.beginReceivingRemoteControlEvents()
|
UIApplication.shared.beginReceivingRemoteControlEvents()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ struct TVNavigationView: View {
|
|||||||
.tag(TabSelection.popular)
|
.tag(TabSelection.popular)
|
||||||
}
|
}
|
||||||
|
|
||||||
if visibleSections.contains(.trending) {
|
if FeatureFlags.trendingEnabled && visibleSections.contains(.trending) {
|
||||||
LazyView(TrendingView())
|
LazyView(TrendingView())
|
||||||
.tabItem { Text("Trending") }
|
.tabItem { Text("Trending") }
|
||||||
.tag(TabSelection.trending)
|
.tag(TabSelection.trending)
|
||||||
|
|||||||
Reference in New Issue
Block a user