From abeb20fd97e55d855907dcc6411938ecb876f175 Mon Sep 17 00:00:00 2001
From: icenine451 <benjamin.r.shelton@protonmail.com>
Date: Mon, 8 May 2023 14:24:41 -0400
Subject: [PATCH] Add Version history to Configurator Add RA token function
 Rework Configurator menus, prep for upcoming features Add starter preset
 configs for some systems Add initial preset sections to retrodeck.cfg

---
 .../reference_lists/incompatible_presets.cfg  |   2 +
 .../presets/Duckstation_presets.cfg           |   6 +
 .../reference_lists/presets/PCSX2_presets.cfg |   6 +
 .../reference_lists/presets/SNES_presets.cfg  |   7 +
 emu-configs/defaults/retrodeck/retrodeck.cfg  |  18 +-
 functions.sh                                  | 239 +++++++++++++++++-
 global.sh                                     |   3 +
 tools/configurator.sh                         | 146 +++++++++--
 8 files changed, 395 insertions(+), 32 deletions(-)
 create mode 100644 emu-configs/defaults/retrodeck/reference_lists/incompatible_presets.cfg
 create mode 100644 emu-configs/defaults/retrodeck/reference_lists/presets/Duckstation_presets.cfg
 create mode 100644 emu-configs/defaults/retrodeck/reference_lists/presets/PCSX2_presets.cfg
 create mode 100644 emu-configs/defaults/retrodeck/reference_lists/presets/SNES_presets.cfg

diff --git a/emu-configs/defaults/retrodeck/reference_lists/incompatible_presets.cfg b/emu-configs/defaults/retrodeck/reference_lists/incompatible_presets.cfg
new file mode 100644
index 00000000..417ab816
--- /dev/null
+++ b/emu-configs/defaults/retrodeck/reference_lists/incompatible_presets.cfg
@@ -0,0 +1,2 @@
+borders:widescreen
+widescreen:borders
diff --git a/emu-configs/defaults/retrodeck/reference_lists/presets/Duckstation_presets.cfg b/emu-configs/defaults/retrodeck/reference_lists/presets/Duckstation_presets.cfg
new file mode 100644
index 00000000..c74d90ac
--- /dev/null
+++ b/emu-configs/defaults/retrodeck/reference_lists/presets/Duckstation_presets.cfg
@@ -0,0 +1,6 @@
+config_file_format^duckstation
+target_file^filesystem/var/data/duckstation/settings.ini
+defaults_file^$emuconfigs/duckstation/settings.ini
+change^cheevos^Enabled^true^Cheevos
+change^cheevos^Username^$cheevos_username^Cheevos
+change^cheevos^Token^$cheevos_token^Cheevos
diff --git a/emu-configs/defaults/retrodeck/reference_lists/presets/PCSX2_presets.cfg b/emu-configs/defaults/retrodeck/reference_lists/presets/PCSX2_presets.cfg
new file mode 100644
index 00000000..07e77854
--- /dev/null
+++ b/emu-configs/defaults/retrodeck/reference_lists/presets/PCSX2_presets.cfg
@@ -0,0 +1,6 @@
+config_file_format^pcsx2
+target_file^$pcsx2qtconf
+defaults_file^$emuconfigs/PCSX2/PCSX2.ini
+change^cheevos^Enabled^true^Achievements
+change^cheevos^Username^$cheevos_username^Achievements
+change^cheevos^Token^$cheevos_token^Achievements
diff --git a/emu-configs/defaults/retrodeck/reference_lists/presets/SNES_presets.cfg b/emu-configs/defaults/retrodeck/reference_lists/presets/SNES_presets.cfg
new file mode 100644
index 00000000..e0330b7f
--- /dev/null
+++ b/emu-configs/defaults/retrodeck/reference_lists/presets/SNES_presets.cfg
@@ -0,0 +1,7 @@
+config_file_format^retroarch
+target_file^filesystem/var/config/retroarch/config/Snes9x/snes.cfg
+defaults_file^$raconf
+change^cheevos^cheevos_enable^true
+change^cheevos^cheevos_token^$cheevos_token
+change^cheevos^cheevos_username^$cheevos_username
+change^cheevos_hardcore^cheevos_hardcore_mode_enable^true
diff --git a/emu-configs/defaults/retrodeck/retrodeck.cfg b/emu-configs/defaults/retrodeck/retrodeck.cfg
index 52553139..60cf8f63 100644
--- a/emu-configs/defaults/retrodeck/retrodeck.cfg
+++ b/emu-configs/defaults/retrodeck/retrodeck.cfg
@@ -27,14 +27,16 @@ ask_default_user=true
 default_user=
 developer_options=false
 
