import SwiftUI struct EditHabitView: View { @Binding var isPresented: Bool @EnvironmentObject var authManager: AuthManager let habit: Habit let onSaved: () async -> Void @State private var name: String @State private var selectedIcon: String @State private var selectedColor: String @State private var frequency: HabitFrequency @State private var selectedWeekdays: Set @State private var intervalDays: String @State private var isLoading = false @State private var showArchiveConfirm = false let weekdayNames = ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"] let icons = ["🔥", "💪", "🏃", "📚", "💧", "🧘", "🎯", "⭐️", "🌟", "✅", "🏋️", "🚴", "🍎", "😴", "🧠", "🎨", "🎵", "💊", "🌿", "💰", "✍️", "🧹", "🏊", "🚶", "🎮", "📝", "🌅", "🥗", "🧃", "🫁"] let colors = ["#0D9488", "#7c3aed", "#ff4757", "#ffa502", "#6366f1", "#ec4899", "#14b8a6", "#f59e0b", "#10b981", "#3b82f6"] let frequencies: [(HabitFrequency, String, String)] = [ (.daily, "Каждый день", "calendar"), (.weekly, "По дням недели", "calendar.badge.clock"), (.interval, "Каждые N дней", "repeat"), (.monthly, "Каждый месяц", "calendar.badge.plus") ] init(isPresented: Binding, habit: Habit, onSaved: @escaping () async -> Void) { self._isPresented = isPresented self.habit = habit self.onSaved = onSaved self._name = State(initialValue: habit.name) self._selectedIcon = State(initialValue: habit.icon ?? "🔥") self._selectedColor = State(initialValue: habit.color ?? "#0D9488") self._frequency = State(initialValue: habit.frequency) self._selectedWeekdays = State(initialValue: Set(habit.targetDays ?? [1,2,3,4,5])) self._intervalDays = State(initialValue: String(habit.targetCount ?? 2)) } var body: some View { ZStack { Color(hex: "0a0a1a").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 }.foregroundColor(Color(hex: "8888aa")) Spacer() Text("Редактировать привычку").font(.headline).foregroundColor(.white) Spacer() Button(action: save) { if isLoading { ProgressView().tint(Color(hex: "0D9488")).scaleEffect(0.8) } else { Text("Сохранить").foregroundColor(name.isEmpty ? Color(hex: "8888aa") : Color(hex: "0D9488")).fontWeight(.semibold) } }.disabled(name.isEmpty || isLoading) } .padding(.horizontal, 20).padding(.vertical, 16) 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))) } } } 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))) } } } } 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")) HStack(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) } } } } // Archive / Restore button Button(action: { showArchiveConfirm = true }) { HStack { Image(systemName: habit.isArchived == true ? "arrow.uturn.backward" : "archivebox") Text(habit.isArchived == true ? "Восстановить" : "Архивировать") } .foregroundColor(habit.isArchived == true ? Color(hex: "0D9488") : Color(hex: "ff4757")) .frame(maxWidth: .infinity) .padding(14) .background(RoundedRectangle(cornerRadius: 12).fill(Color.white.opacity(0.05))) } }.padding(20) } } } .confirmationDialog( habit.isArchived == true ? "Восстановить привычку?" : "Архивировать привычку?", isPresented: $showArchiveConfirm, titleVisibility: .visible ) { Button(habit.isArchived == true ? "Восстановить" : "Архивировать", role: habit.isArchived == true ? .none : .destructive) { Task { await toggleArchive() } } Button("Отмена", role: .cancel) {} } } func save() { isLoading = true Task { var body: [String: Any] = [ "name": name, "frequency": frequency.rawValue, "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 } if let reqBody = try? JSONSerialization.data(withJSONObject: body) { try? await APIService.shared.updateHabit(token: authManager.token, id: habit.id, body: reqBody) } await onSaved() await MainActor.run { isPresented = false } } } func toggleArchive() async { let params: [String: Any] = ["is_archived": !(habit.isArchived == true)] if let body = try? JSONSerialization.data(withJSONObject: params) { try? await APIService.shared.updateHabit(token: authManager.token, id: habit.id, body: body) } await onSaved() await MainActor.run { isPresented = false } } }