extends Node signal decks_loaded() signal deck_saved(deck: Deck) signal deck_deleted(deck_id: String) signal progress_updated(deck_id: String) const DECKS_DIR = "user://data/decks/" const PROGRESS_FILE = "user://data/progress/progress.json" var decks: Array[Deck] = [] var progress_data: Dictionary = {} var user_id: String = "local" func _ready() -> void: _ensure_directories_exist() load_all_decks() load_progress() func _ensure_directories_exist() -> void: DirAccess.make_dir_recursive_absolute("user://data/decks/") DirAccess.make_dir_recursive_absolute("user://data/progress/") func load_all_decks() -> void: decks.clear() var dir = DirAccess.open(DECKS_DIR) if not dir: push_warning("Could not open decks directory, creating it...") _ensure_directories_exist() decks_loaded.emit() return dir.list_dir_begin() var file_name = dir.get_next() while file_name != "": if file_name.ends_with(".json"): var deck = load_deck_from_file(DECKS_DIR + file_name) if deck: decks.append(deck) file_name = dir.get_next() dir.list_dir_end() decks.sort_custom(func(a, b): return a.updated_at > b.updated_at) print("Loaded %d deck(s)" % decks.size()) decks_loaded.emit() func load_deck_from_file(file_path: String) -> Deck: print("Loading Deck From File: ", file_path) var file = FileAccess.open(file_path, FileAccess.READ) if not file: push_error("Failed to open deck file: " + file_path) return null var json_string = file.get_as_text() file.close() var json = JSON.new() var error = json.parse(json_string) if error != OK: push_error("Failed to parse JSON in file: %s (Error: %s)" % [file_path, json.get_error_message()]) return null var deck = Deck.new() deck.from_dict(json.data) return deck func save_deck(deck: Deck) -> bool: if not deck: push_error("Cannot save null deck") return false deck.updated_at = Time.get_datetime_string_from_system(true, true) + "Z" var file_path = DECKS_DIR + deck.id + ".json" print("Saving Deck to: ", file_path) var file = FileAccess.open(file_path, FileAccess.WRITE) if not file: push_error("Failed to create deck file: " + file_path) return false var deck_dict = deck.to_dict() var json_string = JSON.stringify(deck_dict, "\t") file.store_string(json_string) file.close() var found = false for i in range(decks.size()): if decks[i].id == deck.id: decks[i] = deck found = true break if not found: decks.append(deck) decks.sort_custom(func(a, b): return a.updated_at > b.updated_at) print("Saved deck: %s (%d cards)" % [deck.name, deck.get_card_count()]) deck_saved.emit(deck) return true func delete_deck(deck_id: String) -> bool: var file_path = DECKS_DIR + deck_id + ".json" if FileAccess.file_exists(file_path): var error = DirAccess.remove_absolute(file_path) if error != OK: push_error("Failed to delete deck file: " + file_path) return false for i in range(decks.size()): if decks[i].id == deck_id: decks.remove_at(i) break if progress_data.has(deck_id): progress_data.erase(deck_id) save_progress() print("Deleted deck: " + deck_id) deck_deleted.emit(deck_id) return true func get_deck_by_id(deck_id: String) -> Deck: for deck in decks: if deck.id == deck_id: return deck return null func load_progress() -> void: if not FileAccess.file_exists(PROGRESS_FILE): print("No progress file found, starting fresh") return var file = FileAccess.open(PROGRESS_FILE, FileAccess.READ) if not file: push_error("Failed to open progress file") return var json_string = file.get_as_text() file.close() var json = JSON.new() var error = json.parse(json_string) if error != OK: push_error("Failed to parse progress JSON") return var data = json.data user_id = data.get("user_id", "local") var deck_progress = data.get("deck_progress", {}) for deck_id in deck_progress.keys(): var progress = Progress.new() progress.from_dict(deck_progress[deck_id]) progress_data[deck_id] = progress print("Loaded progress for %d deck(s)" % progress_data.size()) func save_progress() -> void: var deck_progress = {} for deck_id in progress_data.keys(): deck_progress[deck_id] = progress_data[deck_id].to_dict() var data = { "version": "1.0", "user_id": user_id, "deck_progress": deck_progress } var file = FileAccess.open(PROGRESS_FILE, FileAccess.WRITE) if not file: push_error("Failed to save progress file") return var json_string = JSON.stringify(data, "\t") file.store_string(json_string) file.close() print("Saved progress for %d deck(s)" % progress_data.size()) func get_or_create_progress(deck_id: String) -> Progress: if not progress_data.has(deck_id): var progress = Progress.new() progress.deck_id = deck_id progress_data[deck_id] = progress return progress_data[deck_id] func record_quiz_result(deck_id: String, card_id: String, is_correct: bool) -> void: var progress = get_or_create_progress(deck_id) progress.record_answer(card_id, is_correct) save_progress() progress_updated.emit(deck_id) func get_progress(deck_id: String) -> Progress: return progress_data.get(deck_id, null) func download_deck_from_api(api_url: String) -> void: print("Downloading deck from API: " + api_url) var http_request = HTTPRequest.new() add_child(http_request) http_request.request_completed.connect(_on_api_deck_downloaded.bind(http_request)) var error = http_request.request(api_url) if error != OK: push_error("Failed to start HTTP request: " + str(error)) http_request.queue_free() func _on_api_deck_downloaded(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, http_request: HTTPRequest) -> void: if not http_request: return if result != HTTPRequest.RESULT_SUCCESS: push_error("HTTP request failed with result: " + str(result)) http_request.queue_free() return if response_code != 200: push_error("API returned error code: " + str(response_code)) http_request.queue_free() return var json_string = body.get_string_from_utf8() var json = JSON.new() var parse_error = json.parse(json_string) if parse_error != OK: push_error("Failed to parse API response JSON") http_request.queue_free() return var deck = Deck.new() deck.from_dict(json.data) save_deck(deck) print("Successfully downloaded and saved deck: " + deck.name) http_request.queue_free() func upload_deck_to_api(deck: Deck, api_url: String, auth_token: String = "") -> void: print("Uploading deck to API: " + deck.name) var http_request = HTTPRequest.new() add_child(http_request) http_request.request_completed.connect(_on_api_deck_uploaded.bind(http_request)) var headers = ["Content-Type: application/json"] if auth_token != "": headers.append("Authorization: Bearer " + auth_token) var deck_dict = deck.to_dict() var json_string = JSON.stringify(deck_dict) var error = http_request.request(api_url, headers, HTTPClient.METHOD_POST, json_string) if error != OK: push_error("Failed to start HTTP upload request: " + str(error)) http_request.queue_free() func _on_api_deck_uploaded(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, http_request: HTTPRequest) -> void: if not http_request: return if result != HTTPRequest.RESULT_SUCCESS: push_error("HTTP upload failed with result: " + str(result)) http_request.queue_free() return if response_code == 200 or response_code == 201: print("Deck successfully uploaded to API!") # Optionally parse response to get the deck ID from server var json_string = body.get_string_from_utf8() print("Server response: " + json_string) else: push_error("API returned error code: " + str(response_code)) http_request.queue_free() func browse_decks_from_api(api_url: String) -> void: print("Browsing decks from API: " + api_url) var http_request = HTTPRequest.new() add_child(http_request) http_request.request_completed.connect(_on_api_decks_browsed.bind(http_request)) var error = http_request.request(api_url) if error != OK: push_error("Failed to start browse request: " + str(error)) http_request.queue_free() func _on_api_decks_browsed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, http_request: HTTPRequest) -> void: if not http_request: return if result != HTTPRequest.RESULT_SUCCESS or response_code != 200: push_error("Browse request failed") http_request.queue_free() return var json_string = body.get_string_from_utf8() var json = JSON.new() if json.parse(json_string) == OK: var decks_list = json.data print("Found %d decks from API" % decks_list.size()) for deck_data in decks_list: print(" - " + deck_data.get("deck", {}).get("name", "Unknown")) http_request.queue_free()