import SwiftUI struct CreateThreadView: View { let boardCode: String @EnvironmentObject var settings: Settings @EnvironmentObject var apiClient: APIClient @Environment(\.dismiss) private var dismiss @State private var title = "" @State private var text = "" @State private var isLoading = false @State private var errorMessage: String? @State private var showingSuccess = false @FocusState private var titleFocused: Bool @FocusState private var textFocused: Bool var body: some View { NavigationView { VStack(spacing: 0) { ScrollView { VStack(spacing: 20) { VStack(alignment: .leading, spacing: 8) { HStack { Text("Заголовок") .font(.headline) .foregroundColor(.primary) Spacer() Text("\(title.count)") .font(.caption) .foregroundColor(.secondary) } TextField("Введите заголовок треда", text: $title) .focused($titleFocused) .padding(16) .background(Color(.secondarySystemBackground)) .cornerRadius(12) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(titleFocused ? Color.accentColor : Color.clear, lineWidth: 2) ) } VStack(alignment: .leading, spacing: 8) { HStack { Text("Содержание") .font(.headline) .foregroundColor(.primary) Spacer() Text("\(text.count)") .font(.caption) .foregroundColor(.secondary) } TextEditor(text: $text) .focused($textFocused) .frame(minHeight: 140) .padding(12) .background(Color(.secondarySystemBackground)) .cornerRadius(12) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(textFocused ? Color.accentColor : Color.clear, lineWidth: 2) ) .overlay( Group { if text.isEmpty { HStack { VStack { Text("Напишите содержание треда...") .foregroundColor(.secondary) .padding(.top, 20) .padding(.leading, 16) Spacer() } Spacer() } } } ) } HStack(spacing: 8) { Image(systemName: settings.passcode.isEmpty ? "exclamationmark.triangle.fill" : "checkmark.circle.fill") .foregroundColor(settings.passcode.isEmpty ? .orange : .green) Text(settings.passcode.isEmpty ? "Passcode не настроен" : "Passcode настроен") .font(.caption) .foregroundColor(settings.passcode.isEmpty ? .orange : .green) Spacer() } .padding(.horizontal, 4) if let error = errorMessage { HStack { Image(systemName: "xmark.circle.fill") .foregroundColor(.red) Text(error) .font(.caption) .foregroundColor(.red) Spacer() } .padding(.horizontal, 4) } } .padding(.horizontal, 20) .padding(.top, 20) } VStack(spacing: 12) { Button(action: createThread) { HStack { if isLoading { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .white)) .scaleEffect(0.8) } else { Image(systemName: "plus.circle.fill") } Text(isLoading ? "Создание..." : "Создать тред") } .frame(maxWidth: .infinity) .frame(height: 50) .background(title.isEmpty || text.isEmpty || isLoading ? Color.gray : Color.accentColor) .foregroundColor(.white) .cornerRadius(25) .animation(.easeInOut(duration: 0.2), value: title.isEmpty || text.isEmpty) } .disabled(title.isEmpty || text.isEmpty || isLoading) Button("Отмена") { dismiss() } .foregroundColor(.secondary) } .padding(.horizontal, 20) .padding(.bottom, 20) } .navigationTitle("/\(boardCode)/") .navigationBarTitleDisplayMode(.inline) .onAppear { titleFocused = true } .alert("Успешно!", isPresented: $showingSuccess) { Button("OK") { dismiss() } } message: { Text("Тред создан") } } } private func createThread() { guard !title.isEmpty && !text.isEmpty else { return } isLoading = true errorMessage = nil apiClient.createThread( boardCode: boardCode, title: title, text: text, passcode: settings.passcode ) { error in DispatchQueue.main.async { self.isLoading = false if let error = error { self.errorMessage = error.localizedDescription } else { self.showingSuccess = true } } } } } #Preview { CreateThreadView(boardCode: "test") .environmentObject(Settings()) .environmentObject(APIClient()) }