+[cheevos]
+PCSX2=false
+Duckstation=false
+SNES=false
+
+[cheevos_hardcore]
+SNES=false
+
 [borders]
-snes=false
-genesis=false
-gb=false
-gba=false
+SNES=false
 
 [widescreen]
-snes=false
-genesis=false
-gb=false
-gba=false
+SNES=false
diff --git a/functions.sh b/functions.sh
index 5402b7ba..2d792662 100644
--- a/functions.sh
+++ b/functions.sh
@@ -456,6 +456,46 @@ add_setting_line() {
   esac
 }
 
+add_setting() {
+  # This function will add a setting name and value to a file. This is useful for dynamically generated config files like Retroarch override files.
+  # USAGE: add_setting $setting_file $setting_name $setting_value $system $section (optional)
+
+  local current_setting_name=$(sed -e 's^\\^\\\\^g;s^`^\\`^g' <<< "$2")
+  local current_setting_value=$(sed -e 's^\\^\\\\^g;s^`^\\`^g' <<< "$3")
+  local current_section_name=$(sed -e 's/%/\\%/g' <<< "$5")
+
+  case $4 in
+
+  "retroarch" )
+    if [[ -z $current_section_name ]]; then
+      sed -i '$ a '"$current_setting_name"' = "'"$current_setting_value"'"' $1
+    else
+      sed -i '/^\s*?\['"$current_section_name"'\]|\b'"$current_section_name"':$/a '"$current_setting_name"' = "'"$current_setting_value"'"' $1
+    fi
+    ;;
+
+  esac
+}
+
+delete_setting() {
+  # This function will delete a setting line from a file. This is useful for dynamically generated config files like Retroarch override files
+  # USAGE: delete_setting $setting_file $setting_name $system $section (optional)
+
+  local current_setting_name=$(sed -e 's^\\^\\\\^g;s^`^\\`^g' <<< "$2")
+  local current_section_name=$(sed -e 's/%/\\%/g' <<< "$4")
+
+  case $3 in
+
+  "retroarch" )
+    if [[ -z $current_section_name ]]; then
+      sed -i '\^'"$current_setting_name"'^d' "$1"
+      sed -i '/^$/d' "$1" # Cleanup empty lines left behind
+    fi
+    ;;
+
+  esac
+}
+
 disable_setting() {
   # This function will add a '#' to the beginning of a defined setting line, disabling it.
   # USAGE: disable_setting $setting_file $setting_line $system $section (optional)
@@ -512,6 +552,91 @@ enable_file() {
   mv $(realpath $1.disabled) $(realpath $(echo $1 | sed -e 's/\.disabled//'))
 }
 
+build_preset_config(){
+  local system_being_changed="$1"
+  shift
+  local presets_being_changed="$*"
+  for preset in $presets_being_changed
+  do
+    current_preset="$preset"
+    local preset_section=$(sed -n '/\['"$current_preset"'\]/, /\[/{ /\['"$current_preset"'\]/! { /\[/! p } }' $rd_conf | sed '/^$/d')
+    while IFS= read -r system_line
+    do
+      local read_system_name=$(get_setting_name "$system_line")
+      if [[ "$read_system_name" == "$system_being_changed" ]]; then
+        local read_system_enabled=$(get_setting_value "$rd_conf" "$read_system_name" "retrodeck" "$current_preset")
+        while IFS='^' read -r action read_preset read_setting_name new_setting_value section
+        do
+          case "$action" in
+
+          "config_file_format" )
+            local read_config_format="$read_preset"
+          ;;
+
+          "target_file" )
+            if [[ "$read_preset" = \$* ]]; then
+              eval read_preset=$read_preset
+            fi
+            local read_target_file="$read_preset"
+          ;;
+
+          "defaults_file" )
+            if [[ "$read_preset" = \$* ]]; then
+              eval read_preset=$read_preset
+            fi
+            local read_defaults_file="$read_preset"
+          ;;
+
+          "change" )
+            if [[ "$read_preset" == "$current_preset" ]]; then
+              if [[ "$read_system_enabled" == "true" ]]; then
+                if [[ "$new_setting_value" = \$* ]]; then
+                  eval new_setting_value=$new_setting_value
+                fi
+                if [[ "$read_config_format" == "retroarch" ]]; then # Generate the override file
+                  if [[ -z $(grep "$read_setting_name" "$read_target_file") ]]; then
+                    if [[ ! -f "$read_target_file" ]]; then
+                      mkdir -p "$(realpath $(dirname "$read_target_file"))"
+                      echo "$read_setting_name = ""$new_setting_value""" > "$read_target_file"
+                    else
+                      add_setting "$read_target_file" "$read_setting_name" "$new_setting_value" "$read_config_format" "$section"
+                    fi
+                  else
+                    set_setting_value "$read_target_file" "$read_setting_name" "$new_setting_value" "$read_config_format" "$section"
+                  fi
+                else
+                  set_setting_value "$read_target_file" "$read_setting_name" "$new_setting_value" "$read_config_format" "$section"
+                fi
+              else
+                if [[ "$read_config_format" == "retroarch" ]]; then
+                  if [[ -f "$read_target_file" ]]; then
+                    delete_setting "$read_target_file" "$read_setting_name" "$read_config_format" "$section"
+                    if [[ -z $(cat "$read_target_file") ]]; then # If the override file is empty
+                      rm -f "$read_target_file"
+                    fi
+                    if [[ -z $(ls -1 $(dirname "$read_target_file")) ]]; then # If the override folder is empty
+                      rmdir "$(dirname $read_target_file)"
+                    fi
+                  fi
+                else
+                  local default_setting_value=$(get_setting_value "$read_defaults_file" "$read_setting_name" "$read_config_format" "$section")
+                  set_setting_value "$read_target_file" "$read_setting_name" "$default_setting_value" "$read_config_format" "$section"
+                fi
+              fi
+            fi
+          ;;
+
+          * )
+            echo "Other data: $action $read_preset $read_setting_name $new_setting_value $section" # DEBUG
+          ;;
+
+          esac
+        done < <(eval cat "$presets_reference_lists_dir/$read_system_name"_presets.cfg)
+      fi
+    done < <(printf '%s\n' "$preset_section")
+  done
+}
+
 generate_single_patch() {
   # generate_single_patch $original_file $modified_file $patch_file $system
 
@@ -808,7 +933,7 @@ update_rd_conf() {
   cp $rd_defaults $rd_conf # Copy defaults file into place
   conf_write # Write old values into new default file
 
-  # STAGE 2: To handle feature sections that use duplicate setting names
+  # STAGE 2: To handle presets sections that use duplicate setting names
 
   mv -f $rd_conf $rd_conf_backup # Backup config file agiain before update but after Stage 1 expansion
   generate_single_patch $rd_defaults $rd_conf_backup $rd_update_patch retrodeck # Create a patch file for differences between defaults and current user settings
@@ -2390,12 +2515,114 @@ configurator_move_folder_dialog() {
 
 changelog_dialog() {
   # This function will pull the changelog notes from the version it is passed (which must match the appdata version tag) from the net.retrodeck.retrodeck.appdata.xml file
+  # The function also accepts "all" as a version, and will print the entire changelog
   # USAGE: changelog_dialog "version"
 
-  changelog=$(xml sel -t -m "//release[@version='$1']/description" -v . -n $rd_appdata | tr -s '\n' | sed 's/^\s*//')
+  if [[ "$1" == "all" ]]; then
+    xmlstarlet sel -t -m "//release" -v "concat('RetroDECK version: ', @version)" -n -v "description" -n $rd_appdata | awk '{$1=$1;print}' | sed -e '/./b' -e :n -e 'N;s/\n$//;tn' > "/var/config/retrodeck/changelog.txt"
 
-  zenity --icon-name=net.retrodeck.retrodeck --info --no-wrap \
-  --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
-  --title "RetroDECK Changelogs" \
-  --text="Welcome to RetroDECK version $1!\n\nHere are the changes that were made in this version:\n$changelog"
+    zenity --icon-name=net.retrodeck.retrodeck --text-info --width=1200 --height=720 \
+    --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
+    --title "RetroDECK Changelogs" \
+    --filename="/var/config/retrodeck/changelog.txt"
+  else
+    local version_changelog=$(xml sel -t -m "//release[@version='$1']/description" -v . -n $rd_appdata | tr -s '\n' | sed 's/^\s*//')
+
+    zenity --icon-name=net.retrodeck.retrodeck --info --no-wrap \
+    --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
+    --title "RetroDECK Changelogs" \
+    --text="In RetroDECK version $1, the following changes were made:\n$version_changelog"
+    fi
+}
+
+get_cheevos_token_dialog() {
+  # This function will return a RetroAchvievements token from a valid username and password, will return "login failed" otherwise
+  # USAGE: get_cheevos_token_dialog
+
+  local cheevos_info=$(zenity --forms --title="Cheevos" \
+  --text="Username and password." \
+  --separator="^" \
+  --add-entry="Username" \
+  --add-password="Password")
+
+  IFS='^' read -r cheevos_username cheevos_password < <(printf '%s\n' "$cheevos_info")
+  cheevos_token=$(curl --silent --data "r=login&u=$cheevos_username&p=$cheevos_password" $RA_API_URL | jq .Token | tr -d '"')
+  if [[ ! "$cheevos_token" == "null" ]]; then
+    echo "$cheevos_username,$cheevos_token"
+  else
+    echo "failed"
+  fi
+}
+
+change_preset_dialog() {
+  # This function will build a list of all systems compatible with a given preset, their current enable/disabled state and allow the user to change one or more
+  # USAGE: change_preset_dialog "$preset"
+
+  local preset="$1"
+  pretty_preset_name=${preset//_/ } # Preset name prettification
+  pretty_preset_name=$(echo $pretty_preset_name | awk '{for(i=1;i<=NF;i++){$i=toupper(substr($i,1,1))substr($i,2)}}1') # Preset name prettification
+  local current_preset_settings=()
+  local current_enabled_systems=()
+  local current_disabled_systems=()
+  local changed_systems=()
+  local changed_presets=()
+  local section_results=$(sed -n '/\['"$preset"'\]/, /\[/{ /\['"$preset"'\]/! { /\[/! p } }' $rd_conf | sed '/^$/d')
+
+  while IFS= read -r config_line
+    do
+      system_name=$(get_setting_name "$config_line" "retrodeck")
+      all_systems=("${all_systems[@]}" "$system_name")
+      system_value=$(get_setting_value "$rd_conf" "$system_name" "retrodeck" "$preset")
+      if [[ "$system_value" == "true" ]]; then
+        current_enabled_systems=("${current_enabled_systems[@]}" "$system_name")
+      elif [[ "$system_value" == "false" ]]; then
+        current_disabled_systems=("${current_disabled_systems[@]}" "$system_name")
+      fi
+      current_preset_settings=("${current_preset_settings[@]}" "$system_value" "$system_name")
+  done < <(printf '%s\n' "$section_results")
+
+  choice=$(zenity \
+    --list --width=1200 --height=720 \
+    --checklist \
+    --separator="," \
+    --text="Enable $pretty_preset_name:" \
+    --column "Enabled" \
+    --column "Emulator" \
+    "${current_preset_settings[@]}")
+
+  local rc=$?
+
+  if [[ ! -z $choice || "$rc" == 0 ]]; then
+    IFS="," read -ra choices <<< "$choice"
+    for emulator in "${all_systems[@]}"; do
+      if [[ " ${choices[*]} " =~ " ${emulator} " && ! " ${current_enabled_systems[*]} " =~ " ${emulator} " ]]; then
+        changed_systems=("${changed_systems[@]}" "$emulator")
+        if [[ ! " ${changed_presets[*]} " =~ " ${preset} " ]]; then
+          changed_presets=("${changed_presets[@]}" "$preset")
+        fi
+        set_setting_value "$rd_conf" "$emulator" "true" "retrodeck" "$preset"
+        # Check for conflicting presets for this system
+        while IFS=: read -r preset_being_checked known_incompatible_preset; do
+          if [[ "$preset" == "$preset_being_checked" ]]; then
+            if [[ $(get_setting_value "$rd_conf" "$emulator" "retrodeck" "$known_incompatible_preset") == "true" ]]; then
+              changed_presets=("${changed_presets[@]}" "$known_incompatible_preset")
+              set_setting_value "$rd_conf" "$emulator" "false" "retrodeck" "$known_incompatible_preset"
+            fi
+          fi
+        done < "$incompatible_presets_reference_list"
+      fi
+      if [[ ! " ${choices[*]} " =~ " ${emulator} " && ! " ${current_disabled_systems[*]} " =~ " ${emulator} " ]]; then
+        changed_systems=("${changed_systems[@]}" "$emulator")
+        if [[ ! " ${changed_presets[*]} " =~ " ${preset} " ]]; then
+          changed_presets=("${changed_presets[@]}" "$preset")
+        fi
+        set_setting_value "$rd_conf" "$emulator" "false" "retrodeck" "$preset"
+      fi
+    done
+    for emulator in "${changed_systems[@]}"; do
+      build_preset_config $emulator ${changed_presets[*]}
+    done
+  else
+    echo "No choices made"
+  fi
 }
diff --git a/global.sh b/global.sh
index 1f8ca2fd..864a58eb 100755
--- a/global.sh
+++ b/global.sh
@@ -33,6 +33,9 @@ helper_files_folder="$emuconfigs/defaults/retrodeck/helper_files"
 helper_files_list="$emuconfigs/defaults/retrodeck/reference_lists/helper_files_list.cfg"                              # The list of files to be deployed and where they go
 rd_appdata="/app/share/appdata/net.retrodeck.retrodeck.appdata.xml"                                                   # The shipped appdata XML file for this version
 rpcs3_firmware="http://dus01.ps3.update.playstation.net/update/ps3/image/us/2023_0228_05fe32f5dc8c78acbcd84d36ee7fdc5b/PS3UPDAT.PUP"
+RA_API_URL="https://retroachievements.org/dorequest.php"                                                              # API URL for RetroAchievements.org
+presets_reference_lists_dir="$emuconfigs/defaults/retrodeck/reference_lists/presets"
+incompatible_presets_reference_list="$emuconfigs/defaults/retrodeck/reference_lists/incompatible_presets.cfg"
 
 # Config files for emulators with single config files
 
diff --git a/tools/configurator.sh b/tools/configurator.sh
index a002f62f..1b226be5 100644
--- a/tools/configurator.sh
+++ b/tools/configurator.sh
@@ -10,11 +10,13 @@ source /app/libexec/functions.sh
 # Configurator Option Tree
 
 # Welcome
+#     - RetroDECK Presets
+#       - Enable/Disable borders
+#       - Enable/Disable widescreen
+#       - Log in to RetroAchievements
 #     - RetroArch Presets
 #       - Change Rewind Setting
 #         - Enable/Disable Rewind
-#       - RetroAchivement Login
-#         - Login prompt
 #     - Dolphin Presets
 #       - Enable/Disable Custom Input Textures
 #     - Primehack Presets
@@ -35,14 +37,13 @@ source /app/libexec/functions.sh
 #     - Tools and Troubleshooting
 #       - Move RetroDECK or subfolders
 #       - Multi-file game check
-#       - Basic BIOS file check
-#       - Advanced BIOS file check
+#       - BIOS file check
 #       - Compress Games
 #         - Manual single-game selection
-#         - Multi-file compression (CHD)
-#       - Download ES themes
+#         - Multi-file compression
 #       - Download PS3 firmware
 #       - Install RetroDECK controller profile
+#       - Install RetroDECK Starter Pack
 #       - Backup RetroDECK userdata
 #     - Reset
 #       - Reset Specific Emulator
@@ -60,6 +61,15 @@ source /app/libexec/functions.sh
 #           - Reset Yuzu
 #       - Reset All Emulators
 #       - Reset RetroDECK
+#     - About RetroDECK
+#       - Version History
+#         - Full changelog
+#         - Version-specific changelogs
+#     - Developer Options (Hidden)
+#       - Change Multi-user mode
+#       - Change Update channel
+#       - Change Update check setting
+#       - Browse the wiki
 
 # DIALOG TREE FUNCTIONS
 
@@ -284,6 +294,50 @@ configurator_power_user_changes_dialog() {
   esac
 }
 
+configurator_retrodeck_presets_dialog() {
+  choice=$(zenity --list --title="RetroDECK Configurator Utility - RetroDECK Presets" --cancel-label="Back" \
+  --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \
+  --column="Choice" --column="Action" \
+  "Enable/Disable Borders" "Enable or disable borders in supported systems" \
+  "Enable/Disable Widescreen" "Enable or disable widescreen in supported systems" \
+  "RetroAchievements Login" "Log into the RetroAchievements service in supported emulators" \
+  "RetroAchievements Hardcore Mode" "Enable RetroAchievements hardcore mode (no cheats, rewind, save states etc.) in supported emulators" )
+
+  case $choice in
+
+  "Enable/Disable Borders" )
+    change_preset_dialog "borders"
+    configurator_retrodeck_presets_dialog
+  ;;
+
+  "Enable/Disable Widescreen" )
+    change_preset_dialog "widescreen"
+    configurator_retrodeck_presets_dialog
+  ;;
+
+  "RetroAchievements Login" )
+    cheevos_response=$(get_cheevos_token_dialog)
+    if [[ ! "$cheevos_response" == "failed" ]]; then
+      IFS=',' read -r cheevos_username cheevos_token < <(printf '%s\n' "$cheevos_response")
+      change_preset "cheevos"
+    else
+      configurator_generic_dialog "RetroDECK Configurator Utility - RetroDECK Presets" "RetroAchievements login failed, please verify your username and password and try the process again."
+    fi
+    configurator_retrodeck_presets_dialog
+  ;;
+
+  "RetroAchievements Hardcore Mode" )
+    change_preset_dialog "cheevos_hardcore"
+    configurator_retrodeck_presets_dialog
+  ;;
+
+  "" ) # No selection made or Back button clicked
+    configurator_welcome_dialog
+  ;;
+
+  esac
+}
+
 configurator_retroarch_rewind_dialog() {
   if [[ $(get_setting_value $raconf rewind_enable retroarch) == "true" ]]; then
     zenity --question \
@@ -318,8 +372,7 @@ configurator_retroarch_presets_dialog() {
   choice=$(zenity --list --title="RetroDECK Configurator Utility - RetroArch Options" --cancel-label="Back" \
   --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \
   --column="Choice" --column="Action" \
-  "Change Rewind Setting" "Enable or disable the Rewind function in RetroArch." \
-  "RetroAchievements Login" "Log into the RetroAchievements service in RetroArch." )
+  "Change Rewind Setting" "Enable or disable the Rewind function in RetroArch." )
 
   case $choice in
 
@@ -327,10 +380,6 @@ configurator_retroarch_presets_dialog() {
     configurator_retroarch_rewind_dialog
   ;;
 
-  "RetroAchievements Login" )
-    configurator_retroachivement_dialog
-  ;;
-
   "" ) # No selection made or Back button clicked
     configurator_welcome_dialog
   ;;
