5 Commits

10 changed files with 213 additions and 128 deletions

12
Gemfile
View File

@@ -18,9 +18,9 @@ gem "win32-security", platforms: [:windows]
# use `bundle _x.y.z_ COMMAND` to use this one... # use `bundle _x.y.z_ COMMAND` to use this one...
# NOTE: Releasy needs to be installed as a system gem i.e. `rake install` # NOTE: Releasy needs to be installed as a system gem i.e. `rake install`
# NOTE: contents of the `gemhome` folder in the packaged folder need to be moved into the lib/ruby/gems\<RUBY_VERSION> folder # NOTE: contents of the `gemhome` folder in the packaged folder need to be moved into the lib/ruby/gems\<RUBY_VERSION> folder
group :windows_packaging do # group :windows_packaging do
gem "bundler", "~>2.4.3" # gem "bundler", "~>2.4.3"
gem "rake" # gem "rake"
gem "ocran" # gem "ocran"
gem "releasy"#, path: "../releasy" # gem "releasy"#, path: "../releasy"
end # end

View File

@@ -1,13 +1,13 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
async (2.35.1) async (2.35.2)
console (~> 1.29) console (~> 1.29)
fiber-annotation fiber-annotation
io-event (~> 1.11) io-event (~> 1.11)
metrics (~> 0.12) metrics (~> 0.12)
traces (~> 0.18) traces (~> 0.18)
async-http (0.93.0) async-http (0.94.0)
async (>= 2.10.2) async (>= 2.10.2)
async-pool (~> 0.11) async-pool (~> 0.11)
io-endpoint (~> 0.14) io-endpoint (~> 0.14)
@@ -30,7 +30,6 @@ GEM
fiber-annotation fiber-annotation
fiber-local (~> 1.1) fiber-local (~> 1.1)
json json
cri (2.15.12)
cyberarm_engine (0.25.0) cyberarm_engine (0.25.0)
gosu (~> 1.1) gosu (~> 1.1)
digest-crc (0.7.0) digest-crc (0.7.0)
@@ -52,13 +51,11 @@ GEM
libui (0.2.0-x64-mingw-ucrt) libui (0.2.0-x64-mingw-ucrt)
fiddle fiddle
metrics (0.15.0) metrics (0.15.0)
ocran (1.3.17)
fiddle (~> 1.0)
protocol-hpack (1.5.1) protocol-hpack (1.5.1)
protocol-http (0.58.0) protocol-http (0.58.0)
protocol-http1 (0.36.0) protocol-http1 (0.36.0)
protocol-http (~> 0.58) protocol-http (~> 0.58)
protocol-http2 (0.23.0) protocol-http2 (0.24.0)
protocol-hpack (~> 1.4) protocol-hpack (~> 1.4)
protocol-http (~> 0.47) protocol-http (~> 0.47)
protocol-rack (0.21.0) protocol-rack (0.21.0)
@@ -70,11 +67,6 @@ GEM
protocol-http (~> 0.2) protocol-http (~> 0.2)
rack (3.2.4) rack (3.2.4)
rake (13.3.1) rake (13.3.1)
releasy (0.2.4)
bundler (>= 1.2.1)
cri (~> 2.15.0)
ocran (~> 1.3.0)
rake (>= 0.9.2.2)
rexml (3.4.4) rexml (3.4.4)
rubyzip (3.2.2) rubyzip (3.2.2)
sdl2-bindings (0.2.3) sdl2-bindings (0.2.3)
@@ -88,19 +80,16 @@ GEM
PLATFORMS PLATFORMS
x64-mingw-ucrt x64-mingw-ucrt
x86_64-linux
DEPENDENCIES DEPENDENCIES
async-http async-http
async-websocket async-websocket
base64 base64
bundler (~> 2.4.3)
cyberarm_engine cyberarm_engine
digest-crc digest-crc
ircparser ircparser
libui libui
ocran
rake
releasy
rexml rexml
rubyzip rubyzip
sdl2-bindings sdl2-bindings
@@ -108,4 +97,4 @@ DEPENDENCIES
win32-security win32-security
BUNDLED WITH BUNDLED WITH
2.4.22 2.6.8

