Compare commits

...

38 Commits

Author SHA1 Message Date
Arkadiusz Fal
16b25df3bc Fix method and property access 2023-06-09 18:03:42 +02:00
Arkadiusz Fal
a66e59a282 Bump build number to 155 2023-06-09 17:50:56 +02:00
Arkadiusz Fal
aeeedf3d63 Update CHANGELOG 2023-06-09 17:50:30 +02:00
Arkadiusz Fal
3d35a60c7a Performance improvements 2023-06-09 17:46:31 +02:00
Arkadiusz Fal
8ffdd4d51f Fix crash 2023-06-09 17:45:51 +02:00
Arkadiusz Fal
f871c7aaf5 Bump build number to 154 2023-06-08 12:27:26 +02:00
Arkadiusz Fal
32af2b385b Update CHANGELOG 2023-06-08 12:25:12 +02:00
Arkadiusz Fal
f78545baf9 Fix issue with AVPlayer rate restore 2023-06-08 12:25:12 +02:00
Arkadiusz Fal
d95bcc4065 Fix #492 2023-06-08 12:17:16 +02:00
Arkadiusz Fal
1efd9e2b90 Fix hiding overlays 2023-06-08 12:11:44 +02:00
Arkadiusz Fal
59e5fcb37d Fix properties access 2023-06-07 23:51:17 +02:00
Arkadiusz Fal
47d68d7948 Update packages 2023-06-07 23:51:09 +02:00
Arkadiusz Fal
3e22c1ebde Bump build number to 153 2023-06-07 23:38:24 +02:00
Arkadiusz Fal
ede5d85693 Update CHANGELOG 2023-06-07 23:37:28 +02:00
Arkadiusz Fal
4d5390ce2d Fixed video player background 2023-06-07 23:37:28 +02:00
Arkadiusz Fal
91290d4736 Fix #486 2023-06-07 23:37:28 +02:00
Arkadiusz Fal
7e7225c59f Fix build on tvOS 2023-06-07 23:37:28 +02:00
Arkadiusz Fal
7b9bbd8974 Fix #473 2023-06-07 23:37:28 +02:00
Arkadiusz Fal
c36dc67a72 Fix issue with AVPlayer rate 2023-06-07 23:37:28 +02:00
Arkadiusz Fal
71b25afa28 Use method to find instance 2023-06-07 23:37:28 +02:00
Arkadiusz Fal
2c5eb18bc9 Fix crash 2023-06-07 23:37:27 +02:00
Arkadiusz Fal
56c2e552f7 Revert "Add loading status to vertical cells"
This reverts commit c6cff4dee4.
2023-06-07 23:37:27 +02:00
Arkadiusz Fal
5ee869c02c Fix lists padding in favorites 2023-06-07 23:37:27 +02:00
Arkadiusz Fal
6f91eedf4c Update watch time on close item 2023-06-07 23:37:27 +02:00
Arkadiusz Fal
0328656a44 Fix AVPlayer layout 2023-06-07 23:37:27 +02:00
Arkadiusz Fal
8d11a92f97 Fix switching to AVPlayer in fullscreen 2023-06-07 23:37:27 +02:00
Arkadiusz Fal
f3a8a0977c Do not reload channels cache if not needed 2023-06-07 23:37:27 +02:00
Arkadiusz Fal
3bbc2df431 Merge pull request #484 from weblate/weblate-yattee-localizable-strings
Translations update from Hosted Weblate
2023-06-07 21:35:50 +02:00
maboroshin
5faa5f0a48 Translated using Weblate (Japanese)
Currently translated at 98.8% (522 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/ja/
2023-06-07 11:52:11 +02:00
maboroshin
ca8586ce7f Translated using Weblate (Japanese)
Currently translated at 98.6% (521 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/ja/
2023-06-05 13:51:46 +02:00
joaooliva
8efa68e65c Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (528 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/pt_BR/
2023-06-03 18:49:46 +02:00
Ophiushi
04c15ed59a Translated using Weblate (French)
Currently translated at 100.0% (528 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/fr/
2023-06-03 18:49:46 +02:00
Bharathi
75772533fd Translated using Weblate (German)
Currently translated at 100.0% (528 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/de/
2023-06-03 18:49:45 +02:00
mere
3ca0f4cf2d Translated using Weblate (Romanian)
Currently translated at 100.0% (528 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/ro/
2023-06-01 08:48:29 +02:00
Arkadiusz Fal
5f745afecb Translated using Weblate (Polish)
Currently translated at 100.0% (528 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/pl/
2023-05-30 10:28:57 +02:00
Anonymous
e8c8c6b5b4 Translated using Weblate (English)
Currently translated at 100.0% (528 of 528 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/en/
2023-05-30 10:28:57 +02:00
Arkadiusz Fal
0585120bd8 Translated using Weblate (English)
Currently translated at 100.0% (527 of 527 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/en/
2023-05-30 10:26:30 +02:00
Anonymous
1f43e11b8e Translated using Weblate (English)
Currently translated at 100.0% (527 of 527 strings)

Translation: Yattee/Localizable.strings
Translate-URL: https://hosted.weblate.org/projects/yattee/localizable-strings/en/
2023-05-30 10:26:26 +02:00
37 changed files with 344 additions and 312 deletions

View File

@@ -1,4 +1,21 @@
## Build 152
## Build 155
* Fixed reported crashes
* Minor performance improvements
## Previous Builds
* Fixed issue where AVPlayer would pause playing on exiting fullscreen
* Fixed issue with empty button appearing on subscriptions list on tvOS
* Fixed issue with AVPlayer not always using full width
* Fixed issue with layout when switching backend while in fullscreen
* Fixed issue with updating watched time on closing video
* Fixed issue with adjusting AVPlayer playback rate when using system controls
* Fixed issue where comments would load indefinitely
* Improved Home buttons layout on tvOS
* Reverted change to placeholders as were causing issues to properly display loading status, will be revisited in future
* Fixed performance issue with swiping back to subscribed channels list
* Fixed reported crashes
* Tapping second time on search tab button focuses the input field and selects entered query text (iOS)
* Added Browsing setting "Keep channels with unwatched videos on top of subscriptions list"
* Improved buttons and layout on tvOS
@@ -10,9 +27,7 @@
* Added remove context menu option for all types of recent items in Search
* Added advanced setting "Show video context menu options to force selected backend"
* Fixed reported crashes
* Other minor fixes and improvements
## Previous Builds
* Improved Home
- Added menu with view options on iOS and toolbar buttons on macOS/tvOS
- Added Home Settings

View File

@@ -53,7 +53,7 @@ struct Account: Defaults.Serializable, Hashable, Identifiable {
}
var instance: Instance! {
Defaults[.instances].first { $0.id == instanceID } ?? Instance(app: app ?? .invidious, name: urlString, apiURLString: urlString)
InstancesModel.shared.find(instanceID) ?? Instance(app: app ?? .invidious, name: urlString, apiURLString: urlString)
}
var isPublic: Bool {

View File

@@ -68,15 +68,14 @@ final class SubscribedChannelsModel: ObservableObject, CacheModel {
return
}
loadCachedChannels(account)
DispatchQueue.main.async { [weak self] in
guard let self else { return }
let request = force ? self.resource?.load() : self.resource?.loadIfNeeded()
guard request != nil else { return }
if request != nil {
self.isLoading = true
}
self.loadCachedChannels(account)
self.isLoading = true
request?
.onCompletion { [weak self] _ in

View File

@@ -69,6 +69,7 @@ final class CommentsModel: ObservableObject {
}
func loadNextPage() {
guard nextPageAvailable else { return }
load(page: nextPage)
}

View File

@@ -46,11 +46,11 @@ extension PlayerModel {
}
}
func updateWatch(finished: Bool = false) {
func updateWatch(finished: Bool = false, time: CMTime? = nil) {
guard let currentVideo, saveHistory else { return }
let id = currentVideo.videoID
let time = backend.currentTime
let time = time ?? backend.currentTime
let seconds = time?.seconds ?? 0
let duration = playerTime.duration.seconds
if seconds < 3 {
@@ -63,7 +63,7 @@ extension PlayerModel {
let results = try? backgroundContext.fetch(watchFetchRequest)
backgroundContext.perform { [weak self] in
guard let self, finished || self.backend.isPlaying else {
guard let self, finished || time != nil || self.backend.isPlaying else {
return
}

View File

@@ -353,9 +353,11 @@ final class AVPlayerBackend: PlayerBackend {
}
self.model.lastSkipped = segment
self.model.handleOnPlayStream(stream)
self.model.play()
}
} else {
self.model.handleOnPlayStream(stream)
self.model.play()
}
}
@@ -486,7 +488,9 @@ final class AVPlayerBackend: PlayerBackend {
if self.model.activeBackend == .appleAVPlayer,
self.isAutoplaying(playerItem)
{
self.model.updateAspectRatio()
if self.model.aspectRatio != self.aspectRatio {
self.model.updateAspectRatio()
}
if self.startPictureInPictureOnPlay,
let controller = self.model.pipController,
@@ -608,7 +612,7 @@ final class AVPlayerBackend: PlayerBackend {
}
self.timeObserverThrottle.execute {
self.model.updateWatch()
self.model.updateWatch(time: self.currentTime)
}
}
}
@@ -638,8 +642,18 @@ final class AVPlayerBackend: PlayerBackend {
if player.timeControlStatus == .playing {
self.model.objectWillChange.send()
if player.rate != Float(self.model.currentRate) {
player.rate = Float(self.model.currentRate)
if let rate = self.model.rateToRestore, player.rate != rate {
player.rate = rate
self.model.rateToRestore = nil
}
if player.rate > 0, player.rate != Float(self.model.currentRate) {
if self.model.avPlayerUsesSystemControls {
self.model.currentRate = Double(player.rate)
} else {
player.rate = Float(self.model.currentRate)
}
}
}
@@ -652,7 +666,7 @@ final class AVPlayerBackend: PlayerBackend {
#endif
self.timeObserverThrottle.execute {
self.model.updateWatch()
self.model.updateWatch(time: self.currentTime)
}
}
}
@@ -708,6 +722,17 @@ final class AVPlayerBackend: PlayerBackend {
} else {
stopMusicMode()
}
#if os(iOS)
if model.playingFullScreen {
ControlOverlaysModel.shared.hide()
model.navigation.presentingPlaybackSettings = false
model.onPlayStream.append { _ in
self.controller.enterFullScreen(animated: true)
}
}
#endif
}
var isStartingPiP: Bool {

View File

@@ -267,9 +267,11 @@ final class MPVBackend: PlayerBackend {
self.model.lastSkipped = segment
self.play()
self.model.handleOnPlayStream(stream)
}
} else {
self.play()
self.model.handleOnPlayStream(stream)
}
}
}
@@ -423,7 +425,7 @@ final class MPVBackend: PlayerBackend {
}
timeObserverThrottle.execute {
self.model.updateWatch()
self.model.updateWatch(time: self.currentTime)
}
}

View File

@@ -182,6 +182,8 @@ final class PlayerModel: ObservableObject {
private var currentArtwork: MPMediaItemArtwork?
var onPresentPlayer = [() -> Void]()
var onPlayStream = [(Stream) -> Void]()
var rateToRestore: Float?
private var remoteCommandCenterConfigured = false
init() {
@@ -541,6 +543,9 @@ final class PlayerModel: ObservableObject {
if !self.backend.canPlayAtRate(currentRate) {
currentRate = self.backend.suggestedPlaybackRates.last { $0 < currentRate } ?? 1.0
}
self.rateToRestore = Float(currentRate)
self.backend.didChangeTo()
if wasPlaying {
@@ -623,13 +628,14 @@ final class PlayerModel: ObservableObject {
closing = true
controls.presentingControls = false
self.prepareCurrentItemForHistory(finished: finished)
self.hide()
Delay.by(0.8) { [weak self] in
guard let self else { return }
self.closePiP()
self.prepareCurrentItemForHistory(finished: finished)
withAnimation {
self.currentItem = nil
}
@@ -1078,7 +1084,9 @@ final class PlayerModel: ObservableObject {
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.aspectRatio = self.backend.aspectRatio
withAnimation {
self.aspectRatio = self.backend.aspectRatio
}
}
#endif
}
@@ -1093,4 +1101,11 @@ final class PlayerModel: ObservableObject {
guard let videoWidth = backend?.videoWidth, let videoHeight = backend?.videoHeight else { return "unknown" }
return "\(String(format: "%.2f", videoWidth))\u{d7}\(String(format: "%.2f", videoHeight))"
}
func handleOnPlayStream(_ stream: Stream) {
backend.setRate(currentRate)
onPlayStream.forEach { $0(stream) }
onPlayStream.removeAll()
}
}

View File

@@ -257,7 +257,7 @@ extension PlayerModel {
if let video = currentVideo, !historyVideos.contains(where: { $0 == video }) {
historyVideos.append(video)
}
updateWatch(finished: finished)
updateWatch(finished: finished, time: backend.currentTime)
}
if let video = currentItem.video,

View File

@@ -15,14 +15,15 @@ struct ChannelPlaylistView: View {
var player = PlayerModel.shared
@ObservedObject private var recents = RecentsModel.shared
@State private var isLoading = false
private var items: [ContentItem] {
ContentItem.array(of: store.item?.videos ?? [])
}
private var resource: Resource? {
accounts.api.channelPlaylist(playlist.id)
let resource = accounts.api.channelPlaylist(playlist.id)
resource?.addObserver(store)
return resource
}
var body: some View {
@@ -47,7 +48,7 @@ struct ChannelPlaylistView: View {
.labelStyle(.iconOnly)
}
#endif
VerticalCells(items: items, isLoading: isLoading)
VerticalCells(items: items)
.environment(\.inChannelPlaylistView, true)
}
.environment(\.listingStyle, channelPlaylistListingStyle)
@@ -55,16 +56,11 @@ struct ChannelPlaylistView: View {
if let cache = ChannelPlaylistsCacheModel.shared.retrievePlaylist(playlist) {
store.replace(cache)
}
isLoading = true
resource?
.load()
.onSuccess { response in
if let playlist: ChannelPlaylist = response.typedContent() {
ChannelPlaylistsCacheModel.shared.storePlaylist(playlist: playlist)
store.replace(playlist)
}
resource?.loadIfNeeded()?.onSuccess { response in
if let playlist: ChannelPlaylist = response.typedContent() {
ChannelPlaylistsCacheModel.shared.storePlaylist(playlist: playlist)
}
.onCompletion { _ in isLoading = false }
}
}
#if os(tvOS)
.background(Color.background(scheme: colorScheme))

View File

@@ -65,7 +65,7 @@ struct ChannelVideosView: View {
.frame(maxWidth: .infinity)
#endif
VerticalCells(items: contentItems, isLoading: resource?.isLoading ?? false, edgesIgnoringSafeArea: verticalCellsEdgesIgnoringSafeArea) {
VerticalCells(items: contentItems, edgesIgnoringSafeArea: verticalCellsEdgesIgnoringSafeArea) {
if let description = presentedChannel?.description, !description.isEmpty {
Button {
withAnimation(.spring()) {

View File

@@ -42,9 +42,21 @@ struct FavoriteItemView: View {
.padding(.leading, 15)
#endif
if limitedItems.isEmpty {
EmptyItems(isLoading: resource?.isLoading ?? false) { reloadVisibleWatches() }
.padding(.vertical, 10)
if limitedItems.isEmpty, !(resource?.isLoading ?? false) {
VStack(alignment: .leading) {
Text(emptyItemsText)
.frame(maxWidth: .infinity, alignment: .leading)
.foregroundColor(.secondary)
if hideShorts || hideWatched {
AccentButton(text: "Disable filters", maxWidth: nil, verticalPadding: 0, minHeight: 30) {
hideShorts = false
hideWatched = false
reloadVisibleWatches()
}
}
}
.padding(.vertical, 10)
#if os(tvOS)
.padding(.horizontal, 40)
#else
@@ -61,7 +73,7 @@ struct FavoriteItemView: View {
#if os(tvOS)
.padding(.leading, 40)
#else
.padding(.leading, 15)
.padding(.horizontal, 15)
#endif
}
}
@@ -101,6 +113,19 @@ struct FavoriteItemView: View {
}
}
var emptyItemsText: String {
var filterText = ""
if hideShorts && hideWatched {
filterText = "(watched and shorts hidden)"
} else if hideShorts {
filterText = "(shorts hidden)"
} else if hideWatched {
filterText = "(watched hidden)"
}
return "No videos to show".localized() + " " + filterText.localized()
}
var contextMenu: some View {
Group {
if item.section == .history {
@@ -179,7 +204,8 @@ struct FavoriteItemView: View {
}
func watch(_ item: ContentItem) -> Watch? {
watches.first { $0.videoID == item.video.videoID }
guard let id = item.video?.videoID else { return nil }
return watches.first { $0.videoID == id }
}
var widgetListingStyle: WidgetListingStyle {

View File

@@ -32,23 +32,8 @@ struct HomeView: View {
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack {
HStack {
#if os(tvOS)
Group {
if showOpenActionsInHome {
AccentButton(text: "Open Video", imageSystemName: "globe") {
NavigationModel.shared.presentingOpenVideos = true
}
}
AccentButton(text: "Locations", imageSystemName: "globe") {
NavigationModel.shared.presentingAccounts = true
}
AccentButton(text: "Settings", imageSystemName: "gear") {
NavigationModel.shared.presentingSettings = true
}
}
#else
#if !os(tvOS)
HStack {
if showOpenActionsInHome {
AccentButton(text: "Files", imageSystemName: "folder") {
NavigationModel.shared.presentingFileImporter = true
@@ -61,16 +46,36 @@ struct HomeView: View {
}
.frame(maxWidth: 40)
}
#endif
}
}
#endif
#if os(tvOS)
HStack {
if showOpenActionsInHome {
Button {
NavigationModel.shared.presentingOpenVideos = true
} label: {
Label("Open Video", systemImage: "globe")
}
}
Button {
NavigationModel.shared.presentingAccounts = true
} label: {
Label("Locations", systemImage: "globe")
}
Spacer()
HideWatchedButtons()
HideShortsButtons()
HomeSettingsButton()
Button {
NavigationModel.shared.presentingSettings = true
} label: {
Label("Settings", systemImage: "gear")
}
}
#if os(tvOS)
.font(.caption)
.imageScale(.small)
#endif
#endif
}
.padding(.top, 15)

View File

@@ -15,8 +15,8 @@ import SwiftUI
false
}
func playerViewController(_: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator) {
#if os(iOS)
#if os(iOS)
func playerViewController(_: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator) {
guard rotateToLandscapeOnEnterFullScreen.isRotating else { return }
if PlayerModel.shared.currentVideoIsLandscape {
let delay = PlayerModel.shared.activeBackend == .appleAVPlayer && avPlayerUsesSystemControls ? 0.8 : 0
@@ -27,34 +27,40 @@ import SwiftUI
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: orientation)
}
}
#endif
}
}
func playerViewController(_: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
let wasPlaying = player.isPlaying
coordinator.animate(alongsideTransition: nil) { context in
#if os(iOS)
func playerViewController(_: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
let wasPlaying = player.isPlaying
coordinator.animate(alongsideTransition: nil) { context in
if wasPlaying {
self.player.play()
}
#endif
if !context.isCancelled {
#if os(iOS)
self.player.lockedOrientation = nil
if !context.isCancelled {
#if os(iOS)
self.player.lockedOrientation = nil
if Constants.isIPhone {
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: .portrait)
}
if Constants.isIPhone {
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: .portrait)
}
if wasPlaying {
self.player.play()
}
if wasPlaying {
self.player.play()
}
self.player.playingFullScreen = false
#endif
self.player.playingFullScreen = false
#endif
}
}
}
}
func playerViewController(_: AVPlayerViewController, restoreUserInterfaceForFullScreenExitWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
withAnimation(nil) {
player.presentingPlayer = true
}
completionHandler(true)
}
#endif
func playerViewControllerWillStartPictureInPicture(_: AVPlayerViewController) {}
@@ -86,14 +92,6 @@ import SwiftUI
}
}
}
func playerViewController(_: AVPlayerViewController, restoreUserInterfaceForFullScreenExitWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
withAnimation(nil) {
player.presentingPlayer = true
}
completionHandler(true)
}
}
#endif

View File

@@ -93,15 +93,17 @@ extension AppleAVPlayerViewController: AVPlayerViewControllerDelegate {
func playerViewControllerDidEndDismissalTransition(_: AVPlayerViewController) {}
func playerViewController(
_: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator
) {}
#if os(iOS)
func playerViewController(
_: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator
) {}
func playerViewController(
_: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator
) {}
func playerViewController(
_: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator
) {}
#endif
func playerViewController(
_: AVPlayerViewController,

View File

@@ -28,13 +28,7 @@ struct PlaybackSettings: View {
#endif
var body: some View {
#if DEBUG
// TODO: remove
if #available(iOS 15.0, macOS 12.0, *) {
Self._printChanges()
}
#endif
return ScrollView {
ScrollView {
VStack(alignment: .leading, spacing: 10) {
HStack {
Button {
@@ -69,21 +63,24 @@ struct PlaybackSettings: View {
}
.padding(.vertical, 10)
HStack {
controlsHeader("Rate".localized())
Spacer()
HStack(spacing: rateButtonsSpacing) {
decreaseRateButton
#if os(tvOS)
.focused($focusedField, equals: .decreaseRate)
#endif
rateButton
increaseRateButton
#if os(tvOS)
.focused($focusedField, equals: .increaseRate)
#endif
if player.activeBackend == .mpv || !player.avPlayerUsesSystemControls {
HStack {
controlsHeader("Rate".localized())
Spacer()
HStack(spacing: rateButtonsSpacing) {
decreaseRateButton
#if os(tvOS)
.focused($focusedField, equals: .decreaseRate)
#endif
rateButton
increaseRateButton
#if os(tvOS)
.focused($focusedField, equals: .increaseRate)
#endif
}
}
}
if player.activeBackend == .mpv {
HStack {
controlsHeader("Captions".localized())

View File

@@ -25,7 +25,7 @@ struct VideoPlayerSizeModifier: ViewModifier {
func body(content: Content) -> some View {
content
.frame(maxWidth: geometry.size.width)
.frame(width: geometry.size.width)
.frame(maxHeight: maxHeight)
#if !os(macOS)

View File

@@ -90,13 +90,7 @@ struct VideoPlayerView: View {
}
var videoPlayer: some View {
#if DEBUG
// TODO: remove
if #available(iOS 15.0, macOS 12.0, *) {
Self._printChanges()
}
#endif
return GeometryReader { geometry in
GeometryReader { geometry in
HStack(spacing: 0) {
content
.onAppear {
@@ -382,7 +376,7 @@ struct VideoPlayerView: View {
.listStyle(.plain)
#endif
.frame(maxWidth: 350)
.background(colorScheme == .dark ? Color.black : Color.white)
.background((colorScheme == .dark ? Color.black : Color.white).ignoresSafeArea())
.transition(.move(edge: .bottom))
}
#elseif os(macOS)

View File

@@ -70,7 +70,7 @@ struct PlaylistVideosView: View {
}
var body: some View {
VerticalCells(items: contentItems, isLoading: resource?.isLoading ?? false)
VerticalCells(items: contentItems)
.onAppear {
guard contentItems.isEmpty else { return }
loadResource()

View File

@@ -63,11 +63,13 @@ struct PlaylistsView: View {
var body: some View {
SignInRequiredView(title: "Playlists".localized()) {
VStack {
VerticalCells(items: items, isLoading: resource?.isLoading ?? false) { if shouldDisplayHeader { header } }
VerticalCells(items: items, allowEmpty: true) { if shouldDisplayHeader { header } }
.environment(\.currentPlaylistID, currentPlaylist?.id)
.environment(\.listingStyle, playlistListingStyle)
if model.all.isEmpty {
if currentPlaylist != nil, items.isEmpty {
hintText("Playlist is empty\n\nTap and hold on a video and then \n\"Add to Playlist\"".localized())
} else if model.all.isEmpty {
hintText("You have no playlists\n\nTap on \"New Playlist\" to create one".localized())
}
}

View File

@@ -244,12 +244,22 @@ struct SearchView: View {
if showRecentQueries {
recentQueries
} else {
VerticalCells(items: state.store.collection, isLoading: state.isLoading) {
VerticalCells(items: state.store.collection, allowEmpty: state.query.isEmpty) {
if shouldDisplayHeader {
header
}
}
.environment(\.loadMoreContentHandler) { state.loadNextPage() }
if noResults {
Text("No results")
if searchFiltersActive {
Button("Reset search filters", action: resetFilters)
}
Spacer()
}
}
}
}
@@ -270,6 +280,12 @@ struct SearchView: View {
searchDuration != .any || searchDate != .any
}
private func resetFilters() {
searchSortOrder = .relevance
searchDate = .any
searchDuration = .any
}
private var noResults: Bool {
state.store.collection.isEmpty && !state.isLoading && !state.query.isEmpty
}

View File

@@ -77,9 +77,11 @@ struct ChannelsView: View {
.listRowSeparator(false)
}
}
#if !os(tvOS)
.background(
NavigationLink(destination: ChannelVideosView(channel: channelForLink ?? Video.fixture.channel), isActive: $channelLinkActive, label: EmptyView.init)
)
#endif
.onAppear {
subscriptions.load()
}

View File

@@ -16,7 +16,7 @@ struct FeedView: View {
}
var body: some View {
VerticalCells(items: videos, isLoading: feed.isLoading) { if shouldDisplayHeader { header } }
VerticalCells(items: videos) { if shouldDisplayHeader { header } }
.environment(\.loadMoreContentHandler) { feed.loadNextPage() }
.onAppear {
feed.loadResources()

View File

@@ -22,51 +22,62 @@ struct TrendingView: View {
}
@State private var error: RequestError?
@State private var resource: Resource?
@State private var isLoading = false
init(_ videos: [Video] = [Video]()) {
self.videos = videos
}
var body: some View {
VerticalCells(items: trending, isLoading: isLoading) { if shouldDisplayHeader { header } }
.environment(\.listingStyle, trendingListingStyle)
.toolbar {
ToolbarItem {
RequestErrorButton(error: error)
}
#if os(macOS)
ToolbarItemGroup {
if let favoriteItem {
FavoriteButton(item: favoriteItem)
.id(favoriteItem.id)
}
var resource: Resource {
let newResource: Resource
categoryButton
countryButton
newResource = accounts.api.trending(country: country, category: category)
newResource.addObserver(store)
return newResource
}
var body: some View {
Section {
VerticalCells(items: trending) { if shouldDisplayHeader { header } }
.environment(\.listingStyle, trendingListingStyle)
}
.toolbar {
ToolbarItem {
RequestErrorButton(error: error)
}
#if os(macOS)
ToolbarItemGroup {
if let favoriteItem {
FavoriteButton(item: favoriteItem)
.id(favoriteItem.id)
}
#endif
}
.onChange(of: category) { _ in updateResource() }
.onChange(of: country) { _ in updateResource() }
.onChange(of: accounts.current) { _ in updateResource() }
.onChange(of: resource) { _ in
isLoading = true
resource?.load()
.onFailure { self.error = $0 }
.onSuccess { _ in self.error = nil }
.onCompletion { _ in self.isLoading = false }
}
.onAppear { updateResource()
}
categoryButton
countryButton
}
#endif
}
.onChange(of: resource) { _ in
resource.load()
.onFailure { self.error = $0 }
.onSuccess { _ in self.error = nil }
updateFavoriteItem()
}
.onAppear {
resource.loadIfNeeded()?
.onFailure { self.error = $0 }
.onSuccess { _ in self.error = nil }
updateFavoriteItem()
}
#if os(tvOS)
.fullScreenCover(isPresented: $presentingCountrySelection) {
TrendingCountry(selectedCountry: $country)
}
.fullScreenCover(isPresented: $presentingCountrySelection) {
TrendingCountry(selectedCountry: $country)
}
#else
.sheet(isPresented: $presentingCountrySelection) {
.sheet(isPresented: $presentingCountrySelection) {
TrendingCountry(selectedCountry: $country)
#if os(macOS)
.frame(minWidth: 400, minHeight: 400)
@@ -74,11 +85,9 @@ struct TrendingView: View {
}
.background(
Button("Refresh") {
isLoading = true
resource?.load()
resource.load()
.onFailure { self.error = $0 }
.onSuccess { _ in self.error = nil }
.onCompletion { _ in self.isLoading = false }
}
.keyboardShortcut("r")
.opacity(0)
@@ -87,18 +96,16 @@ struct TrendingView: View {
#endif
#if os(iOS)
.refreshControl { refreshControl in
resource?.load().onCompletion { _ in
resource.load().onCompletion { _ in
refreshControl.endRefreshing()
}
}
.backport
.refreshable {
DispatchQueue.main.async {
isLoading = true
resource?.load()
resource.load()
.onFailure { self.error = $0 }
.onSuccess { _ in self.error = nil }
.onCompletion { _ in self.isLoading = false }
}
}
.navigationBarTitleDisplayMode(.inline)
@@ -124,13 +131,9 @@ struct TrendingView: View {
}
#else
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
let request = resource?.loadIfNeeded()
if request != nil {
isLoading = true
}
request?.onFailure { self.error = $0 }
resource.loadIfNeeded()?
.onFailure { self.error = $0 }
.onSuccess { _ in self.error = nil }
.onCompletion { _ in self.isLoading = false }
}
#endif
}
@@ -222,7 +225,7 @@ struct TrendingView: View {
private var countryButton: some View {
Button(action: {
presentingCountrySelection.toggle()
resource?.removeObservers(ownedBy: store)
resource.removeObservers(ownedBy: store)
}) {
#if os(iOS)
Label("Country", systemImage: "flag")
@@ -233,13 +236,6 @@ struct TrendingView: View {
}
}
private func updateResource() {
let resource = accounts.api.trending(country: country, category: category)
resource.addObserver(store)
self.resource = resource
updateFavoriteItem()
}
private func updateFavoriteItem() {
favoriteItem = FavoriteItem(section: .trending(country.rawValue, category.rawValue))
}
@@ -258,7 +254,7 @@ struct TrendingView: View {
HideShortsButtons()
Button {
resource?.load()
resource.load()
.onFailure { self.error = $0 }
.onSuccess { _ in self.error = nil }
} label: {

View File

@@ -10,7 +10,7 @@ struct VerticalCells<Header: View>: View {
@Environment(\.listingStyle) private var listingStyle
var items = [ContentItem]()
var isLoading: Bool
var allowEmpty = false
var edgesIgnoringSafeArea = Edge.Set.horizontal
let header: Header?
@@ -19,48 +19,32 @@ struct VerticalCells<Header: View>: View {
init(
items: [ContentItem],
isLoading: Bool,
allowEmpty: Bool = false,
edgesIgnoringSafeArea: Edge.Set = .horizontal,
@ViewBuilder header: @escaping () -> Header? = { nil }
) {
self.items = items
self.isLoading = isLoading
self.allowEmpty = allowEmpty
self.edgesIgnoringSafeArea = edgesIgnoringSafeArea
self.header = header()
}
init(
items: [ContentItem],
isLoading: Bool
allowEmpty: Bool = false
) where Header == EmptyView {
self.init(items: items, isLoading: isLoading) { EmptyView() }
self.init(items: items, allowEmpty: allowEmpty) { EmptyView() }
}
var body: some View {
ScrollView(.vertical, showsIndicators: scrollViewShowsIndicators) {
Group {
LazyVGrid(columns: adaptiveItem, alignment: .center) {
Section(header: header) {
ForEach(contentItems) { item in
ContentItemView(item: item)
.onAppear { loadMoreContentItemsIfNeeded(current: item) }
}
LazyVGrid(columns: adaptiveItem, alignment: .center) {
Section(header: header) {
ForEach(contentItems) { item in
ContentItemView(item: item)
.onAppear { loadMoreContentItemsIfNeeded(current: item) }
}
}
.overlay(
GeometryReader { proxy in
Color.clear
.onAppear {
gridSize = proxy.size
}
.onChange(of: proxy.size) { newValue in
gridSize = newValue
}
}
)
if !isLoading && gridSize.height < 50 {
EmptyItems()
}
}
.padding()
}
@@ -73,7 +57,7 @@ struct VerticalCells<Header: View>: View {
}
var contentItems: [ContentItem] {
items.isEmpty && isLoading ? (ContentItem.placeholders) : items.sorted { $0 < $1 }
items.isEmpty ? (allowEmpty ? items : ContentItem.placeholders) : items.sorted { $0 < $1 }
}
func loadMoreContentItemsIfNeeded(current item: ContentItem) {
@@ -120,7 +104,7 @@ struct VerticalCells<Header: View>: View {
struct VeticalCells_Previews: PreviewProvider {
static var previews: some View {
VerticalCells(items: ContentItem.array(of: Array(repeating: Video.fixture, count: 30)), isLoading: false)
VerticalCells(items: ContentItem.array(of: Array(repeating: Video.fixture, count: 30)))
.injectFixtureEnvironmentObjects()
}
}

View File

@@ -1,62 +0,0 @@
import Defaults
import SwiftUI
struct EmptyItems: View {
@Default(.hideShorts) private var hideShorts
@Default(.hideWatched) private var hideWatched
var isLoading = false
var onDisableFilters: () -> Void = {}
var body: some View {
VStack(alignment: .leading) {
Group {
if isLoading {
HStack(spacing: 10) {
ProgressView()
.progressViewStyle(.circular)
Text("Loading...")
}
} else {
Text(emptyItemsText)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.foregroundColor(.secondary)
if hideShorts || hideWatched {
AccentButton(text: "Disable filters", maxWidth: nil, verticalPadding: 0, minHeight: 30) {
hideShorts = false
hideWatched = false
onDisableFilters()
}
}
}
}
var emptyItemsText: String {
var filterText = ""
if hideShorts && hideWatched {
filterText = "(watched and shorts hidden)"
} else if hideShorts {
filterText = "(shorts hidden)"
} else if hideWatched {
filterText = "(watched hidden)"
}
return "No videos to show".localized() + " " + filterText.localized()
}
}
struct EmptyItems_Previews: PreviewProvider {
static var previews: some View {
VStack {
Spacer()
EmptyItems()
Spacer()
EmptyItems(isLoading: true)
Spacer()
}
.padding()
}
}

View File

@@ -20,7 +20,7 @@ struct PopularView: View {
}
var body: some View {
VerticalCells(items: videos, isLoading: resource?.isLoading ?? false) { if shouldDisplayHeader { header } }
VerticalCells(items: videos) { if shouldDisplayHeader { header } }
.onAppear {
resource?.addObserver(store)
resource?.loadIfNeeded()?

View File

@@ -20,7 +20,6 @@ struct VideoContextMenuView: View {
@FetchRequest private var watchRequest: FetchedResults<Watch>
@Default(.saveHistory) private var saveHistory
@Default(.showPlayNowInBackendContextMenu) private var showPlayNowInBackendContextMenu
private var backgroundContext = PersistenceController.shared.container.newBackgroundContext()
@@ -44,7 +43,7 @@ struct VideoContextMenuView: View {
removeAllFromQueueButton()
}
if !video.localStreamIsDirectory {
if saveHistory {
if Defaults[.saveHistory] {
Section {
if let watchedAtString {
Text(watchedAtString)
@@ -72,7 +71,7 @@ struct VideoContextMenuView: View {
#endif
}
if showPlayNowInBackendContextMenu {
if Defaults[.showPlayNowInBackendContextMenu] {
Section {
ForEach(PlayerBackendType.allCases, id: \.self) { backend in
playNowInBackendButton(backend)

View File

@@ -591,3 +591,7 @@
"Disable filters" = "Filter deaktivieren";
"Limit" = "Grenze";
"Are you sure you want to remove %@ from Favorites?" = "Möchten Sie %@ wirklich aus den Favoriten entfernen?";
"Play Now in MPV" = "Jetzt im MPV abspielen";
"Keep channels with unwatched videos on top of subscriptions list" = "Kanäle mit ungesehenen Videos oben in der Abonnementliste halten";
"Show video context menu options to force selected backend" = "Video-Kontextmenüoptionen anzeigen, um die Auswahl des Backends zu erzwingen";
"Play Now in AVPlayer" = "Jetzt in AVPlayer abspielen";

View File

@@ -589,3 +589,7 @@
"Disable filters" = "Disable filters";
"Limit" = "Limit";
"Are you sure you want to remove %@ from Favorites?" = "Are you sure you want to remove %@ from Favorites?";
"Keep channels with unwatched videos on top of subscriptions list" = "Keep channels with unwatched videos on top of subscriptions list";
"Show video context menu options to force selected backend" = "Show video context menu options to force selected backend";
"Play Now in MPV" = "Play Now in MPV";
"Play Now in AVPlayer" = "Play Now in AVPlayer";

View File

@@ -591,3 +591,7 @@
"(watched hidden)" = "(regardées masquées)";
"Limit" = "Limite";
"Are you sure you want to remove %@ from Favorites?" = "Êtes-vous sûr de vouloir supprimer %@ des favoris ?";
"Keep channels with unwatched videos on top of subscriptions list" = "Conserver les chaînes dont les vidéos n'ont pas été visionnées en haut de la liste des abonnements";
"Show video context menu options to force selected backend" = "Afficher les options contextuelles de la vidéo pour forcer la sélection du backend";
"Play Now in AVPlayer" = "Lire maintenant dans AVPlayer";
"Play Now in MPV" = "Lire maintenant dans MPV";

View File

@@ -510,7 +510,7 @@
"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." = "動画の冒頭で、同じ作成者の他の動画でも見られるアニメーション、静止画やクリップを含む部分。";
"This information will be processed only on your device and used to connect you to the server in the specified country." = "この情報は、この端末上でのみ処理され、指定した国のサーバーに接続するために使用されます。";
"Videos" = "動画";
"Typically near or at the end of the video when the credits pop up and/or endcards are shown." = "クレジットのポップアップやエンドカードが表示される、映像の最後のあたりに表示されます。";
"Typically near or at the end of the video when the credits pop up and/or endcards are shown." = "クレジットのポップアップや終了シーンが表示される、映像の最後のあたりに表示されます。";
"Verified" = "認証済み";
"Mark channel feed as unwatched" = "チャンネルフィードを未視聴にする";
"Open expanded" = "展開したまま開く";
@@ -588,3 +588,7 @@
"(watched hidden)" = "(視聴済み非表示)";
"Disable filters" = "絞り込み解除";
"Are you sure you want to remove %@ from Favorites?" = "お気に入りから %@ を除去しますか?";
"Show video context menu options to force selected backend" = "強制的にバックエンドを選択するための動画のコンテキストメニューを表示";
"Play Now in AVPlayer" = "AVPlayer で今すぐ再生";
"Play Now in MPV" = "MPV で今すぐ再生";
"Keep channels with unwatched videos on top of subscriptions list" = "未視聴の動画があるチャンネルをチャンネル一覧の上部に維持";

View File

@@ -582,7 +582,7 @@
"Landscape left" = "Obrót w lewo";
"Available" = "Dostępne";
"Startup section" = "Sekcja startowa";
"Home Settings" = "Ustawienia strony głównej";
"Home Settings" = "Ustawienia głównej";
"Watched: hidden" = "Obejrzane: ukryte";
"Watched: visible" = "Obejrzane: widoczne";
"No videos to show" = "Brak wideo do pokazania";
@@ -592,3 +592,7 @@
"(watched hidden)" = "(obejrzane ukryte)";
"Limit" = "Limit";
"Are you sure you want to remove %@ from Favorites?" = "Czy na pewno chcesz usunąć element: %@ z Ulubionych?";
"Play Now in AVPlayer" = "Odtwórz teraz w AVPlayerze";
"Play Now in MPV" = "Odtwórz teraz w MPV";
"Keep channels with unwatched videos on top of subscriptions list" = "Kanały z nieobejrzanymi filmami na górze listy subskrypcji";
"Show video context menu options to force selected backend" = "Pokaż opcje menu kontekstowego wideo, aby wymusić wybrany silnik";

View File

@@ -591,3 +591,7 @@
"Are you sure you want to remove %@ from Favorites?" = "Tem certeza que deseja remover %@ dos Favoritos?";
"No videos to show" = "Nenhum vídeo para mostrar";
"(watched and shorts hidden)" = "(assistidos e shorts ocultos)";
"Show video context menu options to force selected backend" = "Mostrar opções do menu contextual do vídeo para forçar o backend selecionado";
"Keep channels with unwatched videos on top of subscriptions list" = "Manter canais com vídeos não vistos no topo da lista de inscrições";
"Play Now in AVPlayer" = "Tocar Agora no AVPlayer";
"Play Now in MPV" = "Tocar Agora em MPV";

View File

@@ -591,3 +591,7 @@
"(shorts hidden)" = "(shorts ascunse)";
"Limit" = "Limită";
"Are you sure you want to remove %@ from Favorites?" = "Sigur doriți să eliminați %@ din Favorite?";
"Keep channels with unwatched videos on top of subscriptions list" = "Păstrați canalele cu videoclipuri nevăzute în partea de sus a listei de abonamente";
"Play Now in AVPlayer" = "Redă acum în AVPlayer";
"Play Now in MPV" = "Redă acum în MPV";
"Show video context menu options to force selected backend" = "Afișați opțiunile din meniul contextual video pentru a forța backend-ul selectat";

View File

@@ -690,9 +690,6 @@
379DC3D128BA4EB400B09677 /* Seek.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DC3D028BA4EB400B09677 /* Seek.swift */; };
379DC3D228BA4EB400B09677 /* Seek.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DC3D028BA4EB400B09677 /* Seek.swift */; };
379DC3D328BA4EB400B09677 /* Seek.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DC3D028BA4EB400B09677 /* Seek.swift */; };
379E7C2F2A20AF0A00AF8118 /* EmptyItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379E7C2E2A20AF0A00AF8118 /* EmptyItems.swift */; };
379E7C302A20AF0A00AF8118 /* EmptyItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379E7C2E2A20AF0A00AF8118 /* EmptyItems.swift */; };
379E7C312A20AF0A00AF8118 /* EmptyItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379E7C2E2A20AF0A00AF8118 /* EmptyItems.swift */; };
379E7C332A20FE3900AF8118 /* FocusableSearchTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379E7C322A20FE3900AF8118 /* FocusableSearchTextField.swift */; };
379E7C342A20FE3900AF8118 /* FocusableSearchTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379E7C322A20FE3900AF8118 /* FocusableSearchTextField.swift */; };
379E7C362A2105B900AF8118 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 379E7C352A2105B900AF8118 /* Introspect */; };
@@ -1397,7 +1394,6 @@
379ACB502A1F8DB000E01914 /* HomeSettingsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeSettingsButton.swift; sourceTree = "<group>"; };
379B0252287A1CDF001015B5 /* OrientationTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrientationTracker.swift; sourceTree = "<group>"; };
379DC3D028BA4EB400B09677 /* Seek.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Seek.swift; sourceTree = "<group>"; };
379E7C2E2A20AF0A00AF8118 /* EmptyItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyItems.swift; sourceTree = "<group>"; };
379E7C322A20FE3900AF8118 /* FocusableSearchTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusableSearchTextField.swift; sourceTree = "<group>"; };
379EF9DF29AA585F009FE6C6 /* HideShortsButtons.swift */ = {isa = PBXFileReference; indentWidth = 3; lastKnownFileType = sourcecode.swift; path = HideShortsButtons.swift; sourceTree = "<group>"; };
379F141E289ECE7F00DE48B5 /* QualitySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QualitySettings.swift; sourceTree = "<group>"; };
@@ -1911,7 +1907,6 @@
37FB285D272225E800A57617 /* ContentItemView.swift */,
372CFD14285F2E2A00B0B54B /* ControlsBar.swift */,
3748186D26A769D60084E870 /* DetailBadge.swift */,
379E7C2E2A20AF0A00AF8118 /* EmptyItems.swift */,
37599F37272B4D740087F250 /* FavoriteButton.swift */,
379EF9DF29AA585F009FE6C6 /* HideShortsButtons.swift */,
37758C0A2A1D1C8B001FD900 /* HideWatchedButtons.swift */,
@@ -3190,7 +3185,6 @@
374AB3DB28BCAF7E00DF56FB /* SeekType.swift in Sources */,
37192D5728B179D60012EEDD /* ChaptersView.swift in Sources */,
37D836BC294927E700005E5E /* ChannelsCacheModel.swift in Sources */,
379E7C2F2A20AF0A00AF8118 /* EmptyItems.swift in Sources */,
37B81AF926D2C9A700675966 /* VideoPlayerSizeModifier.swift in Sources */,
37C0698227260B2100F7F6CB /* ThumbnailsModel.swift in Sources */,
37BC50A82778A84700510953 /* HistorySettings.swift in Sources */,
@@ -3501,7 +3495,6 @@
37599F35272B44000087F250 /* FavoritesModel.swift in Sources */,
376527BC285F60F700102284 /* PlayerTimeModel.swift in Sources */,
37F64FE526FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
379E7C302A20AF0A00AF8118 /* EmptyItems.swift in Sources */,
377ABC45286E4B74009C986F /* ManifestedInstance.swift in Sources */,
3795593727B08538007FF8F4 /* StreamControl.swift in Sources */,
37772E0E2A216F8600608BD9 /* String+ReplacingHTMLEntities.swift in Sources */,
@@ -3796,7 +3789,6 @@
37C3A24727235DA70087A57A /* ChannelPlaylist.swift in Sources */,
3788AC2926F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
37319F0727103F94004ECCD0 /* PlayerQueue.swift in Sources */,
379E7C312A20AF0A00AF8118 /* EmptyItems.swift in Sources */,
3718B9A52921A97F0003DB2E /* InspectorView.swift in Sources */,
37E70925271CD43000D34DDE /* WelcomeScreen.swift in Sources */,
376BE50D27349108009AD608 /* BrowsingSettings.swift in Sources */,
@@ -4061,7 +4053,7 @@
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Open in Yattee/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
@@ -4092,7 +4084,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "Open in Yattee/Info.plist";
@@ -4123,7 +4115,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 11.0;
@@ -4143,7 +4135,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 11.0;
@@ -4303,7 +4295,7 @@
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
ENABLE_PREVIEWS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -4356,7 +4348,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
ENABLE_PREVIEWS = YES;
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
@@ -4408,7 +4400,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
DEAD_CODE_STRIPPING = YES;
ENABLE_APP_SANDBOX = YES;
ENABLE_HARDENED_RUNTIME = YES;
@@ -4450,7 +4442,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
DEAD_CODE_STRIPPING = YES;
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
ENABLE_APP_SANDBOX = YES;
@@ -4488,7 +4480,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4512,7 +4504,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4538,7 +4530,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
DEAD_CODE_STRIPPING = YES;
GENERATE_INFOPLIST_FILE = YES;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4563,7 +4555,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
DEAD_CODE_STRIPPING = YES;
GENERATE_INFOPLIST_FILE = YES;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4589,7 +4581,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
DEVELOPMENT_ASSET_PATHS = "";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -4629,7 +4621,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
DEVELOPMENT_ASSET_PATHS = "";
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
ENABLE_PREVIEWS = YES;
@@ -4670,7 +4662,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
GENERATE_INFOPLIST_FILE = YES;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -4694,7 +4686,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 152;
CURRENT_PROJECT_VERSION = 155;
GENERATE_INFOPLIST_FILE = YES;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",

View File

@@ -96,7 +96,7 @@
"location" : "https://github.com/SDWebImage/SDWebImage",
"state" : {
"branch" : "master",
"revision" : "7f9fb5d43ecd4aa714c00746f54873f354403438"
"revision" : "90aa750c92973005f086263e44c6224a1456bb12"
}
},
{
@@ -150,7 +150,7 @@
"location" : "https://github.com/lorenzofiamingo/swiftui-cached-async-image",
"state" : {
"branch" : "main",
"revision" : "f94be38411297c71aa8df69c6875127e6d8d7a92"
"revision" : "2abb11839f80ebb07a58ac5e146a1da664260c16"
}
},
{
@@ -158,8 +158,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
"state" : {
"revision" : "5b3f3996c7a2a84d5f4ba0e03cd7d584154778f2",
"version" : "0.3.1"
"revision" : "c29b50a475120fdfa22573622464a7346aaf99a4",
"version" : "0.6.0"
}
},
{