From 7aa064fe2454944e765538014ea91c81e4d7f79f Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:03:10 -0500 Subject: [PATCH] Created ItchAppPanel Started working on implementing Itch.io App panel --- UI/Controls/itch_app_panel.gd | 167 +++++++++++++++++++++++++++ UI/Controls/itch_app_panel.gd.uid | 1 + UI/Controls/itch_app_panel.tscn | 186 ++++++++++++++++++++++++++++++ 3 files changed, 354 insertions(+) create mode 100644 UI/Controls/itch_app_panel.gd create mode 100644 UI/Controls/itch_app_panel.gd.uid create mode 100644 UI/Controls/itch_app_panel.tscn diff --git a/UI/Controls/itch_app_panel.gd b/UI/Controls/itch_app_panel.gd new file mode 100644 index 00000000..064d37be --- /dev/null +++ b/UI/Controls/itch_app_panel.gd @@ -0,0 +1,167 @@ +@tool +extends PanelContainer +class_name ItchIOAppInfo + +@export var enable_logger: bool = true +@warning_ignore("unused_private_class_variable") +@export_tool_button("Search", "Button") var _search = tool_search +@export var tool_app_url: String + +#region Test Apps +enum ItchIOGames{ + RIDICULOUS_SHOPPING, + THE_MAZE_AND_THE_BEAST, + THE_SUNNYSIDE_MOTEL_IN_HUTTSVILLE_ARKANSAS, + VOID_DRIVE_THROUGH, + POTION_QUEST, + SUPER_ROLL_OUT, + COVINOS_ROTTEN_FRUIT, + AUTENTIC_ITALIAN_PIZZA, +} +const ITCHIO_APP_URLS: Dictionary[ItchIOGames, String] = { + ItchIOGames.RIDICULOUS_SHOPPING: "https://uff.itch.io/ridiculous-shopping", + ItchIOGames.THE_MAZE_AND_THE_BEAST: "https://uff.itch.io/the-maze-and-the-beast", + ItchIOGames.THE_SUNNYSIDE_MOTEL_IN_HUTTSVILLE_ARKANSAS: "https://fgaha56.itch.io/the-sunnyside-motel-in-huttsville-arkansas", + ItchIOGames.VOID_DRIVE_THROUGH: "https://fgaha56.itch.io/void-drive-through", + ItchIOGames.POTION_QUEST: "https://vex667.itch.io/potion-quest", + ItchIOGames.SUPER_ROLL_OUT: "https://seano4d.itch.io/super-roll-out", + ItchIOGames.COVINOS_ROTTEN_FRUIT: "https://jerem-watts.itch.io/gorley-cleans-up-covinos-rotten-fruit", + ItchIOGames.AUTENTIC_ITALIAN_PIZZA: "https://trevron.itch.io/authentic-italian-pizza", +} +@export var selected_itchio_game: ItchIOGames: + set(val): + selected_itchio_game = val + if is_node_ready(): get_app_info(ITCHIO_APP_URLS[selected_itchio_game]) +@export var test_data: ItchIOAppData +#endregion + +const IMG_VALID_FORMATS = ["png", "jpeg", "jpg", "bmp", "webp", "svg"] + +static var _log: TwitchLogger = TwitchLogger.new(&"ItchAppInfo") +var data: ItchIOAppData: + set(val): + data = val + if is_node_ready(): + %VisitPage.disabled = data == null + +var _save_data: ItchIOAppData + +func _ready() -> void: + %Clear.pressed.connect(clear) + if Engine.is_editor_hint(): + return + clear() + +func tool_search() -> void: + if !Engine.is_editor_hint(): + return + if tool_app_url: + get_app_info(tool_app_url) + +func get_app_info(app_url: String) -> ItchIOAppData: + var _data: ItchIOAppData = await %ItchIOService.get_itch_app_data(app_url) + if not _data: + return null + + display_app_info(_data) + if Engine.is_editor_hint(): + test_data = _data + return _data + +func display_app_info(_data: ItchIOAppData) -> void: + clear() + data = _data + if not data: return + %AppSearch.text = str(data.url) + %AppId.text = str(data.id) + %GameName.text = data.title + + var authors_string: String = "" + for i: int in data.authors.size(): + var author_dic: Dictionary = data.authors[i] + authors_string += "[b][url={url}]{name}[/url][/b]".format(author_dic) + if i+1 < data.authors.size(): + authors_string += ", " + + %AuthorName.text = "[i]by %s[/i]" % authors_string + if data.cover_image: + %CapsuleImage.texture = await load_texture_from_url(data.cover_image) + if not data.screenshots_thumbnails.is_empty(): + var texture := await load_texture_from_url(data.screenshots_thumbnails.front()) + if texture: + %Background.texture = texture + + %lb_price_desc.visible = !data.is_free + if data.is_free: + %GamePrice.text = "[color=green][wave][b]Free to play![/b][/wave][/color]" + else: + %GamePrice.text = "[color=green][b]%s[/b][/color]" % data.price + + %Description.text = data.description + +func clear() -> void: + data = null + %AppSearch.text = "" + %GameName.text = "" + %AuthorName.text = "" + %CapsuleImage.texture = null + %Background.texture = null + %ReleaseDate.text = "" + %GamePrice.text = "" + %h_price.hide() + %Description.text = "" + +func load_texture_from_url(url: String) -> ImageTexture: + var http := HTTPRequest.new() + add_child(http) + var url_no_query: String = url.split("?")[0] + var file_type = url_no_query.get_extension() + if not file_type in ["png", "jpeg", "jpg", "bmp", "webp", "svg"]: + file_type = "webp" + + var _err = http.request(url) + if _err != OK: + print("_err != OK") + return + + var result: Array = await http.request_completed + var _result: int = result[0] + var response_code: int = result[1] + var _headers: PackedStringArray = result[2] + var buffer: PackedByteArray = result[3] + if response_code != HTTPClient.RESPONSE_OK: + print("response_code != HTTPClient.RESPONSE_OK") + return + + var tex_image := Image.new() + match file_type: + "png": tex_image.load_png_from_buffer(buffer) + "jpeg", "jpg": tex_image.load_jpg_from_buffer(buffer) + "bmp": tex_image.load_bmp_from_buffer(buffer) + "webp": tex_image.load_webp_from_buffer(buffer) + "svg": tex_image.load_svg_from_buffer(buffer) + _: + _log.e("%s format not recognized." % file_type) + return null + + var tex = ImageTexture.create_from_image(tex_image) + http.queue_free() + return tex + + +func _notification(what: int) -> void: + if not Engine.is_editor_hint(): return + match what: + NOTIFICATION_EDITOR_PRE_SAVE: + _save_data = data + #_save_capsule_texture = %CapsuleImage.texture + #_save_bg_texture = %Background.texture + #test_data = null + clear() + NOTIFICATION_EDITOR_POST_SAVE: + test_data = _save_data + display_app_info.call_deferred(_save_data) + #%CapsuleImage.texture = _save_capsule_texture + #%Background.texture = _save_bg_texture + #_save_capsule_texture = null + #_save_bg_texture = null diff --git a/UI/Controls/itch_app_panel.gd.uid b/UI/Controls/itch_app_panel.gd.uid new file mode 100644 index 00000000..033aea1f --- /dev/null +++ b/UI/Controls/itch_app_panel.gd.uid @@ -0,0 +1 @@ +uid://cc2x4u4d0qrg1 diff --git a/UI/Controls/itch_app_panel.tscn b/UI/Controls/itch_app_panel.tscn new file mode 100644 index 00000000..35b7260c --- /dev/null +++ b/UI/Controls/itch_app_panel.tscn @@ -0,0 +1,186 @@ +[gd_scene format=3 uid="uid://c0ahhupmdstxq"] + +[ext_resource type="Script" uid="uid://cc2x4u4d0qrg1" path="res://UI/Controls/itch_app_panel.gd" id="1_5d14s"] +[ext_resource type="Script" uid="uid://cyef5m8x5f7k6" path="res://lib/games_info/itch_io_service.gd" id="2_15a0r"] +[ext_resource type="Texture2D" uid="uid://bw7yr2aonagxc" path="res://UI/assets/font_awesome/itch-io.svg" id="3_xpc18"] +[ext_resource type="Texture2D" uid="uid://4juherhkw8hp" path="res://addons/script_splitter/assets/Close.svg" id="4_g2paa"] +[ext_resource type="FontFile" uid="uid://cx1a4aqqxhsrn" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Italic.ttf" id="5_itotn"] +[ext_resource type="FontFile" uid="uid://b6u8lwedqawa7" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Bold italic.ttf" id="6_3efm0"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3mi7s"] +content_margin_left = 8.0 +content_margin_top = 8.0 +content_margin_right = 8.0 +content_margin_bottom = 8.0 +bg_color = Color(0.1, 0.1, 0.1, 0.6) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.6215238, 0.6215239, 0.62152356, 1) +border_blend = true +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="LabelSettings" id="LabelSettings_tbax8"] +font_size = 24 + +[sub_resource type="LabelSettings" id="LabelSettings_s4fpn"] +font = ExtResource("5_itotn") +font_size = 20 + +[sub_resource type="LabelSettings" id="LabelSettings_cc846"] +font = ExtResource("6_3efm0") +font_size = 20 + +[node name="ItchAppPanel" type="PanelContainer" unique_id=691251029] +offset_right = 616.0 +offset_bottom = 860.0 +script = ExtResource("1_5d14s") +selected_itchio_game = 1 + +[node name="ItchIOService" type="Node" parent="." unique_id=1316795504] +unique_name_in_owner = true +script = ExtResource("2_15a0r") +metadata/_custom_type_script = "uid://cyef5m8x5f7k6" + +[node name="Background" type="TextureRect" parent="." unique_id=1907032212] +unique_name_in_owner = true +layout_mode = 2 + +[node name="v" type="VBoxContainer" parent="." unique_id=279286858] +layout_mode = 2 + +[node name="m" type="MarginContainer" parent="v" unique_id=357824354] +layout_mode = 2 + +[node name="h" type="HBoxContainer" parent="v/m" unique_id=833665550] +layout_mode = 2 +alignment = 1 + +[node name="Icon" type="TextureRect" parent="v/m/h" unique_id=1660071037] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +texture = ExtResource("3_xpc18") +expand_mode = 1 +stretch_mode = 5 + +[node name="Title" type="Label" parent="v/m/h" unique_id=833828536] +layout_mode = 2 +text = "itchIO App Info" + +[node name="Clear" type="Button" parent="v/m" unique_id=1103305607] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 4 +icon = ExtResource("4_g2paa") +icon_alignment = 1 + +[node name="hsep" type="HSeparator" parent="v" unique_id=1999803799] +layout_mode = 2 + +[node name="h" type="HBoxContainer" parent="v" unique_id=660296882] +layout_mode = 2 + +[node name="Label" type="Label" parent="v/h" unique_id=1424894063] +layout_mode = 2 +text = "App url" + +[node name="AppSearch" type="LineEdit" parent="v/h" unique_id=1792920414] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="AppId" type="LineEdit" parent="v" unique_id=327619984] +unique_name_in_owner = true +layout_mode = 2 +text = "2673807" +placeholder_text = "App ID" +alignment = 1 + +[node name="info" type="PanelContainer" parent="v" unique_id=1542425427] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_3mi7s") + +[node name="sc" type="ScrollContainer" parent="v/info" unique_id=1867214191] +layout_mode = 2 + +[node name="v" type="VBoxContainer" parent="v/info/sc" unique_id=3173697] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="GameName" type="Label" parent="v/info/sc/v" unique_id=279823622] +unique_name_in_owner = true +layout_mode = 2 +label_settings = SubResource("LabelSettings_tbax8") +horizontal_alignment = 1 +text_overrun_behavior = 3 + +[node name="AuthorName" type="RichTextLabel" parent="v/info/sc/v" unique_id=348439232] +unique_name_in_owner = true +layout_mode = 2 +bbcode_enabled = true +fit_content = true +scroll_active = false +autowrap_mode = 0 +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="CapsuleImage" type="TextureRect" parent="v/info/sc/v" unique_id=1515227202] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="hr" type="HBoxContainer" parent="v/info/sc/v" unique_id=1865485586] +layout_mode = 2 +alignment = 2 + +[node name="lb" type="Label" parent="v/info/sc/v/hr" unique_id=1295698123] +layout_mode = 2 +text = "Release Date:" +label_settings = SubResource("LabelSettings_s4fpn") + +[node name="ReleaseDate" type="Label" parent="v/info/sc/v/hr" unique_id=489036318] +unique_name_in_owner = true +layout_mode = 2 +label_settings = SubResource("LabelSettings_cc846") + +[node name="h_price" type="HBoxContainer" parent="v/info/sc/v" unique_id=2028526260] +unique_name_in_owner = true +visible = false +layout_mode = 2 +alignment = 2 + +[node name="lb_price_desc" type="Label" parent="v/info/sc/v/h_price" unique_id=956528954] +unique_name_in_owner = true +visible = false +layout_mode = 2 +text = "Price:" +label_settings = SubResource("LabelSettings_s4fpn") + +[node name="GamePrice" type="Label" parent="v/info/sc/v/h_price" unique_id=290394728] +unique_name_in_owner = true +layout_mode = 2 +label_settings = SubResource("LabelSettings_cc846") + +[node name="hsep" type="HSeparator" parent="v/info/sc/v" unique_id=343519708] +layout_mode = 2 + +[node name="Description" type="RichTextLabel" parent="v/info/sc/v" unique_id=1459602721] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +bbcode_enabled = true + +[node name="VisitPage" type="Button" parent="v" unique_id=914935418] +unique_name_in_owner = true +layout_mode = 2 +disabled = true +text = "Visit Steam Page"