Fix Basic Multi Server URL (#1012)
This commit is contained in:
parent
0e21fb0369
commit
8a0ef0e48f
|
@ -50,18 +50,18 @@ final class MainCoordinator: NavigationCoordinatable {
|
|||
Notifications[.didSignIn].subscribe(self, selector: #selector(didSignIn))
|
||||
Notifications[.didSignOut].subscribe(self, selector: #selector(didSignOut))
|
||||
Notifications[.processDeepLink].subscribe(self, selector: #selector(processDeepLink(_:)))
|
||||
Notifications[.didChangeServerCurrentURI].subscribe(self, selector: #selector(didChangeServerCurrentURI(_:)))
|
||||
Notifications[.didChangeCurrentServerURL].subscribe(self, selector: #selector(didChangeCurrentServerURL(_:)))
|
||||
}
|
||||
|
||||
@objc
|
||||
func didSignIn() {
|
||||
logger.info("Received `didSignIn` from SwiftfinNotificationCenter.")
|
||||
logger.info("Signed in")
|
||||
root(\.mainTab)
|
||||
}
|
||||
|
||||
@objc
|
||||
func didSignOut() {
|
||||
logger.info("Received `didSignOut` from SwiftfinNotificationCenter.")
|
||||
logger.info("Signed out")
|
||||
root(\.serverList)
|
||||
}
|
||||
|
||||
|
@ -80,13 +80,12 @@ final class MainCoordinator: NavigationCoordinatable {
|
|||
}
|
||||
|
||||
@objc
|
||||
func didChangeServerCurrentURI(_ notification: Notification) {
|
||||
// guard let newCurrentServerState = notification.object as? SwiftfinStore.State.Server
|
||||
// else { fatalError("Need to have new current login state server") }
|
||||
// guard SessionManager.main.currentLogin != nil else { return }
|
||||
// if newCurrentServerState.id == SessionManager.main.currentLogin.server.id {
|
||||
// SessionManager.main.signInUser(server: newCurrentServerState, user: SessionManager.main.currentLogin.user)
|
||||
// }
|
||||
func didChangeCurrentServerURL(_ notification: Notification) {
|
||||
|
||||
guard Container.userSession().authenticated else { return }
|
||||
|
||||
Container.userSession.reset()
|
||||
Notifications[.didSignIn].post()
|
||||
}
|
||||
|
||||
func makeMainTab() -> MainTabCoordinator {
|
||||
|
|
|
@ -1,30 +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) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Stinsen
|
||||
import SwiftUI
|
||||
|
||||
final class ServerDetailCoordinator: NavigationCoordinatable {
|
||||
|
||||
let stack = NavigationStack(initial: \ServerDetailCoordinator.start)
|
||||
|
||||
@Root
|
||||
var start = makeStart
|
||||
|
||||
let viewModel: ServerDetailViewModel
|
||||
|
||||
init(viewModel: ServerDetailViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func makeStart() -> some View {
|
||||
ServerDetailView(viewModel: viewModel)
|
||||
}
|
||||
}
|
|
@ -28,8 +28,8 @@ final class ServerListCoordinator: NavigationCoordinatable {
|
|||
ConnectToServerCoodinator()
|
||||
}
|
||||
|
||||
func makeUserList(server: SwiftfinStore.State.Server) -> UserListCoordinator {
|
||||
UserListCoordinator(viewModel: .init(server: server))
|
||||
func makeUserList(server: ServerState) -> UserListCoordinator {
|
||||
UserListCoordinator(server: server)
|
||||
}
|
||||
|
||||
func makeBasicAppSettings() -> NavigationViewCoordinator<BasicAppSettingsCoordinator> {
|
||||
|
|
|
@ -107,7 +107,7 @@ final class SettingsCoordinator: NavigationCoordinatable {
|
|||
|
||||
@ViewBuilder
|
||||
func makeServerDetail(server: ServerState) -> some View {
|
||||
ServerDetailView(viewModel: .init(server: server))
|
||||
ServerDetailView(server: server)
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
@ -155,7 +155,7 @@ final class SettingsCoordinator: NavigationCoordinatable {
|
|||
func makeServerDetail(server: ServerState) -> NavigationViewCoordinator<BasicNavigationViewCoordinator> {
|
||||
NavigationViewCoordinator(
|
||||
BasicNavigationViewCoordinator {
|
||||
ServerDetailView(viewModel: .init(server: server))
|
||||
ServerDetailView(server: server)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,22 +21,22 @@ final class UserListCoordinator: NavigationCoordinatable {
|
|||
@Route(.push)
|
||||
var serverDetail = makeServerDetail
|
||||
|
||||
let viewModel: UserListViewModel
|
||||
let serverState: ServerState
|
||||
|
||||
init(viewModel: UserListViewModel) {
|
||||
self.viewModel = viewModel
|
||||
init(server: ServerState) {
|
||||
self.serverState = server
|
||||
}
|
||||
|
||||
func makeUserSignIn(server: SwiftfinStore.State.Server) -> UserSignInCoordinator {
|
||||
UserSignInCoordinator(viewModel: .init(server: server))
|
||||
}
|
||||
|
||||
func makeServerDetail(server: SwiftfinStore.State.Server) -> ServerDetailCoordinator {
|
||||
ServerDetailCoordinator(viewModel: .init(server: server))
|
||||
func makeServerDetail(server: SwiftfinStore.State.Server) -> some View {
|
||||
ServerDetailView(server: server)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func makeStart() -> some View {
|
||||
UserListView(viewModel: viewModel)
|
||||
UserListView(server: serverState)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ extension Notifications.Key {
|
|||
static let didSignOut = NotificationKey("didSignOut")
|
||||
static let processDeepLink = NotificationKey("processDeepLink")
|
||||
static let didPurge = NotificationKey("didPurge")
|
||||
static let didChangeServerCurrentURI = NotificationKey("didChangeCurrentLoginURI")
|
||||
static let didChangeCurrentServerURL = NotificationKey("didChangeCurrentServerURL")
|
||||
static let didSendStopReport = NotificationKey("didSendStopReport")
|
||||
static let didRequestGlobalRefresh = NotificationKey("didRequestGlobalRefresh")
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import CoreStore
|
||||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
|
@ -18,16 +19,36 @@ class ServerDetailViewModel: ViewModel {
|
|||
self.server = server
|
||||
}
|
||||
|
||||
func setServerCurrentURI(uri: String) {
|
||||
func setCurrentServerURL(to url: URL) {
|
||||
|
||||
// SessionManager.main.setServerCurrentURI(server: server, uri: uri)
|
||||
// .sink { c in
|
||||
// print(c)
|
||||
// } receiveValue: { newServerState in
|
||||
// self.server = newServerState
|
||||
//
|
||||
// Notifications[.didChangeServerCurrentURI].post(object: newServerState)
|
||||
// }
|
||||
// .store(in: &cancellables)
|
||||
guard let storedServer = try? SwiftfinStore.dataStack.fetchOne(
|
||||
From<ServerModel>(),
|
||||
[Where<ServerModel>("id == %@", server.id)]
|
||||
) else {
|
||||
logger.error("Unable to find server")
|
||||
return
|
||||
}
|
||||
|
||||
guard storedServer.urls.contains(url) else {
|
||||
logger.error("Server did not have matching URL")
|
||||
return
|
||||
}
|
||||
|
||||
let transaction = SwiftfinStore.dataStack.beginUnsafe()
|
||||
|
||||
guard let editServer = transaction.edit(storedServer) else {
|
||||
logger.error("Unable to create edit server instance")
|
||||
return
|
||||
}
|
||||
|
||||
editServer.currentURL = url
|
||||
|
||||
do {
|
||||
try transaction.commitAndWait()
|
||||
|
||||
Notifications[.didChangeCurrentServerURL].post(object: editServer.state)
|
||||
} catch {
|
||||
logger.error("Unable to edit server")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,32 +18,36 @@ class UserListViewModel: ViewModel {
|
|||
|
||||
@Published
|
||||
private(set) var users: [UserState] = []
|
||||
@Published
|
||||
private(set) var server: ServerState
|
||||
|
||||
let client: JellyfinClient
|
||||
let server: ServerState
|
||||
|
||||
init(server: ServerState) {
|
||||
self.client = JellyfinClient(
|
||||
var client: JellyfinClient {
|
||||
JellyfinClient(
|
||||
configuration: .swiftfinConfiguration(url: server.currentURL),
|
||||
sessionDelegate: URLSessionProxyDelegate()
|
||||
)
|
||||
}
|
||||
|
||||
init(server: ServerState) {
|
||||
self.server = server
|
||||
super.init()
|
||||
|
||||
// Notifications[.didChangeServerCurrentURI].subscribe(self, selector: #selector(didChangeCurrentLoginURI(_:)))
|
||||
}
|
||||
|
||||
@objc
|
||||
func didChangeCurrentLoginURI(_ notification: Notification) {
|
||||
// guard let newServerState = notification.object as? SwiftfinStore.State.Server else { fatalError("Need to have new state server") }
|
||||
// self.server = newServerState
|
||||
Notifications[.didChangeCurrentServerURL]
|
||||
.publisher
|
||||
.sink { [weak self] notification in
|
||||
guard let serverState = notification.object as? SwiftfinStore.State.Server else {
|
||||
return
|
||||
}
|
||||
self?.server = serverState
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func fetchUsers() {
|
||||
|
||||
guard let storedServer = try? SwiftfinStore.dataStack.fetchOne(
|
||||
From<SwiftfinStore.Models.StoredServer>(),
|
||||
Where<SwiftfinStore.Models.StoredServer>("id == %@", server.id)
|
||||
From<ServerModel>(),
|
||||
Where<ServerModel>("id == %@", server.id)
|
||||
)
|
||||
else { fatalError("No stored server associated with given state server?") }
|
||||
|
||||
|
@ -58,7 +62,23 @@ class UserListViewModel: ViewModel {
|
|||
Notifications[.didSignIn].post()
|
||||
}
|
||||
|
||||
func remove(user: SwiftfinStore.State.User) {
|
||||
fetchUsers()
|
||||
func remove(user: UserState) {
|
||||
guard let storedUser = try? SwiftfinStore.dataStack.fetchOne(
|
||||
From<SwiftfinStore.Models.StoredUser>(),
|
||||
[Where<SwiftfinStore.Models.StoredUser>("id == %@", user.id)]
|
||||
) else {
|
||||
logger.error("Unable to find user to delete")
|
||||
return
|
||||
}
|
||||
|
||||
let transaction = SwiftfinStore.dataStack.beginUnsafe()
|
||||
transaction.delete(storedUser)
|
||||
|
||||
do {
|
||||
try transaction.commitAndWait()
|
||||
fetchUsers()
|
||||
} catch {
|
||||
logger.error("Unable to delete user")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,5 +28,13 @@ class ViewModel: ObservableObject {
|
|||
|
||||
var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init() {}
|
||||
private var userSessionResolverCancellable: AnyCancellable?
|
||||
|
||||
init() {
|
||||
userSessionResolverCancellable = Notifications[.didChangeCurrentServerURL]
|
||||
.publisher
|
||||
.sink { [weak self] _ in
|
||||
self?.$userSession.resolve(reset: .scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,9 @@ struct ServerButton: View {
|
|||
|
||||
Spacer()
|
||||
}
|
||||
.padding(10)
|
||||
}
|
||||
.buttonStyle(.card)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,12 @@ import SwiftUI
|
|||
|
||||
struct ServerDetailView: View {
|
||||
|
||||
@ObservedObject
|
||||
var viewModel: ServerDetailViewModel
|
||||
@StateObject
|
||||
private var viewModel: ServerDetailViewModel
|
||||
|
||||
init(server: ServerState) {
|
||||
self._viewModel = StateObject(wrappedValue: ServerDetailViewModel(server: server))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
SplitFormWindowView()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import CollectionView
|
||||
import CollectionVGrid
|
||||
import SwiftUI
|
||||
|
||||
struct ServerListView: View {
|
||||
|
@ -22,22 +22,23 @@ struct ServerListView: View {
|
|||
|
||||
@ViewBuilder
|
||||
private var listView: some View {
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
ForEach(viewModel.servers, id: \.id) { server in
|
||||
ServerButton(server: server)
|
||||
.onSelect {
|
||||
router.route(to: \.userList, server)
|
||||
}
|
||||
.onLongPressGesture {
|
||||
longPressedServer = server
|
||||
}
|
||||
.padding(.horizontal, 100)
|
||||
CollectionVGrid(
|
||||
viewModel.servers,
|
||||
layout: .columns(
|
||||
1,
|
||||
insets: EdgeInsets.DefaultEdgeInsets,
|
||||
itemSpacing: EdgeInsets.defaultEdgePadding,
|
||||
lineSpacing: EdgeInsets.defaultEdgePadding
|
||||
)
|
||||
) { server in
|
||||
ServerButton(server: server)
|
||||
.onSelect {
|
||||
router.route(to: \.userList, server)
|
||||
}
|
||||
.onLongPressGesture {
|
||||
longPressedServer = server
|
||||
}
|
||||
}
|
||||
.padding(.top, 50)
|
||||
}
|
||||
.padding(.top, 50)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
@ -72,27 +73,32 @@ struct ServerListView: View {
|
|||
}
|
||||
|
||||
var body: some View {
|
||||
SplitFormWindowView()
|
||||
.descriptionView {
|
||||
VStack {
|
||||
Image(.jellyfinBlobBlue)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(maxWidth: 400)
|
||||
HStack {
|
||||
VStack {
|
||||
Image(.jellyfinBlobBlue)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(maxWidth: 400)
|
||||
|
||||
Button {
|
||||
router.route(to: \.connectToServer)
|
||||
} label: {
|
||||
L10n.connect.text
|
||||
.bold()
|
||||
.font(.callout)
|
||||
.frame(width: 400, height: 75)
|
||||
.background(Color.jellyfinPurple)
|
||||
}
|
||||
.buttonStyle(.card)
|
||||
Button {
|
||||
router.route(to: \.connectToServer)
|
||||
} label: {
|
||||
L10n.connect.text
|
||||
.bold()
|
||||
.font(.callout)
|
||||
.frame(width: 400, height: 75)
|
||||
.background(Color.jellyfinPurple)
|
||||
}
|
||||
.buttonStyle(.card)
|
||||
}
|
||||
.contentView {}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
innerBody
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.onAppear {
|
||||
viewModel.fetchServers()
|
||||
}
|
||||
}
|
||||
|
||||
// var body: some View {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import CollectionView
|
||||
import CollectionVGrid
|
||||
import Factory
|
||||
import JellyfinAPI
|
||||
import SwiftUI
|
||||
|
@ -16,15 +16,27 @@ struct UserListView: View {
|
|||
@EnvironmentObject
|
||||
private var router: UserListCoordinator.Router
|
||||
|
||||
@ObservedObject
|
||||
var viewModel: UserListViewModel
|
||||
|
||||
@State
|
||||
private var longPressedUser: SwiftfinStore.State.User?
|
||||
|
||||
@StateObject
|
||||
private var viewModel: UserListViewModel
|
||||
|
||||
init(server: ServerState) {
|
||||
self._viewModel = StateObject(wrappedValue: UserListViewModel(server: server))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var listView: some View {
|
||||
CollectionView(items: viewModel.users) { _, user, _ in
|
||||
CollectionVGrid(
|
||||
viewModel.users,
|
||||
layout: .minWidth(
|
||||
250,
|
||||
insets: EdgeInsets.DefaultEdgeInsets,
|
||||
itemSpacing: EdgeInsets.defaultEdgePadding,
|
||||
lineSpacing: EdgeInsets.defaultEdgePadding
|
||||
)
|
||||
) { user in
|
||||
UserProfileButton(user: user)
|
||||
.onSelect {
|
||||
viewModel.signIn(user: user)
|
||||
|
@ -33,16 +45,6 @@ struct UserListView: View {
|
|||
longPressedUser = user
|
||||
}
|
||||
}
|
||||
.layout { _, layoutEnvironment in
|
||||
.grid(
|
||||
layoutEnvironment: layoutEnvironment,
|
||||
layoutMode: .adaptive(withMinItemSize: 250),
|
||||
itemSpacing: 20,
|
||||
lineSpacing: 20,
|
||||
sectionInsets: .init(top: 20, leading: 20, bottom: 20, trailing: 20)
|
||||
)
|
||||
}
|
||||
.padding(50)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
|
|
@ -247,8 +247,6 @@
|
|||
E11CEB8D28999B4A003E74C7 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11CEB8C28999B4A003E74C7 /* Font.swift */; };
|
||||
E11CEB9128999D84003E74C7 /* EpisodeItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11CEB8F28999D84003E74C7 /* EpisodeItemView.swift */; };
|
||||
E11CEB9428999D9E003E74C7 /* EpisodeItemContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11CEB9328999D9E003E74C7 /* EpisodeItemContentView.swift */; };
|
||||
E11D224227378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */; };
|
||||
E11D224327378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */; };
|
||||
E11E374D293E7EC9009EF240 /* ItemFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D842902933F87500D1041A /* ItemFields.swift */; };
|
||||
E11E374E293E7F08009EF240 /* MediaSourceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D8428E2933F2D900D1041A /* MediaSourceInfo.swift */; };
|
||||
E11E376D293E9CC1009EF240 /* VideoPlayerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18A8E8428D60D0000333B9A /* VideoPlayerCoordinator.swift */; };
|
||||
|
@ -993,7 +991,6 @@
|
|||
E11CEB8C28999B4A003E74C7 /* Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = "<group>"; };
|
||||
E11CEB8F28999D84003E74C7 /* EpisodeItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeItemView.swift; sourceTree = "<group>"; };
|
||||
E11CEB9328999D9E003E74C7 /* EpisodeItemContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeItemContentView.swift; sourceTree = "<group>"; };
|
||||
E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailCoordinator.swift; sourceTree = "<group>"; };
|
||||
E122A9122788EAAD0060FA63 /* MediaStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaStream.swift; sourceTree = "<group>"; };
|
||||
E12376AD2A33D680001F5B44 /* AboutViewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewCard.swift; sourceTree = "<group>"; };
|
||||
E12376AF2A33D6AE001F5B44 /* AboutViewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewCard.swift; sourceTree = "<group>"; };
|
||||
|
@ -1934,7 +1931,6 @@
|
|||
E1A1528F28FD23D600600579 /* PlaybackSettingsCoordinator.swift */,
|
||||
E18CE0B828A2322D0092E7F1 /* QuickConnectCoordinator.swift */,
|
||||
6220D0B626D5EE1100B8E046 /* SearchCoordinator.swift */,
|
||||
E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */,
|
||||
E13DD3E827177ED6009D4DAF /* ServerListCoordinator.swift */,
|
||||
6220D0B026D5EC9900B8E046 /* SettingsCoordinator.swift */,
|
||||
E13DD4012717EE79009D4DAF /* UserListCoordinator.swift */,
|
||||
|
@ -3302,7 +3298,6 @@
|
|||
E1E1643E28BB074000323B0A /* SelectorView.swift in Sources */,
|
||||
E1A1529128FD23D600600579 /* PlaybackSettingsCoordinator.swift in Sources */,
|
||||
E187A60529AD2E25008387E6 /* StepperView.swift in Sources */,
|
||||
E11D224327378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */,
|
||||
E1575E71293E77B5001665B1 /* RepeatingTimer.swift in Sources */,
|
||||
E1D4BF8B2719D3D000A11E64 /* BasicAppSettingsCoordinator.swift in Sources */,
|
||||
E13DD3FA2717E961009D4DAF /* UserListViewModel.swift in Sources */,
|
||||
|
@ -3702,7 +3697,6 @@
|
|||
E1921B7428E61914003A5238 /* SpecialFeatureHStack.swift in Sources */,
|
||||
C45942D027F69C2400C54FE7 /* LiveTVChannelsCoordinator.swift in Sources */,
|
||||
E118959D289312020042947B /* BaseItemPerson+Poster.swift in Sources */,
|
||||
E11D224227378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */,
|
||||
6264E88C273850380081A12A /* Strings.swift in Sources */,
|
||||
C4AE2C3227498D6A00AE13CF /* LiveTVProgramsView.swift in Sources */,
|
||||
E1BDF31729525F0400CC0294 /* AdvancedActionButton.swift in Sources */,
|
||||
|
@ -4258,7 +4252,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 78;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
|
@ -4274,7 +4268,7 @@
|
|||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
OTHER_CFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jellyfin.swiftfin;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pip.jellyfin.swiftfin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
|
@ -4298,7 +4292,7 @@
|
|||
CURRENT_PROJECT_VERSION = 78;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
|
@ -4314,7 +4308,7 @@
|
|||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
OTHER_CFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jellyfin.swiftfin;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pip.jellyfin.swiftfin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
|
|
|
@ -6,58 +6,55 @@
|
|||
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Factory
|
||||
import SwiftUI
|
||||
|
||||
struct ServerDetailView: View {
|
||||
|
||||
@ObservedObject
|
||||
var viewModel: ServerDetailViewModel
|
||||
|
||||
@State
|
||||
private var currentServerURI: String
|
||||
private var currentServerURL: URL
|
||||
|
||||
init(viewModel: ServerDetailViewModel) {
|
||||
self.viewModel = viewModel
|
||||
self._currentServerURI = State(initialValue: viewModel.server.currentURL.absoluteString)
|
||||
@StateObject
|
||||
private var viewModel: ServerDetailViewModel
|
||||
|
||||
init(server: ServerState) {
|
||||
self._viewModel = StateObject(wrappedValue: ServerDetailViewModel(server: server))
|
||||
self._currentServerURL = State(initialValue: server.currentURL)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
HStack {
|
||||
L10n.name.text
|
||||
Spacer()
|
||||
Text(viewModel.server.name)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
Picker(L10n.url, selection: $currentServerURI) {
|
||||
TextPairView(
|
||||
leading: L10n.name,
|
||||
trailing: viewModel.server.name
|
||||
)
|
||||
|
||||
Picker(L10n.url, selection: $currentServerURL) {
|
||||
ForEach(viewModel.server.urls.sorted(using: \.absoluteString)) { url in
|
||||
Text(url.absoluteString)
|
||||
.tag(url)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.onChange(of: currentServerURI) { _ in
|
||||
.onChange(of: currentServerURL) { _ in
|
||||
// TODO: change server url
|
||||
viewModel.setCurrentServerURL(to: currentServerURL)
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
L10n.version.text
|
||||
Spacer()
|
||||
Text(viewModel.server.version)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
TextPairView(
|
||||
leading: L10n.version,
|
||||
trailing: viewModel.server.version
|
||||
)
|
||||
|
||||
HStack {
|
||||
L10n.operatingSystem.text
|
||||
Spacer()
|
||||
Text(viewModel.server.os)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
TextPairView(
|
||||
leading: L10n.operatingSystem,
|
||||
trailing: viewModel.server.os
|
||||
)
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationTitle(L10n.serverDetails.text)
|
||||
.navigationTitle(L10n.server)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,12 @@ struct UserListView: View {
|
|||
@EnvironmentObject
|
||||
private var router: UserListCoordinator.Router
|
||||
|
||||
@ObservedObject
|
||||
var viewModel: UserListViewModel
|
||||
@StateObject
|
||||
private var viewModel: UserListViewModel
|
||||
|
||||
init(server: ServerState) {
|
||||
self._viewModel = StateObject(wrappedValue: UserListViewModel(server: server))
|
||||
}
|
||||
|
||||
private var noUserView: some View {
|
||||
VStack {
|
||||
|
|
Loading…
Reference in New Issue