Initial CoreStore foundation
This commit is contained in:
parent
9a578f3041
commit
4e75905f70
|
@ -7,6 +7,7 @@
|
|||
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
struct JellyfinPlayer_tvOSApp: App {
|
||||
let persistenceController = PersistenceController.shared
|
||||
|
|
|
@ -258,6 +258,17 @@
|
|||
E131691726C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; };
|
||||
E131691826C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; };
|
||||
E131691926C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; };
|
||||
E13DD3BD27163C63009D4DAF /* EmailHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3BC27163C63009D4DAF /* EmailHelper.swift */; };
|
||||
E13DD3BF27163DD7009D4DAF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3BE27163DD7009D4DAF /* AppDelegate.swift */; };
|
||||
E13DD3C227164941009D4DAF /* SwiftfinStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C127164941009D4DAF /* SwiftfinStore.swift */; };
|
||||
E13DD3C327164941009D4DAF /* SwiftfinStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C127164941009D4DAF /* SwiftfinStore.swift */; };
|
||||
E13DD3C62716499E009D4DAF /* CoreStore in Frameworks */ = {isa = PBXBuildFile; productRef = E13DD3C52716499E009D4DAF /* CoreStore */; };
|
||||
E13DD3C827164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */; };
|
||||
E13DD3C927164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */; };
|
||||
E13DD3CA27164B80009D4DAF /* SwiftfinStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C127164941009D4DAF /* SwiftfinStore.swift */; };
|
||||
E13DD3CB27164BA8009D4DAF /* UIDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */; };
|
||||
E13DD3CD27164CA7009D4DAF /* CoreStore in Frameworks */ = {isa = PBXBuildFile; productRef = E13DD3CC27164CA7009D4DAF /* CoreStore */; };
|
||||
E13DD3CF27164E1F009D4DAF /* CoreStore in Frameworks */ = {isa = PBXBuildFile; productRef = E13DD3CE27164E1F009D4DAF /* CoreStore */; };
|
||||
E14F7D0726DB36EF007C3AE6 /* ItemPortraitMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E14F7D0626DB36EF007C3AE6 /* ItemPortraitMainView.swift */; };
|
||||
E14F7D0926DB36F7007C3AE6 /* ItemLandscapeMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E14F7D0826DB36F7007C3AE6 /* ItemLandscapeMainView.swift */; };
|
||||
E173DA5026D048D600CC4EB7 /* ServerDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E173DA4F26D048D600CC4EB7 /* ServerDetailView.swift */; };
|
||||
|
@ -492,6 +503,10 @@
|
|||
DE5004F745B19E28744A7DE7 /* Pods-JellyfinPlayer tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinPlayer tvOS.debug.xcconfig"; path = "Target Support Files/Pods-JellyfinPlayer tvOS/Pods-JellyfinPlayer tvOS.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
E100720626BDABC100CE3E31 /* MediaPlayButtonRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayButtonRowView.swift; sourceTree = "<group>"; };
|
||||
E131691626C583BC0074BFEE /* LogConstructor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogConstructor.swift; sourceTree = "<group>"; };
|
||||
E13DD3BC27163C63009D4DAF /* EmailHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailHelper.swift; sourceTree = "<group>"; };
|
||||
E13DD3BE27163DD7009D4DAF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
E13DD3C127164941009D4DAF /* SwiftfinStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinStore.swift; sourceTree = "<group>"; };
|
||||
E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDeviceExtensions.swift; sourceTree = "<group>"; };
|
||||
E14F7D0626DB36EF007C3AE6 /* ItemPortraitMainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemPortraitMainView.swift; sourceTree = "<group>"; };
|
||||
E14F7D0826DB36F7007C3AE6 /* ItemLandscapeMainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemLandscapeMainView.swift; sourceTree = "<group>"; };
|
||||
E173DA4F26D048D600CC4EB7 /* ServerDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailView.swift; sourceTree = "<group>"; };
|
||||
|
@ -529,6 +544,7 @@
|
|||
5358708D2669D7A800D05A09 /* KeychainSwift in Frameworks */,
|
||||
536D3D84267BEA550004248C /* ParallaxView in Frameworks */,
|
||||
53ABFDDC267972BF00886593 /* TVServices.framework in Frameworks */,
|
||||
E13DD3CD27164CA7009D4DAF /* CoreStore in Frameworks */,
|
||||
5358709B2669D7A800D05A09 /* NukeUI in Frameworks */,
|
||||
53ABFDED26799D7700886593 /* ActivityIndicator in Frameworks */,
|
||||
);
|
||||
|
@ -545,6 +561,7 @@
|
|||
53EC6E25267EB10F006DD26A /* SwiftyJSON in Frameworks */,
|
||||
53EC6E21267E80B1006DD26A /* Pods_JellyfinPlayer_iOS.framework in Frameworks */,
|
||||
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
||||
E13DD3C62716499E009D4DAF /* CoreStore in Frameworks */,
|
||||
621C638026672A30004216EA /* NukeUI in Frameworks */,
|
||||
625CB57A2678C4A400530A6E /* ActivityIndicator in Frameworks */,
|
||||
6260FFF926A09754003FA968 /* CombineExt in Frameworks */,
|
||||
|
@ -563,6 +580,7 @@
|
|||
53649AB5269D423A00A2D8B7 /* Puppy in Frameworks */,
|
||||
536D3D7D267BD5F90004248C /* ActivityIndicator in Frameworks */,
|
||||
628B953A2670CE250091AF3B /* KeychainSwift in Frameworks */,
|
||||
E13DD3CF27164E1F009D4DAF /* CoreStore in Frameworks */,
|
||||
628B95352670CAEA0091AF3B /* JellyfinAPI in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -710,6 +728,7 @@
|
|||
535870752669D60C00D05A09 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E13DD3C0271648EC009D4DAF /* SwiftfinStore */,
|
||||
E1FCD08E26C466F3007C8DCF /* Errors */,
|
||||
621338912660106C00A81A2A /* Extensions */,
|
||||
535870AB2669D8D300D05A09 /* Objects */,
|
||||
|
@ -774,6 +793,7 @@
|
|||
5377CBF3263B596A003A4E83 /* JellyfinPlayer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E13DD3BB27163C3E009D4DAF /* App */,
|
||||
62C29E9D26D0FE5900C1D2E7 /* Coordinators */,
|
||||
53F866422687A45400DCD1D7 /* Components */,
|
||||
62ECA01926FA6D6900E8EBB7 /* Singleton */,
|
||||
|
@ -783,7 +803,6 @@
|
|||
5389276D263C25100035E14B /* ContinueWatchingView.swift */,
|
||||
5377CC02263B596B003A4E83 /* Info.plist */,
|
||||
E14F7D0A26DB3714007C3AE6 /* ItemView */,
|
||||
5377CBF4263B596A003A4E83 /* JellyfinPlayerApp.swift */,
|
||||
53FF7F29263CF3F500585C35 /* LatestMediaView.swift */,
|
||||
53E4E646263F6CF100F67C6B /* LibraryFilterView.swift */,
|
||||
6213388F265F83A900A81A2A /* LibraryListView.swift */,
|
||||
|
@ -978,6 +997,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
5389277B263CC3DB0035E14B /* BlurHashDecode.swift */,
|
||||
E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */,
|
||||
6267B3D526710B8900A7371D /* CollectionExtensions.swift */,
|
||||
E173DA5126D04AAF00CC4EB7 /* ColorExtension.swift */,
|
||||
62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */,
|
||||
|
@ -1058,6 +1078,24 @@
|
|||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E13DD3BB27163C3E009D4DAF /* App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5377CBF4263B596A003A4E83 /* JellyfinPlayerApp.swift */,
|
||||
E13DD3BE27163DD7009D4DAF /* AppDelegate.swift */,
|
||||
E13DD3BC27163C63009D4DAF /* EmailHelper.swift */,
|
||||
);
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E13DD3C0271648EC009D4DAF /* SwiftfinStore */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E13DD3C127164941009D4DAF /* SwiftfinStore.swift */,
|
||||
);
|
||||
path = SwiftfinStore;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E14F7D0A26DB3714007C3AE6 /* ItemView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1151,6 +1189,7 @@
|
|||
53649AAE269CFAF600A2D8B7 /* Puppy */,
|
||||
6261A0DF26A0AB710072EF1C /* CombineExt */,
|
||||
6220D0C826D63F3700B8E046 /* Stinsen */,
|
||||
E13DD3CC27164CA7009D4DAF /* CoreStore */,
|
||||
);
|
||||
productName = "JellyfinPlayer tvOS";
|
||||
productReference = 535870602669D21600D05A09 /* JellyfinPlayer tvOS.app */;
|
||||
|
@ -1186,6 +1225,7 @@
|
|||
53649AAC269CFAEA00A2D8B7 /* Puppy */,
|
||||
6260FFF826A09754003FA968 /* CombineExt */,
|
||||
62C29E9B26D0FE4200C1D2E7 /* Stinsen */,
|
||||
E13DD3C52716499E009D4DAF /* CoreStore */,
|
||||
);
|
||||
productName = JellyfinPlayer;
|
||||
productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer iOS.app */;
|
||||
|
@ -1211,6 +1251,7 @@
|
|||
536D3D7C267BD5F90004248C /* ActivityIndicator */,
|
||||
53649AB4269D423A00A2D8B7 /* Puppy */,
|
||||
53628C6C26B5AA0D008A64A0 /* Defaults */,
|
||||
E13DD3CE27164E1F009D4DAF /* CoreStore */,
|
||||
);
|
||||
productName = WidgetExtensionExtension;
|
||||
productReference = 628B95202670CABD0091AF3B /* WidgetExtension.appex */;
|
||||
|
@ -1275,6 +1316,7 @@
|
|||
53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */,
|
||||
6260FFF726A09754003FA968 /* XCRemoteSwiftPackageReference "CombineExt" */,
|
||||
62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */,
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */,
|
||||
);
|
||||
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -1535,6 +1577,7 @@
|
|||
6220D0C726D62D8700B8E046 /* VideoPlayerCoordinator.swift in Sources */,
|
||||
53272537268C1DBB0035FBF1 /* SeasonItemView.swift in Sources */,
|
||||
09389CC526814E4500AE350E /* DeviceProfileBuilder.swift in Sources */,
|
||||
E13DD3C927164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
||||
535870A62669D8AE00D05A09 /* LazyView.swift in Sources */,
|
||||
6220D0AE26D5EABB00B8E046 /* ViewExtensions.swift in Sources */,
|
||||
5321753E2671DE9C005491E6 /* Typings.swift in Sources */,
|
||||
|
@ -1552,6 +1595,7 @@
|
|||
531690FA267AD6EC005D8AB9 /* PlainNavigationLinkButton.swift in Sources */,
|
||||
E131691826C583BC0074BFEE /* LogConstructor.swift in Sources */,
|
||||
E1AD105726D981CE003E4A08 /* PortraitHStackView.swift in Sources */,
|
||||
E13DD3C327164941009D4DAF /* SwiftfinStore.swift in Sources */,
|
||||
535870A32669D89F00D05A09 /* Model.xcdatamodeld in Sources */,
|
||||
09389CC826819B4600AE350E /* VideoPlayerModel.swift in Sources */,
|
||||
);
|
||||
|
@ -1629,6 +1673,8 @@
|
|||
6220D0B126D5EC9900B8E046 /* SettingsCoordinator.swift in Sources */,
|
||||
62C29EA626D1036A00C1D2E7 /* HomeCoordinator.swift in Sources */,
|
||||
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */,
|
||||
E13DD3BD27163C63009D4DAF /* EmailHelper.swift in Sources */,
|
||||
E13DD3C227164941009D4DAF /* SwiftfinStore.swift in Sources */,
|
||||
E1AD104A26D94822003E4A08 /* DetailItem.swift in Sources */,
|
||||
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
||||
624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */,
|
||||
|
@ -1637,7 +1683,9 @@
|
|||
62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
|
||||
62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */,
|
||||
E13DD3C827164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
||||
E1AD104D26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */,
|
||||
E13DD3BF27163DD7009D4DAF /* AppDelegate.swift in Sources */,
|
||||
535870AD2669D8DD00D05A09 /* Typings.swift in Sources */,
|
||||
E1AD105F26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift in Sources */,
|
||||
6220D0BA26D6092100B8E046 /* FilterCoordinator.swift in Sources */,
|
||||
|
@ -1662,6 +1710,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
53649AB3269D3F5B00A2D8B7 /* LogManager.swift in Sources */,
|
||||
E13DD3CB27164BA8009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
||||
62EC353126766848000E9F2D /* ServerEnvironment.swift in Sources */,
|
||||
6267B3D726710B9700A7371D /* CollectionExtensions.swift in Sources */,
|
||||
628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */,
|
||||
|
@ -1676,6 +1725,7 @@
|
|||
628B95382670CDAB0091AF3B /* Model.xcdatamodeld in Sources */,
|
||||
E1FCD09926C4F358007C8DCF /* NetworkError.swift in Sources */,
|
||||
E131691926C583BC0074BFEE /* LogConstructor.swift in Sources */,
|
||||
E13DD3CA27164B80009D4DAF /* SwiftfinStore.swift in Sources */,
|
||||
62EC353226766849000E9F2D /* SessionManager.swift in Sources */,
|
||||
536D3D79267BD5D00004248C /* ViewModel.swift in Sources */,
|
||||
);
|
||||
|
@ -2087,7 +2137,7 @@
|
|||
CURRENT_PROJECT_VERSION = 60;
|
||||
DEVELOPMENT_TEAM = 9R8RREG67J;
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -2114,7 +2164,7 @@
|
|||
CURRENT_PROJECT_VERSION = 60;
|
||||
DEVELOPMENT_TEAM = 9R8RREG67J;
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -2268,6 +2318,14 @@
|
|||
kind = branch;
|
||||
};
|
||||
};
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/JohnEstropia/CoreStore.git";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 8.1.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
|
@ -2406,6 +2464,21 @@
|
|||
package = 62CB3F442685BAF7003D0A6F /* XCRemoteSwiftPackageReference "Defaults" */;
|
||||
productName = Defaults;
|
||||
};
|
||||
E13DD3C52716499E009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3CC27164CA7009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3CE27164E1F009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
|
|
|
@ -37,6 +37,15 @@
|
|||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "CoreStore",
|
||||
"repositoryURL": "https://github.com/JohnEstropia/CoreStore.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "496145761ab30e8cf1c44220c0882b95e6b41077",
|
||||
"version": "8.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Defaults",
|
||||
"repositoryURL": "https://github.com/acvigue/Defaults",
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
/*
|
||||
* 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
|
||||
|
||||
class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
static var orientationLock = UIInterfaceOrientationMask.all
|
||||
|
||||
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
||||
AppDelegate.orientationLock
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
/*
|
||||
* 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 SwiftUI
|
||||
import MessageUI
|
||||
|
||||
class EmailHelper: NSObject, MFMailComposeViewControllerDelegate {
|
||||
public static let shared = EmailHelper()
|
||||
override private init() {
|
||||
//
|
||||
}
|
||||
|
||||
func sendLogs(logURL: URL) {
|
||||
if !MFMailComposeViewController.canSendMail() {
|
||||
// Utilities.showErrorBanner(title: "No mail account found", subtitle: "Please setup a mail account")
|
||||
return // EXIT
|
||||
}
|
||||
|
||||
let picker = MFMailComposeViewController()
|
||||
|
||||
let fileManager = FileManager()
|
||||
let data = fileManager.contents(atPath: logURL.path)
|
||||
|
||||
picker.setSubject("[DEV-BUG] SwiftFin")
|
||||
picker
|
||||
.setMessageBody("Please don't edit this email.\n Please don't change the subject. \nUDID: \(UIDevice.current.identifierForVendor?.uuidString ?? "NIL")\n",
|
||||
isHTML: false)
|
||||
picker.setToRecipients(["SwiftFin Bug Reports <swiftfin-bugs@jellyfin.org>"])
|
||||
picker.addAttachmentData(data!, mimeType: "text/plain", fileName: logURL.lastPathComponent)
|
||||
picker.mailComposeDelegate = self
|
||||
|
||||
EmailHelper.getRootViewController()?.present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
EmailHelper.getRootViewController()?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
static func getRootViewController() -> UIViewController? {
|
||||
UIApplication.shared.windows.first?.rootViewController
|
||||
}
|
||||
}
|
||||
|
||||
// A view modifier that detects shaking and calls a function of our choosing.
|
||||
struct DeviceShakeViewModifier: ViewModifier {
|
||||
let action: () -> Void
|
||||
|
||||
func body(content: Self.Content) -> some View {
|
||||
content
|
||||
.onAppear()
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIDevice.deviceDidShakeNotification)) { _ in
|
||||
action()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A View extension to make the modifier easier to use.
|
||||
extension View {
|
||||
func onShake(perform action: @escaping () -> Void) -> some View {
|
||||
modifier(DeviceShakeViewModifier(action: action))
|
||||
}
|
||||
}
|
||||
|
||||
// The notification we'll send when a shake gesture happens.
|
||||
extension UIDevice {
|
||||
static let deviceDidShakeNotification = Notification.Name(rawValue: "deviceDidShakeNotification")
|
||||
}
|
||||
|
||||
// Override the default behavior of shake gestures to send our notification instead.
|
||||
extension UIWindow {
|
||||
override open func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
|
||||
if motion == .motionShake {
|
||||
NotificationCenter.default.post(name: UIDevice.deviceDidShakeNotification, object: nil)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,40 +10,6 @@ import MessageUI
|
|||
import Stinsen
|
||||
import SwiftUI
|
||||
|
||||
// The notification we'll send when a shake gesture happens.
|
||||
extension UIDevice {
|
||||
static let deviceDidShakeNotification = Notification.Name(rawValue: "deviceDidShakeNotification")
|
||||
}
|
||||
|
||||
// Override the default behavior of shake gestures to send our notification instead.
|
||||
extension UIWindow {
|
||||
override open func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
|
||||
if motion == .motionShake {
|
||||
NotificationCenter.default.post(name: UIDevice.deviceDidShakeNotification, object: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A view modifier that detects shaking and calls a function of our choosing.
|
||||
struct DeviceShakeViewModifier: ViewModifier {
|
||||
let action: () -> Void
|
||||
|
||||
func body(content: Self.Content) -> some View {
|
||||
content
|
||||
.onAppear()
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIDevice.deviceDidShakeNotification)) { _ in
|
||||
action()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A View extension to make the modifier easier to use.
|
||||
extension View {
|
||||
func onShake(perform action: @escaping () -> Void) -> some View {
|
||||
modifier(DeviceShakeViewModifier(action: action))
|
||||
}
|
||||
}
|
||||
|
||||
extension UIDevice {
|
||||
var hasNotch: Bool {
|
||||
let bottom = UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.safeAreaInsets.bottom ?? 0
|
||||
|
@ -175,43 +141,6 @@ extension View {
|
|||
}
|
||||
}
|
||||
|
||||
class EmailHelper: NSObject, MFMailComposeViewControllerDelegate {
|
||||
public static let shared = EmailHelper()
|
||||
override private init() {
|
||||
//
|
||||
}
|
||||
|
||||
func sendLogs(logURL: URL) {
|
||||
if !MFMailComposeViewController.canSendMail() {
|
||||
// Utilities.showErrorBanner(title: "No mail account found", subtitle: "Please setup a mail account")
|
||||
return // EXIT
|
||||
}
|
||||
|
||||
let picker = MFMailComposeViewController()
|
||||
|
||||
let fileManager = FileManager()
|
||||
let data = fileManager.contents(atPath: logURL.path)
|
||||
|
||||
picker.setSubject("[DEV-BUG] SwiftFin")
|
||||
picker
|
||||
.setMessageBody("Please don't edit this email.\n Please don't change the subject. \nUDID: \(UIDevice.current.identifierForVendor?.uuidString ?? "NIL")\n",
|
||||
isHTML: false)
|
||||
picker.setToRecipients(["SwiftFin Bug Reports <swiftfin-bugs@jellyfin.org>"])
|
||||
picker.addAttachmentData(data!, mimeType: "text/plain", fileName: logURL.lastPathComponent)
|
||||
picker.mailComposeDelegate = self
|
||||
|
||||
EmailHelper.getRootViewController()?.present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
EmailHelper.getRootViewController()?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
static func getRootViewController() -> UIViewController? {
|
||||
UIApplication.shared.windows.first?.rootViewController
|
||||
}
|
||||
}
|
||||
|
||||
@main
|
||||
struct JellyfinPlayerApp: App {
|
||||
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||
|
@ -221,34 +150,34 @@ struct JellyfinPlayerApp: App {
|
|||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
EmptyView()
|
||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||
.onAppear(perform: {
|
||||
MainCoordinator().view()
|
||||
.onAppear {
|
||||
setupAppearance()
|
||||
})
|
||||
.withHostingWindow { window in
|
||||
window?
|
||||
.rootViewController = PreferenceUIHostingController(wrappedView: MainCoordinator().view()
|
||||
.environment(\.managedObjectContext, persistenceController.container.viewContext))
|
||||
}
|
||||
.onShake {
|
||||
EmailHelper.shared.sendLogs(logURL: LogManager.shared.logFileURL())
|
||||
}
|
||||
.onOpenURL { url in
|
||||
AppURLHandler.shared.processDeepLink(url: url)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// WindowGroup {
|
||||
// EmptyView()
|
||||
// .environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||
// .onAppear(perform: {
|
||||
// setupAppearance()
|
||||
// })
|
||||
// .withHostingWindow { window in
|
||||
// window?
|
||||
// .rootViewController = PreferenceUIHostingController(wrappedView: MainCoordinator().view()
|
||||
// .environment(\.managedObjectContext, persistenceController.container.viewContext))
|
||||
// }
|
||||
// .onShake {
|
||||
// EmailHelper.shared.sendLogs(logURL: LogManager.shared.logFileURL())
|
||||
// }
|
||||
// .onOpenURL { url in
|
||||
// AppURLHandler.shared.processDeepLink(url: url)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private func setupAppearance() {
|
||||
UIApplication.shared.windows.first?.overrideUserInterfaceStyle = appAppearance.style
|
||||
}
|
||||
}
|
||||
|
||||
class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
static var orientationLock = UIInterfaceOrientationMask.all
|
||||
|
||||
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
||||
AppDelegate.orientationLock
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import SwiftUI
|
|||
} else {
|
||||
self.stack = NavigationStack(initial: \MainCoordinator.connectToServer)
|
||||
}
|
||||
|
||||
ImageCache.shared.costLimit = 125 * 1024 * 1024 // 125MB memory
|
||||
DataLoader.sharedUrlCache.diskCapacity = 1000 * 1024 * 1024 // 1000MB disk
|
||||
|
||||
|
|
|
@ -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 UIKit
|
||||
|
||||
extension UIDevice {
|
||||
static var vendorUUIDString: String {
|
||||
return current.identifierForVendor!.uuidString
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
import Combine
|
||||
import CoreData
|
||||
import CoreStore
|
||||
import Foundation
|
||||
import JellyfinAPI
|
||||
import KeychainSwift
|
||||
|
@ -18,6 +19,83 @@ import UIKit
|
|||
import TVServices
|
||||
#endif
|
||||
|
||||
typealias CurrentLogin = (server: SwiftfinStore.Models.Server, user: SwiftfinStore.Models.User)
|
||||
|
||||
// MARK: New SessionManager
|
||||
final class NewSessionManager {
|
||||
|
||||
// MARK: currentLogin
|
||||
private(set) var currentLogin: CurrentLogin!
|
||||
|
||||
// MARK: main
|
||||
static let main = SessionManager()
|
||||
|
||||
private let JellyfinDefaults = UserDefaults(suiteName: "jellyfin-defaults")!
|
||||
|
||||
private init() { }
|
||||
|
||||
func generateServerUserID(server: SwiftfinStore.Models.Server, user: SwiftfinStore.Models.User) -> String {
|
||||
return "\(server.id)-\(user.id)"
|
||||
}
|
||||
|
||||
func connectToServer(with uri: String) -> AnyPublisher<PublicSystemInfo, Error> {
|
||||
var uri = uri
|
||||
if !uri.contains("http") {
|
||||
uri = "https://" + uri
|
||||
}
|
||||
if uri.last == "/" {
|
||||
uri = String(uri.dropLast())
|
||||
}
|
||||
|
||||
JellyfinAPI.basePath = uri
|
||||
|
||||
return SystemAPI.getPublicSystemInfo()
|
||||
.handleEvents(receiveOutput: { response in
|
||||
print(response)
|
||||
}).eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func fetchServers() -> [SwiftfinStore.Models.Server] {
|
||||
let servers = try! SwiftfinStore.dataStack.fetchAll(From<SwiftfinStore.Models.Server>())
|
||||
return servers
|
||||
}
|
||||
|
||||
func loginUser(server: SwiftfinStore.Models.Server, username: String, password: String) -> AnyPublisher<AuthenticationResult, Error> {
|
||||
setAuthHeader(with: "")
|
||||
|
||||
return UserAPI.authenticateUserByName(authenticateUserByName: AuthenticateUserByName(username: username, pw: password))
|
||||
.handleEvents(receiveOutput: { [unowned self] response in
|
||||
guard let accessToken = response.accessToken else { fatalError() }
|
||||
setAuthHeader(with: accessToken)
|
||||
})
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
private func setAuthHeader(with accessToken: String) {
|
||||
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
|
||||
var deviceName = UIDevice.current.name
|
||||
deviceName = deviceName.folding(options: .diacriticInsensitive, locale: .current)
|
||||
deviceName = String(deviceName.unicodeScalars.filter {CharacterSet.urlQueryAllowed.contains($0) })
|
||||
|
||||
var header = "MediaBrowser "
|
||||
|
||||
let platform: String
|
||||
#if os(tvOS)
|
||||
platform = "tvOS"
|
||||
#else
|
||||
platform = "iOS"
|
||||
#endif
|
||||
|
||||
header.append("Client=\"Jellyfin \(platform)\", ")
|
||||
header.append("Device=\"\(deviceName)\", ")
|
||||
header.append("DeviceId=\"\(platform)_\(UIDevice.vendorUUIDString)_\(String(Date().timeIntervalSince1970))\", ")
|
||||
header.append("Version=\"\(appVersion ?? "0.0.1")\", ")
|
||||
header.append("Token=\"\(accessToken)\"")
|
||||
|
||||
JellyfinAPI.customHeaders["X-Emby-Authorization"] = header
|
||||
}
|
||||
}
|
||||
|
||||
final class SessionManager {
|
||||
static let current = SessionManager()
|
||||
fileprivate(set) var user: SignedInUser!
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
/*
|
||||
* 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 Foundation
|
||||
import CoreStore
|
||||
|
||||
enum SwiftfinStore {
|
||||
|
||||
enum Models {
|
||||
|
||||
final class Server: CoreStoreObject {
|
||||
|
||||
@Field.Stored("url")
|
||||
var url: String = ""
|
||||
|
||||
@Field.Stored("name")
|
||||
var name: String = ""
|
||||
|
||||
@Field.Stored("id")
|
||||
var id: String = ""
|
||||
|
||||
@Field.Relationship("users", inverse: \User.$server)
|
||||
var users: Set<User>
|
||||
}
|
||||
|
||||
final class User: CoreStoreObject {
|
||||
|
||||
@Field.Stored("name")
|
||||
var name: String = ""
|
||||
|
||||
@Field.Stored("id")
|
||||
var id: String = ""
|
||||
|
||||
@Field.Relationship("server")
|
||||
var server: Server?
|
||||
}
|
||||
}
|
||||
|
||||
static let dataStack: DataStack = {
|
||||
let schema = CoreStoreSchema(modelVersion: "V1",
|
||||
entities: [
|
||||
Entity<SwiftfinStore.Models.Server>("Server"),
|
||||
Entity<SwiftfinStore.Models.User>("User"),
|
||||
],
|
||||
versionLock: nil)
|
||||
|
||||
let _dataStack = DataStack(schema)
|
||||
try! _dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "Swiftfin.sqlite",
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
return _dataStack
|
||||
}()
|
||||
}
|
Loading…
Reference in New Issue