import SwiftUI struct AddHabitView: View { @Binding var isPresented: Bool @EnvironmentObject var authManager: AuthManager let onAdded: () async -> Void @State private var name = "" @State private var description = "" @State private var frequency = "daily" @State private var selectedIcon = "🔥" @State private var selectedColor = "#0D9488" @State private var isLoading = false @State private var intervalDays = "2" @State private var selectedWeekdays: Set = [1,2,3,4,5] // Mon-Fri let frequencies: [(String, String, String)] = [ ("daily", "Каждый день", "calendar"), ("weekly", "По дням недели", "calendar.badge.clock"), ("interval", "Каждые N дней", "repeat"), ("monthly", "Каждый месяц", "calendar.badge.plus") ] let weekdayNames = ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"] let icons = ["🔥", "💪", "🏃", "📚", "💧", "🧘", "🎯", "⭐️", "🌟", "✅", "🏋️", "🚴", "🍎", "😴", "🧠", "🎨", "🎵", "💊", "🌿", "💰", "✍️", "🧹", "🏊", "🚶", "🎮", "📝", "🌅", "🥗", "🧃", "🫁"] let colors = ["#0D9488", "#7c3aed", "#ff4757", "#ffa502", "#6366f1", "#ec4899", "#14b8a6", "#f59e0b", "#10b981", "#3b82f6"] var body: some View { ZStack { Color(hex: "06060f").ignoresSafeArea() VStack(spacing: 0) { RoundedRectangle(cornerRadius: 3) .fill(Color.white.opacity(0.2)).frame(width: 40, height: 4).padding(.top, 12) HStack { Button("Отмена") { isPresented = false } .font(.callout).foregroundColor(Color(hex: "8888aa")) Spacer() Text("Новая привычка").font(.headline).foregroundColor(.white) Spacer() Button(action: save) { if isLoading { ProgressView().tint(Theme.teal).scaleEffect(0.8) } else { Text("Готово").font(.callout.bold()).foregroundColor(name.isEmpty ? Color(hex: "8888aa") : Theme.teal) } }.disabled(name.isEmpty || isLoading) } .padding(.horizontal, 16).padding(.vertical, 14) Divider().background(Color.white.opacity(0.1)) ScrollView { VStack(spacing: 20) { // Preview HStack(spacing: 16) { ZStack { Circle() .fill(Color(hex: String(selectedColor.dropFirst())).opacity(0.25)) .frame(width: 56, height: 56) Text(selectedIcon).font(.title2) } VStack(alignment: .leading, spacing: 4) { Text(name.isEmpty ? "Название привычки" : name) .font(.callout.bold()) .foregroundColor(name.isEmpty ? Color(hex: "8888aa") : .white) Text(frequencies.first { $0.0 == frequency }?.1 ?? "") .font(.caption).foregroundColor(Color(hex: "8888aa")) } Spacer() } .padding(16) .background(RoundedRectangle(cornerRadius: 16).fill(Color.white.opacity(0.05))) // Name VStack(alignment: .leading, spacing: 8) { Label("Название", systemImage: "pencil").font(.caption).foregroundColor(Color(hex: "8888aa")) TextField("Например: Читать 30 минут", text: $name) .foregroundColor(.white).padding(14) .background(RoundedRectangle(cornerRadius: 12).fill(Color.white.opacity(0.07))) } // Frequency VStack(alignment: .leading, spacing: 8) { Label("Периодичность", systemImage: "calendar").font(.caption).foregroundColor(Color(hex: "8888aa")) VStack(spacing: 6) { ForEach(frequencies, id: \.0) { f in Button(action: { frequency = f.0 }) { HStack { Image(systemName: f.2).foregroundColor(frequency == f.0 ? Color(hex: "0D9488") : Color(hex: "8888aa")) Text(f.1).foregroundColor(frequency == f.0 ? .white : Color(hex: "8888aa")) Spacer() if frequency == f.0 { Image(systemName: "checkmark").foregroundColor(Color(hex: "0D9488")) } } .padding(14) .background(RoundedRectangle(cornerRadius: 12).fill(frequency == f.0 ? Color(hex: "0D9488").opacity(0.15) : Color.white.opacity(0.05))) } } } // Weekly day selector if frequency == "weekly" { HStack(spacing: 8) { ForEach(0..<7) { i in Button(action: { if selectedWeekdays.contains(i) { if selectedWeekdays.count > 1 { selectedWeekdays.remove(i) } } else { selectedWeekdays.insert(i) } }) { Text(weekdayNames[i]) .font(.caption.bold()) .foregroundColor(selectedWeekdays.contains(i) ? .black : .white) .frame(width: 32, height: 32) .background(Circle().fill(selectedWeekdays.contains(i) ? Color(hex: "0D9488") : Color.white.opacity(0.08))) } } } } // Interval days if frequency == "interval" { HStack { Text("Каждые").foregroundColor(Color(hex: "8888aa")).font(.callout) TextField("2", text: $intervalDays).keyboardType(.numberPad) .foregroundColor(.white) .frame(width: 50) .padding(10) .background(RoundedRectangle(cornerRadius: 8).fill(Color.white.opacity(0.07))) Text("дней").foregroundColor(Color(hex: "8888aa")).font(.callout) } } } // Icon picker VStack(alignment: .leading, spacing: 8) { Label("Иконка", systemImage: "face.smiling").font(.caption).foregroundColor(Color(hex: "8888aa")) LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 6), spacing: 8) { ForEach(icons, id: \.self) { icon in Button(action: { selectedIcon = icon }) { Text(icon).font(.title3) .frame(width: 40, height: 40) .background(Circle().fill(selectedIcon == icon ? Color(hex: "0D9488").opacity(0.25) : Color.white.opacity(0.05))) .overlay(Circle().stroke(selectedIcon == icon ? Color(hex: "0D9488") : Color.clear, lineWidth: 2)) } } } } // Color picker VStack(alignment: .leading, spacing: 8) { Label("Цвет", systemImage: "paintpalette").font(.caption).foregroundColor(Color(hex: "8888aa")) LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 5), spacing: 10) { ForEach(colors, id: \.self) { color in Button(action: { selectedColor = color }) { Circle() .fill(Color(hex: String(color.dropFirst()))) .frame(width: 32, height: 32) .overlay(Circle().stroke(.white, lineWidth: selectedColor == color ? 2 : 0)) .scaleEffect(selectedColor == color ? 1.15 : 1.0) .animation(.easeInOut(duration: 0.15), value: selectedColor) } } } } }.padding(20) } } } } func save() { isLoading = true Task { let apiFrequency = (frequency == "interval" || frequency == "monthly") ? "custom" : frequency var body: [String: Any] = [ "name": name, "description": description, "frequency": apiFrequency, "icon": selectedIcon, "color": selectedColor, "target_count": 1 ] if frequency == "weekly" { body["target_days"] = Array(selectedWeekdays).sorted() } if frequency == "interval" { body["target_count"] = Int(intervalDays) ?? 2 } let reqBody = try? JSONSerialization.data(withJSONObject: body) try? await APIService.shared.createHabit(token: authManager.token, body: reqBody ?? Data()) await onAdded() await MainActor.run { isPresented = false } } } }