Add question image media support
This commit is contained in:
@@ -39,11 +39,13 @@ var flag_button: Button
|
||||
var report_button: Button
|
||||
var nav_palette: HBoxContainer
|
||||
var question_content: VBoxContainer
|
||||
var media_container: VBoxContainer
|
||||
var timer_bar: ProgressBar
|
||||
var feedback_fog: ColorRect
|
||||
var labs_overlay: Control
|
||||
var labs_panel: PanelContainer
|
||||
var labs_content: VBoxContainer
|
||||
var media_requests: Array[HTTPRequest] = []
|
||||
var red_fog_time := 0.0
|
||||
var green_fog_time := 0.0
|
||||
var correct_advance_delay := 0.0
|
||||
@@ -151,6 +153,12 @@ func _ready() -> void:
|
||||
stem_label.custom_minimum_size = Vector2(0, 96)
|
||||
question_content.add_child(stem_label)
|
||||
|
||||
media_container = VBoxContainer.new()
|
||||
media_container.visible = false
|
||||
media_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
media_container.add_theme_constant_override("separation", 10)
|
||||
question_content.add_child(media_container)
|
||||
|
||||
lead_label = Label.new()
|
||||
lead_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
Style.set_label(lead_label, 21, Style.TEXT)
|
||||
@@ -336,6 +344,7 @@ func _load_question() -> void:
|
||||
_update_timer_bar()
|
||||
stem_plain_text = str(question.get("stem", ""))
|
||||
_render_stem()
|
||||
_load_question_media(question)
|
||||
lead_label.text = question.get("lead_in", "")
|
||||
_refresh_labs_button()
|
||||
|
||||
@@ -471,8 +480,6 @@ func _submit_or_next() -> void:
|
||||
current_answer = {}
|
||||
next_button.text = "Submit"
|
||||
next_button.disabled = true
|
||||
if skip_button != null:
|
||||
skip_button.disabled = true
|
||||
_trigger_wrong_feedback()
|
||||
_apply_saved_choice_state()
|
||||
return
|
||||
@@ -697,6 +704,112 @@ func _current_question_has_labs() -> bool:
|
||||
return not labs.is_empty()
|
||||
|
||||
|
||||
func _load_question_media(question: Dictionary) -> void:
|
||||
_clear_question_media()
|
||||
var media: Array = question.get("media", [])
|
||||
if media.is_empty():
|
||||
return
|
||||
|
||||
media_container.visible = true
|
||||
var question_id := str(question.get("id", ""))
|
||||
for item in media:
|
||||
var media_url := _resolve_media_url(str(item))
|
||||
if media_url == "":
|
||||
continue
|
||||
var frame := PanelContainer.new()
|
||||
frame.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
frame.add_theme_stylebox_override("panel", Style.panel_box(Color("111a2a"), Color("344463")))
|
||||
media_container.add_child(frame)
|
||||
|
||||
var image_box := VBoxContainer.new()
|
||||
image_box.add_theme_constant_override("separation", 8)
|
||||
frame.add_child(image_box)
|
||||
|
||||
var status := Label.new()
|
||||
status.text = "Loading image..."
|
||||
status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
Style.set_label(status, 15, Style.MUTED)
|
||||
image_box.add_child(status)
|
||||
|
||||
var texture_rect := TextureRect.new()
|
||||
texture_rect.visible = false
|
||||
texture_rect.expand_mode = TextureRect.EXPAND_FIT_WIDTH
|
||||
texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
texture_rect.custom_minimum_size = Vector2(0, 260)
|
||||
texture_rect.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
image_box.add_child(texture_rect)
|
||||
|
||||
var request := HTTPRequest.new()
|
||||
request.request_completed.connect(
|
||||
func(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray):
|
||||
_on_media_loaded(result, response_code, body, question_id, texture_rect, status)
|
||||
)
|
||||
media_requests.append(request)
|
||||
add_child(request)
|
||||
var err := request.request(media_url)
|
||||
if err != OK:
|
||||
status.text = "Image unavailable."
|
||||
|
||||
|
||||
func _clear_question_media() -> void:
|
||||
for request in media_requests:
|
||||
if is_instance_valid(request):
|
||||
request.queue_free()
|
||||
media_requests.clear()
|
||||
if media_container == null:
|
||||
return
|
||||
for child in media_container.get_children():
|
||||
media_container.remove_child(child)
|
||||
child.queue_free()
|
||||
media_container.visible = false
|
||||
|
||||
|
||||
func _resolve_media_url(value: String) -> String:
|
||||
var media_url := value.strip_edges()
|
||||
if media_url == "":
|
||||
return ""
|
||||
if media_url.begins_with("http://") or media_url.begins_with("https://"):
|
||||
return media_url
|
||||
if not media_url.begins_with("/"):
|
||||
media_url = "/%s" % media_url
|
||||
|
||||
var base_url := QuestionBankService.question_api_base_url
|
||||
var scheme_end := base_url.find("://")
|
||||
if scheme_end < 0:
|
||||
return media_url
|
||||
var path_start := base_url.find("/", scheme_end + 3)
|
||||
var origin := base_url if path_start < 0 else base_url.substr(0, path_start)
|
||||
return "%s%s" % [origin, media_url]
|
||||
|
||||
|
||||
func _on_media_loaded(
|
||||
result: int,
|
||||
response_code: int,
|
||||
body: PackedByteArray,
|
||||
question_id: String,
|
||||
texture_rect: TextureRect,
|
||||
status: Label) -> void:
|
||||
if str(BlockSessionService.get_current_question().get("id", "")) != question_id:
|
||||
return
|
||||
if result != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300:
|
||||
status.text = "Image unavailable."
|
||||
return
|
||||
|
||||
var image := Image.new()
|
||||
var err := image.load_png_from_buffer(body)
|
||||
if err != OK:
|
||||
err = image.load_jpg_from_buffer(body)
|
||||
if err != OK:
|
||||
err = image.load_webp_from_buffer(body)
|
||||
if err != OK:
|
||||
status.text = "Image unavailable."
|
||||
return
|
||||
|
||||
texture_rect.texture = ImageTexture.create_from_image(image)
|
||||
texture_rect.visible = true
|
||||
status.visible = false
|
||||
|
||||
|
||||
func _build_labs_modal() -> void:
|
||||
labs_overlay = Control.new()
|
||||
labs_overlay.visible = false
|
||||
|
||||
Reference in New Issue
Block a user