mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
Replace environment objects with observed objects
This commit is contained in:
parent
23fa0968c6
commit
0d333b5583
@ -5,8 +5,6 @@ struct FixtureEnvironmentObjectsModifier: ViewModifier {
|
|||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
content
|
content
|
||||||
.environmentObject(AccountsModel())
|
.environmentObject(AccountsModel())
|
||||||
.environmentObject(comments)
|
|
||||||
.environmentObject(InstancesModel())
|
|
||||||
.environmentObject(InstancesManifest())
|
.environmentObject(InstancesManifest())
|
||||||
.environmentObject(invidious)
|
.environmentObject(invidious)
|
||||||
.environmentObject(NavigationModel())
|
.environmentObject(NavigationModel())
|
||||||
@ -17,20 +15,11 @@ struct FixtureEnvironmentObjectsModifier: ViewModifier {
|
|||||||
.environmentObject(PlayerTimeModel())
|
.environmentObject(PlayerTimeModel())
|
||||||
.environmentObject(PlaylistsModel())
|
.environmentObject(PlaylistsModel())
|
||||||
.environmentObject(RecentsModel())
|
.environmentObject(RecentsModel())
|
||||||
.environmentObject(SearchModel())
|
|
||||||
.environmentObject(SettingsModel())
|
.environmentObject(SettingsModel())
|
||||||
.environmentObject(subscriptions)
|
.environmentObject(subscriptions)
|
||||||
.environmentObject(ThumbnailsModel())
|
.environmentObject(ThumbnailsModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
private var comments: CommentsModel {
|
|
||||||
let comments = CommentsModel()
|
|
||||||
comments.loaded = true
|
|
||||||
comments.all = [.fixture]
|
|
||||||
|
|
||||||
return comments
|
|
||||||
}
|
|
||||||
|
|
||||||
private var invidious: InvidiousAPI {
|
private var invidious: InvidiousAPI {
|
||||||
let api = InvidiousAPI()
|
let api = InvidiousAPI()
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ import Defaults
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class AccountsModel: ObservableObject {
|
final class AccountsModel: ObservableObject {
|
||||||
|
static let shared = AccountsModel()
|
||||||
|
|
||||||
@Published private(set) var current: Account!
|
@Published private(set) var current: Account!
|
||||||
|
|
||||||
@Published private var invidious = InvidiousAPI()
|
@Published private var invidious = InvidiousAPI()
|
||||||
@ -61,8 +63,8 @@ final class AccountsModel: ObservableObject {
|
|||||||
|
|
||||||
func configureAccount() {
|
func configureAccount() {
|
||||||
if let account = lastUsed ??
|
if let account = lastUsed ??
|
||||||
InstancesModel.lastUsed?.anonymousAccount ??
|
InstancesModel.shared.lastUsed?.anonymousAccount ??
|
||||||
InstancesModel.all.first?.anonymousAccount
|
InstancesModel.shared.all.first?.anonymousAccount
|
||||||
{
|
{
|
||||||
setCurrent(account)
|
setCurrent(account)
|
||||||
}
|
}
|
||||||
|
@ -2,27 +2,29 @@ import Defaults
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class InstancesModel: ObservableObject {
|
final class InstancesModel: ObservableObject {
|
||||||
static var all: [Instance] {
|
static var shared = InstancesModel()
|
||||||
|
|
||||||
|
var all: [Instance] {
|
||||||
Defaults[.instances]
|
Defaults[.instances]
|
||||||
}
|
}
|
||||||
|
|
||||||
static var forPlayer: Instance? {
|
var forPlayer: Instance? {
|
||||||
guard let id = Defaults[.playerInstanceID] else {
|
guard let id = Defaults[.playerInstanceID] else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return InstancesModel.find(id)
|
return InstancesModel.shared.find(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
static var lastUsed: Instance? {
|
var lastUsed: Instance? {
|
||||||
guard let id = Defaults[.lastInstanceID] else {
|
guard let id = Defaults[.lastInstanceID] else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return InstancesModel.find(id)
|
return InstancesModel.shared.find(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func find(_ id: Instance.ID?) -> Instance? {
|
func find(_ id: Instance.ID?) -> Instance? {
|
||||||
guard id != nil else {
|
guard id != nil else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -30,11 +32,11 @@ final class InstancesModel: ObservableObject {
|
|||||||
return Defaults[.instances].first { $0.id == id }
|
return Defaults[.instances].first { $0.id == id }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func accounts(_ id: Instance.ID?) -> [Account] {
|
func accounts(_ id: Instance.ID?) -> [Account] {
|
||||||
Defaults[.accounts].filter { $0.instanceID == id }
|
Defaults[.accounts].filter { $0.instanceID == id }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func add(app: VideosApp, name: String, url: String) -> Instance {
|
func add(app: VideosApp, name: String, url: String) -> Instance {
|
||||||
let instance = Instance(
|
let instance = Instance(
|
||||||
app: app, id: UUID().uuidString, name: name, apiURL: standardizedURL(url)
|
app: app, id: UUID().uuidString, name: name, apiURL: standardizedURL(url)
|
||||||
)
|
)
|
||||||
@ -43,7 +45,7 @@ final class InstancesModel: ObservableObject {
|
|||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
static func setFrontendURL(_ instance: Instance, _ url: String) {
|
func setFrontendURL(_ instance: Instance, _ url: String) {
|
||||||
if let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) {
|
if let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) {
|
||||||
var instance = Defaults[.instances][index]
|
var instance = Defaults[.instances][index]
|
||||||
instance.frontendURL = standardizedURL(url)
|
instance.frontendURL = standardizedURL(url)
|
||||||
@ -52,7 +54,7 @@ final class InstancesModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func setProxiesVideos(_ instance: Instance, _ proxiesVideos: Bool) {
|
func setProxiesVideos(_ instance: Instance, _ proxiesVideos: Bool) {
|
||||||
guard let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) else {
|
guard let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -63,15 +65,15 @@ final class InstancesModel: ObservableObject {
|
|||||||
Defaults[.instances][index] = instance
|
Defaults[.instances][index] = instance
|
||||||
}
|
}
|
||||||
|
|
||||||
static func remove(_ instance: Instance) {
|
func remove(_ instance: Instance) {
|
||||||
let accounts = Self.accounts(instance.id)
|
let accounts = accounts(instance.id)
|
||||||
if let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) {
|
if let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) {
|
||||||
Defaults[.instances].remove(at: index)
|
Defaults[.instances].remove(at: index)
|
||||||
accounts.forEach { AccountsModel.remove($0) }
|
accounts.forEach { AccountsModel.remove($0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func standardizedURL(_ url: String) -> String {
|
func standardizedURL(_ url: String) -> String {
|
||||||
if url.count > 7, url.last == "/" {
|
if url.count > 7, url.last == "/" {
|
||||||
return String(url.dropLast())
|
return String(url.dropLast())
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,6 +3,8 @@ import Foundation
|
|||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
|
||||||
final class CommentsModel: ObservableObject {
|
final class CommentsModel: ObservableObject {
|
||||||
|
static let shared = CommentsModel()
|
||||||
|
|
||||||
@Published var all = [Comment]()
|
@Published var all = [Comment]()
|
||||||
|
|
||||||
@Published var nextPage: String?
|
@Published var nextPage: String?
|
||||||
@ -15,10 +17,11 @@ final class CommentsModel: ObservableObject {
|
|||||||
@Published var repliesPageID: String?
|
@Published var repliesPageID: String?
|
||||||
@Published var repliesLoaded = false
|
@Published var repliesLoaded = false
|
||||||
|
|
||||||
var player: PlayerModel!
|
var player = PlayerModel.shared
|
||||||
|
var accounts = AccountsModel.shared
|
||||||
|
|
||||||
var instance: Instance? {
|
var instance: Instance? {
|
||||||
player.accounts.current?.instance
|
accounts.current?.instance
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextPageAvailable: Bool {
|
var nextPageAvailable: Bool {
|
||||||
@ -80,7 +83,7 @@ final class CommentsModel: ObservableObject {
|
|||||||
repliesPageID = page
|
repliesPageID = page
|
||||||
repliesLoaded = false
|
repliesLoaded = false
|
||||||
|
|
||||||
player.accounts.api.comments(player.currentVideo!.videoID, page: page)?
|
accounts.api.comments(player.currentVideo!.videoID, page: page)?
|
||||||
.load()
|
.load()
|
||||||
.onSuccess { [weak self] response in
|
.onSuccess { [weak self] response in
|
||||||
if let page: CommentsPage = response.typedContent() {
|
if let page: CommentsPage = response.typedContent() {
|
||||||
|
@ -34,11 +34,11 @@ final class InstancesManifest: Service, ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPublicAccount(_ country: String?, accounts: AccountsModel, asCurrent: Bool = true) {
|
func setPublicAccount(_ country: String?, asCurrent: Bool = true) {
|
||||||
guard let country else {
|
guard let country else {
|
||||||
accounts.publicAccount = nil
|
AccountsModel.shared.publicAccount = nil
|
||||||
if asCurrent {
|
if asCurrent {
|
||||||
accounts.configureAccount()
|
AccountsModel.shared.configureAccount()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -47,42 +47,42 @@ final class InstancesManifest: Service, ObservableObject {
|
|||||||
if let instances: [ManifestedInstance] = response.typedContent() {
|
if let instances: [ManifestedInstance] = response.typedContent() {
|
||||||
guard let instance = instances.filter { $0.country == country }.randomElement() else { return }
|
guard let instance = instances.filter { $0.country == country }.randomElement() else { return }
|
||||||
let account = instance.anonymousAccount
|
let account = instance.anonymousAccount
|
||||||
accounts.publicAccount = account
|
AccountsModel.shared.publicAccount = account
|
||||||
if asCurrent {
|
if asCurrent {
|
||||||
accounts.setCurrent(account)
|
AccountsModel.shared.setCurrent(account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func changePublicAccount(_ accounts: AccountsModel, settings: SettingsModel) {
|
func changePublicAccount() {
|
||||||
instancesList?.load().onSuccess { response in
|
instancesList?.load().onSuccess { response in
|
||||||
if let instances: [ManifestedInstance] = response.typedContent() {
|
if let instances: [ManifestedInstance] = response.typedContent() {
|
||||||
var countryInstances = instances.filter { $0.country == Defaults[.countryOfPublicInstances] }
|
var countryInstances = instances.filter { $0.country == Defaults[.countryOfPublicInstances] }
|
||||||
let region = countryInstances.first?.region ?? "Europe"
|
let region = countryInstances.first?.region ?? "Europe"
|
||||||
var regionInstances = instances.filter { $0.region == region }
|
var regionInstances = instances.filter { $0.region == region }
|
||||||
|
|
||||||
if let publicAccountUrl = accounts.publicAccount?.url {
|
if let publicAccountUrl = AccountsModel.shared.publicAccount?.url {
|
||||||
countryInstances = countryInstances.filter { $0.url.absoluteString != publicAccountUrl }
|
countryInstances = countryInstances.filter { $0.url.absoluteString != publicAccountUrl }
|
||||||
regionInstances = regionInstances.filter { $0.url.absoluteString != publicAccountUrl }
|
regionInstances = regionInstances.filter { $0.url.absoluteString != publicAccountUrl }
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance: ManifestedInstance?
|
var instance: ManifestedInstance?
|
||||||
|
|
||||||
if accounts.current?.isPublic ?? false {
|
if AccountsModel.shared.current?.isPublic ?? false {
|
||||||
instance = regionInstances.randomElement()
|
instance = regionInstances.randomElement()
|
||||||
} else {
|
} else {
|
||||||
instance = countryInstances.randomElement() ?? regionInstances.randomElement()
|
instance = countryInstances.randomElement() ?? regionInstances.randomElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let instance else {
|
guard let instance else {
|
||||||
settings.presentAlert(title: "Could not change location", message: "No locations available at the moment")
|
SettingsModel.shared.presentAlert(title: "Could not change location", message: "No locations available at the moment")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let account = instance.anonymousAccount
|
let account = instance.anonymousAccount
|
||||||
accounts.publicAccount = account
|
AccountsModel.shared.publicAccount = account
|
||||||
accounts.setCurrent(account)
|
AccountsModel.shared.setCurrent(account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,15 @@ import Combine
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class MenuModel: ObservableObject {
|
final class MenuModel: ObservableObject {
|
||||||
@Published var accounts: AccountsModel? { didSet { registerChildModel(accounts) } }
|
static let shared = MenuModel()
|
||||||
@Published var navigation: NavigationModel? { didSet { registerChildModel(navigation) } }
|
|
||||||
@Published var player: PlayerModel? { didSet { registerChildModel(player) } }
|
|
||||||
|
|
||||||
private var cancellables = [AnyCancellable]()
|
private var cancellables = [AnyCancellable]()
|
||||||
|
|
||||||
|
init() {
|
||||||
|
registerChildModel(AccountsModel.shared)
|
||||||
|
registerChildModel(NavigationModel.shared)
|
||||||
|
registerChildModel(PlayerModel.shared)
|
||||||
|
}
|
||||||
|
|
||||||
func registerChildModel<T: ObservableObject>(_ model: T?) {
|
func registerChildModel<T: ObservableObject>(_ model: T?) {
|
||||||
guard !model.isNil else {
|
guard !model.isNil else {
|
||||||
return
|
return
|
||||||
|
@ -2,7 +2,11 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class NavigationModel: ObservableObject {
|
final class NavigationModel: ObservableObject {
|
||||||
static var shared: NavigationModel!
|
static var shared = NavigationModel()
|
||||||
|
|
||||||
|
var player = PlayerModel.shared
|
||||||
|
var recents = RecentsModel.shared
|
||||||
|
var search = SearchModel.shared
|
||||||
|
|
||||||
enum TabSelection: Hashable {
|
enum TabSelection: Hashable {
|
||||||
case home
|
case home
|
||||||
@ -89,21 +93,15 @@ final class NavigationModel: ObservableObject {
|
|||||||
|
|
||||||
@Published var presentingFileImporter = false
|
@Published var presentingFileImporter = false
|
||||||
|
|
||||||
static func openChannel(
|
func openChannel(_ channel: Channel, navigationStyle: NavigationStyle) {
|
||||||
_ channel: Channel,
|
|
||||||
player: PlayerModel,
|
|
||||||
recents: RecentsModel,
|
|
||||||
navigation: NavigationModel,
|
|
||||||
navigationStyle: NavigationStyle
|
|
||||||
) {
|
|
||||||
guard channel.id != Video.fixtureChannelID else {
|
guard channel.id != Video.fixtureChannelID else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
navigation.hideKeyboard()
|
hideKeyboard()
|
||||||
let presentingPlayer = player.presentingPlayer
|
let presentingPlayer = player.presentingPlayer
|
||||||
player.hide()
|
player.hide()
|
||||||
navigation.presentingChannel = false
|
presentingChannel = false
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
Windows.main.open()
|
Windows.main.open()
|
||||||
@ -113,8 +111,8 @@ final class NavigationModel: ObservableObject {
|
|||||||
recents.add(RecentItem(from: channel))
|
recents.add(RecentItem(from: channel))
|
||||||
|
|
||||||
if navigationStyle == .sidebar {
|
if navigationStyle == .sidebar {
|
||||||
navigation.sidebarSectionChanged.toggle()
|
sidebarSectionChanged.toggle()
|
||||||
navigation.tabSelection = .recentlyOpened(recent.tag)
|
tabSelection = .recentlyOpened(recent.tag)
|
||||||
} else {
|
} else {
|
||||||
var delay = 0.0
|
var delay = 0.0
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -122,21 +120,15 @@ final class NavigationModel: ObservableObject {
|
|||||||
#endif
|
#endif
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||||
withAnimation(Constants.overlayAnimation) {
|
withAnimation(Constants.overlayAnimation) {
|
||||||
navigation.presentingChannel = true
|
self.presentingChannel = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func openChannelPlaylist(
|
func openChannelPlaylist(_ playlist: ChannelPlaylist, navigationStyle: NavigationStyle) {
|
||||||
_ playlist: ChannelPlaylist,
|
presentingChannel = false
|
||||||
player: PlayerModel,
|
presentingPlaylist = false
|
||||||
recents: RecentsModel,
|
|
||||||
navigation: NavigationModel,
|
|
||||||
navigationStyle: NavigationStyle
|
|
||||||
) {
|
|
||||||
navigation.presentingChannel = false
|
|
||||||
navigation.presentingPlaylist = false
|
|
||||||
|
|
||||||
let recent = RecentItem(from: playlist)
|
let recent = RecentItem(from: playlist)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ -145,16 +137,17 @@ final class NavigationModel: ObservableObject {
|
|||||||
player.hide()
|
player.hide()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
navigation.hideKeyboard()
|
hideKeyboard()
|
||||||
let presentingPlayer = player.presentingPlayer
|
let presentingPlayer = player.presentingPlayer
|
||||||
player.hide()
|
player.hide()
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
|
||||||
recents.add(recent)
|
guard let self else { return }
|
||||||
|
self.recents.add(recent)
|
||||||
|
|
||||||
if navigationStyle == .sidebar {
|
if navigationStyle == .sidebar {
|
||||||
navigation.sidebarSectionChanged.toggle()
|
self.sidebarSectionChanged.toggle()
|
||||||
navigation.tabSelection = .recentlyOpened(recent.tag)
|
self.tabSelection = .recentlyOpened(recent.tag)
|
||||||
} else {
|
} else {
|
||||||
var delay = 0.0
|
var delay = 0.0
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -162,25 +155,19 @@ final class NavigationModel: ObservableObject {
|
|||||||
#endif
|
#endif
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||||
withAnimation(Constants.overlayAnimation) {
|
withAnimation(Constants.overlayAnimation) {
|
||||||
navigation.presentingPlaylist = true
|
self.presentingPlaylist = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func openSearchQuery(
|
func openSearchQuery(_ searchQuery: String?) {
|
||||||
_ searchQuery: String?,
|
presentingChannel = false
|
||||||
player: PlayerModel,
|
presentingPlaylist = false
|
||||||
recents: RecentsModel,
|
tabSelection = .search
|
||||||
navigation: NavigationModel,
|
|
||||||
search: SearchModel
|
|
||||||
) {
|
|
||||||
navigation.presentingChannel = false
|
|
||||||
navigation.presentingPlaylist = false
|
|
||||||
navigation.tabSelection = .search
|
|
||||||
|
|
||||||
navigation.hideKeyboard()
|
hideKeyboard()
|
||||||
|
|
||||||
let presentingPlayer = player.presentingPlayer
|
let presentingPlayer = player.presentingPlayer
|
||||||
player.hide()
|
player.hide()
|
||||||
@ -193,9 +180,10 @@ final class NavigationModel: ObservableObject {
|
|||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
if presentingPlayer { delay = 1.0 }
|
if presentingPlayer { delay = 1.0 }
|
||||||
#endif
|
#endif
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||||
search.queryText = searchQuery
|
guard let self else { return }
|
||||||
search.changeQuery { query in query.query = searchQuery }
|
self.search.queryText = searchQuery
|
||||||
|
self.search.changeQuery { query in query.query = searchQuery }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ struct OpenVideosModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var canOpenVideosByID: Bool {
|
var canOpenVideosByID: Bool {
|
||||||
guard let app = player.accounts.current?.app else { return false }
|
guard let app = AccountsModel.shared.current?.app else { return false }
|
||||||
return !player.accounts.isEmpty && app.supportsOpeningVideosByID
|
return !AccountsModel.shared.isEmpty && app.supportsOpeningVideosByID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
|
|
||||||
private var logger = Logger(label: "avplayer-backend")
|
private var logger = Logger(label: "avplayer-backend")
|
||||||
|
|
||||||
var model: PlayerModel! { .shared }
|
var model: PlayerModel { .shared }
|
||||||
var controls: PlayerControlsModel! { .shared }
|
var controls: PlayerControlsModel { .shared }
|
||||||
var playerTime: PlayerTimeModel! { .shared }
|
var playerTime: PlayerTimeModel { .shared }
|
||||||
var networkState: NetworkStateModel! { .shared }
|
var networkState: NetworkStateModel { .shared }
|
||||||
var seek: SeekModel! { .shared }
|
var seek: SeekModel { .shared }
|
||||||
|
|
||||||
var stream: Stream?
|
var stream: Stream?
|
||||||
var video: Video?
|
var video: Video?
|
||||||
|
@ -13,11 +13,11 @@ final class MPVBackend: PlayerBackend {
|
|||||||
|
|
||||||
private var logger = Logger(label: "mpv-backend")
|
private var logger = Logger(label: "mpv-backend")
|
||||||
|
|
||||||
var model: PlayerModel! { .shared }
|
var model: PlayerModel { .shared }
|
||||||
var controls: PlayerControlsModel! { .shared }
|
var controls: PlayerControlsModel { .shared }
|
||||||
var playerTime: PlayerTimeModel! { .shared }
|
var playerTime: PlayerTimeModel { .shared }
|
||||||
var networkState: NetworkStateModel! { .shared }
|
var networkState: NetworkStateModel { .shared }
|
||||||
var seek: SeekModel! { .shared }
|
var seek: SeekModel { .shared }
|
||||||
|
|
||||||
var stream: Stream?
|
var stream: Stream?
|
||||||
var video: Video?
|
var video: Video?
|
||||||
@ -37,9 +37,9 @@ final class MPVBackend: PlayerBackend {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.controls?.isLoadingVideo = self.isLoadingVideo
|
self.controls.isLoadingVideo = self.isLoadingVideo
|
||||||
self.setNeedsNetworkStateUpdates(true)
|
self.setNeedsNetworkStateUpdates(true)
|
||||||
self.model?.objectWillChange.send()
|
self.model.objectWillChange.send()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ final class MPVBackend: PlayerBackend {
|
|||||||
isPlaying = true
|
isPlaying = true
|
||||||
startClientUpdates()
|
startClientUpdates()
|
||||||
|
|
||||||
if controls?.presentingControls ?? false {
|
if controls.presentingControls {
|
||||||
startControlsUpdates()
|
startControlsUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,9 +428,9 @@ final class MPVBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateControlsIsPlaying() {
|
private func updateControlsIsPlaying() {
|
||||||
guard model?.activeBackend == .mpv else { return }
|
guard model.activeBackend == .mpv else { return }
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.controls?.isPlaying = self?.isPlaying ?? false
|
self?.controls.isPlaying = self?.isPlaying ?? false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,14 +533,11 @@ final class MPVBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateNetworkState() {
|
func updateNetworkState() {
|
||||||
guard let client, let networkState else {
|
DispatchQueue.main.async { [weak self] in
|
||||||
return
|
guard let self else { return }
|
||||||
}
|
self.networkState.pausedForCache = self.client.pausedForCache
|
||||||
|
self.networkState.cacheDuration = self.client.cacheDuration
|
||||||
DispatchQueue.main.async {
|
self.networkState.bufferingState = self.client.bufferingState
|
||||||
networkState.pausedForCache = client.pausedForCache
|
|
||||||
networkState.cacheDuration = client.cacheDuration
|
|
||||||
networkState.bufferingState = client.bufferingState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !networkState.needsUpdates {
|
if !networkState.needsUpdates {
|
||||||
|
@ -312,7 +312,8 @@ final class MPVClient: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self, let model = self.backend.model else { return }
|
guard let self else { return }
|
||||||
|
let model = self.backend.model
|
||||||
UIView.animate(withDuration: 0.2, animations: {
|
UIView.animate(withDuration: 0.2, animations: {
|
||||||
let aspectRatio = self.aspectRatio > 0 && self.aspectRatio < VideoPlayerView.defaultAspectRatio ? self.aspectRatio : VideoPlayerView.defaultAspectRatio
|
let aspectRatio = self.aspectRatio > 0 && self.aspectRatio < VideoPlayerView.defaultAspectRatio ? self.aspectRatio : VideoPlayerView.defaultAspectRatio
|
||||||
let height = [model.playerSize.height, model.playerSize.width / aspectRatio].min()!
|
let height = [model.playerSize.height, model.playerSize.width / aspectRatio].min()!
|
||||||
@ -329,7 +330,7 @@ final class MPVClient: ObservableObject {
|
|||||||
self.glView?.queue.async {
|
self.glView?.queue.async {
|
||||||
self.glView.display()
|
self.glView.display()
|
||||||
}
|
}
|
||||||
self.backend?.controls?.objectWillChange.send()
|
self.backend?.controls.objectWillChange.send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ import Foundation
|
|||||||
|
|
||||||
protocol PlayerBackend {
|
protocol PlayerBackend {
|
||||||
var suggestedPlaybackRates: [Double] { get }
|
var suggestedPlaybackRates: [Double] { get }
|
||||||
var model: PlayerModel! { get }
|
var model: PlayerModel { get }
|
||||||
var controls: PlayerControlsModel! { get }
|
var controls: PlayerControlsModel { get }
|
||||||
var playerTime: PlayerTimeModel! { get }
|
var playerTime: PlayerTimeModel { get }
|
||||||
var networkState: NetworkStateModel! { get }
|
var networkState: NetworkStateModel { get }
|
||||||
|
|
||||||
var stream: Stream? { get set }
|
var stream: Stream? { get set }
|
||||||
var video: Video? { get set }
|
var video: Video? { get set }
|
||||||
|
@ -45,7 +45,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static var shared: PlayerModel!
|
static var shared = PlayerModel()
|
||||||
|
|
||||||
let logger = Logger(label: "stream.yattee.app")
|
let logger = Logger(label: "stream.yattee.app")
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var playerBackendView = PlayerBackendView()
|
lazy var playerBackendView = PlayerBackendView()
|
||||||
|
|
||||||
@Published var playerSize: CGSize = .zero { didSet {
|
@Published var playerSize: CGSize = .zero { didSet {
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
@ -125,13 +125,12 @@ final class PlayerModel: ObservableObject {
|
|||||||
@Default(.rotateToPortraitOnExitFullScreen) private var rotateToPortraitOnExitFullScreen
|
@Default(.rotateToPortraitOnExitFullScreen) private var rotateToPortraitOnExitFullScreen
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var accounts: AccountsModel
|
var comments: CommentsModel { .shared }
|
||||||
var comments: CommentsModel
|
|
||||||
var controls: PlayerControlsModel { .shared }
|
var controls: PlayerControlsModel { .shared }
|
||||||
var playerTime: PlayerTimeModel { .shared }
|
var playerTime: PlayerTimeModel { .shared }
|
||||||
var networkState: NetworkStateModel { .shared }
|
var networkState: NetworkStateModel { .shared }
|
||||||
var seek: SeekModel { .shared }
|
var seek: SeekModel { .shared }
|
||||||
var navigation: NavigationModel
|
var navigation: NavigationModel { .shared }
|
||||||
|
|
||||||
var context: NSManagedObjectContext = PersistenceController.shared.container.viewContext
|
var context: NSManagedObjectContext = PersistenceController.shared.container.viewContext
|
||||||
var backgroundContext = PersistenceController.shared.container.newBackgroundContext()
|
var backgroundContext = PersistenceController.shared.container.newBackgroundContext()
|
||||||
@ -173,15 +172,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
var onPresentPlayer = [() -> Void]()
|
var onPresentPlayer = [() -> Void]()
|
||||||
private var remoteCommandCenterConfigured = false
|
private var remoteCommandCenterConfigured = false
|
||||||
|
|
||||||
init(
|
init() {
|
||||||
accounts: AccountsModel = AccountsModel(),
|
|
||||||
comments: CommentsModel = CommentsModel(),
|
|
||||||
navigation: NavigationModel = NavigationModel()
|
|
||||||
) {
|
|
||||||
self.accounts = accounts
|
|
||||||
self.comments = comments
|
|
||||||
self.navigation = navigation
|
|
||||||
|
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
mpvBackend.controller = mpvController
|
mpvBackend.controller = mpvController
|
||||||
mpvBackend.client = mpvController.client
|
mpvBackend.client = mpvController.client
|
||||||
|
@ -83,11 +83,11 @@ extension PlayerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var playerInstance: Instance? {
|
var playerInstance: Instance? {
|
||||||
InstancesModel.forPlayer ?? accounts.current?.instance ?? InstancesModel.all.first
|
InstancesModel.shared.forPlayer ?? AccountsModel.shared.current?.instance ?? InstancesModel.shared.all.first
|
||||||
}
|
}
|
||||||
|
|
||||||
var playerAPI: VideosAPI {
|
var playerAPI: VideosAPI {
|
||||||
playerInstance?.anonymous ?? accounts.api
|
playerInstance?.anonymous ?? AccountsModel.shared.api
|
||||||
}
|
}
|
||||||
|
|
||||||
var qualityProfile: QualityProfile? {
|
var qualityProfile: QualityProfile? {
|
||||||
@ -269,7 +269,7 @@ extension PlayerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadQueueVideoDetails(_ item: PlayerQueueItem) {
|
func loadQueueVideoDetails(_ item: PlayerQueueItem) {
|
||||||
guard !accounts.current.isNil, !item.hasDetailsLoaded else { return }
|
guard !AccountsModel.shared.current.isNil, !item.hasDetailsLoaded else { return }
|
||||||
|
|
||||||
let videoID = item.video?.videoID ?? item.videoID
|
let videoID = item.video?.videoID ?? item.videoID
|
||||||
|
|
||||||
|
@ -9,14 +9,14 @@ final class PlayerTimeModel: ObservableObject {
|
|||||||
@Published var currentTime = CMTime.zero
|
@Published var currentTime = CMTime.zero
|
||||||
@Published var duration = CMTime.zero
|
@Published var duration = CMTime.zero
|
||||||
|
|
||||||
var player: PlayerModel!
|
var player: PlayerModel { .shared }
|
||||||
|
|
||||||
var forceHours: Bool {
|
var forceHours: Bool {
|
||||||
duration.seconds >= 60 * 60
|
duration.seconds >= 60 * 60
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentPlaybackTime: String {
|
var currentPlaybackTime: String {
|
||||||
if player?.currentItem.isNil ?? true || duration.seconds.isZero {
|
if player.currentItem.isNil || duration.seconds.isZero {
|
||||||
return Self.timePlaceholder
|
return Self.timePlaceholder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ final class PlayerTimeModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var durationPlaybackTime: String {
|
var durationPlaybackTime: String {
|
||||||
if player?.currentItem.isNil ?? true {
|
if player.currentItem.isNil {
|
||||||
return Self.timePlaceholder
|
return Self.timePlaceholder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ final class PlayerTimeModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var withoutSegmentsPlaybackTime: String {
|
var withoutSegmentsPlaybackTime: String {
|
||||||
guard let withoutSegmentsDuration = player?.playerItemDurationWithoutSponsorSegments?.seconds else { return Self.timePlaceholder }
|
guard let withoutSegmentsDuration = player.playerItemDurationWithoutSponsorSegments?.seconds else { return Self.timePlaceholder }
|
||||||
return withoutSegmentsDuration.formattedAsPlaybackTime(forceHours: forceHours) ?? Self.timePlaceholder
|
return withoutSegmentsDuration.formattedAsPlaybackTime(forceHours: forceHours) ?? Self.timePlaceholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,12 @@ import Siesta
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class PlaylistsModel: ObservableObject {
|
final class PlaylistsModel: ObservableObject {
|
||||||
|
static var shared = PlaylistsModel()
|
||||||
|
|
||||||
@Published var playlists = [Playlist]()
|
@Published var playlists = [Playlist]()
|
||||||
@Published var reloadPlaylists = false
|
@Published var reloadPlaylists = false
|
||||||
|
|
||||||
var accounts = AccountsModel()
|
var accounts = AccountsModel.shared
|
||||||
|
|
||||||
init(_ playlists: [Playlist] = [Playlist]()) {
|
init(_ playlists: [Playlist] = [Playlist]()) {
|
||||||
self.playlists = playlists
|
self.playlists = playlists
|
||||||
@ -63,14 +65,13 @@ final class PlaylistsModel: ObservableObject {
|
|||||||
playlistID: Playlist.ID,
|
playlistID: Playlist.ID,
|
||||||
videoID: Video.ID,
|
videoID: Video.ID,
|
||||||
onSuccess: @escaping () -> Void = {},
|
onSuccess: @escaping () -> Void = {},
|
||||||
navigation: NavigationModel?,
|
|
||||||
onFailure: ((RequestError) -> Void)? = nil
|
onFailure: ((RequestError) -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
accounts.api.addVideoToPlaylist(
|
accounts.api.addVideoToPlaylist(
|
||||||
videoID,
|
videoID,
|
||||||
playlistID,
|
playlistID,
|
||||||
onFailure: onFailure ?? { requestError in
|
onFailure: onFailure ?? { requestError in
|
||||||
navigation?.presentAlert(
|
NavigationModel.shared.presentAlert(
|
||||||
title: "Error when adding to playlist",
|
title: "Error when adding to playlist",
|
||||||
message: "(\(requestError.httpStatusCode ?? -1)) \(requestError.userMessage)"
|
message: "(\(requestError.httpStatusCode ?? -1)) \(requestError.userMessage)"
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,8 @@ import Defaults
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class RecentsModel: ObservableObject {
|
final class RecentsModel: ObservableObject {
|
||||||
|
static var shared = RecentsModel()
|
||||||
|
|
||||||
@Default(.recentlyOpened) var items
|
@Default(.recentlyOpened) var items
|
||||||
@Default(.saveRecents) var saveRecents
|
@Default(.saveRecents) var saveRecents
|
||||||
|
|
||||||
@ -35,9 +37,9 @@ final class RecentsModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addQuery(_ query: String, navigation: NavigationModel? = nil) {
|
func addQuery(_ query: String) {
|
||||||
if !query.isEmpty {
|
if !query.isEmpty {
|
||||||
navigation?.tabSelection = .search
|
NavigationModel.shared.tabSelection = .search
|
||||||
add(.init(from: query))
|
add(.init(from: query))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import Siesta
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class SearchModel: ObservableObject {
|
final class SearchModel: ObservableObject {
|
||||||
|
static var shared = SearchModel()
|
||||||
|
|
||||||
@Published var store = Store<[ContentItem]>()
|
@Published var store = Store<[ContentItem]>()
|
||||||
@Published var page: SearchPage?
|
@Published var page: SearchPage?
|
||||||
|
|
||||||
@ -14,7 +16,7 @@ final class SearchModel: ObservableObject {
|
|||||||
@Published var querySuggestions = [String]()
|
@Published var querySuggestions = [String]()
|
||||||
private var suggestionsDebouncer = Debouncer(.milliseconds(200))
|
private var suggestionsDebouncer = Debouncer(.milliseconds(200))
|
||||||
|
|
||||||
var accounts = AccountsModel()
|
var accounts: AccountsModel { .shared }
|
||||||
private var resource: Resource!
|
private var resource: Resource!
|
||||||
|
|
||||||
var isLoading: Bool {
|
var isLoading: Bool {
|
||||||
|
@ -2,6 +2,8 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class SettingsModel: ObservableObject {
|
final class SettingsModel: ObservableObject {
|
||||||
|
static var shared = SettingsModel()
|
||||||
|
|
||||||
@Published var presentingAlert = false
|
@Published var presentingAlert = false
|
||||||
@Published var alert = Alert(title: Text("Error"))
|
@Published var alert = Alert(title: Text("Error"))
|
||||||
|
|
||||||
|
@ -3,17 +3,15 @@ import Siesta
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class SubscriptionsModel: ObservableObject {
|
final class SubscriptionsModel: ObservableObject {
|
||||||
|
static var shared = SubscriptionsModel()
|
||||||
|
|
||||||
@Published var channels = [Channel]()
|
@Published var channels = [Channel]()
|
||||||
var accounts: AccountsModel
|
var accounts: AccountsModel { .shared }
|
||||||
|
|
||||||
var resource: Resource? {
|
var resource: Resource? {
|
||||||
accounts.api.subscriptions
|
accounts.api.subscriptions
|
||||||
}
|
}
|
||||||
|
|
||||||
init(accounts: AccountsModel? = nil) {
|
|
||||||
self.accounts = accounts ?? AccountsModel()
|
|
||||||
}
|
|
||||||
|
|
||||||
var all: [Channel] {
|
var all: [Channel] {
|
||||||
channels.sorted { $0.name.lowercased() < $1.name.lowercased() }
|
channels.sorted { $0.name.lowercased() < $1.name.lowercased() }
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ import Defaults
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class ThumbnailsModel: ObservableObject {
|
final class ThumbnailsModel: ObservableObject {
|
||||||
|
static var shared = ThumbnailsModel()
|
||||||
|
|
||||||
@Published var unloadable = Set<URL>()
|
@Published var unloadable = Set<URL>()
|
||||||
|
|
||||||
func insertUnloadable(_ url: URL) {
|
func insertUnloadable(_ url: URL) {
|
||||||
|
@ -11,9 +11,8 @@ struct FavoriteItemView: View {
|
|||||||
@Default(.favorites) private var favorites
|
@Default(.favorites) private var favorites
|
||||||
@Binding private var dragging: FavoriteItem?
|
@Binding private var dragging: FavoriteItem?
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
private var playlists = PlaylistsModel.shared
|
||||||
|
|
||||||
private var favoritesModel = FavoritesModel.shared
|
private var favoritesModel = FavoritesModel.shared
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
@ -8,7 +8,7 @@ struct HistoryView: View {
|
|||||||
@FetchRequest(sortDescriptors: [.init(key: "watchedAt", ascending: false)])
|
@FetchRequest(sortDescriptors: [.init(key: "watchedAt", ascending: false)])
|
||||||
var watches: FetchedResults<Watch>
|
var watches: FetchedResults<Watch>
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
|
@ -4,8 +4,7 @@ import SwiftUI
|
|||||||
import UniformTypeIdentifiers
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
struct HomeView: View {
|
struct HomeView: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
|
||||||
|
|
||||||
@State private var dragging: FavoriteItem?
|
@State private var dragging: FavoriteItem?
|
||||||
@State private var presentingEditFavorites = false
|
@State private var presentingEditFavorites = false
|
||||||
|
@ -12,7 +12,7 @@ struct MenuCommands: Commands {
|
|||||||
|
|
||||||
private var openVideosMenu: some Commands {
|
private var openVideosMenu: some Commands {
|
||||||
CommandGroup(after: .newItem) {
|
CommandGroup(after: .newItem) {
|
||||||
Button("Open Videos...") { model.navigation?.presentingOpenVideos = true }
|
Button("Open Videos...") { NavigationModel.shared.presentingOpenVideos = true }
|
||||||
.keyboardShortcut("t")
|
.keyboardShortcut("t")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ struct MenuCommands: Commands {
|
|||||||
Button("Popular") {
|
Button("Popular") {
|
||||||
setTabSelection(.popular)
|
setTabSelection(.popular)
|
||||||
}
|
}
|
||||||
.disabled(!(model.accounts?.app.supportsPopular ?? false))
|
.disabled(!AccountsModel.shared.app.supportsPopular)
|
||||||
.keyboardShortcut("3")
|
.keyboardShortcut("3")
|
||||||
|
|
||||||
Button("Trending") {
|
Button("Trending") {
|
||||||
@ -51,36 +51,30 @@ struct MenuCommands: Commands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setTabSelection(_ tabSelection: NavigationModel.TabSelection) {
|
private func setTabSelection(_ tabSelection: NavigationModel.TabSelection) {
|
||||||
guard let navigation = model.navigation else {
|
NavigationModel.shared.sidebarSectionChanged.toggle()
|
||||||
return
|
NavigationModel.shared.tabSelection = tabSelection
|
||||||
}
|
|
||||||
|
|
||||||
navigation.sidebarSectionChanged.toggle()
|
|
||||||
navigation.tabSelection = tabSelection
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var subscriptionsDisabled: Bool {
|
private var subscriptionsDisabled: Bool {
|
||||||
!(
|
!(AccountsModel.shared.app.supportsSubscriptions && AccountsModel.shared.signedIn)
|
||||||
(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((PlayerModel.shared.isPlaying) ? "Pause" : "Play") {
|
||||||
model.player?.togglePlay()
|
PlayerModel.shared.togglePlay()
|
||||||
}
|
}
|
||||||
.disabled(model.player?.currentItem.isNil ?? true)
|
.disabled(PlayerModel.shared.currentItem.isNil)
|
||||||
.keyboardShortcut("p")
|
.keyboardShortcut("p")
|
||||||
|
|
||||||
Button("Play Next") {
|
Button("Play Next") {
|
||||||
model.player?.advanceToNextItem()
|
PlayerModel.shared.advanceToNextItem()
|
||||||
}
|
}
|
||||||
.disabled(model.player?.queue.isEmpty ?? true)
|
.disabled(PlayerModel.shared.queue.isEmpty)
|
||||||
.keyboardShortcut("s")
|
.keyboardShortcut("s")
|
||||||
|
|
||||||
Button(togglePlayerLabel) {
|
Button(togglePlayerLabel) {
|
||||||
model.player?.togglePlayer()
|
PlayerModel.shared.togglePlayer()
|
||||||
}
|
}
|
||||||
.keyboardShortcut("o")
|
.keyboardShortcut("o")
|
||||||
}
|
}
|
||||||
@ -90,7 +84,7 @@ struct MenuCommands: Commands {
|
|||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
"Show Player"
|
"Show Player"
|
||||||
#else
|
#else
|
||||||
(model.player?.presentingPlayer ?? true) ? "Hide Player" : "Show Player"
|
PlayerModel.shared.presentingPlayer ? "Hide Player" : "Show Player"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AccountsMenuView: View {
|
struct AccountsMenuView: View {
|
||||||
@EnvironmentObject<AccountsModel> private var model
|
@ObservedObject private var model = AccountsModel.shared
|
||||||
|
|
||||||
@Default(.accounts) private var accounts
|
@Default(.accounts) private var accounts
|
||||||
@Default(.instances) private var instances
|
@Default(.instances) private var instances
|
||||||
|
@ -5,20 +5,11 @@ import SwiftUI
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct AppSidebarNavigation: View {
|
struct AppSidebarNavigation: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
private var navigation: NavigationModel { .shared }
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@State private var didApplyPrimaryViewWorkAround = false
|
@State private var didApplyPrimaryViewWorkAround = false
|
||||||
|
|
||||||
@EnvironmentObject<CommentsModel> private var comments
|
|
||||||
@EnvironmentObject<InstancesModel> private var instances
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SearchModel> private var search
|
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
@EnvironmentObject<ThumbnailsModel> private var thumbnailsModel
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@Default(.showOpenActionsToolbarItem) private var showOpenActionsToolbarItem
|
@Default(.showOpenActionsToolbarItem) private var showOpenActionsToolbarItem
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AppSidebarPlaylists: View {
|
struct AppSidebarPlaylists: View {
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
private var player = PlayerModel.shared
|
||||||
|
@ObservedObject private var playlists = PlaylistsModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Section(header: Text("Playlists")) {
|
Section(header: Text("Playlists")) {
|
||||||
@ -35,7 +36,7 @@ struct AppSidebarPlaylists: View {
|
|||||||
@ViewBuilder func playlistLabel(_ playlist: Playlist) -> some View {
|
@ViewBuilder func playlistLabel(_ playlist: Playlist) -> some View {
|
||||||
let label = Label(playlist.title, systemImage: RecentsModel.symbolSystemImage(playlist.title))
|
let label = Label(playlist.title, systemImage: RecentsModel.symbolSystemImage(playlist.title))
|
||||||
|
|
||||||
if player.accounts.app.userPlaylistsEndpointIncludesVideos, !playlist.videos.isEmpty {
|
if accounts.app.userPlaylistsEndpointIncludesVideos, !playlist.videos.isEmpty {
|
||||||
label
|
label
|
||||||
.backport
|
.backport
|
||||||
.badge(Text("\(playlist.videos.count)"))
|
.badge(Text("\(playlist.videos.count)"))
|
||||||
|
@ -2,7 +2,8 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AppSidebarRecents: View {
|
struct AppSidebarRecents: View {
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
|
var recents = RecentsModel.shared
|
||||||
|
|
||||||
@Default(.recentlyOpened) private var recentItems
|
@Default(.recentlyOpened) private var recentItems
|
||||||
|
|
||||||
@ -47,8 +48,8 @@ struct AppSidebarRecents: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct RecentNavigationLink<DestinationContent: View>: View {
|
struct RecentNavigationLink<DestinationContent: View>: View {
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
var recents = RecentsModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
|
|
||||||
var recent: RecentItem
|
var recent: RecentItem
|
||||||
var systemImage: String?
|
var systemImage: String?
|
||||||
|
@ -2,8 +2,8 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AppSidebarSubscriptions: View {
|
struct AppSidebarSubscriptions: View {
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
@ObservedObject private var subscriptions = SubscriptionsModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Section(header: Text("Subscriptions")) {
|
Section(header: Text("Subscriptions")) {
|
||||||
|
@ -2,16 +2,10 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AppTabNavigation: View {
|
struct AppTabNavigation: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<CommentsModel> private var comments
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<InstancesModel> private var instances
|
private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var subscriptions = SubscriptionsModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SearchModel> private var search
|
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
@EnvironmentObject<ThumbnailsModel> private var thumbnailsModel
|
|
||||||
|
|
||||||
@Default(.showHome) private var showHome
|
@Default(.showHome) private var showHome
|
||||||
@Default(.showDocuments) private var showDocuments
|
@Default(.showDocuments) private var showDocuments
|
||||||
@ -187,11 +181,6 @@ struct AppTabNavigation: View {
|
|||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environment(\.inChannelView, true)
|
.environment(\.inChannelView, true)
|
||||||
.environment(\.navigationStyle, .tab)
|
.environment(\.navigationStyle, .tab)
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(subscriptions)
|
|
||||||
.environmentObject(thumbnailsModel)
|
|
||||||
.id("channelVideos")
|
.id("channelVideos")
|
||||||
.zIndex(player.presentingPlayer ? -1 : 2)
|
.zIndex(player.presentingPlayer ? -1 : 2)
|
||||||
.transition(.move(edge: .bottom))
|
.transition(.move(edge: .bottom))
|
||||||
@ -202,11 +191,6 @@ struct AppTabNavigation: View {
|
|||||||
if navigation.presentingPlaylist {
|
if navigation.presentingPlaylist {
|
||||||
ChannelPlaylistView()
|
ChannelPlaylistView()
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(subscriptions)
|
|
||||||
.environmentObject(thumbnailsModel)
|
|
||||||
.id("channelPlaylist")
|
.id("channelPlaylist")
|
||||||
.zIndex(player.presentingPlayer ? -1 : 1)
|
.zIndex(player.presentingPlayer ? -1 : 1)
|
||||||
.transition(.move(edge: .bottom))
|
.transition(.move(edge: .bottom))
|
||||||
|
@ -8,19 +8,11 @@ import Siesta
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<CommentsModel> private var comments
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<InstancesModel> private var instances
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
private var playlists = PlaylistsModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
private var subscriptions = SubscriptionsModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SearchModel> private var search
|
|
||||||
@EnvironmentObject<SettingsModel> private var settings
|
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
@EnvironmentObject<ThumbnailsModel> private var thumbnailsModel
|
|
||||||
|
|
||||||
@EnvironmentObject<MenuModel> private var menu
|
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||||
@ -44,7 +36,6 @@ struct ContentView: View {
|
|||||||
AppSidebarNavigation()
|
AppSidebarNavigation()
|
||||||
#elseif os(tvOS)
|
#elseif os(tvOS)
|
||||||
TVNavigationView()
|
TVNavigationView()
|
||||||
.environmentObject(settings)
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.onChange(of: accounts.current) { _ in
|
.onChange(of: accounts.current) { _ in
|
||||||
@ -55,16 +46,6 @@ struct ContentView: View {
|
|||||||
subscriptions.load(force: true)
|
subscriptions.load(force: true)
|
||||||
playlists.load(force: true)
|
playlists.load(force: true)
|
||||||
}
|
}
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(comments)
|
|
||||||
.environmentObject(instances)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(playlists)
|
|
||||||
.environmentObject(recents)
|
|
||||||
.environmentObject(search)
|
|
||||||
.environmentObject(subscriptions)
|
|
||||||
.environmentObject(thumbnailsModel)
|
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.overlay(videoPlayer)
|
.overlay(videoPlayer)
|
||||||
@ -80,18 +61,11 @@ struct ContentView: View {
|
|||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingWelcomeScreen) {
|
EmptyView().sheet(isPresented: $navigation.presentingWelcomeScreen) {
|
||||||
WelcomeScreen()
|
WelcomeScreen()
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingSettings) {
|
EmptyView().sheet(isPresented: $navigation.presentingSettings) {
|
||||||
SettingsView()
|
SettingsView()
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(instances)
|
|
||||||
.environmentObject(settings)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(player)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
@ -125,25 +99,17 @@ struct ContentView: View {
|
|||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingAddToPlaylist) {
|
EmptyView().sheet(isPresented: $navigation.presentingAddToPlaylist) {
|
||||||
AddToPlaylistView(video: navigation.videoToAddToPlaylist)
|
AddToPlaylistView(video: navigation.videoToAddToPlaylist)
|
||||||
.environmentObject(playlists)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingPlaylistForm) {
|
EmptyView().sheet(isPresented: $navigation.presentingPlaylistForm) {
|
||||||
PlaylistFormView(playlist: $navigation.editedPlaylist)
|
PlaylistFormView(playlist: $navigation.editedPlaylist)
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(playlists)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingOpenVideos) {
|
EmptyView().sheet(isPresented: $navigation.presentingOpenVideos) {
|
||||||
OpenVideosView()
|
OpenVideosView()
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(recents)
|
|
||||||
.environmentObject(search)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.background(playerViewInitialize)
|
.background(playerViewInitialize)
|
||||||
@ -174,16 +140,6 @@ struct ContentView: View {
|
|||||||
|
|
||||||
var playerView: some View {
|
var playerView: some View {
|
||||||
VideoPlayerView()
|
VideoPlayerView()
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(comments)
|
|
||||||
.environmentObject(instances)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(playerControls)
|
|
||||||
.environmentObject(playlists)
|
|
||||||
.environmentObject(recents)
|
|
||||||
.environmentObject(subscriptions)
|
|
||||||
.environmentObject(thumbnailsModel)
|
|
||||||
.environment(\.navigationStyle, navigationStyle)
|
.environment(\.navigationStyle, navigationStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct Sidebar: View {
|
struct Sidebar: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
|
|
||||||
@Default(.showHome) private var showHome
|
@Default(.showHome) private var showHome
|
||||||
@Default(.visibleSections) private var visibleSections
|
@Default(.visibleSections) private var visibleSections
|
||||||
|
@ -7,11 +7,11 @@ struct OpenURLHandler {
|
|||||||
static var shared = OpenURLHandler()
|
static var shared = OpenURLHandler()
|
||||||
static let yatteeProtocol = "yattee://"
|
static let yatteeProtocol = "yattee://"
|
||||||
|
|
||||||
var accounts: AccountsModel!
|
var accounts: AccountsModel { .shared }
|
||||||
var navigation: NavigationModel!
|
var navigation: NavigationModel { .shared }
|
||||||
var recents: RecentsModel!
|
var recents: RecentsModel { .shared }
|
||||||
var player: PlayerModel!
|
var player: PlayerModel { .shared }
|
||||||
var search: SearchModel!
|
var search: SearchModel { .shared }
|
||||||
var navigationStyle = NavigationStyle.sidebar
|
var navigationStyle = NavigationStyle.sidebar
|
||||||
|
|
||||||
func handle(_ url: URL) {
|
func handle(_ url: URL) {
|
||||||
@ -162,11 +162,8 @@ struct OpenURLHandler {
|
|||||||
if var playlist: ChannelPlaylist = response.typedContent() {
|
if var playlist: ChannelPlaylist = response.typedContent() {
|
||||||
playlist.id = playlistID
|
playlist.id = playlistID
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
NavigationModel.openChannelPlaylist(
|
NavigationModel.shared.openChannelPlaylist(
|
||||||
playlist,
|
playlist,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -194,11 +191,8 @@ struct OpenURLHandler {
|
|||||||
.onSuccess { response in
|
.onSuccess { response in
|
||||||
if let channel: Channel = response.typedContent() {
|
if let channel: Channel = response.typedContent() {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
NavigationModel.openChannel(
|
NavigationModel.shared.openChannel(
|
||||||
channel,
|
channel,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -228,7 +222,7 @@ struct OpenURLHandler {
|
|||||||
return accounts.api.channelByName(name)
|
return accounts.api.channelByName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let instance = InstancesModel.all.first(where: { $0.app.supportsOpeningChannelsByName }) {
|
if let instance = InstancesModel.shared.all.first(where: { $0.app.supportsOpeningChannelsByName }) {
|
||||||
return instance.anonymous.channelByName(name)
|
return instance.anonymous.channelByName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +236,7 @@ struct OpenURLHandler {
|
|||||||
return accounts.api.channelByUsername(username)
|
return accounts.api.channelByUsername(username)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let instance = InstancesModel.all.first(where: { $0.app.supportsOpeningChannelsByName }) {
|
if let instance = InstancesModel.shared.all.first(where: { $0.app.supportsOpeningChannelsByName }) {
|
||||||
return instance.anonymous.channelByUsername(username)
|
return instance.anonymous.channelByUsername(username)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,13 +248,7 @@ struct OpenURLHandler {
|
|||||||
if alertIfNoMainWindowOpen() { return }
|
if alertIfNoMainWindowOpen() { return }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NavigationModel.openSearchQuery(
|
NavigationModel.shared.openSearchQuery(parser.searchQuery)
|
||||||
parser.searchQuery,
|
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
search: search
|
|
||||||
)
|
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
focusMainWindow()
|
focusMainWindow()
|
||||||
|
@ -4,11 +4,8 @@ import SwiftUI
|
|||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
struct AppleAVPlayerView: UIViewRepresentable {
|
struct AppleAVPlayerView: UIViewRepresentable {
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
|
|
||||||
func makeUIView(context _: Context) -> some UIView {
|
func makeUIView(context _: Context) -> some UIView {
|
||||||
let playerLayerView = PlayerLayerView(frame: .zero)
|
let playerLayerView = PlayerLayerView(frame: .zero)
|
||||||
playerLayerView.player = player
|
|
||||||
return playerLayerView
|
return playerLayerView
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,30 +13,15 @@ import SwiftUI
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
struct AppleAVPlayerView: UIViewControllerRepresentable {
|
struct AppleAVPlayerView: UIViewControllerRepresentable {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
|
||||||
@EnvironmentObject<CommentsModel> private var comments
|
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
|
|
||||||
func makeUIViewController(context _: Context) -> AppleAVPlayerViewController {
|
func makeUIViewController(context _: Context) -> AppleAVPlayerViewController {
|
||||||
let controller = AppleAVPlayerViewController()
|
let controller = AppleAVPlayerViewController()
|
||||||
|
PlayerModel.shared.avPlayerBackend.controller = controller
|
||||||
controller.accountsModel = accounts
|
|
||||||
controller.commentsModel = comments
|
|
||||||
controller.navigationModel = navigation
|
|
||||||
controller.playerModel = player
|
|
||||||
controller.playlistsModel = playlists
|
|
||||||
controller.subscriptionsModel = subscriptions
|
|
||||||
|
|
||||||
player.avPlayerBackend.controller = controller
|
|
||||||
|
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIViewController(_: AppleAVPlayerViewController, context _: Context) {
|
func updateUIViewController(_: AppleAVPlayerViewController, context _: Context) {
|
||||||
player.rebuildTVMenu()
|
PlayerModel.shared.rebuildTVMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,12 +4,11 @@ import SwiftUI
|
|||||||
|
|
||||||
final class AppleAVPlayerViewController: UIViewController {
|
final class AppleAVPlayerViewController: UIViewController {
|
||||||
var playerLoaded = false
|
var playerLoaded = false
|
||||||
var accountsModel: AccountsModel!
|
var accountsModel: AccountsModel { .shared }
|
||||||
var commentsModel: CommentsModel!
|
var navigationModel: NavigationModel { .shared }
|
||||||
var navigationModel: NavigationModel!
|
var playerModel: PlayerModel { .shared }
|
||||||
var playerModel: PlayerModel!
|
var playlistsModel: PlaylistsModel { .shared }
|
||||||
var playlistsModel: PlaylistsModel!
|
var subscriptionsModel: SubscriptionsModel { .shared }
|
||||||
var subscriptionsModel: SubscriptionsModel!
|
|
||||||
var playerView = AVPlayerViewController()
|
var playerView = AVPlayerViewController()
|
||||||
|
|
||||||
let persistenceController = PersistenceController.shared
|
let persistenceController = PersistenceController.shared
|
||||||
@ -66,12 +65,6 @@ final class AppleAVPlayerViewController: UIViewController {
|
|||||||
AnyView(
|
AnyView(
|
||||||
NowPlayingView(sections: sections, inInfoViewController: true)
|
NowPlayingView(sections: sections, inInfoViewController: true)
|
||||||
.frame(maxHeight: 600)
|
.frame(maxHeight: 600)
|
||||||
.environmentObject(accountsModel)
|
|
||||||
.environmentObject(commentsModel)
|
|
||||||
.environmentObject(navigationModel)
|
|
||||||
.environmentObject(playerModel)
|
|
||||||
.environmentObject(playlistsModel)
|
|
||||||
.environmentObject(subscriptionsModel)
|
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2,8 +2,8 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ControlsOverlay: View {
|
struct ControlsOverlay: View {
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<PlayerControlsModel> private var model
|
private var model = PlayerControlsModel.shared
|
||||||
|
|
||||||
@State private var contentSize: CGSize = .zero
|
@State private var contentSize: CGSize = .zero
|
||||||
|
|
||||||
@ -399,8 +399,5 @@ struct ControlsOverlay: View {
|
|||||||
struct ControlsOverlay_Previews: PreviewProvider {
|
struct ControlsOverlay_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ControlsOverlay()
|
ControlsOverlay()
|
||||||
.environmentObject(NetworkStateModel())
|
|
||||||
.environmentObject(PlayerModel())
|
|
||||||
.environmentObject(PlayerControlsModel())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ struct Buffering: View {
|
|||||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
||||||
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
||||||
|
@ -15,7 +15,5 @@ struct NetworkState_Previews: PreviewProvider {
|
|||||||
networkState.bufferingState = 30
|
networkState.bufferingState = 30
|
||||||
|
|
||||||
return NetworkState()
|
return NetworkState()
|
||||||
.environmentObject(networkState)
|
|
||||||
.environmentObject(PlayerModel())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct OpeningStream: View {
|
struct OpeningStream: View {
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<NetworkStateModel> private var model
|
@ObservedObject private var model = NetworkStateModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Buffering(reason: reason, state: state)
|
Buffering(reason: reason, state: state)
|
||||||
|
@ -6,7 +6,7 @@ struct Seek: View {
|
|||||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<PlayerControlsModel> private var controls
|
@ObservedObject private var controls = PlayerControlsModel.shared
|
||||||
@StateObject private var model = SeekModel.shared
|
@StateObject private var model = SeekModel.shared
|
||||||
|
|
||||||
private var updateThrottle = Throttle(interval: 2)
|
private var updateThrottle = Throttle(interval: 2)
|
||||||
@ -137,6 +137,5 @@ struct Seek: View {
|
|||||||
struct Seek_Previews: PreviewProvider {
|
struct Seek_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
Seek()
|
Seek()
|
||||||
.environmentObject(PlayerTimeModel())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ import SwiftUI
|
|||||||
struct PlayerControls: View {
|
struct PlayerControls: View {
|
||||||
static let animation = Animation.easeInOut(duration: 0.2)
|
static let animation = Animation.easeInOut(duration: 0.2)
|
||||||
|
|
||||||
private var player: PlayerModel!
|
private var player: PlayerModel { .shared }
|
||||||
private var thumbnails: ThumbnailsModel!
|
private var thumbnails: ThumbnailsModel { .shared }
|
||||||
|
|
||||||
@ObservedObject private var model = PlayerControlsModel.shared
|
@ObservedObject private var model = PlayerControlsModel.shared
|
||||||
|
|
||||||
@ -39,11 +39,6 @@ struct PlayerControls: View {
|
|||||||
player.playingFullScreen ? fullScreenPlayerControlsLayout : regularPlayerControlsLayout
|
player.playingFullScreen ? fullScreenPlayerControlsLayout : regularPlayerControlsLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
init(player: PlayerModel, thumbnails: ThumbnailsModel) {
|
|
||||||
self.player = player
|
|
||||||
self.thumbnails = thumbnails
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .topLeading) {
|
ZStack(alignment: .topLeading) {
|
||||||
Seek()
|
Seek()
|
||||||
@ -206,12 +201,12 @@ struct PlayerControls: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var detailsWidth: Double {
|
var detailsWidth: Double {
|
||||||
guard let player, player.playerSize.width.isFinite else { return 200 }
|
guard player.playerSize.width.isFinite else { return 200 }
|
||||||
return [player.playerSize.width, 600].min()!
|
return [player.playerSize.width, 600].min()!
|
||||||
}
|
}
|
||||||
|
|
||||||
var detailsHeight: Double {
|
var detailsHeight: Double {
|
||||||
guard let player, player.playerSize.height.isFinite else { return 200 }
|
guard player.playerSize.height.isFinite else { return 200 }
|
||||||
var inset = 0.0
|
var inset = 0.0
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
inset = SafeArea.insets.bottom
|
inset = SafeArea.insets.bottom
|
||||||
@ -499,7 +494,7 @@ struct PlayerControls_Previews: PreviewProvider {
|
|||||||
ZStack {
|
ZStack {
|
||||||
Color.gray
|
Color.gray
|
||||||
|
|
||||||
PlayerControls(player: PlayerModel(), thumbnails: ThumbnailsModel())
|
PlayerControls()
|
||||||
.injectFixtureEnvironmentObjects()
|
.injectFixtureEnvironmentObjects()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ import SwiftUI
|
|||||||
|
|
||||||
struct TVControls: UIViewRepresentable {
|
struct TVControls: UIViewRepresentable {
|
||||||
var model: PlayerControlsModel!
|
var model: PlayerControlsModel!
|
||||||
var player: PlayerModel!
|
var player: PlayerModel { .shared }
|
||||||
var thumbnails: ThumbnailsModel!
|
var thumbnails: ThumbnailsModel { .shared }
|
||||||
|
|
||||||
@State private var direction = ""
|
@State private var direction = ""
|
||||||
@State private var controlsArea = UIView()
|
@State private var controlsArea = UIView()
|
||||||
@ -30,7 +30,7 @@ struct TVControls: UIViewRepresentable {
|
|||||||
controlsArea.addGestureRecognizer(downSwipe)
|
controlsArea.addGestureRecognizer(downSwipe)
|
||||||
controlsArea.addGestureRecognizer(tap)
|
controlsArea.addGestureRecognizer(tap)
|
||||||
|
|
||||||
let controls = UIHostingController(rootView: PlayerControls(player: player, thumbnails: thumbnails))
|
let controls = UIHostingController(rootView: PlayerControls())
|
||||||
controls.view.frame = .init(
|
controls.view.frame = .init(
|
||||||
origin: .init(x: SafeArea.insets.left, y: SafeArea.insets.top),
|
origin: .init(x: SafeArea.insets.left, y: SafeArea.insets.top),
|
||||||
size: .init(
|
size: .init(
|
||||||
|
@ -45,9 +45,9 @@ struct TimelineView: View {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ObservedObject private var playerTime = PlayerTimeModel.shared
|
@ObservedObject private var playerTime = PlayerTimeModel.shared
|
||||||
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
private var controls = PlayerControlsModel.shared
|
||||||
@EnvironmentObject<PlayerControlsModel> private var controls
|
|
||||||
|
|
||||||
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
||||||
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
||||||
@ -124,6 +124,8 @@ struct TimelineView: View {
|
|||||||
.frame(minWidth: 35)
|
.frame(minWidth: 35)
|
||||||
.padding(.leading, playerControlsLayout.timeLeadingEdgePadding)
|
.padding(.leading, playerControlsLayout.timeLeadingEdgePadding)
|
||||||
.padding(.trailing, playerControlsLayout.timeTrailingEdgePadding)
|
.padding(.trailing, playerControlsLayout.timeTrailingEdgePadding)
|
||||||
|
.modifier(ControlBackgroundModifier())
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||||
|
|
||||||
ZStack(alignment: .center) {
|
ZStack(alignment: .center) {
|
||||||
ZStack(alignment: .leading) {
|
ZStack(alignment: .leading) {
|
||||||
@ -172,6 +174,8 @@ struct TimelineView: View {
|
|||||||
.padding(.leading, playerControlsLayout.timeTrailingEdgePadding)
|
.padding(.leading, playerControlsLayout.timeTrailingEdgePadding)
|
||||||
.padding(.trailing, playerControlsLayout.timeLeadingEdgePadding)
|
.padding(.trailing, playerControlsLayout.timeLeadingEdgePadding)
|
||||||
.frame(minWidth: 30, alignment: .trailing)
|
.frame(minWidth: 30, alignment: .trailing)
|
||||||
|
.modifier(ControlBackgroundModifier())
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.highPriorityGesture(
|
.highPriorityGesture(
|
||||||
@ -207,8 +211,6 @@ struct TimelineView: View {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
.modifier(ControlBackgroundModifier())
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
|
||||||
.font(.system(size: playerControlsLayout.timeFontSize).monospacedDigit())
|
.font(.system(size: playerControlsLayout.timeFontSize).monospacedDigit())
|
||||||
.zIndex(2)
|
.zIndex(2)
|
||||||
}
|
}
|
||||||
@ -369,14 +371,11 @@ struct TimelineView_Previews: PreviewProvider {
|
|||||||
let playerModel = PlayerModel()
|
let playerModel = PlayerModel()
|
||||||
playerModel.currentItem = .init(Video.fixture)
|
playerModel.currentItem = .init(Video.fixture)
|
||||||
let playerTimeModel = PlayerTimeModel.shared
|
let playerTimeModel = PlayerTimeModel.shared
|
||||||
playerTimeModel.player = playerModel
|
|
||||||
playerTimeModel.currentTime = .secondsInDefaultTimescale(33)
|
playerTimeModel.currentTime = .secondsInDefaultTimescale(33)
|
||||||
playerTimeModel.duration = .secondsInDefaultTimescale(100)
|
playerTimeModel.duration = .secondsInDefaultTimescale(100)
|
||||||
return VStack(spacing: 40) {
|
return VStack(spacing: 40) {
|
||||||
TimelineView()
|
TimelineView()
|
||||||
}
|
}
|
||||||
.environmentObject(playerModel)
|
|
||||||
.environmentObject(PlayerControlsModel())
|
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct VideoDetailsOverlay: View {
|
struct VideoDetailsOverlay: View {
|
||||||
@EnvironmentObject<PlayerControlsModel> private var controls
|
@ObservedObject private var controls = PlayerControlsModel.shared
|
||||||
|
|
||||||
@State private var detailsPage = VideoDetails.DetailsPage.queue
|
@State private var detailsPage = VideoDetails.DetailsPage.queue
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ struct PlayerBackendView: View {
|
|||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||||
#endif
|
#endif
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<ThumbnailsModel> private var thumbnails
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
@ -29,7 +28,7 @@ struct PlayerBackendView: View {
|
|||||||
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
PlayerGestures()
|
PlayerGestures()
|
||||||
PlayerControls(player: player, thumbnails: thumbnails)
|
PlayerControls()
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.padding(.top, controlsTopPadding)
|
.padding(.top, controlsTopPadding)
|
||||||
.padding(.bottom, controlsBottomPadding)
|
.padding(.bottom, controlsBottomPadding)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct PlayerGestures: View {
|
struct PlayerGestures: View {
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<PlayerControlsModel> private var model
|
@ObservedObject private var model = PlayerControlsModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
|
@ -8,7 +8,7 @@ import Foundation
|
|||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
final class PlayerLayerView: NSView {
|
final class PlayerLayerView: NSView {
|
||||||
var player: PlayerModel! { didSet {
|
var player = PlayerModel.shared { didSet {
|
||||||
wantsLayer = true
|
wantsLayer = true
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
final class PlayerLayerView: UIView {
|
final class PlayerLayerView: UIView {
|
||||||
var player: PlayerModel!
|
var player: PlayerModel { .shared }
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
@ -9,7 +9,7 @@ struct PlayerQueueRow: View {
|
|||||||
var autoplay = false
|
var autoplay = false
|
||||||
@Binding var fullScreen: Bool
|
@Binding var fullScreen: Bool
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
private var player = PlayerModel.shared
|
||||||
|
|
||||||
@Default(.closePiPOnNavigation) var closePiPOnNavigation
|
@Default(.closePiPOnNavigation) var closePiPOnNavigation
|
||||||
|
|
||||||
|
@ -2,10 +2,7 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct RelatedView: View {
|
struct RelatedView: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
|
@ -9,7 +9,7 @@ struct StreamControl: View {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
|
@ -5,7 +5,7 @@ import SwiftUI
|
|||||||
struct ChapterView: View {
|
struct ChapterView: View {
|
||||||
var chapter: Chapter
|
var chapter: Chapter
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
var player = PlayerModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
Button {
|
||||||
|
@ -3,7 +3,7 @@ import SDWebImageSwiftUI
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ChaptersView: View {
|
struct ChaptersView: View {
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if let chapters = player.currentVideo?.chapters, !chapters.isEmpty {
|
if let chapters = player.currentVideo?.chapters, !chapters.isEmpty {
|
||||||
|
@ -14,11 +14,8 @@ struct CommentView: View {
|
|||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<CommentsModel> private var comments
|
@ObservedObject private var comments = CommentsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
var subscriptions = SubscriptionsModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
@ -252,11 +249,8 @@ struct CommentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func openChannelAction() {
|
private func openChannelAction() {
|
||||||
NavigationModel.openChannel(
|
NavigationModel.shared.openChannel(
|
||||||
comment.channel,
|
comment.channel,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -269,7 +263,6 @@ struct CommentView_Previews: PreviewProvider {
|
|||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
CommentView(comment: fixture, repliesID: .constant(fixture.id))
|
CommentView(comment: fixture, repliesID: .constant(fixture.id))
|
||||||
.environmentObject(SubscriptionsModel())
|
|
||||||
.padding(5)
|
.padding(5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ struct CommentsView: View {
|
|||||||
var embedInScrollView = false
|
var embedInScrollView = false
|
||||||
@State private var repliesID: Comment.ID?
|
@State private var repliesID: Comment.ID?
|
||||||
|
|
||||||
@EnvironmentObject<CommentsModel> private var comments
|
@ObservedObject private var comments = CommentsModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
|
@ -3,7 +3,7 @@ import SwiftUI
|
|||||||
struct InspectorView: View {
|
struct InspectorView: View {
|
||||||
var video: Video?
|
var video: Video?
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
|
@ -9,10 +9,7 @@ struct PlayerQueueView: View {
|
|||||||
@FetchRequest(sortDescriptors: [.init(key: "watchedAt", ascending: false)])
|
@FetchRequest(sortDescriptors: [.init(key: "watchedAt", ascending: false)])
|
||||||
var watches: FetchedResults<Watch>
|
var watches: FetchedResults<Watch>
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
|
|
||||||
@Default(.saveHistory) private var saveHistory
|
@Default(.saveHistory) private var saveHistory
|
||||||
|
|
||||||
|
@ -2,10 +2,10 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct VideoActions: View {
|
struct VideoActions: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
@ObservedObject private var subscriptions = SubscriptionsModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
var video: Video?
|
var video: Video?
|
||||||
|
|
||||||
|
@ -6,10 +6,7 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct VideoDescription: View {
|
struct VideoDescription: View {
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
private var search: SearchModel { .shared }
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SearchModel> private var search
|
|
||||||
@Default(.showKeywords) private var showKeywords
|
@Default(.showKeywords) private var showKeywords
|
||||||
|
|
||||||
var video: Video
|
var video: Video
|
||||||
@ -56,7 +53,7 @@ struct VideoDescription: View {
|
|||||||
HStack {
|
HStack {
|
||||||
ForEach(video.keywords, id: \.self) { keyword in
|
ForEach(video.keywords, id: \.self) { keyword in
|
||||||
Button {
|
Button {
|
||||||
NavigationModel.openSearchQuery(keyword, player: player, recents: recents, navigation: navigation, search: search)
|
NavigationModel.shared.openSearchQuery(keyword)
|
||||||
} label: {
|
} label: {
|
||||||
HStack(alignment: .center, spacing: 0) {
|
HStack(alignment: .center, spacing: 0) {
|
||||||
Text("#")
|
Text("#")
|
||||||
@ -96,7 +93,8 @@ struct VideoDescription: View {
|
|||||||
@State private var label = ActiveLabel()
|
@State private var label = ActiveLabel()
|
||||||
|
|
||||||
@Environment(\.openURL) private var openURL
|
@Environment(\.openURL) private var openURL
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
|
var player = PlayerModel.shared
|
||||||
|
|
||||||
func makeUIView(context _: Context) -> some UIView {
|
func makeUIView(context _: Context) -> some UIView {
|
||||||
customizeLabel()
|
customizeLabel()
|
||||||
|
@ -23,12 +23,9 @@ struct VideoDetails: View {
|
|||||||
|
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<CommentsModel> private var comments
|
let comments = CommentsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
|
|
||||||
@Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike
|
@Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike
|
||||||
@Default(.detailsToolbarPosition) private var detailsToolbarPosition
|
@Default(.detailsToolbarPosition) private var detailsToolbarPosition
|
||||||
@ -148,6 +145,7 @@ struct VideoDetails: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
|
.frame(maxHeight: .infinity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@State private var detailsSize = CGSize.zero
|
@State private var detailsSize = CGSize.zero
|
||||||
|
@ -13,7 +13,7 @@ struct VideoDetailsToolbar: View {
|
|||||||
@State private var startedToolPosition: CGRect = .zero
|
@State private var startedToolPosition: CGRect = .zero
|
||||||
@State private var opacity = 1.0
|
@State private var opacity = 1.0
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@Default(.playerDetailsPageButtonLabelStyle) private var playerDetailsPageButtonLabelStyle
|
@Default(.playerDetailsPageButtonLabelStyle) private var playerDetailsPageButtonLabelStyle
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -57,13 +57,10 @@ struct VideoPlayerView: View {
|
|||||||
@State internal var orientationNotification: Any?
|
@State internal var orientationNotification: Any?
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> internal var player
|
internal var player: PlayerModel! = PlayerModel.shared
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@EnvironmentObject<NavigationModel> internal var navigation
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<SearchModel> internal var search
|
|
||||||
#endif
|
|
||||||
#if os(tvOS)
|
|
||||||
@EnvironmentObject<ThumbnailsModel> private var thumbnails
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@Default(.horizontalPlayerGestureEnabled) var horizontalPlayerGestureEnabled
|
@Default(.horizontalPlayerGestureEnabled) var horizontalPlayerGestureEnabled
|
||||||
@ -482,7 +479,7 @@ struct VideoPlayerView: View {
|
|||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
var tvControls: some View {
|
var tvControls: some View {
|
||||||
TVControls(player: player, thumbnails: thumbnails)
|
TVControls()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,7 @@ struct AddToPlaylistView: View {
|
|||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@Environment(\.presentationMode) private var presentationMode
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var model = PlaylistsModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var model
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
@ -164,7 +163,7 @@ struct AddToPlaylistView: View {
|
|||||||
|
|
||||||
Defaults[.lastUsedPlaylistID] = id
|
Defaults[.lastUsedPlaylistID] = id
|
||||||
|
|
||||||
model.addVideo(playlistID: id, videoID: video.videoID, navigation: navigation)
|
model.addVideo(playlistID: id, videoID: video.videoID)
|
||||||
|
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ struct PlaylistFormView: View {
|
|||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@Environment(\.presentationMode) private var presentationMode
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
@ObservedObject private var playlists = PlaylistsModel.shared
|
||||||
|
|
||||||
var editing: Bool {
|
var editing: Bool {
|
||||||
playlist != nil
|
playlist != nil
|
||||||
|
@ -14,9 +14,9 @@ struct PlaylistsView: View {
|
|||||||
@StateObject private var channelPlaylist = Store<ChannelPlaylist>()
|
@StateObject private var channelPlaylist = Store<ChannelPlaylist>()
|
||||||
@StateObject private var userPlaylist = Store<Playlist>()
|
@StateObject private var userPlaylist = Store<Playlist>()
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var model
|
@ObservedObject private var model = PlaylistsModel.shared
|
||||||
|
|
||||||
@Namespace private var focusNamespace
|
@Namespace private var focusNamespace
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ struct PlaylistsView: View {
|
|||||||
if videos.isEmpty {
|
if videos.isEmpty {
|
||||||
videos = userPlaylist.item?.videos ?? channelPlaylist.item?.videos ?? []
|
videos = userPlaylist.item?.videos ?? channelPlaylist.item?.videos ?? []
|
||||||
|
|
||||||
if !player.accounts.app.userPlaylistsEndpointIncludesVideos {
|
if !accounts.app.userPlaylistsEndpointIncludesVideos {
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
||||||
for index in videos.indices {
|
for index in videos.indices {
|
||||||
@ -44,9 +44,9 @@ struct PlaylistsView: View {
|
|||||||
private var resource: Resource? {
|
private var resource: Resource? {
|
||||||
guard let playlist = currentPlaylist else { return nil }
|
guard let playlist = currentPlaylist else { return nil }
|
||||||
|
|
||||||
let resource = player.accounts.api.playlist(playlist.id)
|
let resource = accounts.api.playlist(playlist.id)
|
||||||
|
|
||||||
if player.accounts.app.userPlaylistsUseChannelPlaylistEndpoint {
|
if accounts.app.userPlaylistsUseChannelPlaylistEndpoint {
|
||||||
resource?.addObserver(channelPlaylist)
|
resource?.addObserver(channelPlaylist)
|
||||||
} else {
|
} else {
|
||||||
resource?.addObserver(userPlaylist)
|
resource?.addObserver(userPlaylist)
|
||||||
@ -150,11 +150,9 @@ struct PlaylistsView: View {
|
|||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.fullScreenCover(isPresented: $showingNewPlaylist, onDismiss: selectCreatedPlaylist) {
|
.fullScreenCover(isPresented: $showingNewPlaylist, onDismiss: selectCreatedPlaylist) {
|
||||||
PlaylistFormView(playlist: $createdPlaylist)
|
PlaylistFormView(playlist: $createdPlaylist)
|
||||||
.environmentObject(accounts)
|
|
||||||
}
|
}
|
||||||
.fullScreenCover(isPresented: $showingEditPlaylist, onDismiss: selectEditedPlaylist) {
|
.fullScreenCover(isPresented: $showingEditPlaylist, onDismiss: selectEditedPlaylist) {
|
||||||
PlaylistFormView(playlist: $editedPlaylist)
|
PlaylistFormView(playlist: $editedPlaylist)
|
||||||
.environmentObject(accounts)
|
|
||||||
}
|
}
|
||||||
.focusScope(focusNamespace)
|
.focusScope(focusNamespace)
|
||||||
#else
|
#else
|
||||||
@ -162,14 +160,12 @@ struct PlaylistsView: View {
|
|||||||
EmptyView()
|
EmptyView()
|
||||||
.sheet(isPresented: $showingNewPlaylist, onDismiss: selectCreatedPlaylist) {
|
.sheet(isPresented: $showingNewPlaylist, onDismiss: selectCreatedPlaylist) {
|
||||||
PlaylistFormView(playlist: $createdPlaylist)
|
PlaylistFormView(playlist: $createdPlaylist)
|
||||||
.environmentObject(accounts)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
EmptyView()
|
EmptyView()
|
||||||
.sheet(isPresented: $showingEditPlaylist, onDismiss: selectEditedPlaylist) {
|
.sheet(isPresented: $showingEditPlaylist, onDismiss: selectEditedPlaylist) {
|
||||||
PlaylistFormView(playlist: $editedPlaylist)
|
PlaylistFormView(playlist: $editedPlaylist)
|
||||||
.environmentObject(accounts)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,9 +4,8 @@ import SwiftUI
|
|||||||
struct SearchTextField: View {
|
struct SearchTextField: View {
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
@ObservedObject private var state = SearchModel.shared
|
||||||
@EnvironmentObject<SearchModel> private var state
|
|
||||||
|
|
||||||
@Binding var favoriteItem: FavoriteItem?
|
@Binding var favoriteItem: FavoriteItem?
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ struct SearchTextField: View {
|
|||||||
query.query = state.queryText
|
query.query = state.queryText
|
||||||
navigation.hideKeyboard()
|
navigation.hideKeyboard()
|
||||||
}
|
}
|
||||||
recents.addQuery(state.queryText, navigation: navigation)
|
RecentsModel.shared.addQuery(state.queryText)
|
||||||
}
|
}
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SearchSuggestions: View {
|
struct SearchSuggestions: View {
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var state = SearchModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SearchModel> private var state
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
@ -80,10 +78,10 @@ struct SearchSuggestions: View {
|
|||||||
|
|
||||||
state.changeQuery { query in
|
state.changeQuery { query in
|
||||||
query.query = queryText
|
query.query = queryText
|
||||||
navigation.hideKeyboard()
|
NavigationModel.shared.hideKeyboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
recents.addQuery(queryText, navigation: navigation)
|
RecentsModel.shared.addQuery(queryText)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var visibleSuggestions: [String] {
|
private var visibleSuggestions: [String] {
|
||||||
|
@ -14,17 +14,15 @@ struct SearchView: View {
|
|||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
@State private var searchDebounce = Debounce()
|
@State private var searchDebounce = Debounce()
|
||||||
@State private var recentsDebounce = Debounce()
|
@State private var recentsDebounce = Debounce()
|
||||||
|
private var recents = RecentsModel.shared
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@State private var favoriteItem: FavoriteItem?
|
@State private var favoriteItem: FavoriteItem?
|
||||||
|
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var state = SearchModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SearchModel> private var state
|
|
||||||
private var favorites = FavoritesModel.shared
|
private var favorites = FavoritesModel.shared
|
||||||
|
|
||||||
@Default(.recentlyOpened) private var recentlyOpened
|
@Default(.recentlyOpened) private var recentlyOpened
|
||||||
@ -313,20 +311,17 @@ struct SearchView: View {
|
|||||||
case .query:
|
case .query:
|
||||||
state.queryText = item.title
|
state.queryText = item.title
|
||||||
state.changeQuery { query in query.query = item.title }
|
state.changeQuery { query in query.query = item.title }
|
||||||
navigation.hideKeyboard()
|
NavigationModel.shared.hideKeyboard()
|
||||||
|
|
||||||
updateFavoriteItem()
|
updateFavoriteItem()
|
||||||
recents.add(item)
|
RecentsModel.shared.add(item)
|
||||||
case .channel:
|
case .channel:
|
||||||
guard let channel = item.channel else {
|
guard let channel = item.channel else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationModel.openChannel(
|
NavigationModel.shared.openChannel(
|
||||||
channel,
|
channel,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
case .playlist:
|
case .playlist:
|
||||||
@ -334,11 +329,8 @@ struct SearchView: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationModel.openChannelPlaylist(
|
NavigationModel.shared.openChannelPlaylist(
|
||||||
playlist,
|
playlist,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -359,7 +351,7 @@ struct SearchView: View {
|
|||||||
|
|
||||||
private func removeButton(_ item: RecentItem) -> some View {
|
private func removeButton(_ item: RecentItem) -> some View {
|
||||||
Button {
|
Button {
|
||||||
recents.close(item)
|
RecentsModel.shared.close(item)
|
||||||
recentsChanged.toggle()
|
recentsChanged.toggle()
|
||||||
} label: {
|
} label: {
|
||||||
Label("Remove", systemImage: "trash")
|
Label("Remove", systemImage: "trash")
|
||||||
@ -368,12 +360,12 @@ struct SearchView: View {
|
|||||||
|
|
||||||
private var clearHistoryButton: some View {
|
private var clearHistoryButton: some View {
|
||||||
Button {
|
Button {
|
||||||
navigation.presentAlert(
|
NavigationModel.shared.presentAlert(
|
||||||
Alert(
|
Alert(
|
||||||
title: Text("Are you sure you want to clear search history?"),
|
title: Text("Are you sure you want to clear search history?"),
|
||||||
message: Text("This cannot be reverted"),
|
message: Text("This cannot be reverted"),
|
||||||
primaryButton: .destructive(Text("Clear")) {
|
primaryButton: .destructive(Text("Clear")) {
|
||||||
recents.clear()
|
RecentsModel.shared.clear()
|
||||||
recentsChanged.toggle()
|
recentsChanged.toggle()
|
||||||
},
|
},
|
||||||
secondaryButton: .cancel()
|
secondaryButton: .cancel()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AccountsNavigationLink: View {
|
struct AccountsNavigationLink: View {
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
var instance: Instance
|
var instance: Instance
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -30,6 +30,6 @@ struct AccountsNavigationLink: View {
|
|||||||
if accounts.current?.instance == instance {
|
if accounts.current?.instance == instance {
|
||||||
accounts.setCurrent(nil)
|
accounts.setCurrent(nil)
|
||||||
}
|
}
|
||||||
InstancesModel.remove(instance)
|
InstancesModel.shared.remove(instance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,6 @@ struct AdvancedSettings: View {
|
|||||||
@Default(.countryOfPublicInstances) private var countryOfPublicInstances
|
@Default(.countryOfPublicInstances) private var countryOfPublicInstances
|
||||||
@Default(.instances) private var instances
|
@Default(.instances) private var instances
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<SettingsModel> private var settings
|
|
||||||
|
|
||||||
@State private var countries = [String]()
|
@State private var countries = [String]()
|
||||||
@State private var filesToShare = [MPVClient.logFile]
|
@State private var filesToShare = [MPVClient.logFile]
|
||||||
@State private var presentingInstanceForm = false
|
@State private var presentingInstanceForm = false
|
||||||
@ -39,7 +34,7 @@ struct AdvancedSettings: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.onChange(of: countryOfPublicInstances) { newCountry in
|
.onChange(of: countryOfPublicInstances) { newCountry in
|
||||||
InstancesManifest.shared.setPublicAccount(newCountry, accounts: accounts, asCurrent: accounts.current?.isPublic ?? true)
|
InstancesManifest.shared.setPublicAccount(newCountry, asCurrent: AccountsModel.shared.current?.isPublic ?? true)
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $presentingInstanceForm) {
|
.sheet(isPresented: $presentingInstanceForm) {
|
||||||
InstanceForm(savedInstanceID: $savedFormInstanceID)
|
InstanceForm(savedInstanceID: $savedFormInstanceID)
|
||||||
|
@ -22,7 +22,7 @@ struct BrowsingSettings: View {
|
|||||||
@Default(.homeHistoryItems) private var homeHistoryItems
|
@Default(.homeHistoryItems) private var homeHistoryItems
|
||||||
@Default(.visibleSections) private var visibleSections
|
@Default(.visibleSections) private var visibleSections
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
@State private var homeHistoryItemsText = ""
|
@State private var homeHistoryItemsText = ""
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
|
@ -2,8 +2,7 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct EditFavorites: View {
|
struct EditFavorites: View {
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlistsModel
|
private var playlistsModel = PlaylistsModel.shared
|
||||||
|
|
||||||
private var model = FavoritesModel.shared
|
private var model = FavoritesModel.shared
|
||||||
|
|
||||||
@Default(.favorites) private var favorites
|
@Default(.favorites) private var favorites
|
||||||
|
@ -4,8 +4,8 @@ import SwiftUI
|
|||||||
struct HistorySettings: View {
|
struct HistorySettings: View {
|
||||||
static let watchedThresholds = [50, 60, 70, 80, 90, 95, 100]
|
static let watchedThresholds = [50, 60, 70, 80, 90, 95, 100]
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<SettingsModel> private var settings
|
private var settings = SettingsModel.shared
|
||||||
|
|
||||||
@Default(.saveRecents) private var saveRecents
|
@Default(.saveRecents) private var saveRecents
|
||||||
@Default(.saveLastPlayed) private var saveLastPlayed
|
@Default(.saveLastPlayed) private var saveLastPlayed
|
||||||
|
@ -16,7 +16,7 @@ struct InstanceForm: View {
|
|||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@Environment(\.presentationMode) private var presentationMode
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
@ -140,7 +140,7 @@ struct InstanceForm: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let savedInstance = InstancesModel.add(app: app, name: name, url: url)
|
let savedInstance = InstancesModel.shared.add(app: app, name: name, url: url)
|
||||||
savedInstanceID = savedInstance.id
|
savedInstanceID = savedInstance.id
|
||||||
|
|
||||||
if accounts.isEmpty {
|
if accounts.isEmpty {
|
||||||
|
@ -13,7 +13,7 @@ struct InstanceSettings: View {
|
|||||||
List {
|
List {
|
||||||
Section(header: Text("Accounts".localized())) {
|
Section(header: Text("Accounts".localized())) {
|
||||||
if instance.app.supportsAccounts {
|
if instance.app.supportsAccounts {
|
||||||
ForEach(InstancesModel.accounts(instance.id), id: \.self) { account in
|
ForEach(InstancesModel.shared.accounts(instance.id), id: \.self) { account in
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
Button(account.description) {}
|
Button(account.description) {}
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
@ -70,7 +70,7 @@ struct InstanceSettings: View {
|
|||||||
frontendURL = instance.frontendURL ?? ""
|
frontendURL = instance.frontendURL ?? ""
|
||||||
}
|
}
|
||||||
.onChange(of: frontendURL) { newValue in
|
.onChange(of: frontendURL) { newValue in
|
||||||
InstancesModel.setFrontendURL(instance, newValue)
|
InstancesModel.shared.setFrontendURL(instance, newValue)
|
||||||
}
|
}
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
@ -84,7 +84,7 @@ struct InstanceSettings: View {
|
|||||||
proxiesVideos = instance.proxiesVideos
|
proxiesVideos = instance.proxiesVideos
|
||||||
}
|
}
|
||||||
.onChange(of: proxiesVideos) { newValue in
|
.onChange(of: proxiesVideos) { newValue in
|
||||||
InstancesModel.setProxiesVideos(instance, newValue)
|
InstancesModel.shared.setProxiesVideos(instance, newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,8 @@ struct LocationsSettings: View {
|
|||||||
@State private var presentingInstanceForm = false
|
@State private var presentingInstanceForm = false
|
||||||
@State private var savedFormInstanceID: Instance.ID?
|
@State private var savedFormInstanceID: Instance.ID?
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
private var model = SettingsModel.shared
|
||||||
@EnvironmentObject<SettingsModel> private var model
|
|
||||||
|
|
||||||
@Default(.countryOfPublicInstances) private var countryOfPublicInstances
|
@Default(.countryOfPublicInstances) private var countryOfPublicInstances
|
||||||
@Default(.instances) private var instances
|
@Default(.instances) private var instances
|
||||||
@ -30,7 +29,7 @@ struct LocationsSettings: View {
|
|||||||
}
|
}
|
||||||
.onAppear(perform: loadCountries)
|
.onAppear(perform: loadCountries)
|
||||||
.onChange(of: countryOfPublicInstances) { newCountry in
|
.onChange(of: countryOfPublicInstances) { newCountry in
|
||||||
InstancesManifest.shared.setPublicAccount(newCountry, accounts: accounts, asCurrent: accounts.current?.isPublic ?? true)
|
InstancesManifest.shared.setPublicAccount(newCountry, asCurrent: accounts.current?.isPublic ?? true)
|
||||||
}
|
}
|
||||||
.onChange(of: instancesManifest) { _ in
|
.onChange(of: instancesManifest) { _ in
|
||||||
countryOfPublicInstances = nil
|
countryOfPublicInstances = nil
|
||||||
@ -74,7 +73,7 @@ struct LocationsSettings: View {
|
|||||||
.disabled(countries.isEmpty)
|
.disabled(countries.isEmpty)
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
InstancesManifest.shared.changePublicAccount(accounts, settings: model)
|
InstancesManifest.shared.changePublicAccount()
|
||||||
} label: {
|
} label: {
|
||||||
if let account = accounts.current, account.isPublic {
|
if let account = accounts.current, account.isPublic {
|
||||||
Text("Switch to other public location")
|
Text("Switch to other public location")
|
||||||
@ -89,7 +88,6 @@ struct LocationsSettings: View {
|
|||||||
Section(header: SettingsHeader(text: "Custom Locations".localized())) {
|
Section(header: SettingsHeader(text: "Custom Locations".localized())) {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
InstancesSettings()
|
InstancesSettings()
|
||||||
.environmentObject(model)
|
|
||||||
#else
|
#else
|
||||||
ForEach(instances) { instance in
|
ForEach(instances) { instance in
|
||||||
AccountsNavigationLink(instance: instance)
|
AccountsNavigationLink(instance: instance)
|
||||||
@ -137,8 +135,5 @@ struct LocationsSettings: View {
|
|||||||
struct LocationsSettings_Previews: PreviewProvider {
|
struct LocationsSettings_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
LocationsSettings()
|
LocationsSettings()
|
||||||
.environmentObject(AccountsModel())
|
|
||||||
.environmentObject(NavigationModel())
|
|
||||||
.environmentObject(SettingsModel())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ struct PlayerSettings: View {
|
|||||||
@Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike
|
@Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike
|
||||||
@Default(.systemControlsCommands) private var systemControlsCommands
|
@Default(.systemControlsCommands) private var systemControlsCommands
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
private var player = PlayerModel.shared
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
private var idiom: UIUserInterfaceIdiom {
|
private var idiom: UIUserInterfaceIdiom {
|
||||||
|
@ -5,7 +5,7 @@ struct QualitySettings: View {
|
|||||||
@State private var presentingProfileForm = false
|
@State private var presentingProfileForm = false
|
||||||
@State private var editedProfileID: QualityProfile.ID?
|
@State private var editedProfileID: QualityProfile.ID?
|
||||||
|
|
||||||
@EnvironmentObject<SettingsModel> private var settings
|
@ObservedObject private var settings = SettingsModel.shared
|
||||||
|
|
||||||
@Default(.qualityProfiles) private var qualityProfiles
|
@Default(.qualityProfiles) private var qualityProfiles
|
||||||
@Default(.batteryCellularProfile) private var batteryCellularProfile
|
@Default(.batteryCellularProfile) private var batteryCellularProfile
|
||||||
|
@ -19,15 +19,13 @@ struct SettingsView: View {
|
|||||||
@Environment(\.presentationMode) private var presentationMode
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var model = SettingsModel.shared
|
||||||
@EnvironmentObject<SettingsModel> private var model
|
|
||||||
|
|
||||||
@Default(.instances) private var instances
|
@Default(.instances) private var instances
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
settings
|
settings
|
||||||
.environmentObject(model)
|
|
||||||
.alert(isPresented: $model.presentingAlert) { model.alert }
|
.alert(isPresented: $model.presentingAlert) { model.alert }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ struct TrendingView: View {
|
|||||||
|
|
||||||
@State private var favoriteItem: FavoriteItem?
|
@State private var favoriteItem: FavoriteItem?
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
var trending: [ContentItem] {
|
var trending: [ContentItem] {
|
||||||
ContentItem.array(of: store.collection)
|
ContentItem.array(of: store.collection)
|
||||||
|
@ -14,9 +14,7 @@ struct VideoCell: View {
|
|||||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject var thumbnails = ThumbnailsModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<ThumbnailsModel> private var thumbnails
|
|
||||||
|
|
||||||
@Default(.channelOnThumbnail) private var channelOnThumbnail
|
@Default(.channelOnThumbnail) private var channelOnThumbnail
|
||||||
@Default(.timeOnThumbnail) private var timeOnThumbnail
|
@Default(.timeOnThumbnail) private var timeOnThumbnail
|
||||||
@ -53,7 +51,6 @@ struct VideoCell: View {
|
|||||||
.contentShape(RoundedRectangle(cornerRadius: thumbnailRoundingCornerRadius))
|
.contentShape(RoundedRectangle(cornerRadius: thumbnailRoundingCornerRadius))
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
VideoContextMenuView(video: video)
|
VideoContextMenuView(video: video)
|
||||||
.environmentObject(accounts)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,11 +307,8 @@ struct VideoCell: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationModel.openChannel(
|
NavigationModel.shared.openChannel(
|
||||||
video.channel,
|
video.channel,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -7,17 +7,10 @@ struct ChannelCell: View {
|
|||||||
|
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
Button {
|
||||||
NavigationModel.openChannel(
|
NavigationModel.shared.openChannel(
|
||||||
channel,
|
channel,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -6,13 +6,12 @@ struct ChannelPlaylistCell: View {
|
|||||||
|
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
Button {
|
||||||
let recent = RecentItem(from: playlist)
|
let recent = RecentItem(from: playlist)
|
||||||
recents.add(recent)
|
RecentsModel.shared.add(recent)
|
||||||
navigation.presentingPlaylist = true
|
navigation.presentingPlaylist = true
|
||||||
|
|
||||||
if navigationStyle == .sidebar {
|
if navigationStyle == .sidebar {
|
||||||
|
@ -12,10 +12,9 @@ struct ChannelPlaylistView: View {
|
|||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
var player = PlayerModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var recents = RecentsModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
|
|
||||||
private var items: [ContentItem] {
|
private var items: [ContentItem] {
|
||||||
ContentItem.array(of: store.item?.videos ?? [])
|
ContentItem.array(of: store.item?.videos ?? [])
|
||||||
@ -89,7 +88,7 @@ struct ChannelPlaylistView: View {
|
|||||||
if navigationStyle == .tab {
|
if navigationStyle == .tab {
|
||||||
Button("Done") {
|
Button("Done") {
|
||||||
withAnimation(Constants.overlayAnimation) {
|
withAnimation(Constants.overlayAnimation) {
|
||||||
navigation.presentingPlaylist = false
|
NavigationModel.shared.presentingPlaylist = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,12 @@ struct ChannelVideosView: View {
|
|||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
@ObservedObject private var recents = RecentsModel.shared
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
@ObservedObject private var subscriptions = SubscriptionsModel.shared
|
||||||
|
|
||||||
@Namespace private var focusNamespace
|
@Namespace private var focusNamespace
|
||||||
|
|
||||||
var presentedChannel: Channel? {
|
var presentedChannel: Channel? {
|
||||||
|
@ -10,12 +10,11 @@ struct ControlsBar: View {
|
|||||||
|
|
||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var model
|
@ObservedObject private var model = PlayerModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
@ObservedObject private var playlists = PlaylistsModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
@ObservedObject private var subscriptions = SubscriptionsModel.shared
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
|
|
||||||
@ObservedObject private var controls = PlayerControlsModel.shared
|
@ObservedObject private var controls = PlayerControlsModel.shared
|
||||||
|
|
||||||
@ -139,11 +138,8 @@ struct ControlsBar: View {
|
|||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
Button {
|
Button {
|
||||||
if let video = model.currentVideo, !video.isLocal {
|
if let video = model.currentVideo, !video.isLocal {
|
||||||
NavigationModel.openChannel(
|
navigation.openChannel(
|
||||||
video.channel,
|
video.channel,
|
||||||
player: model,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -179,7 +175,7 @@ struct ControlsBar: View {
|
|||||||
|
|
||||||
if let playlist = playlists.lastUsed, let video = model.currentVideo {
|
if let playlist = playlists.lastUsed, let video = model.currentVideo {
|
||||||
Button {
|
Button {
|
||||||
playlists.addVideo(playlistID: playlist.id, videoID: video.videoID, navigation: navigation)
|
playlists.addVideo(playlistID: playlist.id, videoID: video.videoID)
|
||||||
} label: {
|
} label: {
|
||||||
Label("Add to \(playlist.title)", systemImage: "text.badge.star")
|
Label("Add to \(playlist.title)", systemImage: "text.badge.star")
|
||||||
}
|
}
|
||||||
@ -194,11 +190,8 @@ struct ControlsBar: View {
|
|||||||
Section {
|
Section {
|
||||||
if !video.isLocal {
|
if !video.isLocal {
|
||||||
Button {
|
Button {
|
||||||
NavigationModel.openChannel(
|
navigation.openChannel(
|
||||||
video.channel,
|
video.channel,
|
||||||
player: model,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -2,10 +2,8 @@ import SwiftUI
|
|||||||
|
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
struct MPVPlayerView: UIViewControllerRepresentable {
|
struct MPVPlayerView: UIViewControllerRepresentable {
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
|
|
||||||
func makeUIViewController(context _: Context) -> some UIViewController {
|
func makeUIViewController(context _: Context) -> some UIViewController {
|
||||||
player.mpvController
|
PlayerModel.shared.mpvController
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIViewController(_: UIViewControllerType, context _: Context) {}
|
func updateUIViewController(_: UIViewControllerType, context _: Context) {}
|
||||||
@ -15,10 +13,8 @@ import SwiftUI
|
|||||||
@State private var client = MPVClient()
|
@State private var client = MPVClient()
|
||||||
@State private var layer = VideoLayer()
|
@State private var layer = VideoLayer()
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
|
|
||||||
func makeNSView(context _: Context) -> some NSView {
|
func makeNSView(context _: Context) -> some NSView {
|
||||||
player.mpvBackend.client = client
|
PlayerModel.shared.mpvBackend.client = client
|
||||||
|
|
||||||
let view = MPVOGLView()
|
let view = MPVOGLView()
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ struct OpenSettingsButton: View {
|
|||||||
@Environment(\.presentationMode) private var presentationMode
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
private var navigation: NavigationModel { .shared }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -6,11 +6,7 @@ struct OpenVideosView: View {
|
|||||||
@State private var playbackMode = OpenVideosModel.PlaybackMode.playNow
|
@State private var playbackMode = OpenVideosModel.PlaybackMode.playNow
|
||||||
@State private var removeQueueItems = false
|
@State private var removeQueueItems = false
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
|
||||||
@EnvironmentObject<SearchModel> private var search
|
|
||||||
|
|
||||||
@Environment(\.openURL) private var openURL
|
@Environment(\.openURL) private var openURL
|
||||||
@Environment(\.presentationMode) private var presentationMode
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
@ -132,8 +128,8 @@ struct OpenVideosView: View {
|
|||||||
|
|
||||||
openURLs(urlsToOpen)
|
openURLs(urlsToOpen)
|
||||||
} catch {
|
} catch {
|
||||||
NavigationModel.shared.alert = Alert(title: Text("Could not open Files"))
|
navigation.alert = Alert(title: Text("Could not open Files"))
|
||||||
NavigationModel.shared.presentingAlertInOpenVideos = true
|
navigation.presentingAlertInOpenVideos = true
|
||||||
}
|
}
|
||||||
|
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
@ -4,8 +4,9 @@ import SwiftUI
|
|||||||
struct PlaylistVideosView: View {
|
struct PlaylistVideosView: View {
|
||||||
let playlist: Playlist
|
let playlist: Playlist
|
||||||
|
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var model
|
var player = PlayerModel.shared
|
||||||
|
@ObservedObject private var model = PlaylistsModel.shared
|
||||||
|
|
||||||
@StateObject private var channelPlaylist = Store<ChannelPlaylist>()
|
@StateObject private var channelPlaylist = Store<ChannelPlaylist>()
|
||||||
@StateObject private var userPlaylist = Store<Playlist>()
|
@StateObject private var userPlaylist = Store<Playlist>()
|
||||||
@ -15,7 +16,7 @@ struct PlaylistVideosView: View {
|
|||||||
|
|
||||||
if videos.isEmpty {
|
if videos.isEmpty {
|
||||||
videos = userPlaylist.item?.videos ?? channelPlaylist.item?.videos ?? []
|
videos = userPlaylist.item?.videos ?? channelPlaylist.item?.videos ?? []
|
||||||
if !player.accounts.app.userPlaylistsEndpointIncludesVideos {
|
if !accounts.app.userPlaylistsEndpointIncludesVideos {
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
||||||
for index in videos.indices {
|
for index in videos.indices {
|
||||||
@ -31,9 +32,9 @@ struct PlaylistVideosView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var resource: Resource? {
|
private var resource: Resource? {
|
||||||
let resource = player.accounts.api.playlist(playlist.id)
|
let resource = accounts.api.playlist(playlist.id)
|
||||||
|
|
||||||
if player.accounts.app.userPlaylistsUseChannelPlaylistEndpoint {
|
if accounts.app.userPlaylistsUseChannelPlaylistEndpoint {
|
||||||
resource?.addObserver(channelPlaylist)
|
resource?.addObserver(channelPlaylist)
|
||||||
} else {
|
} else {
|
||||||
resource?.addObserver(userPlaylist)
|
resource?.addObserver(userPlaylist)
|
||||||
|
@ -4,7 +4,7 @@ import SwiftUI
|
|||||||
struct PopularView: View {
|
struct PopularView: View {
|
||||||
@StateObject private var store = Store<[Video]>()
|
@StateObject private var store = Store<[Video]>()
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
var resource: Resource? {
|
var resource: Resource? {
|
||||||
accounts.api.popular
|
accounts.api.popular
|
||||||
|
@ -3,9 +3,9 @@ import SwiftUI
|
|||||||
struct ShareButton<LabelView: View>: View {
|
struct ShareButton<LabelView: View>: View {
|
||||||
let contentItem: ContentItem
|
let contentItem: ContentItem
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
private var navigation: NavigationModel { .shared }
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
|
|
||||||
let label: LabelView?
|
let label: LabelView?
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ struct SignInRequiredView<Content: View>: View {
|
|||||||
let title: String
|
let title: String
|
||||||
let content: Content
|
let content: Content
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
@Default(.instances) private var instances
|
@Default(.instances) private var instances
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import SwiftUI
|
|||||||
struct SubscriptionsView: View {
|
struct SubscriptionsView: View {
|
||||||
@StateObject private var store = Store<[Video]>()
|
@StateObject private var store = Store<[Video]>()
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
var feed: Resource? {
|
var feed: Resource? {
|
||||||
accounts.api.feed
|
accounts.api.feed
|
||||||
|
@ -11,12 +11,11 @@ struct VideoContextMenuView: View {
|
|||||||
@Environment(\.navigationStyle) private var navigationStyle
|
@Environment(\.navigationStyle) private var navigationStyle
|
||||||
@Environment(\.currentPlaylistID) private var playlistID
|
@Environment(\.currentPlaylistID) private var playlistID
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<NavigationModel> private var navigation
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
@ObservedObject private var player = PlayerModel.shared
|
||||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
@ObservedObject private var playlists = PlaylistsModel.shared
|
||||||
@EnvironmentObject<RecentsModel> private var recents
|
@ObservedObject private var subscriptions = SubscriptionsModel.shared
|
||||||
@EnvironmentObject<SubscriptionsModel> private var subscriptions
|
|
||||||
|
|
||||||
@FetchRequest private var watchRequest: FetchedResults<Watch>
|
@FetchRequest private var watchRequest: FetchedResults<Watch>
|
||||||
|
|
||||||
@ -261,11 +260,8 @@ struct VideoContextMenuView: View {
|
|||||||
|
|
||||||
private var openChannelButton: some View {
|
private var openChannelButton: some View {
|
||||||
Button {
|
Button {
|
||||||
NavigationModel.openChannel(
|
NavigationModel.shared.openChannel(
|
||||||
video.channel,
|
video.channel,
|
||||||
player: player,
|
|
||||||
recents: recents,
|
|
||||||
navigation: navigation,
|
|
||||||
navigationStyle: navigationStyle
|
navigationStyle: navigationStyle
|
||||||
)
|
)
|
||||||
} label: {
|
} label: {
|
||||||
@ -308,7 +304,7 @@ struct VideoContextMenuView: View {
|
|||||||
@ViewBuilder private var addToLastPlaylistButton: some View {
|
@ViewBuilder private var addToLastPlaylistButton: some View {
|
||||||
if let playlist = playlists.lastUsed {
|
if let playlist = playlists.lastUsed {
|
||||||
Button {
|
Button {
|
||||||
playlists.addVideo(playlistID: playlist.id, videoID: video.videoID, navigation: navigation)
|
playlists.addVideo(playlistID: playlist.id, videoID: video.videoID)
|
||||||
} label: {
|
} label: {
|
||||||
Label("Add to \(playlist.title)", systemImage: "text.badge.star")
|
Label("Add to \(playlist.title)", systemImage: "text.badge.star")
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import SwiftUI
|
|||||||
struct WelcomeScreen: View {
|
struct WelcomeScreen: View {
|
||||||
@Environment(\.presentationMode) private var presentationMode
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
|
||||||
@State private var store = [ManifestedInstance]()
|
@State private var store = [ManifestedInstance]()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -25,7 +24,7 @@ struct WelcomeScreen: View {
|
|||||||
ForEach(countries, id: \.self) { country in
|
ForEach(countries, id: \.self) { country in
|
||||||
Button {
|
Button {
|
||||||
Defaults[.countryOfPublicInstances] = country
|
Defaults[.countryOfPublicInstances] = country
|
||||||
InstancesManifest.shared.setPublicAccount(country, accounts: accounts)
|
InstancesManifest.shared.setPublicAccount(country)
|
||||||
|
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -32,19 +32,16 @@ struct YatteeApp: App {
|
|||||||
|
|
||||||
@State private var configured = false
|
@State private var configured = false
|
||||||
|
|
||||||
@StateObject private var accounts = AccountsModel()
|
@StateObject private var comments = CommentsModel.shared
|
||||||
@StateObject private var comments = CommentsModel()
|
@StateObject private var instances = InstancesModel.shared
|
||||||
@StateObject private var instances = InstancesModel()
|
@StateObject private var menu = MenuModel.shared
|
||||||
@StateObject private var menu = MenuModel()
|
@StateObject private var networkState = NetworkStateModel.shared
|
||||||
@StateObject private var navigation = NavigationModel()
|
@StateObject private var player = PlayerModel.shared
|
||||||
@StateObject private var networkState = NetworkStateModel()
|
@StateObject private var playlists = PlaylistsModel.shared
|
||||||
@StateObject private var player = PlayerModel()
|
@StateObject private var recents = RecentsModel.shared
|
||||||
@StateObject private var playlists = PlaylistsModel()
|
@StateObject private var settings = SettingsModel.shared
|
||||||
@StateObject private var recents = RecentsModel()
|
@StateObject private var subscriptions = SubscriptionsModel.shared
|
||||||
@StateObject private var search = SearchModel()
|
@StateObject private var thumbnails = ThumbnailsModel.shared
|
||||||
@StateObject private var settings = SettingsModel()
|
|
||||||
@StateObject private var subscriptions = SubscriptionsModel()
|
|
||||||
@StateObject private var thumbnails = ThumbnailsModel()
|
|
||||||
|
|
||||||
let persistenceController = PersistenceController.shared
|
let persistenceController = PersistenceController.shared
|
||||||
|
|
||||||
@ -55,20 +52,6 @@ struct YatteeApp: App {
|
|||||||
ContentView()
|
ContentView()
|
||||||
.onAppear(perform: configure)
|
.onAppear(perform: configure)
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(comments)
|
|
||||||
.environmentObject(instances)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(networkState)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(playerControls)
|
|
||||||
.environmentObject(playlists)
|
|
||||||
.environmentObject(recents)
|
|
||||||
.environmentObject(settings)
|
|
||||||
.environmentObject(subscriptions)
|
|
||||||
.environmentObject(thumbnails)
|
|
||||||
.environmentObject(menu)
|
|
||||||
.environmentObject(search)
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.background(
|
.background(
|
||||||
HostingWindowFinder { window in
|
HostingWindowFinder { window in
|
||||||
@ -100,7 +83,7 @@ struct YatteeApp: App {
|
|||||||
|
|
||||||
CommandGroup(replacing: .newItem, addition: {})
|
CommandGroup(replacing: .newItem, addition: {})
|
||||||
|
|
||||||
MenuCommands(model: Binding<MenuModel>(get: { menu }, set: { _ in }))
|
MenuCommands(model: Binding<MenuModel>(get: { MenuModel.shared }, set: { _ in }))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -127,18 +110,7 @@ struct YatteeApp: App {
|
|||||||
.onDisappear { player.presentingPlayer = false }
|
.onDisappear { player.presentingPlayer = false }
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environment(\.navigationStyle, .sidebar)
|
.environment(\.navigationStyle, .sidebar)
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(comments)
|
|
||||||
.environmentObject(instances)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(networkState)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(playerControls)
|
|
||||||
.environmentObject(playlists)
|
|
||||||
.environmentObject(recents)
|
|
||||||
.environmentObject(search)
|
|
||||||
.environmentObject(subscriptions)
|
|
||||||
.environmentObject(thumbnails)
|
|
||||||
.handlesExternalEvents(preferring: Set(["player", "*"]), allowing: Set(["player", "*"]))
|
.handlesExternalEvents(preferring: Set(["player", "*"]), allowing: Set(["player", "*"]))
|
||||||
}
|
}
|
||||||
.handlesExternalEvents(matching: Set(["player", "*"]))
|
.handlesExternalEvents(matching: Set(["player", "*"]))
|
||||||
@ -146,12 +118,6 @@ struct YatteeApp: App {
|
|||||||
Settings {
|
Settings {
|
||||||
SettingsView()
|
SettingsView()
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environmentObject(accounts)
|
|
||||||
.environmentObject(instances)
|
|
||||||
.environmentObject(navigation)
|
|
||||||
.environmentObject(player)
|
|
||||||
.environmentObject(playerControls)
|
|
||||||
.environmentObject(settings)
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -171,39 +137,14 @@ struct YatteeApp: App {
|
|||||||
migrateAccounts()
|
migrateAccounts()
|
||||||
|
|
||||||
if !Defaults[.lastAccountIsPublic] {
|
if !Defaults[.lastAccountIsPublic] {
|
||||||
accounts.configureAccount()
|
AccountsModel.shared.configureAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let countryOfPublicInstances = Defaults[.countryOfPublicInstances] {
|
if let countryOfPublicInstances = Defaults[.countryOfPublicInstances] {
|
||||||
InstancesManifest.shared.setPublicAccount(countryOfPublicInstances, accounts: accounts, asCurrent: accounts.current.isNil)
|
InstancesManifest.shared.setPublicAccount(countryOfPublicInstances, asCurrent: AccountsModel.shared.current.isNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
playlists.accounts = accounts
|
if !AccountsModel.shared.current.isNil {
|
||||||
search.accounts = accounts
|
|
||||||
subscriptions.accounts = accounts
|
|
||||||
|
|
||||||
comments.player = player
|
|
||||||
|
|
||||||
menu.accounts = accounts
|
|
||||||
menu.navigation = navigation
|
|
||||||
menu.player = player
|
|
||||||
|
|
||||||
player.accounts = accounts
|
|
||||||
player.comments = comments
|
|
||||||
player.navigation = navigation
|
|
||||||
|
|
||||||
PlayerModel.shared = player
|
|
||||||
PlayerTimeModel.shared.player = player
|
|
||||||
|
|
||||||
#if !os(tvOS)
|
|
||||||
OpenURLHandler.shared.accounts = accounts
|
|
||||||
OpenURLHandler.shared.navigation = navigation
|
|
||||||
OpenURLHandler.shared.recents = recents
|
|
||||||
OpenURLHandler.shared.player = player
|
|
||||||
OpenURLHandler.shared.search = search
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if !accounts.current.isNil {
|
|
||||||
player.restoreQueue()
|
player.restoreQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,9 +160,7 @@ struct YatteeApp: App {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
navigation.tabSelection = section ?? .search
|
NavigationModel.shared.tabSelection = section ?? .search
|
||||||
|
|
||||||
NavigationModel.shared = navigation
|
|
||||||
|
|
||||||
subscriptions.load()
|
subscriptions.load()
|
||||||
playlists.load()
|
playlists.load()
|
||||||
|
@ -2,14 +2,8 @@ import Defaults
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AppleAVPlayerView: NSViewRepresentable {
|
struct AppleAVPlayerView: NSViewRepresentable {
|
||||||
@EnvironmentObject<PlayerModel> private var player
|
|
||||||
|
|
||||||
func makeNSView(context _: Context) -> some NSView {
|
func makeNSView(context _: Context) -> some NSView {
|
||||||
let playerLayerView = PlayerLayerView(frame: .zero)
|
PlayerLayerView(frame: .zero)
|
||||||
|
|
||||||
playerLayerView.player = player
|
|
||||||
|
|
||||||
return playerLayerView
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNSView(_: NSViewType, context _: Context) {}
|
func updateNSView(_: NSViewType, context _: Context) {}
|
||||||
|
@ -13,8 +13,8 @@ struct InstancesSettings: View {
|
|||||||
@State private var proxiesVideos = false
|
@State private var proxiesVideos = false
|
||||||
|
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@EnvironmentObject<AccountsModel> private var accounts
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@EnvironmentObject<SettingsModel> private var settings
|
private var settings = SettingsModel.shared
|
||||||
|
|
||||||
@Default(.instances) private var instances
|
@Default(.instances) private var instances
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ struct InstancesSettings: View {
|
|||||||
frontendURL = selectedInstanceFrontendURL
|
frontendURL = selectedInstanceFrontendURL
|
||||||
}
|
}
|
||||||
.onChange(of: frontendURL) { newValue in
|
.onChange(of: frontendURL) { newValue in
|
||||||
InstancesModel.setFrontendURL(selectedInstance, newValue)
|
InstancesModel.shared.setFrontendURL(selectedInstance, newValue)
|
||||||
}
|
}
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ struct InstancesSettings: View {
|
|||||||
proxiesVideos = selectedInstance.proxiesVideos
|
proxiesVideos = selectedInstance.proxiesVideos
|
||||||
}
|
}
|
||||||
.onChange(of: proxiesVideos) { newValue in
|
.onChange(of: proxiesVideos) { newValue in
|
||||||
InstancesModel.setProxiesVideos(selectedInstance, newValue)
|
InstancesModel.shared.setProxiesVideos(selectedInstance, newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ struct InstancesSettings: View {
|
|||||||
accounts.setCurrent(nil)
|
accounts.setCurrent(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancesModel.remove(selectedInstance!)
|
InstancesModel.shared.remove(selectedInstance!)
|
||||||
selectedInstanceID = instances.last?.id
|
selectedInstanceID = instances.last?.id
|
||||||
},
|
},
|
||||||
secondaryButton: .cancel()
|
secondaryButton: .cancel()
|
||||||
@ -170,7 +170,7 @@ struct InstancesSettings: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var selectedInstance: Instance! {
|
var selectedInstance: Instance! {
|
||||||
InstancesModel.find(selectedInstanceID)
|
InstancesModel.shared.find(selectedInstanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedInstanceFrontendURL: String {
|
var selectedInstanceFrontendURL: String {
|
||||||
@ -182,7 +182,7 @@ struct InstancesSettings: View {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
return InstancesModel.accounts(selectedInstanceID)
|
return InstancesModel.shared.accounts(selectedInstanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var proxiesVideosToggle: some View {
|
private var proxiesVideosToggle: some View {
|
||||||
|
@ -5,7 +5,7 @@ import SwiftUI
|
|||||||
struct AccountSelectionView: View {
|
struct AccountSelectionView: View {
|
||||||
var showHeader = true
|
var showHeader = true
|
||||||
|
|
||||||
@EnvironmentObject<AccountsModel> private var accountsModel
|
@ObservedObject private var accountsModel = AccountsModel.shared
|
||||||
|
|
||||||
@Default(.accounts) private var accounts
|
@Default(.accounts) private var accounts
|
||||||
@Default(.instances) private var instances
|
@Default(.instances) private var instances
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user