initial iOS LiveTV coordination
This commit is contained in:
parent
9c41420ecd
commit
4dac5dd0b9
|
@ -20,6 +20,8 @@ final class LibraryListCoordinator: NavigationCoordinatable {
|
||||||
var search = makeSearch
|
var search = makeSearch
|
||||||
@Route(.push)
|
@Route(.push)
|
||||||
var library = makeLibrary
|
var library = makeLibrary
|
||||||
|
@Route(.push)
|
||||||
|
var liveTV = makeLiveTV
|
||||||
|
|
||||||
let viewModel: LibraryListViewModel
|
let viewModel: LibraryListViewModel
|
||||||
|
|
||||||
|
@ -34,6 +36,10 @@ final class LibraryListCoordinator: NavigationCoordinatable {
|
||||||
func makeSearch(viewModel: LibrarySearchViewModel) -> SearchCoordinator {
|
func makeSearch(viewModel: LibrarySearchViewModel) -> SearchCoordinator {
|
||||||
SearchCoordinator(viewModel: viewModel)
|
SearchCoordinator(viewModel: viewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeLiveTV() -> LiveTVCoordinator {
|
||||||
|
LiveTVCoordinator()
|
||||||
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func makeStart() -> some View {
|
func makeStart() -> some View {
|
||||||
|
|
|
@ -24,7 +24,7 @@ final class LiveTVChannelsCoordinator: NavigationCoordinatable {
|
||||||
func makeModalItem(item: BaseItemDto) -> NavigationViewCoordinator<ItemCoordinator> {
|
func makeModalItem(item: BaseItemDto) -> NavigationViewCoordinator<ItemCoordinator> {
|
||||||
NavigationViewCoordinator(ItemCoordinator(item: item))
|
NavigationViewCoordinator(ItemCoordinator(item: item))
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeVideoPlayer(viewModel: VideoPlayerViewModel) -> NavigationViewCoordinator<LiveTVVideoPlayerCoordinator> {
|
func makeVideoPlayer(viewModel: VideoPlayerViewModel) -> NavigationViewCoordinator<LiveTVVideoPlayerCoordinator> {
|
||||||
NavigationViewCoordinator(LiveTVVideoPlayerCoordinator(viewModel: viewModel))
|
NavigationViewCoordinator(LiveTVVideoPlayerCoordinator(viewModel: viewModel))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import JellyfinAPI
|
||||||
|
import Stinsen
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
final class LiveTVCoordinator: NavigationCoordinatable {
|
||||||
|
let stack = NavigationStack(initial: \LiveTVCoordinator.start)
|
||||||
|
|
||||||
|
@Root
|
||||||
|
var start = makeStart
|
||||||
|
// @Route(.push)
|
||||||
|
// var search = makeSearch
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func makeStart() -> some View {
|
||||||
|
LiveTVChannelsView()
|
||||||
|
}
|
||||||
|
|
||||||
|
// func makeSearch(viewModel: LibrarySearchViewModel) -> SearchCoordinator {
|
||||||
|
// SearchCoordinator(viewModel: viewModel)
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import Defaults
|
||||||
|
import Foundation
|
||||||
|
import JellyfinAPI
|
||||||
|
import Stinsen
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
final class LiveTVVideoPlayerCoordinator: NavigationCoordinatable {
|
||||||
|
|
||||||
|
let stack = NavigationStack(initial: \LiveTVVideoPlayerCoordinator.start)
|
||||||
|
|
||||||
|
@Root
|
||||||
|
var start = makeStart
|
||||||
|
|
||||||
|
let viewModel: VideoPlayerViewModel
|
||||||
|
|
||||||
|
init(viewModel: VideoPlayerViewModel) {
|
||||||
|
self.viewModel = viewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func makeStart() -> some View {
|
||||||
|
// if Defaults[.Experimental.liveTVNativePlayer] {
|
||||||
|
// LiveTVNativeVideoPlayerView(viewModel: viewModel)
|
||||||
|
// .navigationBarHidden(true)
|
||||||
|
// .ignoresSafeArea()
|
||||||
|
// } else {
|
||||||
|
LiveTVPlayerView(viewModel: viewModel)
|
||||||
|
.navigationBarHidden(true)
|
||||||
|
.ignoresSafeArea()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
|
@ -120,7 +120,9 @@ struct LiveTVChannelItemElement: View {
|
||||||
.stroke(isFocused ? Color.blue : Color.clear, lineWidth: 4))
|
.stroke(isFocused ? Color.blue : Color.clear, lineWidth: 4))
|
||||||
.cornerRadius(20)
|
.cornerRadius(20)
|
||||||
.scaleEffect(isFocused ? 1.1 : 1)
|
.scaleEffect(isFocused ? 1.1 : 1)
|
||||||
|
#if os(tvOS)
|
||||||
.focusable(true)
|
.focusable(true)
|
||||||
|
#endif
|
||||||
.focused($focused)
|
.focused($focused)
|
||||||
.onChange(of: focused) { foc in
|
.onChange(of: focused) { foc in
|
||||||
withAnimation(.linear(duration: 0.15)) {
|
withAnimation(.linear(duration: 0.15)) {
|
||||||
|
|
|
@ -259,6 +259,14 @@
|
||||||
C4534981279A3F140045F1E2 /* tvOSLiveTVOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4534980279A3F140045F1E2 /* tvOSLiveTVOverlay.swift */; };
|
C4534981279A3F140045F1E2 /* tvOSLiveTVOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4534980279A3F140045F1E2 /* tvOSLiveTVOverlay.swift */; };
|
||||||
C4534983279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4534982279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift */; };
|
C4534983279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4534982279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift */; };
|
||||||
C4534985279A40C60045F1E2 /* LiveTVVideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4534984279A40C50045F1E2 /* LiveTVVideoPlayerView.swift */; };
|
C4534985279A40C60045F1E2 /* LiveTVVideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4534984279A40C50045F1E2 /* LiveTVVideoPlayerView.swift */; };
|
||||||
|
C45942C527F67DA400C54FE7 /* LiveTVCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45942C427F67DA400C54FE7 /* LiveTVCoordinator.swift */; };
|
||||||
|
C45942C627F695FB00C54FE7 /* LiveTVProgramsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BE07702725EB06003F4AD1 /* LiveTVProgramsCoordinator.swift */; };
|
||||||
|
C45942C927F697CA00C54FE7 /* iOSLiveTVVideoPlayerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45942C827F697CA00C54FE7 /* iOSLiveTVVideoPlayerCoordinator.swift */; };
|
||||||
|
C45942CB27F6984100C54FE7 /* LiveTVPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45942CA27F6984100C54FE7 /* LiveTVPlayerViewController.swift */; };
|
||||||
|
C45942CD27F6994A00C54FE7 /* LiveTVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45942CC27F6994A00C54FE7 /* LiveTVPlayerView.swift */; };
|
||||||
|
C45942CE27F69BF300C54FE7 /* LiveTVChannelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BE078A272844AF003F4AD1 /* LiveTVChannelsView.swift */; };
|
||||||
|
C45942CF27F69BF500C54FE7 /* LiveTVChannelItemElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E52304272CE68800654268 /* LiveTVChannelItemElement.swift */; };
|
||||||
|
C45942D027F69C2400C54FE7 /* LiveTVChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BE07872728448B003F4AD1 /* LiveTVChannelsCoordinator.swift */; };
|
||||||
C45B29BB26FAC5B600CEF5E0 /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E173DA5126D04AAF00CC4EB7 /* ColorExtension.swift */; };
|
C45B29BB26FAC5B600CEF5E0 /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E173DA5126D04AAF00CC4EB7 /* ColorExtension.swift */; };
|
||||||
C4AE2C3027498D2300AE13CF /* LiveTVHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AE2C2F27498D2300AE13CF /* LiveTVHomeView.swift */; };
|
C4AE2C3027498D2300AE13CF /* LiveTVHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AE2C2F27498D2300AE13CF /* LiveTVHomeView.swift */; };
|
||||||
C4AE2C3227498D6A00AE13CF /* LiveTVProgramsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AE2C3127498D6A00AE13CF /* LiveTVProgramsView.swift */; };
|
C4AE2C3227498D6A00AE13CF /* LiveTVProgramsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AE2C3127498D6A00AE13CF /* LiveTVProgramsView.swift */; };
|
||||||
|
@ -739,6 +747,10 @@
|
||||||
C4534980279A3F140045F1E2 /* tvOSLiveTVOverlay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = tvOSLiveTVOverlay.swift; sourceTree = "<group>"; };
|
C4534980279A3F140045F1E2 /* tvOSLiveTVOverlay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = tvOSLiveTVOverlay.swift; sourceTree = "<group>"; };
|
||||||
C4534982279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = tvOSLiveTVVideoPlayerCoordinator.swift; sourceTree = "<group>"; };
|
C4534982279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = tvOSLiveTVVideoPlayerCoordinator.swift; sourceTree = "<group>"; };
|
||||||
C4534984279A40C50045F1E2 /* LiveTVVideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveTVVideoPlayerView.swift; sourceTree = "<group>"; };
|
C4534984279A40C50045F1E2 /* LiveTVVideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveTVVideoPlayerView.swift; sourceTree = "<group>"; };
|
||||||
|
C45942C427F67DA400C54FE7 /* LiveTVCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
C45942C827F697CA00C54FE7 /* iOSLiveTVVideoPlayerCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSLiveTVVideoPlayerCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
C45942CA27F6984100C54FE7 /* LiveTVPlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVPlayerViewController.swift; sourceTree = "<group>"; };
|
||||||
|
C45942CC27F6994A00C54FE7 /* LiveTVPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVPlayerView.swift; sourceTree = "<group>"; };
|
||||||
C4AE2C2F27498D2300AE13CF /* LiveTVHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVHomeView.swift; sourceTree = "<group>"; };
|
C4AE2C2F27498D2300AE13CF /* LiveTVHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVHomeView.swift; sourceTree = "<group>"; };
|
||||||
C4AE2C3127498D6A00AE13CF /* LiveTVProgramsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVProgramsView.swift; sourceTree = "<group>"; };
|
C4AE2C3127498D6A00AE13CF /* LiveTVProgramsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVProgramsView.swift; sourceTree = "<group>"; };
|
||||||
C4B9B91327E1921B0063535C /* LiveTVNativeVideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVNativeVideoPlayerView.swift; sourceTree = "<group>"; };
|
C4B9B91327E1921B0063535C /* LiveTVNativeVideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVNativeVideoPlayerView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1466,6 +1478,7 @@
|
||||||
C4BE07872728448B003F4AD1 /* LiveTVChannelsCoordinator.swift */,
|
C4BE07872728448B003F4AD1 /* LiveTVChannelsCoordinator.swift */,
|
||||||
C4BE07702725EB06003F4AD1 /* LiveTVProgramsCoordinator.swift */,
|
C4BE07702725EB06003F4AD1 /* LiveTVProgramsCoordinator.swift */,
|
||||||
C4BE07782726EE82003F4AD1 /* LiveTVTabCoordinator.swift */,
|
C4BE07782726EE82003F4AD1 /* LiveTVTabCoordinator.swift */,
|
||||||
|
C45942C427F67DA400C54FE7 /* LiveTVCoordinator.swift */,
|
||||||
E193D5412719404B00900D82 /* MainCoordinator */,
|
E193D5412719404B00900D82 /* MainCoordinator */,
|
||||||
C40CD921271F8CD8000FB198 /* MoviesLibrariesCoordinator.swift */,
|
C40CD921271F8CD8000FB198 /* MoviesLibrariesCoordinator.swift */,
|
||||||
6220D0B626D5EE1100B8E046 /* SearchCoordinator.swift */,
|
6220D0B626D5EE1100B8E046 /* SearchCoordinator.swift */,
|
||||||
|
@ -1724,7 +1737,9 @@
|
||||||
E1002B692793E12E00E47059 /* Overlays */,
|
E1002B692793E12E00E47059 /* Overlays */,
|
||||||
E1C812B5277A8E5D00918266 /* PlayerOverlayDelegate.swift */,
|
E1C812B5277A8E5D00918266 /* PlayerOverlayDelegate.swift */,
|
||||||
E1C812B8277A8E5D00918266 /* VLCPlayerView.swift */,
|
E1C812B8277A8E5D00918266 /* VLCPlayerView.swift */,
|
||||||
|
C45942CC27F6994A00C54FE7 /* LiveTVPlayerView.swift */,
|
||||||
E1C812B6277A8E5D00918266 /* VLCPlayerViewController.swift */,
|
E1C812B6277A8E5D00918266 /* VLCPlayerViewController.swift */,
|
||||||
|
C45942CA27F6984100C54FE7 /* LiveTVPlayerViewController.swift */,
|
||||||
);
|
);
|
||||||
path = VideoPlayer;
|
path = VideoPlayer;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1801,6 +1816,7 @@
|
||||||
E1C812CF277AE4C700918266 /* VideoPlayerCoordinator */ = {
|
E1C812CF277AE4C700918266 /* VideoPlayerCoordinator */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C45942C827F697CA00C54FE7 /* iOSLiveTVVideoPlayerCoordinator.swift */,
|
||||||
6220D0C526D62D8700B8E046 /* iOSVideoPlayerCoordinator.swift */,
|
6220D0C526D62D8700B8E046 /* iOSVideoPlayerCoordinator.swift */,
|
||||||
C4534982279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift */,
|
C4534982279A40990045F1E2 /* tvOSLiveTVVideoPlayerCoordinator.swift */,
|
||||||
E1C812D0277AE4E300918266 /* tvOSVideoPlayerCoordinator.swift */,
|
E1C812D0277AE4E300918266 /* tvOSVideoPlayerCoordinator.swift */,
|
||||||
|
@ -2374,6 +2390,7 @@
|
||||||
62C29E9F26D1016600C1D2E7 /* iOSMainCoordinator.swift in Sources */,
|
62C29E9F26D1016600C1D2E7 /* iOSMainCoordinator.swift in Sources */,
|
||||||
5389276E263C25100035E14B /* ContinueWatchingView.swift in Sources */,
|
5389276E263C25100035E14B /* ContinueWatchingView.swift in Sources */,
|
||||||
53F866442687A45F00DCD1D7 /* PortraitItemButton.swift in Sources */,
|
53F866442687A45F00DCD1D7 /* PortraitItemButton.swift in Sources */,
|
||||||
|
C45942CD27F6994A00C54FE7 /* LiveTVPlayerView.swift in Sources */,
|
||||||
E1AD105626D981CE003E4A08 /* PortraitHStackView.swift in Sources */,
|
E1AD105626D981CE003E4A08 /* PortraitHStackView.swift in Sources */,
|
||||||
62C29EA126D102A500C1D2E7 /* iOSMainTabCoordinator.swift in Sources */,
|
62C29EA126D102A500C1D2E7 /* iOSMainTabCoordinator.swift in Sources */,
|
||||||
C4BE076E2720FEA8003F4AD1 /* PortraitItemElement.swift in Sources */,
|
C4BE076E2720FEA8003F4AD1 /* PortraitItemElement.swift in Sources */,
|
||||||
|
@ -2392,9 +2409,11 @@
|
||||||
5D160403278A41FD00D22B99 /* VLCPlayer+subtitles.swift in Sources */,
|
5D160403278A41FD00D22B99 /* VLCPlayer+subtitles.swift in Sources */,
|
||||||
536D3D78267BD5C30004248C /* ViewModel.swift in Sources */,
|
536D3D78267BD5C30004248C /* ViewModel.swift in Sources */,
|
||||||
E1A2C158279A7D76005EC829 /* BundleExtensions.swift in Sources */,
|
E1A2C158279A7D76005EC829 /* BundleExtensions.swift in Sources */,
|
||||||
|
C45942C627F695FB00C54FE7 /* LiveTVProgramsCoordinator.swift in Sources */,
|
||||||
E1FCD08826C35A0D007C8DCF /* NetworkError.swift in Sources */,
|
E1FCD08826C35A0D007C8DCF /* NetworkError.swift in Sources */,
|
||||||
E13AD72E2798BC8D00FDCEE8 /* NativePlayerViewController.swift in Sources */,
|
E13AD72E2798BC8D00FDCEE8 /* NativePlayerViewController.swift in Sources */,
|
||||||
E13DD3E527177D15009D4DAF /* ServerListView.swift in Sources */,
|
E13DD3E527177D15009D4DAF /* ServerListView.swift in Sources */,
|
||||||
|
C45942CB27F6984100C54FE7 /* LiveTVPlayerViewController.swift in Sources */,
|
||||||
E18845F826DEA9C900B0C5B7 /* ItemViewBody.swift in Sources */,
|
E18845F826DEA9C900B0C5B7 /* ItemViewBody.swift in Sources */,
|
||||||
E173DA5426D050F500CC4EB7 /* ServerDetailViewModel.swift in Sources */,
|
E173DA5426D050F500CC4EB7 /* ServerDetailViewModel.swift in Sources */,
|
||||||
E19169CE272514760085832A /* HTTPScheme.swift in Sources */,
|
E19169CE272514760085832A /* HTTPScheme.swift in Sources */,
|
||||||
|
@ -2412,6 +2431,7 @@
|
||||||
E1C812BC277A8E5D00918266 /* PlaybackSpeed.swift in Sources */,
|
E1C812BC277A8E5D00918266 /* PlaybackSpeed.swift in Sources */,
|
||||||
E1E5D5492783CDD700692DFE /* OverlaySettingsView.swift in Sources */,
|
E1E5D5492783CDD700692DFE /* OverlaySettingsView.swift in Sources */,
|
||||||
E173DA5226D04AAF00CC4EB7 /* ColorExtension.swift in Sources */,
|
E173DA5226D04AAF00CC4EB7 /* ColorExtension.swift in Sources */,
|
||||||
|
C45942D027F69C2400C54FE7 /* LiveTVChannelsCoordinator.swift in Sources */,
|
||||||
E11D224227378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */,
|
E11D224227378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */,
|
||||||
6264E88C273850380081A12A /* Strings.swift in Sources */,
|
6264E88C273850380081A12A /* Strings.swift in Sources */,
|
||||||
C4AE2C3227498D6A00AE13CF /* LiveTVProgramsView.swift in Sources */,
|
C4AE2C3227498D6A00AE13CF /* LiveTVProgramsView.swift in Sources */,
|
||||||
|
@ -2463,6 +2483,7 @@
|
||||||
C4BE07762725EBEA003F4AD1 /* LiveTVProgramsViewModel.swift in Sources */,
|
C4BE07762725EBEA003F4AD1 /* LiveTVProgramsViewModel.swift in Sources */,
|
||||||
E13DD3E927177ED6009D4DAF /* ServerListCoordinator.swift in Sources */,
|
E13DD3E927177ED6009D4DAF /* ServerListCoordinator.swift in Sources */,
|
||||||
E1C812BD277A8E5D00918266 /* PlayerOverlayDelegate.swift in Sources */,
|
E1C812BD277A8E5D00918266 /* PlayerOverlayDelegate.swift in Sources */,
|
||||||
|
C45942C527F67DA400C54FE7 /* LiveTVCoordinator.swift in Sources */,
|
||||||
E13DD3C227164941009D4DAF /* SwiftfinStore.swift in Sources */,
|
E13DD3C227164941009D4DAF /* SwiftfinStore.swift in Sources */,
|
||||||
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
||||||
E193D4DB27193CCA00900D82 /* PillStackable.swift in Sources */,
|
E193D4DB27193CCA00900D82 /* PillStackable.swift in Sources */,
|
||||||
|
@ -2480,6 +2501,7 @@
|
||||||
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
|
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
|
||||||
62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */,
|
62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */,
|
||||||
5D64683D277B1649009E09AE /* PreferenceUIHostingSwizzling.swift in Sources */,
|
5D64683D277B1649009E09AE /* PreferenceUIHostingSwizzling.swift in Sources */,
|
||||||
|
C45942C927F697CA00C54FE7 /* iOSLiveTVVideoPlayerCoordinator.swift in Sources */,
|
||||||
E13DD3C827164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
E13DD3C827164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
||||||
E10EAA53277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift in Sources */,
|
E10EAA53277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift in Sources */,
|
||||||
E1AD104D26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */,
|
E1AD104D26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */,
|
||||||
|
@ -2496,10 +2518,12 @@
|
||||||
62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */,
|
62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */,
|
||||||
5389277C263CC3DB0035E14B /* BlurHashDecode.swift in Sources */,
|
5389277C263CC3DB0035E14B /* BlurHashDecode.swift in Sources */,
|
||||||
E1D4BF8A2719D3D000A11E64 /* BasicAppSettingsCoordinator.swift in Sources */,
|
E1D4BF8A2719D3D000A11E64 /* BasicAppSettingsCoordinator.swift in Sources */,
|
||||||
|
C45942CE27F69BF300C54FE7 /* LiveTVChannelsView.swift in Sources */,
|
||||||
E13DD3F92717E961009D4DAF /* UserListViewModel.swift in Sources */,
|
E13DD3F92717E961009D4DAF /* UserListViewModel.swift in Sources */,
|
||||||
E126F741278A656C00A522BF /* ServerStreamType.swift in Sources */,
|
E126F741278A656C00A522BF /* ServerStreamType.swift in Sources */,
|
||||||
539B2DA5263BA5B8007FF1A4 /* SettingsView.swift in Sources */,
|
539B2DA5263BA5B8007FF1A4 /* SettingsView.swift in Sources */,
|
||||||
5338F74E263B61370014BF09 /* ConnectToServerView.swift in Sources */,
|
5338F74E263B61370014BF09 /* ConnectToServerView.swift in Sources */,
|
||||||
|
C45942CF27F69BF500C54FE7 /* LiveTVChannelItemElement.swift in Sources */,
|
||||||
09389CC726819B4600AE350E /* VideoPlayerModel.swift in Sources */,
|
09389CC726819B4600AE350E /* VideoPlayerModel.swift in Sources */,
|
||||||
E1D4BF872719D27100A11E64 /* Bitrates.swift in Sources */,
|
E1D4BF872719D27100A11E64 /* Bitrates.swift in Sources */,
|
||||||
6220D0B726D5EE1100B8E046 /* SearchCoordinator.swift in Sources */,
|
6220D0B726D5EE1100B8E046 /* SearchCoordinator.swift in Sources */,
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Defaults
|
||||||
import Foundation
|
import Foundation
|
||||||
import Stinsen
|
import Stinsen
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
@ -15,8 +16,17 @@ struct LibraryListView: View {
|
||||||
var libraryListRouter: LibraryListCoordinator.Router
|
var libraryListRouter: LibraryListCoordinator.Router
|
||||||
@StateObject
|
@StateObject
|
||||||
var viewModel = LibraryListViewModel()
|
var viewModel = LibraryListViewModel()
|
||||||
|
|
||||||
let supportedCollectionTypes = ["movies", "tvshows", "boxsets", "other"]
|
@Default(.Experimental.liveTVAlphaEnabled)
|
||||||
|
var liveTVAlphaEnabled
|
||||||
|
|
||||||
|
var supportedCollectionTypes: [String] {
|
||||||
|
if liveTVAlphaEnabled {
|
||||||
|
return ["movies", "tvshows", "livetv", "boxsets", "other"]
|
||||||
|
} else {
|
||||||
|
return ["movies", "tvshows", "boxsets", "other"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
|
@ -49,9 +59,13 @@ struct LibraryListView: View {
|
||||||
return self.supportedCollectionTypes.contains(collectionType)
|
return self.supportedCollectionTypes.contains(collectionType)
|
||||||
}, id: \.id) { library in
|
}, id: \.id) { library in
|
||||||
Button {
|
Button {
|
||||||
libraryListRouter.route(to: \.library,
|
if library.collectionType == "livetv" {
|
||||||
|
libraryListRouter.route(to: \.liveTV)
|
||||||
|
} else {
|
||||||
|
libraryListRouter.route(to: \.library,
|
||||||
(viewModel: LibraryViewModel(parentID: library.id),
|
(viewModel: LibraryViewModel(parentID: library.id),
|
||||||
title: library.name ?? ""))
|
title: library.name ?? ""))
|
||||||
|
}
|
||||||
} label: {
|
} label: {
|
||||||
ZStack {
|
ZStack {
|
||||||
ImageView(library.getPrimaryImage(maxWidth: 500), blurHash: library.getPrimaryImageBlurHash())
|
ImageView(library.getPrimaryImage(maxWidth: 500), blurHash: library.getPrimaryImageBlurHash())
|
||||||
|
|
|
@ -10,7 +10,201 @@ import Stinsen
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct LiveTVProgramsView: View {
|
struct LiveTVProgramsView: View {
|
||||||
var body: some View {
|
@EnvironmentObject
|
||||||
Text("Coming Soon")
|
var programsRouter: LiveTVProgramsCoordinator.Router
|
||||||
}
|
@StateObject
|
||||||
|
var viewModel = LiveTVProgramsViewModel()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView {
|
||||||
|
LazyVStack(alignment: .leading) {
|
||||||
|
if !viewModel.recommendedItems.isEmpty,
|
||||||
|
let items = viewModel.recommendedItems
|
||||||
|
{
|
||||||
|
Text("On Now")
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.leading, 90)
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack {
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
ForEach(items, id: \.id) { item in
|
||||||
|
Button {
|
||||||
|
if let chanId = item.channelId,
|
||||||
|
let chan = viewModel.findChannel(id: chanId)
|
||||||
|
{
|
||||||
|
self.viewModel.fetchVideoPlayerViewModel(item: chan) { playerViewModel in
|
||||||
|
self.programsRouter.route(to: \.videoPlayer, playerViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
#if os(iOS)
|
||||||
|
#elseif os(tvOS)
|
||||||
|
LandscapeItemElement(item: item)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
}
|
||||||
|
}.frame(height: 350)
|
||||||
|
}
|
||||||
|
if !viewModel.seriesItems.isEmpty,
|
||||||
|
let items = viewModel.seriesItems
|
||||||
|
{
|
||||||
|
Text("Shows")
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.leading, 90)
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack {
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
ForEach(items, id: \.id) { item in
|
||||||
|
Button {
|
||||||
|
if let chanId = item.channelId,
|
||||||
|
let chan = viewModel.findChannel(id: chanId)
|
||||||
|
{
|
||||||
|
self.viewModel.fetchVideoPlayerViewModel(item: chan) { playerViewModel in
|
||||||
|
self.programsRouter.route(to: \.videoPlayer, playerViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
#if os(iOS)
|
||||||
|
#elseif os(tvOS)
|
||||||
|
LandscapeItemElement(item: item)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
}
|
||||||
|
}.frame(height: 350)
|
||||||
|
}
|
||||||
|
if !viewModel.movieItems.isEmpty,
|
||||||
|
let items = viewModel.movieItems
|
||||||
|
{
|
||||||
|
Text("Movies")
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.leading, 90)
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack {
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
ForEach(items, id: \.id) { item in
|
||||||
|
Button {
|
||||||
|
if let chanId = item.channelId,
|
||||||
|
let chan = viewModel.findChannel(id: chanId)
|
||||||
|
{
|
||||||
|
self.viewModel.fetchVideoPlayerViewModel(item: chan) { playerViewModel in
|
||||||
|
self.programsRouter.route(to: \.videoPlayer, playerViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
#if os(iOS)
|
||||||
|
#elseif os(tvOS)
|
||||||
|
LandscapeItemElement(item: item)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
}
|
||||||
|
}.frame(height: 350)
|
||||||
|
}
|
||||||
|
if !viewModel.sportsItems.isEmpty,
|
||||||
|
let items = viewModel.sportsItems
|
||||||
|
{
|
||||||
|
Text("Sports")
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.leading, 90)
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack {
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
ForEach(items, id: \.id) { item in
|
||||||
|
Button {
|
||||||
|
if let chanId = item.channelId,
|
||||||
|
let chan = viewModel.findChannel(id: chanId)
|
||||||
|
{
|
||||||
|
self.viewModel.fetchVideoPlayerViewModel(item: chan) { playerViewModel in
|
||||||
|
self.programsRouter.route(to: \.videoPlayer, playerViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
#if os(iOS)
|
||||||
|
#elseif os(tvOS)
|
||||||
|
LandscapeItemElement(item: item)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
}
|
||||||
|
}.frame(height: 350)
|
||||||
|
}
|
||||||
|
if !viewModel.kidsItems.isEmpty,
|
||||||
|
let items = viewModel.kidsItems
|
||||||
|
{
|
||||||
|
Text("Kids")
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.leading, 90)
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack {
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
ForEach(items, id: \.id) { item in
|
||||||
|
Button {
|
||||||
|
if let chanId = item.channelId,
|
||||||
|
let chan = viewModel.findChannel(id: chanId)
|
||||||
|
{
|
||||||
|
self.viewModel.fetchVideoPlayerViewModel(item: chan) { playerViewModel in
|
||||||
|
self.programsRouter.route(to: \.videoPlayer, playerViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
#if os(iOS)
|
||||||
|
#elseif os(tvOS)
|
||||||
|
LandscapeItemElement(item: item)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
}
|
||||||
|
}.frame(height: 350)
|
||||||
|
}
|
||||||
|
if !viewModel.newsItems.isEmpty,
|
||||||
|
let items = viewModel.newsItems
|
||||||
|
{
|
||||||
|
Text("News")
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.leading, 90)
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack {
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
ForEach(items, id: \.id) { item in
|
||||||
|
Button {
|
||||||
|
if let chanId = item.channelId,
|
||||||
|
let chan = viewModel.findChannel(id: chanId)
|
||||||
|
{
|
||||||
|
self.viewModel.fetchVideoPlayerViewModel(item: chan) { playerViewModel in
|
||||||
|
self.programsRouter.route(to: \.videoPlayer, playerViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
#if os(iOS)
|
||||||
|
#elseif os(tvOS)
|
||||||
|
LandscapeItemElement(item: item)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 45)
|
||||||
|
}
|
||||||
|
}.frame(height: 350)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ struct ExperimentalSettingsView: View {
|
||||||
var syncSubtitleStateWithAdjacent
|
var syncSubtitleStateWithAdjacent
|
||||||
@Default(.Experimental.nativePlayer)
|
@Default(.Experimental.nativePlayer)
|
||||||
var nativePlayer
|
var nativePlayer
|
||||||
|
@Default(.Experimental.liveTVAlphaEnabled)
|
||||||
|
var liveTVAlphaEnabled
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
|
@ -31,6 +33,14 @@ struct ExperimentalSettingsView: View {
|
||||||
} header: {
|
} header: {
|
||||||
L10n.experimental.text
|
L10n.experimental.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
|
||||||
|
Toggle("Live TV (Alpha)", isOn: $liveTVAlphaEnabled)
|
||||||
|
|
||||||
|
} header: {
|
||||||
|
Text("Live TV")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
//struct NativePlayerView: UIViewControllerRepresentable {
|
||||||
|
//
|
||||||
|
// let viewModel: VideoPlayerViewModel
|
||||||
|
//
|
||||||
|
// typealias UIViewControllerType = NativePlayerViewController
|
||||||
|
//
|
||||||
|
// func makeUIViewController(context: Context) -> NativePlayerViewController {
|
||||||
|
//
|
||||||
|
// NativePlayerViewController(viewModel: viewModel)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func updateUIViewController(_ uiViewController: NativePlayerViewController, context: Context) {}
|
||||||
|
//}
|
||||||
|
|
||||||
|
struct LiveTVPlayerView: UIViewControllerRepresentable {
|
||||||
|
|
||||||
|
let viewModel: VideoPlayerViewModel
|
||||||
|
|
||||||
|
typealias UIViewControllerType = LiveTVPlayerViewController
|
||||||
|
|
||||||
|
func makeUIViewController(context: Context) -> LiveTVPlayerViewController {
|
||||||
|
|
||||||
|
LiveTVPlayerViewController(viewModel: viewModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIViewController(_ uiViewController: LiveTVPlayerViewController, context: Context) {}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue