[tvOS] Update ConnectToServerView & UserSignInView (#1365)
* UserSignInView and ConnectToServerView Cleanup * Public User icon changes, move the Jellyfin 'NavigationBar' to a `View Modifier` for easier re-use. * A better solution * isLoading == isLoading NOT isLoading == true * clean up --------- Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
This commit is contained in:
parent
7685048258
commit
97affd198e
|
@ -46,8 +46,8 @@ internal enum L10n {
|
||||||
internal static let additionalSecurityAccessDescription = L10n.tr("Localizable", "additionalSecurityAccessDescription", fallback: "Additional security access for users signed in to this device. This does not change any Jellyfin server user settings.")
|
internal static let additionalSecurityAccessDescription = L10n.tr("Localizable", "additionalSecurityAccessDescription", fallback: "Additional security access for users signed in to this device. This does not change any Jellyfin server user settings.")
|
||||||
/// Add Server
|
/// Add Server
|
||||||
internal static let addServer = L10n.tr("Localizable", "addServer", fallback: "Add Server")
|
internal static let addServer = L10n.tr("Localizable", "addServer", fallback: "Add Server")
|
||||||
/// Add Trigger
|
/// Add trigger
|
||||||
internal static let addTrigger = L10n.tr("Localizable", "addTrigger", fallback: "Add Trigger")
|
internal static let addTrigger = L10n.tr("Localizable", "addTrigger", fallback: "Add trigger")
|
||||||
/// Add URL
|
/// Add URL
|
||||||
internal static let addURL = L10n.tr("Localizable", "addURL", fallback: "Add URL")
|
internal static let addURL = L10n.tr("Localizable", "addURL", fallback: "Add URL")
|
||||||
/// Add User
|
/// Add User
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
//
|
||||||
|
// 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 SwiftUI
|
||||||
|
|
||||||
|
struct SplitLoginWindowView<Leading: View, Trailing: View>: View {
|
||||||
|
|
||||||
|
// MARK: - Loading State
|
||||||
|
|
||||||
|
private let isLoading: Bool
|
||||||
|
|
||||||
|
// MARK: - Content Variables
|
||||||
|
|
||||||
|
private let leadingTitle: String
|
||||||
|
private let leadingContentView: () -> Leading
|
||||||
|
private let trailingTitle: String
|
||||||
|
private let trailingContentView: () -> Trailing
|
||||||
|
|
||||||
|
// MARK: - Body
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(alignment: .top) {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Section(leadingTitle) {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
leadingContentView()
|
||||||
|
.eraseToAnyView()
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
.padding(.vertical, 100)
|
||||||
|
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Section(trailingTitle) {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
trailingContentView()
|
||||||
|
.eraseToAnyView()
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationBarBranding(isLoading: isLoading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SplitLoginWindowView {
|
||||||
|
|
||||||
|
init(
|
||||||
|
isLoading: Bool = false,
|
||||||
|
leadingTitle: String,
|
||||||
|
trailingTitle: String,
|
||||||
|
@ViewBuilder leadingContentView: @escaping () -> Leading,
|
||||||
|
@ViewBuilder trailingContentView: @escaping () -> Trailing
|
||||||
|
) {
|
||||||
|
self.isLoading = isLoading
|
||||||
|
self.leadingTitle = leadingTitle
|
||||||
|
self.trailingTitle = trailingTitle
|
||||||
|
self.leadingContentView = leadingContentView
|
||||||
|
self.trailingContentView = trailingContentView
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// 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 Defaults
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct NavigationBarBrandingModifier: ViewModifier {
|
||||||
|
|
||||||
|
let isLoading: Bool
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
content
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .principal) {
|
||||||
|
Image(.jellyfinBlobBlue)
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(height: 100)
|
||||||
|
.padding(.bottom, 25)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLoading {
|
||||||
|
ToolbarItem(placement: .topBarTrailing) {
|
||||||
|
ProgressView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// 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 Defaults
|
||||||
|
import SwiftUI
|
||||||
|
import SwiftUIIntrospect
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func navigationBarBranding(
|
||||||
|
isLoading: Bool = false
|
||||||
|
) -> some View {
|
||||||
|
modifier(
|
||||||
|
NavigationBarBrandingModifier(
|
||||||
|
isLoading: isLoading
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// 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 Combine
|
||||||
|
import Defaults
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension ConnectToServerView {
|
||||||
|
|
||||||
|
struct LocalServerButton: View {
|
||||||
|
|
||||||
|
// MARK: - Environment Variables
|
||||||
|
|
||||||
|
@Environment(\.isEnabled)
|
||||||
|
private var isEnabled: Bool
|
||||||
|
|
||||||
|
// MARK: - Local Server Variables
|
||||||
|
|
||||||
|
private let server: ServerState
|
||||||
|
private let action: () -> Void
|
||||||
|
|
||||||
|
// MARK: - Initializer
|
||||||
|
|
||||||
|
init(server: ServerState, action: @escaping () -> Void) {
|
||||||
|
self.server = server
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Local Server Button
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: action) {
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text(server.name)
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
|
||||||
|
Text(server.currentURL.absoluteString)
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Image(systemName: "chevron.right")
|
||||||
|
.font(.body.weight(.regular))
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
.disabled(!isEnabled)
|
||||||
|
.buttonStyle(.card)
|
||||||
|
.foregroundStyle(.primary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,82 +55,56 @@ struct ConnectToServerView: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var connectSection: some View {
|
private var connectSection: some View {
|
||||||
Section(L10n.connectToServer) {
|
TextField(L10n.serverURL, text: $url)
|
||||||
TextField(L10n.serverURL, text: $url)
|
.disableAutocorrection(true)
|
||||||
.disableAutocorrection(true)
|
.textInputAutocapitalization(.never)
|
||||||
.textInputAutocapitalization(.never)
|
.keyboardType(.URL)
|
||||||
.keyboardType(.URL)
|
.focused($isURLFocused)
|
||||||
.focused($isURLFocused)
|
|
||||||
}
|
|
||||||
|
|
||||||
if viewModel.state == .connecting {
|
if viewModel.state == .connecting {
|
||||||
// ListRowButton(L10n.cancel) {
|
ListRowButton(L10n.cancel) {
|
||||||
// viewModel.send(.cancel)
|
|
||||||
// }
|
|
||||||
Button(L10n.cancel) {
|
|
||||||
viewModel.send(.cancel)
|
viewModel.send(.cancel)
|
||||||
}
|
}
|
||||||
.foregroundStyle(.red, .red.opacity(0.2))
|
.foregroundStyle(.red, accentColor)
|
||||||
|
.padding(.vertical)
|
||||||
} else {
|
} else {
|
||||||
// ListRowButton(L10n.connect) {
|
ListRowButton(L10n.connect) {
|
||||||
// isURLFocused = false
|
|
||||||
// viewModel.send(.connect(url))
|
|
||||||
// }
|
|
||||||
Button(L10n.connect) {
|
|
||||||
isURLFocused = false
|
isURLFocused = false
|
||||||
viewModel.send(.connect(url))
|
viewModel.send(.connect(url))
|
||||||
}
|
}
|
||||||
.disabled(url.isEmpty)
|
.disabled(url.isEmpty)
|
||||||
.foregroundStyle(
|
.foregroundStyle(
|
||||||
accentColor.overlayColor,
|
accentColor.overlayColor,
|
||||||
accentColor
|
url.isEmpty ? Color.white.opacity(0.5) : accentColor
|
||||||
)
|
)
|
||||||
.opacity(url.isEmpty ? 0.5 : 1)
|
.opacity(url.isEmpty ? 0.5 : 1)
|
||||||
|
.padding(.vertical)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Local Server Button
|
|
||||||
|
|
||||||
private func localServerButton(for server: ServerState) -> some View {
|
|
||||||
Button {
|
|
||||||
url = server.currentURL.absoluteString
|
|
||||||
viewModel.send(.connect(server.currentURL.absoluteString))
|
|
||||||
} label: {
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text(server.name)
|
|
||||||
.font(.headline)
|
|
||||||
.fontWeight(.semibold)
|
|
||||||
|
|
||||||
Text(server.currentURL.absoluteString)
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Image(systemName: "chevron.right")
|
|
||||||
.font(.body.weight(.regular))
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.disabled(viewModel.state == .connecting)
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Local Servers Section
|
// MARK: - Local Servers Section
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var localServersSection: some View {
|
private var localServersSection: some View {
|
||||||
Section(L10n.localServers) {
|
if viewModel.localServers.isEmpty {
|
||||||
if viewModel.localServers.isEmpty {
|
L10n.noLocalServersFound.text
|
||||||
L10n.noLocalServersFound.text
|
.font(.callout)
|
||||||
.font(.callout)
|
.foregroundColor(.secondary)
|
||||||
.foregroundColor(.secondary)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(maxWidth: .infinity)
|
} else {
|
||||||
} else {
|
LazyVGrid(
|
||||||
ForEach(viewModel.localServers) { server in
|
columns: Array(repeating: GridItem(.flexible()), count: 1),
|
||||||
localServerButton(for: server)
|
spacing: 30
|
||||||
|
) {
|
||||||
|
ForEach(viewModel.localServers, id: \.id) { server in
|
||||||
|
LocalServerButton(server: server) {
|
||||||
|
url = server.currentURL.absoluteString
|
||||||
|
viewModel.send(.connect(server.currentURL.absoluteString))
|
||||||
|
}
|
||||||
|
.environment(
|
||||||
|
\.isEnabled,
|
||||||
|
viewModel.state != .connecting && server.currentURL.absoluteString != url
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,34 +113,14 @@ struct ConnectToServerView: View {
|
||||||
// MARK: - Body
|
// MARK: - Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
SplitLoginWindowView(
|
||||||
HStack {
|
isLoading: viewModel.state == .connecting,
|
||||||
Spacer()
|
leadingTitle: L10n.connectToServer,
|
||||||
|
trailingTitle: L10n.localServers
|
||||||
if viewModel.state == .connecting {
|
) {
|
||||||
ProgressView()
|
connectSection
|
||||||
}
|
} trailingContentView: {
|
||||||
}
|
localServersSection
|
||||||
.frame(height: 100)
|
|
||||||
.overlay {
|
|
||||||
Image(.jellyfinBlobBlue)
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(height: 100)
|
|
||||||
.edgePadding()
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack(alignment: .top) {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
connectSection
|
|
||||||
}
|
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
localServersSection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.onFirstAppear {
|
.onFirstAppear {
|
||||||
isURLFocused = true
|
isURLFocused = true
|
|
@ -289,6 +289,7 @@ struct SelectUserView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
.navigationBarBranding()
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.send(.getServers)
|
viewModel.send(.getServers)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
//
|
||||||
|
// 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 JellyfinAPI
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension UserSignInView {
|
||||||
|
|
||||||
|
struct PublicUserButton: View {
|
||||||
|
|
||||||
|
// MARK: - Environment Variables
|
||||||
|
|
||||||
|
@Environment(\.isEnabled)
|
||||||
|
private var isEnabled: Bool
|
||||||
|
|
||||||
|
// MARK: - Public User Variables
|
||||||
|
|
||||||
|
private let user: UserDto
|
||||||
|
private let client: JellyfinClient
|
||||||
|
private let action: () -> Void
|
||||||
|
|
||||||
|
// MARK: - Initializer
|
||||||
|
|
||||||
|
init(
|
||||||
|
user: UserDto,
|
||||||
|
client: JellyfinClient,
|
||||||
|
action: @escaping () -> Void
|
||||||
|
) {
|
||||||
|
self.user = user
|
||||||
|
self.client = client
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Fallback Person View
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var fallbackPersonView: some View {
|
||||||
|
ZStack {
|
||||||
|
Color.secondarySystemFill
|
||||||
|
|
||||||
|
RelativeSystemImageView(systemName: "person.fill", ratio: 0.5)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
.clipShape(.circle)
|
||||||
|
.aspectRatio(1, contentMode: .fill)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Person View
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var personView: some View {
|
||||||
|
ZStack {
|
||||||
|
Color.clear
|
||||||
|
|
||||||
|
ImageView(user.profileImageSource(client: client, maxWidth: 120))
|
||||||
|
.image { image in
|
||||||
|
image
|
||||||
|
.posterBorder(ratio: 0.5, of: \.width)
|
||||||
|
}
|
||||||
|
.placeholder { _ in
|
||||||
|
fallbackPersonView
|
||||||
|
}
|
||||||
|
.failure {
|
||||||
|
fallbackPersonView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Body
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: action) {
|
||||||
|
personView
|
||||||
|
.aspectRatio(1, contentMode: .fill)
|
||||||
|
.posterShadow()
|
||||||
|
.clipShape(.circle)
|
||||||
|
.frame(width: 150, height: 150)
|
||||||
|
.hoverEffect(.highlight)
|
||||||
|
|
||||||
|
Text(user.name ?? .emptyDash)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundStyle(.primary)
|
||||||
|
.lineLimit(1)
|
||||||
|
.padding(.bottom)
|
||||||
|
}
|
||||||
|
.buttonBorderShape(.circle)
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.disabled(!isEnabled)
|
||||||
|
.foregroundStyle(.primary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,81 +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 JellyfinAPI
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
// TODO: change from list to grid button
|
|
||||||
|
|
||||||
extension UserSignInView {
|
|
||||||
|
|
||||||
struct PublicUserRow: View {
|
|
||||||
|
|
||||||
private let user: UserDto
|
|
||||||
private let client: JellyfinClient
|
|
||||||
private let action: () -> Void
|
|
||||||
|
|
||||||
init(
|
|
||||||
user: UserDto,
|
|
||||||
client: JellyfinClient,
|
|
||||||
action: @escaping () -> Void
|
|
||||||
) {
|
|
||||||
self.user = user
|
|
||||||
self.client = client
|
|
||||||
self.action = action
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var personView: some View {
|
|
||||||
ZStack {
|
|
||||||
Color.secondarySystemFill
|
|
||||||
|
|
||||||
RelativeSystemImageView(systemName: "person.fill", ratio: 0.5)
|
|
||||||
.foregroundStyle(.secondary)
|
|
||||||
}
|
|
||||||
.clipShape(.circle)
|
|
||||||
.aspectRatio(1, contentMode: .fill)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Button {
|
|
||||||
action()
|
|
||||||
} label: {
|
|
||||||
HStack {
|
|
||||||
ZStack {
|
|
||||||
Color.clear
|
|
||||||
|
|
||||||
ImageView(user.profileImageSource(client: client, maxWidth: 120))
|
|
||||||
.image { image in
|
|
||||||
image
|
|
||||||
.posterBorder(ratio: 0.5, of: \.width)
|
|
||||||
}
|
|
||||||
.placeholder { _ in
|
|
||||||
personView
|
|
||||||
}
|
|
||||||
.failure {
|
|
||||||
personView
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.aspectRatio(1, contentMode: .fill)
|
|
||||||
.posterShadow()
|
|
||||||
.clipShape(.circle)
|
|
||||||
.frame(width: 50, height: 50)
|
|
||||||
|
|
||||||
Text(user.name ?? .emptyDash)
|
|
||||||
.fontWeight(.semibold)
|
|
||||||
.foregroundStyle(.primary)
|
|
||||||
.lineLimit(1)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.buttonStyle(.card)
|
|
||||||
.foregroundStyle(.primary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,8 +13,6 @@ import JellyfinAPI
|
||||||
import Stinsen
|
import Stinsen
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
// TODO: change public users from list to grid
|
|
||||||
|
|
||||||
struct UserSignInView: View {
|
struct UserSignInView: View {
|
||||||
|
|
||||||
// MARK: - Defaults
|
// MARK: - Defaults
|
||||||
|
@ -30,13 +28,16 @@ struct UserSignInView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
@FocusState
|
@FocusState
|
||||||
private var focusedTextField: FocusField?
|
private var focusedField: FocusField?
|
||||||
|
|
||||||
// MARK: - State & Environment Objects
|
// MARK: - State & Environment Objects
|
||||||
|
|
||||||
@EnvironmentObject
|
@EnvironmentObject
|
||||||
private var router: UserSignInCoordinator.Router
|
private var router: UserSignInCoordinator.Router
|
||||||
|
|
||||||
|
@StateObject
|
||||||
|
private var focusGuide: FocusGuide = .init()
|
||||||
|
|
||||||
@StateObject
|
@StateObject
|
||||||
private var viewModel: UserSignInViewModel
|
private var viewModel: UserSignInViewModel
|
||||||
|
|
||||||
|
@ -69,39 +70,37 @@ struct UserSignInView: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var signInSection: some View {
|
private var signInSection: some View {
|
||||||
Section {
|
TextField(L10n.username, text: $username)
|
||||||
TextField(L10n.username, text: $username)
|
.autocorrectionDisabled()
|
||||||
.autocorrectionDisabled()
|
.textInputAutocapitalization(.never)
|
||||||
.textInputAutocapitalization(.never)
|
.focused($focusedField, equals: .username)
|
||||||
.focused($focusedTextField, equals: .username)
|
|
||||||
|
|
||||||
SecureField(L10n.password, text: $password)
|
SecureField(L10n.password, text: $password)
|
||||||
.focused($focusedTextField, equals: .password)
|
.focused($focusedField, equals: .password)
|
||||||
.onSubmit {
|
.onSubmit {
|
||||||
guard username.isNotEmpty else {
|
guard username.isNotEmpty else {
|
||||||
return
|
return
|
||||||
}
|
|
||||||
viewModel.send(.signIn(username: username, password: password, policy: .none))
|
|
||||||
}
|
}
|
||||||
} header: {
|
viewModel.send(.signIn(username: username, password: password, policy: .none))
|
||||||
Text(L10n.signInToServer(viewModel.server.name))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if case .signingIn = viewModel.state {
|
if case .signingIn = viewModel.state {
|
||||||
Button(L10n.cancel) {
|
ListRowButton(L10n.cancel) {
|
||||||
viewModel.send(.cancel)
|
viewModel.send(.cancel)
|
||||||
}
|
}
|
||||||
.foregroundStyle(.red, .red.opacity(0.2))
|
.foregroundStyle(.red, accentColor)
|
||||||
|
.padding(.vertical)
|
||||||
} else {
|
} else {
|
||||||
Button(L10n.signIn) {
|
ListRowButton(L10n.signIn) {
|
||||||
viewModel.send(.signIn(username: username, password: password, policy: .none))
|
viewModel.send(.signIn(username: username, password: password, policy: .none))
|
||||||
}
|
}
|
||||||
.disabled(username.isEmpty)
|
.disabled(username.isEmpty)
|
||||||
.foregroundStyle(
|
.foregroundStyle(
|
||||||
accentColor.overlayColor,
|
accentColor.overlayColor,
|
||||||
accentColor
|
username.isEmpty ? Color.white.opacity(0.5) : accentColor
|
||||||
)
|
)
|
||||||
.opacity(username.isEmpty ? 0.5 : 1)
|
.opacity(username.isEmpty ? 0.5 : 1)
|
||||||
|
.padding(.vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
if viewModel.isQuickConnectEnabled {
|
if viewModel.isQuickConnectEnabled {
|
||||||
|
@ -114,14 +113,17 @@ struct UserSignInView: View {
|
||||||
accentColor.overlayColor,
|
accentColor.overlayColor,
|
||||||
accentColor
|
accentColor
|
||||||
)
|
)
|
||||||
|
.padding(.bottom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let disclaimer = viewModel.serverDisclaimer {
|
if let disclaimer = viewModel.serverDisclaimer {
|
||||||
Section(L10n.disclaimer) {
|
Section(L10n.disclaimer) {
|
||||||
Text(disclaimer)
|
Text(disclaimer)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
}
|
}
|
||||||
|
.padding(.top)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,22 +131,30 @@ struct UserSignInView: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var publicUsersSection: some View {
|
private var publicUsersSection: some View {
|
||||||
Section(L10n.publicUsers) {
|
if viewModel.publicUsers.isEmpty {
|
||||||
if viewModel.publicUsers.isEmpty {
|
L10n.noPublicUsers.text
|
||||||
L10n.noPublicUsers.text
|
.font(.callout)
|
||||||
.font(.callout)
|
.foregroundColor(.secondary)
|
||||||
.foregroundColor(.secondary)
|
.frame(maxWidth: .infinity, alignment: .center)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxHeight: .infinity, alignment: .center)
|
||||||
} else {
|
} else {
|
||||||
|
LazyVGrid(
|
||||||
|
columns: Array(repeating: GridItem(.flexible()), count: 4),
|
||||||
|
spacing: 30
|
||||||
|
) {
|
||||||
ForEach(viewModel.publicUsers, id: \.id) { user in
|
ForEach(viewModel.publicUsers, id: \.id) { user in
|
||||||
PublicUserRow(
|
PublicUserButton(
|
||||||
user: user,
|
user: user,
|
||||||
client: viewModel.server.client
|
client: viewModel.server.client
|
||||||
) {
|
) {
|
||||||
username = user.name ?? ""
|
username = user.name ?? ""
|
||||||
password = ""
|
password = ""
|
||||||
focusedTextField = .password
|
focusedField = .password
|
||||||
}
|
}
|
||||||
|
.environment(
|
||||||
|
\.isEnabled,
|
||||||
|
viewModel.state != .signingIn
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,34 +163,14 @@ struct UserSignInView: View {
|
||||||
// MARK: - Body
|
// MARK: - Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
SplitLoginWindowView(
|
||||||
HStack {
|
isLoading: viewModel.state == .signingIn,
|
||||||
Spacer()
|
leadingTitle: L10n.signInToServer(viewModel.server.name),
|
||||||
|
trailingTitle: L10n.publicUsers
|
||||||
if viewModel.state == .signingIn {
|
) {
|
||||||
ProgressView()
|
signInSection
|
||||||
}
|
} trailingContentView: {
|
||||||
}
|
publicUsersSection
|
||||||
.frame(height: 100)
|
|
||||||
.overlay {
|
|
||||||
Image(.jellyfinBlobBlue)
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(height: 100)
|
|
||||||
.edgePadding()
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack(alignment: .top) {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
signInSection
|
|
||||||
}
|
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
publicUsersSection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.onReceive(viewModel.events) { event in
|
.onReceive(viewModel.events) { event in
|
||||||
switch event {
|
switch event {
|
||||||
|
@ -198,7 +188,7 @@ struct UserSignInView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onFirstAppear {
|
.onFirstAppear {
|
||||||
focusedTextField = .username
|
focusedField = .username
|
||||||
viewModel.send(.getPublicData)
|
viewModel.send(.getPublicData)
|
||||||
}
|
}
|
||||||
.alert(
|
.alert(
|
||||||
|
@ -209,11 +199,11 @@ struct UserSignInView: View {
|
||||||
|
|
||||||
// TODO: uncomment when duplicate user fixed
|
// TODO: uncomment when duplicate user fixed
|
||||||
// Button(L10n.signIn) {
|
// Button(L10n.signIn) {
|
||||||
// signInUplicate(user: user, replace: false)
|
// signInDuplicate(user: user, replace: false)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Button("Replace") {
|
// Button("Replace") {
|
||||||
// signInUplicate(user: user, replace: true)
|
// signInDuplicate(user: user, replace: true)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
Button(L10n.dismiss, role: .cancel)
|
Button(L10n.dismiss, role: .cancel)
|
||||||
|
|
|
@ -84,6 +84,8 @@
|
||||||
4E49DEE42CE55FB900352DCD /* SyncPlayUserAccessType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E49DEE22CE55FB500352DCD /* SyncPlayUserAccessType.swift */; };
|
4E49DEE42CE55FB900352DCD /* SyncPlayUserAccessType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E49DEE22CE55FB500352DCD /* SyncPlayUserAccessType.swift */; };
|
||||||
4E49DEE62CE5616800352DCD /* UserProfileImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E49DEE52CE5616800352DCD /* UserProfileImagePicker.swift */; };
|
4E49DEE62CE5616800352DCD /* UserProfileImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E49DEE52CE5616800352DCD /* UserProfileImagePicker.swift */; };
|
||||||
4E4A53222CBE0A1C003BD24D /* ChevronAlertButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB7B33A2CBDE63F004A342E /* ChevronAlertButton.swift */; };
|
4E4A53222CBE0A1C003BD24D /* ChevronAlertButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB7B33A2CBDE63F004A342E /* ChevronAlertButton.swift */; };
|
||||||
|
4E4DAC372D11EE5E00E13FF9 /* SplitLoginWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4DAC362D11EE4F00E13FF9 /* SplitLoginWindowView.swift */; };
|
||||||
|
4E4DAC3D2D11F94400E13FF9 /* LocalServerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4DAC3C2D11F94000E13FF9 /* LocalServerButton.swift */; };
|
||||||
4E4E9C672CFEBF2A00A6946F /* StudioEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4E9C662CFEBF2500A6946F /* StudioEditorViewModel.swift */; };
|
4E4E9C672CFEBF2A00A6946F /* StudioEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4E9C662CFEBF2500A6946F /* StudioEditorViewModel.swift */; };
|
||||||
4E4E9C682CFEBF2A00A6946F /* StudioEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4E9C662CFEBF2500A6946F /* StudioEditorViewModel.swift */; };
|
4E4E9C682CFEBF2A00A6946F /* StudioEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4E9C662CFEBF2500A6946F /* StudioEditorViewModel.swift */; };
|
||||||
4E4E9C6A2CFEDCA400A6946F /* PeopleEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4E9C692CFEDC9D00A6946F /* PeopleEditorViewModel.swift */; };
|
4E4E9C6A2CFEDCA400A6946F /* PeopleEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4E9C692CFEDC9D00A6946F /* PeopleEditorViewModel.swift */; };
|
||||||
|
@ -158,6 +160,8 @@
|
||||||
4E90F76A2CC72B1F00417C31 /* DetailsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E90F7592CC72B1F00417C31 /* DetailsSection.swift */; };
|
4E90F76A2CC72B1F00417C31 /* DetailsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E90F7592CC72B1F00417C31 /* DetailsSection.swift */; };
|
||||||
4E97D1832D064748004B89AD /* ItemSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E97D1822D064748004B89AD /* ItemSection.swift */; };
|
4E97D1832D064748004B89AD /* ItemSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E97D1822D064748004B89AD /* ItemSection.swift */; };
|
||||||
4E97D1852D064B43004B89AD /* RefreshMetadataButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E97D1842D064B43004B89AD /* RefreshMetadataButton.swift */; };
|
4E97D1852D064B43004B89AD /* RefreshMetadataButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E97D1842D064B43004B89AD /* RefreshMetadataButton.swift */; };
|
||||||
|
4E98F7D22D123AD4001E7518 /* NavigationBarMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E98F7C12D123AD4001E7518 /* NavigationBarMenuButton.swift */; };
|
||||||
|
4E98F7D32D123AD4001E7518 /* View-tvOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E98F7C92D123AD4001E7518 /* View-tvOS.swift */; };
|
||||||
4E9A24E62C82B5A50023DA83 /* CustomDeviceProfileSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9A24E52C82B5A50023DA83 /* CustomDeviceProfileSettingsView.swift */; };
|
4E9A24E62C82B5A50023DA83 /* CustomDeviceProfileSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9A24E52C82B5A50023DA83 /* CustomDeviceProfileSettingsView.swift */; };
|
||||||
4E9A24E82C82B6190023DA83 /* CustomProfileButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9A24E72C82B6190023DA83 /* CustomProfileButton.swift */; };
|
4E9A24E82C82B6190023DA83 /* CustomProfileButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9A24E72C82B6190023DA83 /* CustomProfileButton.swift */; };
|
||||||
4E9A24E92C82B79D0023DA83 /* EditCustomDeviceProfileCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC1C8572C80332500E2879E /* EditCustomDeviceProfileCoordinator.swift */; };
|
4E9A24E92C82B79D0023DA83 /* EditCustomDeviceProfileCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC1C8572C80332500E2879E /* EditCustomDeviceProfileCoordinator.swift */; };
|
||||||
|
@ -759,7 +763,7 @@
|
||||||
E1763A2B2BF3046E004DF6AB /* UserGridButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A2A2BF3046E004DF6AB /* UserGridButton.swift */; };
|
E1763A2B2BF3046E004DF6AB /* UserGridButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A2A2BF3046E004DF6AB /* UserGridButton.swift */; };
|
||||||
E1763A642BF3C9AA004DF6AB /* ListRowButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A632BF3C9AA004DF6AB /* ListRowButton.swift */; };
|
E1763A642BF3C9AA004DF6AB /* ListRowButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A632BF3C9AA004DF6AB /* ListRowButton.swift */; };
|
||||||
E1763A662BF3CA83004DF6AB /* FullScreenMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A652BF3CA83004DF6AB /* FullScreenMenu.swift */; };
|
E1763A662BF3CA83004DF6AB /* FullScreenMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A652BF3CA83004DF6AB /* FullScreenMenu.swift */; };
|
||||||
E1763A6A2BF3D177004DF6AB /* PublicUserRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A692BF3D177004DF6AB /* PublicUserRow.swift */; };
|
E1763A6A2BF3D177004DF6AB /* PublicUserButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A692BF3D177004DF6AB /* PublicUserButton.swift */; };
|
||||||
E1763A712BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A702BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift */; };
|
E1763A712BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A702BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift */; };
|
||||||
E1763A722BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A702BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift */; };
|
E1763A722BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A702BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift */; };
|
||||||
E1763A742BF3FA4C004DF6AB /* AppLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A732BF3FA4C004DF6AB /* AppLoadingView.swift */; };
|
E1763A742BF3FA4C004DF6AB /* AppLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A732BF3FA4C004DF6AB /* AppLoadingView.swift */; };
|
||||||
|
@ -1227,6 +1231,8 @@
|
||||||
4E49DEDD2CE55F7F00352DCD /* SquareImageCropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SquareImageCropView.swift; sourceTree = "<group>"; };
|
4E49DEDD2CE55F7F00352DCD /* SquareImageCropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SquareImageCropView.swift; sourceTree = "<group>"; };
|
||||||
4E49DEE22CE55FB500352DCD /* SyncPlayUserAccessType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPlayUserAccessType.swift; sourceTree = "<group>"; };
|
4E49DEE22CE55FB500352DCD /* SyncPlayUserAccessType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPlayUserAccessType.swift; sourceTree = "<group>"; };
|
||||||
4E49DEE52CE5616800352DCD /* UserProfileImagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileImagePicker.swift; sourceTree = "<group>"; };
|
4E49DEE52CE5616800352DCD /* UserProfileImagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileImagePicker.swift; sourceTree = "<group>"; };
|
||||||
|
4E4DAC362D11EE4F00E13FF9 /* SplitLoginWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitLoginWindowView.swift; sourceTree = "<group>"; };
|
||||||
|
4E4DAC3C2D11F94000E13FF9 /* LocalServerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalServerButton.swift; sourceTree = "<group>"; };
|
||||||
4E4E9C662CFEBF2500A6946F /* StudioEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudioEditorViewModel.swift; sourceTree = "<group>"; };
|
4E4E9C662CFEBF2500A6946F /* StudioEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudioEditorViewModel.swift; sourceTree = "<group>"; };
|
||||||
4E4E9C692CFEDC9D00A6946F /* PeopleEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeopleEditorViewModel.swift; sourceTree = "<group>"; };
|
4E4E9C692CFEDC9D00A6946F /* PeopleEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeopleEditorViewModel.swift; sourceTree = "<group>"; };
|
||||||
4E5071D62CFCEB6F003FA2AD /* TagEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagEditorViewModel.swift; sourceTree = "<group>"; };
|
4E5071D62CFCEB6F003FA2AD /* TagEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagEditorViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1283,6 +1289,8 @@
|
||||||
4E90F7612CC72B1F00417C31 /* EditServerTaskView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditServerTaskView.swift; sourceTree = "<group>"; };
|
4E90F7612CC72B1F00417C31 /* EditServerTaskView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditServerTaskView.swift; sourceTree = "<group>"; };
|
||||||
4E97D1822D064748004B89AD /* ItemSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemSection.swift; sourceTree = "<group>"; };
|
4E97D1822D064748004B89AD /* ItemSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemSection.swift; sourceTree = "<group>"; };
|
||||||
4E97D1842D064B43004B89AD /* RefreshMetadataButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshMetadataButton.swift; sourceTree = "<group>"; };
|
4E97D1842D064B43004B89AD /* RefreshMetadataButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshMetadataButton.swift; sourceTree = "<group>"; };
|
||||||
|
4E98F7C12D123AD4001E7518 /* NavigationBarMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarMenuButton.swift; sourceTree = "<group>"; };
|
||||||
|
4E98F7C92D123AD4001E7518 /* View-tvOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View-tvOS.swift"; sourceTree = "<group>"; };
|
||||||
4E9A24E52C82B5A50023DA83 /* CustomDeviceProfileSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDeviceProfileSettingsView.swift; sourceTree = "<group>"; };
|
4E9A24E52C82B5A50023DA83 /* CustomDeviceProfileSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDeviceProfileSettingsView.swift; sourceTree = "<group>"; };
|
||||||
4E9A24E72C82B6190023DA83 /* CustomProfileButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomProfileButton.swift; sourceTree = "<group>"; };
|
4E9A24E72C82B6190023DA83 /* CustomProfileButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomProfileButton.swift; sourceTree = "<group>"; };
|
||||||
4E9A24EA2C82B9ED0023DA83 /* CustomDeviceProfileCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDeviceProfileCoordinator.swift; sourceTree = "<group>"; };
|
4E9A24EA2C82B9ED0023DA83 /* CustomDeviceProfileCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDeviceProfileCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1689,7 +1697,7 @@
|
||||||
E1763A2A2BF3046E004DF6AB /* UserGridButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGridButton.swift; sourceTree = "<group>"; };
|
E1763A2A2BF3046E004DF6AB /* UserGridButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGridButton.swift; sourceTree = "<group>"; };
|
||||||
E1763A632BF3C9AA004DF6AB /* ListRowButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRowButton.swift; sourceTree = "<group>"; };
|
E1763A632BF3C9AA004DF6AB /* ListRowButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRowButton.swift; sourceTree = "<group>"; };
|
||||||
E1763A652BF3CA83004DF6AB /* FullScreenMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenMenu.swift; sourceTree = "<group>"; };
|
E1763A652BF3CA83004DF6AB /* FullScreenMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenMenu.swift; sourceTree = "<group>"; };
|
||||||
E1763A692BF3D177004DF6AB /* PublicUserRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicUserRow.swift; sourceTree = "<group>"; };
|
E1763A692BF3D177004DF6AB /* PublicUserButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicUserButton.swift; sourceTree = "<group>"; };
|
||||||
E1763A702BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftfinStore+Mappings.swift"; sourceTree = "<group>"; };
|
E1763A702BF3F67C004DF6AB /* SwiftfinStore+Mappings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftfinStore+Mappings.swift"; sourceTree = "<group>"; };
|
||||||
E1763A732BF3FA4C004DF6AB /* AppLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLoadingView.swift; sourceTree = "<group>"; };
|
E1763A732BF3FA4C004DF6AB /* AppLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLoadingView.swift; sourceTree = "<group>"; };
|
||||||
E1763A752BF3FF01004DF6AB /* AppLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLoadingView.swift; sourceTree = "<group>"; };
|
E1763A752BF3FF01004DF6AB /* AppLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLoadingView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -2260,6 +2268,23 @@
|
||||||
path = UserProfileImagePicker;
|
path = UserProfileImagePicker;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4E4DAC3A2D11F54300E13FF9 /* ConnectToServerView */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4E4DAC3B2D11F69000E13FF9 /* Components */,
|
||||||
|
53ABFDEA2679753200886593 /* ConnectToServerView.swift */,
|
||||||
|
);
|
||||||
|
path = ConnectToServerView;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
4E4DAC3B2D11F69000E13FF9 /* Components */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4E4DAC3C2D11F94000E13FF9 /* LocalServerButton.swift */,
|
||||||
|
);
|
||||||
|
path = Components;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
4E5071D52CFCEB03003FA2AD /* ItemEditorViewModel */ = {
|
4E5071D52CFCEB03003FA2AD /* ItemEditorViewModel */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -2499,6 +2524,31 @@
|
||||||
path = EditServerTaskView;
|
path = EditServerTaskView;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4E98F7C82D123AD4001E7518 /* Modifiers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4E98F7C12D123AD4001E7518 /* NavigationBarMenuButton.swift */,
|
||||||
|
);
|
||||||
|
path = Modifiers;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
4E98F7CA2D123AD4001E7518 /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4E98F7C82D123AD4001E7518 /* Modifiers */,
|
||||||
|
4E98F7C92D123AD4001E7518 /* View-tvOS.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
4E98F7CB2D123AD4001E7518 /* Extensions */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4E98F7CA2D123AD4001E7518 /* View */,
|
||||||
|
);
|
||||||
|
path = Extensions;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
4E9A24E32C82B4700023DA83 /* CustomDeviceProfileSettingsView */ = {
|
4E9A24E32C82B4700023DA83 /* CustomDeviceProfileSettingsView */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -2839,6 +2889,7 @@
|
||||||
children = (
|
children = (
|
||||||
E12186DF2718F2030010884C /* App */,
|
E12186DF2718F2030010884C /* App */,
|
||||||
536D3D77267BB9650004248C /* Components */,
|
536D3D77267BB9650004248C /* Components */,
|
||||||
|
4E98F7CB2D123AD4001E7518 /* Extensions */,
|
||||||
E185920B28CEF23F00326F80 /* Objects */,
|
E185920B28CEF23F00326F80 /* Objects */,
|
||||||
E1DABAD62A26E28E008AC34A /* Resources */,
|
E1DABAD62A26E28E008AC34A /* Resources */,
|
||||||
E12186E02718F23B0010884C /* Views */,
|
E12186E02718F23B0010884C /* Views */,
|
||||||
|
@ -2941,6 +2992,7 @@
|
||||||
E1E9EFE928C6B96400CC1F8B /* ServerButton.swift */,
|
E1E9EFE928C6B96400CC1F8B /* ServerButton.swift */,
|
||||||
E17885A3278105170094FBCF /* SFSymbolButton.swift */,
|
E17885A3278105170094FBCF /* SFSymbolButton.swift */,
|
||||||
E12E30F0296383810022FAC9 /* SplitFormWindowView.swift */,
|
E12E30F0296383810022FAC9 /* SplitFormWindowView.swift */,
|
||||||
|
4E4DAC362D11EE4F00E13FF9 /* SplitLoginWindowView.swift */,
|
||||||
E187A60429AD2E25008387E6 /* StepperView.swift */,
|
E187A60429AD2E25008387E6 /* StepperView.swift */,
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Components;
|
||||||
|
@ -3673,7 +3725,7 @@
|
||||||
E1763A752BF3FF01004DF6AB /* AppLoadingView.swift */,
|
E1763A752BF3FF01004DF6AB /* AppLoadingView.swift */,
|
||||||
E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */,
|
E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */,
|
||||||
E10231522BCF8AF8009D71FC /* ChannelLibraryView */,
|
E10231522BCF8AF8009D71FC /* ChannelLibraryView */,
|
||||||
53ABFDEA2679753200886593 /* ConnectToServerView.swift */,
|
4E4DAC3A2D11F54300E13FF9 /* ConnectToServerView */,
|
||||||
E154967B296CBB1A00C4EF88 /* FontPickerView.swift */,
|
E154967B296CBB1A00C4EF88 /* FontPickerView.swift */,
|
||||||
E1A42E4D28CBD3B200A14DCB /* HomeView */,
|
E1A42E4D28CBD3B200A14DCB /* HomeView */,
|
||||||
E12376B22A33DFAC001F5B44 /* ItemOverviewView.swift */,
|
E12376B22A33DFAC001F5B44 /* ItemOverviewView.swift */,
|
||||||
|
@ -4001,7 +4053,7 @@
|
||||||
E1763A682BF3D16E004DF6AB /* Components */ = {
|
E1763A682BF3D16E004DF6AB /* Components */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E1763A692BF3D177004DF6AB /* PublicUserRow.swift */,
|
E1763A692BF3D177004DF6AB /* PublicUserButton.swift */,
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Components;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -5043,6 +5095,8 @@
|
||||||
E1575E99293E7B1E001665B1 /* UIColor.swift in Sources */,
|
E1575E99293E7B1E001665B1 /* UIColor.swift in Sources */,
|
||||||
E1575E92293E7B1E001665B1 /* CGSize.swift in Sources */,
|
E1575E92293E7B1E001665B1 /* CGSize.swift in Sources */,
|
||||||
E1575E7E293E77B5001665B1 /* ItemFilterCollection.swift in Sources */,
|
E1575E7E293E77B5001665B1 /* ItemFilterCollection.swift in Sources */,
|
||||||
|
4E98F7D22D123AD4001E7518 /* NavigationBarMenuButton.swift in Sources */,
|
||||||
|
4E98F7D32D123AD4001E7518 /* View-tvOS.swift in Sources */,
|
||||||
C46DD8EF2A8FB56E0046A504 /* LiveBottomBarView.swift in Sources */,
|
C46DD8EF2A8FB56E0046A504 /* LiveBottomBarView.swift in Sources */,
|
||||||
C46DD8EA2A8FB45C0046A504 /* LiveOverlay.swift in Sources */,
|
C46DD8EA2A8FB45C0046A504 /* LiveOverlay.swift in Sources */,
|
||||||
E11E376D293E9CC1009EF240 /* VideoPlayerCoordinator.swift in Sources */,
|
E11E376D293E9CC1009EF240 /* VideoPlayerCoordinator.swift in Sources */,
|
||||||
|
@ -5056,6 +5110,7 @@
|
||||||
4EF18B2A2CB993BD00343666 /* ListRow.swift in Sources */,
|
4EF18B2A2CB993BD00343666 /* ListRow.swift in Sources */,
|
||||||
4EF659E32CDD270D00E0BE5D /* ActionMenu.swift in Sources */,
|
4EF659E32CDD270D00E0BE5D /* ActionMenu.swift in Sources */,
|
||||||
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */,
|
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */,
|
||||||
|
4E4DAC372D11EE5E00E13FF9 /* SplitLoginWindowView.swift in Sources */,
|
||||||
4E97D1832D064748004B89AD /* ItemSection.swift in Sources */,
|
4E97D1832D064748004B89AD /* ItemSection.swift in Sources */,
|
||||||
E145EB232BDCCA43003BF6F3 /* BulletedList.swift in Sources */,
|
E145EB232BDCCA43003BF6F3 /* BulletedList.swift in Sources */,
|
||||||
E104DC972B9E7E29008F506D /* AssertionFailureView.swift in Sources */,
|
E104DC972B9E7E29008F506D /* AssertionFailureView.swift in Sources */,
|
||||||
|
@ -5263,6 +5318,7 @@
|
||||||
E1B4E4372CA7795200DC49DE /* OrderedDictionary.swift in Sources */,
|
E1B4E4372CA7795200DC49DE /* OrderedDictionary.swift in Sources */,
|
||||||
E1AD104E26D96CE3003E4A08 /* BaseItemDto.swift in Sources */,
|
E1AD104E26D96CE3003E4A08 /* BaseItemDto.swift in Sources */,
|
||||||
E118959E289312020042947B /* BaseItemPerson+Poster.swift in Sources */,
|
E118959E289312020042947B /* BaseItemPerson+Poster.swift in Sources */,
|
||||||
|
4E4DAC3D2D11F94400E13FF9 /* LocalServerButton.swift in Sources */,
|
||||||
62E632DD267D2E130063E547 /* SearchViewModel.swift in Sources */,
|
62E632DD267D2E130063E547 /* SearchViewModel.swift in Sources */,
|
||||||
BD0BA22C2AD6503B00306A8D /* OnlineVideoPlayerManager.swift in Sources */,
|
BD0BA22C2AD6503B00306A8D /* OnlineVideoPlayerManager.swift in Sources */,
|
||||||
E1575EA2293E7B1E001665B1 /* Color.swift in Sources */,
|
E1575EA2293E7B1E001665B1 /* Color.swift in Sources */,
|
||||||
|
@ -5313,7 +5369,7 @@
|
||||||
E1575E7D293E77B5001665B1 /* PosterDisplayType.swift in Sources */,
|
E1575E7D293E77B5001665B1 /* PosterDisplayType.swift in Sources */,
|
||||||
E1E5D553278419D900692DFE /* ConfirmCloseOverlay.swift in Sources */,
|
E1E5D553278419D900692DFE /* ConfirmCloseOverlay.swift in Sources */,
|
||||||
E18A17F2298C68BB00C22F62 /* MainOverlay.swift in Sources */,
|
E18A17F2298C68BB00C22F62 /* MainOverlay.swift in Sources */,
|
||||||
E1763A6A2BF3D177004DF6AB /* PublicUserRow.swift in Sources */,
|
E1763A6A2BF3D177004DF6AB /* PublicUserButton.swift in Sources */,
|
||||||
E1E6C44B29AED2B70064123F /* HorizontalAlignment.swift in Sources */,
|
E1E6C44B29AED2B70064123F /* HorizontalAlignment.swift in Sources */,
|
||||||
4E35CE672CBED8B600DBD886 /* ServerTicks.swift in Sources */,
|
4E35CE672CBED8B600DBD886 /* ServerTicks.swift in Sources */,
|
||||||
E193D549271941CC00900D82 /* UserSignInView.swift in Sources */,
|
E193D549271941CC00900D82 /* UserSignInView.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue