[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 <ethanpippin2343@gmail.com>
This commit is contained in:
Joe Kribs 2024-12-19 15:38:27 -07:00 committed by GitHub
parent 97affd198e
commit d580e8dcfd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 51 additions and 228 deletions

View File

@ -12,11 +12,6 @@ import SwiftUI
final class SelectUserCoordinator: NavigationCoordinatable {
struct SelectServerParameters {
let selection: Binding<SelectUserServerSelection>
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<AppSettingsCoordinator> {
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()

View File

@ -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<Content: View>: 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()
}
}

View File

@ -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<SelectUserServerSelection>,
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)
}
}
}

View File

@ -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<SelectUserServerSelection>,
viewModel: SelectUserViewModel
@ -42,34 +45,57 @@ extension SelectUserView {
self.viewModel = viewModel
}
// MARK: - Body
var body: some View {
Menu {
Picker(L10n.servers, selection: _serverSelection) {
ForEach(viewModel.servers.keys) { server in
Button {
let parameters = SelectUserCoordinator.SelectServerParameters(
selection: _serverSelection,
viewModel: viewModel
)
router.route(to: \.selectServer, parameters)
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 {
HStack(spacing: 16) {
switch serverSelection {
case .all:
Label(L10n.allServers, systemImage: "person.2.fill")
Image(systemName: "person.2.fill")
Text(L10n.allServers)
case let .server(id):
if let server = viewModel.servers.keys.first(where: { $0.id == id }) {
Label(server.name, systemImage: "server.rack")
Image(systemName: "server.rack")
Text(server.name)
}
}
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()
}
}
}

View File

@ -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 = "<group>"; };
E193D546271941C500900D82 /* SelectUserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectUserView.swift; sourceTree = "<group>"; };
E193D548271941CC00900D82 /* UserSignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSignInView.swift; sourceTree = "<group>"; };
E193D54A271941D300900D82 /* SelectServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectServerView.swift; sourceTree = "<group>"; };
E193D54F2719430400900D82 /* ServerDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailView.swift; sourceTree = "<group>"; };
E193D552271943D500900D82 /* tvOSMainTabCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = tvOSMainTabCoordinator.swift; sourceTree = "<group>"; };
E19D41A62BEEDC450082B8B2 /* UserLocalSecurityViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLocalSecurityViewModel.swift; sourceTree = "<group>"; };
@ -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 */,