View File

@@ -86,15 +86,15 @@ class W3DHub
# open wwconfig.exe or config.exe for ecw # open wwconfig.exe or config.exe for ecw
if (app_data = installed?(app_id, channel) && W3DHub.unix?) return unless (app_data = installed?(app_id, channel) && W3DHub.unix?)
exe = if Store.settings[:wine_prefix]
"WINEPREFIX=\"#{Store.settings[:wine_prefix]}\" winecfg"
else
"winecfg"
end
Process.spawn("#{exe}") exe = if !Store.settings[:wine_prefix].to_s.empty?
end "WINEPREFIX=\"#{Store.settings[:wine_prefix]}\" winecfg"
else
"winecfg"
end
Process.spawn(exe)
end end
def repair(app_id, channel) def repair(app_id, channel)
@@ -169,7 +169,7 @@ class W3DHub
def wine_command(app_id, channel) def wine_command(app_id, channel)
return "" if W3DHub.windows? return "" if W3DHub.windows?
if Store.settings[:wine_prefix] if !Store.settings[:wine_prefix].to_s.empty?
"WINEPREFIX=\"#{Store.settings[:wine_prefix]}\" \"#{Store.settings[:wine_command]}\" " "WINEPREFIX=\"#{Store.settings[:wine_prefix]}\" \"#{Store.settings[:wine_command]}\" "
else else
"#{Store.settings[:wine_command]} " "#{Store.settings[:wine_command]} "

View File

@@ -183,7 +183,8 @@ class W3DHub
# Wine present? # Wine present?
if W3DHub.unix? if W3DHub.unix?
wine_present = W3DHub.command("which #{Store.settings[:wine_command]}") wine_present = W3DHub.command("which #{Store.settings[:wine_command]}")
fail!("FAIL FAST: `which #{Store.settings[:wine_command]}` command failed, wine is not installed. Will be unable to create prefixes or launch games.") unless wine_present fail!("FAIL FAST: `which #{Store.settings[:wine_command]}` command failed, wine is not installed.\n\n"\
"Will be unable to launch game.\n\nCheck wine options in launcher's settings.") unless wine_present
end end
end end

View File

@@ -140,18 +140,16 @@ class W3DHub
end end
status.zero? status.zero?
else elsif block
if block IO.popen(command, "r") do |io|
IO.popen(command, "r") do |io| io.each_line do |line|
io.each_line do |line| block&.call(line)
block&.call(line)
end
end end
$CHILD_STATUS.success?
else
system(command)
end end
$CHILD_STATUS.success?
else
system(command)
end end
end end
@@ -159,23 +157,26 @@ class W3DHub
File.expand_path("~") File.expand_path("~")
end end
def self.ask_file(title: "Open File", filter: "*game*.exe") def self.ask_file(title: "Open File", filter: "*game*.exe", filters: [])
filters << filter if filters.empty?
if W3DHub.unix? if W3DHub.unix?
# search for command # search for command
cmds = %w{ zenity matedialog qarma kdialog } cmds = %w[zenity matedialog qarma kdialog]
command = cmds.find do |cmd| command = cmds.find do |cmd|
cmd if system("which #{cmd}") cmd if system("which #{cmd}")
end end
path = case File.basename(command) path = case File.basename(command)
when "zenity", "matedialog", "qarma" when "zenity", "matedialog", "qarma"
`#{command} --file-selection --title "#{title}" --file-filter "#{filter}"` options = filters.map { |s| format("--file-filter=\"%s\"", s) }.join(" ")
when "kdialog" `#{command} --file-selection --title \"#{title}\" #{options}`
`#{command} --title "#{title}" --getopenfilename . "#{filter}"` when "kdialog"
else `#{command} --title "#{title}" --getopenfilename . "#{filters.join(" ")}"`
raise "No known command found for system file selection dialog!" else
end raise "No known command found for system file selection dialog!"
end
path.strip path.strip
else else
@@ -189,20 +190,20 @@ class W3DHub
def self.ask_folder(title: "Open Folder") def self.ask_folder(title: "Open Folder")
if W3DHub.unix? if W3DHub.unix?
# search for command # search for command
cmds = %w{ zenity matedialog qarma kdialog } cmds = %w[zenity matedialog qarma kdialog]
command = cmds.find do |cmd| command = cmds.find do |cmd|
cmd if system("which #{cmd}") cmd if system("which #{cmd}")
end end
path = case File.basename(command) path = case File.basename(command)
when "zenity", "matedialog", "qarma" when "zenity", "matedialog", "qarma"
`#{command} --file-selection --directory --title "#{title}"` `#{command} --file-selection --directory --title "#{title}"`
when "kdialog" when "kdialog"
`#{command} --title "#{title}" --getexistingdirectory #{Dir.home}"` `#{command} --title "#{title}" --getexistingdirectory #{Dir.home}"`
else else
raise "No known command found for system file selection dialog!" raise "No known command found for system file selection dialog!"
end end
path.strip path.strip
else else

