mirror of
https://github.com/mr0xb/godot-flashcards.git
synced 2026-08-27 20:44:56 -04:00
initial commit
This commit is contained in:
commit
94847a50a2
42 changed files with 2063 additions and 0 deletions
321
scenes/autoloads/data_manager.gd
Normal file
321
scenes/autoloads/data_manager.gd
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
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()
|
||||
Loading…
Reference in a new issue