iOS/iPadOS Quick Connect (#522)
This commit is contained in:
parent
599cff4c95
commit
6a23570d93
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Stinsen
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
final class QuickConnectCoordinator: NavigationCoordinatable {
|
||||||
|
|
||||||
|
let stack = NavigationStack(initial: \QuickConnectCoordinator.start)
|
||||||
|
|
||||||
|
@Root
|
||||||
|
var start = makeStart
|
||||||
|
|
||||||
|
private let viewModel: UserSignInViewModel
|
||||||
|
|
||||||
|
init(viewModel: UserSignInViewModel) {
|
||||||
|
self.viewModel = viewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func makeStart() -> some View {
|
||||||
|
QuickConnectView(viewModel: viewModel)
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,10 @@ final class UserSignInCoordinator: NavigationCoordinatable {
|
||||||
|
|
||||||
@Root
|
@Root
|
||||||
var start = makeStart
|
var start = makeStart
|
||||||
|
#if !os(tvOS)
|
||||||
|
@Route(.modal)
|
||||||
|
var quickConnect = makeQuickConnect
|
||||||
|
#endif
|
||||||
|
|
||||||
let viewModel: UserSignInViewModel
|
let viewModel: UserSignInViewModel
|
||||||
|
|
||||||
|
@ -23,6 +27,12 @@ final class UserSignInCoordinator: NavigationCoordinatable {
|
||||||
self.viewModel = viewModel
|
self.viewModel = viewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
|
func makeQuickConnect() -> NavigationViewCoordinator<QuickConnectCoordinator> {
|
||||||
|
NavigationViewCoordinator(QuickConnectCoordinator(viewModel: viewModel))
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func makeStart() -> some View {
|
func makeStart() -> some View {
|
||||||
UserSignInView(viewModel: viewModel)
|
UserSignInView(viewModel: viewModel)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import JellyfinAPI
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension UserDto {
|
||||||
|
func profileImageSource(maxWidth: CGFloat, maxHeight: CGFloat) -> ImageSource {
|
||||||
|
let scaleWidth = UIScreen.main.scale(maxWidth)
|
||||||
|
let scaleHeight = UIScreen.main.scale(maxHeight)
|
||||||
|
let profileImageURL = ImageAPI.getUserImageWithRequestBuilder(
|
||||||
|
userId: id ?? "",
|
||||||
|
imageType: .primary,
|
||||||
|
maxWidth: scaleWidth,
|
||||||
|
maxHeight: scaleHeight
|
||||||
|
).url
|
||||||
|
|
||||||
|
return ImageSource(url: profileImageURL, blurHash: nil)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class RepeatingTimer {
|
||||||
|
|
||||||
|
let action: () -> Void
|
||||||
|
private let interval: TimeInterval
|
||||||
|
private var timer: Timer?
|
||||||
|
|
||||||
|
init(interval: TimeInterval, _ action: @escaping () -> Void) {
|
||||||
|
self.action = action
|
||||||
|
self.interval = interval
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
private func runAction() {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
self.timer = Timer.scheduledTimer(
|
||||||
|
timeInterval: interval,
|
||||||
|
target: self,
|
||||||
|
selector: #selector(runAction),
|
||||||
|
userInfo: nil,
|
||||||
|
repeats: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
self.timer?.invalidate()
|
||||||
|
self.timer = nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import Stinsen
|
||||||
final class UserSignInViewModel: ViewModel {
|
final class UserSignInViewModel: ViewModel {
|
||||||
|
|
||||||
@RouterObject
|
@RouterObject
|
||||||
private var Router: UserSignInCoordinator.Router?
|
private var router: UserSignInCoordinator.Router?
|
||||||
|
|
||||||
@Published
|
@Published
|
||||||
var publicUsers: [UserDto] = []
|
var publicUsers: [UserDto] = []
|
||||||
|
@ -24,7 +24,7 @@ final class UserSignInViewModel: ViewModel {
|
||||||
var quickConnectEnabled = false
|
var quickConnectEnabled = false
|
||||||
|
|
||||||
let server: SwiftfinStore.State.Server
|
let server: SwiftfinStore.State.Server
|
||||||
private var quickConnectTimer: Timer?
|
private var quickConnectTimer: RepeatingTimer?
|
||||||
private var quickConnectSecret: String?
|
private var quickConnectSecret: String?
|
||||||
|
|
||||||
init(server: SwiftfinStore.State.Server) {
|
init(server: SwiftfinStore.State.Server) {
|
||||||
|
@ -33,6 +33,7 @@ final class UserSignInViewModel: ViewModel {
|
||||||
|
|
||||||
JellyfinAPIAPI.basePath = server.currentURI
|
JellyfinAPIAPI.basePath = server.currentURI
|
||||||
checkQuickConnect()
|
checkQuickConnect()
|
||||||
|
getPublicUsers()
|
||||||
}
|
}
|
||||||
|
|
||||||
var alertTitle: String {
|
var alertTitle: String {
|
||||||
|
@ -64,7 +65,7 @@ final class UserSignInViewModel: ViewModel {
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadUsers() {
|
func getPublicUsers() {
|
||||||
UserAPI.getPublicUsers()
|
UserAPI.getPublicUsers()
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
|
@ -75,35 +76,17 @@ final class UserSignInViewModel: ViewModel {
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProfileImageUrl(user: UserDto) -> URL? {
|
|
||||||
let urlString = ImageAPI.getUserImageWithRequestBuilder(
|
|
||||||
userId: user.id ?? "--",
|
|
||||||
imageType: .primary,
|
|
||||||
width: 200,
|
|
||||||
quality: 90
|
|
||||||
).URLString
|
|
||||||
return URL(string: urlString)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSplashscreenUrl() -> URL? {
|
|
||||||
let urlString = ImageAPI.getSplashscreenWithRequestBuilder().URLString
|
|
||||||
return URL(string: urlString)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkQuickConnect() {
|
func checkQuickConnect() {
|
||||||
QuickConnectAPI.getEnabled()
|
QuickConnectAPI.getEnabled()
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.handleAPIRequestError(completion: completion)
|
self.handleAPIRequestError(completion: completion)
|
||||||
}, receiveValue: { enabled in
|
}, receiveValue: { enabled in
|
||||||
self.quickConnectEnabled = enabled
|
self.quickConnectEnabled = enabled
|
||||||
if enabled {
|
|
||||||
self.startQuickConnect()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startQuickConnect() {
|
func startQuickConnect(_ onSuccess: @escaping () -> Void) {
|
||||||
QuickConnectAPI.initiate()
|
QuickConnectAPI.initiate()
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.handleAPIRequestError(completion: completion)
|
self.handleAPIRequestError(completion: completion)
|
||||||
|
@ -113,19 +96,17 @@ final class UserSignInViewModel: ViewModel {
|
||||||
self.quickConnectCode = response.code
|
self.quickConnectCode = response.code
|
||||||
LogManager.log.debug("QuickConnect code: \(response.code ?? "--")")
|
LogManager.log.debug("QuickConnect code: \(response.code ?? "--")")
|
||||||
|
|
||||||
self.quickConnectTimer = Timer.scheduledTimer(
|
self.quickConnectTimer = RepeatingTimer(interval: 5) {
|
||||||
timeInterval: 5,
|
self.checkAuthStatus(onSuccess)
|
||||||
target: self,
|
}
|
||||||
selector: #selector(self.checkAuthStatus),
|
|
||||||
userInfo: nil,
|
self.quickConnectTimer?.start()
|
||||||
repeats: true
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
private func checkAuthStatus() {
|
private func checkAuthStatus(_ onSuccess: @escaping () -> Void) {
|
||||||
guard let quickConnectSecret = quickConnectSecret else { return }
|
guard let quickConnectSecret = quickConnectSecret else { return }
|
||||||
|
|
||||||
QuickConnectAPI.connect(secret: quickConnectSecret)
|
QuickConnectAPI.connect(secret: quickConnectSecret)
|
||||||
|
@ -138,7 +119,8 @@ final class UserSignInViewModel: ViewModel {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.quickConnectTimer?.invalidate()
|
self.stopQuickConnectAuthCheck()
|
||||||
|
onSuccess()
|
||||||
|
|
||||||
SessionManager.main.signInUser(server: self.server, quickConnectSecret: quickConnectSecret)
|
SessionManager.main.signInUser(server: self.server, quickConnectSecret: quickConnectSecret)
|
||||||
.trackActivity(self.loading)
|
.trackActivity(self.loading)
|
||||||
|
@ -150,4 +132,11 @@ final class UserSignInViewModel: ViewModel {
|
||||||
})
|
})
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stopQuickConnectAuthCheck() {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.quickConnectTimer?.stop()
|
||||||
|
self.quickConnectTimer = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import JellyfinAPI
|
||||||
import Stinsen
|
import Stinsen
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ struct UserSignInView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
ImageView(viewModel.getSplashscreenUrl())
|
ImageView(ImageAPI.getSplashscreenWithRequestBuilder().url)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
Color.black
|
Color.black
|
||||||
|
@ -96,14 +97,20 @@ struct UserSignInView: View {
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.startQuickConnect {}
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
viewModel.stopQuickConnectAuthCheck()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserSignInView_Preivews: PreviewProvider {
|
// struct UserSignInView_Preivews: PreviewProvider {
|
||||||
static var previews: some View {
|
// static var previews: some View {
|
||||||
UserSignInView(viewModel: .init(server: .sample))
|
// UserSignInView(viewModel: .init(server: .sample))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -182,7 +182,6 @@
|
||||||
62EC3530267666A5000E9F2D /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC352E267666A5000E9F2D /* SessionManager.swift */; };
|
62EC3530267666A5000E9F2D /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC352E267666A5000E9F2D /* SessionManager.swift */; };
|
||||||
62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */; };
|
62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */; };
|
||||||
62ECA01826FA685A00E8EBB7 /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62ECA01726FA685A00E8EBB7 /* DeepLink.swift */; };
|
62ECA01826FA685A00E8EBB7 /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62ECA01726FA685A00E8EBB7 /* DeepLink.swift */; };
|
||||||
631759CF2879DB6A00A621AD /* PublicUserSignInCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631759CE2879DB6A00A621AD /* PublicUserSignInCellView.swift */; };
|
|
||||||
6334175B287DDFB9000603CE /* QuickConnectSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175A287DDFB9000603CE /* QuickConnectSettingsView.swift */; };
|
6334175B287DDFB9000603CE /* QuickConnectSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175A287DDFB9000603CE /* QuickConnectSettingsView.swift */; };
|
||||||
6334175D287DE0D0000603CE /* QuickConnectSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175C287DE0D0000603CE /* QuickConnectSettingsViewModel.swift */; };
|
6334175D287DE0D0000603CE /* QuickConnectSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175C287DE0D0000603CE /* QuickConnectSettingsViewModel.swift */; };
|
||||||
637FCAF5287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
637FCAF5287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
||||||
|
@ -254,6 +253,7 @@
|
||||||
E10EAA54277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10EAA52277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift */; };
|
E10EAA54277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10EAA52277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift */; };
|
||||||
E1101177281B1E8A006A3584 /* Puppy in Frameworks */ = {isa = PBXBuildFile; productRef = E1101176281B1E8A006A3584 /* Puppy */; };
|
E1101177281B1E8A006A3584 /* Puppy in Frameworks */ = {isa = PBXBuildFile; productRef = E1101176281B1E8A006A3584 /* Puppy */; };
|
||||||
E111DE222790BB46008118A3 /* DetectBottomScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E111DE212790BB46008118A3 /* DetectBottomScrollView.swift */; };
|
E111DE222790BB46008118A3 /* DetectBottomScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E111DE212790BB46008118A3 /* DetectBottomScrollView.swift */; };
|
||||||
|
E1171A1928A2212600FA1AF5 /* QuickConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1171A1828A2212600FA1AF5 /* QuickConnectView.swift */; };
|
||||||
E118959D289312020042947B /* BaseItemPerson+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E118959C289312020042947B /* BaseItemPerson+Poster.swift */; };
|
E118959D289312020042947B /* BaseItemPerson+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E118959C289312020042947B /* BaseItemPerson+Poster.swift */; };
|
||||||
E118959E289312020042947B /* BaseItemPerson+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E118959C289312020042947B /* BaseItemPerson+Poster.swift */; };
|
E118959E289312020042947B /* BaseItemPerson+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E118959C289312020042947B /* BaseItemPerson+Poster.swift */; };
|
||||||
E11895A9289383BC0042947B /* ScrollViewOffsetModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */; };
|
E11895A9289383BC0042947B /* ScrollViewOffsetModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */; };
|
||||||
|
@ -337,6 +337,11 @@
|
||||||
E184C161288C5C08000B25BA /* RequestBuilderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E184C15F288C5C08000B25BA /* RequestBuilderExtensions.swift */; };
|
E184C161288C5C08000B25BA /* RequestBuilderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E184C15F288C5C08000B25BA /* RequestBuilderExtensions.swift */; };
|
||||||
E18845F526DD631E00B0C5B7 /* BaseItemDto+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845F426DD631E00B0C5B7 /* BaseItemDto+Poster.swift */; };
|
E18845F526DD631E00B0C5B7 /* BaseItemDto+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845F426DD631E00B0C5B7 /* BaseItemDto+Poster.swift */; };
|
||||||
E18845F626DD631E00B0C5B7 /* BaseItemDto+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845F426DD631E00B0C5B7 /* BaseItemDto+Poster.swift */; };
|
E18845F626DD631E00B0C5B7 /* BaseItemDto+Poster.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18845F426DD631E00B0C5B7 /* BaseItemDto+Poster.swift */; };
|
||||||
|
E18CE0AF28A222240092E7F1 /* PublicUserSignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CE0AE28A222240092E7F1 /* PublicUserSignInView.swift */; };
|
||||||
|
E18CE0B228A229E70092E7F1 /* UserDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CE0B128A229E70092E7F1 /* UserDtoExtensions.swift */; };
|
||||||
|
E18CE0B428A22EDA0092E7F1 /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CE0B328A22EDA0092E7F1 /* RepeatingTimer.swift */; };
|
||||||
|
E18CE0B528A22EDD0092E7F1 /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CE0B328A22EDA0092E7F1 /* RepeatingTimer.swift */; };
|
||||||
|
E18CE0B928A2322D0092E7F1 /* QuickConnectCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CE0B828A2322D0092E7F1 /* QuickConnectCoordinator.swift */; };
|
||||||
E18E01A9288746AF0022598C /* PortraitPosterHStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18E01A3288746AF0022598C /* PortraitPosterHStack.swift */; };
|
E18E01A9288746AF0022598C /* PortraitPosterHStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18E01A3288746AF0022598C /* PortraitPosterHStack.swift */; };
|
||||||
E18E01AA288746AF0022598C /* RefreshableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18E01A4288746AF0022598C /* RefreshableScrollView.swift */; };
|
E18E01AA288746AF0022598C /* RefreshableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18E01A4288746AF0022598C /* RefreshableScrollView.swift */; };
|
||||||
E18E01AB288746AF0022598C /* PillHStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18E01A5288746AF0022598C /* PillHStack.swift */; };
|
E18E01AB288746AF0022598C /* PillHStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18E01A5288746AF0022598C /* PillHStack.swift */; };
|
||||||
|
@ -690,7 +695,6 @@
|
||||||
62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = "<group>"; };
|
62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = "<group>"; };
|
||||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
||||||
62ECA01726FA685A00E8EBB7 /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = "<group>"; };
|
62ECA01726FA685A00E8EBB7 /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = "<group>"; };
|
||||||
631759CE2879DB6A00A621AD /* PublicUserSignInCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicUserSignInCellView.swift; sourceTree = "<group>"; };
|
|
||||||
6334175A287DDFB9000603CE /* QuickConnectSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectSettingsView.swift; sourceTree = "<group>"; };
|
6334175A287DDFB9000603CE /* QuickConnectSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectSettingsView.swift; sourceTree = "<group>"; };
|
||||||
6334175C287DE0D0000603CE /* QuickConnectSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectSettingsViewModel.swift; sourceTree = "<group>"; };
|
6334175C287DE0D0000603CE /* QuickConnectSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectSettingsViewModel.swift; sourceTree = "<group>"; };
|
||||||
637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = UDPBroadcast.xcframework; path = Carthage/Build/UDPBroadcast.xcframework; sourceTree = "<group>"; };
|
637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = UDPBroadcast.xcframework; path = Carthage/Build/UDPBroadcast.xcframework; sourceTree = "<group>"; };
|
||||||
|
@ -742,6 +746,7 @@
|
||||||
E10EAA4E277BBCC4000269ED /* CGSizeExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGSizeExtensions.swift; sourceTree = "<group>"; };
|
E10EAA4E277BBCC4000269ED /* CGSizeExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGSizeExtensions.swift; sourceTree = "<group>"; };
|
||||||
E10EAA52277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemDto+VideoPlayerViewModel.swift"; sourceTree = "<group>"; };
|
E10EAA52277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemDto+VideoPlayerViewModel.swift"; sourceTree = "<group>"; };
|
||||||
E111DE212790BB46008118A3 /* DetectBottomScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectBottomScrollView.swift; sourceTree = "<group>"; };
|
E111DE212790BB46008118A3 /* DetectBottomScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectBottomScrollView.swift; sourceTree = "<group>"; };
|
||||||
|
E1171A1828A2212600FA1AF5 /* QuickConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectView.swift; sourceTree = "<group>"; };
|
||||||
E118959C289312020042947B /* BaseItemPerson+Poster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemPerson+Poster.swift"; sourceTree = "<group>"; };
|
E118959C289312020042947B /* BaseItemPerson+Poster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemPerson+Poster.swift"; sourceTree = "<group>"; };
|
||||||
E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewOffsetModifier.swift; sourceTree = "<group>"; };
|
E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewOffsetModifier.swift; sourceTree = "<group>"; };
|
||||||
E11895AB289383EE0042947B /* NavBarOffsetModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavBarOffsetModifier.swift; sourceTree = "<group>"; };
|
E11895AB289383EE0042947B /* NavBarOffsetModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavBarOffsetModifier.swift; sourceTree = "<group>"; };
|
||||||
|
@ -794,6 +799,10 @@
|
||||||
E17885A3278105170094FBCF /* SFSymbolButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SFSymbolButton.swift; sourceTree = "<group>"; };
|
E17885A3278105170094FBCF /* SFSymbolButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SFSymbolButton.swift; sourceTree = "<group>"; };
|
||||||
E184C15F288C5C08000B25BA /* RequestBuilderExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBuilderExtensions.swift; sourceTree = "<group>"; };
|
E184C15F288C5C08000B25BA /* RequestBuilderExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBuilderExtensions.swift; sourceTree = "<group>"; };
|
||||||
E18845F426DD631E00B0C5B7 /* BaseItemDto+Poster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemDto+Poster.swift"; sourceTree = "<group>"; };
|
E18845F426DD631E00B0C5B7 /* BaseItemDto+Poster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemDto+Poster.swift"; sourceTree = "<group>"; };
|
||||||
|
E18CE0AE28A222240092E7F1 /* PublicUserSignInView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicUserSignInView.swift; sourceTree = "<group>"; };
|
||||||
|
E18CE0B128A229E70092E7F1 /* UserDtoExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDtoExtensions.swift; sourceTree = "<group>"; };
|
||||||
|
E18CE0B328A22EDA0092E7F1 /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = "<group>"; };
|
||||||
|
E18CE0B828A2322D0092E7F1 /* QuickConnectCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectCoordinator.swift; sourceTree = "<group>"; };
|
||||||
E18E01A3288746AF0022598C /* PortraitPosterHStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PortraitPosterHStack.swift; sourceTree = "<group>"; };
|
E18E01A3288746AF0022598C /* PortraitPosterHStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PortraitPosterHStack.swift; sourceTree = "<group>"; };
|
||||||
E18E01A4288746AF0022598C /* RefreshableScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshableScrollView.swift; sourceTree = "<group>"; };
|
E18E01A4288746AF0022598C /* RefreshableScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshableScrollView.swift; sourceTree = "<group>"; };
|
||||||
E18E01A5288746AF0022598C /* PillHStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PillHStack.swift; sourceTree = "<group>"; };
|
E18E01A5288746AF0022598C /* PillHStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PillHStack.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1145,15 +1154,16 @@
|
||||||
children = (
|
children = (
|
||||||
E1D4BF802719D22800A11E64 /* AppAppearance.swift */,
|
E1D4BF802719D22800A11E64 /* AppAppearance.swift */,
|
||||||
E1D4BF862719D27100A11E64 /* Bitrates.swift */,
|
E1D4BF862719D27100A11E64 /* Bitrates.swift */,
|
||||||
E1C925F328875037002A7A66 /* ItemViewType.swift */,
|
|
||||||
53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */,
|
53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */,
|
||||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */,
|
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */,
|
||||||
E19169CD272514760085832A /* HTTPScheme.swift */,
|
E19169CD272514760085832A /* HTTPScheme.swift */,
|
||||||
|
E1C925F328875037002A7A66 /* ItemViewType.swift */,
|
||||||
E1AA331E2782639D00F6439C /* OverlayType.swift */,
|
E1AA331E2782639D00F6439C /* OverlayType.swift */,
|
||||||
E1C925F62887504B002A7A66 /* PanDirectionGestureRecognizer.swift */,
|
E1C925F62887504B002A7A66 /* PanDirectionGestureRecognizer.swift */,
|
||||||
E193D4DA27193CCA00900D82 /* PillStackable.swift */,
|
E193D4DA27193CCA00900D82 /* PillStackable.swift */,
|
||||||
E1C812B4277A8E5D00918266 /* PlaybackSpeed.swift */,
|
E1C812B4277A8E5D00918266 /* PlaybackSpeed.swift */,
|
||||||
E1937A60288F32DB00CB80AA /* Poster.swift */,
|
E1937A60288F32DB00CB80AA /* Poster.swift */,
|
||||||
|
E18CE0B328A22EDA0092E7F1 /* RepeatingTimer.swift */,
|
||||||
5D1603FB278A3D5700D22B99 /* SubtitleSize.swift */,
|
5D1603FB278A3D5700D22B99 /* SubtitleSize.swift */,
|
||||||
E1D4BF832719D25A00A11E64 /* TrackLanguage.swift */,
|
E1D4BF832719D25A00A11E64 /* TrackLanguage.swift */,
|
||||||
535870AC2669D8DD00D05A09 /* Typings.swift */,
|
535870AC2669D8DD00D05A09 /* Typings.swift */,
|
||||||
|
@ -1405,8 +1415,8 @@
|
||||||
E111DE212790BB46008118A3 /* DetectBottomScrollView.swift */,
|
E111DE212790BB46008118A3 /* DetectBottomScrollView.swift */,
|
||||||
E18E01A7288746AF0022598C /* DotHStack.swift */,
|
E18E01A7288746AF0022598C /* DotHStack.swift */,
|
||||||
E18E01A5288746AF0022598C /* PillHStack.swift */,
|
E18E01A5288746AF0022598C /* PillHStack.swift */,
|
||||||
E18E01A3288746AF0022598C /* PortraitPosterHStack.swift */,
|
|
||||||
53F866432687A45F00DCD1D7 /* PortraitPosterButton.swift */,
|
53F866432687A45F00DCD1D7 /* PortraitPosterButton.swift */,
|
||||||
|
E18E01A3288746AF0022598C /* PortraitPosterHStack.swift */,
|
||||||
E1AA331C2782541500F6439C /* PrimaryButton.swift */,
|
E1AA331C2782541500F6439C /* PrimaryButton.swift */,
|
||||||
E18E01A4288746AF0022598C /* RefreshableScrollView.swift */,
|
E18E01A4288746AF0022598C /* RefreshableScrollView.swift */,
|
||||||
);
|
);
|
||||||
|
@ -1425,7 +1435,6 @@
|
||||||
621338912660106C00A81A2A /* Extensions */ = {
|
621338912660106C00A81A2A /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E1AD105226D96D5F003E4A08 /* JellyfinAPIExtensions */,
|
|
||||||
E1A2C157279A7D76005EC829 /* BundleExtensions.swift */,
|
E1A2C157279A7D76005EC829 /* BundleExtensions.swift */,
|
||||||
E10EAA4E277BBCC4000269ED /* CGSizeExtensions.swift */,
|
E10EAA4E277BBCC4000269ED /* CGSizeExtensions.swift */,
|
||||||
6267B3D526710B8900A7371D /* CollectionExtensions.swift */,
|
6267B3D526710B8900A7371D /* CollectionExtensions.swift */,
|
||||||
|
@ -1433,11 +1442,12 @@
|
||||||
E1399473289B1EA900401ABC /* Defaults+Workaround.swift */,
|
E1399473289B1EA900401ABC /* Defaults+Workaround.swift */,
|
||||||
E1E00A34278628A40022235B /* DoubleExtensions.swift */,
|
E1E00A34278628A40022235B /* DoubleExtensions.swift */,
|
||||||
E11CEB8C28999B4A003E74C7 /* FontExtensions.swift */,
|
E11CEB8C28999B4A003E74C7 /* FontExtensions.swift */,
|
||||||
|
E1AD105226D96D5F003E4A08 /* JellyfinAPIExtensions */,
|
||||||
621338922660107500A81A2A /* StringExtensions.swift */,
|
621338922660107500A81A2A /* StringExtensions.swift */,
|
||||||
E1A2C153279A7D5A005EC829 /* UIApplicationExtensions.swift */,
|
E1A2C153279A7D5A005EC829 /* UIApplicationExtensions.swift */,
|
||||||
E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */,
|
E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */,
|
||||||
E18E0239288749540022598C /* UIScrollViewExtensions.swift */,
|
|
||||||
E1937A3D288F0D3D00CB80AA /* UIScreenExtensions.swift */,
|
E1937A3D288F0D3D00CB80AA /* UIScreenExtensions.swift */,
|
||||||
|
E18E0239288749540022598C /* UIScrollViewExtensions.swift */,
|
||||||
E1C812C4277A90B200918266 /* URLComponentsExtensions.swift */,
|
E1C812C4277A90B200918266 /* URLComponentsExtensions.swift */,
|
||||||
62E1DCC2273CE19800C9AE76 /* URLExtensions.swift */,
|
62E1DCC2273CE19800C9AE76 /* URLExtensions.swift */,
|
||||||
E11895A22893409D0042947B /* ViewExtensions */,
|
E11895A22893409D0042947B /* ViewExtensions */,
|
||||||
|
@ -1466,11 +1476,12 @@
|
||||||
6220D0B326D5ED8000B8E046 /* LibraryCoordinator.swift */,
|
6220D0B326D5ED8000B8E046 /* LibraryCoordinator.swift */,
|
||||||
62C29EA726D103D500C1D2E7 /* LibraryListCoordinator.swift */,
|
62C29EA726D103D500C1D2E7 /* LibraryListCoordinator.swift */,
|
||||||
C4BE07872728448B003F4AD1 /* LiveTVChannelsCoordinator.swift */,
|
C4BE07872728448B003F4AD1 /* LiveTVChannelsCoordinator.swift */,
|
||||||
|
C45942C427F67DA400C54FE7 /* LiveTVCoordinator.swift */,
|
||||||
C4BE07702725EB06003F4AD1 /* LiveTVProgramsCoordinator.swift */,
|
C4BE07702725EB06003F4AD1 /* LiveTVProgramsCoordinator.swift */,
|
||||||
C4BE07782726EE82003F4AD1 /* LiveTVTabCoordinator.swift */,
|
C4BE07782726EE82003F4AD1 /* LiveTVTabCoordinator.swift */,
|
||||||
C45942C427F67DA400C54FE7 /* LiveTVCoordinator.swift */,
|
|
||||||
E193D5412719404B00900D82 /* MainCoordinator */,
|
E193D5412719404B00900D82 /* MainCoordinator */,
|
||||||
C40CD921271F8CD8000FB198 /* MoviesLibrariesCoordinator.swift */,
|
C40CD921271F8CD8000FB198 /* MoviesLibrariesCoordinator.swift */,
|
||||||
|
E18CE0B828A2322D0092E7F1 /* QuickConnectCoordinator.swift */,
|
||||||
6220D0B626D5EE1100B8E046 /* SearchCoordinator.swift */,
|
6220D0B626D5EE1100B8E046 /* SearchCoordinator.swift */,
|
||||||
E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */,
|
E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */,
|
||||||
E13DD3E827177ED6009D4DAF /* ServerListCoordinator.swift */,
|
E13DD3E827177ED6009D4DAF /* ServerListCoordinator.swift */,
|
||||||
|
@ -1544,6 +1555,15 @@
|
||||||
path = ItemViewModel;
|
path = ItemViewModel;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E1171A1A28A2215800FA1AF5 /* UserSignInView */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E18CE0B028A222310092E7F1 /* Components */,
|
||||||
|
E13DD3F4271793BB009D4DAF /* UserSignInView.swift */,
|
||||||
|
);
|
||||||
|
path = UserSignInView;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E11895A22893409D0042947B /* ViewExtensions */ = {
|
E11895A22893409D0042947B /* ViewExtensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1675,12 +1695,12 @@
|
||||||
C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */,
|
C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */,
|
||||||
C4AE2C2F27498D2300AE13CF /* LiveTVHomeView.swift */,
|
C4AE2C2F27498D2300AE13CF /* LiveTVHomeView.swift */,
|
||||||
C4AE2C3127498D6A00AE13CF /* LiveTVProgramsView.swift */,
|
C4AE2C3127498D6A00AE13CF /* LiveTVProgramsView.swift */,
|
||||||
631759CE2879DB6A00A621AD /* PublicUserSignInCellView.swift */,
|
E1171A1828A2212600FA1AF5 /* QuickConnectView.swift */,
|
||||||
E173DA4F26D048D600CC4EB7 /* ServerDetailView.swift */,
|
E173DA4F26D048D600CC4EB7 /* ServerDetailView.swift */,
|
||||||
E13DD3E427177D15009D4DAF /* ServerListView.swift */,
|
E13DD3E427177D15009D4DAF /* ServerListView.swift */,
|
||||||
E1E5D54A2783E26100692DFE /* SettingsView */,
|
E1E5D54A2783E26100692DFE /* SettingsView */,
|
||||||
E13DD3FB2717EAE8009D4DAF /* UserListView.swift */,
|
E13DD3FB2717EAE8009D4DAF /* UserListView.swift */,
|
||||||
E13DD3F4271793BB009D4DAF /* UserSignInView.swift */,
|
E1171A1A28A2215800FA1AF5 /* UserSignInView */,
|
||||||
E193D5452719418B00900D82 /* VideoPlayer */,
|
E193D5452719418B00900D82 /* VideoPlayer */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
|
@ -1776,6 +1796,14 @@
|
||||||
path = Overlays;
|
path = Overlays;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E18CE0B028A222310092E7F1 /* Components */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E18CE0AE28A222240092E7F1 /* PublicUserSignInView.swift */,
|
||||||
|
);
|
||||||
|
path = Components;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E18E01B4288747230022598C /* iPadOS */ = {
|
E18E01B4288747230022598C /* iPadOS */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1964,6 +1992,7 @@
|
||||||
E122A9122788EAAD0060FA63 /* MediaStreamExtension.swift */,
|
E122A9122788EAAD0060FA63 /* MediaStreamExtension.swift */,
|
||||||
E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */,
|
E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */,
|
||||||
E184C15F288C5C08000B25BA /* RequestBuilderExtensions.swift */,
|
E184C15F288C5C08000B25BA /* RequestBuilderExtensions.swift */,
|
||||||
|
E18CE0B128A229E70092E7F1 /* UserDtoExtensions.swift */,
|
||||||
);
|
);
|
||||||
path = JellyfinAPIExtensions;
|
path = JellyfinAPIExtensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -2502,6 +2531,7 @@
|
||||||
E1FA2F7427818A8800B4C270 /* SmallMenuOverlay.swift in Sources */,
|
E1FA2F7427818A8800B4C270 /* SmallMenuOverlay.swift in Sources */,
|
||||||
E193D53C27193F9500900D82 /* UserListCoordinator.swift in Sources */,
|
E193D53C27193F9500900D82 /* UserListCoordinator.swift in Sources */,
|
||||||
E1CEFBF727914E6400F60429 /* CustomizeViewsSettings.swift in Sources */,
|
E1CEFBF727914E6400F60429 /* CustomizeViewsSettings.swift in Sources */,
|
||||||
|
E18CE0B528A22EDD0092E7F1 /* RepeatingTimer.swift in Sources */,
|
||||||
E13DD3C927164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
E13DD3C927164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */,
|
||||||
E193D53A27193F9000900D82 /* ServerListCoordinator.swift in Sources */,
|
E193D53A27193F9000900D82 /* ServerListCoordinator.swift in Sources */,
|
||||||
6220D0AE26D5EABB00B8E046 /* ViewExtensions.swift in Sources */,
|
6220D0AE26D5EABB00B8E046 /* ViewExtensions.swift in Sources */,
|
||||||
|
@ -2579,6 +2609,7 @@
|
||||||
C45942CD27F6994A00C54FE7 /* LiveTVPlayerView.swift in Sources */,
|
C45942CD27F6994A00C54FE7 /* LiveTVPlayerView.swift in Sources */,
|
||||||
62C29EA126D102A500C1D2E7 /* iOSMainTabCoordinator.swift in Sources */,
|
62C29EA126D102A500C1D2E7 /* iOSMainTabCoordinator.swift in Sources */,
|
||||||
E18E01E8288747230022598C /* SeriesItemContentView.swift in Sources */,
|
E18E01E8288747230022598C /* SeriesItemContentView.swift in Sources */,
|
||||||
|
E18CE0AF28A222240092E7F1 /* PublicUserSignInView.swift in Sources */,
|
||||||
E18E01E5288747230022598C /* CinematicScrollView.swift in Sources */,
|
E18E01E5288747230022598C /* CinematicScrollView.swift in Sources */,
|
||||||
E1C812C0277A8E5D00918266 /* VLCPlayerView.swift in Sources */,
|
E1C812C0277A8E5D00918266 /* VLCPlayerView.swift in Sources */,
|
||||||
E176DE6D278E30D2001EFD8D /* EpisodeCard.swift in Sources */,
|
E176DE6D278E30D2001EFD8D /* EpisodeCard.swift in Sources */,
|
||||||
|
@ -2636,11 +2667,13 @@
|
||||||
5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */,
|
5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */,
|
||||||
E107BB9327880A8F00354E07 /* CollectionItemViewModel.swift in Sources */,
|
E107BB9327880A8F00354E07 /* CollectionItemViewModel.swift in Sources */,
|
||||||
532175402671EE4F005491E6 /* LibraryFilterView.swift in Sources */,
|
532175402671EE4F005491E6 /* LibraryFilterView.swift in Sources */,
|
||||||
|
E1171A1928A2212600FA1AF5 /* QuickConnectView.swift in Sources */,
|
||||||
53DF641E263D9C0600A7CD1A /* LibraryView.swift in Sources */,
|
53DF641E263D9C0600A7CD1A /* LibraryView.swift in Sources */,
|
||||||
E11CEB8D28999B4A003E74C7 /* FontExtensions.swift in Sources */,
|
E11CEB8D28999B4A003E74C7 /* FontExtensions.swift in Sources */,
|
||||||
E1C812CE277AE43100918266 /* VideoPlayerViewModel.swift in Sources */,
|
E1C812CE277AE43100918266 /* VideoPlayerViewModel.swift in Sources */,
|
||||||
E11895A9289383BC0042947B /* ScrollViewOffsetModifier.swift in Sources */,
|
E11895A9289383BC0042947B /* ScrollViewOffsetModifier.swift in Sources */,
|
||||||
E1C812C3277A8E5D00918266 /* VLCPlayerOverlayView.swift in Sources */,
|
E1C812C3277A8E5D00918266 /* VLCPlayerOverlayView.swift in Sources */,
|
||||||
|
E18CE0B228A229E70092E7F1 /* UserDtoExtensions.swift in Sources */,
|
||||||
E18E01F0288747230022598C /* AttributeHStack.swift in Sources */,
|
E18E01F0288747230022598C /* AttributeHStack.swift in Sources */,
|
||||||
6334175B287DDFB9000603CE /* QuickConnectSettingsView.swift in Sources */,
|
6334175B287DDFB9000603CE /* QuickConnectSettingsView.swift in Sources */,
|
||||||
E18E0205288749200022598C /* AppIcon.swift in Sources */,
|
E18E0205288749200022598C /* AppIcon.swift in Sources */,
|
||||||
|
@ -2657,6 +2690,7 @@
|
||||||
5D1603FC278A3D5800D22B99 /* SubtitleSize.swift in Sources */,
|
5D1603FC278A3D5800D22B99 /* SubtitleSize.swift in Sources */,
|
||||||
E1F0204E26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */,
|
E1F0204E26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */,
|
||||||
E1FA891E289A305D00176FEB /* iPadOSCollectionItemContentView.swift in Sources */,
|
E1FA891E289A305D00176FEB /* iPadOSCollectionItemContentView.swift in Sources */,
|
||||||
|
E18CE0B928A2322D0092E7F1 /* QuickConnectCoordinator.swift in Sources */,
|
||||||
6334175D287DE0D0000603CE /* QuickConnectSettingsViewModel.swift in Sources */,
|
6334175D287DE0D0000603CE /* QuickConnectSettingsViewModel.swift in Sources */,
|
||||||
E18E01E0288747230022598C /* iPadOSMovieItemContentView.swift in Sources */,
|
E18E01E0288747230022598C /* iPadOSMovieItemContentView.swift in Sources */,
|
||||||
53649AB1269CFB1900A2D8B7 /* LogManager.swift in Sources */,
|
53649AB1269CFB1900A2D8B7 /* LogManager.swift in Sources */,
|
||||||
|
@ -2670,7 +2704,6 @@
|
||||||
6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */,
|
6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */,
|
||||||
53DE4BD2267098F300739748 /* SearchBarView.swift in Sources */,
|
53DE4BD2267098F300739748 /* SearchBarView.swift in Sources */,
|
||||||
E1E48CC9271E6D410021A2F9 /* RefreshHelper.swift in Sources */,
|
E1E48CC9271E6D410021A2F9 /* RefreshHelper.swift in Sources */,
|
||||||
631759CF2879DB6A00A621AD /* PublicUserSignInCellView.swift in Sources */,
|
|
||||||
E1D4BF842719D25A00A11E64 /* TrackLanguage.swift in Sources */,
|
E1D4BF842719D25A00A11E64 /* TrackLanguage.swift in Sources */,
|
||||||
E1002B5F2793C3BE00E47059 /* VLCPlayerChapterOverlayView.swift in Sources */,
|
E1002B5F2793C3BE00E47059 /* VLCPlayerChapterOverlayView.swift in Sources */,
|
||||||
E18E01DC288747230022598C /* iPadOSCinematicScrollView.swift in Sources */,
|
E18E01DC288747230022598C /* iPadOSCinematicScrollView.swift in Sources */,
|
||||||
|
@ -2713,6 +2746,7 @@
|
||||||
E176DE70278E369F001EFD8D /* MissingItemsSettingsView.swift in Sources */,
|
E176DE70278E369F001EFD8D /* MissingItemsSettingsView.swift in Sources */,
|
||||||
C4BE076F2720FEFF003F4AD1 /* PlainNavigationLinkButton.swift in Sources */,
|
C4BE076F2720FEFF003F4AD1 /* PlainNavigationLinkButton.swift in Sources */,
|
||||||
E1EBCB46278BD595009FE6E9 /* ItemOverviewView.swift in Sources */,
|
E1EBCB46278BD595009FE6E9 /* ItemOverviewView.swift in Sources */,
|
||||||
|
E18CE0B428A22EDA0092E7F1 /* RepeatingTimer.swift in Sources */,
|
||||||
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
|
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
|
||||||
62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */,
|
62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */,
|
||||||
5D64683D277B1649009E09AE /* PreferenceUIHostingSwizzling.swift in Sources */,
|
5D64683D277B1649009E09AE /* PreferenceUIHostingSwizzling.swift in Sources */,
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1320"
|
|
||||||
wasCreatedForAppExtension = "YES"
|
|
||||||
version = "2.0">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "628B951F2670CABD0091AF3B"
|
|
||||||
BuildableName = "Swiftfin Widget.appex"
|
|
||||||
BlueprintName = "Swiftfin Widget"
|
|
||||||
ReferencedContainer = "container:Swiftfin.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "5377CBF0263B596A003A4E83"
|
|
||||||
BuildableName = "Swiftfin iOS.app"
|
|
||||||
BlueprintName = "Swiftfin iOS"
|
|
||||||
ReferencedContainer = "container:Swiftfin.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<Testables>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = ""
|
|
||||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
|
||||||
launchStyle = "0"
|
|
||||||
askForAppToLaunch = "Yes"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES"
|
|
||||||
launchAutomaticallySubstyle = "2">
|
|
||||||
<RemoteRunnable
|
|
||||||
runnableDebuggingMode = "2"
|
|
||||||
BundleIdentifier = "com.apple.springboard">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "628B951F2670CABD0091AF3B"
|
|
||||||
BuildableName = "Swiftfin Widget.appex"
|
|
||||||
BlueprintName = "Swiftfin Widget"
|
|
||||||
ReferencedContainer = "container:Swiftfin.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</RemoteRunnable>
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "5377CBF0263B596A003A4E83"
|
|
||||||
BuildableName = "Swiftfin iOS.app"
|
|
||||||
BlueprintName = "Swiftfin iOS"
|
|
||||||
ReferencedContainer = "container:Swiftfin.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<EnvironmentVariables>
|
|
||||||
<EnvironmentVariable
|
|
||||||
key = "_XCWidgetKind"
|
|
||||||
value = ""
|
|
||||||
isEnabled = "NO">
|
|
||||||
</EnvironmentVariable>
|
|
||||||
<EnvironmentVariable
|
|
||||||
key = "_XCWidgetDefaultView"
|
|
||||||
value = "snapshot"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</EnvironmentVariable>
|
|
||||||
<EnvironmentVariable
|
|
||||||
key = "_XCWidgetFamily"
|
|
||||||
value = "medium"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</EnvironmentVariable>
|
|
||||||
</EnvironmentVariables>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
launchAutomaticallySubstyle = "2">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "5377CBF0263B596A003A4E83"
|
|
||||||
BuildableName = "Swiftfin iOS.app"
|
|
||||||
BlueprintName = "Swiftfin iOS"
|
|
||||||
ReferencedContainer = "container:Swiftfin.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
|
@ -1,45 +0,0 @@
|
||||||
//
|
|
||||||
// Swiftfin is subject to the terms of the Mozilla Public
|
|
||||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
|
||||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
|
||||||
//
|
|
||||||
|
|
||||||
import JellyfinAPI
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct UserLoginCellView: View {
|
|
||||||
|
|
||||||
@ObservedObject
|
|
||||||
var viewModel: UserSignInViewModel
|
|
||||||
|
|
||||||
@State
|
|
||||||
private var enteredPassword: String = ""
|
|
||||||
|
|
||||||
var user: UserDto
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
DisclosureGroup {
|
|
||||||
SecureField(L10n.password, text: $enteredPassword)
|
|
||||||
Button {
|
|
||||||
viewModel.signIn(username: user.name ?? "--", password: enteredPassword)
|
|
||||||
} label: {
|
|
||||||
L10n.signIn.text
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
HStack {
|
|
||||||
ImageView(viewModel.getProfileImageUrl(user: user)) {
|
|
||||||
Image(systemName: "person.circle")
|
|
||||||
.resizable()
|
|
||||||
.frame(width: 50, height: 50)
|
|
||||||
}
|
|
||||||
.frame(width: 50, height: 50)
|
|
||||||
.clipShape(Circle())
|
|
||||||
|
|
||||||
Text(user.name ?? "--")
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct QuickConnectView: View {
|
||||||
|
|
||||||
|
@EnvironmentObject
|
||||||
|
private var router: QuickConnectCoordinator.Router
|
||||||
|
@ObservedObject
|
||||||
|
var viewModel: UserSignInViewModel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
|
L10n.quickConnectStep1.text
|
||||||
|
|
||||||
|
L10n.quickConnectStep2.text
|
||||||
|
|
||||||
|
L10n.quickConnectStep3.text
|
||||||
|
.padding(.bottom)
|
||||||
|
|
||||||
|
Text(viewModel.quickConnectCode ?? "------")
|
||||||
|
.tracking(10)
|
||||||
|
.font(.largeTitle)
|
||||||
|
.monospacedDigit()
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
|
.navigationTitle(L10n.quickConnect)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.startQuickConnect {
|
||||||
|
self.router.dismissCoordinator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
viewModel.stopQuickConnectAuthCheck()
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||||
|
Button {
|
||||||
|
router.dismissCoordinator()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "xmark.circle.fill")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,15 +67,6 @@ struct SettingsView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
|
||||||
settingsRouter.dismissCoordinator {
|
|
||||||
SessionManager.main.logout()
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
L10n.switchUser.text
|
|
||||||
.font(.callout)
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
settingsRouter.route(to: \.quickConnect)
|
settingsRouter.route(to: \.quickConnect)
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -86,6 +77,15 @@ struct SettingsView: View {
|
||||||
Image(systemName: "chevron.right")
|
Image(systemName: "chevron.right")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
settingsRouter.dismissCoordinator {
|
||||||
|
SessionManager.main.logout()
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
L10n.switchUser.text
|
||||||
|
.font(.callout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: L10n.videoPlayer.text) {
|
Section(header: L10n.videoPlayer.text) {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// Swiftfin is subject to the terms of the Mozilla Public
|
||||||
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||||
|
//
|
||||||
|
|
||||||
|
import JellyfinAPI
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension UserSignInView {
|
||||||
|
|
||||||
|
struct PublicUserSignInView: View {
|
||||||
|
|
||||||
|
@ObservedObject
|
||||||
|
var viewModel: UserSignInViewModel
|
||||||
|
|
||||||
|
@State
|
||||||
|
private var enteredPassword: String = ""
|
||||||
|
|
||||||
|
let publicUser: UserDto
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
DisclosureGroup {
|
||||||
|
SecureField(L10n.password, text: $enteredPassword)
|
||||||
|
Button {
|
||||||
|
viewModel.signIn(username: publicUser.name ?? "--", password: enteredPassword)
|
||||||
|
} label: {
|
||||||
|
L10n.signIn.text
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
ImageView(publicUser.profileImageSource(maxWidth: 50, maxHeight: 50)) {
|
||||||
|
Image(systemName: "person.circle")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 50, height: 50)
|
||||||
|
}
|
||||||
|
.frame(width: 50, height: 50)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Text(publicUser.name ?? "--")
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,8 @@ import SwiftUI
|
||||||
|
|
||||||
struct UserSignInView: View {
|
struct UserSignInView: View {
|
||||||
|
|
||||||
|
@EnvironmentObject
|
||||||
|
private var router: UserSignInCoordinator.Router
|
||||||
@ObservedObject
|
@ObservedObject
|
||||||
var viewModel: UserSignInViewModel
|
var viewModel: UserSignInViewModel
|
||||||
@State
|
@State
|
||||||
|
@ -47,10 +49,18 @@ struct UserSignInView: View {
|
||||||
L10n.signInToServer(viewModel.server.name).text
|
L10n.signInToServer(viewModel.server.name).text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if viewModel.quickConnectEnabled {
|
||||||
|
Button {
|
||||||
|
router.route(to: \.quickConnect)
|
||||||
|
} label: {
|
||||||
|
L10n.quickConnect.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
if !viewModel.publicUsers.isEmpty {
|
if !viewModel.publicUsers.isEmpty {
|
||||||
ForEach(viewModel.publicUsers, id: \.id) { user in
|
ForEach(viewModel.publicUsers, id: \.id) { user in
|
||||||
UserLoginCellView(viewModel: viewModel, user: user)
|
PublicUserSignInView(viewModel: viewModel, publicUser: user)
|
||||||
.disabled(viewModel.isLoading)
|
.disabled(viewModel.isLoading)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -65,9 +75,11 @@ struct UserSignInView: View {
|
||||||
} header: {
|
} header: {
|
||||||
HStack {
|
HStack {
|
||||||
L10n.publicUsers.text
|
L10n.publicUsers.text
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
viewModel.loadUsers()
|
viewModel.getPublicUsers()
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "arrow.clockwise.circle.fill")
|
Image(systemName: "arrow.clockwise.circle.fill")
|
||||||
}
|
}
|
||||||
|
@ -85,6 +97,8 @@ struct UserSignInView: View {
|
||||||
}
|
}
|
||||||
.navigationTitle(L10n.signIn)
|
.navigationTitle(L10n.signIn)
|
||||||
.navigationBarBackButtonHidden(viewModel.isLoading)
|
.navigationBarBackButtonHidden(viewModel.isLoading)
|
||||||
.onAppear(perform: viewModel.loadUsers)
|
.onDisappear {
|
||||||
|
viewModel.stopQuickConnectAuthCheck()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue