[create-pull-request] automated change
This commit is contained in:
parent
ac26ac8077
commit
add5908be2
|
@ -10,19 +10,19 @@
|
|||
import SwiftUI
|
||||
import JellyfinAPI
|
||||
|
||||
fileprivate struct CutOffShadow: Shape {
|
||||
let radius = 6.0;
|
||||
|
||||
private struct CutOffShadow: Shape {
|
||||
let radius = 6.0
|
||||
|
||||
func path(in rect: CGRect) -> Path {
|
||||
var path = Path()
|
||||
|
||||
|
||||
let tl = CGPoint(x: rect.minX, y: rect.minY)
|
||||
let tr = CGPoint(x: rect.maxX, y: rect.minY)
|
||||
let brs = CGPoint(x: rect.maxX, y: rect.maxY - radius)
|
||||
let brc = CGPoint(x: rect.maxX - radius, y: rect.maxY - radius)
|
||||
let bls = CGPoint(x: rect.minX + radius, y: rect.maxY)
|
||||
let blc = CGPoint(x: rect.minX + radius, y: rect.maxY - radius)
|
||||
|
||||
|
||||
path.move(to: tl)
|
||||
path.addLine(to: tr)
|
||||
path.addLine(to: brs)
|
||||
|
@ -31,29 +31,29 @@ fileprivate struct CutOffShadow: Shape {
|
|||
path.addLine(to: bls)
|
||||
path.addRelativeArc(center: blc, radius: radius,
|
||||
startAngle: Angle.degrees(90), delta: Angle.degrees(90))
|
||||
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
struct LandscapeItemElement: View {
|
||||
@Environment(\.isFocused) var envFocused: Bool
|
||||
@State var focused: Bool = false;
|
||||
@State var backgroundURL: URL?;
|
||||
|
||||
var item: BaseItemDto;
|
||||
|
||||
@State var focused: Bool = false
|
||||
@State var backgroundURL: URL?
|
||||
|
||||
var item: BaseItemDto
|
||||
|
||||
var body: some View {
|
||||
VStack() {
|
||||
VStack {
|
||||
ImageView(src: (item.type == "Episode" ? item.getSeriesBackdropImage(maxWidth: 445) : item.getBackdropImage(maxWidth: 445)), bh: item.type == "Episode" ? item.getSeriesBackdropImageBlurHash() : item.getBackdropImageBlurHash())
|
||||
.frame(width: 445, height: 250)
|
||||
.cornerRadius(10)
|
||||
.overlay(
|
||||
Group {
|
||||
if(focused && item.userData?.playedPercentage != nil) {
|
||||
if focused && item.userData?.playedPercentage != nil {
|
||||
ZStack(alignment: .leading) {
|
||||
Rectangle()
|
||||
.fill(LinearGradient(colors: [.black,.clear], startPoint: .bottom, endPoint: .top))
|
||||
.fill(LinearGradient(colors: [.black, .clear], startPoint: .bottom, endPoint: .top))
|
||||
.frame(width: 445, height: 90)
|
||||
.mask(CutOffShadow())
|
||||
VStack(alignment: .leading) {
|
||||
|
@ -79,7 +79,7 @@ struct LandscapeItemElement: View {
|
|||
)
|
||||
.shadow(radius: focused ? 10.0 : 0, y: focused ? 10.0 : 0)
|
||||
.shadow(radius: focused ? 10.0 : 0, y: focused ? 10.0 : 0)
|
||||
if(focused) {
|
||||
if focused {
|
||||
Text(item.type == "Episode" ? "\(item.seriesName ?? "") • S\(String(item.parentIndexNumber ?? 0)):E\(String(item.indexNumber ?? 0))" : item.name ?? "")
|
||||
.font(.callout)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -93,11 +93,11 @@ struct LandscapeItemElement: View {
|
|||
withAnimation(.linear(duration: 0.15)) {
|
||||
self.focused = envFocus
|
||||
}
|
||||
|
||||
if(envFocus == true) {
|
||||
|
||||
if envFocus == true {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
// your code here
|
||||
if(self.focused == true) {
|
||||
if self.focused == true {
|
||||
backgroundURL = item.getBackdropImage(maxWidth: 1080)
|
||||
BackgroundManager.current.setBackground(to: backgroundURL!, hash: item.getBackdropImageBlurHash())
|
||||
}
|
||||
|
|
|
@ -10,19 +10,19 @@
|
|||
import SwiftUI
|
||||
import JellyfinAPI
|
||||
|
||||
fileprivate struct CutOffShadow: Shape {
|
||||
let radius = 6.0;
|
||||
|
||||
private struct CutOffShadow: Shape {
|
||||
let radius = 6.0
|
||||
|
||||
func path(in rect: CGRect) -> Path {
|
||||
var path = Path()
|
||||
|
||||
|
||||
let tl = CGPoint(x: rect.minX, y: rect.minY)
|
||||
let tr = CGPoint(x: rect.maxX, y: rect.minY)
|
||||
let brs = CGPoint(x: rect.maxX, y: rect.maxY - radius)
|
||||
let brc = CGPoint(x: rect.maxX - radius, y: rect.maxY - radius)
|
||||
let bls = CGPoint(x: rect.minX + radius, y: rect.maxY)
|
||||
let blc = CGPoint(x: rect.minX + radius, y: rect.maxY - radius)
|
||||
|
||||
|
||||
path.move(to: tl)
|
||||
path.addLine(to: tr)
|
||||
path.addLine(to: brs)
|
||||
|
@ -31,20 +31,20 @@ fileprivate struct CutOffShadow: Shape {
|
|||
path.addLine(to: bls)
|
||||
path.addRelativeArc(center: blc, radius: radius,
|
||||
startAngle: Angle.degrees(90), delta: Angle.degrees(90))
|
||||
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
struct PortraitItemElement: View {
|
||||
@Environment(\.isFocused) var envFocused: Bool
|
||||
@State var focused: Bool = false;
|
||||
@State var backgroundURL: URL?;
|
||||
|
||||
var item: BaseItemDto;
|
||||
|
||||
@State var focused: Bool = false
|
||||
@State var backgroundURL: URL?
|
||||
|
||||
var item: BaseItemDto
|
||||
|
||||
var body: some View {
|
||||
VStack() {
|
||||
VStack {
|
||||
ImageView(src: item.type == "Episode" ? item.getSeriesPrimaryImage(maxWidth: 200) : item.getPrimaryImage(maxWidth: 200), bh: item.type == "Episode" ? item.getSeriesPrimaryImageBlurHash() : item.getPrimaryImageBlurHash())
|
||||
.frame(width: 200, height: 300)
|
||||
.cornerRadius(10)
|
||||
|
@ -55,11 +55,11 @@ struct PortraitItemElement: View {
|
|||
withAnimation(.linear(duration: 0.15)) {
|
||||
self.focused = envFocus
|
||||
}
|
||||
|
||||
if(envFocus == true) {
|
||||
|
||||
if envFocus == true {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
// your code here
|
||||
if(self.focused == true) {
|
||||
if self.focused == true {
|
||||
backgroundURL = item.getBackdropImage(maxWidth: 1080)
|
||||
BackgroundManager.current.setBackground(to: backgroundURL!, hash: item.getBackdropImageBlurHash())
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@ import CoreMedia
|
|||
|
||||
struct PublicUserButton: View {
|
||||
@Environment(\.isFocused) var envFocused: Bool
|
||||
@State var focused: Bool = false;
|
||||
@State var focused: Bool = false
|
||||
var publicUser: UserDto
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if publicUser.primaryImageTag != nil {
|
||||
|
@ -31,7 +31,7 @@ struct PublicUserButton: View {
|
|||
.cornerRadius(125.0)
|
||||
.shadow(radius: 6)
|
||||
}
|
||||
if(focused) {
|
||||
if focused {
|
||||
Text(publicUser.name ?? "").font(.headline).fontWeight(.semibold)
|
||||
} else {
|
||||
Spacer().frame(height: 60)
|
||||
|
|
|
@ -16,12 +16,12 @@ struct ConnectToServerView: View {
|
|||
if viewModel.isConnectedServer {
|
||||
if viewModel.publicUsers.isEmpty {
|
||||
Section(header: Text(viewModel.lastPublicUsers.isEmpty || viewModel.username == "" ? "Login to \(ServerEnvironment.current.server.name ?? "")": "")) {
|
||||
if(viewModel.lastPublicUsers.isEmpty || viewModel.username == "") {
|
||||
if viewModel.lastPublicUsers.isEmpty || viewModel.username == "" {
|
||||
TextField("Username", text: $viewModel.username)
|
||||
.disableAutocorrection(true)
|
||||
.autocapitalization(.none)
|
||||
} else {
|
||||
HStack() {
|
||||
HStack {
|
||||
Spacer()
|
||||
ImageView(src: URL(string: "\(ServerEnvironment.current.server.baseURI ?? "")/Users/\(viewModel.selectedPublicUser.id ?? "")/Images/Primary?width=500&quality=80&tag=\(viewModel.selectedPublicUser.primaryImageTag ?? "")")!)
|
||||
.frame(width: 250, height: 250)
|
||||
|
@ -29,16 +29,16 @@ struct ConnectToServerView: View {
|
|||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SecureField("Password (optional)", text: $viewModel.password)
|
||||
.disableAutocorrection(true)
|
||||
.autocapitalization(.none)
|
||||
}
|
||||
|
||||
|
||||
Section {
|
||||
HStack() {
|
||||
HStack {
|
||||
Button {
|
||||
if(!viewModel.lastPublicUsers.isEmpty) {
|
||||
if !viewModel.lastPublicUsers.isEmpty {
|
||||
viewModel.username = ""
|
||||
viewModel.showPublicUsers()
|
||||
} else {
|
||||
|
@ -51,7 +51,7 @@ struct ConnectToServerView: View {
|
|||
}
|
||||
Spacer()
|
||||
}
|
||||
|
||||
|
||||
Button {
|
||||
viewModel.login()
|
||||
} label: {
|
||||
|
@ -66,11 +66,11 @@ struct ConnectToServerView: View {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
VStack() {
|
||||
HStack() {
|
||||
VStack {
|
||||
HStack {
|
||||
ForEach(viewModel.publicUsers, id: \.id) { publicUser in
|
||||
Button(action: {
|
||||
if(SessionManager.current.doesUserHaveSavedSession(userID: publicUser.id!)) {
|
||||
if SessionManager.current.doesUserHaveSavedSession(userID: publicUser.id!) {
|
||||
let user = SessionManager.current.getSavedSession(userID: publicUser.id!)
|
||||
SessionManager.current.loginWithSavedSession(user: user)
|
||||
} else {
|
||||
|
@ -87,7 +87,7 @@ struct ConnectToServerView: View {
|
|||
}.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||
}
|
||||
}.padding(.bottom, 20)
|
||||
HStack() {
|
||||
HStack {
|
||||
Spacer()
|
||||
Button {
|
||||
viewModel.hidePublicUsers()
|
||||
|
|
|
@ -12,7 +12,7 @@ import SwiftUI
|
|||
|
||||
struct HomeView: View {
|
||||
@StateObject var viewModel = HomeViewModel()
|
||||
|
||||
|
||||
@State var showingSettings = false
|
||||
|
||||
var body: some View {
|
||||
|
@ -32,9 +32,9 @@ struct HomeView: View {
|
|||
ForEach(viewModel.librariesShowRecentlyAddedIDs, id: \.self) { libraryID in
|
||||
VStack(alignment: .leading) {
|
||||
let library = viewModel.libraries.first(where: { $0.id == libraryID })
|
||||
|
||||
|
||||
NavigationLink(destination: Text("library_latest")) {
|
||||
HStack() {
|
||||
HStack {
|
||||
Text("Latest \(library?.name ?? "")")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
|
|
|
@ -11,7 +11,7 @@ import UIKit
|
|||
@main
|
||||
struct JellyfinPlayer_tvOSApp: App {
|
||||
let persistenceController = PersistenceController.shared
|
||||
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
SplashView()
|
||||
|
|
|
@ -15,16 +15,16 @@ struct MainTabView: View {
|
|||
@StateObject private var viewModel = MainTabViewModel()
|
||||
@State private var backdropAnim: Bool = true
|
||||
@State private var lastBackdropAnim: Bool = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack() {
|
||||
//please do not touch my magical crossfading. i will wave my magical github wand and cry
|
||||
if(viewModel.lastBackgroundURL != nil) {
|
||||
ZStack {
|
||||
// please do not touch my magical crossfading. i will wave my magical github wand and cry
|
||||
if viewModel.lastBackgroundURL != nil {
|
||||
ImageView(src: viewModel.lastBackgroundURL!, bh: viewModel.backgroundBlurHash)
|
||||
.frame(minWidth: 100, maxWidth: .infinity, minHeight: 100, maxHeight: .infinity)
|
||||
.opacity(lastBackdropAnim ? 0.4 : 0)
|
||||
}
|
||||
if(viewModel.backgroundURL != nil) {
|
||||
if viewModel.backgroundURL != nil {
|
||||
ImageView(src: viewModel.backgroundURL!, bh: viewModel.backgroundBlurHash)
|
||||
.frame(minWidth: 100, maxWidth: .infinity, minHeight: 100, maxHeight: .infinity)
|
||||
.opacity(backdropAnim ? 0.4 : 0)
|
||||
|
@ -37,7 +37,7 @@ struct MainTabView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TabView(selection: $tabSelection) {
|
||||
HomeView()
|
||||
.offset(y: -20)
|
||||
|
@ -46,7 +46,7 @@ struct MainTabView: View {
|
|||
Image(systemName: "house")
|
||||
}
|
||||
.tag(Tab.home)
|
||||
|
||||
|
||||
Text("Library")
|
||||
.tabItem {
|
||||
Text(Tab.allMedia.localized)
|
||||
|
@ -62,7 +62,7 @@ extension MainTabView {
|
|||
enum Tab: String {
|
||||
case home
|
||||
case allMedia
|
||||
|
||||
|
||||
var localized: String {
|
||||
switch self {
|
||||
case .home:
|
||||
|
|
|
@ -11,11 +11,11 @@ import SwiftUI
|
|||
|
||||
struct SplashView: View {
|
||||
@StateObject var viewModel = SplashViewModel()
|
||||
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if viewModel.isLoggedIn {
|
||||
NavigationView() {
|
||||
NavigationView {
|
||||
MainTabView()
|
||||
}.padding(.all, -1)
|
||||
} else {
|
||||
|
|
|
@ -12,7 +12,7 @@ import SwiftUI
|
|||
|
||||
struct MainTabView: View {
|
||||
@State private var tabSelection: Tab = .home
|
||||
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: $tabSelection) {
|
||||
NavigationView {
|
||||
|
@ -38,11 +38,11 @@ struct MainTabView: View {
|
|||
}
|
||||
|
||||
extension MainTabView {
|
||||
|
||||
|
||||
enum Tab: String {
|
||||
case home
|
||||
case allMedia
|
||||
|
||||
|
||||
var localized: String {
|
||||
switch self {
|
||||
case .home:
|
||||
|
|
|
@ -18,7 +18,6 @@ struct SeasonItemView: View {
|
|||
|
||||
var item: BaseItemDto = BaseItemDto()
|
||||
@State private var episodes: [BaseItemDto] = []
|
||||
|
||||
|
||||
@State private var isLoading: Bool = true
|
||||
@State private var viewDidLoad: Bool = false
|
||||
|
@ -249,7 +248,7 @@ struct SeasonItemView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
if isLoading {
|
||||
ProgressView()
|
||||
|
|
|
@ -26,7 +26,6 @@ struct SeriesItemView: View {
|
|||
}
|
||||
|
||||
isLoading = true
|
||||
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
TvShowsAPI.getSeasons(seriesId: item.id ?? "", fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
||||
|
|
|
@ -10,16 +10,16 @@ import SwiftUI
|
|||
|
||||
struct SettingsView: View {
|
||||
@Environment(\.managedObjectContext) private var viewContext
|
||||
|
||||
|
||||
@ObservedObject var viewModel: SettingsViewModel
|
||||
|
||||
|
||||
@Binding var close: Bool
|
||||
@State private var inNetworkStreamBitrate: Int = 40_000_000
|
||||
@State private var outOfNetworkStreamBitrate: Int = 40_000_000
|
||||
@State private var autoSelectSubtitles: Bool = false
|
||||
@State private var autoSelectSubtitlesLangcode: String = "none"
|
||||
@State private var username: String = ""
|
||||
|
||||
|
||||
func onAppear() {
|
||||
let defaults = UserDefaults.standard
|
||||
username = SessionManager.current.user.username!
|
||||
|
@ -28,7 +28,7 @@ struct SettingsView: View {
|
|||
autoSelectSubtitles = defaults.bool(forKey: "AutoSelectSubtitles")
|
||||
autoSelectSubtitlesLangcode = defaults.string(forKey: "AutoSelectSubtitlesLangcode") ?? ""
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
Form {
|
||||
|
@ -41,7 +41,7 @@ struct SettingsView: View {
|
|||
let defaults = UserDefaults.standard
|
||||
defaults.setValue(_inNetworkStreamBitrate.wrappedValue, forKey: "InNetworkBandwidth")
|
||||
}
|
||||
|
||||
|
||||
Picker("Default remote quality", selection: $outOfNetworkStreamBitrate) {
|
||||
ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
||||
Text(bitrate.name).tag(bitrate.value)
|
||||
|
@ -51,7 +51,7 @@ struct SettingsView: View {
|
|||
defaults.setValue(_outOfNetworkStreamBitrate.wrappedValue, forKey: "OutOfNetworkBandwidth")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("Accessibility")) {
|
||||
Toggle("Automatically show subtitles", isOn: $autoSelectSubtitles).onChange(of: autoSelectSubtitles, perform: { _ in
|
||||
let defaults = UserDefaults.standard
|
||||
|
@ -59,7 +59,7 @@ struct SettingsView: View {
|
|||
})
|
||||
Picker("Language preferences", selection: $autoSelectSubtitlesLangcode) {}
|
||||
}
|
||||
|
||||
|
||||
Section {
|
||||
HStack {
|
||||
Text("Signed in as \(username)").foregroundColor(.primary)
|
||||
|
@ -67,22 +67,22 @@ struct SettingsView: View {
|
|||
Button {
|
||||
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Server")
|
||||
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
|
||||
|
||||
|
||||
do {
|
||||
try viewContext.execute(deleteRequest)
|
||||
} catch _ as NSError {
|
||||
// TODO: handle the error
|
||||
}
|
||||
|
||||
|
||||
let fetchRequest2: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "SignedInUser")
|
||||
let deleteRequest2 = NSBatchDeleteRequest(fetchRequest: fetchRequest2)
|
||||
|
||||
|
||||
do {
|
||||
try viewContext.execute(deleteRequest2)
|
||||
} catch _ as NSError {
|
||||
// TODO: handle the error
|
||||
}
|
||||
|
||||
|
||||
SessionManager.current.logout()
|
||||
ServerEnvironment.current.reset()
|
||||
} label: {
|
||||
|
|
|
@ -300,7 +300,7 @@ class PlayerViewController: UIViewController, VLCMediaDelegate, VLCMediaPlayerDe
|
|||
}, receiveValue: { [self] response in
|
||||
playSessionId = response.playSessionId ?? ""
|
||||
|
||||
if(response.mediaSources == nil) {
|
||||
if response.mediaSources == nil {
|
||||
delegate?.exitPlayer(self)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ extension BaseItemDto {
|
|||
func getBackdropImageBlurHash() -> String {
|
||||
let rawImgURL = self.getBackdropImage(maxWidth: 1).absoluteString
|
||||
let imgTag = rawImgURL.components(separatedBy: "&tag=")[1]
|
||||
|
||||
|
||||
if rawImgURL.contains("Backdrop") {
|
||||
return self.imageBlurHashes?.backdrop?[imgTag] ?? "001fC^"
|
||||
} else {
|
||||
|
|
|
@ -21,17 +21,16 @@ final class BackgroundManager {
|
|||
func setBackground(to: URL, hash: String) {
|
||||
self.backgroundURL = to
|
||||
self.blurhash = hash
|
||||
|
||||
|
||||
let nc = NotificationCenter.default
|
||||
nc.post(name: Notification.Name("backgroundDidChange"), object: nil)
|
||||
}
|
||||
|
||||
|
||||
func clearBackground() {
|
||||
self.backgroundURL = nil
|
||||
self.blurhash = "001fC^"
|
||||
|
||||
|
||||
let nc = NotificationCenter.default
|
||||
nc.post(name: Notification.Name("backgroundDidChange"), object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ final class ServerEnvironment {
|
|||
init() {
|
||||
let serverRequest = Server.fetchRequest()
|
||||
let servers = try? PersistenceController.shared.container.viewContext.fetch(serverRequest)
|
||||
|
||||
if(servers?.count != 0) {
|
||||
|
||||
if servers?.count != 0 {
|
||||
server = servers?.first
|
||||
JellyfinAPI.basePath = server.baseURI!
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ final class ServerEnvironment {
|
|||
if uri.last == "/" {
|
||||
uri = String(uri.dropLast())
|
||||
}
|
||||
|
||||
|
||||
JellyfinAPI.basePath = uri
|
||||
return SystemAPI.getPublicSystemInfo()
|
||||
.map { response in
|
||||
|
@ -56,8 +56,8 @@ final class ServerEnvironment {
|
|||
|
||||
let serverRequest: NSFetchRequest<NSFetchRequestResult> = Server.fetchRequest()
|
||||
let deleteRequest = NSBatchDeleteRequest(fetchRequest: serverRequest)
|
||||
|
||||
//coredata will theoretically never throw
|
||||
|
||||
// coredata will theoretically never throw
|
||||
_ = try? PersistenceController.shared.container.viewContext.execute(deleteRequest)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,23 +27,23 @@ final class SessionManager {
|
|||
#if os(tvOS)
|
||||
let tvUserManager = TVUserManager()
|
||||
#endif
|
||||
|
||||
|
||||
init() {
|
||||
let savedUserRequest = SignedInUser.fetchRequest()
|
||||
|
||||
|
||||
let savedUsers = try? PersistenceController.shared.container.viewContext.fetch(savedUserRequest)
|
||||
|
||||
#if os(tvOS)
|
||||
savedUsers?.forEach() { savedUser in
|
||||
if(savedUser.appletv_id == tvUserManager.currentUserIdentifier ?? "") {
|
||||
savedUsers?.forEach { savedUser in
|
||||
if savedUser.appletv_id == tvUserManager.currentUserIdentifier ?? "" {
|
||||
self.user = savedUser
|
||||
}
|
||||
}
|
||||
#else
|
||||
user = savedUsers?.first
|
||||
#endif
|
||||
|
||||
if(user != nil) {
|
||||
|
||||
if user != nil {
|
||||
let authToken = getAuthToken(userID: user.user_id!)
|
||||
generateAuthHeader(with: authToken)
|
||||
}
|
||||
|
@ -70,43 +70,43 @@ final class SessionManager {
|
|||
deviceID = "iOS_\(UIDevice.current.identifierForVendor!.uuidString)_\(user?.user_id ?? "")"
|
||||
#endif
|
||||
header.append("Version=\"\(appVersion ?? "0.0.1")\", ")
|
||||
|
||||
if(authToken != nil) {
|
||||
|
||||
if authToken != nil {
|
||||
header.append("Token=\"\(authToken!)\"")
|
||||
accessToken = authToken!
|
||||
}
|
||||
|
||||
JellyfinAPI.customHeaders["X-Emby-Authorization"] = header
|
||||
}
|
||||
|
||||
|
||||
fileprivate func getAuthToken(userID: String) -> String? {
|
||||
let keychain = KeychainSwift()
|
||||
keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain"
|
||||
return keychain.get("AccessToken_\(userID)")
|
||||
}
|
||||
|
||||
|
||||
func doesUserHaveSavedSession(userID: String) -> Bool {
|
||||
let savedUserRequest = SignedInUser.fetchRequest()
|
||||
savedUserRequest.predicate = NSPredicate(format: "user_id == %@", userID)
|
||||
let savedUsers = try? PersistenceController.shared.container.viewContext.fetch(savedUserRequest)
|
||||
|
||||
if(savedUsers!.isEmpty) {
|
||||
|
||||
if savedUsers!.isEmpty {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
func getSavedSession(userID: String) -> SignedInUser {
|
||||
let savedUserRequest = SignedInUser.fetchRequest()
|
||||
savedUserRequest.predicate = NSPredicate(format: "user_id == %@", userID)
|
||||
let savedUsers = try? PersistenceController.shared.container.viewContext.fetch(savedUserRequest)
|
||||
return savedUsers!.first!
|
||||
}
|
||||
|
||||
|
||||
func loginWithSavedSession(user: SignedInUser) {
|
||||
let accessToken = getAuthToken(userID: user.user_id!)
|
||||
|
||||
|
||||
self.user = user
|
||||
generateAuthHeader(with: accessToken)
|
||||
print(JellyfinAPI.customHeaders)
|
||||
|
@ -116,29 +116,29 @@ final class SessionManager {
|
|||
|
||||
func login(username: String, password: String) -> AnyPublisher<SignedInUser, Error> {
|
||||
generateAuthHeader(with: nil)
|
||||
|
||||
|
||||
return UserAPI.authenticateUserByName(authenticateUserByName: AuthenticateUserByName(username: username, pw: password))
|
||||
.map { response -> (SignedInUser, String?) in
|
||||
let user = SignedInUser(context: PersistenceController.shared.container.viewContext)
|
||||
user.username = response.user?.name
|
||||
user.user_id = response.user?.id
|
||||
|
||||
|
||||
#if os(tvOS)
|
||||
//user.appletv_id = tvUserManager.currentUserIdentifier ?? ""
|
||||
// user.appletv_id = tvUserManager.currentUserIdentifier ?? ""
|
||||
#endif
|
||||
|
||||
|
||||
return (user, response.accessToken)
|
||||
}
|
||||
.handleEvents(receiveOutput: { [unowned self] response, accessToken in
|
||||
user = response
|
||||
_ = try? PersistenceController.shared.container.viewContext.save()
|
||||
|
||||
|
||||
let keychain = KeychainSwift()
|
||||
keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain"
|
||||
keychain.set(accessToken!, forKey: "AccessToken_\(user.user_id!)")
|
||||
|
||||
|
||||
generateAuthHeader(with: accessToken)
|
||||
|
||||
|
||||
let nc = NotificationCenter.default
|
||||
nc.post(name: Notification.Name("didSignIn"), object: nil)
|
||||
})
|
||||
|
@ -155,7 +155,7 @@ final class SessionManager {
|
|||
let deleteRequest = NSBatchDeleteRequest(objectIDs: [user.objectID])
|
||||
user = nil
|
||||
_ = try? PersistenceController.shared.container.viewContext.execute(deleteRequest)
|
||||
|
||||
|
||||
let nc = NotificationCenter.default
|
||||
nc.post(name: Notification.Name("didSignOut"), object: nil)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ final class ConnectToServerViewModel: ViewModel {
|
|||
var username = ""
|
||||
@Published
|
||||
var password = ""
|
||||
|
||||
|
||||
@Published
|
||||
var lastPublicUsers = [UserDto]()
|
||||
@Published
|
||||
|
@ -45,17 +45,17 @@ final class ConnectToServerViewModel: ViewModel {
|
|||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func hidePublicUsers() {
|
||||
self.lastPublicUsers = publicUsers;
|
||||
publicUsers = [];
|
||||
self.lastPublicUsers = publicUsers
|
||||
publicUsers = []
|
||||
}
|
||||
|
||||
|
||||
func showPublicUsers() {
|
||||
self.publicUsers = lastPublicUsers;
|
||||
lastPublicUsers = [];
|
||||
self.publicUsers = lastPublicUsers
|
||||
lastPublicUsers = []
|
||||
}
|
||||
|
||||
|
||||
func connectToServer() {
|
||||
ServerEnvironment.current.create(with: uri)
|
||||
.sink(receiveCompletion: { result in
|
||||
|
@ -65,7 +65,7 @@ final class ConnectToServerViewModel: ViewModel {
|
|||
default:
|
||||
break
|
||||
}
|
||||
}, receiveValue: { response in
|
||||
}, receiveValue: { _ in
|
||||
self.getPublicUsers()
|
||||
})
|
||||
.store(in: &cancellables)
|
||||
|
@ -76,7 +76,7 @@ final class ConnectToServerViewModel: ViewModel {
|
|||
.sink(receiveCompletion: { completion in
|
||||
self.HandleAPIRequestCompletion(completion: completion)
|
||||
}, receiveValue: { _ in
|
||||
|
||||
|
||||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ final class HomeViewModel: ViewModel {
|
|||
var resumeItems = [BaseItemDto]()
|
||||
@Published
|
||||
var nextUpItems = [BaseItemDto]()
|
||||
|
||||
|
||||
// temp
|
||||
var recentFilterSet: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.descending], sortBy: ["DateCreated"])
|
||||
|
||||
|
@ -39,18 +39,18 @@ final class HomeViewModel: ViewModel {
|
|||
self.HandleAPIRequestCompletion(completion: completion)
|
||||
}, receiveValue: { response in
|
||||
response.items!.forEach { item in
|
||||
if(item.collectionType == "movies" || item.collectionType == "tvshows") {
|
||||
if item.collectionType == "movies" || item.collectionType == "tvshows" {
|
||||
self.libraries.append(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UserAPI.getCurrentUser()
|
||||
.trackActivity(self.loading)
|
||||
.sink(receiveCompletion: { completion in
|
||||
self.HandleAPIRequestCompletion(completion: completion)
|
||||
}, receiveValue: { response in
|
||||
self.libraries.forEach { library in
|
||||
if(!(response.configuration?.latestItemsExcludes?.contains(library.id!))!) {
|
||||
if !(response.configuration?.latestItemsExcludes?.contains(library.id!))! {
|
||||
self.librariesShowRecentlyAddedIDs.append(library.id!)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ final class MainTabViewModel: ViewModel {
|
|||
let nc = NotificationCenter.default
|
||||
nc.addObserver(self, selector: #selector(backgroundDidChange), name: Notification.Name("backgroundDidChange"), object: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func backgroundDidChange() {
|
||||
self.lastBackgroundURL = self.backgroundURL
|
||||
self.backgroundURL = BackgroundManager.current.backgroundURL
|
||||
|
|
|
@ -16,20 +16,20 @@ import WidgetKit
|
|||
#endif
|
||||
|
||||
final class SplashViewModel: ViewModel {
|
||||
|
||||
|
||||
@Published var isLoggedIn: Bool = false
|
||||
|
||||
|
||||
override init() {
|
||||
isLoggedIn = ServerEnvironment.current.server != nil && SessionManager.current.user != nil
|
||||
super.init()
|
||||
|
||||
|
||||
ImageCache.shared.costLimit = 125 * 1024 * 1024 // 125MB memory
|
||||
DataLoader.sharedUrlCache.diskCapacity = 1000 * 1024 * 1024 // 1000MB disk
|
||||
|
||||
|
||||
#if !os(tvOS)
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
#endif
|
||||
|
||||
|
||||
let defaults = UserDefaults.standard
|
||||
if defaults.integer(forKey: "InNetworkBandwidth") == 0 {
|
||||
defaults.setValue(40_000_000, forKey: "InNetworkBandwidth")
|
||||
|
@ -37,17 +37,17 @@ final class SplashViewModel: ViewModel {
|
|||
if defaults.integer(forKey: "OutOfNetworkBandwidth") == 0 {
|
||||
defaults.setValue(40_000_000, forKey: "OutOfNetworkBandwidth")
|
||||
}
|
||||
|
||||
|
||||
let nc = NotificationCenter.default
|
||||
nc.addObserver(self, selector: #selector(didLogIn), name: Notification.Name("didSignIn"), object: nil)
|
||||
nc.addObserver(self, selector: #selector(didLogOut), name: Notification.Name("didSignOut"), object: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func didLogIn() {
|
||||
print("didLogIn")
|
||||
isLoggedIn = true
|
||||
}
|
||||
|
||||
|
||||
@objc func didLogOut() {
|
||||
print("didLogOut")
|
||||
isLoggedIn = false
|
||||
|
|
|
@ -27,11 +27,11 @@ class ViewModel: ObservableObject {
|
|||
let loading = ActivityIndicator()
|
||||
@Published
|
||||
var errorMessage: ErrorMessage?
|
||||
|
||||
|
||||
init() {
|
||||
loading.loading.assign(to: \.isLoading, on: self).store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
||||
func HandleAPIRequestCompletion(completion: Subscribers.Completion<Error>) {
|
||||
switch completion {
|
||||
case .finished:
|
||||
|
|
|
@ -28,7 +28,7 @@ struct NextUpWidgetProvider: TimelineProvider {
|
|||
let server = ServerEnvironment.current.server!
|
||||
let savedUser = SessionManager.current.user!
|
||||
var tempCancellables = Set<AnyCancellable>()
|
||||
|
||||
|
||||
JellyfinAPI.basePath = server.baseURI ?? ""
|
||||
TvShowsAPI.getNextUp(userId: savedUser.user_id, limit: 3,
|
||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||
|
@ -69,7 +69,7 @@ struct NextUpWidgetProvider: TimelineProvider {
|
|||
let entryDate = Calendar.current.date(byAdding: .hour, value: 1, to: currentDate)!
|
||||
let server = ServerEnvironment.current.server!
|
||||
let savedUser = SessionManager.current.user!
|
||||
|
||||
|
||||
var tempCancellables = Set<AnyCancellable>()
|
||||
JellyfinAPI.basePath = server.baseURI ?? ""
|
||||
TvShowsAPI.getNextUp(userId: savedUser.user_id, limit: 3,
|
||||
|
|
Loading…
Reference in New Issue