@@ -1061,10 +1110,59 @@ configurator_retrodeck_multiuser_dialog() {
   fi
 }
 
-configurator_developer_dialog() {
-  choice=$(zenity --list --title="RetroDECK Configurator Utility - Change Options" --cancel-label="Back" \
+configurator_version_history_dialog() {
+  local version_array=($(xmlstarlet sel -t -v '//component/releases/release/@version' -n $rd_appdata))
+  local all_versions_list=()
+
+  for rd_version in ${version_array[*]}; do
+    all_versions_list=("${all_versions_list[@]}" "RetroDECK $rd_version Changelog" "View the changes specific to version $rd_version")
+  done
+  
+  choice=$(zenity --list --title="RetroDECK Configurator Utility - RetroDECK Version History" --cancel-label="Back" \
   --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \
-  --column="Choice" --column="Action" \
+  --column="Choice" --column="Description" \
+  "Full RetroDECK Changelog" "View the list of all changes that have ever been made to RetroDECK" \
+  "${all_versions_list[@]}")
+
+  case $choice in
+
+  "Full RetroDECK Changelog" )
+    changelog_dialog "all"
+  ;;
+
+  "RetroDECK"*"Changelog" )
+    local version=$(echo "$choice" | sed 's/^RetroDECK \(.*\) Changelog$/\1/')
+    changelog_dialog "$version"
+  ;;
+
+  esac
+
+  configurator_about_retrodeck_dialog
+}
+
+configurator_about_retrodeck_dialog() {
+  choice=$(zenity --list --title="RetroDECK Configurator Utility - About RetroDECK" --cancel-label="Back" \
+  --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \
+  --column="Choice" --column="Description" \
+  "Version History" "View the version changelogs for RetroDECK" )
+
+  case $choice in
+
+  "Version History" )
+    configurator_version_history_dialog
+  ;;
+
+  "" ) # No selection made or Back button clicked
+    configurator_welcome_dialog
+  ;;
+
+  esac
+}
+
+configurator_developer_dialog() {
+  choice=$(zenity --list --title="RetroDECK Configurator Utility - Developer Options" --cancel-label="Back" \
+  --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \
+  --column="Choice" --column="Description" \
   "Change Multi-user mode" "Enable or disable multi-user support" \
   "Change Update Channel" "Change between normal and cooker builds" \
   "Change Update Check Setting" "Enable or disable online checks for new versions of RetroDECK" \
@@ -1096,20 +1194,24 @@ configurator_developer_dialog() {
 
 configurator_welcome_dialog() {
   if [[ $developer_options == "true" ]]; then
-    welcome_menu_options=("RetroArch Presets" "Change RetroArch presets, log into RetroAchievements etc." \
+    welcome_menu_options=("RetroDECK Presets" "Change RetroDECK presets, log into RetroAchievements etc." \
+    "RetroArch Presets" "Change available RetroArch presets" \
     "Dolphin Presets" "Change available Dolphin presets" \
     "Primehack Presets" "Change available Primehack presets" \
     "Emulator Options" "Launch and configure each emulators settings (for advanced users)" \
     "Tools and Troubleshooting" "Move RetroDECK to a new location, compress games and perform basic troubleshooting" \
     "Reset" "Reset specific parts or all of RetroDECK" \
+    "About RetroDECK" "Show additional information about RetroDECK" \
     "Developer Options" "Welcome to the DANGER ZONE")
   else
-    welcome_menu_options=("RetroArch Presets" "Change RetroArch presets, log into RetroAchievements etc." \
+    welcome_menu_options=("RetroDECK Presets" "Change RetroDECK presets, log into RetroAchievements etc." \
+    "RetroArch Presets" "Change available RetroArch presets" \
     "Dolphin Presets" "Change available Dolphin presets" \
     "Primehack Presets" "Change available Primehack presets" \
     "Emulator Options" "Launch and configure each emulators settings (for advanced users)" \
     "Tools and Troubleshooting" "Move RetroDECK to a new location, compress games and perform basic troubleshooting" \
-    "Reset" "Reset specific parts or all of RetroDECK" )
+    "Reset" "Reset specific parts or all of RetroDECK" \
+    "About RetroDECK" "Show additional information about RetroDECK")
   fi
 
   choice=$(zenity --list --title="RetroDECK Configurator Utility" --cancel-label="Quit" \
@@ -1119,6 +1221,10 @@ configurator_welcome_dialog() {
 
   case $choice in
 
+  "RetroDECK Presets" )
+    configurator_retrodeck_presets_dialog
+  ;;
+
   "RetroArch Presets" )
     configurator_retroarch_presets_dialog
   ;;
@@ -1143,6 +1249,10 @@ configurator_welcome_dialog() {
     configurator_reset_dialog
   ;;
 
+  "About RetroDECK" )
+    configurator_about_retrodeck_dialog
+  ;;
+
   "Developer Options" )
     configurator_generic_dialog "RetroDECK Configurator - Developer Options" "The following features and options are potentially VERY DANGEROUS for your RetroDECK install!\n\nThey should be considered the bleeding-edge of upcoming RetroDECK features, and never used when you have important saves/states/roms that are not backed up!\n\nYOU HAVE BEEN WARNED!"
     configurator_developer_dialog