mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
iOS 14/macOS Big Sur Support
This commit is contained in:
parent
696751e07c
commit
5ef89ac9f4
13
Backports/Backport.swift
Normal file
13
Backports/Backport.swift
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
public struct Backport<Content> {
|
||||||
|
public let content: Content
|
||||||
|
|
||||||
|
public init(_ content: Content) {
|
||||||
|
self.content = content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
var backport: Backport<Self> { Backport(self) }
|
||||||
|
}
|
11
Backports/Badge+Backport.swift
Normal file
11
Backports/Badge+Backport.swift
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension Backport where Content: View {
|
||||||
|
@ViewBuilder func badge(_ count: Text) -> some View {
|
||||||
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
|
content.badge(count)
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Backports/Tint+Backport.swift
Normal file
11
Backports/Tint+Backport.swift
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension Backport where Content: View {
|
||||||
|
@ViewBuilder func tint(_ color: Color?) -> some View {
|
||||||
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
|
content.tint(color)
|
||||||
|
} else {
|
||||||
|
content.foregroundColor(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Extensions/Color+Background.swift
Normal file
17
Extensions/Color+Background.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension Color {
|
||||||
|
#if os(macOS)
|
||||||
|
static let background = Color(NSColor.windowBackgroundColor)
|
||||||
|
static let secondaryBackground = Color(NSColor.underPageBackgroundColor)
|
||||||
|
static let tertiaryBackground = Color(NSColor.controlBackgroundColor)
|
||||||
|
#elseif os(iOS)
|
||||||
|
static let background = Color(UIColor.systemBackground)
|
||||||
|
static let secondaryBackground = Color(UIColor.secondarySystemBackground)
|
||||||
|
static let tertiaryBackground = Color(UIColor.tertiarySystemBackground)
|
||||||
|
#else
|
||||||
|
static let background = Color.black
|
||||||
|
static let secondaryBackground = Color.black
|
||||||
|
static let tertiaryBackground = Color.black
|
||||||
|
#endif
|
||||||
|
}
|
8
Extensions/NSTextField+FocusRingType.swift
Normal file
8
Extensions/NSTextField+FocusRingType.swift
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import AppKit
|
||||||
|
|
||||||
|
extension NSTextField {
|
||||||
|
override open var focusRingType: NSFocusRingType {
|
||||||
|
get { .none }
|
||||||
|
set {} // swiftlint:disable:this unused_setter_value
|
||||||
|
}
|
||||||
|
}
|
10
Extensions/String+Format.swift
Normal file
10
Extensions/String+Format.swift
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
func replacingFirstOccurrence(of target: String, with replacement: String) -> String {
|
||||||
|
guard let range = range(of: target) else {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
return replacingCharacters(in: range, with: replacement)
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,21 @@ extension View {
|
|||||||
verticalEdgeBorder(.bottom, height: height, color: color)
|
verticalEdgeBorder(.bottom, height: height, color: color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func borderLeading(width: Double, color: Color = Color(white: 0.7, opacity: 1)) -> some View {
|
||||||
|
horizontalEdgeBorder(.leading, width: width, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
|
func borderTrailing(width: Double, color: Color = Color(white: 0.7, opacity: 1)) -> some View {
|
||||||
|
horizontalEdgeBorder(.trailing, width: width, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
private func verticalEdgeBorder(_ edge: Alignment, height: Double, color: Color) -> some View {
|
private func verticalEdgeBorder(_ edge: Alignment, height: Double, color: Color) -> some View {
|
||||||
overlay(Rectangle().frame(width: nil, height: height, alignment: .top).foregroundColor(color), alignment: edge)
|
overlay(Rectangle().frame(width: nil, height: height, alignment: .top)
|
||||||
|
.foregroundColor(color), alignment: edge)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func horizontalEdgeBorder(_ edge: Alignment, width: Double, color: Color) -> some View {
|
||||||
|
overlay(Rectangle().frame(width: width, height: nil, alignment: .leading)
|
||||||
|
.foregroundColor(color), alignment: edge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ extension Video {
|
|||||||
thumbnails: Thumbnail.fixturesForAllQualities(videoId: id),
|
thumbnails: Thumbnail.fixturesForAllQualities(videoId: id),
|
||||||
live: false,
|
live: false,
|
||||||
upcoming: false,
|
upcoming: false,
|
||||||
publishedAt: Date.now,
|
publishedAt: Date(),
|
||||||
likes: 37333,
|
likes: 37333,
|
||||||
dislikes: 30,
|
dislikes: 30,
|
||||||
keywords: ["very", "cool", "video", "msfs 2020", "757", "747", "A380", "737-900", "MOD", "Zibo", "MD80", "MD11", "Rotate", "Laminar", "787", "A350", "MSFS", "MS2020", "Microsoft Flight Simulator", "Microsoft", "Flight", "Simulator", "SIM", "World", "Ortho", "Flying", "Boeing MAX"]
|
keywords: ["very", "cool", "video", "msfs 2020", "757", "747", "A380", "737-900", "MOD", "Zibo", "MD80", "MD11", "Rotate", "Laminar", "787", "A350", "MSFS", "MS2020", "Microsoft Flight Simulator", "Microsoft", "Flight", "Simulator", "SIM", "World", "Ortho", "Flying", "Boeing MAX"]
|
||||||
|
@ -45,6 +45,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
var accounts: AccountsModel
|
var accounts: AccountsModel
|
||||||
|
|
||||||
var composition = AVMutableComposition()
|
var composition = AVMutableComposition()
|
||||||
|
var loadedCompositionAssets = [AVMediaType]()
|
||||||
|
|
||||||
private var currentArtwork: MPMediaItemArtwork?
|
private var currentArtwork: MPMediaItemArtwork?
|
||||||
private var frequentTimeObserver: Any?
|
private var frequentTimeObserver: Any?
|
||||||
@ -147,9 +148,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
logger.info("composition audio asset: \(stream.audioAsset.url)")
|
logger.info("composition audio asset: \(stream.audioAsset.url)")
|
||||||
logger.info("composition video asset: \(stream.videoAsset.url)")
|
logger.info("composition video asset: \(stream.videoAsset.url)")
|
||||||
|
|
||||||
Task {
|
loadComposition(stream, of: video, preservingTime: preservingTime)
|
||||||
await self.loadComposition(stream, of: video, preservingTime: preservingTime)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCurrentArtwork()
|
updateCurrentArtwork()
|
||||||
@ -228,46 +227,59 @@ final class PlayerModel: ObservableObject {
|
|||||||
_ stream: Stream,
|
_ stream: Stream,
|
||||||
of video: Video,
|
of video: Video,
|
||||||
preservingTime: Bool = false
|
preservingTime: Bool = false
|
||||||
) async {
|
) {
|
||||||
await loadCompositionAsset(stream.audioAsset, type: .audio, of: video)
|
loadedCompositionAssets = []
|
||||||
await loadCompositionAsset(stream.videoAsset, type: .video, of: video)
|
loadCompositionAsset(stream.audioAsset, stream: stream, type: .audio, of: video, preservingTime: preservingTime)
|
||||||
|
loadCompositionAsset(stream.videoAsset, stream: stream, type: .video, of: video, preservingTime: preservingTime)
|
||||||
guard streamSelection == stream else {
|
|
||||||
logger.critical("IGNORING LOADED")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
insertPlayerItem(stream, for: video, preservingTime: preservingTime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadCompositionAsset(
|
func loadCompositionAsset(
|
||||||
_ asset: AVURLAsset,
|
_ asset: AVURLAsset,
|
||||||
|
stream: Stream,
|
||||||
type: AVMediaType,
|
type: AVMediaType,
|
||||||
of video: Video
|
of video: Video,
|
||||||
) async {
|
preservingTime: Bool = false
|
||||||
async let assetTracks = asset.loadTracks(withMediaType: type)
|
) {
|
||||||
|
asset.loadValuesAsynchronously(forKeys: ["playable"]) { [weak self] in
|
||||||
|
guard let self = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.logger.info("loading \(type.rawValue) track")
|
||||||
|
|
||||||
logger.info("loading \(type.rawValue) track")
|
let assetTracks = asset.tracks(withMediaType: type)
|
||||||
guard let compositionTrack = composition.addMutableTrack(
|
|
||||||
withMediaType: type,
|
guard let compositionTrack = self.composition.addMutableTrack(
|
||||||
preferredTrackID: kCMPersistentTrackID_Invalid
|
withMediaType: type,
|
||||||
) else {
|
preferredTrackID: kCMPersistentTrackID_Invalid
|
||||||
logger.critical("composition \(type.rawValue) addMutableTrack FAILED")
|
) else {
|
||||||
return
|
self.logger.critical("composition \(type.rawValue) addMutableTrack FAILED")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let assetTrack = assetTracks.first else {
|
||||||
|
self.logger.critical("asset \(type.rawValue) track FAILED")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try! compositionTrack.insertTimeRange(
|
||||||
|
CMTimeRange(start: .zero, duration: CMTime.secondsInDefaultTimescale(video.length)),
|
||||||
|
of: assetTrack,
|
||||||
|
at: .zero
|
||||||
|
)
|
||||||
|
|
||||||
|
self.logger.critical("\(type.rawValue) LOADED")
|
||||||
|
|
||||||
|
guard self.streamSelection == stream else {
|
||||||
|
self.logger.critical("IGNORING LOADED")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.loadedCompositionAssets.append(type)
|
||||||
|
|
||||||
|
if self.loadedCompositionAssets.count == 2 {
|
||||||
|
self.insertPlayerItem(stream, for: video, preservingTime: preservingTime)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let assetTrack = try? await assetTracks.first else {
|
|
||||||
logger.critical("asset \(type.rawValue) track FAILED")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try! compositionTrack.insertTimeRange(
|
|
||||||
CMTimeRange(start: .zero, duration: CMTime.secondsInDefaultTimescale(video.length)),
|
|
||||||
of: assetTrack,
|
|
||||||
at: .zero
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.critical("\(type.rawValue) LOADED")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func playerItem(_ stream: Stream) -> AVPlayerItem? {
|
private func playerItem(_ stream: Stream) -> AVPlayerItem? {
|
||||||
|
@ -10,6 +10,8 @@ final class SearchModel: ObservableObject {
|
|||||||
@Published var queryText = ""
|
@Published var queryText = ""
|
||||||
@Published var querySuggestions = Store<[String]>()
|
@Published var querySuggestions = Store<[String]>()
|
||||||
|
|
||||||
|
@Published var fieldIsFocused = false
|
||||||
|
|
||||||
private var previousResource: Resource?
|
private var previousResource: Resource?
|
||||||
private var resource: Resource!
|
private var resource: Resource!
|
||||||
|
|
||||||
@ -80,6 +82,10 @@ final class SearchModel: ObservableObject {
|
|||||||
private var suggestionsDebounceTimer: Timer?
|
private var suggestionsDebounceTimer: Timer?
|
||||||
|
|
||||||
func loadSuggestions(_ query: String) {
|
func loadSuggestions(_ query: String) {
|
||||||
|
guard !query.isEmpty else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
suggestionsDebounceTimer?.invalidate()
|
suggestionsDebounceTimer?.invalidate()
|
||||||
|
|
||||||
suggestionsDebounceTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
|
suggestionsDebounceTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
|
||||||
|
57
README.md
57
README.md
@ -1,11 +1,11 @@
|
|||||||
![Yattee Banner](https://r.yattee.stream/icons/yattee-banner.png)
|
![Yattee Banner](https://r.yattee.stream/icons/yattee-banner.png)
|
||||||
|
|
||||||
Video player with support for [Invidious](https://github.com/iv-org/invidious) and [Piped](https://github.com/TeamPiped/Piped) instances built for iOS 15, tvOS 15 and macOS Monterey.
|
Video player for [Invidious](https://github.com/iv-org/invidious) and [Piped](https://github.com/TeamPiped/Piped) instances built for iOS, tvOS and macOS.
|
||||||
|
|
||||||
|
|
||||||
[![AGPL v3](https://shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.en.html)
|
[![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/app)
|
[![GitHub issues](https://img.shields.io/github/issues/yattee/yattee)](https://github.com/yattee/yattee/issues)
|
||||||
![GitHub pull requests](https://img.shields.io/github/issues-pr/yattee/app)
|
[![GitHub pull requests](https://img.shields.io/github/issues-pr/yattee/yattee)](https://github.com/yattee/yattee/pulls)
|
||||||
[![Matrix](https://img.shields.io/matrix/yattee:matrix.org)](https://matrix.to/#/#yattee:matrix.org)
|
[![Matrix](https://img.shields.io/matrix/yattee:matrix.org)](https://matrix.to/#/#yattee:matrix.org)
|
||||||
|
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ Video player with support for [Invidious](https://github.com/iv-org/invidious) a
|
|||||||
* Fullscreen playback, Picture in Picture and AirPlay support
|
* Fullscreen playback, Picture in Picture and AirPlay support
|
||||||
* Stream quality selection
|
* Stream quality selection
|
||||||
* Favorites: customizable section of channels, playlists, trending, searches and other views
|
* Favorites: customizable section of channels, playlists, trending, searches and other views
|
||||||
* URL Scheme for integrations
|
* `yattee://` URL Scheme for integrations
|
||||||
|
|
||||||
### Availability
|
### Availability
|
||||||
| Feature | Invidious | Piped |
|
| Feature | Invidious | Piped |
|
||||||
@ -38,17 +38,24 @@ Video player with support for [Invidious](https://github.com/iv-org/invidious) a
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
### Requirements
|
### Requirements
|
||||||
Only iOS/tvOS 15 and macOS Monterey are supported.
|
System requirements:
|
||||||
|
* iOS 14 (or newer)
|
||||||
|
* tvOS 15 (or newer)
|
||||||
|
* macOS Big Sur (or newer)
|
||||||
|
|
||||||
### How to install?
|
### How to install?
|
||||||
#### [AltStore](https://altstore.io/)
|
#### [AltStore](https://altstore.io/) (free)
|
||||||
You can sideload IPA files that you can download from Releases page.
|
You can sideload IPA files downloaded from the [Releases](https://github.com/yattee/yattee/releases) page to your iOS or tvOS device - check [AltStore FAQ](https://altstore.io/faq/) for more information.
|
||||||
Alternatively, if you have to access to the beta AltStore version (v1.5), you can add the following repository in `Browse > Sources` screen:
|
|
||||||
|
If you have to access to the beta AltStore version (v1.5, for Patreons only), you can add the following repository in `Browse > Sources` screen:
|
||||||
|
|
||||||
`https://alt.yattee.stream`
|
`https://alt.yattee.stream`
|
||||||
|
|
||||||
|
#### Signing IPA files online (paid)
|
||||||
|
[UDID Registrations](https://www.udidregistrations.com/) provides services to sign IPA files for your devices. Refer to: ***Break free from the App Store*** section of the website for more information.
|
||||||
|
|
||||||
#### Manual installation
|
#### Manual installation
|
||||||
Download sources and compile them on a Mac using Xcode, install to your devices. Please note that if you are not registered in Apple Developer Program then the applications will require reinstalling every 7 days.
|
Download sources and compile them on a Mac using Xcode, install to your devices. Please note that if you are not registered in Apple Developer Program you will need to reinstall every 7 days.
|
||||||
|
|
||||||
## Integrations
|
## Integrations
|
||||||
### macOS
|
### macOS
|
||||||
@ -63,14 +70,6 @@ With [Finicky](https://github.com/johnste/finicky) you can configure your system
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Experimental: Safari
|
|
||||||
macOS and iOS apps include Safari extension which will redirect opened YouTube tabs to the app.
|
|
||||||
|
|
||||||
### Expermiental: Firefox
|
|
||||||
You can use [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect) extension to make the videos open in the app. In extension settings put the following URL as Invidious instance:
|
|
||||||
|
|
||||||
`https://r.yatte.stream`
|
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
### iOS
|
### iOS
|
||||||
| Player | Search | Playlists |
|
| Player | Search | Playlists |
|
||||||
@ -111,6 +110,30 @@ You can use [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect)
|
|||||||
* `Command+S` - Play Next
|
* `Command+S` - Play Next
|
||||||
* `Command+O` - Toggle Player
|
* `Command+O` - Toggle Player
|
||||||
|
|
||||||
|
|
||||||
|
## Donations
|
||||||
|
|
||||||
|
You can support development of this app with
|
||||||
|
[Patreon](https://www.patreon.com/arekf) or cryptocurrencies:
|
||||||
|
|
||||||
|
**Monero (XMR)**
|
||||||
|
```
|
||||||
|
48zfKjLmnXs21PinU2ucMiUPwhiKt5d7WJKiy3ACVS28BKqSn52c1TX8L337oESHJ5TZCyGkozjfWZG11h6C46mN9n4NPrD
|
||||||
|
```
|
||||||
|
**Bitcoin (BTC)**
|
||||||
|
```
|
||||||
|
bc1qe24zz5a5hm0trc7glwckz93py274eycxzju3mv
|
||||||
|
```
|
||||||
|
**Ethereum (ETH)**
|
||||||
|
```
|
||||||
|
0xa2f81A58Ec5E550132F03615c8d91954A4E37423
|
||||||
|
```
|
||||||
|
|
||||||
|
Donations will be used to cover development program access and domain renewal costs.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
If you're interestred in contributing, you can browse the [issues](https://github.com/yattee/yattee/issues) list or create a new one to discuss your feature idea. Every contribution is very welcome.
|
||||||
|
|
||||||
## License and Liability
|
## License and Liability
|
||||||
|
|
||||||
Yattee and its components is shared on [AGPL v3](https://www.gnu.org/licenses/agpl-3.0.en.html) license.
|
Yattee and its components is shared on [AGPL v3](https://www.gnu.org/licenses/agpl-3.0.en.html) license.
|
||||||
|
@ -51,7 +51,7 @@ struct FavoritesView: View {
|
|||||||
.navigationTitle("Favorites")
|
.navigationTitle("Favorites")
|
||||||
#endif
|
#endif
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.background()
|
.background(Color.tertiaryBackground)
|
||||||
.frame(minWidth: 360)
|
.frame(minWidth: 360)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ struct MenuCommands: Commands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var navigationMenu: some Commands {
|
private var navigationMenu: some Commands {
|
||||||
CommandMenu("Navigation") {
|
CommandGroup(before: .windowSize) {
|
||||||
Button("Favorites") {
|
Button("Favorites") {
|
||||||
model.navigation?.tabSelection = .favorites
|
model.navigation?.tabSelection = .favorites
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ struct MenuCommands: Commands {
|
|||||||
Button("Subscriptions") {
|
Button("Subscriptions") {
|
||||||
model.navigation?.tabSelection = .subscriptions
|
model.navigation?.tabSelection = .subscriptions
|
||||||
}
|
}
|
||||||
.disabled(!(model.accounts?.app.supportsSubscriptions ?? true))
|
.disabled(subscriptionsDisabled)
|
||||||
.keyboardShortcut("2")
|
.keyboardShortcut("2")
|
||||||
|
|
||||||
Button("Popular") {
|
Button("Popular") {
|
||||||
@ -37,9 +37,17 @@ struct MenuCommands: Commands {
|
|||||||
model.navigation?.tabSelection = .search
|
model.navigation?.tabSelection = .search
|
||||||
}
|
}
|
||||||
.keyboardShortcut("f")
|
.keyboardShortcut("f")
|
||||||
|
|
||||||
|
Divider()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var subscriptionsDisabled: Bool {
|
||||||
|
!(
|
||||||
|
(model.accounts?.app.supportsSubscriptions ?? false) && model.accounts?.signedIn ?? false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private var playbackMenu: some Commands {
|
private var playbackMenu: some Commands {
|
||||||
CommandMenu("Playback") {
|
CommandMenu("Playback") {
|
||||||
Button((model.player?.isPlaying ?? true) ? "Pause" : "Play") {
|
Button((model.player?.isPlaying ?? true) ? "Pause" : "Play") {
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct UnsubscribeAlertModifier: ViewModifier {
|
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
content
|
|
||||||
.alert(unsubscribeAlertTitle, isPresented: $navigation.presentingUnsubscribeAlert) {
|
|
||||||
if let channel = navigation.channelToUnsubscribe {
|
|
||||||
Button("Unsubscribe", role: .destructive) {
|
|
||||||
subscriptions.unsubscribe(channel.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var unsubscribeAlertTitle: String {
|
|
||||||
if let channel = navigation.channelToUnsubscribe {
|
|
||||||
return "Unsubscribe from \(channel.name)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Unknown channel"
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,13 +15,25 @@ struct AccountsMenuView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Label(model.current?.description ?? "Select Account", systemImage: "person.crop.circle")
|
if #available(iOS 15.0, macOS 12.0, *) {
|
||||||
.labelStyle(.titleAndIcon)
|
label
|
||||||
|
.labelStyle(.titleAndIcon)
|
||||||
|
} else {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "person.crop.circle")
|
||||||
|
label
|
||||||
|
.labelStyle(.titleOnly)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.disabled(instances.isEmpty)
|
.disabled(instances.isEmpty)
|
||||||
.transaction { t in t.animation = .none }
|
.transaction { t in t.animation = .none }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var label: some View {
|
||||||
|
Label(model.current?.description ?? "Select Account", systemImage: "person.crop.circle")
|
||||||
|
}
|
||||||
|
|
||||||
private var allAccounts: [Account] {
|
private var allAccounts: [Account] {
|
||||||
accounts + instances.map(\.anonymousAccount)
|
accounts + instances.map(\.anonymousAccount)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ struct AppSidebarPlaylists: View {
|
|||||||
LazyView(PlaylistVideosView(playlist))
|
LazyView(PlaylistVideosView(playlist))
|
||||||
} label: {
|
} label: {
|
||||||
Label(playlist.title, systemImage: AppSidebarNavigation.symbolSystemImage(playlist.title))
|
Label(playlist.title, systemImage: AppSidebarNavigation.symbolSystemImage(playlist.title))
|
||||||
|
.backport
|
||||||
.badge(Text("\(playlist.videos.count)"))
|
.badge(Text("\(playlist.videos.count)"))
|
||||||
}
|
}
|
||||||
.id(playlist.id)
|
.id(playlist.id)
|
||||||
|
@ -18,7 +18,6 @@ struct AppSidebarSubscriptions: View {
|
|||||||
navigation.presentUnsubscribeAlert(channel)
|
navigation.presentUnsubscribeAlert(channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modifier(UnsubscribeAlertModifier())
|
|
||||||
.id("channel\(channel.id)")
|
.id("channel\(channel.id)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,8 @@ struct AppTabNavigation: View {
|
|||||||
} else {
|
} else {
|
||||||
trendingNavigationView
|
trendingNavigationView
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
trendingNavigationView
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if accounts.app.supportsPopular {
|
if accounts.app.supportsPopular {
|
||||||
@ -62,26 +64,7 @@ struct AppTabNavigation: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NavigationView {
|
NavigationView {
|
||||||
LazyView(
|
LazyView(SearchView())
|
||||||
SearchView()
|
|
||||||
.toolbar { toolbarContent }
|
|
||||||
.searchable(text: $search.queryText, placement: .navigationBarDrawer(displayMode: .always)) {
|
|
||||||
ForEach(search.querySuggestions.collection, id: \.self) { suggestion in
|
|
||||||
Text(suggestion)
|
|
||||||
.searchCompletion(suggestion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onChange(of: search.queryText) { query in
|
|
||||||
search.loadSuggestions(query)
|
|
||||||
}
|
|
||||||
.onSubmit(of: .search) {
|
|
||||||
search.changeQuery { query in
|
|
||||||
query.query = search.queryText
|
|
||||||
}
|
|
||||||
|
|
||||||
recents.addQuery(search.queryText)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Search", systemImage: "magnifyingglass")
|
Label("Search", systemImage: "magnifyingglass")
|
||||||
@ -129,7 +112,7 @@ struct AppTabNavigation: View {
|
|||||||
.toolbar { toolbarContent }
|
.toolbar { toolbarContent }
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Popular", systemImage: "chart.bar")
|
Label("Popular", systemImage: "arrow.up.right.circle")
|
||||||
.accessibility(label: Text("Popular"))
|
.accessibility(label: Text("Popular"))
|
||||||
}
|
}
|
||||||
.tag(TabSelection.popular)
|
.tag(TabSelection.popular)
|
||||||
@ -141,7 +124,7 @@ struct AppTabNavigation: View {
|
|||||||
.toolbar { toolbarContent }
|
.toolbar { toolbarContent }
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Trending", systemImage: "chart.line.uptrend.xyaxis")
|
Label("Trending", systemImage: "chart.bar")
|
||||||
.accessibility(label: Text("Trending"))
|
.accessibility(label: Text("Trending"))
|
||||||
}
|
}
|
||||||
.tag(TabSelection.trending)
|
.tag(TabSelection.trending)
|
||||||
|
@ -46,7 +46,7 @@ struct Sidebar: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mainNavigationLinks: some View {
|
var mainNavigationLinks: some View {
|
||||||
Section("Videos") {
|
Section(header: Text("Videos")) {
|
||||||
NavigationLink(destination: LazyView(FavoritesView()), tag: TabSelection.favorites, selection: $navigation.tabSelection) {
|
NavigationLink(destination: LazyView(FavoritesView()), tag: TabSelection.favorites, selection: $navigation.tabSelection) {
|
||||||
Label("Favorites", systemImage: "heart")
|
Label("Favorites", systemImage: "heart")
|
||||||
.accessibility(label: Text("Favorites"))
|
.accessibility(label: Text("Favorites"))
|
||||||
@ -60,13 +60,13 @@ struct Sidebar: View {
|
|||||||
|
|
||||||
if accounts.app.supportsPopular {
|
if 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: "chart.bar")
|
Label("Popular", systemImage: "arrow.up.right.circle")
|
||||||
.accessibility(label: Text("Popular"))
|
.accessibility(label: Text("Popular"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: LazyView(TrendingView()), tag: TabSelection.trending, selection: $navigation.tabSelection) {
|
NavigationLink(destination: LazyView(TrendingView()), tag: TabSelection.trending, selection: $navigation.tabSelection) {
|
||||||
Label("Trending", systemImage: "chart.line.uptrend.xyaxis")
|
Label("Trending", systemImage: "chart.bar")
|
||||||
.accessibility(label: Text("Trending"))
|
.accessibility(label: Text("Trending"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct PlaybackBar: View {
|
struct PlaybackBar: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
@Environment(\.inNavigationView) private var inNavigationView
|
@Environment(\.inNavigationView) private var inNavigationView
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@EnvironmentObject<PlayerModel> private var player
|
||||||
@ -64,18 +65,20 @@ struct PlaybackBar: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.alert(player.playerError?.localizedDescription ?? "", isPresented: $player.presentingErrorDetails) {
|
.alert(isPresented: $player.presentingErrorDetails) {
|
||||||
Button("OK") {}
|
Alert(
|
||||||
|
title: Text("Error"),
|
||||||
|
message: Text(player.playerError?.localizedDescription ?? "")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.environment(\.colorScheme, .dark)
|
|
||||||
.frame(minWidth: 0, maxWidth: .infinity)
|
.frame(minWidth: 0, maxWidth: .infinity)
|
||||||
.padding(4)
|
.padding(4)
|
||||||
.background(.black)
|
.background(colorScheme == .dark ? Color.black : Color.white)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var closeButton: some View {
|
private var closeButton: some View {
|
||||||
Button {
|
Button {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
} label: {
|
} label: {
|
||||||
Label(
|
Label(
|
||||||
"Close",
|
"Close",
|
||||||
@ -105,10 +108,18 @@ struct PlaybackBar: View {
|
|||||||
return "less than a minute"
|
return "less than a minute"
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeFinishAt = Date.now.addingTimeInterval(remainingSeconds)
|
let timeFinishAt = Date().addingTimeInterval(remainingSeconds)
|
||||||
let timeFinishAtString = timeFinishAt.formatted(date: .omitted, time: .shortened)
|
|
||||||
|
|
||||||
return "ends at \(timeFinishAtString)"
|
return "ends at \(formattedTimeFinishAt(timeFinishAt))"
|
||||||
|
}
|
||||||
|
|
||||||
|
private func formattedTimeFinishAt(_ date: Date) -> String {
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
|
||||||
|
dateFormatter.dateStyle = .none
|
||||||
|
dateFormatter.timeStyle = .short
|
||||||
|
|
||||||
|
return dateFormatter.string(from: date)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var rateMenu: some View {
|
private var rateMenu: some View {
|
||||||
|
@ -44,16 +44,18 @@ struct PlayerQueueView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ForEach(player.queue) { item in
|
ForEach(player.queue) { item in
|
||||||
PlayerQueueRow(item: item, fullScreen: $fullScreen)
|
let row = PlayerQueueRow(item: item, fullScreen: $fullScreen)
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
removeButton(item, history: false)
|
removeButton(item, history: false)
|
||||||
removeAllButton(history: false)
|
removeAllButton(history: false)
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
row.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||||
removeButton(item, history: false)
|
removeButton(item, history: false)
|
||||||
}
|
}
|
||||||
#endif
|
} else {
|
||||||
|
row
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,14 +65,18 @@ struct PlayerQueueView: View {
|
|||||||
if !player.history.isEmpty {
|
if !player.history.isEmpty {
|
||||||
Section(header: Text("Played Previously")) {
|
Section(header: Text("Played Previously")) {
|
||||||
ForEach(player.history) { item in
|
ForEach(player.history) { item in
|
||||||
PlayerQueueRow(item: item, history: true, fullScreen: $fullScreen)
|
let row = PlayerQueueRow(item: item, history: true, fullScreen: $fullScreen)
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
removeButton(item, history: true)
|
removeButton(item, history: true)
|
||||||
removeAllButton(history: true)
|
removeAllButton(history: true)
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
removeButton(item, history: true)
|
row.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||||
|
removeButton(item, history: true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
row
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -100,28 +106,44 @@ struct PlayerQueueView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func removeButton(_ item: PlayerQueueItem, history: Bool) -> some View {
|
private func removeButton(_ item: PlayerQueueItem, history: Bool) -> some View {
|
||||||
Button(role: .destructive) {
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
if history {
|
return Button(role: .destructive) {
|
||||||
player.removeHistory(item)
|
removeButtonAction(item, history: history)
|
||||||
} else {
|
} label: {
|
||||||
player.remove(item)
|
Label("Remove", systemImage: "trash")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Button {
|
||||||
|
removeButtonAction(item, history: history)
|
||||||
|
} label: {
|
||||||
|
Label("Remove", systemImage: "trash")
|
||||||
}
|
}
|
||||||
} label: {
|
|
||||||
Label("Remove", systemImage: "trash")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func removeButtonAction(_ item: PlayerQueueItem, history: Bool) {
|
||||||
|
_ = history ? player.removeHistory(item) : player.remove(item)
|
||||||
|
}
|
||||||
|
|
||||||
private func removeAllButton(history: Bool) -> some View {
|
private func removeAllButton(history: Bool) -> some View {
|
||||||
Button(role: .destructive) {
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
if history {
|
return Button(role: .destructive) {
|
||||||
player.removeHistoryItems()
|
removeAllButtonAction(history: history)
|
||||||
} else {
|
} label: {
|
||||||
player.removeQueueItems()
|
Label("Remove All", systemImage: "trash.fill")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Button {
|
||||||
|
removeAllButtonAction(history: history)
|
||||||
|
} label: {
|
||||||
|
Label("Remove All", systemImage: "trash.fill")
|
||||||
}
|
}
|
||||||
} label: {
|
|
||||||
Label("Remove All", systemImage: "trash.fill")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func removeAllButtonAction(history: Bool) {
|
||||||
|
_ = history ? player.removeHistoryItems() : player.removeQueueItems()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PlayerQueueView_Previews: PreviewProvider {
|
struct PlayerQueueView_Previews: PreviewProvider {
|
||||||
|
@ -11,14 +11,14 @@ struct VideoDetails: View {
|
|||||||
@Binding var fullScreen: Bool
|
@Binding var fullScreen: Bool
|
||||||
|
|
||||||
@State private var subscribed = false
|
@State private var subscribed = false
|
||||||
@State private var confirmationShown = false
|
@State private var presentingUnsubscribeAlert = false
|
||||||
@State private var presentingAddToPlaylist = false
|
@State private var presentingAddToPlaylist = false
|
||||||
@State private var presentingShareSheet = false
|
@State private var presentingShareSheet = false
|
||||||
@State private var shareURL: URL?
|
@State private var shareURL: URL?
|
||||||
|
|
||||||
@State private var currentPage = Page.details
|
@State private var currentPage = Page.details
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
@Environment(\.inNavigationView) private var inNavigationView
|
@Environment(\.inNavigationView) private var inNavigationView
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
@ -82,7 +82,7 @@ struct VideoDetails: View {
|
|||||||
if fullScreen {
|
if fullScreen {
|
||||||
fullScreen = false
|
fullScreen = false
|
||||||
} else {
|
} else {
|
||||||
self.dismiss()
|
self.presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,19 +184,26 @@ struct VideoDetails: View {
|
|||||||
Section {
|
Section {
|
||||||
if subscribed {
|
if subscribed {
|
||||||
Button("Unsubscribe") {
|
Button("Unsubscribe") {
|
||||||
confirmationShown = true
|
presentingUnsubscribeAlert = true
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
|
.backport
|
||||||
.tint(.gray)
|
.tint(.gray)
|
||||||
#endif
|
#endif
|
||||||
.confirmationDialog("Are you you want to unsubscribe from \(video!.channel.name)?", isPresented: $confirmationShown) {
|
.alert(isPresented: $presentingUnsubscribeAlert) {
|
||||||
Button("Unsubscribe") {
|
Alert(
|
||||||
subscriptions.unsubscribe(video!.channel.id)
|
title: Text(
|
||||||
|
"Are you you want to unsubscribe from \(video!.channel.name)?"
|
||||||
|
),
|
||||||
|
primaryButton: .destructive(Text("Unsubscribe")) {
|
||||||
|
subscriptions.unsubscribe(video!.channel.id)
|
||||||
|
|
||||||
withAnimation {
|
withAnimation {
|
||||||
subscribed.toggle()
|
subscribed.toggle()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
secondaryButton: .cancel()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Button("Subscribe") {
|
Button("Subscribe") {
|
||||||
@ -206,12 +213,12 @@ struct VideoDetails: View {
|
|||||||
subscribed.toggle()
|
subscribed.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.backport
|
||||||
.tint(.blue)
|
.tint(.blue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.font(.system(size: 13))
|
.font(.system(size: 13))
|
||||||
.buttonStyle(.borderless)
|
.buttonStyle(.borderless)
|
||||||
.buttonBorderShape(.roundedRectangle)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,13 +248,13 @@ struct VideoDetails: View {
|
|||||||
Text(published)
|
Text(published)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let publishedAt = video.publishedAt {
|
if let date = video.publishedAt {
|
||||||
if video.publishedDate != nil {
|
if video.publishedDate != nil {
|
||||||
Text("•")
|
Text("•")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.opacity(0.3)
|
.opacity(0.3)
|
||||||
}
|
}
|
||||||
Text(publishedAt.formatted(date: .abbreviated, time: .omitted))
|
Text(formattedPublishedAt(date))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.font(.system(size: 12))
|
.font(.system(size: 12))
|
||||||
@ -257,6 +264,15 @@ struct VideoDetails: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formattedPublishedAt(_ date: Date) -> String {
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
|
||||||
|
dateFormatter.dateStyle = .short
|
||||||
|
dateFormatter.timeStyle = .none
|
||||||
|
|
||||||
|
return dateFormatter.string(from: date)
|
||||||
|
}
|
||||||
|
|
||||||
var countsSection: some View {
|
var countsSection: some View {
|
||||||
Group {
|
Group {
|
||||||
if let video = player.currentVideo {
|
if let video = player.currentVideo {
|
||||||
@ -338,11 +354,17 @@ struct VideoDetails: View {
|
|||||||
|
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
if let description = video.description {
|
if let description = video.description {
|
||||||
Text(description)
|
Group {
|
||||||
.textSelection(.enabled)
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
Text(description)
|
||||||
.font(.caption)
|
.textSelection(.enabled)
|
||||||
.padding(.bottom, 4)
|
} else {
|
||||||
|
Text(description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.font(.caption)
|
||||||
|
.padding(.bottom, 4)
|
||||||
} else {
|
} else {
|
||||||
Text("No description")
|
Text("No description")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
@ -16,8 +16,10 @@ struct VideoPlayerView: View {
|
|||||||
@State private var playerSize: CGSize = .zero
|
@State private var playerSize: CGSize = .zero
|
||||||
@State private var fullScreen = false
|
@State private var fullScreen = false
|
||||||
|
|
||||||
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||||
#endif
|
#endif
|
||||||
@ -82,11 +84,11 @@ struct VideoPlayerView: View {
|
|||||||
fullScreen = true
|
fullScreen = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
down: { dismiss() }
|
down: { presentationMode.wrappedValue.dismiss() }
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.background(.black)
|
.background(Color.black)
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -98,7 +100,7 @@ struct VideoPlayerView: View {
|
|||||||
VideoDetails(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
|
VideoDetails(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.background()
|
.background(colorScheme == .dark ? Color.black : Color.white)
|
||||||
.modifier(VideoDetailsPaddingModifier(geometry: geometry, aspectRatio: player.controller?.aspectRatio, fullScreen: fullScreen))
|
.modifier(VideoDetailsPaddingModifier(geometry: geometry, aspectRatio: player.controller?.aspectRatio, fullScreen: fullScreen))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@ struct AddToPlaylistView: View {
|
|||||||
|
|
||||||
@State private var selectedPlaylistID: Playlist.ID = ""
|
@State private var selectedPlaylistID: Playlist.ID = ""
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
@EnvironmentObject<PlaylistsModel> private var model
|
@EnvironmentObject<PlaylistsModel> private var model
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -37,7 +37,7 @@ struct AddToPlaylistView: View {
|
|||||||
.padding(.vertical)
|
.padding(.vertical)
|
||||||
#elseif os(tvOS)
|
#elseif os(tvOS)
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||||
.background(.thickMaterial)
|
.background(Color.tertiaryBackground)
|
||||||
#else
|
#else
|
||||||
.padding(.vertical)
|
.padding(.vertical)
|
||||||
#endif
|
#endif
|
||||||
@ -70,7 +70,7 @@ struct AddToPlaylistView: View {
|
|||||||
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
Button("Cancel") {
|
Button("Cancel") {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
#endif
|
#endif
|
||||||
@ -155,7 +155,7 @@ struct AddToPlaylistView: View {
|
|||||||
Defaults[.lastUsedPlaylistID] = id
|
Defaults[.lastUsedPlaylistID] = id
|
||||||
|
|
||||||
model.addVideo(playlistID: id, videoID: video.videoID) {
|
model.addVideo(playlistID: id, videoID: video.videoID) {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,9 +10,7 @@ struct PlaylistFormView: View {
|
|||||||
@State private var valid = false
|
@State private var valid = false
|
||||||
@State private var showingDeleteConfirmation = false
|
@State private var showingDeleteConfirmation = false
|
||||||
|
|
||||||
@FocusState private var focused: Bool
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
@EnvironmentObject<PlaylistsModel> private var playlists
|
||||||
@ -22,77 +20,68 @@ struct PlaylistFormView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
#if os(macOS) || os(iOS)
|
Group {
|
||||||
VStack(alignment: .leading) {
|
#if os(macOS) || os(iOS)
|
||||||
HStack(alignment: .center) {
|
VStack(alignment: .leading) {
|
||||||
Text(editing ? "Edit Playlist" : "Create Playlist")
|
HStack(alignment: .center) {
|
||||||
.font(.title2.bold())
|
Text(editing ? "Edit Playlist" : "Create Playlist")
|
||||||
|
.font(.title2.bold())
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button("Cancel") {
|
Button("Cancel") {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}.keyboardShortcut(.cancelAction)
|
}.keyboardShortcut(.cancelAction)
|
||||||
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
|
|
||||||
|
Form {
|
||||||
|
TextField("Name", text: $name, onCommit: validate)
|
||||||
|
.frame(maxWidth: 450)
|
||||||
|
.padding(.leading, 10)
|
||||||
|
|
||||||
|
visibilityFormItem
|
||||||
|
.pickerStyle(.segmented)
|
||||||
|
}
|
||||||
|
#if os(macOS)
|
||||||
|
.padding(.horizontal)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
if editing {
|
||||||
|
deletePlaylistButton
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Button("Save", action: submitForm)
|
||||||
|
.disabled(!valid)
|
||||||
|
.keyboardShortcut(.defaultAction)
|
||||||
|
}
|
||||||
|
.frame(minHeight: 35)
|
||||||
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
|
||||||
|
|
||||||
Form {
|
#if os(iOS)
|
||||||
TextField("Name", text: $name, onCommit: validate)
|
.padding(.vertical)
|
||||||
.frame(maxWidth: 450)
|
#else
|
||||||
.padding(.leading, 10)
|
.frame(width: 400, height: 150)
|
||||||
.focused($focused)
|
|
||||||
|
|
||||||
visibilityFormItem
|
|
||||||
.pickerStyle(.segmented)
|
|
||||||
}
|
|
||||||
#if os(macOS)
|
|
||||||
.padding(.horizontal)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HStack {
|
|
||||||
if editing {
|
|
||||||
deletePlaylistButton
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button("Save", action: submitForm)
|
|
||||||
.disabled(!valid)
|
|
||||||
.keyboardShortcut(.defaultAction)
|
|
||||||
}
|
|
||||||
.frame(minHeight: 35)
|
|
||||||
.padding(.horizontal)
|
|
||||||
}
|
|
||||||
.onChange(of: name) { _ in validate() }
|
|
||||||
.onAppear(perform: initializeForm)
|
|
||||||
#if os(iOS)
|
|
||||||
.padding(.vertical)
|
|
||||||
#else
|
#else
|
||||||
.frame(width: 400, height: 150)
|
VStack {
|
||||||
|
Group {
|
||||||
|
header
|
||||||
|
form
|
||||||
|
}
|
||||||
|
.frame(maxWidth: 1000)
|
||||||
|
}
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||||
|
.background(Color.tertiaryBackground)
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
#else
|
.onChange(of: name) { _ in validate() }
|
||||||
VStack {
|
.onAppear(perform: initializeForm)
|
||||||
Group {
|
|
||||||
header
|
|
||||||
form
|
|
||||||
}
|
|
||||||
.frame(maxWidth: 1000)
|
|
||||||
}
|
|
||||||
.onAppear {
|
|
||||||
guard editing else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.name = self.playlist.title
|
|
||||||
self.visibility = self.playlist.visibility
|
|
||||||
|
|
||||||
validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
|
||||||
.background(.thickMaterial)
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
@ -152,16 +141,16 @@ struct PlaylistFormView: View {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
func initializeForm() {
|
func initializeForm() {
|
||||||
focused = true
|
|
||||||
|
|
||||||
guard editing else {
|
guard editing else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
name = playlist.title
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
visibility = playlist.visibility
|
name = playlist.title
|
||||||
|
visibility = playlist.visibility
|
||||||
|
|
||||||
validate()
|
validate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate() {
|
func validate() {
|
||||||
@ -182,7 +171,7 @@ struct PlaylistFormView: View {
|
|||||||
|
|
||||||
playlists.load(force: true)
|
playlists.load(force: true)
|
||||||
|
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +183,7 @@ struct PlaylistFormView: View {
|
|||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
Picker("Visibility", selection: $visibility) {
|
Picker("Visibility", selection: $visibility) {
|
||||||
ForEach(Playlist.Visibility.allCases) { visibility in
|
ForEach(Playlist.Visibility.allCases) { visibility in
|
||||||
Text(visibility.name)
|
Text(visibility.name).tag(visibility)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -216,9 +205,10 @@ struct PlaylistFormView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var deletePlaylistButton: some View {
|
var deletePlaylistButton: some View {
|
||||||
Button("Delete", role: .destructive) {
|
Button("Delete") {
|
||||||
showingDeleteConfirmation = true
|
showingDeleteConfirmation = true
|
||||||
}.alert(isPresented: $showingDeleteConfirmation) {
|
}
|
||||||
|
.alert(isPresented: $showingDeleteConfirmation) {
|
||||||
Alert(
|
Alert(
|
||||||
title: Text("Are you sure you want to delete playlist?"),
|
title: Text("Are you sure you want to delete playlist?"),
|
||||||
message: Text("Playlist \"\(playlist.title)\" will be deleted.\nIt cannot be undone."),
|
message: Text("Playlist \"\(playlist.title)\" will be deleted.\nIt cannot be undone."),
|
||||||
@ -226,16 +216,14 @@ struct PlaylistFormView: View {
|
|||||||
secondaryButton: .cancel()
|
secondaryButton: .cancel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#if os(macOS)
|
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func deletePlaylistAndDismiss() {
|
func deletePlaylistAndDismiss() {
|
||||||
accounts.api.playlist(playlist.id)?.request(.delete).onSuccess { _ in
|
accounts.api.playlist(playlist.id)?.request(.delete).onSuccess { _ in
|
||||||
playlist = nil
|
playlist = nil
|
||||||
playlists.load(force: true)
|
playlists.load(force: true)
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,17 +71,20 @@ struct PlaylistsView: View {
|
|||||||
ToolbarItemGroup {
|
ToolbarItemGroup {
|
||||||
#if !os(iOS)
|
#if !os(iOS)
|
||||||
if !model.isEmpty {
|
if !model.isEmpty {
|
||||||
selectPlaylistButton
|
if #available(macOS 12.0, *) {
|
||||||
.prefersDefaultFocus(in: focusNamespace)
|
selectPlaylistButton
|
||||||
|
.prefersDefaultFocus(in: focusNamespace)
|
||||||
|
} else {
|
||||||
|
selectPlaylistButton
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentPlaylist != nil {
|
if currentPlaylist != nil {
|
||||||
editPlaylistButton
|
editPlaylistButton
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
FavoriteButton(item: FavoriteItem(section: .playlist(selectedPlaylistID)))
|
|
||||||
|
|
||||||
newPlaylistButton
|
FavoriteButton(item: FavoriteItem(section: .playlist(selectedPlaylistID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -99,6 +102,8 @@ struct PlaylistsView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
newPlaylistButton
|
||||||
|
|
||||||
if currentPlaylist != nil {
|
if currentPlaylist != nil {
|
||||||
editPlaylistButton
|
editPlaylistButton
|
||||||
}
|
}
|
||||||
@ -168,7 +173,7 @@ struct PlaylistsView: View {
|
|||||||
}
|
}
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.background()
|
.background(Color.tertiaryBackground)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
80
Shared/Search/SearchField.swift
Normal file
80
Shared/Search/SearchField.swift
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SearchTextField: View {
|
||||||
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
|
@EnvironmentObject<RecentsModel> private var recents
|
||||||
|
@EnvironmentObject<SearchModel> private var state
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
#if os(macOS)
|
||||||
|
fieldBorder
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
#if os(macOS)
|
||||||
|
Image(systemName: "magnifyingglass")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: 12, height: 12)
|
||||||
|
.padding(.horizontal, 8)
|
||||||
|
.opacity(0.8)
|
||||||
|
#endif
|
||||||
|
TextField("Search...", text: $state.queryText) {
|
||||||
|
state.changeQuery { query in query.query = state.queryText }
|
||||||
|
recents.addQuery(state.queryText)
|
||||||
|
}
|
||||||
|
.onChange(of: state.queryText) { _ in
|
||||||
|
if state.query.query.compare(state.queryText, options: .caseInsensitive) == .orderedSame {
|
||||||
|
state.fieldIsFocused = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(macOS)
|
||||||
|
.textFieldStyle(.plain)
|
||||||
|
#else
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
.padding(.leading)
|
||||||
|
.padding(.trailing, 15)
|
||||||
|
#endif
|
||||||
|
if !self.state.queryText.isEmpty {
|
||||||
|
clearButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.top, navigationStyle == .tab ? 10 : 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var fieldBorder: some View {
|
||||||
|
RoundedRectangle(cornerRadius: 5, style: .continuous)
|
||||||
|
.fill(Color.background)
|
||||||
|
.frame(width: 250, height: 32)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 5, style: .continuous)
|
||||||
|
.stroke(
|
||||||
|
state.fieldIsFocused ? Color.blue.opacity(0.7) : Color.gray.opacity(0.4),
|
||||||
|
lineWidth: state.fieldIsFocused ? 3 : 1
|
||||||
|
)
|
||||||
|
.frame(width: 250, height: 31)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var clearButton: some View {
|
||||||
|
Button(action: {
|
||||||
|
self.state.queryText = ""
|
||||||
|
}) {
|
||||||
|
Image(systemName: "xmark.circle.fill")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
#if os(macOS)
|
||||||
|
.frame(width: 14, height: 14)
|
||||||
|
#else
|
||||||
|
.frame(width: 18, height: 18)
|
||||||
|
#endif
|
||||||
|
.padding(.trailing, 3)
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
.padding(.trailing, 10)
|
||||||
|
.opacity(0.7)
|
||||||
|
}
|
||||||
|
}
|
77
Shared/Search/SearchSuggestions.swift
Normal file
77
Shared/Search/SearchSuggestions.swift
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SearchSuggestions: View {
|
||||||
|
@EnvironmentObject<RecentsModel> private var recents
|
||||||
|
@EnvironmentObject<SearchModel> private var state
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
Button {
|
||||||
|
state.changeQuery { query in
|
||||||
|
query.query = state.queryText
|
||||||
|
state.fieldIsFocused = false
|
||||||
|
}
|
||||||
|
|
||||||
|
recents.addQuery(state.queryText)
|
||||||
|
} label: {
|
||||||
|
HStack(spacing: 5) {
|
||||||
|
Label(state.queryText, systemImage: "magnifyingglass")
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(macOS)
|
||||||
|
.onHover(perform: onHover(_:))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ForEach(visibleSuggestions, id: \.self) { suggestion in
|
||||||
|
Button {
|
||||||
|
state.queryText = suggestion
|
||||||
|
} label: {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Label(state.queryText, systemImage: "arrow.up.left.circle")
|
||||||
|
.lineLimit(1)
|
||||||
|
.layoutPriority(2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Text(querySuffix(suggestion))
|
||||||
|
.lineLimit(1)
|
||||||
|
.layoutPriority(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(macOS)
|
||||||
|
.onHover(perform: onHover(_:))
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(macOS)
|
||||||
|
.buttonStyle(.link)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private var visibleSuggestions: [String] {
|
||||||
|
state.querySuggestions.collection.filter {
|
||||||
|
$0.compare(state.queryText, options: .caseInsensitive) != .orderedSame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func querySuffix(_ suggestion: String) -> String {
|
||||||
|
suggestion.replacingFirstOccurrence(of: state.queryText.lowercased(), with: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
private func onHover(_ inside: Bool) {
|
||||||
|
if inside {
|
||||||
|
NSCursor.pointingHand.push()
|
||||||
|
} else {
|
||||||
|
NSCursor.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SearchSuggestions_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
SearchSuggestions()
|
||||||
|
.injectFixtureEnvironmentObjects()
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,6 @@ struct SearchView: View {
|
|||||||
@State private var searchDate = SearchQuery.Date.any
|
@State private var searchDate = SearchQuery.Date.any
|
||||||
@State private var searchDuration = SearchQuery.Duration.any
|
@State private var searchDuration = SearchQuery.Duration.any
|
||||||
|
|
||||||
@State private var presentingClearConfirmation = false
|
|
||||||
@State private var recentsChanged = false
|
@State private var recentsChanged = false
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
@ -31,50 +30,37 @@ struct SearchView: View {
|
|||||||
state.store.collection.sorted { $0 < $1 }
|
state.store.collection.sorted { $0 < $1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
init(_ query: SearchQuery? = nil, videos: [Video] = [Video]()) {
|
init(_ query: SearchQuery? = nil, videos: [Video] = []) {
|
||||||
self.query = query
|
self.query = query
|
||||||
self.videos = videos
|
self.videos = videos
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
PlayerControlsView {
|
PlayerControlsView {
|
||||||
VStack {
|
#if os(iOS)
|
||||||
if showRecentQueries {
|
VStack {
|
||||||
recentQueries
|
SearchTextField()
|
||||||
} else {
|
|
||||||
#if os(tvOS)
|
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
if accounts.app.supportsSearchFilters {
|
|
||||||
filtersHorizontalStack
|
|
||||||
}
|
|
||||||
|
|
||||||
if let favoriteItem = favoriteItem {
|
if state.query.query != state.queryText, !state.queryText.isEmpty, !state.querySuggestions.collection.isEmpty {
|
||||||
FavoriteButton(item: favoriteItem)
|
SearchSuggestions()
|
||||||
.id(favoriteItem.id)
|
} else {
|
||||||
.labelStyle(.iconOnly)
|
results
|
||||||
.font(.system(size: 25))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalCells(items: items)
|
|
||||||
}
|
|
||||||
.edgesIgnoringSafeArea(.horizontal)
|
|
||||||
#else
|
|
||||||
VerticalCells(items: items)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if noResults {
|
|
||||||
Text("No results")
|
|
||||||
|
|
||||||
if searchFiltersActive {
|
|
||||||
Button("Reset search filters", action: resetFilters)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
#else
|
||||||
|
ZStack {
|
||||||
|
results
|
||||||
|
|
||||||
|
if state.query.query != state.queryText, !state.queryText.isEmpty, !state.querySuggestions.collection.isEmpty {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
SearchSuggestions()
|
||||||
|
.borderLeading(width: 1, color: Color("ControlsBorderColor"))
|
||||||
|
.frame(maxWidth: 280)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
@ -118,6 +104,10 @@ struct SearchView: View {
|
|||||||
if accounts.app.supportsSearchFilters {
|
if accounts.app.supportsSearchFilters {
|
||||||
filtersMenu
|
filtersMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
SearchTextField()
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -132,10 +122,11 @@ struct SearchView: View {
|
|||||||
state.store.replace(ContentItem.array(of: videos))
|
state.store.replace(ContentItem.array(of: videos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.searchable(text: $state.queryText, placement: searchFieldPlacement) {
|
.onChange(of: state.query.query) { newQuery in
|
||||||
ForEach(state.querySuggestions.collection, id: \.self) { suggestion in
|
if newQuery.isEmpty {
|
||||||
Text(suggestion)
|
favoriteItem = nil
|
||||||
.searchCompletion(suggestion)
|
} else {
|
||||||
|
updateFavoriteItem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: state.queryText) { newQuery in
|
.onChange(of: state.queryText) { newQuery in
|
||||||
@ -161,11 +152,7 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.onSubmit(of: .search) {
|
|
||||||
state.changeQuery { query in query.query = state.queryText }
|
|
||||||
recents.addQuery(state.queryText)
|
|
||||||
updateFavoriteItem()
|
|
||||||
}
|
|
||||||
.onChange(of: searchSortOrder) { order in
|
.onChange(of: searchSortOrder) { order in
|
||||||
state.changeQuery { query in
|
state.changeQuery { query in
|
||||||
query.sortBy = order
|
query.sortBy = order
|
||||||
@ -185,19 +172,55 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
|
.ignoresSafeArea(.keyboard, edges: .bottom)
|
||||||
.navigationTitle("Search")
|
.navigationTitle("Search")
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
var searchFieldPlacement: SearchFieldPlacement {
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.navigationBarDrawer(displayMode: .always)
|
.navigationBarHidden(true)
|
||||||
#else
|
|
||||||
.automatic
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var toolbarPlacement: ToolbarItemPlacement {
|
private var results: some View {
|
||||||
|
VStack {
|
||||||
|
if showRecentQueries {
|
||||||
|
recentQueries
|
||||||
|
} else {
|
||||||
|
#if os(tvOS)
|
||||||
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
if accounts.app.supportsSearchFilters {
|
||||||
|
filtersHorizontalStack
|
||||||
|
}
|
||||||
|
|
||||||
|
if let favoriteItem = favoriteItem {
|
||||||
|
FavoriteButton(item: favoriteItem)
|
||||||
|
.id(favoriteItem.id)
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
.font(.system(size: 25))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalCells(items: items)
|
||||||
|
}
|
||||||
|
.edgesIgnoringSafeArea(.horizontal)
|
||||||
|
#else
|
||||||
|
VerticalCells(items: items)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if noResults {
|
||||||
|
Text("No results")
|
||||||
|
|
||||||
|
if searchFiltersActive {
|
||||||
|
Button("Reset search filters", action: resetFilters)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var toolbarPlacement: ToolbarItemPlacement {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.bottomBar
|
.bottomBar
|
||||||
#else
|
#else
|
||||||
@ -205,25 +228,25 @@ struct SearchView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate var showRecentQueries: Bool {
|
private var showRecentQueries: Bool {
|
||||||
navigationStyle == .tab && state.queryText.isEmpty
|
navigationStyle == .tab && state.queryText.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate var filtersActive: Bool {
|
private var filtersActive: Bool {
|
||||||
searchDuration != .any || searchDate != .any
|
searchDuration != .any || searchDate != .any
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func resetFilters() {
|
private func resetFilters() {
|
||||||
searchSortOrder = .relevance
|
searchSortOrder = .relevance
|
||||||
searchDate = .any
|
searchDate = .any
|
||||||
searchDuration = .any
|
searchDuration = .any
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate var noResults: Bool {
|
private var noResults: Bool {
|
||||||
items.isEmpty && !state.isLoading && !state.query.isEmpty
|
items.isEmpty && !state.isLoading && !state.query.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
var recentQueries: some View {
|
private var recentQueries: some View {
|
||||||
VStack {
|
VStack {
|
||||||
List {
|
List {
|
||||||
Section(header: Text("Recents")) {
|
Section(header: Text("Recents")) {
|
||||||
@ -237,22 +260,13 @@ struct SearchView: View {
|
|||||||
state.changeQuery { query in query.query = item.title }
|
state.changeQuery { query in query.query = item.title }
|
||||||
updateFavoriteItem()
|
updateFavoriteItem()
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
|
||||||
.swipeActions(edge: .trailing) {
|
|
||||||
deleteButton(item)
|
|
||||||
}
|
|
||||||
#elseif os(tvOS)
|
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
deleteButton(item)
|
deleteButton(item)
|
||||||
|
deleteAllButton
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.redrawOn(change: recentsChanged)
|
.redrawOn(change: recentsChanged)
|
||||||
|
|
||||||
if !recentItems.isEmpty {
|
|
||||||
clearAllButton
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -260,37 +274,33 @@ struct SearchView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !os(macOS)
|
private func deleteButton(_ item: RecentItem) -> some View {
|
||||||
func deleteButton(_ item: RecentItem) -> some View {
|
Button {
|
||||||
Button(role: .destructive) {
|
recents.close(item)
|
||||||
recents.close(item)
|
recentsChanged.toggle()
|
||||||
recentsChanged.toggle()
|
} label: {
|
||||||
} label: {
|
Label("Delete", systemImage: "trash")
|
||||||
Label("Delete", systemImage: "trash")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var clearAllButton: some View {
|
|
||||||
Button("Clear All", role: .destructive) {
|
|
||||||
presentingClearConfirmation = true
|
|
||||||
}
|
|
||||||
.confirmationDialog("Clear All", isPresented: $presentingClearConfirmation) {
|
|
||||||
Button("Clear All", role: .destructive) {
|
|
||||||
recents.clearQueries()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchFiltersActive: Bool {
|
private var deleteAllButton: some View {
|
||||||
|
Button {
|
||||||
|
recents.clearQueries()
|
||||||
|
recentsChanged.toggle()
|
||||||
|
} label: {
|
||||||
|
Label("Delete All", systemImage: "trash.fill")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var searchFiltersActive: Bool {
|
||||||
searchDate != .any || searchDuration != .any
|
searchDate != .any || searchDuration != .any
|
||||||
}
|
}
|
||||||
|
|
||||||
var recentItems: [RecentItem] {
|
private var recentItems: [RecentItem] {
|
||||||
Defaults[.recentlyOpened].filter { $0.type == .query }.reversed()
|
Defaults[.recentlyOpened].filter { $0.type == .query }.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchSortOrderPicker: some View {
|
private var searchSortOrderPicker: some View {
|
||||||
Picker("Sort", selection: $searchSortOrder) {
|
Picker("Sort", selection: $searchSortOrder) {
|
||||||
ForEach(SearchQuery.SortOrder.allCases) { sortOrder in
|
ForEach(SearchQuery.SortOrder.allCases) { sortOrder in
|
||||||
Text(sortOrder.name).tag(sortOrder)
|
Text(sortOrder.name).tag(sortOrder)
|
||||||
@ -299,7 +309,7 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
var searchSortOrderButton: some View {
|
private var searchSortOrderButton: some View {
|
||||||
Button(action: { self.searchSortOrder = self.searchSortOrder.next() }) { Text(self.searchSortOrder.name)
|
Button(action: { self.searchSortOrder = self.searchSortOrder.next() }) { Text(self.searchSortOrder.name)
|
||||||
.font(.system(size: 30))
|
.font(.system(size: 30))
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
@ -315,7 +325,7 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchDateButton: some View {
|
private var searchDateButton: some View {
|
||||||
Button(action: { self.searchDate = self.searchDate.next() }) {
|
Button(action: { self.searchDate = self.searchDate.next() }) {
|
||||||
Text(self.searchDate.name)
|
Text(self.searchDate.name)
|
||||||
.font(.system(size: 30))
|
.font(.system(size: 30))
|
||||||
@ -332,7 +342,7 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchDurationButton: some View {
|
private var searchDurationButton: some View {
|
||||||
Button(action: { self.searchDuration = self.searchDuration.next() }) {
|
Button(action: { self.searchDuration = self.searchDuration.next() }) {
|
||||||
Text(self.searchDuration.name)
|
Text(self.searchDuration.name)
|
||||||
.font(.system(size: 30))
|
.font(.system(size: 30))
|
||||||
@ -349,7 +359,7 @@ struct SearchView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var filtersHorizontalStack: some View {
|
private var filtersHorizontalStack: some View {
|
||||||
HStack {
|
HStack {
|
||||||
HStack(spacing: 30) {
|
HStack(spacing: 30) {
|
||||||
Text("Sort")
|
Text("Sort")
|
||||||
@ -375,7 +385,7 @@ struct SearchView: View {
|
|||||||
.font(.system(size: 30))
|
.font(.system(size: 30))
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
var filtersMenu: some View {
|
private var filtersMenu: some View {
|
||||||
Menu(filtersActive ? "Filter: active" : "Filter") {
|
Menu(filtersActive ? "Filter: active" : "Filter") {
|
||||||
Picker(selection: $searchDuration, label: Text("Duration")) {
|
Picker(selection: $searchDuration, label: Text("Duration")) {
|
||||||
ForEach(SearchQuery.Duration.allCases) { duration in
|
ForEach(SearchQuery.Duration.allCases) { duration in
|
@ -15,9 +15,7 @@ struct AccountForm: View {
|
|||||||
@State private var validationError: String?
|
@State private var validationError: String?
|
||||||
@State private var validationDebounce = Debounce()
|
@State private var validationDebounce = Debounce()
|
||||||
|
|
||||||
@FocusState private var focused: Bool
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
@ -32,7 +30,7 @@ struct AccountForm: View {
|
|||||||
.padding(.vertical)
|
.padding(.vertical)
|
||||||
#elseif os(tvOS)
|
#elseif os(tvOS)
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||||
.background(.thickMaterial)
|
.background(Color.tertiaryBackground)
|
||||||
#else
|
#else
|
||||||
.frame(width: 400, height: 145)
|
.frame(width: 400, height: 145)
|
||||||
#endif
|
#endif
|
||||||
@ -46,7 +44,7 @@ struct AccountForm: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button("Cancel") {
|
Button("Cancel") {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
@ -68,7 +66,6 @@ struct AccountForm: View {
|
|||||||
formFields
|
formFields
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.onAppear(perform: initializeForm)
|
|
||||||
.onChange(of: username) { _ in validate() }
|
.onChange(of: username) { _ in validate() }
|
||||||
.onChange(of: password) { _ in validate() }
|
.onChange(of: password) { _ in validate() }
|
||||||
}
|
}
|
||||||
@ -76,24 +73,23 @@ struct AccountForm: View {
|
|||||||
var formFields: some View {
|
var formFields: some View {
|
||||||
Group {
|
Group {
|
||||||
if !instance.app.accountsUsePassword {
|
if !instance.app.accountsUsePassword {
|
||||||
TextField("Name", text: $name, prompt: Text("Account Name (optional)"))
|
TextField("Name", text: $name)
|
||||||
.focused($focused)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField("Username", text: $username, prompt: usernamePrompt)
|
TextField(usernamePrompt, text: $username)
|
||||||
|
|
||||||
if instance.app.accountsUsePassword {
|
if instance.app.accountsUsePassword {
|
||||||
SecureField("Password", text: $password, prompt: Text("Password"))
|
SecureField("Password", text: $password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var usernamePrompt: Text {
|
var usernamePrompt: String {
|
||||||
switch instance.app {
|
switch instance.app {
|
||||||
case .invidious:
|
case .invidious:
|
||||||
return Text("SID Cookie")
|
return "SID Cookie"
|
||||||
default:
|
default:
|
||||||
return Text("Username")
|
return "Username"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,10 +117,6 @@ struct AccountForm: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func initializeForm() {
|
|
||||||
focused = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private func validate() {
|
private func validate() {
|
||||||
isValid = false
|
isValid = false
|
||||||
validationDebounce.invalidate()
|
validationDebounce.invalidate()
|
||||||
@ -151,7 +143,7 @@ struct AccountForm: View {
|
|||||||
let account = AccountsModel.add(instance: instance, name: name, username: username, password: password)
|
let account = AccountsModel.add(instance: instance, name: name, username: username, password: password)
|
||||||
selectedAccount?.wrappedValue = account
|
selectedAccount?.wrappedValue = account
|
||||||
|
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var validator: AccountValidator {
|
private var validator: AccountValidator {
|
||||||
|
31
Shared/Settings/AccountsNavigationLink.swift
Normal file
31
Shared/Settings/AccountsNavigationLink.swift
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct AccountsNavigationLink: View {
|
||||||
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
|
var instance: Instance
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationLink(instance.longDescription) {
|
||||||
|
InstanceSettings(instanceID: instance.id)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.contextMenu {
|
||||||
|
removeInstanceButton(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func removeInstanceButton(_ instance: Instance) -> some View {
|
||||||
|
if #available(iOS 15.0, *) {
|
||||||
|
return Button("Remove", role: .destructive) { removeAction(instance) }
|
||||||
|
} else {
|
||||||
|
return Button("Remove") { removeAction(instance) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func removeAction(_ instance: Instance) {
|
||||||
|
if accounts.current?.instance == instance {
|
||||||
|
accounts.setCurrent(nil)
|
||||||
|
}
|
||||||
|
InstancesModel.remove(instance)
|
||||||
|
}
|
||||||
|
}
|
@ -1,102 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct AccountsSettings: View {
|
|
||||||
let instanceID: Instance.ID?
|
|
||||||
|
|
||||||
@State private var accountsChanged = false
|
|
||||||
@State private var presentingAccountForm = false
|
|
||||||
|
|
||||||
@State private var frontendURL = ""
|
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var model
|
|
||||||
@EnvironmentObject<InstancesModel> private var instances
|
|
||||||
|
|
||||||
var instance: Instance! {
|
|
||||||
InstancesModel.find(instanceID)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
List {
|
|
||||||
if instance.app.hasFrontendURL {
|
|
||||||
Section(header: Text("Frontend URL")) {
|
|
||||||
TextField(
|
|
||||||
"Frontend URL",
|
|
||||||
text: $frontendURL,
|
|
||||||
prompt: Text("To enable videos, channels and playlists sharing")
|
|
||||||
)
|
|
||||||
.onAppear {
|
|
||||||
frontendURL = instance.frontendURL ?? ""
|
|
||||||
}
|
|
||||||
.onChange(of: frontendURL) { newValue in
|
|
||||||
InstancesModel.setFrontendURL(instance, newValue)
|
|
||||||
}
|
|
||||||
.labelsHidden()
|
|
||||||
.autocapitalization(.none)
|
|
||||||
.keyboardType(.URL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Section(header: Text("Accounts"), footer: sectionFooter) {
|
|
||||||
if instance.app.supportsAccounts {
|
|
||||||
accounts
|
|
||||||
} else {
|
|
||||||
Text("Accounts are not supported for the application of this instance")
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if os(tvOS)
|
|
||||||
.frame(maxWidth: 1000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.navigationTitle(instance.description)
|
|
||||||
}
|
|
||||||
|
|
||||||
var accounts: some View {
|
|
||||||
Group {
|
|
||||||
ForEach(InstancesModel.accounts(instanceID), id: \.self) { account in
|
|
||||||
#if os(tvOS)
|
|
||||||
Button(account.description) {}
|
|
||||||
.contextMenu {
|
|
||||||
Button("Remove", role: .destructive) { removeAccount(account) }
|
|
||||||
Button("Cancel", role: .cancel) {}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
Text(account.description)
|
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
|
||||||
Button("Remove", role: .destructive) { removeAccount(account) }
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
.redrawOn(change: accountsChanged)
|
|
||||||
|
|
||||||
Button("Add account...") {
|
|
||||||
presentingAccountForm = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.sheet(isPresented: $presentingAccountForm, onDismiss: { accountsChanged.toggle() }) {
|
|
||||||
AccountForm(instance: instance)
|
|
||||||
}
|
|
||||||
#if !os(tvOS)
|
|
||||||
.listStyle(.insetGrouped)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private var sectionFooter: some View {
|
|
||||||
if !instance.app.supportsAccounts {
|
|
||||||
return Text("")
|
|
||||||
}
|
|
||||||
|
|
||||||
#if os(iOS)
|
|
||||||
return Text("Swipe to remove account")
|
|
||||||
#else
|
|
||||||
return Text("Tap and hold to remove account")
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private func removeAccount(_ account: Account) {
|
|
||||||
AccountsModel.remove(account)
|
|
||||||
accountsChanged.toggle()
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,9 +13,7 @@ struct InstanceForm: View {
|
|||||||
@State private var validationError: String?
|
@State private var validationError: String?
|
||||||
@State private var validationDebounce = Debounce()
|
@State private var validationDebounce = Debounce()
|
||||||
|
|
||||||
@FocusState private var nameFieldFocused: Bool
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
@ -30,12 +28,11 @@ struct InstanceForm: View {
|
|||||||
}
|
}
|
||||||
.onChange(of: app) { _ in validate() }
|
.onChange(of: app) { _ in validate() }
|
||||||
.onChange(of: url) { _ in validate() }
|
.onChange(of: url) { _ in validate() }
|
||||||
.onAppear(perform: initializeForm)
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.padding(.vertical)
|
.padding(.vertical)
|
||||||
#elseif os(tvOS)
|
#elseif os(tvOS)
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
|
||||||
.background(.thickMaterial)
|
.background(Color.tertiaryBackground)
|
||||||
#else
|
#else
|
||||||
.frame(width: 400, height: 190)
|
.frame(width: 400, height: 190)
|
||||||
#endif
|
#endif
|
||||||
@ -49,7 +46,7 @@ struct InstanceForm: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button("Cancel") {
|
Button("Cancel") {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
@ -80,10 +77,9 @@ struct InstanceForm: View {
|
|||||||
}
|
}
|
||||||
.pickerStyle(.segmented)
|
.pickerStyle(.segmented)
|
||||||
|
|
||||||
TextField("Name", text: $name, prompt: Text("Instance Name (optional)"))
|
TextField("Name", text: $name)
|
||||||
.focused($nameFieldFocused)
|
|
||||||
|
|
||||||
TextField("API URL", text: $url, prompt: Text("https://invidious.home.net"))
|
TextField("API URL", text: $url)
|
||||||
|
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
@ -138,10 +134,6 @@ struct InstanceForm: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeForm() {
|
|
||||||
nameFieldFocused = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func submitForm() {
|
func submitForm() {
|
||||||
guard isValid else {
|
guard isValid else {
|
||||||
return
|
return
|
||||||
@ -149,7 +141,7 @@ struct InstanceForm: View {
|
|||||||
|
|
||||||
savedInstanceID = InstancesModel.add(app: app, name: name, url: url).id
|
savedInstanceID = InstancesModel.add(app: app, name: name, url: url).id
|
||||||
|
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
104
Shared/Settings/InstanceSettings.swift
Normal file
104
Shared/Settings/InstanceSettings.swift
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct InstanceSettings: View {
|
||||||
|
let instanceID: Instance.ID?
|
||||||
|
|
||||||
|
@State private var accountsChanged = false
|
||||||
|
@State private var presentingAccountForm = false
|
||||||
|
|
||||||
|
@State private var frontendURL = ""
|
||||||
|
|
||||||
|
@EnvironmentObject<AccountsModel> private var model
|
||||||
|
@EnvironmentObject<InstancesModel> private var instances
|
||||||
|
|
||||||
|
var instance: Instance! {
|
||||||
|
InstancesModel.find(instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
if instance.app.hasFrontendURL {
|
||||||
|
Section(header: Text("Frontend URL")) {
|
||||||
|
TextField(
|
||||||
|
"Frontend URL",
|
||||||
|
text: $frontendURL
|
||||||
|
)
|
||||||
|
.onAppear {
|
||||||
|
frontendURL = instance.frontendURL ?? ""
|
||||||
|
}
|
||||||
|
.onChange(of: frontendURL) { newValue in
|
||||||
|
InstancesModel.setFrontendURL(instance, newValue)
|
||||||
|
}
|
||||||
|
.labelsHidden()
|
||||||
|
.autocapitalization(.none)
|
||||||
|
.keyboardType(.URL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Section(header: Text("Accounts"), footer: sectionFooter) {
|
||||||
|
if instance.app.supportsAccounts {
|
||||||
|
ForEach(InstancesModel.accounts(instanceID), id: \.self) { account in
|
||||||
|
#if os(tvOS)
|
||||||
|
Button(account.description) {}
|
||||||
|
.contextMenu {
|
||||||
|
Button("Remove") { removeAccount(account) }
|
||||||
|
Button("Cancel", role: .cancel) {}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ZStack {
|
||||||
|
NavigationLink(destination: EmptyView()) {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
|
.disabled(true)
|
||||||
|
.hidden()
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Text(account.description)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.contextMenu {
|
||||||
|
Button("Remove") { removeAccount(account) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.redrawOn(change: accountsChanged)
|
||||||
|
|
||||||
|
Button("Add account...") {
|
||||||
|
presentingAccountForm = true
|
||||||
|
}
|
||||||
|
.sheet(isPresented: $presentingAccountForm, onDismiss: { accountsChanged.toggle() }) {
|
||||||
|
AccountForm(instance: instance)
|
||||||
|
}
|
||||||
|
#if !os(tvOS)
|
||||||
|
.listStyle(.insetGrouped)
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
Text("Accounts are not supported for the application of this instance")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(tvOS)
|
||||||
|
.frame(maxWidth: 1000)
|
||||||
|
#elseif os(iOS)
|
||||||
|
.listStyle(.insetGrouped)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.navigationTitle(instance.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var sectionFooter: some View {
|
||||||
|
if !instance.app.supportsAccounts {
|
||||||
|
return Text("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text("Tap and hold to remove account")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func removeAccount(_ account: Account) {
|
||||||
|
AccountsModel.remove(account)
|
||||||
|
accountsChanged.toggle()
|
||||||
|
}
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
import Defaults
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct InstancesSettings: View {
|
|
||||||
@Default(.instances) private var instances
|
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
|
||||||
|
|
||||||
@State private var selectedInstanceID: Instance.ID?
|
|
||||||
@State private var selectedAccount: Account?
|
|
||||||
|
|
||||||
@State private var presentingInstanceForm = false
|
|
||||||
@State private var savedFormInstanceID: Instance.ID?
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Group {
|
|
||||||
Section(header: SettingsHeader(text: "Instances")) {
|
|
||||||
ForEach(instances) { instance in
|
|
||||||
Group {
|
|
||||||
NavigationLink(instance.longDescription) {
|
|
||||||
AccountsSettings(instanceID: instance.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if os(iOS)
|
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
|
||||||
removeInstanceButton(instance)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
#else
|
|
||||||
.contextMenu {
|
|
||||||
removeInstanceButton(instance)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
addInstanceButton
|
|
||||||
}
|
|
||||||
#if os(iOS)
|
|
||||||
.listStyle(.insetGrouped)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
.sheet(isPresented: $presentingInstanceForm) {
|
|
||||||
InstanceForm(savedInstanceID: $savedFormInstanceID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var addInstanceButton: some View {
|
|
||||||
Button("Add Instance...") {
|
|
||||||
presentingInstanceForm = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func removeInstanceButton(_ instance: Instance) -> some View {
|
|
||||||
Button("Remove", role: .destructive) {
|
|
||||||
if accounts.current?.instance == instance {
|
|
||||||
accounts.setCurrent(nil)
|
|
||||||
}
|
|
||||||
InstancesModel.remove(instance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct InstancesSettingsView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
VStack {
|
|
||||||
InstancesSettings()
|
|
||||||
}
|
|
||||||
.frame(width: 400, height: 270)
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,8 +9,7 @@ struct ServicesSettings: View {
|
|||||||
Section(header: SettingsHeader(text: "SponsorBlock API")) {
|
Section(header: SettingsHeader(text: "SponsorBlock API")) {
|
||||||
TextField(
|
TextField(
|
||||||
"SponsorBlock API Instance",
|
"SponsorBlock API Instance",
|
||||||
text: $sponsorBlockInstance,
|
text: $sponsorBlockInstance
|
||||||
prompt: Text("SponsorBlock API URL, leave blank to disable")
|
|
||||||
)
|
)
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
@ -21,7 +20,7 @@ struct ServicesSettings: View {
|
|||||||
|
|
||||||
Section(header: SettingsHeader(text: "Categories to Skip")) {
|
Section(header: SettingsHeader(text: "Categories to Skip")) {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
List(SponsorBlockAPI.categories, id: \.self) { category in
|
let list = List(SponsorBlockAPI.categories, id: \.self) { category in
|
||||||
SponsorBlockCategorySelectionRow(
|
SponsorBlockCategorySelectionRow(
|
||||||
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
||||||
selected: sponsorBlockCategories.contains(category)
|
selected: sponsorBlockCategories.contains(category)
|
||||||
@ -29,7 +28,16 @@ struct ServicesSettings: View {
|
|||||||
toggleCategory(category, value: value)
|
toggleCategory(category, value: value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
|
||||||
|
Group {
|
||||||
|
if #available(macOS 12.0, *) {
|
||||||
|
list
|
||||||
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
|
} else {
|
||||||
|
list
|
||||||
|
.listStyle(.inset)
|
||||||
|
}
|
||||||
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
#else
|
#else
|
||||||
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||||
|
@ -10,11 +10,16 @@ struct SettingsView: View {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
|
|
||||||
|
@State private var presentingInstanceForm = false
|
||||||
|
@State private var savedFormInstanceID: Instance.ID?
|
||||||
|
|
||||||
|
@Default(.instances) private var instances
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
TabView {
|
TabView {
|
||||||
@ -65,8 +70,14 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
InstancesSettings()
|
|
||||||
.environmentObject(accounts)
|
Section(header: Text("Instances")) {
|
||||||
|
ForEach(instances) { instance in
|
||||||
|
AccountsNavigationLink(instance: instance)
|
||||||
|
}
|
||||||
|
addInstanceButton
|
||||||
|
}
|
||||||
|
|
||||||
BrowsingSettings()
|
BrowsingSettings()
|
||||||
PlaybackSettings()
|
PlaybackSettings()
|
||||||
ServicesSettings()
|
ServicesSettings()
|
||||||
@ -76,7 +87,7 @@ struct SettingsView: View {
|
|||||||
ToolbarItem(placement: .navigationBarTrailing) {
|
ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
Button("Done") {
|
Button("Done") {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
#endif
|
#endif
|
||||||
@ -87,11 +98,20 @@ struct SettingsView: View {
|
|||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $presentingInstanceForm) {
|
||||||
|
InstanceForm(savedInstanceID: $savedFormInstanceID)
|
||||||
|
}
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.background(.black)
|
.background(Color.black)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var addInstanceButton: some View {
|
||||||
|
Button("Add Instance...") {
|
||||||
|
presentingInstanceForm = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SettingsView_Previews: PreviewProvider {
|
struct SettingsView_Previews: PreviewProvider {
|
||||||
|
@ -9,51 +9,34 @@ struct TrendingCountry: View {
|
|||||||
@State private var query: String = ""
|
@State private var query: String = ""
|
||||||
@State private var selection: Country?
|
@State private var selection: Country?
|
||||||
|
|
||||||
@FocusState var countryIsFocused
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
#if os(macOS)
|
#if !os(tvOS)
|
||||||
HStack {
|
HStack {
|
||||||
TextField("Country", text: $query, prompt: Text(TrendingCountry.prompt))
|
if #available(iOS 15.0, macOS 12.0, *) {
|
||||||
.focused($countryIsFocused)
|
TextField("Country", text: $query, prompt: Text(TrendingCountry.prompt))
|
||||||
|
} else {
|
||||||
|
TextField(TrendingCountry.prompt, text: $query)
|
||||||
|
}
|
||||||
|
|
||||||
Button("Done") { selectCountryAndDismiss() }
|
Button("Done") { selectCountryAndDismiss() }
|
||||||
.keyboardShortcut(.defaultAction)
|
.keyboardShortcut(.defaultAction)
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
}
|
}
|
||||||
.padding([.horizontal, .top])
|
.padding([.horizontal, .top])
|
||||||
|
|
||||||
countriesList
|
|
||||||
#else
|
|
||||||
NavigationView {
|
|
||||||
countriesList
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItemGroup(placement: .navigationBarLeading) {
|
|
||||||
Button("Done") { selectCountryAndDismiss() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if os(iOS)
|
|
||||||
.navigationBarTitle("Trending Country", displayMode: .automatic)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
countriesList
|
||||||
}
|
}
|
||||||
.onAppear {
|
|
||||||
countryIsFocused = true
|
|
||||||
}
|
|
||||||
.onSubmit { selectCountryAndDismiss() }
|
|
||||||
#if !os(macOS)
|
|
||||||
.searchable(text: $query, placement: searchPlacement, prompt: Text(TrendingCountry.prompt))
|
|
||||||
#endif
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.background(.thinMaterial)
|
.searchable(text: $query, placement: .automatic, prompt: Text(TrendingCountry.prompt))
|
||||||
|
.background(Color.black)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var countriesList: some View {
|
var countriesList: some View {
|
||||||
ScrollViewReader { _ in
|
let list = ScrollViewReader { _ in
|
||||||
List(store.collection, selection: $selection) { country in
|
List(store.collection, selection: $selection) { country in
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
Text(country.name)
|
Text(country.name)
|
||||||
@ -71,29 +54,29 @@ struct TrendingCountry: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
return Group {
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
#if os(macOS)
|
||||||
.padding(.bottom, 5)
|
if #available(macOS 12.0, *) {
|
||||||
|
list
|
||||||
#endif
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
}
|
} else {
|
||||||
|
list
|
||||||
#if !os(macOS)
|
}
|
||||||
var searchPlacement: SearchFieldPlacement {
|
|
||||||
#if os(iOS)
|
|
||||||
.navigationBarDrawer(displayMode: .always)
|
|
||||||
#else
|
#else
|
||||||
.automatic
|
list
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#if os(macOS)
|
||||||
|
.padding(.bottom, 5)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
func selectCountryAndDismiss(_ country: Country? = nil) {
|
func selectCountryAndDismiss(_ country: Country? = nil) {
|
||||||
if let selected = country ?? selection {
|
if let selected = country ?? selection {
|
||||||
selectedCountry = selected
|
selectedCountry = selected
|
||||||
}
|
}
|
||||||
|
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +172,12 @@ struct TrendingView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
Picker("Category", selection: $category) {
|
Picker(category.controlLabel, selection: $category) {
|
||||||
ForEach(TrendingCategory.allCases) { category in
|
ForEach(TrendingCategory.allCases) { category in
|
||||||
Text(category.controlLabel).tag(category)
|
Text(category.controlLabel).tag(category)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.pickerStyle(.menu)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ struct VerticalCells: View {
|
|||||||
}
|
}
|
||||||
.edgesIgnoringSafeArea(.horizontal)
|
.edgesIgnoringSafeArea(.horizontal)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.background()
|
.background(Color.tertiaryBackground)
|
||||||
.frame(minWidth: 360)
|
.frame(minWidth: 360)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ struct VideoCell: View {
|
|||||||
@Environment(\.horizontalCells) private var horizontalCells
|
@Environment(\.horizontalCells) private var horizontalCells
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@EnvironmentObject<PlayerModel> private var player
|
||||||
@EnvironmentObject<ThumbnailsModel> private var thumbnails
|
@EnvironmentObject<ThumbnailsModel> private var thumbnails
|
||||||
|
|
||||||
@ -38,7 +39,13 @@ struct VideoCell: View {
|
|||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.contentShape(RoundedRectangle(cornerRadius: 12))
|
.contentShape(RoundedRectangle(cornerRadius: 12))
|
||||||
.contextMenu { VideoContextMenuView(video: video, playerNavigationLinkActive: $player.playerNavigationLinkActive) }
|
.contextMenu {
|
||||||
|
VideoContextMenuView(
|
||||||
|
video: video,
|
||||||
|
playerNavigationLinkActive: $player.playerNavigationLinkActive
|
||||||
|
)
|
||||||
|
.environmentObject(accounts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var content: some View {
|
var content: some View {
|
||||||
@ -55,7 +62,7 @@ struct VideoCell: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.background()
|
.background(Color.tertiaryBackground)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ struct ChannelPlaylistView: View {
|
|||||||
.navigationTitle(playlist.title)
|
.navigationTitle(playlist.title)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
.background(.thickMaterial)
|
.background(Color.tertiaryBackground)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ struct ChannelVideosView: View {
|
|||||||
|
|
||||||
@StateObject private var store = Store<Channel>()
|
@StateObject private var store = Store<Channel>()
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
@Environment(\.inNavigationView) private var inNavigationView
|
@Environment(\.inNavigationView) private var inNavigationView
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -43,7 +43,7 @@ struct ChannelVideosView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var content: some View {
|
var content: some View {
|
||||||
VStack {
|
let content = VStack {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
HStack {
|
HStack {
|
||||||
Text(navigationTitle)
|
Text(navigationTitle)
|
||||||
@ -65,40 +65,43 @@ struct ChannelVideosView: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VerticalCells(items: videos)
|
#if os(iOS)
|
||||||
|
VerticalCells(items: videos)
|
||||||
#if !os(iOS)
|
#else
|
||||||
.prefersDefaultFocus(in: focusNamespace)
|
if #available(macOS 12.0, *) {
|
||||||
|
VerticalCells(items: videos)
|
||||||
|
.prefersDefaultFocus(in: focusNamespace)
|
||||||
|
} else {
|
||||||
|
VerticalCells(items: videos)
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.environment(\.inChannelView, true)
|
.environment(\.inChannelView, true)
|
||||||
#if !os(iOS)
|
|
||||||
.focusScope(focusNamespace)
|
|
||||||
#endif
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .navigation) {
|
ToolbarItem(placement: .navigation) {
|
||||||
ShareButton(
|
ShareButton(
|
||||||
contentItem: contentItem,
|
contentItem: contentItem,
|
||||||
presentingShareSheet: $presentingShareSheet,
|
presentingShareSheet: $presentingShareSheet,
|
||||||
shareURL: $shareURL
|
shareURL: $shareURL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolbarItem {
|
ToolbarItem {
|
||||||
HStack {
|
HStack {
|
||||||
Text("**\(store.item?.subscriptionsString ?? "loading")** subscribers")
|
Text("**\(store.item?.subscriptionsString ?? "loading")** subscribers")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.opacity(store.item?.subscriptionsString != nil ? 1 : 0)
|
.opacity(store.item?.subscriptionsString != nil ? 1 : 0)
|
||||||
|
|
||||||
subscriptionToggleButton
|
subscriptionToggleButton
|
||||||
|
|
||||||
FavoriteButton(item: FavoriteItem(section: .channel(channel.id, channel.name)))
|
FavoriteButton(item: FavoriteItem(section: .channel(channel.id, channel.name)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
.background(.thickMaterial)
|
.background(Color.tertiaryBackground)
|
||||||
#endif
|
#endif
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.sheet(isPresented: $presentingShareSheet) {
|
.sheet(isPresented: $presentingShareSheet) {
|
||||||
@ -107,7 +110,6 @@ struct ChannelVideosView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
.modifier(UnsubscribeAlertModifier())
|
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if store.item.isNil {
|
if store.item.isNil {
|
||||||
resource.addObserver(store)
|
resource.addObserver(store)
|
||||||
@ -115,6 +117,17 @@ struct ChannelVideosView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(navigationTitle)
|
.navigationTitle(navigationTitle)
|
||||||
|
|
||||||
|
return Group {
|
||||||
|
if #available(macOS 12.0, *) {
|
||||||
|
content
|
||||||
|
#if !os(iOS)
|
||||||
|
.focusScope(focusNamespace)
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var resource: Resource {
|
private var resource: Resource {
|
||||||
|
@ -26,8 +26,13 @@ struct DetailBadge: View {
|
|||||||
|
|
||||||
struct DefaultStyleModifier: ViewModifier {
|
struct DefaultStyleModifier: ViewModifier {
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
content
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
.background(.thinMaterial)
|
content
|
||||||
|
.background(.thinMaterial)
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
.background(Color.background)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct OpenSettingsButton: View {
|
struct OpenSettingsButton: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@EnvironmentObject<NavigationModel> private var navigation
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
let button = Button {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
|
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
|
||||||
@ -19,7 +19,13 @@ struct OpenSettingsButton: View {
|
|||||||
} label: {
|
} label: {
|
||||||
Label("Open Settings", systemImage: "gearshape.2")
|
Label("Open Settings", systemImage: "gearshape.2")
|
||||||
}
|
}
|
||||||
.buttonStyle(.borderedProminent)
|
|
||||||
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
|
button
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
|
} else {
|
||||||
|
button
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ struct PlayerControlsView<Content: View>: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var controls: some View {
|
private var controls: some View {
|
||||||
HStack {
|
let controls = HStack {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
model.presentingPlayer.toggle()
|
model.presentingPlayer.toggle()
|
||||||
}) {
|
}) {
|
||||||
@ -92,14 +92,23 @@ struct PlayerControlsView<Content: View>: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 55)
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 55)
|
||||||
.padding(.vertical, 0)
|
.padding(.vertical, 0)
|
||||||
.background(.ultraThinMaterial)
|
.borderTop(height: 0.4, color: Color("ControlsBorderColor"))
|
||||||
.borderTop(height: 0.4, color: Color("PlayerControlsBorderColor"))
|
.borderBottom(height: navigationStyle == .sidebar ? 0 : 0.4, color: Color("ControlsBorderColor"))
|
||||||
.borderBottom(height: navigationStyle == .sidebar ? 0 : 0.4, color: Color("PlayerControlsBorderColor"))
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.onSwipeGesture(up: {
|
.onSwipeGesture(up: {
|
||||||
model.presentingPlayer = true
|
model.presentingPlayer = true
|
||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return Group {
|
||||||
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
|
controls
|
||||||
|
.background(Material.ultraThinMaterial)
|
||||||
|
} else {
|
||||||
|
controls
|
||||||
|
.background(Color.tertiaryBackground)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var appVersion: String {
|
private var appVersion: String {
|
||||||
|
@ -31,9 +31,6 @@ struct SubscriptionsView: View {
|
|||||||
FavoriteButton(item: FavoriteItem(section: .subscriptions))
|
FavoriteButton(item: FavoriteItem(section: .subscriptions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.refreshable {
|
|
||||||
loadResources(force: true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func loadResources(force: Bool = false) {
|
fileprivate func loadResources(force: Bool = false) {
|
||||||
|
@ -113,7 +113,7 @@ struct VideoContextMenuView: View {
|
|||||||
private var subscriptionButton: some View {
|
private var subscriptionButton: some View {
|
||||||
Group {
|
Group {
|
||||||
if subscriptions.isSubscribing(video.channel.id) {
|
if subscriptions.isSubscribing(video.channel.id) {
|
||||||
Button(role: .destructive) {
|
Button {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
subscriptions.unsubscribe(video.channel.id)
|
subscriptions.unsubscribe(video.channel.id)
|
||||||
#else
|
#else
|
||||||
@ -143,7 +143,7 @@ struct VideoContextMenuView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeFromPlaylistButton(playlistID: String) -> some View {
|
func removeFromPlaylistButton(playlistID: String) -> some View {
|
||||||
Button(role: .destructive) {
|
Button {
|
||||||
playlists.removeVideo(videoIndexID: video.indexID!, playlistID: playlistID)
|
playlists.removeVideo(videoIndexID: video.indexID!, playlistID: playlistID)
|
||||||
} label: {
|
} label: {
|
||||||
Label("Remove from playlist", systemImage: "text.badge.minus")
|
Label("Remove from playlist", systemImage: "text.badge.minus")
|
||||||
|
@ -2,14 +2,14 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct WelcomeScreen: View {
|
struct WelcomeScreen: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
|
|
||||||
@Default(.accounts) private var allAccounts
|
@Default(.accounts) private var allAccounts
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
let welcomeScreen = VStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("Welcome")
|
Text("Welcome")
|
||||||
@ -26,7 +26,7 @@ struct WelcomeScreen: View {
|
|||||||
AccountSelectionView(showHeader: false)
|
AccountSelectionView(showHeader: false)
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
} label: {
|
} label: {
|
||||||
Text("Start")
|
Text("Start")
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ struct WelcomeScreen: View {
|
|||||||
#else
|
#else
|
||||||
AccountsMenuView()
|
AccountsMenuView()
|
||||||
.onChange(of: accounts.current) { _ in
|
.onChange(of: accounts.current) { _ in
|
||||||
dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.frame(maxWidth: 280)
|
.frame(maxWidth: 280)
|
||||||
@ -50,10 +50,16 @@ struct WelcomeScreen: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.interactiveDismissDisabled()
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.frame(minWidth: 400, minHeight: 400)
|
.frame(minWidth: 400, minHeight: 400)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||||
|
welcomeScreen
|
||||||
|
.interactiveDismissDisabled()
|
||||||
|
} else {
|
||||||
|
welcomeScreen
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,8 @@
|
|||||||
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
|
3722AEBC274DA396005EA4D6 /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
||||||
|
3722AEBE274DA401005EA4D6 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||||
3729037E2739E47400EA99F6 /* MenuCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3729037D2739E47400EA99F6 /* MenuCommands.swift */; };
|
3729037E2739E47400EA99F6 /* MenuCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3729037D2739E47400EA99F6 /* MenuCommands.swift */; };
|
||||||
3729037F2739E47400EA99F6 /* MenuCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3729037D2739E47400EA99F6 /* MenuCommands.swift */; };
|
3729037F2739E47400EA99F6 /* MenuCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3729037D2739E47400EA99F6 /* MenuCommands.swift */; };
|
||||||
372915E42687E33E00F5A35B /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 372915E32687E33E00F5A35B /* Defaults */; };
|
372915E42687E33E00F5A35B /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 372915E32687E33E00F5A35B /* Defaults */; };
|
||||||
@ -110,6 +112,8 @@
|
|||||||
3743CA52270F284F00E4D32B /* View+Borders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743CA51270F284F00E4D32B /* View+Borders.swift */; };
|
3743CA52270F284F00E4D32B /* View+Borders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743CA51270F284F00E4D32B /* View+Borders.swift */; };
|
||||||
3743CA53270F284F00E4D32B /* View+Borders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743CA51270F284F00E4D32B /* View+Borders.swift */; };
|
3743CA53270F284F00E4D32B /* View+Borders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743CA51270F284F00E4D32B /* View+Borders.swift */; };
|
||||||
3743CA54270F284F00E4D32B /* View+Borders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743CA51270F284F00E4D32B /* View+Borders.swift */; };
|
3743CA54270F284F00E4D32B /* View+Borders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743CA51270F284F00E4D32B /* View+Borders.swift */; };
|
||||||
|
374710052755291C00CE0F87 /* SearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374710042755291C00CE0F87 /* SearchField.swift */; };
|
||||||
|
374710062755291C00CE0F87 /* SearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374710042755291C00CE0F87 /* SearchField.swift */; };
|
||||||
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
||||||
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
||||||
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186526A7627F0084E870 /* Video+Fixtures.swift */; };
|
||||||
@ -122,16 +126,14 @@
|
|||||||
37484C1926FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
37484C1926FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
||||||
37484C1A26FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
37484C1A26FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
||||||
37484C1B26FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
37484C1B26FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
||||||
37484C1D26FC83A400287258 /* InstancesSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1C26FC83A400287258 /* InstancesSettings.swift */; };
|
|
||||||
37484C1F26FC83A400287258 /* InstancesSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1C26FC83A400287258 /* InstancesSettings.swift */; };
|
|
||||||
37484C2526FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
37484C2526FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
||||||
37484C2626FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
37484C2626FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
||||||
37484C2726FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
37484C2726FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
||||||
37484C2926FC83FF00287258 /* AccountForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2826FC83FF00287258 /* AccountForm.swift */; };
|
37484C2926FC83FF00287258 /* AccountForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2826FC83FF00287258 /* AccountForm.swift */; };
|
||||||
37484C2A26FC83FF00287258 /* AccountForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2826FC83FF00287258 /* AccountForm.swift */; };
|
37484C2A26FC83FF00287258 /* AccountForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2826FC83FF00287258 /* AccountForm.swift */; };
|
||||||
37484C2B26FC83FF00287258 /* AccountForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2826FC83FF00287258 /* AccountForm.swift */; };
|
37484C2B26FC83FF00287258 /* AccountForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2826FC83FF00287258 /* AccountForm.swift */; };
|
||||||
37484C2D26FC844700287258 /* AccountsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2C26FC844700287258 /* AccountsSettings.swift */; };
|
37484C2D26FC844700287258 /* InstanceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2C26FC844700287258 /* InstanceSettings.swift */; };
|
||||||
37484C2F26FC844700287258 /* AccountsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2C26FC844700287258 /* AccountsSettings.swift */; };
|
37484C2F26FC844700287258 /* InstanceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2C26FC844700287258 /* InstanceSettings.swift */; };
|
||||||
37484C3126FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
37484C3126FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
||||||
37484C3226FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
37484C3226FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
||||||
37484C3326FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
37484C3326FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
||||||
@ -164,9 +166,6 @@
|
|||||||
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
|
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
|
||||||
3761ABFE26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
|
3761ABFE26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
|
||||||
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
|
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
|
||||||
3761AC0F26F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */; };
|
|
||||||
3761AC1026F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */; };
|
|
||||||
3761AC1126F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */; };
|
|
||||||
3763495126DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; };
|
3763495126DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; };
|
||||||
3763495226DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; };
|
3763495226DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; };
|
||||||
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578842685429C00D4EA09 /* CaseIterable+Next.swift */; };
|
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578842685429C00D4EA09 /* CaseIterable+Next.swift */; };
|
||||||
@ -269,12 +268,29 @@
|
|||||||
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
||||||
377FC7ED267A0A0800A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7EC267A0A0800A6BBAF /* SwiftyJSON */; };
|
377FC7ED267A0A0800A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7EC267A0A0800A6BBAF /* SwiftyJSON */; };
|
||||||
377FC7F3267A0A0800A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7F2267A0A0800A6BBAF /* Logging */; };
|
377FC7F3267A0A0800A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7F2267A0A0800A6BBAF /* Logging */; };
|
||||||
|
3782B94F27553A6700990149 /* SearchSuggestions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3782B94E27553A6700990149 /* SearchSuggestions.swift */; };
|
||||||
|
3782B95027553A6700990149 /* SearchSuggestions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3782B94E27553A6700990149 /* SearchSuggestions.swift */; };
|
||||||
|
3782B9522755667600990149 /* String+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3782B9512755667600990149 /* String+Format.swift */; };
|
||||||
|
3782B9532755667600990149 /* String+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3782B9512755667600990149 /* String+Format.swift */; };
|
||||||
|
3782B9542755667600990149 /* String+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3782B9512755667600990149 /* String+Format.swift */; };
|
||||||
|
3782B95627557E4E00990149 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
||||||
|
3782B95727557E6E00990149 /* SearchSuggestions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3782B94E27553A6700990149 /* SearchSuggestions.swift */; };
|
||||||
|
3782B95E2755858100990149 /* NSTextField+FocusRingType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3782B95C2755858100990149 /* NSTextField+FocusRingType.swift */; };
|
||||||
3784B23B272894DA00B09468 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23A272894DA00B09468 /* ShareSheet.swift */; };
|
3784B23B272894DA00B09468 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23A272894DA00B09468 /* ShareSheet.swift */; };
|
||||||
3784B23D2728B85300B09468 /* ShareButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23C2728B85300B09468 /* ShareButton.swift */; };
|
3784B23D2728B85300B09468 /* ShareButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23C2728B85300B09468 /* ShareButton.swift */; };
|
||||||
3784B23E2728B85300B09468 /* ShareButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23C2728B85300B09468 /* ShareButton.swift */; };
|
3784B23E2728B85300B09468 /* ShareButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23C2728B85300B09468 /* ShareButton.swift */; };
|
||||||
3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
||||||
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
||||||
3788AC2926F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
3788AC2926F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
||||||
|
378AE93A274EDFAF006A4EE1 /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
||||||
|
378AE93C274EDFB2006A4EE1 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||||
|
378AE93D274EDFB3006A4EE1 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||||
|
378AE93E274EDFB4006A4EE1 /* Tint+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */; };
|
||||||
|
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */; };
|
||||||
|
378AE940274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */; };
|
||||||
|
378AE943274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
||||||
|
378AE944274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
||||||
|
378AE945274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
||||||
378E50FB26FE8B9F00F49626 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378E50FA26FE8B9F00F49626 /* Instance.swift */; };
|
378E50FB26FE8B9F00F49626 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378E50FA26FE8B9F00F49626 /* Instance.swift */; };
|
||||||
378E50FC26FE8B9F00F49626 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378E50FA26FE8B9F00F49626 /* Instance.swift */; };
|
378E50FC26FE8B9F00F49626 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378E50FA26FE8B9F00F49626 /* Instance.swift */; };
|
||||||
378E50FD26FE8B9F00F49626 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378E50FA26FE8B9F00F49626 /* Instance.swift */; };
|
378E50FD26FE8B9F00F49626 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378E50FA26FE8B9F00F49626 /* Instance.swift */; };
|
||||||
@ -294,8 +310,6 @@
|
|||||||
37A3B15F27255E7F000FB5EE /* images in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B15E27255E7F000FB5EE /* images */; };
|
37A3B15F27255E7F000FB5EE /* images in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B15E27255E7F000FB5EE /* images */; };
|
||||||
37A3B16127255E7F000FB5EE /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16027255E7F000FB5EE /* manifest.json */; };
|
37A3B16127255E7F000FB5EE /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16027255E7F000FB5EE /* manifest.json */; };
|
||||||
37A3B16527255E7F000FB5EE /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16427255E7F000FB5EE /* content.js */; };
|
37A3B16527255E7F000FB5EE /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16427255E7F000FB5EE /* content.js */; };
|
||||||
37A3B17027255E7F000FB5EE /* Open in Yattee (macOS).appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 37A3B15727255E7F000FB5EE /* Open in Yattee (macOS).appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
|
||||||
37A3B18F2725735F000FB5EE /* Open in Yattee (iOS).appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 37A3B1792725735F000FB5EE /* Open in Yattee (iOS).appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
|
||||||
37A3B194272574FB000FB5EE /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A3B15927255E7F000FB5EE /* SafariWebExtensionHandler.swift */; };
|
37A3B194272574FB000FB5EE /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A3B15927255E7F000FB5EE /* SafariWebExtensionHandler.swift */; };
|
||||||
37A3B19627257503000FB5EE /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16427255E7F000FB5EE /* content.js */; };
|
37A3B19627257503000FB5EE /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16427255E7F000FB5EE /* content.js */; };
|
||||||
37A3B1982725750B000FB5EE /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16027255E7F000FB5EE /* manifest.json */; };
|
37A3B1982725750B000FB5EE /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = 37A3B16027255E7F000FB5EE /* manifest.json */; };
|
||||||
@ -307,7 +321,6 @@
|
|||||||
37A9965F26D6F9B9006E3224 /* FavoritesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965D26D6F9B9006E3224 /* FavoritesView.swift */; };
|
37A9965F26D6F9B9006E3224 /* FavoritesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965D26D6F9B9006E3224 /* FavoritesView.swift */; };
|
||||||
37A9966026D6F9B9006E3224 /* FavoritesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965D26D6F9B9006E3224 /* FavoritesView.swift */; };
|
37A9966026D6F9B9006E3224 /* FavoritesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965D26D6F9B9006E3224 /* FavoritesView.swift */; };
|
||||||
37AAF27E26737323007FC770 /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
|
37AAF27E26737323007FC770 /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
|
||||||
37AAF28026737550007FC770 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
|
||||||
37AAF29026740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
37AAF29026740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
||||||
37AAF29126740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
37AAF29126740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
||||||
37AAF29226740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
37AAF29226740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
||||||
@ -452,6 +465,8 @@
|
|||||||
37DD87C7271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
|
37DD87C7271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
|
||||||
37DD87C8271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
|
37DD87C8271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
|
||||||
37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
|
37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
|
||||||
|
37E084AC2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */; };
|
||||||
|
37E084AD2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */; };
|
||||||
37E2EEAB270656EC00170416 /* PlayerControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E2EEAA270656EC00170416 /* PlayerControlsView.swift */; };
|
37E2EEAB270656EC00170416 /* PlayerControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E2EEAA270656EC00170416 /* PlayerControlsView.swift */; };
|
||||||
37E2EEAC270656EC00170416 /* PlayerControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E2EEAA270656EC00170416 /* PlayerControlsView.swift */; };
|
37E2EEAC270656EC00170416 /* PlayerControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E2EEAA270656EC00170416 /* PlayerControlsView.swift */; };
|
||||||
37E2EEAD270656EC00170416 /* PlayerControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E2EEAA270656EC00170416 /* PlayerControlsView.swift */; };
|
37E2EEAD270656EC00170416 /* PlayerControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E2EEAA270656EC00170416 /* PlayerControlsView.swift */; };
|
||||||
@ -510,20 +525,6 @@
|
|||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
37A3B16E27255E7F000FB5EE /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = 37D4B0BD2671614700C925CA /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = 37A3B15627255E7F000FB5EE;
|
|
||||||
remoteInfo = "Open in Yattee";
|
|
||||||
};
|
|
||||||
37A3B18D2725735F000FB5EE /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = 37D4B0BD2671614700C925CA /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = 37A3B1782725735F000FB5EE;
|
|
||||||
remoteInfo = "Open in Yattee";
|
|
||||||
};
|
|
||||||
37D4B0D52671614900C925CA /* PBXContainerItemProxy */ = {
|
37D4B0D52671614900C925CA /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 37D4B0BD2671614700C925CA /* Project object */;
|
containerPortal = 37D4B0BD2671614700C925CA /* Project object */;
|
||||||
@ -547,31 +548,6 @@
|
|||||||
};
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
37A3B17127255E7F000FB5EE /* Embed App Extensions */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 13;
|
|
||||||
files = (
|
|
||||||
37A3B17027255E7F000FB5EE /* Open in Yattee (macOS).appex in Embed App Extensions */,
|
|
||||||
);
|
|
||||||
name = "Embed App Extensions";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
37A3B1932725735F000FB5EE /* Embed App Extensions */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 13;
|
|
||||||
files = (
|
|
||||||
37A3B18F2725735F000FB5EE /* Open in Yattee (iOS).appex in Embed App Extensions */,
|
|
||||||
);
|
|
||||||
name = "Embed App Extensions";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
3700155A271B0D4D0049C794 /* PipedAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipedAPI.swift; sourceTree = "<group>"; };
|
3700155A271B0D4D0049C794 /* PipedAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipedAPI.swift; sourceTree = "<group>"; };
|
||||||
3700155E271B12DD0049C794 /* SiestaConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiestaConfiguration.swift; sourceTree = "<group>"; };
|
3700155E271B12DD0049C794 /* SiestaConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiestaConfiguration.swift; sourceTree = "<group>"; };
|
||||||
@ -585,6 +561,9 @@
|
|||||||
37169AA12729D98A0011DE61 /* InstancesBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesBridge.swift; sourceTree = "<group>"; };
|
37169AA12729D98A0011DE61 /* InstancesBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesBridge.swift; sourceTree = "<group>"; };
|
||||||
37169AA52729E2CC0011DE61 /* AccountsBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsBridge.swift; sourceTree = "<group>"; };
|
37169AA52729E2CC0011DE61 /* AccountsBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsBridge.swift; sourceTree = "<group>"; };
|
||||||
371F2F19269B43D300E4A7AB /* NavigationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModel.swift; sourceTree = "<group>"; };
|
371F2F19269B43D300E4A7AB /* NavigationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModel.swift; sourceTree = "<group>"; };
|
||||||
|
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Badge+Backport.swift"; sourceTree = "<group>"; };
|
||||||
|
3722AEBD274DA401005EA4D6 /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
||||||
|
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tint+Backport.swift"; sourceTree = "<group>"; };
|
||||||
3729037D2739E47400EA99F6 /* MenuCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuCommands.swift; sourceTree = "<group>"; };
|
3729037D2739E47400EA99F6 /* MenuCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuCommands.swift; sourceTree = "<group>"; };
|
||||||
372915E52687E3B900F5A35B /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
|
372915E52687E3B900F5A35B /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
|
||||||
3730D89F2712E2B70020ED53 /* NowPlayingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingView.swift; sourceTree = "<group>"; };
|
3730D89F2712E2B70020ED53 /* NowPlayingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingView.swift; sourceTree = "<group>"; };
|
||||||
@ -598,14 +577,14 @@
|
|||||||
3743B86727216D3600261544 /* ChannelCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelCell.swift; sourceTree = "<group>"; };
|
3743B86727216D3600261544 /* ChannelCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelCell.swift; sourceTree = "<group>"; };
|
||||||
3743CA4D270EFE3400E4D32B /* PlayerQueueRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerQueueRow.swift; sourceTree = "<group>"; };
|
3743CA4D270EFE3400E4D32B /* PlayerQueueRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerQueueRow.swift; sourceTree = "<group>"; };
|
||||||
3743CA51270F284F00E4D32B /* View+Borders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Borders.swift"; sourceTree = "<group>"; };
|
3743CA51270F284F00E4D32B /* View+Borders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Borders.swift"; sourceTree = "<group>"; };
|
||||||
|
374710042755291C00CE0F87 /* SearchField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchField.swift; sourceTree = "<group>"; };
|
||||||
3748186526A7627F0084E870 /* Video+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Video+Fixtures.swift"; sourceTree = "<group>"; };
|
3748186526A7627F0084E870 /* Video+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Video+Fixtures.swift"; sourceTree = "<group>"; };
|
||||||
3748186926A764FB0084E870 /* Thumbnail+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thumbnail+Fixtures.swift"; sourceTree = "<group>"; };
|
3748186926A764FB0084E870 /* Thumbnail+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thumbnail+Fixtures.swift"; sourceTree = "<group>"; };
|
||||||
3748186D26A769D60084E870 /* DetailBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBadge.swift; sourceTree = "<group>"; };
|
3748186D26A769D60084E870 /* DetailBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBadge.swift; sourceTree = "<group>"; };
|
||||||
37484C1826FC837400287258 /* PlaybackSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackSettings.swift; sourceTree = "<group>"; };
|
37484C1826FC837400287258 /* PlaybackSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackSettings.swift; sourceTree = "<group>"; };
|
||||||
37484C1C26FC83A400287258 /* InstancesSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesSettings.swift; sourceTree = "<group>"; };
|
|
||||||
37484C2426FC83E000287258 /* InstanceForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceForm.swift; sourceTree = "<group>"; };
|
37484C2426FC83E000287258 /* InstanceForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceForm.swift; sourceTree = "<group>"; };
|
||||||
37484C2826FC83FF00287258 /* AccountForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountForm.swift; sourceTree = "<group>"; };
|
37484C2826FC83FF00287258 /* AccountForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountForm.swift; sourceTree = "<group>"; };
|
||||||
37484C2C26FC844700287258 /* AccountsSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsSettings.swift; sourceTree = "<group>"; };
|
37484C2C26FC844700287258 /* InstanceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceSettings.swift; sourceTree = "<group>"; };
|
||||||
37484C3026FCB8F900287258 /* AccountValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidator.swift; sourceTree = "<group>"; };
|
37484C3026FCB8F900287258 /* AccountValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidator.swift; sourceTree = "<group>"; };
|
||||||
374C053427242D9F009BDDBE /* ServicesSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesSettings.swift; sourceTree = "<group>"; };
|
374C053427242D9F009BDDBE /* ServicesSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesSettings.swift; sourceTree = "<group>"; };
|
||||||
374C053A2724614F009BDDBE /* PlayerTVMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTVMenu.swift; sourceTree = "<group>"; };
|
374C053A2724614F009BDDBE /* PlayerTVMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTVMenu.swift; sourceTree = "<group>"; };
|
||||||
@ -618,7 +597,6 @@
|
|||||||
37599F37272B4D740087F250 /* FavoriteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteButton.swift; sourceTree = "<group>"; };
|
37599F37272B4D740087F250 /* FavoriteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteButton.swift; sourceTree = "<group>"; };
|
||||||
375DFB5726F9DA010013F468 /* InstancesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesModel.swift; sourceTree = "<group>"; };
|
375DFB5726F9DA010013F468 /* InstancesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesModel.swift; sourceTree = "<group>"; };
|
||||||
3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentValues.swift; sourceTree = "<group>"; };
|
3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentValues.swift; sourceTree = "<group>"; };
|
||||||
3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnsubscribeAlertModifier.swift; sourceTree = "<group>"; };
|
|
||||||
3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarRecents.swift; sourceTree = "<group>"; };
|
3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarRecents.swift; sourceTree = "<group>"; };
|
||||||
376578842685429C00D4EA09 /* CaseIterable+Next.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CaseIterable+Next.swift"; sourceTree = "<group>"; };
|
376578842685429C00D4EA09 /* CaseIterable+Next.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CaseIterable+Next.swift"; sourceTree = "<group>"; };
|
||||||
376578882685471400D4EA09 /* Playlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Playlist.swift; sourceTree = "<group>"; };
|
376578882685471400D4EA09 /* Playlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Playlist.swift; sourceTree = "<group>"; };
|
||||||
@ -634,9 +612,13 @@
|
|||||||
37732FF32703D32400F04329 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = "<group>"; };
|
37732FF32703D32400F04329 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = "<group>"; };
|
||||||
3774122927387B6C00423605 /* InstancesModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesModelTests.swift; sourceTree = "<group>"; };
|
3774122927387B6C00423605 /* InstancesModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesModelTests.swift; sourceTree = "<group>"; };
|
||||||
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = "<group>"; };
|
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = "<group>"; };
|
||||||
|
3782B94E27553A6700990149 /* SearchSuggestions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSuggestions.swift; sourceTree = "<group>"; };
|
||||||
|
3782B9512755667600990149 /* String+Format.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Format.swift"; sourceTree = "<group>"; };
|
||||||
|
3782B95C2755858100990149 /* NSTextField+FocusRingType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextField+FocusRingType.swift"; sourceTree = "<group>"; };
|
||||||
3784B23A272894DA00B09468 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
|
3784B23A272894DA00B09468 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
|
||||||
3784B23C2728B85300B09468 /* ShareButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareButton.swift; sourceTree = "<group>"; };
|
3784B23C2728B85300B09468 /* ShareButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareButton.swift; sourceTree = "<group>"; };
|
||||||
3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteItemView.swift; sourceTree = "<group>"; };
|
3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteItemView.swift; sourceTree = "<group>"; };
|
||||||
|
378AE942274EF00A006A4EE1 /* Color+Background.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Background.swift"; sourceTree = "<group>"; };
|
||||||
378E50FA26FE8B9F00F49626 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = "<group>"; };
|
378E50FA26FE8B9F00F49626 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = "<group>"; };
|
||||||
378E50FE26FE8EEE00F49626 /* AccountsMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsMenuView.swift; sourceTree = "<group>"; };
|
378E50FE26FE8EEE00F49626 /* AccountsMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsMenuView.swift; sourceTree = "<group>"; };
|
||||||
37977582268922F600DD52A8 /* InvidiousAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvidiousAPI.swift; sourceTree = "<group>"; };
|
37977582268922F600DD52A8 /* InvidiousAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvidiousAPI.swift; sourceTree = "<group>"; };
|
||||||
@ -710,7 +692,7 @@
|
|||||||
37D4B0D82671614900C925CA /* Tests_iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_iOS.swift; sourceTree = "<group>"; };
|
37D4B0D82671614900C925CA /* Tests_iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_iOS.swift; sourceTree = "<group>"; };
|
||||||
37D4B0DE2671614900C925CA /* Tests (macOS).xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests (macOS).xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
37D4B0DE2671614900C925CA /* Tests (macOS).xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests (macOS).xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
37D4B0E22671614900C925CA /* Tests_macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_macOS.swift; sourceTree = "<group>"; };
|
37D4B0E22671614900C925CA /* Tests_macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_macOS.swift; sourceTree = "<group>"; };
|
||||||
37D4B158267164AE00C925CA /* Yattee (tvOS).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Yattee (tvOS).app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
37D4B158267164AE00C925CA /* Yattee.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Yattee.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
37D4B15E267164AF00C925CA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
37D4B15E267164AF00C925CA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
37D4B171267164B000C925CA /* Tests (tvOS).xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests (tvOS).xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
37D4B171267164B000C925CA /* Tests (tvOS).xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests (tvOS).xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
37D4B175267164B000C925CA /* YatteeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YatteeUITests.swift; sourceTree = "<group>"; };
|
37D4B175267164B000C925CA /* YatteeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YatteeUITests.swift; sourceTree = "<group>"; };
|
||||||
@ -721,6 +703,7 @@
|
|||||||
37D526E22720B4BE00ED2F5E /* View+SwipeGesture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+SwipeGesture.swift"; sourceTree = "<group>"; };
|
37D526E22720B4BE00ED2F5E /* View+SwipeGesture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+SwipeGesture.swift"; sourceTree = "<group>"; };
|
||||||
37D9169A27388A81002B1BAA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
37D9169A27388A81002B1BAA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStreams.swift; sourceTree = "<group>"; };
|
37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStreams.swift; sourceTree = "<group>"; };
|
||||||
|
37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsNavigationLink.swift; sourceTree = "<group>"; };
|
||||||
37E2EEAA270656EC00170416 /* PlayerControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerControlsView.swift; sourceTree = "<group>"; };
|
37E2EEAA270656EC00170416 /* PlayerControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerControlsView.swift; sourceTree = "<group>"; };
|
||||||
37E64DD026D597EB00C71877 /* SubscriptionsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsModel.swift; sourceTree = "<group>"; };
|
37E64DD026D597EB00C71877 /* SubscriptionsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsModel.swift; sourceTree = "<group>"; };
|
||||||
37E70922271CD43000D34DDE /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = "<group>"; };
|
37E70922271CD43000D34DDE /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = "<group>"; };
|
||||||
@ -909,7 +892,6 @@
|
|||||||
37E2EEAA270656EC00170416 /* PlayerControlsView.swift */,
|
37E2EEAA270656EC00170416 /* PlayerControlsView.swift */,
|
||||||
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */,
|
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */,
|
||||||
37AAF27D26737323007FC770 /* PopularView.swift */,
|
37AAF27D26737323007FC770 /* PopularView.swift */,
|
||||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
|
||||||
3784B23C2728B85300B09468 /* ShareButton.swift */,
|
3784B23C2728B85300B09468 /* ShareButton.swift */,
|
||||||
376B2E0626F920D600B1D64D /* SignInRequiredView.swift */,
|
376B2E0626F920D600B1D64D /* SignInRequiredView.swift */,
|
||||||
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
||||||
@ -919,6 +901,16 @@
|
|||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
3722AEBA274DA312005EA4D6 /* Backports */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3722AEBD274DA401005EA4D6 /* Backport.swift */,
|
||||||
|
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */,
|
||||||
|
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */,
|
||||||
|
);
|
||||||
|
path = Backports;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
3743B864272169E200261544 /* Applications */ = {
|
3743B864272169E200261544 /* Applications */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -976,11 +968,11 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
37484C2826FC83FF00287258 /* AccountForm.swift */,
|
37484C2826FC83FF00287258 /* AccountForm.swift */,
|
||||||
37484C2C26FC844700287258 /* AccountsSettings.swift */,
|
37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */,
|
||||||
37732FEF2703A26300F04329 /* AccountValidationStatus.swift */,
|
37732FEF2703A26300F04329 /* AccountValidationStatus.swift */,
|
||||||
376BE50A27349108009AD608 /* BrowsingSettings.swift */,
|
376BE50A27349108009AD608 /* BrowsingSettings.swift */,
|
||||||
37484C2426FC83E000287258 /* InstanceForm.swift */,
|
37484C2426FC83E000287258 /* InstanceForm.swift */,
|
||||||
37484C1C26FC83A400287258 /* InstancesSettings.swift */,
|
37484C2C26FC844700287258 /* InstanceSettings.swift */,
|
||||||
37484C1826FC837400287258 /* PlaybackSettings.swift */,
|
37484C1826FC837400287258 /* PlaybackSettings.swift */,
|
||||||
374C053427242D9F009BDDBE /* ServicesSettings.swift */,
|
374C053427242D9F009BDDBE /* ServicesSettings.swift */,
|
||||||
376BE50627347B57009AD608 /* SettingsHeader.swift */,
|
376BE50627347B57009AD608 /* SettingsHeader.swift */,
|
||||||
@ -1002,7 +994,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
37F64FE326FE70A60081B69E /* RedrawOnModifier.swift */,
|
37F64FE326FE70A60081B69E /* RedrawOnModifier.swift */,
|
||||||
3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */,
|
|
||||||
);
|
);
|
||||||
path = Modifiers;
|
path = Modifiers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1014,6 +1005,16 @@
|
|||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
3782B95527557A2400990149 /* Search */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
374710042755291C00CE0F87 /* SearchField.swift */,
|
||||||
|
3782B94E27553A6700990149 /* SearchSuggestions.swift */,
|
||||||
|
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||||
|
);
|
||||||
|
path = Search;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
3788AC2126F683AB00F6BAA9 /* Favorites */ = {
|
3788AC2126F683AB00F6BAA9 /* Favorites */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -1067,8 +1068,8 @@
|
|||||||
37BE0BD826A214500092E2DB /* macOS */ = {
|
37BE0BD826A214500092E2DB /* macOS */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
37FD43E1270472060073EE42 /* Settings */,
|
|
||||||
374C0542272496E4009BDDBE /* AppDelegate.swift */,
|
374C0542272496E4009BDDBE /* AppDelegate.swift */,
|
||||||
|
37FD43DB270470B70073EE42 /* InstancesSettings.swift */,
|
||||||
374108D0272B11B2006C5CC8 /* PictureInPictureDelegate.swift */,
|
374108D0272B11B2006C5CC8 /* PictureInPictureDelegate.swift */,
|
||||||
37BE0BDB26A2367F0092E2DB /* Player.swift */,
|
37BE0BDB26A2367F0092E2DB /* Player.swift */,
|
||||||
37BE0BD926A214630092E2DB /* PlayerViewController.swift */,
|
37BE0BD926A214630092E2DB /* PlayerViewController.swift */,
|
||||||
@ -1083,8 +1084,11 @@
|
|||||||
379775922689365600DD52A8 /* Array+Next.swift */,
|
379775922689365600DD52A8 /* Array+Next.swift */,
|
||||||
376578842685429C00D4EA09 /* CaseIterable+Next.swift */,
|
376578842685429C00D4EA09 /* CaseIterable+Next.swift */,
|
||||||
37C0697D2725C8D400F7F6CB /* CMTime+DefaultTimescale.swift */,
|
37C0697D2725C8D400F7F6CB /* CMTime+DefaultTimescale.swift */,
|
||||||
|
378AE942274EF00A006A4EE1 /* Color+Background.swift */,
|
||||||
37C3A240272359900087A57A /* Double+Format.swift */,
|
37C3A240272359900087A57A /* Double+Format.swift */,
|
||||||
37BA794E26DC3E0E002A0235 /* Int+Format.swift */,
|
37BA794E26DC3E0E002A0235 /* Int+Format.swift */,
|
||||||
|
3782B95C2755858100990149 /* NSTextField+FocusRingType.swift */,
|
||||||
|
3782B9512755667600990149 /* String+Format.swift */,
|
||||||
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */,
|
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */,
|
||||||
3743CA51270F284F00E4D32B /* View+Borders.swift */,
|
3743CA51270F284F00E4D32B /* View+Borders.swift */,
|
||||||
);
|
);
|
||||||
@ -1098,6 +1102,7 @@
|
|||||||
37BE0BD826A214500092E2DB /* macOS */,
|
37BE0BD826A214500092E2DB /* macOS */,
|
||||||
37D4B159267164AE00C925CA /* tvOS */,
|
37D4B159267164AE00C925CA /* tvOS */,
|
||||||
37D4B0C12671614700C925CA /* Shared */,
|
37D4B0C12671614700C925CA /* Shared */,
|
||||||
|
3722AEBA274DA312005EA4D6 /* Backports */,
|
||||||
37D4B1B72672CFE300C925CA /* Model */,
|
37D4B1B72672CFE300C925CA /* Model */,
|
||||||
37C7A9022679058300E721B4 /* Extensions */,
|
37C7A9022679058300E721B4 /* Extensions */,
|
||||||
3748186426A762300084E870 /* Fixtures */,
|
3748186426A762300084E870 /* Fixtures */,
|
||||||
@ -1120,6 +1125,7 @@
|
|||||||
371AAE2326CEB9E800901972 /* Navigation */,
|
371AAE2326CEB9E800901972 /* Navigation */,
|
||||||
371AAE2426CEBA4100901972 /* Player */,
|
371AAE2426CEBA4100901972 /* Player */,
|
||||||
371AAE2626CEBF1600901972 /* Playlists */,
|
371AAE2626CEBF1600901972 /* Playlists */,
|
||||||
|
3782B95527557A2400990149 /* Search */,
|
||||||
37484C1726FC836500287258 /* Settings */,
|
37484C1726FC836500287258 /* Settings */,
|
||||||
371AAE2526CEBF0B00901972 /* Trending */,
|
371AAE2526CEBF0B00901972 /* Trending */,
|
||||||
371AAE2726CEBF4700901972 /* Videos */,
|
371AAE2726CEBF4700901972 /* Videos */,
|
||||||
@ -1145,7 +1151,7 @@
|
|||||||
37D4B0CF2671614900C925CA /* Yattee.app */,
|
37D4B0CF2671614900C925CA /* Yattee.app */,
|
||||||
37D4B0D42671614900C925CA /* Tests (iOS).xctest */,
|
37D4B0D42671614900C925CA /* Tests (iOS).xctest */,
|
||||||
37D4B0DE2671614900C925CA /* Tests (macOS).xctest */,
|
37D4B0DE2671614900C925CA /* Tests (macOS).xctest */,
|
||||||
37D4B158267164AE00C925CA /* Yattee (tvOS).app */,
|
37D4B158267164AE00C925CA /* Yattee.app */,
|
||||||
37D4B171267164B000C925CA /* Tests (tvOS).xctest */,
|
37D4B171267164B000C925CA /* Tests (tvOS).xctest */,
|
||||||
37A3B15727255E7F000FB5EE /* Open in Yattee (macOS).appex */,
|
37A3B15727255E7F000FB5EE /* Open in Yattee (macOS).appex */,
|
||||||
37A3B1792725735F000FB5EE /* Open in Yattee (iOS).appex */,
|
37A3B1792725735F000FB5EE /* Open in Yattee (iOS).appex */,
|
||||||
@ -1242,14 +1248,6 @@
|
|||||||
path = Search;
|
path = Search;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
37FD43E1270472060073EE42 /* Settings */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
37FD43DB270470B70073EE42 /* InstancesSettings.swift */,
|
|
||||||
);
|
|
||||||
path = Settings;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -1295,12 +1293,10 @@
|
|||||||
37D4B0C52671614900C925CA /* Sources */,
|
37D4B0C52671614900C925CA /* Sources */,
|
||||||
37D4B0C62671614900C925CA /* Frameworks */,
|
37D4B0C62671614900C925CA /* Frameworks */,
|
||||||
37D4B0C72671614900C925CA /* Resources */,
|
37D4B0C72671614900C925CA /* Resources */,
|
||||||
37A3B1932725735F000FB5EE /* Embed App Extensions */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
37A3B18E2725735F000FB5EE /* PBXTargetDependency */,
|
|
||||||
);
|
);
|
||||||
name = "Yattee (iOS)";
|
name = "Yattee (iOS)";
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
@ -1327,12 +1323,10 @@
|
|||||||
37D4B0CB2671614900C925CA /* Sources */,
|
37D4B0CB2671614900C925CA /* Sources */,
|
||||||
37D4B0CC2671614900C925CA /* Frameworks */,
|
37D4B0CC2671614900C925CA /* Frameworks */,
|
||||||
37D4B0CD2671614900C925CA /* Resources */,
|
37D4B0CD2671614900C925CA /* Resources */,
|
||||||
37A3B17127255E7F000FB5EE /* Embed App Extensions */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
37A3B16F27255E7F000FB5EE /* PBXTargetDependency */,
|
|
||||||
);
|
);
|
||||||
name = "Yattee (macOS)";
|
name = "Yattee (macOS)";
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
@ -1419,7 +1413,7 @@
|
|||||||
3765917D27237D2A009F956E /* PINCache */,
|
3765917D27237D2A009F956E /* PINCache */,
|
||||||
);
|
);
|
||||||
productName = Yattee;
|
productName = Yattee;
|
||||||
productReference = 37D4B158267164AE00C925CA /* Yattee (tvOS).app */;
|
productReference = 37D4B158267164AE00C925CA /* Yattee.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
37D4B170267164B000C925CA /* Tests (tvOS) */ = {
|
37D4B170267164B000C925CA /* Tests (tvOS) */ = {
|
||||||
@ -1723,6 +1717,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
374710052755291C00CE0F87 /* SearchField.swift in Sources */,
|
||||||
37CEE4BD2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
37CEE4BD2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||||
37CC3F45270CE30600608308 /* PlayerQueueItem.swift in Sources */,
|
37CC3F45270CE30600608308 /* PlayerQueueItem.swift in Sources */,
|
||||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
||||||
@ -1737,6 +1732,7 @@
|
|||||||
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
||||||
37152EEA26EFEB95004FB96D /* LazyView.swift in Sources */,
|
37152EEA26EFEB95004FB96D /* LazyView.swift in Sources */,
|
||||||
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
||||||
|
3782B94F27553A6700990149 /* SearchSuggestions.swift in Sources */,
|
||||||
378E50FF26FE8EEE00F49626 /* AccountsMenuView.swift in Sources */,
|
378E50FF26FE8EEE00F49626 /* AccountsMenuView.swift in Sources */,
|
||||||
37169AA62729E2CC0011DE61 /* AccountsBridge.swift in Sources */,
|
37169AA62729E2CC0011DE61 /* AccountsBridge.swift in Sources */,
|
||||||
37C7A1DA267CACF50010EAD6 /* TrendingCountry.swift in Sources */,
|
37C7A1DA267CACF50010EAD6 /* TrendingCountry.swift in Sources */,
|
||||||
@ -1756,8 +1752,10 @@
|
|||||||
37BE0BD326A1D4780092E2DB /* Player.swift in Sources */,
|
37BE0BD326A1D4780092E2DB /* Player.swift in Sources */,
|
||||||
37A9965E26D6F9B9006E3224 /* FavoritesView.swift in Sources */,
|
37A9965E26D6F9B9006E3224 /* FavoritesView.swift in Sources */,
|
||||||
37CEE4C12677B697005A1EFE /* Stream.swift in Sources */,
|
37CEE4C12677B697005A1EFE /* Stream.swift in Sources */,
|
||||||
|
378AE943274EF00A006A4EE1 /* Color+Background.swift in Sources */,
|
||||||
37F4AE7226828F0900BD60EA /* VerticalCells.swift in Sources */,
|
37F4AE7226828F0900BD60EA /* VerticalCells.swift in Sources */,
|
||||||
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||||
|
3722AEBC274DA396005EA4D6 /* Badge+Backport.swift in Sources */,
|
||||||
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
37599F34272B44000087F250 /* FavoritesModel.swift in Sources */,
|
37599F34272B44000087F250 /* FavoritesModel.swift in Sources */,
|
||||||
37BA794726DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */,
|
37BA794726DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */,
|
||||||
@ -1765,7 +1763,9 @@
|
|||||||
37CC3F4C270CFE1700608308 /* PlayerQueueView.swift in Sources */,
|
37CC3F4C270CFE1700608308 /* PlayerQueueView.swift in Sources */,
|
||||||
37FFC440272734C3009FFD26 /* Throttle.swift in Sources */,
|
37FFC440272734C3009FFD26 /* Throttle.swift in Sources */,
|
||||||
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||||
|
378AE940274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
|
||||||
376BE50927347B5F009AD608 /* SettingsHeader.swift in Sources */,
|
376BE50927347B5F009AD608 /* SettingsHeader.swift in Sources */,
|
||||||
|
3722AEBE274DA401005EA4D6 /* Backport.swift in Sources */,
|
||||||
3700155F271B12DD0049C794 /* SiestaConfiguration.swift in Sources */,
|
3700155F271B12DD0049C794 /* SiestaConfiguration.swift in Sources */,
|
||||||
37EAD86F267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD86F267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
375168D62700FAFF008F96A6 /* Debounce.swift in Sources */,
|
375168D62700FAFF008F96A6 /* Debounce.swift in Sources */,
|
||||||
@ -1773,6 +1773,7 @@
|
|||||||
376578892685471400D4EA09 /* Playlist.swift in Sources */,
|
376578892685471400D4EA09 /* Playlist.swift in Sources */,
|
||||||
373CFADB269663F1003CB2C6 /* Thumbnail.swift in Sources */,
|
373CFADB269663F1003CB2C6 /* Thumbnail.swift in Sources */,
|
||||||
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
|
3782B9522755667600990149 /* String+Format.swift in Sources */,
|
||||||
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||||
37BF661F27308884008CCFB0 /* DropFavoriteOutside.swift in Sources */,
|
37BF661F27308884008CCFB0 /* DropFavoriteOutside.swift in Sources */,
|
||||||
3700155B271B0D4D0049C794 /* PipedAPI.swift in Sources */,
|
3700155B271B0D4D0049C794 /* PipedAPI.swift in Sources */,
|
||||||
@ -1786,7 +1787,6 @@
|
|||||||
37BA794326DBA973002A0235 /* PlaylistsModel.swift in Sources */,
|
37BA794326DBA973002A0235 /* PlaylistsModel.swift in Sources */,
|
||||||
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
||||||
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
||||||
3761AC0F26F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */,
|
|
||||||
37B81AFF26D2CA3700675966 /* VideoDetails.swift in Sources */,
|
37B81AFF26D2CA3700675966 /* VideoDetails.swift in Sources */,
|
||||||
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */,
|
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */,
|
||||||
376578912685490700D4EA09 /* PlaylistsView.swift in Sources */,
|
376578912685490700D4EA09 /* PlaylistsView.swift in Sources */,
|
||||||
@ -1795,7 +1795,7 @@
|
|||||||
374C053F272472C0009BDDBE /* PlayerSponsorBlock.swift in Sources */,
|
374C053F272472C0009BDDBE /* PlayerSponsorBlock.swift in Sources */,
|
||||||
37FB28412721B22200A57617 /* ContentItem.swift in Sources */,
|
37FB28412721B22200A57617 /* ContentItem.swift in Sources */,
|
||||||
37C3A24D272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
37C3A24D272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
||||||
37484C2D26FC844700287258 /* AccountsSettings.swift in Sources */,
|
37484C2D26FC844700287258 /* InstanceSettings.swift in Sources */,
|
||||||
377A20A92693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
|
377A20A92693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
|
||||||
37484C3126FCB8F900287258 /* AccountValidator.swift in Sources */,
|
37484C3126FCB8F900287258 /* AccountValidator.swift in Sources */,
|
||||||
37319F0527103F94004ECCD0 /* PlayerQueue.swift in Sources */,
|
37319F0527103F94004ECCD0 /* PlayerQueue.swift in Sources */,
|
||||||
@ -1830,6 +1830,7 @@
|
|||||||
373CFAEB26975CBF003CB2C6 /* PlaylistFormView.swift in Sources */,
|
373CFAEB26975CBF003CB2C6 /* PlaylistFormView.swift in Sources */,
|
||||||
37B81B0226D2CAE700675966 /* PlaybackBar.swift in Sources */,
|
37B81B0226D2CAE700675966 /* PlaybackBar.swift in Sources */,
|
||||||
372915E62687E3B900F5A35B /* Defaults.swift in Sources */,
|
372915E62687E3B900F5A35B /* Defaults.swift in Sources */,
|
||||||
|
37E084AC2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */,
|
||||||
37D526E32720B4BE00ED2F5E /* View+SwipeGesture.swift in Sources */,
|
37D526E32720B4BE00ED2F5E /* View+SwipeGesture.swift in Sources */,
|
||||||
37732FF42703D32400F04329 /* Sidebar.swift in Sources */,
|
37732FF42703D32400F04329 /* Sidebar.swift in Sources */,
|
||||||
37D4B19726717E1500C925CA /* Video.swift in Sources */,
|
37D4B19726717E1500C925CA /* Video.swift in Sources */,
|
||||||
@ -1842,7 +1843,6 @@
|
|||||||
37CC3F50270D010D00608308 /* VideoBanner.swift in Sources */,
|
37CC3F50270D010D00608308 /* VideoBanner.swift in Sources */,
|
||||||
378E50FB26FE8B9F00F49626 /* Instance.swift in Sources */,
|
378E50FB26FE8B9F00F49626 /* Instance.swift in Sources */,
|
||||||
37E70923271CD43000D34DDE /* WelcomeScreen.swift in Sources */,
|
37E70923271CD43000D34DDE /* WelcomeScreen.swift in Sources */,
|
||||||
37484C1D26FC83A400287258 /* InstancesSettings.swift in Sources */,
|
|
||||||
37BD07BB2698AB60003EBB87 /* AppSidebarNavigation.swift in Sources */,
|
37BD07BB2698AB60003EBB87 /* AppSidebarNavigation.swift in Sources */,
|
||||||
37C0697A2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
|
37C0697A2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
|
||||||
37D4B0E42671614900C925CA /* YatteeApp.swift in Sources */,
|
37D4B0E42671614900C925CA /* YatteeApp.swift in Sources */,
|
||||||
@ -1857,6 +1857,8 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
374710062755291C00CE0F87 /* SearchField.swift in Sources */,
|
||||||
|
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
|
||||||
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
||||||
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
|
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
|
||||||
3743CA53270F284F00E4D32B /* View+Borders.swift in Sources */,
|
3743CA53270F284F00E4D32B /* View+Borders.swift in Sources */,
|
||||||
@ -1870,6 +1872,7 @@
|
|||||||
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
37C3A24E272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
37C3A24E272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
||||||
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
|
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
|
||||||
|
3782B95027553A6700990149 /* SearchSuggestions.swift in Sources */,
|
||||||
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */,
|
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */,
|
||||||
37001564271B1F250049C794 /* AccountsModel.swift in Sources */,
|
37001564271B1F250049C794 /* AccountsModel.swift in Sources */,
|
||||||
3761ABFE26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
3761ABFE26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
||||||
@ -1889,9 +1892,11 @@
|
|||||||
37484C1A26FC837400287258 /* PlaybackSettings.swift in Sources */,
|
37484C1A26FC837400287258 /* PlaybackSettings.swift in Sources */,
|
||||||
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
||||||
37484C3226FCB8F900287258 /* AccountValidator.swift in Sources */,
|
37484C3226FCB8F900287258 /* AccountValidator.swift in Sources */,
|
||||||
|
378AE944274EF00A006A4EE1 /* Color+Background.swift in Sources */,
|
||||||
37F49BA426CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
37F49BA426CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
||||||
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
|
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
|
||||||
|
378AE93A274EDFAF006A4EE1 /* Badge+Backport.swift in Sources */,
|
||||||
37599F35272B44000087F250 /* FavoritesModel.swift in Sources */,
|
37599F35272B44000087F250 /* FavoritesModel.swift in Sources */,
|
||||||
37F64FE526FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
|
37F64FE526FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
|
||||||
37FFC441272734C3009FFD26 /* Throttle.swift in Sources */,
|
37FFC441272734C3009FFD26 /* Throttle.swift in Sources */,
|
||||||
@ -1900,6 +1905,7 @@
|
|||||||
378E510026FE8EEE00F49626 /* AccountsMenuView.swift in Sources */,
|
378E510026FE8EEE00F49626 /* AccountsMenuView.swift in Sources */,
|
||||||
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
376BE50727347B57009AD608 /* SettingsHeader.swift in Sources */,
|
376BE50727347B57009AD608 /* SettingsHeader.swift in Sources */,
|
||||||
|
378AE93C274EDFB2006A4EE1 /* Backport.swift in Sources */,
|
||||||
37152EEB26EFEB95004FB96D /* LazyView.swift in Sources */,
|
37152EEB26EFEB95004FB96D /* LazyView.swift in Sources */,
|
||||||
377FC7E2267A084A00A6BBAF /* VideoCell.swift in Sources */,
|
377FC7E2267A084A00A6BBAF /* VideoCell.swift in Sources */,
|
||||||
37CC3F51270D010D00608308 /* VideoBanner.swift in Sources */,
|
37CC3F51270D010D00608308 /* VideoBanner.swift in Sources */,
|
||||||
@ -1907,6 +1913,7 @@
|
|||||||
37169AA32729D98A0011DE61 /* InstancesBridge.swift in Sources */,
|
37169AA32729D98A0011DE61 /* InstancesBridge.swift in Sources */,
|
||||||
37B044B826F7AB9000E1419D /* SettingsView.swift in Sources */,
|
37B044B826F7AB9000E1419D /* SettingsView.swift in Sources */,
|
||||||
3765788A2685471400D4EA09 /* Playlist.swift in Sources */,
|
3765788A2685471400D4EA09 /* Playlist.swift in Sources */,
|
||||||
|
3782B9532755667600990149 /* String+Format.swift in Sources */,
|
||||||
37E2EEAC270656EC00170416 /* PlayerControlsView.swift in Sources */,
|
37E2EEAC270656EC00170416 /* PlayerControlsView.swift in Sources */,
|
||||||
37BF662027308884008CCFB0 /* DropFavoriteOutside.swift in Sources */,
|
37BF662027308884008CCFB0 /* DropFavoriteOutside.swift in Sources */,
|
||||||
37E70924271CD43000D34DDE /* WelcomeScreen.swift in Sources */,
|
37E70924271CD43000D34DDE /* WelcomeScreen.swift in Sources */,
|
||||||
@ -1935,7 +1942,6 @@
|
|||||||
37B81AFD26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
|
37B81AFD26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
|
||||||
37C0697F2725C8D400F7F6CB /* CMTime+DefaultTimescale.swift in Sources */,
|
37C0697F2725C8D400F7F6CB /* CMTime+DefaultTimescale.swift in Sources */,
|
||||||
37A9965B26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
|
37A9965B26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
|
||||||
3761AC1026F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */,
|
|
||||||
37732FF52703D32400F04329 /* Sidebar.swift in Sources */,
|
37732FF52703D32400F04329 /* Sidebar.swift in Sources */,
|
||||||
379775942689365600DD52A8 /* Array+Next.swift in Sources */,
|
379775942689365600DD52A8 /* Array+Next.swift in Sources */,
|
||||||
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
@ -1976,6 +1982,7 @@
|
|||||||
37B17DA1268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */,
|
37B17DA1268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */,
|
||||||
3743B86927216D3600261544 /* ChannelCell.swift in Sources */,
|
3743B86927216D3600261544 /* ChannelCell.swift in Sources */,
|
||||||
3748186B26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
3748186B26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
||||||
|
3782B95E2755858100990149 /* NSTextField+FocusRingType.swift in Sources */,
|
||||||
37C3A252272366440087A57A /* ChannelPlaylistView.swift in Sources */,
|
37C3A252272366440087A57A /* ChannelPlaylistView.swift in Sources */,
|
||||||
373CFADC269663F1003CB2C6 /* Thumbnail.swift in Sources */,
|
373CFADC269663F1003CB2C6 /* Thumbnail.swift in Sources */,
|
||||||
37C0697B2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
|
37C0697B2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
|
||||||
@ -2055,7 +2062,6 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
37AAF28026737550007FC770 /* SearchView.swift in Sources */,
|
|
||||||
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
37CC3F52270D010D00608308 /* VideoBanner.swift in Sources */,
|
37CC3F52270D010D00608308 /* VideoBanner.swift in Sources */,
|
||||||
37F49BA526CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
37F49BA526CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
||||||
@ -2071,6 +2077,7 @@
|
|||||||
37D4B1802671650A00C925CA /* YatteeApp.swift in Sources */,
|
37D4B1802671650A00C925CA /* YatteeApp.swift in Sources */,
|
||||||
3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
|
3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
|
||||||
37A9965C26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
|
37A9965C26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
|
||||||
|
3782B95727557E6E00990149 /* SearchSuggestions.swift in Sources */,
|
||||||
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */,
|
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */,
|
||||||
376B2E0926F920D600B1D64D /* SignInRequiredView.swift in Sources */,
|
376B2E0926F920D600B1D64D /* SignInRequiredView.swift in Sources */,
|
||||||
37141671267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
37141671267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
@ -2080,10 +2087,12 @@
|
|||||||
37E70925271CD43000D34DDE /* WelcomeScreen.swift in Sources */,
|
37E70925271CD43000D34DDE /* WelcomeScreen.swift in Sources */,
|
||||||
376BE50D27349108009AD608 /* BrowsingSettings.swift in Sources */,
|
376BE50D27349108009AD608 /* BrowsingSettings.swift in Sources */,
|
||||||
37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */,
|
37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */,
|
||||||
|
378AE93E274EDFB4006A4EE1 /* Tint+Backport.swift in Sources */,
|
||||||
37FFC442272734C3009FFD26 /* Throttle.swift in Sources */,
|
37FFC442272734C3009FFD26 /* Throttle.swift in Sources */,
|
||||||
375168D82700FDB9008F96A6 /* Debounce.swift in Sources */,
|
375168D82700FDB9008F96A6 /* Debounce.swift in Sources */,
|
||||||
37BA794126DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
|
37BA794126DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
|
||||||
37C0697C2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
|
37C0697C2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
|
||||||
|
378AE93D274EDFB3006A4EE1 /* Backport.swift in Sources */,
|
||||||
37C3A243272359900087A57A /* Double+Format.swift in Sources */,
|
37C3A243272359900087A57A /* Double+Format.swift in Sources */,
|
||||||
37AAF29226740715007FC770 /* Channel.swift in Sources */,
|
37AAF29226740715007FC770 /* Channel.swift in Sources */,
|
||||||
37EAD86D267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86D267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
@ -2098,7 +2107,6 @@
|
|||||||
3743B86A27216D3600261544 /* ChannelCell.swift in Sources */,
|
3743B86A27216D3600261544 /* ChannelCell.swift in Sources */,
|
||||||
37B767DD2677C3CA0098BAA8 /* PlayerModel.swift in Sources */,
|
37B767DD2677C3CA0098BAA8 /* PlayerModel.swift in Sources */,
|
||||||
373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||||
3761AC1126F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */,
|
|
||||||
3730D8A02712E2B70020ED53 /* NowPlayingView.swift in Sources */,
|
3730D8A02712E2B70020ED53 /* NowPlayingView.swift in Sources */,
|
||||||
37169AA42729D98A0011DE61 /* InstancesBridge.swift in Sources */,
|
37169AA42729D98A0011DE61 /* InstancesBridge.swift in Sources */,
|
||||||
37D4B18E26717B3800C925CA /* VideoCell.swift in Sources */,
|
37D4B18E26717B3800C925CA /* VideoCell.swift in Sources */,
|
||||||
@ -2112,7 +2120,6 @@
|
|||||||
37E70929271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */,
|
37E70929271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */,
|
||||||
376A33E62720CB35000C1D6B /* Account.swift in Sources */,
|
376A33E62720CB35000C1D6B /* Account.swift in Sources */,
|
||||||
37599F3A272B4D740087F250 /* FavoriteButton.swift in Sources */,
|
37599F3A272B4D740087F250 /* FavoriteButton.swift in Sources */,
|
||||||
37484C1F26FC83A400287258 /* InstancesSettings.swift in Sources */,
|
|
||||||
37EF5C242739D37B00B03725 /* MenuModel.swift in Sources */,
|
37EF5C242739D37B00B03725 /* MenuModel.swift in Sources */,
|
||||||
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
||||||
376578932685490700D4EA09 /* PlaylistsView.swift in Sources */,
|
376578932685490700D4EA09 /* PlaylistsView.swift in Sources */,
|
||||||
@ -2123,6 +2130,7 @@
|
|||||||
377A20AB2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
|
377A20AB2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
|
||||||
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
37C3A253272366440087A57A /* ChannelPlaylistView.swift in Sources */,
|
37C3A253272366440087A57A /* ChannelPlaylistView.swift in Sources */,
|
||||||
|
378AE945274EF00A006A4EE1 /* Color+Background.swift in Sources */,
|
||||||
3743CA54270F284F00E4D32B /* View+Borders.swift in Sources */,
|
3743CA54270F284F00E4D32B /* View+Borders.swift in Sources */,
|
||||||
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */,
|
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */,
|
||||||
37E2EEAD270656EC00170416 /* PlayerControlsView.swift in Sources */,
|
37E2EEAD270656EC00170416 /* PlayerControlsView.swift in Sources */,
|
||||||
@ -2148,6 +2156,7 @@
|
|||||||
37FAE000272ED58000330459 /* EditFavorites.swift in Sources */,
|
37FAE000272ED58000330459 /* EditFavorites.swift in Sources */,
|
||||||
37599F32272B42810087F250 /* FavoriteItem.swift in Sources */,
|
37599F32272B42810087F250 /* FavoriteItem.swift in Sources */,
|
||||||
37141675267A8E10006CA35D /* Country.swift in Sources */,
|
37141675267A8E10006CA35D /* Country.swift in Sources */,
|
||||||
|
3782B9542755667600990149 /* String+Format.swift in Sources */,
|
||||||
37152EEC26EFEB95004FB96D /* LazyView.swift in Sources */,
|
37152EEC26EFEB95004FB96D /* LazyView.swift in Sources */,
|
||||||
37484C2726FC83E000287258 /* InstanceForm.swift in Sources */,
|
37484C2726FC83E000287258 /* InstanceForm.swift in Sources */,
|
||||||
37F49BA826CB0FCE00304AC0 /* PlaylistFormView.swift in Sources */,
|
37F49BA826CB0FCE00304AC0 /* PlaylistFormView.swift in Sources */,
|
||||||
@ -2158,6 +2167,8 @@
|
|||||||
37D526E02720AC4400ED2F5E /* VideosAPI.swift in Sources */,
|
37D526E02720AC4400ED2F5E /* VideosAPI.swift in Sources */,
|
||||||
37599F36272B44000087F250 /* FavoritesModel.swift in Sources */,
|
37599F36272B44000087F250 /* FavoritesModel.swift in Sources */,
|
||||||
3705B184267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
3705B184267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||||
|
37E084AD2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */,
|
||||||
|
3782B95627557E4E00990149 /* SearchView.swift in Sources */,
|
||||||
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
||||||
37C3A24F272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
37C3A24F272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
||||||
37FB28432721B22200A57617 /* ContentItem.swift in Sources */,
|
37FB28432721B22200A57617 /* ContentItem.swift in Sources */,
|
||||||
@ -2166,7 +2177,7 @@
|
|||||||
372915E82687E3B900F5A35B /* Defaults.swift in Sources */,
|
372915E82687E3B900F5A35B /* Defaults.swift in Sources */,
|
||||||
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */,
|
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */,
|
||||||
3797758D2689345500DD52A8 /* Store.swift in Sources */,
|
3797758D2689345500DD52A8 /* Store.swift in Sources */,
|
||||||
37484C2F26FC844700287258 /* AccountsSettings.swift in Sources */,
|
37484C2F26FC844700287258 /* InstanceSettings.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -2181,16 +2192,6 @@
|
|||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
37A3B16F27255E7F000FB5EE /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = 37A3B15627255E7F000FB5EE /* Open in Yattee (macOS) */;
|
|
||||||
targetProxy = 37A3B16E27255E7F000FB5EE /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
37A3B18E2725735F000FB5EE /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = 37A3B1782725735F000FB5EE /* Open in Yattee (iOS) */;
|
|
||||||
targetProxy = 37A3B18D2725735F000FB5EE /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
37D4B0D62671614900C925CA /* PBXTargetDependency */ = {
|
37D4B0D62671614900C925CA /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = 37D4B0C82671614900C925CA /* Yattee (iOS) */;
|
target = 37D4B0C82671614900C925CA /* Yattee (iOS) */;
|
||||||
@ -2216,7 +2217,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 = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -2229,7 +2230,7 @@
|
|||||||
"@executable_path/../../../../Frameworks",
|
"@executable_path/../../../../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.2;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-framework",
|
"-framework",
|
||||||
SafariServices,
|
SafariServices,
|
||||||
@ -2250,7 +2251,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 = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -2263,7 +2264,7 @@
|
|||||||
"@executable_path/../../../../Frameworks",
|
"@executable_path/../../../../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.2;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-framework",
|
"-framework",
|
||||||
SafariServices,
|
SafariServices,
|
||||||
@ -2282,7 +2283,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 = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
@ -2294,7 +2295,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.2;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-framework",
|
"-framework",
|
||||||
SafariServices,
|
SafariServices,
|
||||||
@ -2314,7 +2315,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 = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
@ -2326,7 +2327,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.2;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-framework",
|
"-framework",
|
||||||
SafariServices,
|
SafariServices,
|
||||||
@ -2474,11 +2475,10 @@
|
|||||||
37D4B0ED2671614900C925CA /* Debug */ = {
|
37D4B0ED2671614900C925CA /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -2488,12 +2488,12 @@
|
|||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1;
|
MARKETING_VERSION = 1.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = Yattee;
|
PRODUCT_NAME = Yattee;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -2506,11 +2506,10 @@
|
|||||||
37D4B0EE2671614900C925CA /* Release */ = {
|
37D4B0EE2671614900C925CA /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -2520,12 +2519,12 @@
|
|||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1;
|
MARKETING_VERSION = 1.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = Yattee;
|
PRODUCT_NAME = Yattee;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -2539,14 +2538,13 @@
|
|||||||
37D4B0F02671614900C925CA /* Debug */ = {
|
37D4B0F02671614900C925CA /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = Shared/Yattee.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Shared/Yattee.entitlements;
|
||||||
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 = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@ -2556,13 +2554,12 @@
|
|||||||
INFOPLIST_FILE = macOS/Info.plist;
|
INFOPLIST_FILE = macOS/Info.plist;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
INFOPLIST_KEY_NSMainStoryboardFile = Main;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
MARKETING_VERSION = 1.1;
|
MARKETING_VERSION = 1.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = Yattee;
|
PRODUCT_NAME = Yattee;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
@ -2574,14 +2571,13 @@
|
|||||||
37D4B0F12671614900C925CA /* Release */ = {
|
37D4B0F12671614900C925CA /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = Shared/Yattee.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Shared/Yattee.entitlements;
|
||||||
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 = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@ -2591,13 +2587,12 @@
|
|||||||
INFOPLIST_FILE = macOS/Info.plist;
|
INFOPLIST_FILE = macOS/Info.plist;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.video";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
INFOPLIST_KEY_NSMainStoryboardFile = Main;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
MARKETING_VERSION = 1.1;
|
MARKETING_VERSION = 1.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = Yattee;
|
PRODUCT_NAME = Yattee;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
@ -2713,14 +2708,13 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
|
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = tvOS/Info.plist;
|
INFOPLIST_FILE = tvOS/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Yattee;
|
INFOPLIST_KEY_CFBundleDisplayName = Yattee;
|
||||||
INFOPLIST_KEY_CFBundleExecutable = "Yattee (Apple TV)";
|
|
||||||
INFOPLIST_KEY_CFBundleName = "Yattee (Apple TV)";
|
INFOPLIST_KEY_CFBundleName = "Yattee (Apple TV)";
|
||||||
INFOPLIST_KEY_CFBundleVersion = 1;
|
INFOPLIST_KEY_CFBundleVersion = 1;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
@ -2729,9 +2723,9 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1;
|
MARKETING_VERSION = 1.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = Yattee;
|
||||||
SDKROOT = appletvos;
|
SDKROOT = appletvos;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -2746,14 +2740,13 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
|
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 2;
|
CURRENT_PROJECT_VERSION = 3;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = tvOS/Info.plist;
|
INFOPLIST_FILE = tvOS/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Yattee;
|
INFOPLIST_KEY_CFBundleDisplayName = Yattee;
|
||||||
INFOPLIST_KEY_CFBundleExecutable = "Yattee (Apple TV)";
|
|
||||||
INFOPLIST_KEY_CFBundleName = "Yattee (Apple TV)";
|
INFOPLIST_KEY_CFBundleName = "Yattee (Apple TV)";
|
||||||
INFOPLIST_KEY_CFBundleVersion = 1;
|
INFOPLIST_KEY_CFBundleVersion = 1;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
@ -2762,9 +2755,9 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1;
|
MARKETING_VERSION = 1.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = Yattee;
|
||||||
SDKROOT = appletvos;
|
SDKROOT = appletvos;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -2980,7 +2973,7 @@
|
|||||||
repositoryURL = "https://github.com/sindresorhus/Defaults";
|
repositoryURL = "https://github.com/sindresorhus/Defaults";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMajorVersion;
|
kind = upToNextMajorVersion;
|
||||||
minimumVersion = 5.0.0;
|
minimumVersion = 6.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
3765917827237D07009F956E /* XCRemoteSwiftPackageReference "PINCache" */ = {
|
3765917827237D07009F956E /* XCRemoteSwiftPackageReference "PINCache" */ = {
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
"repositoryURL": "https://github.com/sindresorhus/Defaults",
|
"repositoryURL": "https://github.com/sindresorhus/Defaults",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "63d93f97ad545c8bceb125a8a36175ea705f7cf5",
|
"revision": "55f3302c3ab30a8760f10042d0ebc0a6907f865a",
|
||||||
"version": "5.0.0"
|
"version": "6.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"repositoryURL": "https://github.com/pinterest/PINCache",
|
"repositoryURL": "https://github.com/pinterest/PINCache",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"revision": "a16dae6cec4897a7a9710239e0cb50b6de935e7b",
|
"revision": "046f67609085a7d73d27105d2be91729d139208f",
|
||||||
"version": null
|
"version": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "37D4B157267164AE00C925CA"
|
BlueprintIdentifier = "37D4B157267164AE00C925CA"
|
||||||
BuildableName = "Yattee (tvOS).app"
|
BuildableName = "Yattee.app"
|
||||||
BlueprintName = "Yattee (tvOS)"
|
BlueprintName = "Yattee (tvOS)"
|
||||||
ReferencedContainer = "container:Yattee.xcodeproj">
|
ReferencedContainer = "container:Yattee.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "37D4B157267164AE00C925CA"
|
BlueprintIdentifier = "37D4B157267164AE00C925CA"
|
||||||
BuildableName = "Yattee (tvOS).app"
|
BuildableName = "Yattee.app"
|
||||||
BlueprintName = "Yattee (tvOS)"
|
BlueprintName = "Yattee (tvOS)"
|
||||||
ReferencedContainer = "container:Yattee.xcodeproj">
|
ReferencedContainer = "container:Yattee.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "37D4B157267164AE00C925CA"
|
BlueprintIdentifier = "37D4B157267164AE00C925CA"
|
||||||
BuildableName = "Yattee (tvOS).app"
|
BuildableName = "Yattee.app"
|
||||||
BlueprintName = "Yattee (tvOS)"
|
BlueprintName = "Yattee (tvOS)"
|
||||||
ReferencedContainer = "container:Yattee.xcodeproj">
|
ReferencedContainer = "container:Yattee.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
@ -40,7 +40,7 @@ struct InstancesSettings: View {
|
|||||||
if !selectedInstance.isNil, selectedInstance.app.supportsAccounts {
|
if !selectedInstance.isNil, selectedInstance.app.supportsAccounts {
|
||||||
SettingsHeader(text: "Accounts")
|
SettingsHeader(text: "Accounts")
|
||||||
|
|
||||||
List(selection: $selectedAccount) {
|
let list = List(selection: $selectedAccount) {
|
||||||
if selectedInstanceAccounts.isEmpty {
|
if selectedInstanceAccounts.isEmpty {
|
||||||
Text("You have no accounts for this instance")
|
Text("You have no accounts for this instance")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
@ -51,7 +51,7 @@ struct InstancesSettings: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button("Remove", role: .destructive) {
|
Button("Remove") {
|
||||||
presentingAccountRemovalConfirmation = true
|
presentingAccountRemovalConfirmation = true
|
||||||
}
|
}
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
@ -60,30 +60,40 @@ struct InstancesSettings: View {
|
|||||||
.tag(account)
|
.tag(account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.confirmationDialog(
|
.alert(isPresented: $presentingAccountRemovalConfirmation) {
|
||||||
"Are you sure you want to remove \(selectedAccount?.description ?? "") account?",
|
Alert(
|
||||||
isPresented: $presentingAccountRemovalConfirmation
|
title: Text(
|
||||||
) {
|
"Are you sure you want to remove \(selectedAccount?.description ?? "") account?"
|
||||||
Button("Remove", role: .destructive) {
|
),
|
||||||
AccountsModel.remove(selectedAccount!)
|
message: Text("This cannot be undone"),
|
||||||
}
|
primaryButton: .destructive(Text("Delete")) {
|
||||||
|
AccountsModel.remove(selectedAccount!)
|
||||||
|
},
|
||||||
|
secondaryButton: .cancel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if #available(macOS 12.0, *) {
|
||||||
|
list
|
||||||
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
|
} else {
|
||||||
|
list
|
||||||
}
|
}
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if selectedInstance != nil, selectedInstance.app.hasFrontendURL {
|
if selectedInstance != nil, selectedInstance.app.hasFrontendURL {
|
||||||
SettingsHeader(text: "Frontend URL")
|
SettingsHeader(text: "Frontend URL")
|
||||||
|
|
||||||
TextField("Frontend URL", text: $frontendURL, prompt: Text("Frontend URL"))
|
TextField("Frontend URL", text: $frontendURL)
|
||||||
.onAppear {
|
.onChange(of: selectedInstance) { _ in
|
||||||
frontendURL = selectedInstance.frontendURL ?? ""
|
frontendURL = selectedInstanceFrontendURL
|
||||||
}
|
}
|
||||||
.onChange(of: frontendURL) { newValue in
|
.onChange(of: frontendURL) { newValue in
|
||||||
InstancesModel.setFrontendURL(selectedInstance, newValue)
|
InstancesModel.setFrontendURL(selectedInstance, newValue)
|
||||||
}
|
}
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
|
|
||||||
Text("If provided, you can copy links from videos, channels and playlist")
|
Text("Used to create links from videos, channels and playlist")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
@ -105,23 +115,26 @@ struct InstancesSettings: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button("Remove Instance", role: .destructive) {
|
Button("Remove Instance") {
|
||||||
presentingInstanceRemovalConfirmation = true
|
presentingInstanceRemovalConfirmation = true
|
||||||
}
|
}
|
||||||
.confirmationDialog(
|
.alert(isPresented: $presentingInstanceRemovalConfirmation) {
|
||||||
"Are you sure you want to remove \(selectedInstance!.longDescription) instance?",
|
Alert(
|
||||||
isPresented: $presentingInstanceRemovalConfirmation
|
title: Text(
|
||||||
) {
|
"Are you sure you want to remove \(selectedInstance!.longDescription) instance?"
|
||||||
Button("Remove Instance", role: .destructive) {
|
),
|
||||||
if accounts.current?.instance == selectedInstance {
|
message: Text("This cannot be undone"),
|
||||||
accounts.setCurrent(nil)
|
primaryButton: .destructive(Text("Remove")) {
|
||||||
}
|
if accounts.current?.instance == selectedInstance {
|
||||||
|
accounts.setCurrent(nil)
|
||||||
|
}
|
||||||
|
|
||||||
InstancesModel.remove(selectedInstance!)
|
InstancesModel.remove(selectedInstance!)
|
||||||
selectedInstanceID = instances.last?.id
|
selectedInstanceID = instances.last?.id
|
||||||
}
|
},
|
||||||
|
secondaryButton: .cancel()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,6 +147,7 @@ struct InstancesSettings: View {
|
|||||||
|
|
||||||
.onAppear {
|
.onAppear {
|
||||||
selectedInstanceID = instances.first?.id
|
selectedInstanceID = instances.first?.id
|
||||||
|
frontendURL = selectedInstanceFrontendURL
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $presentingAccountForm) {
|
.sheet(isPresented: $presentingAccountForm) {
|
||||||
AccountForm(instance: selectedInstance, selectedAccount: $selectedAccount)
|
AccountForm(instance: selectedInstance, selectedAccount: $selectedAccount)
|
||||||
@ -154,6 +168,10 @@ struct InstancesSettings: View {
|
|||||||
InstancesModel.find(selectedInstanceID)
|
InstancesModel.find(selectedInstanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var selectedInstanceFrontendURL: String {
|
||||||
|
selectedInstance?.frontendURL ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
private var selectedInstanceAccounts: [Account] {
|
private var selectedInstanceAccounts: [Account] {
|
||||||
guard selectedInstance != nil else {
|
guard selectedInstance != nil else {
|
||||||
return []
|
return []
|
@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
|
"filename" : "TopShelf-Wide.png",
|
||||||
"idiom" : "tv",
|
"idiom" : "tv",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "TopShelf-Wide@2x.png",
|
||||||
"idiom" : "tv",
|
"idiom" : "tv",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
Loading…
Reference in New Issue
Block a user