View File

@@ -278,7 +278,7 @@ class W3DHub
end end
# Game Events # Game Events
@game_events_container = flow(width: 1.0, height: 128, padding: 8, visible: false) do @game_events_container = stack(width: 1.0, height: 128, padding: 8, scroll: true, visible: false) do
end end
# Game News # Game News
@@ -513,15 +513,15 @@ class W3DHub
@game_events_container.show unless events.empty? @game_events_container.show unless events.empty?
@game_events_container.hide if events.empty? @game_events_container.hide if events.empty?
@game_events_container.clear do return unless (event = events.flatten.first)
events.flatten.each do |event|
stack(fill: true, height: 1.0, margin_left: 8, margin_right: 8, border_thickness: 1, border_color: lighten(Gosu::Color.new(game.color))) do
background 0x44_000000
title event.title, width: 1.0, text_align: :center @game_events_container.clear do
title event.start_time.strftime("%A"), width: 1.0, text_align: :center stack(width: 1.0, fill: true, margin_left: 8, margin_right: 8, border_thickness: 1, border_color: lighten(Gosu::Color.new(game.color))) do
caption event.start_time.strftime("%B %e, %Y %l:%M %p"), width: 1.0, text_align: :center background 0x44_000000
end
title event.title, width: 1.0, text_align: :center
title event.start_time.strftime("%A"), width: 1.0, text_align: :center
caption event.start_time.strftime("%B %e, %Y %l:%M %p"), width: 1.0, text_align: :center
end end
end end
end end

View File

