jellyflood/Swiftfin/Views/AdminDashboardView/ServerUsers/AddServerUserView/AddServerUserView.swift
Ashik K 09a3ce15a0 Rename project from jellypig to jellyflood
Complete rebranding from jellypig to jellyflood including:
- Renamed all jellypig references to jellyflood
- Updated store implementations (jellypigstore -> jellyfloodstore)
- Moved jellypig tvOS to Swiftfin tvOS structure
- Updated service configurations and defaults
- Preserved all Xtream plugin support and EPG functionality

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 09:14:33 +02:00

133 lines
4.0 KiB
Swift

//
// 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) 2025 Jellyfin & Jellyfin Contributors
//
import SwiftUI
struct AddServerUserView: View {
private enum Field {
case username
case password
case confirmPassword
}
@FocusState
private var focusedfield: Field?
@Router
private var router
@State
private var confirmPassword: String = ""
@State
private var password: String = ""
@State
private var username: String = ""
@StateObject
private var viewModel = AddServerUserViewModel()
private var isValid: Bool {
username.isNotEmpty && password == confirmPassword
}
// MARK: - Body
var body: some View {
List {
Section {
TextField(L10n.username, text: $username) {
focusedfield = .password
}
.autocorrectionDisabled()
.textInputAutocapitalization(.none)
.focused($focusedfield, equals: .username)
.disabled(viewModel.state == .addingUser)
} header: {
Text(L10n.username)
} footer: {
if username.isEmpty {
Label(L10n.usernameRequired, systemImage: "exclamationmark.circle.fill")
.labelStyle(.sectionFooterWithImage(imageStyle: .orange))
}
}
Section(L10n.password) {
SecureField(
L10n.password,
text: $password,
maskToggle: .enabled
)
.onSubmit {
focusedfield = .confirmPassword
}
.autocorrectionDisabled()
.textInputAutocapitalization(.none)
.focused($focusedfield, equals: .password)
.disabled(viewModel.state == .addingUser)
}
Section {
SecureField(
L10n.confirmPassword,
text: $confirmPassword,
maskToggle: .enabled
)
.autocorrectionDisabled()
.textInputAutocapitalization(.none)
.focused($focusedfield, equals: .confirmPassword)
.disabled(viewModel.state == .addingUser)
} header: {
Text(L10n.confirmPassword)
} footer: {
if password != confirmPassword {
Label(L10n.passwordsDoNotMatch, systemImage: "exclamationmark.circle.fill")
.labelStyle(.sectionFooterWithImage(imageStyle: .orange))
}
}
}
.animation(.linear(duration: 0.1), value: isValid)
.interactiveDismissDisabled(viewModel.state == .addingUser)
.navigationTitle(L10n.newUser)
.navigationBarTitleDisplayMode(.inline)
.navigationBarCloseButton(disabled: viewModel.state != .initial) {
router.dismiss()
}
.onFirstAppear {
focusedfield = .username
}
.onReceive(viewModel.events) { event in
switch event {
case let .created(newUser):
UIDevice.feedback(.success)
Notifications[.didAddServerUser].post(newUser)
router.dismiss()
}
}
.topBarTrailing {
if viewModel.state == .addingUser {
ProgressView()
Button(L10n.cancel) {
viewModel.cancel()
}
.buttonStyle(.toolbarPill(.red))
} else {
Button(L10n.save) {
viewModel.add(username: username, password: password)
}
.buttonStyle(.toolbarPill)
.disabled(!isValid)
}
}
.errorMessage($viewModel.error) {
focusedfield = .username
}
}
}