From b505f22b8c7f49e0a1e71a68c4d196cf6d95a2d0 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Wed, 16 Sep 2026 14:26:22 -0500 Subject: [PATCH] Applications can now be marked as installed, status bar can now show real data --- lib/pages/games.rb | 59 ++++++++++++++++++++++++++++++++++++----- lib/states/interface.rb | 24 +++++++++-------- lib/worker.rb | 9 +++++++ lib/worker/request.rb | 9 ++----- lib/worker/task.rb | 37 ++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 24 deletions(-) diff --git a/lib/pages/games.rb b/lib/pages/games.rb index 809695b..1f8cfca 100644 --- a/lib/pages/games.rb +++ b/lib/pages/games.rb @@ -157,7 +157,7 @@ module W3DHubLauncher def populate_game_info # FIXME: We should be able to query an api to figure out the installation state, instead of explictly writing it out like this... - application = MemCache[:settings].applications.find { |app| app.id == @current_app.id } + application = MemCache[:settings].applications.find { |app| app.id == @current_app.id && app.channel == @current_channel&.id } # pp application @game_info_container.clear do @@ -188,19 +188,33 @@ module W3DHubLauncher if application button "JOIN", tip: "Join most populated or lowest ping server", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_LEFT, **CTA_BUTTON_THEME button safe_get_image("#{ROOT_PATH}/media/icons/singleplayer.png"), tip: "Single player", image_height: 1.0, background_nine_slice: NINE_SLICE_SQUARE, **CTA_BUTTON_THEME - button safe_get_image("#{ROOT_PATH}/media/icons/gear.png"), tip: "Options", image_height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME + button safe_get_image("#{ROOT_PATH}/media/icons/gear.png"), tip: "Options", image_height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME do |btn| + menu(parent: btn) do + menu_item("Game Settings") + menu_item("Show in Explorer") + menu_item("Repair Installation") + menu_item("Check for Updates") + stack(width: 1.0, height: 4, background: 0xff_bbbbbb) + menu_item("Move Installation") + menu_item("Uninstall") + end.show + end elsif @current_app.servicable? # pp @current_app button "Import", enabled: false, tip: "Import existing application installation", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_LEFT, **CTA_BUTTON_THEME - button "Download", tip: "Download and install application", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME do - Worker::Api.install_application(@current_app.id, @current_channel.id) + button "Download", tip: "Download and install application", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME do |btn| + btn.enabled = false + + Worker::Api.install_application(@current_app.id, @current_channel.id) do |status, result| + handle_task_update(status, result) + end end else button "Import", enabled: false, tip: "Import existing application installation", fill: true, height: 1.0, **CTA_BUTTON_THEME end end - # FIXME: the reported version should be the _installed_ version, not the current channel version - inscription "Version: #{@current_channel.version}", margin_top: PADDING, tip: "Installed version" if application + + inscription "Version: #{application.version}", margin_top: PADDING, tip: "Installed version" if application end end @@ -251,6 +265,39 @@ module W3DHubLauncher def news_item_width_ratio (@news_container.width / 400.0).round.clamp(1..10) end + + def handle_task_update(result, status) + pp [result, status] + + status_bar = current_state.application_task_status_bar_container + status_bar_title = find_element_by_tag(status_bar, :status_bar_title) + status_bar_label = find_element_by_tag(status_bar, :status_bar_label) + status_bar_progress = find_element_by_tag(status_bar, :status_bar_progress) + + data = result.data + + case status + when Worker::Request::STATUS_COMPLETE + status_bar.hide + + MemCache[:settings].applications << Worker::Api::Settings::Application.new(data["application"]) + Worker::Api.update_settings(MemCache[:settings]) + + populate_game_info + when Worker::Request::STATUS_IN_PROGRESS + status_bar.show + + status_bar_title.value = data["status"]["title"] + status_bar_label.value = data["status"]["label"] + status_bar_progress.value = data["status"]["fraction"] + when Worker::Request::STATUS_ERROR + status_bar.hide + + populate_game_info + + # FIXME: Present error to player + end + end end end end diff --git a/lib/states/interface.rb b/lib/states/interface.rb index b62d01d..f07f752 100644 --- a/lib/states/interface.rb +++ b/lib/states/interface.rb @@ -1,6 +1,8 @@ module W3DHubLauncher class States class Interface < W3DHubLauncher::State + attr_reader :application_task_status_bar_container + def setup super @@ -30,9 +32,9 @@ module W3DHubLauncher # stack(fill: true) # navigation container - flow(width: 1.0) do - link("GAMES", text_v_align: :center, font: FONT_BLACK, margin_left: PADDING) { page(Page::Games) } - link("SERVERS", text_v_align: :center, font: FONT_BLACK, margin_left: PADDING) { page(Page::ServerBrowser) } + flow(width: 1.0, fill: true) do + link("GAMES",height: 1.0, text_v_align: :center, font: FONT_BLACK, margin_left: PADDING) { page(Page::Games) } + link("SERVERS",height: 1.0, text_v_align: :center, font: FONT_BLACK, margin_left: PADDING) { page(Page::ServerBrowser) } stack(fill: true) image safe_get_image("#{ROOT_PATH}/media/icons/import.png"), height: 40, color: 0xff_bbbbbb, tip: "Downloads" do |img| dialog(Dialog::Downloads) @@ -40,31 +42,31 @@ module W3DHubLauncher image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 40, color: 0xff_bbbbbb, tip: "Notifications" end # application task status bar container - stack(width: 1.0, fill: true, margin_left: PADDING) do + @application_task_status_bar_container = stack(width: 1.0, fill: true, margin_left: PADDING, visible: false) do flow(width: 1.0) do - para "Updating Red Alert: A Path Beyond (Release)" + para "Updating Red Alert: A Path Beyond (Release)", tag: :status_bar_title stack(fill: true) - para "Fetching manifests..." + para "Fetching manifests...", tag: :status_bar_label end - progress(width: 1.0, fraction: 0.75) + progress(width: 1.0, fraction: 0.0, tag: :status_bar_progress) end end # self account container - flow(width: 400, height: 80, margin_left: LARGE_PADDING) do + @account_container = flow(width: 400, height: 80, margin_left: LARGE_PADDING) do # self avatar container - stack(width: 80, height: 1.0, background_image: rounded_avatar(safe_get_image("#{ROOT_PATH}/media/default.png"))) do |i| + stack(width: 80, height: 1.0, background_image: rounded_avatar(safe_get_image("#{ROOT_PATH}/media/default.png")), tag: :account_avatar) do |i| i.subscribe(:clicked_left_mouse_button) do dialog(Dialog::Account) end # self online state container - stack(width: 20, height: 20, v_align: :bottom, h_align: :right, background_image: safe_get_image("#{ROOT_PATH}/media/ui/circle_small.png"), background_image_color: 0xff_26a269) + stack(width: 20, height: 20, v_align: :bottom, h_align: :right, background_image: safe_get_image("#{ROOT_PATH}/media/ui/circle_small.png"), background_image_color: 0xff_26a269, tag: :account_online_state) end stack(fill: true, height: 1.0, margin_left: HALF_PADDING) do flow(fill: true) # self name - caption "cyberarm", font: FONT_BLACK, text_wrap: :none + caption "cyberarm", font: FONT_BLACK, text_wrap: :none, width: 1.0, tag: :account_name # self set online state link "Online ▼", text_size: 18 do |l| menu(parent: l) do diff --git a/lib/worker.rb b/lib/worker.rb index 328b245..f2fc6e6 100644 --- a/lib/worker.rb +++ b/lib/worker.rb @@ -140,6 +140,15 @@ module W3DHubLauncher @client&.flush end + def message_requester(request_id:, status:, data:, error: nil) + payload = { status: status, request_id: request_id, data: data, error: error }.to_json + + @client&.write(payload) + @client&.write(RESPONSE_SEPARATOR) + @client&.flush + end + + # Send request to server def request(query) # pp [:client_request, query] diff --git a/lib/worker/request.rb b/lib/worker/request.rb index e9c9342..c712207 100644 --- a/lib/worker/request.rb +++ b/lib/worker/request.rb @@ -3,12 +3,6 @@ module W3DHubLauncher class Request Query = Data.define(:type, :request_id, :data) - FETCH_URL = 0 - DOWNLOAD_URL = 1 - W3DHUB_API_CALL = 10 - LAUNCHER_SETTINGS = 1000 - LAUNCHER_UPDATE_SETTINGS = 1001 - STATUS_ERROR = -1 # request has failed STATUS_PENDING = 0 # request has not yet started STATUS_OK = 1 # request completed successfully @@ -54,9 +48,10 @@ module W3DHubLauncher def handle_event(event, data) # pp [event, data] + @callback&.call(data, event) + case event when STATUS_ERROR, STATUS_COMPLETE - @callback&.call(data) Request.requests.delete(self) end end diff --git a/lib/worker/task.rb b/lib/worker/task.rb index 90d1a74..3556304 100644 --- a/lib/worker/task.rb +++ b/lib/worker/task.rb @@ -40,12 +40,16 @@ module W3DHubLauncher @installation_directory ||= application_target_installation_directory + update_status(label: "Starting...", fraction: 0.0) + execute end def abort_task!(reason = "") puts reason + message_requester(Worker::Request::STATUS_ERROR, data: nil, error: reason) + raise reason end @@ -60,6 +64,8 @@ module W3DHubLauncher end def fetch_manifests(version = @target_version) + update_status(label: "Fetching manifests...", fraction: 0.0) + while (manifest = fetch_manifest(version)) @manifests[version] = manifest @@ -70,6 +76,8 @@ module W3DHubLauncher end def build_package_list + update_status(label: "Building package list...", fraction: 0.0) + channel_manifests = [] version = @target_version @@ -108,6 +116,8 @@ module W3DHubLauncher end def verify_files + update_status(label: "Verifying files...", fraction: 0.0) + @required_manifest_files = @manifest_files.clone # Process manifest game files in NEWEST to OLDEST order so that we don't erroneously flag @@ -135,6 +145,8 @@ module W3DHubLauncher end def fetch_packages + update_status(label: "Downloading packages...", fraction: 0.0) + required_packages = {} @required_manifest_files.each do |file| required_packages[file.version] ||= [] @@ -203,6 +215,8 @@ module W3DHubLauncher end def install_packages + update_status(label: "Installing...", fraction: 0.0) + create_directory(@installation_directory) processed_packages = {} @@ -225,6 +239,8 @@ module W3DHubLauncher end def remove_deleted_files + update_status(label: "Removing files...", fraction: 0.0) + @deleted_manifest_files.each do |manifest_file| file_path = normalize_path(manifest_file.name) @@ -253,14 +269,35 @@ module W3DHubLauncher # updated, and moved applications will overwrite existing application data in settings def mark_application_installed + app = Worker::Api::Settings::Application.create( + id: @application.id, + channel: @channel.id, + version: @target_version.to_s, + installation_path: @installation_directory, + wine_prefix_path: "", + launch_command: "%COMMAND%", + timestamp: Time.now.to_i + ) + + message_requester(Worker::Request::STATUS_COMPLETE, data: { application: app }) + puts "APPLICATION: #{@application.name} #{@application.id}:#{@channel.id}:#{@target_version} installed." end def mark_application_uninstalled + message_requester(Worker::Request::STATUS_COMPLETE, data: {}) end # helper functions + def message_requester(status = Worker::Request::STATUS_IN_PROGRESS, data:, error: nil) + @worker.message_requester(request_id: @request_id, status: status, data: data, error: error) + end + + def update_status(label:, fraction:) + message_requester(data: { status: { title: "TASK #{@application.name} (#{@channel.name})", label: label, fraction: fraction } } ) + end + def application_target_installation_directory target_application = @worker.settings.applications.find { |app| app.id == @application.id && app.channel == @channel.id } if target_application