@@ -7,47 +7,74 @@ class W3DHub
background 0xaa_252525 background 0xaa_252525
stack(width: 1.0, fill: true, max_width: 720, h_align: :center, scroll: true) do stack(width: 1.0, fill: true, max_width: 720, h_align: :center, scroll: true) do
stack(width: 1.0, height: 112) do tagline "Launcher Language"
tagline "Launcher Language" @language_menu = list_box items: I18n.available_locales.map { |l| expand_language_code(l.to_s) }, choose: expand_language_code(Store.settings[:language]), width: 1.0, margin_left: 16
@language_menu = list_box items: I18n.available_locales.map { |l| expand_language_code(l.to_s) }, choose: expand_language_code(Store.settings[:language]), width: 1.0, margin_left: 16 para "Select the UI language you'd like to use in the W3D Hub Launcher.", margin_left: 16
para "Select the UI language you'd like to use in the W3D Hub Launcher.", margin_left: 16
tagline "Launcher Directories", margin_top: 16
caption "Applications Install Directory", margin_left: 16
flow(width: 1.0, margin_left: 16) do
@app_install_dir_input = edit_line Store.settings[:app_install_dir], fill: true
button "Browse...", width: 128, tip: "Browse for applications install directory" do
path = W3DHub.ask_folder
@app_install_dir_input.value = path unless path.empty?
end
end end
caption "Package Cache Directory", margin_left: 16, margin_top: 16
stack(width: 1.0, height: 200, margin_top: 16) do flow(width: 1.0, margin_left: 16) do
tagline "Launcher Directories" @package_cache_dir_input = edit_line Store.settings[:package_cache_dir], fill: true
caption "Applications Install Directory", margin_left: 16 button "Browse...", width: 128, tip: "Browse for package cache directory" do
flow(width: 1.0, fill: true, margin_left: 16) do path = W3DHub.ask_folder
@app_install_dir_input = edit_line Store.settings[:app_install_dir], fill: true @package_cache_dir_input.value = path unless path.empty?
button "Browse...", width: 128, tip: "Browse for applications install directory" do
path = W3DHub.ask_folder
@app_install_dir_input.value = path unless path.empty?
end
end
caption "Package Cache Directory", margin_left: 16, margin_top: 16
flow(width: 1.0, fill: true, margin_left: 16) do
@package_cache_dir_input = edit_line Store.settings[:package_cache_dir], fill: true
button "Browse...", width: 128, tip: "Browse for package cache directory" do
path = W3DHub.ask_folder
@package_cache_dir_input.value = path unless path.empty?
end
end end
end end
if W3DHub.unix? if W3DHub.unix?
stack(width: 1.0, height: 224, margin_top: 16) do tagline "Wine - Windows compatibility layer", margin_top: 16
tagline "Wine - Windows compatibility layer" caption "Wine Command", margin_left: 16
caption "Wine Command", margin_left: 16 flow(width: 1.0, margin_left: 16) do
@wine_command_input = edit_line Store.settings[:wine_command], width: 1.0, margin_left: 16 @wine_command_input = edit_line Store.settings[:wine_command], fill: true
para "Command to use to for Windows compatiblity layer.", margin_left: 16 button "Browse...", width: 128, tip: "Browse for wine executable" do
path = W3DHub.ask_file(filters: %w[wine proton])
caption "Wine Prefix", margin_left: 16, margin_top: 16 @wine_command_input.value = path unless path.empty?
flow(width: 1.0, height: 48, margin_left: 16) do
@wine_prefix_toggle = toggle_button checked: Store.settings[:wine_prefix], enabled: false
para "Whether each game gets its own prefix. Uses global/default prefix by default."
end end
end end
para "Command to use to for Windows compatiblity layer.", margin_left: 16
caption "Wine Prefix", margin_left: 16, margin_top: 16
flow(width: 1.0, margin_left: 16) do
@wine_prefix_input = edit_line Store.settings[:wine_prefix], fill: true
button "Browse...", width: 128, tip: "Browse for wine prefix directory" do
path = W3DHub.ask_folder
@wine_prefix_input.value = path unless path.empty?
end
end
para "Leave empty to use default global prefix.", margin_left: 16
link "Wiki: Getting Started With Wine", tip: "https://github.com/cyberarm/w3d_hub_linux_launcher/wiki/Getting-Started-With-Wine", margin_top: 16, margin_left: 16, border_color_bottom: 0xff_777777 do
W3DHub.url("https://github.com/cyberarm/w3d_hub_linux_launcher/wiki/Getting-Started-With-Wine")
end
# TODO: support winetricks stuff
# tagline "Winetricks", margin_top: 16
# caption "Winetricks Command", margin_left: 16
# flow(width: 1.0, margin_left: 16) do
# @winetricks_command_input = edit_line Store.settings[:winetricks_command], fill: true, enabled: false
# button "Browse...", width: 128, tip: "Browse for winetricks executable", enabled: false do
# path = W3DHub.ask_file(filters: %w[winetricks protontricks])
# @winetricks_command_input.value = path unless path.empty?
# end
# end
# caption "Fixups", margin_left: 16, margin_top: 16
# button "Install d3dcompiler_47", margin_left: 16, enabled: false
# para "Fixes games instantly crashing at startup due to not being able to compile shaders.", margin_left: 16
# button "Install DXVK", margin_left: 16, margin_top: 16, enabled: false
# para "Use Vulkan-based DirectX translation layers.", margin_left: 16
# para "WARNING: Games will stop working if your hardware does not support Vulkan!", margin_left: 16
end end
end end
@@ -55,10 +82,9 @@ class W3DHub
button "Save", width: 1.0 do button "Save", width: 1.0 do
save_settings! save_settings!
end end
flow(fill: true) flow(fill: true)
end end
button("Clear package cache: #{W3DHub.format_size(Dir.glob("#{Store.settings[:package_cache_dir]}/**/**").map { |f| File.file?(f) ? File.size(f) : 0}.sum)}", tip: "Purge #{Store.settings[:package_cache_dir]}", **DANGEROUS_BUTTON) do |btn| button("Clear package cache: #{W3DHub.format_size(Dir.glob("#{Store.settings[:package_cache_dir]}/**/**").map { |f| File.file?(f) ? File.size(f) : 0}.sum)}", tip: "Purge #{Store.settings[:package_cache_dir]}", **DANGEROUS_BUTTON) do |btn|
logger.info(LOG_TAG) { "Purging cache (#{Store.settings[:package_cache_dir]})..." } logger.info(LOG_TAG) { "Purging cache (#{Store.settings[:package_cache_dir]})..." }
FileUtils.remove_dir(Store.settings[:package_cache_dir], force: true) FileUtils.remove_dir(Store.settings[:package_cache_dir], force: true)
@@ -106,7 +132,9 @@ class W3DHub
Store.settings[:package_cache_dir] = @package_cache_dir_input.value Store.settings[:package_cache_dir] = @package_cache_dir_input.value
Store.settings[:wine_command] = @wine_command_input.value Store.settings[:wine_command] = @wine_command_input.value
Store.settings[:wine_prefix] = @wine_prefix_toggle.value Store.settings[:wine_prefix] = @wine_prefix_input.value
Store.settings[:winetricks_command] = @winetricks_command_input.value if @winetricks_command_input
Store.settings.save_settings Store.settings.save_settings

View File

@@ -7,7 +7,8 @@ class W3DHub
package_cache_dir: default_package_cache_dir, package_cache_dir: default_package_cache_dir,
parallel_downloads: 4, parallel_downloads: 4,
wine_command: "wine", wine_command: "wine",
create_wine_prefixes: true, wine_prefix: "",
winetricks_command: "winetricks",
allow_diagnostic_reports: false, allow_diagnostic_reports: false,
server_list_username: "", server_list_username: "",
server_list_filters: {}, server_list_filters: {},
@@ -66,6 +67,14 @@ class W3DHub
def load_settings def load_settings
@settings = JSON.parse(File.read(SETTINGS_FILE_PATH), symbolize_names: true) @settings = JSON.parse(File.read(SETTINGS_FILE_PATH), symbolize_names: true)
# FIXUPS
# FOR: v0.9.0
@settings.delete(:create_wine_prefixes)
@settings[:wine_prefix] ||= ""
@settings[:winetricks_command] ||= "winetricks"
@settings
end end
def save_settings def save_settings

View File

@@ -10,7 +10,7 @@ class W3DHub
flow(width: 1.0, height: 1.0, background_image: "#{GAME_ROOT_PATH}/media/banners/background.png", background_image_color: 0xff_525252, background_image_mode: :fill) do flow(width: 1.0, height: 1.0, background_image: "#{GAME_ROOT_PATH}/media/banners/background.png", background_image_color: 0xff_525252, background_image_mode: :fill) do
flow(fill: true) flow(fill: true)
@card_container = stack(width: 1.0, max_width: MAX_PAGE_WIDTH, height: 1.0, max_height: 720, margin: 128, padding: 16) do @card_container = stack(width: 1.0, max_width: MAX_PAGE_WIDTH, height: 1.0, max_height: 720, margin: 64, v_align: :center, h_align: :center, padding: 16) do
background 0xaa_353535 background 0xaa_353535
end end
@@ -24,9 +24,12 @@ class W3DHub
def card_welcome def card_welcome
stack(width: 1.0, fill: true) do stack(width: 1.0, fill: true) do
banner "Welcome", width: 1.0, border_thickness_bottom: 4, border_color_bottom: 0xff_000000 banner "Welcome", width: 1.0, border_thickness_bottom: 4, border_color_bottom: 0xff_0074e0
title "Welcome to the #{I18n.t(:app_name_simple)}" title "Welcome to the #{I18n.t(:app_name_simple)}"
caption "The #{I18n.t(:app_name_simple)} is a one-stop shop for your W3D gaming needs, providing game downloads, automatic updating, an integrated server browser, and centralized management of in-game options.", width: 1.0, margin_left: 32 caption "The #{I18n.t(:app_name_simple)} is a one-stop shop for your W3D gaming needs, providing game downloads, "\
"automatic updating, an integrated server browser, and centralized management of in-game options.", width: 1.0, margin_left: 32
image "#{GAME_ROOT_PATH}/media/icons/app.png", height: 256
end end
flow(width: 1.0, height: 46) do flow(width: 1.0, height: 46) do
@@ -44,14 +47,25 @@ class W3DHub
def card_getting_started def card_getting_started
stack(width: 1.0, fill: true) do stack(width: 1.0, fill: true) do
banner "Getting Started", width: 1.0, border_thickness_bottom: 4, border_color_bottom: 0xff_000000 banner "Getting Started", width: 1.0, border_thickness_bottom: 4, border_color_bottom: 0xff_0074e0
title "Import C&C Renegade" title "Import Command & Conquer: Renegade"
caption "You can import your installed copy of Renegade if it wasn't automatically imported from the Games tab. If you need to procure a copy of Renegade, EA's Origin Store has the Command & Conquer The Ultimate Collection available. We cannot provide Renegade for installation.", width: 1.0, margin_left: 32 caption "You can import your installed copy of Renegade if it wasn't automatically imported from the Games tab.\n"\
"If you need to procure a copy of Renegade, Both Steam and the EA App have the Command & Conquer The Ultimate Collection available for purchase. "\
"We cannot provide Renegade for installation.", width: 1.0, margin_left: 32
stack(width: 1.0, height: 2, background: 0x88_ffffff) stack(width: 1.0, height: 2, background: 0xff_0074e0, margin_top: 16, margin_bottom: 16)
title "Install one of our standalone games" title "Install one of our standalone games"
caption "Browse our selection of games from the left panel of the Games tab.\n• Interim Apex - Renegade but with hundreds of vehicles and characters.\n• Red Alert: A Path Beyond - DESCRIPTION\n• Tiberian Sun: Reborn - DESCRIPTION\n\nAnd more... Check out the left panel on the Games tab.", width: 1.0, margin_left: 32 stack(width: 1.0, fill: true, margin_left: 32) do
tagline "Interim Apex"
caption "An expanded boots on the ground conflict set after the advent of Tiberian Dawn and the inter-war period between Tiberian Dawn and Tiberian Sun.", margin_left: 16
tagline "Red Alert 2: Apocalypse Rising"
caption "A multiplayer first-and-third-person shooter set in the vibrant universe of Command & Conquer: Red Alert 2. ", margin_left: 16
tagline "Tiberian Sun: Reborn"
caption "A standalone first-person shooter set in the Tiberian Sun universe.", margin_left: 16
para ""
caption "And more games! See them all on the Games tab."
end
end end
flow(width: 1.0, height: 46) do flow(width: 1.0, height: 46) do
@@ -66,25 +80,22 @@ class W3DHub
end end
button "Next >" do button "Next >" do
@card_container.clear { card_communitiy } @card_container.clear { W3DHub.unix? ? card_wine : card_community }
end end
end end
end end
def card_communitiy def card_wine
stack(width: 1.0, fill: true) do stack(width: 1.0, fill: true) do
banner "W3D Hub Community", width: 1.0, border_thickness_bottom: 4, border_color_bottom: 0xff_000000 banner "Wine - Windows compatibility layer", width: 1.0, border_thickness_bottom: 4, border_color_bottom: 0xff_0074e0
title "Forums" stack(width: 1.0, fill: true, margin_left: 32) do
caption "Join our forum community", margin_left: 32 title "Got Wine?"
caption "The launcher requires a windows compatibility tool like wine in order to run the games.", margin_left: 32
title "Facebook" caption "Install wine and winetricks through your distribution's package manager or use a wine manager like Bottles.", margin_left: 32
caption "Like us on Facebook", margin_left: 32 link "See most up to date instructions on the wiki.", tip: "https://github.com/cyberarm/w3d_hub_linux_launcher/wiki/Getting-Started-With-Wine", margin_top: 16, margin_left: 32, border_color_bottom: 0xff_777777 do
W3DHub.url("https://github.com/cyberarm/w3d_hub_linux_launcher/wiki/Getting-Started-With-Wine")
title "Discord" end
caption "Join our Discord community server", margin_left: 32 end
title "YouTube"
caption "Subscribe to our YouTube channel", margin_left: 32
end end
flow(width: 1.0, height: 46) do flow(width: 1.0, height: 46) do
@@ -92,6 +103,52 @@ class W3DHub
button "< Back" do button "< Back" do
@card_container.clear { card_getting_started } @card_container.clear { card_getting_started }
end end
link "Skip", border_color_bottom: 0xff_777777, margin_left: 16 do
pop_state
end
end
button "Next >" do
@card_container.clear { card_community }
end
end
end
def card_community
stack(width: 1.0, fill: true) do
banner "W3D Hub Community", width: 1.0, border_thickness_bottom: 4, border_color_bottom: 0xff_0074e0
title "W3D Hub"
link "Visit website", tip: "https://w3dhub.com", margin_left: 32, border_color_bottom: 0xff_777777 do
W3DHub.url("https://w3dhub.com")
end
title "Forum"
link "Join our forum community", tip: "https://w3dhub.com/forum", margin_left: 32, border_color_bottom: 0xff_777777 do
W3DHub.url("https://w3dhub.com/forum")
end
title "Facebook"
link "Like us on Facebook", tip: "https://www.facebook.com/w3dhub/", margin_left: 32, border_color_bottom: 0xff_777777 do
W3DHub.url("https://www.facebook.com/w3dhub/")
end
title "Discord"
link "Join our Discord community server", tip: "https://discord.gg/jMmmRa2", margin_left: 32, border_color_bottom: 0xff_777777 do
W3DHub.url("https://discord.gg/jMmmRa2")
end
title "YouTube"
link "Subscribe to our YouTube channel", tip: "https://www.youtube.com/@w3dhub-official", margin_left: 32, border_color_bottom: 0xff_777777 do
W3DHub.url("https://www.youtube.com/@w3dhub-official")
end
end
flow(width: 1.0, height: 46) do
flow(fill: true, height: 1.0) do
button "< Back" do
@card_container.clear { W3DHub.unix? ? card_wine : card_getting_started }
end
end end
button "Done" do button "Done" do

View File

@@ -17,8 +17,8 @@ class W3DHub
end end
# push_state(W3DHub::States::DemoInputDelay) # push_state(W3DHub::States::DemoInputDelay)
# push_state(W3DHub::States::Welcome)
push_state(W3DHub::States::Boot) push_state(W3DHub::States::Boot)
push_state(W3DHub::States::Welcome) unless File.exist?(SETTINGS_FILE_PATH)
# push_state(W3DHub::States::DirectConnectDialog) # push_state(W3DHub::States::DirectConnectDialog)
# push_state(W3DHub::Asterisk::States::IRCProfileForm) # push_state(W3DHub::Asterisk::States::IRCProfileForm)
end end