mirror of
https://github.com/mr0xb/godot-flashcards.git
synced 2026-08-28 04:54:57 -04:00
initial commit
This commit is contained in:
commit
94847a50a2
42 changed files with 2063 additions and 0 deletions
106
scenes/ui/deck_manager/deck_editor.gd
Normal file
106
scenes/ui/deck_manager/deck_editor.gd
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
extends Panel
|
||||
|
||||
signal deck_saved(deck: Deck)
|
||||
signal editor_closed()
|
||||
|
||||
var current_deck: Deck
|
||||
|
||||
@onready var deck_name_edit = $MarginContainer/VBoxContainer/DeckInfoSection/DeckNameEdit
|
||||
@onready var deck_desc_edit = $MarginContainer/VBoxContainer/DeckInfoSection/DeckDescEdit
|
||||
@onready var color_picker = $MarginContainer/VBoxContainer/DeckInfoSection/ColorPicker
|
||||
@onready var cards_list = $MarginContainer/VBoxContainer/CardsSection/ScrollContainer/CardsList
|
||||
@onready var save_btn = $MarginContainer/VBoxContainer/ButtonsSection/SaveButton
|
||||
@onready var cancel_btn = $MarginContainer/VBoxContainer/ButtonsSection/CancelButton
|
||||
@onready var add_card_btn = $MarginContainer/VBoxContainer/CardsSection/AddCardButton
|
||||
|
||||
func _ready() -> void:
|
||||
save_btn.pressed.connect(_on_save_pressed)
|
||||
cancel_btn.pressed.connect(_on_cancel_pressed)
|
||||
add_card_btn.pressed.connect(_on_add_card_pressed)
|
||||
hide()
|
||||
|
||||
func edit_deck(deck: Deck) -> void:
|
||||
current_deck = deck
|
||||
|
||||
deck_name_edit.text = deck.name
|
||||
deck_desc_edit.text = deck.description
|
||||
color_picker.color = deck.color_theme
|
||||
|
||||
_refresh_cards_list()
|
||||
|
||||
show()
|
||||
|
||||
func _refresh_cards_list() -> void:
|
||||
for child in cards_list.get_children():
|
||||
child.queue_free()
|
||||
|
||||
for i in range(current_deck.cards.size()):
|
||||
var card = current_deck.cards[i]
|
||||
_add_card_ui_entry(card, i)
|
||||
|
||||
func _add_card_ui_entry(card: Flashcard, index: int) -> void:
|
||||
var card_panel = PanelContainer.new()
|
||||
var margin = MarginContainer.new()
|
||||
margin.add_theme_constant_override("margin_left", 10)
|
||||
margin.add_theme_constant_override("margin_top", 10)
|
||||
margin.add_theme_constant_override("margin_right", 10)
|
||||
margin.add_theme_constant_override("margin_bottom", 10)
|
||||
card_panel.add_child(margin)
|
||||
|
||||
var vbox = VBoxContainer.new()
|
||||
margin.add_child(vbox)
|
||||
|
||||
var q_hbox = HBoxContainer.new()
|
||||
vbox.add_child(q_hbox)
|
||||
var q_label = Label.new()
|
||||
q_label.text = "Q: "
|
||||
q_hbox.add_child(q_label)
|
||||
var q_edit = LineEdit.new()
|
||||
q_edit.text = card.question_text
|
||||
q_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
q_edit.text_changed.connect(func(new_text): card.question_text = new_text)
|
||||
q_hbox.add_child(q_edit)
|
||||
|
||||
var a_hbox = HBoxContainer.new()
|
||||
vbox.add_child(a_hbox)
|
||||
var a_label = Label.new()
|
||||
a_label.text = "A: "
|
||||
a_hbox.add_child(a_label)
|
||||
var a_edit = LineEdit.new()
|
||||
a_edit.text = card.answer_text
|
||||
a_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
a_edit.text_changed.connect(func(new_text): card.answer_text = new_text)
|
||||
a_hbox.add_child(a_edit)
|
||||
|
||||
var delete_btn = Button.new()
|
||||
delete_btn.text = "Delete"
|
||||
delete_btn.pressed.connect(func(): _on_delete_card_pressed(index))
|
||||
vbox.add_child(delete_btn)
|
||||
|
||||
cards_list.add_child(card_panel)
|
||||
|
||||
func _on_add_card_pressed() -> void:
|
||||
var new_card = Flashcard.new()
|
||||
new_card.question_text = "New Question"
|
||||
new_card.answer_text = "New Answer"
|
||||
current_deck.add_card(new_card)
|
||||
_refresh_cards_list()
|
||||
|
||||
func _on_delete_card_pressed(index: int) -> void:
|
||||
if index >= 0 and index < current_deck.cards.size():
|
||||
current_deck.cards.remove_at(index)
|
||||
_refresh_cards_list()
|
||||
|
||||
func _on_save_pressed() -> void:
|
||||
current_deck.name = deck_name_edit.text
|
||||
current_deck.description = deck_desc_edit.text
|
||||
current_deck.color_theme = color_picker.color
|
||||
|
||||
DataManager.save_deck(current_deck)
|
||||
|
||||
deck_saved.emit(current_deck)
|
||||
hide()
|
||||
|
||||
func _on_cancel_pressed() -> void:
|
||||
editor_closed.emit()
|
||||
hide()
|
||||
1
scenes/ui/deck_manager/deck_editor.gd.uid
Normal file
1
scenes/ui/deck_manager/deck_editor.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://caqx35wgjp2v0
|
||||
100
scenes/ui/deck_manager/deck_editor.tscn
Normal file
100
scenes/ui/deck_manager/deck_editor.tscn
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://c4p1nfvj0oy7k"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/ui/deck_manager/deck_editor.gd" id="1_b0nwp"]
|
||||
|
||||
[node name="DeckEditor" type="Panel"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_b0nwp")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 60
|
||||
theme_override_constants/margin_top = 60
|
||||
theme_override_constants/margin_right = 60
|
||||
theme_override_constants/margin_bottom = 60
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="Title" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 32
|
||||
text = "Edit Deck"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="DeckInfoSection" type="VBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="NameLabel" type="Label" parent="MarginContainer/VBoxContainer/DeckInfoSection"]
|
||||
layout_mode = 2
|
||||
text = "Deck Name:"
|
||||
|
||||
[node name="DeckNameEdit" type="LineEdit" parent="MarginContainer/VBoxContainer/DeckInfoSection"]
|
||||
layout_mode = 2
|
||||
placeholder_text = "Enter deck name"
|
||||
|
||||
[node name="DescLabel" type="Label" parent="MarginContainer/VBoxContainer/DeckInfoSection"]
|
||||
layout_mode = 2
|
||||
text = "Description:"
|
||||
|
||||
[node name="DeckDescEdit" type="TextEdit" parent="MarginContainer/VBoxContainer/DeckInfoSection"]
|
||||
custom_minimum_size = Vector2(0, 60)
|
||||
layout_mode = 2
|
||||
placeholder_text = "Enter deck description"
|
||||
|
||||
[node name="ColorLabel" type="Label" parent="MarginContainer/VBoxContainer/DeckInfoSection"]
|
||||
layout_mode = 2
|
||||
text = "Deck Color:"
|
||||
|
||||
[node name="ColorPicker" type="ColorPickerButton" parent="MarginContainer/VBoxContainer/DeckInfoSection"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CardsSection" type="VBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="CardsLabel" type="Label" parent="MarginContainer/VBoxContainer/CardsSection"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "Cards:"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer/CardsSection"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="CardsList" type="VBoxContainer" parent="MarginContainer/VBoxContainer/CardsSection/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="AddCardButton" type="Button" parent="MarginContainer/VBoxContainer/CardsSection"]
|
||||
custom_minimum_size = Vector2(0, 40)
|
||||
layout_mode = 2
|
||||
text = "+ Add Card"
|
||||
|
||||
[node name="ButtonsSection" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
alignment = 1
|
||||
|
||||
[node name="CancelButton" type="Button" parent="MarginContainer/VBoxContainer/ButtonsSection"]
|
||||
custom_minimum_size = Vector2(150, 50)
|
||||
layout_mode = 2
|
||||
text = "Cancel"
|
||||
|
||||
[node name="SaveButton" type="Button" parent="MarginContainer/VBoxContainer/ButtonsSection"]
|
||||
custom_minimum_size = Vector2(150, 50)
|
||||
layout_mode = 2
|
||||
text = "Save Deck"
|
||||
45
scenes/ui/deck_manager/deck_list_item.gd
Normal file
45
scenes/ui/deck_manager/deck_list_item.gd
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
extends PanelContainer
|
||||
|
||||
signal study_requested(deck: Deck)
|
||||
signal edit_requested(deck: Deck)
|
||||
signal delete_requested(deck: Deck)
|
||||
|
||||
var deck: Deck
|
||||
|
||||
@onready var deck_name_label = $MarginContainer/HBoxContainer/VBoxContainer/DeckName
|
||||
@onready var deck_info_label = $MarginContainer/HBoxContainer/VBoxContainer/DeckInfo
|
||||
@onready var color_indicator = $MarginContainer/HBoxContainer/ColorIndicator
|
||||
@onready var study_btn = $MarginContainer/HBoxContainer/Actions/StudyButton
|
||||
@onready var edit_btn = $MarginContainer/HBoxContainer/Actions/EditButton
|
||||
@onready var delete_btn = $MarginContainer/HBoxContainer/Actions/DeleteButton
|
||||
|
||||
func _ready() -> void:
|
||||
study_btn.pressed.connect(_on_study_pressed)
|
||||
edit_btn.pressed.connect(_on_edit_pressed)
|
||||
delete_btn.pressed.connect(_on_delete_pressed)
|
||||
|
||||
func set_deck(p_deck: Deck) -> void:
|
||||
deck = p_deck
|
||||
|
||||
if deck:
|
||||
deck_name_label.text = deck.name
|
||||
deck_info_label.text = "%d cards" % deck.get_card_count()
|
||||
color_indicator.color = deck.color_theme
|
||||
|
||||
var progress = DataManager.get_progress(deck.id)
|
||||
if progress:
|
||||
deck_info_label.text += " • %.1f%% accuracy" % progress.get_accuracy()
|
||||
|
||||
func _on_study_pressed() -> void:
|
||||
if deck and deck.get_card_count() > 0:
|
||||
study_requested.emit(deck)
|
||||
else:
|
||||
push_warning("Cannot study empty deck")
|
||||
|
||||
func _on_edit_pressed() -> void:
|
||||
if deck:
|
||||
edit_requested.emit(deck)
|
||||
|
||||
func _on_delete_pressed() -> void:
|
||||
if deck:
|
||||
delete_requested.emit(deck)
|
||||
1
scenes/ui/deck_manager/deck_list_item.gd.uid
Normal file
1
scenes/ui/deck_manager/deck_list_item.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://uu8j34y86hs3
|
||||
56
scenes/ui/deck_manager/deck_list_item.tscn
Normal file
56
scenes/ui/deck_manager/deck_list_item.tscn
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://clrpqfuax7qhv"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/ui/deck_manager/deck_list_item.gd" id="1_qp4wn"]
|
||||
|
||||
[node name="DeckListItem" type="PanelContainer"]
|
||||
custom_minimum_size = Vector2(0, 80)
|
||||
script = ExtResource("1_qp4wn")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 10
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_right = 10
|
||||
theme_override_constants/margin_bottom = 10
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ColorIndicator" type="ColorRect" parent="MarginContainer/HBoxContainer"]
|
||||
custom_minimum_size = Vector2(8, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 5
|
||||
|
||||
[node name="DeckName" type="Label" parent="MarginContainer/HBoxContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "Deck Name"
|
||||
|
||||
[node name="DeckInfo" type="Label" parent="MarginContainer/HBoxContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.7, 0.7, 0.7, 1)
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "0 cards"
|
||||
|
||||
[node name="Actions" type="HBoxContainer" parent="MarginContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="StudyButton" type="Button" parent="MarginContainer/HBoxContainer/Actions"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "Study"
|
||||
|
||||
[node name="EditButton" type="Button" parent="MarginContainer/HBoxContainer/Actions"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "Edit"
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="MarginContainer/HBoxContainer/Actions"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
text = "Delete"
|
||||
89
scenes/ui/deck_manager/deck_manager.gd
Normal file
89
scenes/ui/deck_manager/deck_manager.gd
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
extends Control
|
||||
|
||||
const DeckListItemScene = preload("res://scenes/ui/deck_manager/deck_list_item.tscn")
|
||||
|
||||
@onready var back_btn = $MarginContainer/VBoxContainer/Header/BackButton
|
||||
@onready var browse_online_btn = $MarginContainer/VBoxContainer/Header/BrowseOnlineButton
|
||||
@onready var create_deck_btn = $MarginContainer/VBoxContainer/Header/CreateDeckButton
|
||||
@onready var deck_list_container = $MarginContainer/VBoxContainer/ScrollContainer/DeckListContainer
|
||||
@onready var modal_overlay = $ModalOverlay
|
||||
@onready var deck_editor = $DeckEditor
|
||||
@onready var online_browser = $OnlineDeckBrowser
|
||||
|
||||
func _ready() -> void:
|
||||
back_btn.pressed.connect(_on_back_pressed)
|
||||
browse_online_btn.pressed.connect(_on_browse_online_pressed)
|
||||
create_deck_btn.pressed.connect(_on_create_deck_pressed)
|
||||
|
||||
DataManager.decks_loaded.connect(_refresh_deck_list)
|
||||
DataManager.deck_saved.connect(_on_deck_saved)
|
||||
DataManager.deck_deleted.connect(_on_deck_deleted)
|
||||
|
||||
deck_editor.deck_saved.connect(_on_editor_deck_saved)
|
||||
deck_editor.editor_closed.connect(_on_editor_closed)
|
||||
|
||||
online_browser.browser_closed.connect(_on_browser_closed)
|
||||
|
||||
_refresh_deck_list()
|
||||
|
||||
func _refresh_deck_list() -> void:
|
||||
for child in deck_list_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
for deck in DataManager.decks:
|
||||
var item = DeckListItemScene.instantiate()
|
||||
deck_list_container.add_child(item)
|
||||
item.set_deck(deck)
|
||||
|
||||
item.study_requested.connect(_on_study_deck)
|
||||
item.edit_requested.connect(_on_edit_deck)
|
||||
item.delete_requested.connect(_on_delete_deck)
|
||||
|
||||
print("Refreshed deck list with %d deck(s)" % DataManager.decks.size())
|
||||
|
||||
func _on_back_pressed() -> void:
|
||||
GameManager.return_to_main_menu()
|
||||
|
||||
func _on_create_deck_pressed() -> void:
|
||||
var new_deck = Deck.new()
|
||||
new_deck.name = "New Deck"
|
||||
new_deck.description = "A new flashcard deck"
|
||||
|
||||
var sample_card = Flashcard.new()
|
||||
sample_card.question_text = "Sample Question"
|
||||
sample_card.answer_text = "Sample Answer"
|
||||
new_deck.add_card(sample_card)
|
||||
|
||||
DataManager.save_deck(new_deck)
|
||||
|
||||
func _on_study_deck(deck: Deck) -> void:
|
||||
GameManager.start_quiz(deck)
|
||||
|
||||
func _on_edit_deck(deck: Deck) -> void:
|
||||
modal_overlay.show()
|
||||
deck_editor.edit_deck(deck)
|
||||
|
||||
func _on_delete_deck(deck: Deck) -> void:
|
||||
print("Deleting deck: " + deck.name)
|
||||
DataManager.delete_deck(deck.id)
|
||||
|
||||
func _on_deck_saved(deck: Deck) -> void:
|
||||
_refresh_deck_list()
|
||||
|
||||
func _on_deck_deleted(deck_id: String) -> void:
|
||||
_refresh_deck_list()
|
||||
|
||||
func _on_editor_deck_saved(deck: Deck) -> void:
|
||||
_refresh_deck_list()
|
||||
|
||||
func _on_editor_closed() -> void:
|
||||
modal_overlay.hide()
|
||||
|
||||
func _on_browse_online_pressed() -> void:
|
||||
modal_overlay.show()
|
||||
online_browser.open_browser()
|
||||
|
||||
func _on_browser_closed() -> void:
|
||||
modal_overlay.hide()
|
||||
# Refresh the deck list in case new decks were downloaded
|
||||
_refresh_deck_list()
|
||||
1
scenes/ui/deck_manager/deck_manager.gd.uid
Normal file
1
scenes/ui/deck_manager/deck_manager.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://becqmtpte7ysr
|
||||
84
scenes/ui/deck_manager/deck_manager.tscn
Normal file
84
scenes/ui/deck_manager/deck_manager.tscn
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://bpd7dt0cpoh1m"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://becqmtpte7ysr" path="res://scenes/ui/deck_manager/deck_manager.gd" id="1_jh7lm"]
|
||||
[ext_resource type="PackedScene" path="res://scenes/ui/deck_manager/deck_editor.tscn" id="2_deck_editor"]
|
||||
[ext_resource type="PackedScene" uid="uid://chj1kxack8ean" path="res://scenes/ui/deck_manager/online_deck_browser.tscn" id="3_online_browser"]
|
||||
|
||||
[node name="DeckManager" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_jh7lm")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 40
|
||||
theme_override_constants/margin_top = 40
|
||||
theme_override_constants/margin_right = 40
|
||||
theme_override_constants/margin_bottom = 40
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="Header" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="BackButton" type="Button" parent="MarginContainer/VBoxContainer/Header"]
|
||||
custom_minimum_size = Vector2(100, 50)
|
||||
layout_mode = 2
|
||||
text = "← Back"
|
||||
|
||||
[node name="Title" type="Label" parent="MarginContainer/VBoxContainer/Header"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_font_sizes/font_size = 32
|
||||
text = "Deck Manager"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="BrowseOnlineButton" type="Button" parent="MarginContainer/VBoxContainer/Header"]
|
||||
custom_minimum_size = Vector2(150, 50)
|
||||
layout_mode = 2
|
||||
text = "🌐 Browse Online"
|
||||
|
||||
[node name="CreateDeckButton" type="Button" parent="MarginContainer/VBoxContainer/Header"]
|
||||
custom_minimum_size = Vector2(150, 50)
|
||||
layout_mode = 2
|
||||
text = "+ New Deck"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="DeckListContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="ModalOverlay" type="ColorRect" parent="."]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0, 0, 0, 0.9411765)
|
||||
|
||||
[node name="DeckEditor" parent="." instance=ExtResource("2_deck_editor")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="OnlineDeckBrowser" parent="." instance=ExtResource("3_online_browser")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
133
scenes/ui/deck_manager/online_deck_browser.gd
Normal file
133
scenes/ui/deck_manager/online_deck_browser.gd
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
extends Panel
|
||||
|
||||
signal browser_closed()
|
||||
|
||||
const API_BASE_URL = "http://localhost:8080"
|
||||
|
||||
@onready var close_btn = $MarginContainer/VBoxContainer/Header/CloseButton
|
||||
@onready var refresh_btn = $MarginContainer/VBoxContainer/Header/RefreshButton
|
||||
@onready var status_label = $MarginContainer/VBoxContainer/StatusLabel
|
||||
@onready var decks_container = $MarginContainer/VBoxContainer/ScrollContainer/DecksContainer
|
||||
|
||||
var http_request: HTTPRequest
|
||||
|
||||
func _ready() -> void:
|
||||
close_btn.pressed.connect(_on_close_pressed)
|
||||
refresh_btn.pressed.connect(_on_refresh_pressed)
|
||||
hide()
|
||||
|
||||
func open_browser() -> void:
|
||||
show()
|
||||
_load_online_decks()
|
||||
|
||||
func _load_online_decks() -> void:
|
||||
status_label.text = "Loading decks from API..."
|
||||
_clear_deck_list()
|
||||
|
||||
if http_request:
|
||||
http_request.queue_free()
|
||||
|
||||
http_request = HTTPRequest.new()
|
||||
add_child(http_request)
|
||||
http_request.request_completed.connect(_on_decks_loaded)
|
||||
|
||||
var error = http_request.request(API_BASE_URL + "/decks")
|
||||
if error != OK:
|
||||
status_label.text = "Error: Failed to connect to API server"
|
||||
print("HTTP request error: ", error)
|
||||
|
||||
func _on_decks_loaded(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
status_label.text = "Error: Failed to load decks"
|
||||
return
|
||||
|
||||
if response_code != 200:
|
||||
status_label.text = "Error: API returned code " + str(response_code)
|
||||
return
|
||||
|
||||
var json_string = body.get_string_from_utf8()
|
||||
var json = JSON.new()
|
||||
var parse_error = json.parse(json_string)
|
||||
|
||||
if parse_error != OK:
|
||||
status_label.text = "Error: Failed to parse response"
|
||||
return
|
||||
|
||||
var decks_list = json.data
|
||||
if decks_list.is_empty():
|
||||
status_label.text = "No decks available on server"
|
||||
return
|
||||
|
||||
status_label.text = "Found %d deck(s) online" % decks_list.size()
|
||||
_display_decks(decks_list)
|
||||
|
||||
func _display_decks(decks_list: Array) -> void:
|
||||
_clear_deck_list()
|
||||
|
||||
for deck_data in decks_list:
|
||||
var deck_info = deck_data.get("deck", {})
|
||||
var metadata = deck_info.get("metadata", {})
|
||||
var author_info = deck_info.get("author", {})
|
||||
|
||||
var deck_item = PanelContainer.new()
|
||||
var margin = MarginContainer.new()
|
||||
margin.add_theme_constant_override("margin_left", 15)
|
||||
margin.add_theme_constant_override("margin_top", 15)
|
||||
margin.add_theme_constant_override("margin_right", 15)
|
||||
margin.add_theme_constant_override("margin_bottom", 15)
|
||||
deck_item.add_child(margin)
|
||||
|
||||
var vbox = VBoxContainer.new()
|
||||
margin.add_child(vbox)
|
||||
|
||||
var name_label = Label.new()
|
||||
name_label.text = deck_info.get("name", "Unknown Deck")
|
||||
name_label.add_theme_font_size_override("font_size", 20)
|
||||
vbox.add_child(name_label)
|
||||
|
||||
var desc_label = Label.new()
|
||||
desc_label.text = deck_info.get("description", "")
|
||||
desc_label.add_theme_color_override("font_color", Color(0.7, 0.7, 0.7))
|
||||
vbox.add_child(desc_label)
|
||||
|
||||
var cards_count = deck_info.get("cards", []).size()
|
||||
var rating = metadata.get("rating", 0.0)
|
||||
var downloads = metadata.get("download_count", 0)
|
||||
var author_name = author_info.get("name", "N/A")
|
||||
|
||||
var meta_label = Label.new()
|
||||
meta_label.text = "%d cards • ⭐ %.1f • %d downloads 🧑 %s" % [cards_count, rating, downloads, author_name]
|
||||
meta_label.add_theme_color_override("font_color", Color(0.6, 0.6, 0.6))
|
||||
meta_label.add_theme_font_size_override("font_size", 14)
|
||||
vbox.add_child(meta_label)
|
||||
|
||||
var download_btn = Button.new()
|
||||
download_btn.text = "Download Deck"
|
||||
download_btn.custom_minimum_size = Vector2(150, 40)
|
||||
download_btn.pressed.connect(_on_download_deck.bind(deck_info.get("id", "")))
|
||||
vbox.add_child(download_btn)
|
||||
|
||||
decks_container.add_child(deck_item)
|
||||
|
||||
func _on_download_deck(deck_id: String) -> void:
|
||||
if deck_id == "":
|
||||
return
|
||||
|
||||
status_label.text = "Downloading deck..."
|
||||
print("Downloading deck: " + deck_id)
|
||||
|
||||
DataManager.download_deck_from_api(API_BASE_URL + "/decks/" + deck_id)
|
||||
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
status_label.text = "Deck downloaded! Check your deck list."
|
||||
|
||||
func _clear_deck_list() -> void:
|
||||
for child in decks_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
func _on_refresh_pressed() -> void:
|
||||
_load_online_decks()
|
||||
|
||||
func _on_close_pressed() -> void:
|
||||
browser_closed.emit()
|
||||
hide()
|
||||
1
scenes/ui/deck_manager/online_deck_browser.gd.uid
Normal file
1
scenes/ui/deck_manager/online_deck_browser.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b1tcvxtd8urjl
|
||||
62
scenes/ui/deck_manager/online_deck_browser.tscn
Normal file
62
scenes/ui/deck_manager/online_deck_browser.tscn
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://chj1kxack8ean"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b1tcvxtd8urjl" path="res://scenes/ui/deck_manager/online_deck_browser.gd" id="1_online"]
|
||||
|
||||
[node name="OnlineDeckBrowser" type="Panel"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_online")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 60
|
||||
theme_override_constants/margin_top = 60
|
||||
theme_override_constants/margin_right = 60
|
||||
theme_override_constants/margin_bottom = 60
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="Header" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="MarginContainer/VBoxContainer/Header"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_font_sizes/font_size = 32
|
||||
text = "Browse Online Decks"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="RefreshButton" type="Button" parent="MarginContainer/VBoxContainer/Header"]
|
||||
custom_minimum_size = Vector2(120, 50)
|
||||
layout_mode = 2
|
||||
text = "🔄 Refresh"
|
||||
|
||||
[node name="CloseButton" type="Button" parent="MarginContainer/VBoxContainer/Header"]
|
||||
custom_minimum_size = Vector2(100, 50)
|
||||
layout_mode = 2
|
||||
text = "Close"
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "Loading..."
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="DecksContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 15
|
||||
Loading…
Reference in a new issue