From d580e8dcfd8e1049ce8bc1fe4a6cdc70356686ff Mon Sep 17 00:00:00 2001 From: Joe Kribs Date: Thu, 19 Dec 2024 15:38:27 -0700 Subject: [PATCH] [tvOS] SelectServerView Change to Menu (#1363) * Selection & Fix ServerSelectionMenu padding * ButtonStyle * Move from `FullScreenMenu` to just use `Menu` Remove usages of `FullScreenMenu` since it's no longer used anywhere else. * Remove unused `FullScreenMenu` * Remove unused `SelectServerView` since it's now in the `ServerSelectionMenu` * Selection menu fixes * Focus issues * clean up --------- Co-authored-by: Ethan Pippin --- .../Coordinators/SelectUserCoordinator.swift | 19 --- Swiftfin tvOS/Components/FullScreenMenu.swift | 51 ------- Swiftfin tvOS/Views/SelectServerView.swift | 127 ------------------ .../Components/ServerSelectionMenu.swift | 74 ++++++---- Swiftfin.xcodeproj/project.pbxproj | 6 - 5 files changed, 50 insertions(+), 227 deletions(-) delete mode 100644 Swiftfin tvOS/Components/FullScreenMenu.swift delete mode 100644 Swiftfin tvOS/Views/SelectServerView.swift diff --git a/Shared/Coordinators/SelectUserCoordinator.swift b/Shared/Coordinators/SelectUserCoordinator.swift index c2fecfbe1..d12d11983 100644 --- a/Shared/Coordinators/SelectUserCoordinator.swift +++ b/Shared/Coordinators/SelectUserCoordinator.swift @@ -12,11 +12,6 @@ import SwiftUI final class SelectUserCoordinator: NavigationCoordinatable { - struct SelectServerParameters { - let selection: Binding - let viewModel: SelectUserViewModel - } - let stack = NavigationStack(initial: \SelectUserCoordinator.start) @Root @@ -31,11 +26,6 @@ final class SelectUserCoordinator: NavigationCoordinatable { @Route(.modal) var userSignIn = makeUserSignIn - #if os(tvOS) - @Route(.fullScreen) - var selectServer = makeSelectServer - #endif - func makeAdvancedSettings() -> NavigationViewCoordinator { NavigationViewCoordinator(AppSettingsCoordinator()) } @@ -62,15 +52,6 @@ final class SelectUserCoordinator: NavigationCoordinatable { NavigationViewCoordinator(UserSignInCoordinator(server: server)) } - #if os(tvOS) - func makeSelectServer(parameters: SelectServerParameters) -> some View { - SelectServerView( - selection: parameters.selection, - viewModel: parameters.viewModel - ) - } - #endif - @ViewBuilder func makeStart() -> some View { SelectUserView() diff --git a/Swiftfin tvOS/Components/FullScreenMenu.swift b/Swiftfin tvOS/Components/FullScreenMenu.swift deleted file mode 100644 index d035fc5f8..000000000 --- a/Swiftfin tvOS/Components/FullScreenMenu.swift +++ /dev/null @@ -1,51 +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 SwiftUI - -struct FullScreenMenu: View { - - private let content: () -> Content - private let title: String - - init(_ title: String, @ViewBuilder content: @escaping () -> Content) { - self.title = title - self.content = content - } - - var body: some View { - ZStack { - Color.black - .opacity(0.5) - - HStack { - Spacer() - - VStack { - Text(title) - .font(.title2) - .fontWeight(.bold) - - ScrollView { - VStack { - content() - } - .padding(.horizontal, 20) - } - .frame(width: 580) - } - .padding(.top, 20) - .background(Material.regular, in: RoundedRectangle(cornerRadius: 30)) - .frame(width: 620) - .padding(100) - .shadow(radius: 50) - } - } - .ignoresSafeArea() - } -} diff --git a/Swiftfin tvOS/Views/SelectServerView.swift b/Swiftfin tvOS/Views/SelectServerView.swift deleted file mode 100644 index d2283656c..000000000 --- a/Swiftfin tvOS/Views/SelectServerView.swift +++ /dev/null @@ -1,127 +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 CollectionVGrid -import SwiftUI - -struct SelectServerView: View { - - @EnvironmentObject - private var router: SelectUserCoordinator.Router - - @Binding - private var serverSelection: SelectUserServerSelection - - @ObservedObject - private var viewModel: SelectUserViewModel - - private var selectedServer: ServerState? { - if case let SelectUserServerSelection.server(id: id) = serverSelection, - let server = viewModel.servers.keys.first(where: { server in server.id == id }) - { - return server - } - - return nil - } - - init( - selection: Binding, - viewModel: SelectUserViewModel - ) { - self._serverSelection = selection - self.viewModel = viewModel - } - - var body: some View { - FullScreenMenu(L10n.servers) { - Section { - Button { - router.popLast { - router.route(to: \.connectToServer) - } - } label: { - HStack { - L10n.addServer.text - - Spacer() - - Image(systemName: "plus") - } - } - - if let selectedServer { - Button { - router.popLast { - router.route(to: \.editServer, selectedServer) - } - } label: { - HStack { - L10n.editServer.text - - Spacer() - - Image(systemName: "server.rack") - } - } - } - } - - Section { - - if viewModel.servers.keys.count > 1 { - Button { - serverSelection = .all - router.popLast() - } label: { - HStack { - L10n.allServers.text - - Spacer() - - if serverSelection == .all { - Image(systemName: "checkmark.circle.fill") - } - } - } - } - - ForEach(viewModel.servers.keys.reversed()) { server in - Button { - serverSelection = .server(id: server.id) - router.popLast() - } label: { - HStack { - VStack(alignment: .leading) { - Text(server.name) - .font(.headline) - .fontWeight(.semibold) - - Text(server.currentURL.absoluteString) - .font(.subheadline) - .foregroundColor(.primary) - } - - Spacer() - - if selectedServer == server { - Image(systemName: "checkmark.circle.fill") - } - } - .padding() - } - .buttonStyle(.card) - .padding(.horizontal) - } - } header: { - Text(L10n.servers) - } - .headerProminence(.increased) - } - } -} diff --git a/Swiftfin tvOS/Views/SelectUserView/Components/ServerSelectionMenu.swift b/Swiftfin tvOS/Views/SelectUserView/Components/ServerSelectionMenu.swift index 03f86d16b..30c3b344a 100644 --- a/Swiftfin tvOS/Views/SelectUserView/Components/ServerSelectionMenu.swift +++ b/Swiftfin tvOS/Views/SelectUserView/Components/ServerSelectionMenu.swift @@ -12,17 +12,18 @@ extension SelectUserView { struct ServerSelectionMenu: View { + // MARK: - Observed & Environment Objects + @EnvironmentObject private var router: SelectUserCoordinator.Router - @Binding - private var serverSelection: SelectUserServerSelection - @ObservedObject private var viewModel: SelectUserViewModel - @State - private var isPresentingServers: Bool = false + // MARK: - Server Selection + + @Binding + private var serverSelection: SelectUserServerSelection private var selectedServer: ServerState? { if case let SelectUserServerSelection.server(id: id) = serverSelection, @@ -34,6 +35,8 @@ extension SelectUserView { return nil } + // MARK: - Initializer + init( selection: Binding, viewModel: SelectUserViewModel @@ -42,34 +45,57 @@ extension SelectUserView { self.viewModel = viewModel } - var body: some View { - Button { - let parameters = SelectUserCoordinator.SelectServerParameters( - selection: _serverSelection, - viewModel: viewModel - ) + // MARK: - Body - router.route(to: \.selectServer, parameters) + var body: some View { + Menu { + Picker(L10n.servers, selection: _serverSelection) { + ForEach(viewModel.servers.keys) { server in + Button { + Text(server.name) + Text(server.currentURL.absoluteString) + } + .tag(SelectUserServerSelection.server(id: server.id)) + } + if viewModel.servers.keys.count > 1 { + Label(L10n.allServers, systemImage: "person.2.fill") + .tag(SelectUserServerSelection.all) + } + } + Section { + if let selectedServer { + Button(L10n.editServer, systemImage: "server.rack") { + router.route(to: \.editServer, selectedServer) + } + } + Button(L10n.addServer, systemImage: "plus") { + router.route(to: \.connectToServer) + } + } } label: { - ZStack { - - Group { - switch serverSelection { - case .all: - Label(L10n.allServers, systemImage: "person.2.fill") - case let .server(id): - if let server = viewModel.servers.keys.first(where: { $0.id == id }) { - Label(server.name, systemImage: "server.rack") - } + HStack(spacing: 16) { + switch serverSelection { + case .all: + Image(systemName: "person.2.fill") + Text(L10n.allServers) + case let .server(id): + if let server = viewModel.servers.keys.first(where: { $0.id == id }) { + Image(systemName: "server.rack") + Text(server.name) } } - .font(.body.weight(.semibold)) - .foregroundStyle(Color.primary) + Image(systemName: "chevron.up.chevron.down") + .foregroundStyle(.secondary) + .font(.subheadline.weight(.semibold)) } + .font(.body.weight(.semibold)) + .foregroundStyle(Color.primary) .frame(height: 50) .frame(maxWidth: 400) .clipShape(RoundedRectangle(cornerRadius: 10)) } + .menuOrder(.fixed) + .padding() } } } diff --git a/Swiftfin.xcodeproj/project.pbxproj b/Swiftfin.xcodeproj/project.pbxproj index 6e1582066..074a8bc3d 100644 --- a/Swiftfin.xcodeproj/project.pbxproj +++ b/Swiftfin.xcodeproj/project.pbxproj @@ -881,7 +881,6 @@ E193D5432719407E00900D82 /* tvOSMainCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D5422719407E00900D82 /* tvOSMainCoordinator.swift */; }; E193D547271941C500900D82 /* SelectUserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D546271941C500900D82 /* SelectUserView.swift */; }; E193D549271941CC00900D82 /* UserSignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D548271941CC00900D82 /* UserSignInView.swift */; }; - E193D54B271941D300900D82 /* SelectServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D54A271941D300900D82 /* SelectServerView.swift */; }; E193D5502719430400900D82 /* ServerDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D54F2719430400900D82 /* ServerDetailView.swift */; }; E193D5512719432400900D82 /* ServerConnectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E173DA5326D050F500CC4EB7 /* ServerConnectionViewModel.swift */; }; E193D553271943D500900D82 /* tvOSMainTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D552271943D500900D82 /* tvOSMainTabCoordinator.swift */; }; @@ -1774,7 +1773,6 @@ E193D5422719407E00900D82 /* tvOSMainCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = tvOSMainCoordinator.swift; sourceTree = ""; }; E193D546271941C500900D82 /* SelectUserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectUserView.swift; sourceTree = ""; }; E193D548271941CC00900D82 /* UserSignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSignInView.swift; sourceTree = ""; }; - E193D54A271941D300900D82 /* SelectServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectServerView.swift; sourceTree = ""; }; E193D54F2719430400900D82 /* ServerDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailView.swift; sourceTree = ""; }; E193D552271943D500900D82 /* tvOSMainTabCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = tvOSMainTabCoordinator.swift; sourceTree = ""; }; E19D41A62BEEDC450082B8B2 /* UserLocalSecurityViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLocalSecurityViewModel.swift; sourceTree = ""; }; @@ -2980,7 +2978,6 @@ E1A42E4928CA6CCD00A14DCB /* CinematicItemSelector.swift */, E1C92618288756BD002A7A66 /* DotHStack.swift */, E12E30F4296392EC0022FAC9 /* EnumPickerView.swift */, - E1763A652BF3CA83004DF6AB /* FullScreenMenu.swift */, E1549677296CB22B00C4EF88 /* InlineEnumToggle.swift */, E1A42E5028CBE44500A14DCB /* LandscapePosterProgressBar.swift */, E1763A632BF3C9AA004DF6AB /* ListRowButton.swift */, @@ -3737,7 +3734,6 @@ E10B1E8C2BD7708900A92EAF /* QuickConnectView.swift */, E1E1643928BAC2EF00323B0A /* SearchView.swift */, 4EF18B232CB9932F00343666 /* PagingLibraryView */, - E193D54A271941D300900D82 /* SelectServerView.swift */, E164A8122BE4995200A54B18 /* SelectUserView */, E193D54F2719430400900D82 /* ServerDetailView.swift */, E1E5D54D2783E66600692DFE /* SettingsView */, @@ -5234,7 +5230,6 @@ 4ECF5D8B2D0A57EF00F066B1 /* DynamicDayOfWeek.swift in Sources */, 62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */, 5398514526B64DA100101B49 /* SettingsView.swift in Sources */, - E193D54B271941D300900D82 /* SelectServerView.swift in Sources */, E1575E91293E7B1E001665B1 /* URL.swift in Sources */, 53ABFDE6267974EF00886593 /* SettingsViewModel.swift in Sources */, E10B1EC22BD9AD6100A92EAF /* V1UserModel.swift in Sources */, @@ -5485,7 +5480,6 @@ E193D553271943D500900D82 /* tvOSMainTabCoordinator.swift in Sources */, 4E8B34EB2AB91B6E0018F305 /* ItemFilter.swift in Sources */, E174121029AE9D94003EF3B5 /* NavigationCoordinatable.swift in Sources */, - E1763A662BF3CA83004DF6AB /* FullScreenMenu.swift in Sources */, E14EDECD2B8FB709000F00A4 /* ItemYear.swift in Sources */, E154965F296CA2EF00C4EF88 /* DownloadTask.swift in Sources */, E154967E296CCB6C00C4EF88 /* BasicNavigationCoordinator.swift in Sources */,