Compare commits

...

22 Commits

Author SHA1 Message Date
Arkadiusz Fal
088d5a69dd Bump version number 2022-01-30 23:05:26 +01:00
Arkadiusz Fal
1dfdb5ece3 Fix opening playlists when recents is not saved (fix #57) 2022-01-30 22:52:20 +01:00
Arkadiusz Fal
5f263efeb2 Bump build and version number 2022-01-24 22:34:24 +01:00
Arkadiusz Fal
a98b4eac83 Fix selecting best quality stream (fix #54) 2022-01-24 22:23:10 +01:00
Arkadiusz Fal
975b8fe5c3 Fix displaying settings/account buttons when only search is visible (fix #56) 2022-01-24 22:22:47 +01:00
Arkadiusz Fal
33e86710a8 Bump build number 2022-01-20 23:14:42 +01:00
Arkadiusz Fal
96f4e819a7 Update README 2022-01-20 23:14:11 +01:00
Arkadiusz Fal
8ab97ddbaf Fix search closing when entering new query after opening recent 2022-01-20 23:14:11 +01:00
Arkadiusz Fal
df72bf99ba Fix displaying searches in favorites 2022-01-13 21:16:25 +01:00
Arkadiusz Fal
db4a817164 Bump build number 2022-01-09 16:52:12 +01:00
Arkadiusz Fal
ce8a8cbef3 Fix selecting video details tab on sidebar visibility change 2022-01-09 16:38:17 +01:00
Arkadiusz Fal
a04827cc56 Fix restoring queue 2022-01-09 16:38:05 +01:00
Arkadiusz Fal
534f356471 Fix search suggestion prefix 2022-01-09 15:47:48 +01:00
Arkadiusz Fal
5050ad5d02 Fix menu command for Popular 2022-01-09 15:47:24 +01:00
Arkadiusz Fal
ca38133b1d Fix opening channel from video details 2022-01-09 15:47:00 +01:00
Arkadiusz Fal
a9ccd6b0f2 Bump build number 2022-01-07 22:19:13 +01:00
Arkadiusz Fal
76273a4724 Add option to rotate to landscape on entering fullscreen with button 2022-01-07 22:19:11 +01:00
Arkadiusz Fal
8370714b61 Fix hiding history in Now Playing view in tvOS 2022-01-07 20:11:56 +01:00
Arkadiusz Fal
d096fdb344 Slightly more compact thumbnails badges 2022-01-07 20:06:18 +01:00
Arkadiusz Fal
5b12dbcb1e Pause before dismissing player on tvOS 2022-01-07 19:48:03 +01:00
Arkadiusz Fal
d1ed896166 Add SponsorBlock categories details 2022-01-07 19:46:47 +01:00
Arkadiusz Fal
3630cd404d Fix refresh buttons opacity 2022-01-07 12:12:56 +01:00
27 changed files with 232 additions and 72 deletions

View File

@@ -47,7 +47,7 @@ final class NavigationModel: ObservableObject {
recents: RecentsModel,
navigation: NavigationModel,
navigationStyle: NavigationStyle,
delay: Bool = false
delay: Bool = true
) {
let recent = RecentItem(from: channel)
#if os(macOS)

View File

@@ -33,7 +33,7 @@ final class PlayerModel: ObservableObject {
@Published var streamSelection: Stream? { didSet { rebuildTVMenu() } }
@Published var queue = [PlayerQueueItem]() { didSet { Defaults[.queue] = queue } }
@Published var currentItem: PlayerQueueItem! { didSet { updateWindowTitle() } }
@Published var currentItem: PlayerQueueItem! { didSet { handleCurrentItemChange() } }
@Published var historyVideos = [Video]()
@Published var preservedTime: CMTime?
@@ -804,10 +804,12 @@ final class PlayerModel: ObservableObject {
}
#endif
func updateWindowTitle() {
func handleCurrentItemChange() {
#if os(macOS)
Windows.player.window?.title = windowTitle
#endif
Defaults[.lastPlayed] = currentItem
}
#if os(macOS)

View File

@@ -95,7 +95,9 @@ extension PlayerModel {
switch quality {
case .best:
return streams.first { $0.kind == .hls } ?? streams.first
return streams.first { $0.kind == .hls } ??
streams.filter { $0.kind == .stream }.max { $0.resolution < $1.resolution } ??
streams.first
default:
let sorted = streams.filter { $0.kind != .hls }.sorted { $0.resolution > $1.resolution }
return sorted.first(where: { $0.resolution.height <= quality.value.height })
@@ -201,4 +203,21 @@ extension PlayerModel {
func removeQueueItems() {
queue.removeAll()
}
func restoreQueue() {
guard !accounts.current.isNil else {
return
}
queue = ([Defaults[.lastPlayed]] + Defaults[.queue]).compactMap { $0 }
Defaults[.lastPlayed] = nil
queue.forEach { item in
accounts.api.loadDetails(item) { newItem in
if let index = self.queue.firstIndex(where: { $0.id == item.id }) {
self.queue[index] = newItem
}
}
}
}
}

View File

@@ -16,7 +16,7 @@ final class RecentsModel: ObservableObject {
if !saveRecents {
clear()
if item.type != .channel {
if item.type == .query {
return
}
}
@@ -34,8 +34,9 @@ final class RecentsModel: ObservableObject {
}
}
func addQuery(_ query: String) {
func addQuery(_ query: String, navigation: NavigationModel? = nil) {
if !query.isEmpty {
navigation?.tabSelection = .search
add(.init(from: query))
}
}

View File

@@ -20,13 +20,47 @@ final class SponsorBlockAPI: ObservableObject {
switch name {
case "selfpromo":
return "Self-promotion"
case "music_offtopic":
return "Offtopic in Music Videos"
default:
return name.capitalized
}
}
static func categoryDetails(_ name: String) -> String? {
guard SponsorBlockAPI.categories.contains(name) else {
return nil
}
switch name {
case "sponsor":
return "Part of a video promoting a product or service not directly related to the creator. " +
"The creator will receive payment or compensation in the form of money or free products."
case "selfpromo":
return "Promoting a product or service that is directly related to the creator themselves. " +
"This usually includes merchandise or promotion of monetized platforms."
case "intro":
return "Segments typically found at the start of a video that include an animation, " +
"still frame or clip which are also seen in other videos by the same creator."
case "outro":
return "Typically near or at the end of the video when the credits pop up and/or endcards are shown."
case "interaction":
return "Explicit reminders to like, subscribe or interact with them on any paid or free platform(s) (e.g. click on a video)."
case "music_offtopic":
return "For videos which feature music as the primary content."
default:
return nil
}
}
func loadSegments(videoID: String, categories: Set<String>, completionHandler: @escaping () -> Void = {}) {
guard !skipSegmentsURL.isNil, self.videoID != videoID else {
completionHandler()

View File

@@ -1,7 +1,7 @@
<div align="center">
<img src="https://r.yattee.stream/icons/yattee-150.png" width="150" height="150" alt="Yattee logo">
<h1>Yattee</h1>
<p>Videos browser and player for <a href="https://github.com/iv-org/invidious">Invidious</a> and <a href="https://github.com/TeamPiped/Piped">Piped</a> (alternative, privacy-friendly YouTube frontends)<br />built for iOS, tvOS and macOS.</p>
<p>Alternative YouTube frontend for iOS, tvOS and macOS<br />built with <a href="https://github.com/iv-org/invidious">Invidious</a> and <a href="https://github.com/TeamPiped/Piped">Piped</a></p>
[![AGPL v3](https://shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.en.html)
[![GitHub issues](https://img.shields.io/github/issues/yattee/yattee)](https://github.com/yattee/yattee/issues)

View File

@@ -64,6 +64,7 @@ extension Defaults.Keys {
static let recentlyOpened = Key<[RecentItem]>("recentlyOpened", default: [])
static let queue = Key<[PlayerQueueItem]>("queue", default: [])
static let lastPlayed = Key<PlayerQueueItem?>("lastPlayed")
static let saveHistory = Key<Bool>("saveHistory", default: true)
static let showWatchingProgress = Key<Bool>("showWatchingProgress", default: true)
@@ -86,6 +87,7 @@ extension Defaults.Keys {
#if os(iOS)
static let honorSystemOrientationLock = Key<Bool>("honorSystemOrientationLock", default: true)
static let enterFullscreenInLandscape = Key<Bool>("enterFullscreenInLandscape", default: UIDevice.current.userInterfaceIdiom == .phone)
static let lockLandscapeOnRotation = Key<Bool>("lockLandscapeOnRotation", default: false)
static let lockLandscapeWhenEnteringFullscreen = Key<Bool>("lockLandscapeWhenEnteringFullscreen", default: false)
#endif
}

View File

@@ -30,10 +30,10 @@ private struct CurrentPlaylistID: EnvironmentKey {
}
private struct LoadMoreContentHandler: EnvironmentKey {
static let defaultValue: LoadMoreContentHandlerClosure = { print("infinite load") }
static let defaultValue: LoadMoreContentHandlerType = {}
}
typealias LoadMoreContentHandlerClosure = () -> Void
typealias LoadMoreContentHandlerType = () -> Void
extension EnvironmentValues {
var inNavigationView: Bool {
@@ -66,7 +66,7 @@ extension EnvironmentValues {
set { self[CurrentPlaylistID.self] = newValue }
}
var loadMoreContentHandler: LoadMoreContentHandlerClosure {
var loadMoreContentHandler: LoadMoreContentHandlerType {
get { self[LoadMoreContentHandler.self] }
set { self[LoadMoreContentHandler.self] = newValue }
}

View File

@@ -13,6 +13,8 @@ final class FavoriteResourceObserver: ObservableObject, ResourceObserver {
contentItems = playlist.videos.map { ContentItem(video: $0) }
} else if let playlist: Playlist = resource.typedContent() {
contentItems = playlist.videos.map { ContentItem(video: $0) }
} else if let page: SearchPage = resource.typedContent() {
contentItems = page.results
} else if let items: [ContentItem] = resource.typedContent() {
contentItems = items
}

View File

@@ -25,7 +25,7 @@ struct MenuCommands: Commands {
Button("Popular") {
model.navigation?.tabSelection = .popular
}
.disabled(!(model.accounts?.app.supportsPopular ?? true))
.disabled(!(model.accounts?.app.supportsPopular ?? false))
.keyboardShortcut("3")
Button("Trending") {

View File

@@ -35,7 +35,7 @@ struct AppTabNavigation: View {
trendingNavigationView
}
if visibleSections.contains(.playlists), accounts.app.supportsUserPlaylists {
if playlistsVisible {
playlistsNavigationView
}
@@ -118,6 +118,11 @@ struct AppTabNavigation: View {
accounts.app.supportsSubscriptions && !(accounts.current?.anonymous ?? true)
}
private var playlistsVisible: Bool {
visibleSections.contains(.playlists) &&
accounts.app.supportsUserPlaylists && !(accounts.current?.anonymous ?? true)
}
private var popularNavigationView: some View {
NavigationView {
LazyView(PopularView())

View File

@@ -139,6 +139,10 @@ struct ContentView: View {
player.accounts = accounts
player.comments = comments
if !accounts.current.isNil {
player.restoreQueue()
}
if !Defaults[.saveRecents] {
recents.clear()
}

View File

@@ -127,6 +127,9 @@ extension PlayerViewController: AVPlayerViewControllerDelegate {
}
func playerViewControllerWillBeginDismissalTransition(_: AVPlayerViewController) {
if Defaults[.pauseOnHidingPlayer] {
playerModel.pause()
}
dismiss(animated: false)
}
@@ -134,9 +137,15 @@ extension PlayerViewController: AVPlayerViewControllerDelegate {
func playerViewController(
_: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator
willBeginFullScreenPresentationWithAnimationCoordinator context: UIViewControllerTransitionCoordinator
) {
playerModel.playingFullscreen = true
#if os(iOS)
if !context.isCancelled, Defaults[.lockLandscapeWhenEnteringFullscreen] {
Orientation.lockOrientation(.landscape, andRotateTo: UIDevice.current.orientation.isLandscape ? nil : .landscapeRight)
}
#endif
}
func playerViewController(

View File

@@ -5,7 +5,7 @@ import SwiftUI
struct VideoDetails: View {
enum Page {
case info, queue, related, comments
case info, comments, related, queue
}
@Binding var sidebarQueue: Bool
@@ -129,7 +129,7 @@ struct VideoDetails: View {
}
.onChange(of: sidebarQueue) { queue in
if queue {
if currentPage == .queue {
if currentPage == .related || currentPage == .queue {
currentPage = .info
}
} else if video.isNil {

View File

@@ -28,13 +28,11 @@ struct VideoPlayerView: View {
@Default(.enterFullscreenInLandscape) private var enterFullscreenInLandscape
@Default(.honorSystemOrientationLock) private var honorSystemOrientationLock
@Default(.lockLandscapeWhenEnteringFullscreen) private var lockLandscapeWhenEnteringFullscreen
@Default(.lockLandscapeOnRotation) private var lockLandscapeOnRotation
@State private var motionManager: CMMotionManager!
@State private var orientation = UIInterfaceOrientation.portrait
@State private var lastOrientation: UIInterfaceOrientation?
private var orientationThrottle = Throttle(interval: 2)
#endif
@EnvironmentObject<AccountsModel> private var accounts
@@ -140,7 +138,11 @@ struct VideoPlayerView: View {
#endif
}
.background(colorScheme == .dark ? Color.black : Color.white)
.modifier(VideoDetailsPaddingModifier(geometry: geometry, aspectRatio: player.controller?.aspectRatio, fullScreen: fullScreenDetails))
.modifier(VideoDetailsPaddingModifier(
geometry: geometry,
aspectRatio: player.controller?.aspectRatio,
fullScreen: fullScreenDetails
))
}
#endif
}
@@ -231,7 +233,11 @@ struct VideoPlayerView: View {
#if os(iOS)
private func configureOrientationUpdatesBasedOnAccelerometer() {
if UIDevice.current.orientation.isLandscape, enterFullscreenInLandscape, !player.playingFullscreen {
if UIDevice.current.orientation.isLandscape,
enterFullscreenInLandscape,
!player.playingFullscreen,
!player.playingInPictureInPicture
{
DispatchQueue.main.async {
player.enterFullScreen()
}
@@ -244,7 +250,7 @@ struct VideoPlayerView: View {
motionManager = CMMotionManager()
motionManager.accelerometerUpdateInterval = 0.2
motionManager.startAccelerometerUpdates(to: OperationQueue()) { data, _ in
guard player.presentingPlayer, !data.isNil else {
guard player.presentingPlayer, !player.playingInPictureInPicture, !data.isNil else {
return
}
@@ -278,11 +284,12 @@ struct VideoPlayerView: View {
player.enterFullScreen()
let orientationLockMask = orientation == .landscapeLeft ? UIInterfaceOrientationMask.landscapeLeft : .landscapeRight
let orientationLockMask = orientation == .landscapeLeft ?
UIInterfaceOrientationMask.landscapeLeft : .landscapeRight
Orientation.lockOrientation(orientationLockMask, andRotateTo: orientation)
guard lockLandscapeWhenEnteringFullscreen else {
guard lockLandscapeOnRotation else {
return
}
@@ -307,7 +314,11 @@ struct VideoPlayerView: View {
private func handleOrientationDidChangeNotification() {
let newOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
if newOrientation?.isLandscape ?? false, player.presentingPlayer, lockLandscapeWhenEnteringFullscreen, !player.lockedOrientation.isNil {
if newOrientation?.isLandscape ?? false,
player.presentingPlayer,
lockLandscapeOnRotation,
!player.lockedOrientation.isNil
{
Orientation.lockOrientation(.landscape, andRotateTo: newOrientation)
return
}

View File

@@ -3,6 +3,7 @@ import SwiftUI
struct SearchTextField: View {
@Environment(\.navigationStyle) private var navigationStyle
@EnvironmentObject<NavigationModel> private var navigation
@EnvironmentObject<RecentsModel> private var recents
@EnvironmentObject<SearchModel> private var state
@@ -29,7 +30,7 @@ struct SearchTextField: View {
#endif
TextField("Search...", text: $state.queryText) {
state.changeQuery { query in query.query = state.queryText }
recents.addQuery(state.queryText)
recents.addQuery(state.queryText, navigation: navigation)
}
.onChange(of: state.queryText) { _ in
if state.query.query.compare(state.queryText, options: .caseInsensitive) == .orderedSame {

View File

@@ -1,6 +1,7 @@
import SwiftUI
struct SearchSuggestions: View {
@EnvironmentObject<NavigationModel> private var navigation
@EnvironmentObject<RecentsModel> private var recents
@EnvironmentObject<SearchModel> private var state
@@ -30,10 +31,12 @@ struct SearchSuggestions: View {
HStack {
Image(systemName: "magnifyingglass")
HStack(spacing: 0) {
Text(state.suggestionsText)
.lineLimit(1)
.layoutPriority(2)
.foregroundColor(.secondary)
if suggestion.hasPrefix(state.suggestionsText.lowercased()) {
Text(state.suggestionsText.lowercased())
.lineLimit(1)
.layoutPriority(2)
.foregroundColor(.secondary)
}
Text(querySuffix(suggestion))
.lineLimit(1)
@@ -74,7 +77,7 @@ struct SearchSuggestions: View {
state.fieldIsFocused = false
}
recents.addQuery(state.queryText)
recents.addQuery(state.queryText, navigation: navigation)
}
private var visibleSuggestions: [String] {

View File

@@ -177,11 +177,40 @@ struct SearchView: View {
.navigationTitle("Search")
#endif
#if os(iOS)
.navigationBarHidden(!Defaults[.visibleSections].isEmpty || navigationStyle == .sidebar)
.navigationBarHidden(navigationBarHidden)
.navigationBarTitleDisplayMode(.inline)
#endif
}
private var navigationBarHidden: Bool {
if navigationStyle == .sidebar {
return true
}
let preferred = Defaults[.visibleSections]
var visibleSections = [VisibleSection]()
if accounts.app.supportsPopular && preferred.contains(.popular) {
visibleSections.append(.popular)
}
if accounts.app.supportsSubscriptions && accounts.signedIn && preferred.contains(.subscriptions) {
visibleSections.append(.subscriptions)
}
if accounts.app.supportsUserPlaylists && preferred.contains(.playlists) {
visibleSections.append(.playlists)
}
[VisibleSection.favorites, .trending].forEach { section in
if preferred.contains(section) {
visibleSections.append(section)
}
}
return !visibleSections.isEmpty
}
private var results: some View {
VStack {
if showRecentQueries {

View File

@@ -18,8 +18,9 @@ struct PlayerSettings: View {
@Default(.pauseOnHidingPlayer) private var pauseOnHidingPlayer
#if os(iOS)
@Default(.honorSystemOrientationLock) private var honorSystemOrientationLock
@Default(.lockLandscapeWhenEnteringFullscreen) private var lockLandscapeWhenEnteringFullscreen
@Default(.lockLandscapeOnRotation) private var lockLandscapeOnRotation
@Default(.enterFullscreenInLandscape) private var enterFullscreenInLandscape
@Default(.lockLandscapeWhenEnteringFullscreen) private var lockLandscapeWhenEnteringFullscreen
#endif
@Default(.closePiPOnNavigation) private var closePiPOnNavigation
@Default(.closePiPOnOpeningPlayer) private var closePiPOnOpeningPlayer
@@ -85,16 +86,6 @@ struct PlayerSettings: View {
channelSubscribersToggle
}
#if os(iOS)
Section(header: SettingsHeader(text: "Orientation")) {
if idiom == .pad {
enterFullscreenInLandscapeToggle
}
honorSystemOrientationLockToggle
lockLandscapeWhenEnteringFullscreenToggle
}
#endif
Section(header: SettingsHeader(text: "Picture in Picture")) {
closePiPOnNavigationToggle
closePiPOnOpeningPlayerToggle
@@ -102,6 +93,17 @@ struct PlayerSettings: View {
closePiPAndOpenPlayerOnEnteringForegroundToggle
#endif
}
#if os(iOS)
Section(header: SettingsHeader(text: "Orientation"), footer: orientationFooter) {
if idiom == .pad {
enterFullscreenInLandscapeToggle
}
honorSystemOrientationLockToggle
lockLandscapeOnRotationToggle
lockLandscapeWhenEnteringFullscreenToggle
}
#endif
}
}
@@ -212,10 +214,18 @@ struct PlayerSettings: View {
Toggle("Enter fullscreen in landscape", isOn: $enterFullscreenInLandscape)
}
private var lockLandscapeWhenEnteringFullscreenToggle: some View {
Toggle("Lock landscape on rotation", isOn: $lockLandscapeWhenEnteringFullscreen)
private var lockLandscapeOnRotationToggle: some View {
Toggle("Lock landscape on rotation", isOn: $lockLandscapeOnRotation)
.disabled(!enterFullscreenInLandscape)
}
private var lockLandscapeWhenEnteringFullscreenToggle: some View {
Toggle("Rotate and lock landscape on entering fullscreen", isOn: $lockLandscapeWhenEnteringFullscreen)
}
private var orientationFooter: some View {
Text("Orientation settings are experimental and do not yet work properly with all devices and iOS versions")
}
#endif
private var closePiPOnNavigationToggle: some View {

View File

@@ -183,7 +183,7 @@ struct SettingsView: View {
case .history:
return 480
case .sponsorBlock:
return 290
return 660
case .updates:
return 200
case .help:

View File

@@ -39,7 +39,7 @@ struct SponsorBlockSettings: View {
#endif
}
Section(header: SettingsHeader(text: "Categories to Skip")) {
Section(header: SettingsHeader(text: "Categories to Skip"), footer: categoriesDetails) {
#if os(macOS)
let list = ForEach(SponsorBlockAPI.categories, id: \.self) { category in
SponsorBlockCategorySelectionRow(
@@ -74,6 +74,24 @@ struct SponsorBlockSettings: View {
}
}
private var categoriesDetails: some View {
VStack(alignment: .leading) {
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
Text(SponsorBlockAPI.categoryDescription(category) ?? "Category")
.fontWeight(.bold)
#if os(tvOS)
.focusable()
#endif
Text(SponsorBlockAPI.categoryDetails(category) ?? "Details")
.padding(.bottom, 3)
.fixedSize(horizontal: false, vertical: true)
}
}
.foregroundColor(.secondary)
.padding(.top, 3)
}
func toggleCategory(_ category: String, value: Bool) {
if let index = sponsorBlockCategories.firstIndex(where: { $0 == category }), !value {
sponsorBlockCategories.remove(at: index)
@@ -123,7 +141,7 @@ struct SponsorBlockSettings: View {
}
}
struct ServicesSettings_Previews: PreviewProvider {
struct SponsorBlockSettings_Previews: PreviewProvider {
static var previews: some View {
VStack {
SponsorBlockSettings()

View File

@@ -127,6 +127,7 @@ struct TrendingView: View {
resource.load()
}
.keyboardShortcut("r")
.opacity(0)
)
.navigationTitle("Trending")
#endif

View File

@@ -1,3 +1,4 @@
import Defaults
import SwiftUI
struct DetailBadge: View {
@@ -82,12 +83,17 @@ struct DetailBadge: View {
var text: String
var style: Style = .default
@Default(.roundedThumbnails) private var roundedThumbnails
var body: some View {
Text(text)
.truncationMode(.middle)
.padding(10)
.padding(4)
#if os(tvOS)
.padding(.horizontal, 5)
#endif
.modifier(StyleModifier(style: style))
.mask(RoundedRectangle(cornerRadius: 12))
.mask(RoundedRectangle(cornerRadius: roundedThumbnails ? 6 : 0))
}
}

View File

@@ -36,6 +36,7 @@ struct PopularView: View {
resource?.load()
}
.keyboardShortcut("r")
.opacity(0)
)
#endif
#if os(iOS)

View File

@@ -44,6 +44,7 @@ struct SubscriptionsView: View {
loadResources(force: true)
}
.keyboardShortcut("r")
.opacity(0)
)
#endif
#if os(iOS)

View File

@@ -2458,7 +2458,7 @@
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2471,7 +2471,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@@ -2492,7 +2492,7 @@
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2505,7 +2505,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@@ -2524,7 +2524,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Open in Yattee/Info.plist";
@@ -2536,7 +2536,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@@ -2556,7 +2556,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Open in Yattee/Info.plist";
@@ -2568,7 +2568,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@@ -2719,14 +2719,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = iOS/Info.plist;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UIRequiresFullScreen = NO;
INFOPLIST_KEY_UIRequiresFullScreen = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
@@ -2735,7 +2735,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
PRODUCT_NAME = Yattee;
SDKROOT = iphoneos;
@@ -2751,14 +2751,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = iOS/Info.plist;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UIRequiresFullScreen = NO;
INFOPLIST_KEY_UIRequiresFullScreen = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
@@ -2767,7 +2767,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
PRODUCT_NAME = Yattee;
SDKROOT = iphoneos;
@@ -2787,7 +2787,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
ENABLE_APP_SANDBOX = YES;
ENABLE_HARDENED_RUNTIME = YES;
@@ -2802,7 +2802,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
PRODUCT_NAME = Yattee;
SDKROOT = macosx;
@@ -2820,7 +2820,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = "";
ENABLE_APP_SANDBOX = YES;
ENABLE_HARDENED_RUNTIME = YES;
@@ -2835,7 +2835,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
PRODUCT_NAME = Yattee;
SDKROOT = macosx;
@@ -2951,7 +2951,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
@@ -2966,7 +2966,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
PRODUCT_NAME = Yattee;
SDKROOT = appletvos;
@@ -2983,7 +2983,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
@@ -2998,7 +2998,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
PRODUCT_NAME = Yattee;
SDKROOT = appletvos;

View File

@@ -20,6 +20,7 @@ struct NowPlayingView: View {
@EnvironmentObject<RecentsModel> private var recents
@Default(.saveHistory) private var saveHistory
@Default(.showHistoryInPlayer) private var showHistoryInPlayer
var body: some View {
if inInfoViewController {
@@ -102,7 +103,7 @@ struct NowPlayingView: View {
}
}
if sections.contains(.playedPreviously), saveHistory, !visibleWatches.isEmpty {
if sections.contains(.playedPreviously), saveHistory, showHistoryInPlayer, !visibleWatches.isEmpty {
Section(header: Text("Played Previously")) {
ForEach(visibleWatches, id: \.videoID) { watch in
Button {