my app have some points: after I restart iPhone my duties and notes in app is disappeared. similar state of affairs after I replace new model of my app. my app has synchronization by way of iCloud by means of all Apple gadgets (iPad, Mac, iPhone)
my app is distributing in App Retailer: https://apps.apple.com/ru/app/just-to-do-it-list/id6758045201
under code of my app, inform me please some methods to do for get 100% proper syntonization by way of iCloud with out bugs and lacking content material:
ContentView.swift:
import SwiftUI
struct ContentView: View {
@State non-public var currentTodo = ""
@State non-public var currentNoteContent = ""
@State non-public var expandedTaskId: UUID?
@State non-public var isShowingNotes = false
@State non-public var showingAlert = false
@State non-public var alertMessage = ""
@StateObject non-public var taskManager = TaskManager()
// Добавление задачи
non-public func addTodoAction() {
guard !currentTodo.trimmingCharacters(in: .whitespaces).isEmpty else {
alertMessage = "Введите текст задачи"
showingAlert = true
return
}
taskManager.addTodo(todo: currentTodo.trimmingCharacters(in: .whitespaces))
currentTodo = ""
}
var physique: some View {
NavigationStack {
VStack {
// 1. Поле ввода и кнопка
HStack {
TextField("Write activity right here and click on the suitable button", textual content: $currentTodo)
.textFieldStyle(RoundedBorderTextFieldStyle())
.onSubmit { addTodoAction() }
Button(motion: addTodoAction) {
Picture(systemName: "pencil.tip.crop.circle.badge.plus")
}
.padding(.main, 5)
}
.padding()
// 2. Список задач
Record {
ForEach($taskManager.todos, id: .id) { $todo in
VStack(alignment: .main) {
HStack(alignment: .middle) {
VStack(alignment: .main, spacing: 4) {
Textual content(todo.todo)
.lineLimit(1)
HStack {
Slider(
worth: $todo.progress,
in: 0...100,
step: 1
) { isEditing in
if !isEditing {
taskManager.updateProgress(for: todo.id, progress: todo.progress)
}
}
.body(width: 100)
Textual content("(Int(todo.progress))%")
.font(.caption)
.foregroundColor(.grey)
.body(width: 40, alignment: .main)
}
}
.body(maxWidth: .infinity, alignment: .main)
Button(motion: {
todo.subtasks.append(Subtask(title: "New subtask"))
expandedTaskId = todo.id
}) {
Picture(systemName: "plus.circle")
.foregroundColor(.blue)
}
.buttonStyle(PlainButtonStyle())
.padding(.main, 4)
Button(motion: {
expandedTaskId = (expandedTaskId == todo.id) ? nil : todo.id
}) {
Picture(systemName: expandedTaskId == todo.id ? "chevron.down" : "chevron.proper")
.foregroundColor(.grey)
.imageScale(.medium)
}
.buttonStyle(PlainButtonStyle())
.contentShape(Rectangle())
.body(width: 24, top: 24)
}
.padding(.vertical, 6)
if expandedTaskId == todo.id && !todo.subtasks.isEmpty {
ForEach($todo.subtasks, id: .id) { $subtask in
HStack {
Button(motion: {
taskManager.toggleSubtaskCompletion(for: todo.id, subtaskId: subtask.id)
}) {
Picture(systemName: subtask.isCompleted ? "checkmark.sq..fill" : "sq.")
.foregroundColor(subtask.isCompleted ? .blue : .grey)
}
.buttonStyle(PlainButtonStyle())
TextField("Подзадача", textual content: $subtask.title)
.disabled(subtask.isCompleted)
.foregroundColor(subtask.isCompleted ? .grey : .major)
.padding(.main, 4)
.onChange(of: subtask.title) { _ in
taskManager.scheduleSave()
}
}
.padding(.main, 28)
.padding(.vertical, 4)
}
.padding(.prime, 4)
}
}
.padding(.horizontal, -8)
}
.onDelete(carry out: { offsets in
taskManager.deleteTodo(at: offsets)
})
// 3. Кнопка Notes
Button(motion: {
isShowingNotes = true
}) {
Textual content("Notes")
.font(.headline)
.foregroundColor(.white)
.padding()
.body(maxWidth: .infinity)
.background(Colour.blue)
.cornerRadius(10)
}
.padding(.horizontal)
.padding(.prime, 10)
// 4. Индикатор загрузки
if taskManager.isSyncing {
ProgressView("Downloading..")
.progressViewStyle(CircularProgressViewStyle())
.padding()
}
}
.navigationTitle("Simply To Do It Record")
}
.onAppear {
DataManager.shared.ensureTodosFileExists()
DataManager.shared.taskManager = taskManager
DataManager.shared.startMonitoringTodosChanges()
taskManager.loadTodos()
// Принудительно перезагружаем заметки при открытии
DataManager.shared.loadNotes { end in
change consequence {
case .success(let content material):
currentNoteContent = content material ?? ""
case .failure(let error):
alertMessage = "Error loading notes: (error.localizedDescription)"
showingAlert = true
}
}
// Запускаем мониторинг изменений (если ещё не запущен)
DataManager.shared.startMonitoringNotesChanges()
DataManager.shared.startMonitoringTodosChanges()
}
.navigationDestination(isPresented: $isShowingNotes) {
NotesEditView(
noteContent: $currentNoteContent,
onSave: { savedText in
currentNoteContent = savedText
DataManager.shared.saveNotes(
content material: savedText,
completion: { error in
if let error = error {
alertMessage = "Error: (error.localizedDescription)"
showingAlert = true
}
}
)
}
)
.onDisappear {
// Принудительно сохраняем текущие заметки при закрытии
DataManager.shared.saveNotes(
content material: currentNoteContent,
completion: { error in
if let error = error {
alertMessage = "Error by way of closure: (error.localizedDescription)"
showingAlert = true
} else {
print("✅ Notes saved by way of closure")
}
}
)
isShowingNotes = false
}
}
