Merge branch 'main' into multi-server-url
This commit is contained in:
commit
eb901da824
|
@ -290,6 +290,9 @@
|
||||||
E18845F826DEA9C900B0C5B7 /* ItemViewBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845F726DEA9C900B0C5B7 /* ItemViewBody.swift */; };
|
E18845F826DEA9C900B0C5B7 /* ItemViewBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845F726DEA9C900B0C5B7 /* ItemViewBody.swift */; };
|
||||||
E188460026DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845FF26DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift */; };
|
E188460026DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845FF26DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift */; };
|
||||||
E188460426DEF04800B0C5B7 /* EpisodeCardVStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E188460326DEF04800B0C5B7 /* EpisodeCardVStackView.swift */; };
|
E188460426DEF04800B0C5B7 /* EpisodeCardVStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E188460326DEF04800B0C5B7 /* EpisodeCardVStackView.swift */; };
|
||||||
|
E19169CE272514760085832A /* HTTPScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19169CD272514760085832A /* HTTPScheme.swift */; };
|
||||||
|
E19169CF272514760085832A /* HTTPScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19169CD272514760085832A /* HTTPScheme.swift */; };
|
||||||
|
E19169D0272514760085832A /* HTTPScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19169CD272514760085832A /* HTTPScheme.swift */; };
|
||||||
E193D4D827193CAC00900D82 /* PortraitImageStackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */; };
|
E193D4D827193CAC00900D82 /* PortraitImageStackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */; };
|
||||||
E193D4D927193CAC00900D82 /* PortraitImageStackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */; };
|
E193D4D927193CAC00900D82 /* PortraitImageStackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */; };
|
||||||
E193D4DB27193CCA00900D82 /* PillStackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D4DA27193CCA00900D82 /* PillStackable.swift */; };
|
E193D4DB27193CCA00900D82 /* PillStackable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D4DA27193CCA00900D82 /* PillStackable.swift */; };
|
||||||
|
@ -342,6 +345,7 @@
|
||||||
E1D4BF8C2719F39F00A11E64 /* AppAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF802719D22800A11E64 /* AppAppearance.swift */; };
|
E1D4BF8C2719F39F00A11E64 /* AppAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF802719D22800A11E64 /* AppAppearance.swift */; };
|
||||||
E1D4BF8D2719F3A300A11E64 /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
E1D4BF8D2719F3A300A11E64 /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
||||||
E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */; };
|
E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */; };
|
||||||
|
E1E48CC9271E6D410021A2F9 /* RefreshHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E48CC8271E6D410021A2F9 /* RefreshHelper.swift */; };
|
||||||
E1F0204E26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
E1F0204E26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
||||||
E1F0204F26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
E1F0204F26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
||||||
E1FCD08826C35A0D007C8DCF /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FCD08726C35A0D007C8DCF /* NetworkError.swift */; };
|
E1FCD08826C35A0D007C8DCF /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FCD08726C35A0D007C8DCF /* NetworkError.swift */; };
|
||||||
|
@ -575,6 +579,7 @@
|
||||||
E18845F726DEA9C900B0C5B7 /* ItemViewBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemViewBody.swift; sourceTree = "<group>"; };
|
E18845F726DEA9C900B0C5B7 /* ItemViewBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemViewBody.swift; sourceTree = "<group>"; };
|
||||||
E18845FF26DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemLandscapeTopBarView.swift; sourceTree = "<group>"; };
|
E18845FF26DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemLandscapeTopBarView.swift; sourceTree = "<group>"; };
|
||||||
E188460326DEF04800B0C5B7 /* EpisodeCardVStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeCardVStackView.swift; sourceTree = "<group>"; };
|
E188460326DEF04800B0C5B7 /* EpisodeCardVStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeCardVStackView.swift; sourceTree = "<group>"; };
|
||||||
|
E19169CD272514760085832A /* HTTPScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPScheme.swift; sourceTree = "<group>"; };
|
||||||
E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortraitImageStackable.swift; sourceTree = "<group>"; };
|
E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortraitImageStackable.swift; sourceTree = "<group>"; };
|
||||||
E193D4DA27193CCA00900D82 /* PillStackable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillStackable.swift; sourceTree = "<group>"; };
|
E193D4DA27193CCA00900D82 /* PillStackable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillStackable.swift; sourceTree = "<group>"; };
|
||||||
E193D5422719407E00900D82 /* tvOSMainCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = tvOSMainCoordinator.swift; sourceTree = "<group>"; };
|
E193D5422719407E00900D82 /* tvOSMainCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = tvOSMainCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
@ -597,6 +602,7 @@
|
||||||
E1D4BF862719D27100A11E64 /* Bitrates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bitrates.swift; sourceTree = "<group>"; };
|
E1D4BF862719D27100A11E64 /* Bitrates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bitrates.swift; sourceTree = "<group>"; };
|
||||||
E1D4BF892719D3D000A11E64 /* BasicAppSettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicAppSettingsCoordinator.swift; sourceTree = "<group>"; };
|
E1D4BF892719D3D000A11E64 /* BasicAppSettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicAppSettingsCoordinator.swift; sourceTree = "<group>"; };
|
||||||
E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicAppSettingsView.swift; sourceTree = "<group>"; };
|
E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicAppSettingsView.swift; sourceTree = "<group>"; };
|
||||||
|
E1E48CC8271E6D410021A2F9 /* RefreshHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshHelper.swift; sourceTree = "<group>"; };
|
||||||
E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerJumpLength.swift; sourceTree = "<group>"; };
|
E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerJumpLength.swift; sourceTree = "<group>"; };
|
||||||
E1FCD08726C35A0D007C8DCF /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = "<group>"; };
|
E1FCD08726C35A0D007C8DCF /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = "<group>"; };
|
||||||
E1FCD09526C47118007C8DCF /* ErrorMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorMessage.swift; sourceTree = "<group>"; };
|
E1FCD09526C47118007C8DCF /* ErrorMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorMessage.swift; sourceTree = "<group>"; };
|
||||||
|
@ -807,6 +813,7 @@
|
||||||
E1AD104926D94822003E4A08 /* DetailItem.swift */,
|
E1AD104926D94822003E4A08 /* DetailItem.swift */,
|
||||||
53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */,
|
53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */,
|
||||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */,
|
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */,
|
||||||
|
E19169CD272514760085832A /* HTTPScheme.swift */,
|
||||||
E193D4DA27193CCA00900D82 /* PillStackable.swift */,
|
E193D4DA27193CCA00900D82 /* PillStackable.swift */,
|
||||||
E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */,
|
E193D4D727193CAC00900D82 /* PortraitImageStackable.swift */,
|
||||||
E1D4BF832719D25A00A11E64 /* TrackLanguage.swift */,
|
E1D4BF832719D25A00A11E64 /* TrackLanguage.swift */,
|
||||||
|
@ -856,6 +863,7 @@
|
||||||
5377CBF3263B596A003A4E83 /* JellyfinPlayer */ = {
|
5377CBF3263B596A003A4E83 /* JellyfinPlayer */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E1DD1127271E7D15005BE12F /* Objects */,
|
||||||
E13DD3BB27163C3E009D4DAF /* App */,
|
E13DD3BB27163C3E009D4DAF /* App */,
|
||||||
62ECA01926FA6D6900E8EBB7 /* AppURLHandler */,
|
62ECA01926FA6D6900E8EBB7 /* AppURLHandler */,
|
||||||
5377CBF8263B596B003A4E83 /* Assets.xcassets */,
|
5377CBF8263B596B003A4E83 /* Assets.xcassets */,
|
||||||
|
@ -1293,6 +1301,14 @@
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E1DD1127271E7D15005BE12F /* Objects */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E1E48CC8271E6D410021A2F9 /* RefreshHelper.swift */,
|
||||||
|
);
|
||||||
|
path = Objects;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E1FCD08E26C466F3007C8DCF /* Errors */ = {
|
E1FCD08E26C466F3007C8DCF /* Errors */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1734,6 +1750,7 @@
|
||||||
E193D549271941CC00900D82 /* UserSignInView.swift in Sources */,
|
E193D549271941CC00900D82 /* UserSignInView.swift in Sources */,
|
||||||
535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */,
|
535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */,
|
||||||
53ABFDE5267974EF00886593 /* ViewModel.swift in Sources */,
|
53ABFDE5267974EF00886593 /* ViewModel.swift in Sources */,
|
||||||
|
E19169CF272514760085832A /* HTTPScheme.swift in Sources */,
|
||||||
C45B29BB26FAC5B600CEF5E0 /* ColorExtension.swift in Sources */,
|
C45B29BB26FAC5B600CEF5E0 /* ColorExtension.swift in Sources */,
|
||||||
531069582684E7EE00CFFDBA /* MediaInfoView.swift in Sources */,
|
531069582684E7EE00CFFDBA /* MediaInfoView.swift in Sources */,
|
||||||
E1D4BF822719D22800A11E64 /* AppAppearance.swift in Sources */,
|
E1D4BF822719D22800A11E64 /* AppAppearance.swift in Sources */,
|
||||||
|
@ -1808,6 +1825,7 @@
|
||||||
E173DA5426D050F500CC4EB7 /* ServerDetailViewModel.swift in Sources */,
|
E173DA5426D050F500CC4EB7 /* ServerDetailViewModel.swift in Sources */,
|
||||||
E188460426DEF04800B0C5B7 /* EpisodeCardVStackView.swift in Sources */,
|
E188460426DEF04800B0C5B7 /* EpisodeCardVStackView.swift in Sources */,
|
||||||
53F8377D265FF67C00F456B3 /* VideoPlayerSettingsView.swift in Sources */,
|
53F8377D265FF67C00F456B3 /* VideoPlayerSettingsView.swift in Sources */,
|
||||||
|
E19169CE272514760085832A /* HTTPScheme.swift in Sources */,
|
||||||
53192D5D265AA78A008A4215 /* DeviceProfileBuilder.swift in Sources */,
|
53192D5D265AA78A008A4215 /* DeviceProfileBuilder.swift in Sources */,
|
||||||
62133890265F83A900A81A2A /* LibraryListView.swift in Sources */,
|
62133890265F83A900A81A2A /* LibraryListView.swift in Sources */,
|
||||||
62C29EA326D1030F00C1D2E7 /* ConnectToServerCoodinator.swift in Sources */,
|
62C29EA326D1030F00C1D2E7 /* ConnectToServerCoodinator.swift in Sources */,
|
||||||
|
@ -1841,6 +1859,7 @@
|
||||||
6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */,
|
6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */,
|
||||||
62E632F3267D54030063E547 /* ItemViewModel.swift in Sources */,
|
62E632F3267D54030063E547 /* ItemViewModel.swift in Sources */,
|
||||||
53DE4BD2267098F300739748 /* SearchBarView.swift in Sources */,
|
53DE4BD2267098F300739748 /* SearchBarView.swift in Sources */,
|
||||||
|
E1E48CC9271E6D410021A2F9 /* RefreshHelper.swift in Sources */,
|
||||||
E1D4BF842719D25A00A11E64 /* TrackLanguage.swift in Sources */,
|
E1D4BF842719D25A00A11E64 /* TrackLanguage.swift in Sources */,
|
||||||
E14F7D0726DB36EF007C3AE6 /* ItemPortraitMainView.swift in Sources */,
|
E14F7D0726DB36EF007C3AE6 /* ItemPortraitMainView.swift in Sources */,
|
||||||
E1AD106226D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift in Sources */,
|
E1AD106226D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift in Sources */,
|
||||||
|
@ -1904,6 +1923,7 @@
|
||||||
files = (
|
files = (
|
||||||
53649AB3269D3F5B00A2D8B7 /* LogManager.swift in Sources */,
|
53649AB3269D3F5B00A2D8B7 /* LogManager.swift in Sources */,
|
||||||
E13DD3CB27164BA8009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
E13DD3CB27164BA8009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
||||||
|
E19169D0272514760085832A /* HTTPScheme.swift in Sources */,
|
||||||
6267B3D726710B9700A7371D /* CollectionExtensions.swift in Sources */,
|
6267B3D726710B9700A7371D /* CollectionExtensions.swift in Sources */,
|
||||||
628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */,
|
628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */,
|
||||||
6267B3DB2671139400A7371D /* ImageExtensions.swift in Sources */,
|
6267B3DB2671139400A7371D /* ImageExtensions.swift in Sources */,
|
||||||
|
|
|
@ -19,8 +19,7 @@ struct JellyfinPlayerApp: App {
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
// TODO: Replace with a SplashView
|
EmptyView()
|
||||||
Color(appAppearance.style == .light ? UIColor.white : UIColor.black)
|
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
.onAppear {
|
.onAppear {
|
||||||
setupAppearance()
|
setupAppearance()
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "1.000",
|
||||||
|
"green" : "1.000",
|
||||||
|
"red" : "1.000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0.000",
|
||||||
|
"green" : "0.000",
|
||||||
|
"red" : "0.000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "swiftfin-logo.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "swiftfin-logo-1.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "swiftfin-logo-2.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -62,9 +62,14 @@ network.</string>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UILaunchScreen</key>
|
<key>UILaunchScreen</key>
|
||||||
<dict/>
|
<dict>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UIImageRespectsSafeAreaInsets</key>
|
||||||
<string>VideoPlayer</string>
|
<true/>
|
||||||
|
<key>UIImageName</key>
|
||||||
|
<string>swiftfin-logo</string>
|
||||||
|
<key>UIColorName</key>
|
||||||
|
<string>LaunchScreenBackground</string>
|
||||||
|
</dict>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
<array>
|
<array>
|
||||||
<string>armv7</string>
|
<string>armv7</string>
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* 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 2021 Aiden Vigue & Jellyfin Contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
// A more general derivative of
|
||||||
|
// https://stackoverflow.com/questions/65812080/introspect-library-uirefreshcontrol-with-swiftui-not-working
|
||||||
|
class RefreshHelper {
|
||||||
|
var refreshControl: UIRefreshControl?
|
||||||
|
var refreshAction: (() -> Void)?
|
||||||
|
|
||||||
|
@objc func didRefresh() {
|
||||||
|
guard let refreshControl = refreshControl else { return }
|
||||||
|
refreshAction?()
|
||||||
|
refreshControl.endRefreshing()
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ struct BasicAppSettingsView: View {
|
||||||
@State var resetTapped: Bool = false
|
@State var resetTapped: Bool = false
|
||||||
|
|
||||||
@Default(.appAppearance) var appAppearance
|
@Default(.appAppearance) var appAppearance
|
||||||
|
@Default(.defaultHTTPScheme) var defaultHTTPScheme
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
|
@ -33,6 +34,16 @@ struct BasicAppSettingsView: View {
|
||||||
Text("Accessibility")
|
Text("Accessibility")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
Picker("Default Scheme", selection: $defaultHTTPScheme) {
|
||||||
|
ForEach(HTTPScheme.allCases, id: \.self) { scheme in
|
||||||
|
Text("\(scheme.rawValue)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} header: {
|
||||||
|
Text("Networking")
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
resetTapped = true
|
resetTapped = true
|
||||||
} label: {
|
} label: {
|
||||||
|
|
|
@ -6,14 +6,17 @@
|
||||||
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import SwiftUI
|
import Defaults
|
||||||
import Stinsen
|
import Stinsen
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct ConnectToServerView: View {
|
struct ConnectToServerView: View {
|
||||||
|
|
||||||
@ObservedObject var viewModel: ConnectToServerViewModel
|
@ObservedObject var viewModel: ConnectToServerViewModel
|
||||||
@State var uri = ""
|
@State var uri = ""
|
||||||
|
|
||||||
|
@Default(.defaultHTTPScheme) var defaultHTTPScheme
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
Section {
|
Section {
|
||||||
|
@ -21,6 +24,11 @@ struct ConnectToServerView: View {
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
.keyboardType(.URL)
|
.keyboardType(.URL)
|
||||||
|
.onAppear {
|
||||||
|
if uri == "" {
|
||||||
|
uri = "\(defaultHTTPScheme.rawValue)://"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if viewModel.isLoading {
|
if viewModel.isLoading {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
|
|
|
@ -8,12 +8,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Introspect
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct HomeView: View {
|
struct HomeView: View {
|
||||||
|
|
||||||
@EnvironmentObject var homeRouter: HomeCoordinator.Router
|
@EnvironmentObject var homeRouter: HomeCoordinator.Router
|
||||||
@StateObject var viewModel = HomeViewModel()
|
@StateObject var viewModel = HomeViewModel()
|
||||||
|
|
||||||
|
private let refreshHelper = RefreshHelper()
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var innerBody: some View {
|
var innerBody: some View {
|
||||||
|
@ -28,33 +31,40 @@ struct HomeView: View {
|
||||||
if !viewModel.nextUpItems.isEmpty {
|
if !viewModel.nextUpItems.isEmpty {
|
||||||
NextUpView(items: viewModel.nextUpItems)
|
NextUpView(items: viewModel.nextUpItems)
|
||||||
}
|
}
|
||||||
if !viewModel.librariesShowRecentlyAddedIDs.isEmpty {
|
|
||||||
ForEach(viewModel.librariesShowRecentlyAddedIDs, id: \.self) { libraryID in
|
ForEach(viewModel.libraries, id: \.self) { library in
|
||||||
let library = viewModel.libraries.first(where: { $0.id == libraryID })
|
HStack {
|
||||||
HStack {
|
Text("Latest \(library.name ?? "")")
|
||||||
Text("Latest \(library?.name ?? "")")
|
.font(.title2)
|
||||||
.font(.title2)
|
.fontWeight(.bold)
|
||||||
.fontWeight(.bold)
|
Spacer()
|
||||||
Spacer()
|
Button {
|
||||||
Button {
|
homeRouter
|
||||||
homeRouter
|
.route(to: \.library, (viewModel: .init(parentID: library.id!,
|
||||||
.route(to: \.library, (viewModel: .init(parentID: libraryID,
|
filters: viewModel.recentFilterSet),
|
||||||
filters: viewModel.recentFilterSet),
|
title: library.name ?? ""))
|
||||||
title: library?.name ?? ""))
|
} label: {
|
||||||
} label: {
|
HStack {
|
||||||
HStack {
|
Text("See All").font(.subheadline).fontWeight(.bold)
|
||||||
Text("See All").font(.subheadline).fontWeight(.bold)
|
Image(systemName: "chevron.right").font(Font.subheadline.bold())
|
||||||
Image(systemName: "chevron.right").font(Font.subheadline.bold())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.padding(.leading, 16)
|
}
|
||||||
.padding(.trailing, 16)
|
}.padding(.leading, 16)
|
||||||
LatestMediaView(viewModel: .init(libraryID: libraryID))
|
.padding(.trailing, 16)
|
||||||
}
|
LatestMediaView(viewModel: .init(libraryID: library.id!))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.bottom, UIDevice.current.userInterfaceIdiom == .phone ? 20 : 30)
|
.padding(.bottom, UIDevice.current.userInterfaceIdiom == .phone ? 20 : 30)
|
||||||
}
|
}
|
||||||
|
.introspectScrollView { scrollView in
|
||||||
|
let control = UIRefreshControl()
|
||||||
|
|
||||||
|
refreshHelper.refreshControl = control
|
||||||
|
refreshHelper.refreshAction = viewModel.refresh
|
||||||
|
|
||||||
|
control.addTarget(refreshHelper, action: #selector(RefreshHelper.didRefresh), for: .valueChanged)
|
||||||
|
scrollView.refreshControl = control
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* 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 2021 Aiden Vigue & Jellyfin Contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Defaults
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum HTTPScheme: String, Defaults.Serializable, CaseIterable {
|
||||||
|
case http
|
||||||
|
case https
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ public class ServerDiscovery {
|
||||||
if let port = components?.port {
|
if let port = components?.port {
|
||||||
return port
|
return port
|
||||||
}
|
}
|
||||||
return 8096
|
return 7359
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -54,10 +54,14 @@ final class SessionManager {
|
||||||
|
|
||||||
// Connects to a server at the given uri, storing if successful
|
// Connects to a server at the given uri, storing if successful
|
||||||
func connectToServer(with uri: String) -> AnyPublisher<SwiftfinStore.State.Server, Error> {
|
func connectToServer(with uri: String) -> AnyPublisher<SwiftfinStore.State.Server, Error> {
|
||||||
var uri = uri
|
var uriComponents = URLComponents(string: uri) ?? URLComponents()
|
||||||
if !uri.contains("http") {
|
|
||||||
uri = "https://" + uri
|
if uriComponents.scheme == nil {
|
||||||
|
uriComponents.scheme = SwiftfinStore.Defaults.suite[.defaultHTTPScheme].rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uri = uriComponents.string ?? ""
|
||||||
|
|
||||||
if uri.last == "/" {
|
if uri.last == "/" {
|
||||||
uri = String(uri.dropLast())
|
uri = String(uri.dropLast())
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ extension SwiftfinStore {
|
||||||
extension Defaults.Keys {
|
extension Defaults.Keys {
|
||||||
static let lastServerUserID = Defaults.Key<String?>("lastServerUserID", suite: SwiftfinStore.Defaults.suite)
|
static let lastServerUserID = Defaults.Key<String?>("lastServerUserID", suite: SwiftfinStore.Defaults.suite)
|
||||||
|
|
||||||
|
static let defaultHTTPScheme = Key<HTTPScheme>("defaultHTTPScheme", default: .http, suite: SwiftfinStore.Defaults.suite)
|
||||||
static let inNetworkBandwidth = Key<Int>("InNetworkBandwidth", default: 40_000_000, suite: SwiftfinStore.Defaults.suite)
|
static let inNetworkBandwidth = Key<Int>("InNetworkBandwidth", default: 40_000_000, suite: SwiftfinStore.Defaults.suite)
|
||||||
static let outOfNetworkBandwidth = Key<Int>("OutOfNetworkBandwidth", default: 40_000_000, suite: SwiftfinStore.Defaults.suite)
|
static let outOfNetworkBandwidth = Key<Int>("OutOfNetworkBandwidth", default: 40_000_000, suite: SwiftfinStore.Defaults.suite)
|
||||||
static let isAutoSelectSubtitles = Key<Bool>("isAutoSelectSubtitles", default: false, suite: SwiftfinStore.Defaults.suite)
|
static let isAutoSelectSubtitles = Key<Bool>("isAutoSelectSubtitles", default: false, suite: SwiftfinStore.Defaults.suite)
|
||||||
|
|
|
@ -14,10 +14,10 @@ import JellyfinAPI
|
||||||
|
|
||||||
final class HomeViewModel: ViewModel {
|
final class HomeViewModel: ViewModel {
|
||||||
|
|
||||||
@Published var librariesShowRecentlyAddedIDs = [String]()
|
@Published var librariesShowRecentlyAddedIDs: [String] = []
|
||||||
@Published var libraries = [BaseItemDto]()
|
@Published var libraries: [BaseItemDto] = []
|
||||||
@Published var resumeItems = [BaseItemDto]()
|
@Published var resumeItems: [BaseItemDto] = []
|
||||||
@Published var nextUpItems = [BaseItemDto]()
|
@Published var nextUpItems: [BaseItemDto] = []
|
||||||
|
|
||||||
// temp
|
// temp
|
||||||
var recentFilterSet: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.descending], sortBy: [.dateAdded])
|
var recentFilterSet: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.descending], sortBy: [.dateAdded])
|
||||||
|
@ -32,26 +32,42 @@ final class HomeViewModel: ViewModel {
|
||||||
UserViewsAPI.getUserViews(userId: SessionManager.main.currentLogin.user.id)
|
UserViewsAPI.getUserViews(userId: SessionManager.main.currentLogin.user.id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.handleAPIRequestError(completion: completion)
|
switch completion {
|
||||||
|
case .finished: ()
|
||||||
|
case .failure(_):
|
||||||
|
self.libraries = []
|
||||||
|
self.handleAPIRequestError(completion: completion)
|
||||||
|
}
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
|
|
||||||
|
var newLibraries: [BaseItemDto] = []
|
||||||
|
|
||||||
response.items!.forEach { item in
|
response.items!.forEach { item in
|
||||||
LogManager.shared.log.debug("Retrieved user view: \(item.id!) (\(item.name ?? "nil")) with type \(item.collectionType ?? "nil")")
|
LogManager.shared.log.debug("Retrieved user view: \(item.id!) (\(item.name ?? "nil")) with type \(item.collectionType ?? "nil")")
|
||||||
if item.collectionType == "movies" || item.collectionType == "tvshows" {
|
if item.collectionType == "movies" || item.collectionType == "tvshows" {
|
||||||
self.libraries.append(item)
|
newLibraries.append(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UserAPI.getCurrentUser()
|
UserAPI.getCurrentUser()
|
||||||
.trackActivity(self.loading)
|
.trackActivity(self.loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.handleAPIRequestError(completion: completion)
|
switch completion {
|
||||||
|
case .finished: ()
|
||||||
|
case .failure(_):
|
||||||
|
self.libraries = []
|
||||||
|
self.handleAPIRequestError(completion: completion)
|
||||||
|
}
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
self.libraries.forEach { library in
|
let excludeIDs = response.configuration?.latestItemsExcludes != nil ? response.configuration!.latestItemsExcludes! : []
|
||||||
if !(response.configuration?.latestItemsExcludes?.contains(library.id!))! {
|
|
||||||
LogManager.shared.log.debug("Adding library \(library.id!) (\(library.name ?? "nil")) to recently added list")
|
for excludeID in excludeIDs {
|
||||||
self.librariesShowRecentlyAddedIDs.append(library.id!)
|
newLibraries.removeAll { library in
|
||||||
|
return library.id == excludeID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.libraries = newLibraries
|
||||||
})
|
})
|
||||||
.store(in: &self.cancellables)
|
.store(in: &self.cancellables)
|
||||||
})
|
})
|
||||||
|
@ -59,12 +75,20 @@ final class HomeViewModel: ViewModel {
|
||||||
|
|
||||||
ItemsAPI.getResumeItems(userId: SessionManager.main.currentLogin.user.id, limit: 12,
|
ItemsAPI.getResumeItems(userId: SessionManager.main.currentLogin.user.id, limit: 12,
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||||
mediaTypes: ["Video"], imageTypeLimit: 1, enableImageTypes: [.primary, .backdrop, .thumb])
|
mediaTypes: ["Video"],
|
||||||
|
imageTypeLimit: 1,
|
||||||
|
enableImageTypes: [.primary, .backdrop, .thumb])
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.handleAPIRequestError(completion: completion)
|
switch completion {
|
||||||
|
case .finished: ()
|
||||||
|
case .failure(_):
|
||||||
|
self.resumeItems = []
|
||||||
|
self.handleAPIRequestError(completion: completion)
|
||||||
|
}
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
LogManager.shared.log.debug("Retrieved \(String(response.items!.count)) resume items")
|
LogManager.shared.log.debug("Retrieved \(String(response.items!.count)) resume items")
|
||||||
|
|
||||||
self.resumeItems = response.items ?? []
|
self.resumeItems = response.items ?? []
|
||||||
})
|
})
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
@ -73,9 +97,15 @@ final class HomeViewModel: ViewModel {
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.handleAPIRequestError(completion: completion)
|
switch completion {
|
||||||
|
case .finished: ()
|
||||||
|
case .failure(_):
|
||||||
|
self.nextUpItems = []
|
||||||
|
self.handleAPIRequestError(completion: completion)
|
||||||
|
}
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
LogManager.shared.log.debug("Retrieved \(String(response.items!.count)) nextup items")
|
LogManager.shared.log.debug("Retrieved \(String(response.items!.count)) nextup items")
|
||||||
|
|
||||||
self.nextUpItems = response.items ?? []
|
self.nextUpItems = response.items ?? []
|
||||||
})
|
})
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue