From 5c3b7e0c00ed08acf79c445e13fbbc869be6f355 Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Wed, 6 May 2026 19:41:25 +1200 Subject: [PATCH 1/9] Cache application categories to speed up browsing --- api | 45 ++++++++++++++++++++++ gui | 113 ++++++++++++++----------------------------------------- settings | 3 ++ update | 5 +++ 4 files changed, 81 insertions(+), 85 deletions(-) diff --git a/api b/api index 6f1dd8e..ff3a9e1 100755 --- a/api +++ b/api @@ -166,6 +166,51 @@ search_apps() { fi } +cache_categories() { + # $1 - apps dir + # $2 - include Pi-Apps? + yad --title="LinStore" \ + --class="LinStore" \ + --center --borders=10 \ + --text "Generating app cache..." \ + --no-buttons & + + if [ -e "${1}/app_categories" ]; then + rm -f "${1}/app_categories" + fi + + for app_dir in "${1}"/*; do + app_name=$(basename "${app_dir}") + if [ -e "${1}/$app_name/category" ]; then + echo "$app_name|$(cat "${1}/$app_name/category")" >> "${1}/app_categories" + fi + done + + if [[ "$2" == "TRUE" ]]; then + if [ -e "$HOME/pi-apps/etc/categories" ]; then + while IFS= read -r line; do + app_name=$(echo "$line" | awk -F'|' '{print $1}') + category=$(grep -r "$(echo "$line" | awk -F'|' '{print $2}')" etc/mapping | head -n1 | awk -F'|' '{print $2}') + echo "$app_name|$category" >> "${1}/app_categories" + done < "$HOME/pi-apps/etc/categories" + fi + fi + + sort "${1}/app_categories" > "${1}/app_categories.tmp" + mv "${1}/app_categories.tmp" "${1}/app_categories" + + pkill -f "yad*" +} + +get_categories() { + cat etc/categories +} + +get_apps_in_category() { + local category="$1" + grep "|$category$" etc/categories | cut -d'|' -f1 +} + update() { pkill -f "yad*" ./api info "Updating LinStore..." diff --git a/gui b/gui index 87bc285..dcf65c3 100755 --- a/gui +++ b/gui @@ -1,5 +1,7 @@ #!/bin/bash +source api + APP_STORE_NAME="LinStore" APP_STORE_WIDTH=320 APP_STORE_HEIGHT=600 @@ -74,71 +76,6 @@ list_piapps() { fi } -read_categories() { - while read -r category; do - categories["$category"]="" - done "${1}/$app_name/category" - category_file="${1}/$app_name/category" - else - continue - fi - else - continue - fi - fi - - category_file="${1}/$app_name/category" - install_script="$app_dir/install" - - # Check if the install script or architecture-specific install scripts exist for this app - if [ -e "$install_script" ]; then - while IFS= read -r app_in_category; do - # Make sure $app_in_category is not empty before accessing the array - if [ -n "$app_in_category" ]; then - if [ -n "${categories[$app_in_category]}" ]; then - categories["$app_in_category"]+=" $app_name" - category_apps["$app_in_category"]+="|$app_name" - else - categories["$app_in_category"]="$app_name" - category_apps["$app_in_category"]="$app_name" - fi - fi - break - done <"$category_file" - else - architecture=$(cat ~/.linstore/architecture.txt) - install_script_arch="install-$architecture" - - if [ -e "$app_dir/$install_script_arch" ]; then - while IFS= read -r app_in_category; do - # Make sure $app_in_category is not empty before accessing the array - if [ -n "$app_in_category" ]; then - if [ -n "${categories[$app_in_category]}" ]; then - categories["$app_in_category"]+=" $app_name" - category_apps["$app_in_category"]+="|$app_name" - else - categories["$app_in_category"]="$app_name" - category_apps["$app_in_category"]="$app_name" - fi - fi - break - done <"$category_file" - fi - fi - done -} - get_app_description() { app_name="$1" description_file="apps/$app_name/description" @@ -284,9 +221,12 @@ show_apps_in_category() { formatted_apps=() if [ "$1" == "All Apps" ]; then title="All Apps" - for app_dir in apps/*; do - app_name=$(basename "$app_dir") - if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ]; then + while IFS= read -r line; do + app_name=$(echo "$line" | awk -F'|' '{print $1}') + app_dir="apps/$app_name" + if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install" ]; then app_icon="apps/$app_name/icon-24.png" formatted_apps+=("$app_icon") if [ -e "$HOME/.linstore/installscripts/$app_name" ]; then @@ -295,22 +235,26 @@ show_apps_in_category() { formatted_apps+=("$app_name") fi fi - done + done < "apps/app_categories" else - apps_in_category="${category_apps["$1"]}" title="Apps in $1 Category" #formatted_apps=() - IFS='|' read -r -a app_list <<<"$apps_in_category" - for app in "${app_list[@]}"; do - app_icon="apps/$app/icon-24.png" - formatted_apps+=("$app_icon") - if [ -e "$HOME/.linstore/installscripts/$app" ]; then - formatted_apps+=("$app") - else - formatted_apps+=("$app") + while IFS= read -r line; do + [[ $(echo "$line" | awk -F'|' '{print $2}') == "$1" ]] || continue + app=$(echo "$line" | awk -F'|' '{print $1}') + if [ -e "apps/$app/install" ] || [ -e "apps/$app/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app/install" ]; then + app_icon="apps/$app/icon-24.png" + formatted_apps+=("$app_icon") + if [ -e "$HOME/.linstore/installscripts/$app" ]; then + formatted_apps+=("$app") + else + formatted_apps+=("$app") + fi fi - done + done < "apps/app_categories" fi GTK_THEME="${theme}" GDK_BACKEND=x11 $YAD_COMMAND --text "$title" --geometry=${APP_STORE_WIDTH}x${APP_STORE_HEIGHT}+${categoryPos}+${categoryPosY} --center --columns="2" \ @@ -330,13 +274,8 @@ show_apps_in_category() { } show_app_store() { - read_categories "apps" - if [[ "$use_piapps" == "TRUE" ]]; then - read_categories "/home/${USER}/pi-apps/apps" - fi - # Sort categories alphabetically and format with newlines - sorted_categories=$(printf '%s\n' "${!categories[@]}" | sort) + sorted_categories=$(printf '%s\n' "$(get_categories)" | sort) list_items=() list_items=("images/categories/All Apps.png" "All Apps") @@ -373,6 +312,10 @@ show_app_store() { fi } +if [ ! -e apps/app_categories ]; then + cache_categories "apps" "$(list_piapps)" +fi + if [[ $1 == "" ]]; then ./api logo ./api buildinfo diff --git a/settings b/settings index f6552b9..02c04f5 100755 --- a/settings +++ b/settings @@ -1,5 +1,7 @@ #!/bin/bash +source api + APP_STORE_DIRECTORY="apps" CATEGORIES_FILE="etc/categories" THEMES_DIRECTORY="/usr/share/themes" @@ -139,6 +141,7 @@ show_settings() { import_from_piapps=$(echo "$fixed_settings" | awk -F '|' '{print $5}') echo $import_from_piapps > "etc/pi-apps-import" + cache_categories "apps" "$(cat "etc/pi-apps-import" 2> /dev/null || echo FALSE)" express_updates=$(echo "$fixed_settings" | awk -F '|' '{print $6}') echo $express_updates > "etc/express-updates" diff --git a/update b/update index a823a90..3c9f191 100755 --- a/update +++ b/update @@ -1,5 +1,7 @@ #!/bin/bash +source api + if [[ $(xrandr --current) =~ "connected primary" ]]; then resolution=$(xrandr --current | grep " connected primary" | awk '{print $4}' | cut -d'+' -f1) else @@ -33,6 +35,9 @@ check_for_updates() { mv ~/.linstore/tmp/apps ./apps sleep 1 + echo '# Update app cache' + cache_categories "apps" "$(cat "etc/pi-apps-import" 2> /dev/null || echo FALSE)" + # Clean up # rm -rf ~/.linstore/tmp echo "# Finished" From 294f61334bcfb1fa4fa638e950fc5d627c419d07 Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Thu, 7 May 2026 18:00:07 +1200 Subject: [PATCH 2/9] Improve support for listing apps from Pi-Apps --- api | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- gui | 35 +++---------------------- 2 files changed, 86 insertions(+), 34 deletions(-) diff --git a/api b/api index ff3a9e1..d3f9ac5 100755 --- a/api +++ b/api @@ -31,7 +31,7 @@ logo() { # Function to install an app install_app() { - local app_directory="$1" + local app_directory="$(get_app_directory "$2")" local selected_app_name="$2" local installed_file="$HOME/.linstore/installed" local temp_script=$(mktemp) @@ -73,7 +73,7 @@ open_app() { # Function to install an app installation_script() { - local app_directory="$1" + local app_directory="$(get_app_directory "$2")" local selected_app_name="$2" local installed_file="$HOME/.linstore/installed" @@ -97,7 +97,7 @@ installation_script() { # Function to uninstall an app uninstall_app() { - local app_directory="$1" + local app_directory="$(get_app_directory "$2")" local selected_app_name="$2" local uninstalled_file="$HOME/.linstore/uninstalled" local temp_script=$(mktemp) @@ -211,6 +211,79 @@ get_apps_in_category() { grep "|$category$" etc/categories | cut -d'|' -f1 } +get_app_description() { + app_name="$1" + description_file="apps/$app_name/description" + if [ -e "$description_file" ]; then + cat "$description_file" + elif [ -e "$HOME/pi-apps/apps/$app_name/description" ]; then + cat "$HOME/pi-apps/apps/$app_name/description" + else + echo "No description available." + fi +} +get_app_creator() { + app_name="$1" + creator_file="apps/$app_name/creator" + if [ -e "$creator_file" ]; then + cat "$creator_file" + elif [ -e "$HOME/pi-apps/apps/$app_name/credits" ]; then + cat "$HOME/pi-apps/apps/$app_name/credits" + else + echo "No description available." + fi +} +get_app_website() { + app_name="$1" + website_file="apps/$app_name/website" + if [ -e "$website_file" ]; then + cat "$website_file" + else + echo "No description available." + fi +} +get_app_directory() { + app_name="$1" + if [ -d "apps/$app_name" ]; then + echo "apps/$app_name" + elif [ -d "$HOME/pi-apps/apps/$app_name" ]; then + echo "$HOME/pi-apps/apps/$app_name" + else + echo "" + fi +} + +install_packages() { + packages="$@" + sudo apt update > /dev/null 2>&1 + + for package in $packages; do + if [[ "$package" == http* ]]; then + echo "Downloading and installing $package..." + wget --no-check-certificate "$package" -O /tmp/package.deb > /dev/null 2>&1 + sudo dpkg -i /tmp/package.deb > /dev/null 2>&1 + rm -r /tmp/package.deb + elif [[ "$package" == *.deb ]]; then + echo "Installing $package using dpkg..." + sudo dpkg -i "$package" > /dev/null 2>&1 + else + echo "Installing $package using apt..." + + sudo apt install "$package" -y > /dev/null 2>&1 + fi + done +} + +git_clone() { + if [ -z "$2" ]; then + local directory=$(basename "$1") + else + local directory="$2" + fi + + git clone "$1" "$directory" +} + update() { pkill -f "yad*" ./api info "Updating LinStore..." @@ -237,6 +310,12 @@ information() { printf '\033[1;104;30m INFO:\033[0;104m %s \033[0m\n' "$msg" >&2 } +export -f install_packages +export -f error +export -f warning +export -f information +export -f git_clone + # Main logic to handle command line arguments if [[ $1 == "search" ]]; then search_apps diff --git a/gui b/gui index dcf65c3..7c27dcf 100755 --- a/gui +++ b/gui @@ -76,33 +76,6 @@ list_piapps() { fi } -get_app_description() { - app_name="$1" - description_file="apps/$app_name/description" - if [ -e "$description_file" ]; then - cat "$description_file" - else - echo "No description available." - fi -} -get_app_creator() { - app_name="$1" - creator_file="apps/$app_name/creator" - if [ -e "$creator_file" ]; then - cat "$creator_file" - else - echo "No description available." - fi -} -get_app_website() { - app_name="$1" - website_file="apps/$app_name/website" - if [ -e "$website_file" ]; then - cat "$website_file" - else - echo "No description available." - fi -} theme_get() { website_file="etc/theme" if [ -e "$website_file" ]; then @@ -159,8 +132,8 @@ app_details_page() { local selected_app_name="${1//|/}" selected_app_name=$(echo "$selected_app_name" | sed 's/<[^>]*>//g') - local app_directory="apps/$selected_app_name" - local app_icon="$app_directory/icon-48.png" + local app_directory="$(get_app_directory "$selected_app_name")" + local app_icon="$app_directory/icon-64.png" local description=$(get_app_description "$selected_app_name") local creator=$(get_app_creator "$selected_app_name") local website=$(get_app_website "$selected_app_name") @@ -227,7 +200,7 @@ show_apps_in_category() { if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ] \ || [ -e "$HOME/pi-apps/apps/$app_name/install-$(cat ~/.linstore/architecture.txt)" ] \ || [ -e "$HOME/pi-apps/apps/$app_name/install" ]; then - app_icon="apps/$app_name/icon-24.png" + app_icon="$(get_app_directory "$app_name")/icon-24.png" formatted_apps+=("$app_icon") if [ -e "$HOME/.linstore/installscripts/$app_name" ]; then formatted_apps+=("$app_name") @@ -246,7 +219,7 @@ show_apps_in_category() { if [ -e "apps/$app/install" ] || [ -e "apps/$app/install-$(cat ~/.linstore/architecture.txt)" ] \ || [ -e "$HOME/pi-apps/apps/$app/install-$(cat ~/.linstore/architecture.txt)" ] \ || [ -e "$HOME/pi-apps/apps/$app/install" ]; then - app_icon="apps/$app/icon-24.png" + app_icon="$(get_app_directory "$app")/icon-24.png" formatted_apps+=("$app_icon") if [ -e "$HOME/.linstore/installscripts/$app" ]; then formatted_apps+=("$app") From cc268edeaed90c6125b5893f6e8d91c6a3622f6e Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Fri, 8 May 2026 08:28:31 +1200 Subject: [PATCH 3/9] Update gitignore to not include configuration files --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index cbd3f99..1472561 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ -/updates_list.txt \ No newline at end of file +/updates_list.txt +/apps/app_categories +/etc/accent +/etc/editor +/etc/express-updates +/etc/pi-apps-import +/etc/theme \ No newline at end of file From 5a00e969ff0ac6127f426e1342f5c57b4bb4f914 Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Sun, 10 May 2026 20:09:45 +1200 Subject: [PATCH 4/9] Move to using a FIFO for list data --- api | 2 + gui | 129 ++++++++++++++++++++++++++---------------------------------- 2 files changed, 57 insertions(+), 74 deletions(-) diff --git a/api b/api index d3f9ac5..eb269ac 100755 --- a/api +++ b/api @@ -315,6 +315,8 @@ export -f error export -f warning export -f information export -f git_clone +export -f get_app_directory +export -f get_categories # Main logic to handle command line arguments if [[ $1 == "search" ]]; then diff --git a/gui b/gui index 7c27dcf..71b4654 100755 --- a/gui +++ b/gui @@ -11,6 +11,12 @@ YAD_COMMAND="yad" YAD_FLAGS="" ACCENT="green" +export ACCENT + +pipe="$(mktemp -u)" +mkfifo $pipe +export pipe +trap "rm -f $pipe" EXIT #pwd if ! command -v "$YAD_COMMAND" &>/dev/null; then @@ -189,90 +195,67 @@ app_details_page() { rm -f /tmp/description.tmp } -show_apps_in_category() { - while true; do - formatted_apps=() - if [ "$1" == "All Apps" ]; then - title="All Apps" - while IFS= read -r line; do - app_name=$(echo "$line" | awk -F'|' '{print $1}') - app_dir="apps/$app_name" - if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ] \ - || [ -e "$HOME/pi-apps/apps/$app_name/install-$(cat ~/.linstore/architecture.txt)" ] \ - || [ -e "$HOME/pi-apps/apps/$app_name/install" ]; then - app_icon="$(get_app_directory "$app_name")/icon-24.png" - formatted_apps+=("$app_icon") - if [ -e "$HOME/.linstore/installscripts/$app_name" ]; then - formatted_apps+=("$app_name") - else - formatted_apps+=("$app_name") - fi - fi - done < "apps/app_categories" - else - title="Apps in $1 Category" - #formatted_apps=() +update_fifo() { + if [[ "$2" == "Back" ]]; then + selected_item="" + else + selected_item="$2" + fi - while IFS= read -r line; do - [[ $(echo "$line" | awk -F'|' '{print $2}') == "$1" ]] || continue - app=$(echo "$line" | awk -F'|' '{print $1}') - if [ -e "apps/$app/install" ] || [ -e "apps/$app/install-$(cat ~/.linstore/architecture.txt)" ] \ - || [ -e "$HOME/pi-apps/apps/$app/install-$(cat ~/.linstore/architecture.txt)" ] \ - || [ -e "$HOME/pi-apps/apps/$app/install" ]; then - app_icon="$(get_app_directory "$app")/icon-24.png" - formatted_apps+=("$app_icon") - if [ -e "$HOME/.linstore/installscripts/$app" ]; then - formatted_apps+=("$app") - else - formatted_apps+=("$app") - fi + if [[ "$selected_item" == "" ]]; then + echo -e "\f" >> "$pipe" + sorted_categories=$(printf '%s\n' "$(get_categories)" | sort) + + echo "images/categories/All Apps.png" >> "$pipe" + echo "All Apps" >> "$pipe" + while IFS= read -r category; do + category_icon="images/categories/$category.png" # Path to category icons + echo "$category_icon" >> "$pipe" + echo "$category" >> "$pipe" + done <<<"$sorted_categories" + elif [[ "$selected_item" == "All Apps" ]] || grep -q "$selected_item" "etc/categories"; then + echo -e "\f" >> "$pipe" + + echo "images/button/back.png" >> "$pipe" + echo "Back" >> "$pipe" + + while IFS= read -r line; do + [[ $(echo "$line" | awk -F'|' '{print $2}') == "$selected_item" ]] ||\ + [[ "$selected_item" == "All Apps" ]] || continue + app_name=$(echo "$line" | awk -F'|' '{print $1}') + app_dir="apps/$app_name" + if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install" ]; then + app_icon="$(get_app_directory "$app_name")/icon-24.png" + echo "$app_icon" >> "$pipe" + if [ -e "$HOME/.linstore/installscripts/$app_name" ]; then + echo "$app_name" >> "$pipe" + else + echo "$app_name" >> "$pipe" fi - done < "apps/app_categories" - fi - - GTK_THEME="${theme}" GDK_BACKEND=x11 $YAD_COMMAND --text "$title" --geometry=${APP_STORE_WIDTH}x${APP_STORE_HEIGHT}+${categoryPos}+${categoryPosY} --center --columns="2" \ - --list --image="images/logo/logo-64.png" --window-icon="images/logo/logo-64.png" --image-on-top --title "LinStore" --column "Icon:IMG" --column "Apps" --class="LinStore" \ - --button="Back"!images/button/back.png!:4 --separator="\n" --markup "${formatted_apps[@]}" --no-headers \ - --css="span{fgcolor:green;}" --select-action='bash -c "./gui showdetails \"%s\"" &'#> /dev/null 2>&1 - - button_clicked=$? - if [ $button_clicked -eq 4 ]; then - show_app_store - break - fi - - show_app_store - break - done + fi + done < "apps/app_categories" + else + ./gui showdetails "$selected_item" + fi } +export -f update_fifo show_app_store() { - # Sort categories alphabetically and format with newlines - sorted_categories=$(printf '%s\n' "$(get_categories)" | sort) - - list_items=() - list_items=("images/categories/All Apps.png" "All Apps") - while IFS= read -r category; do - category_icon="images/categories/$category.png" # Path to category icons - list_items+=("$category_icon") - list_items+=("$category") - done <<<"$sorted_categories" - # Fetching a random line from the announcements file random_announcement=$(shuf -n 1 etc/announcements) - - # Search function - - selected_category_raw=$(GTK_THEME="${theme}" GDK_BACKEND=x11 $YAD_COMMAND --text "$random_announcement" \ + update_fifo "" & + + GTK_THEME="${theme}" GDK_BACKEND=x11 $YAD_COMMAND --text "$random_announcement" \ --geometry=${APP_STORE_WIDTH}x${APP_STORE_HEIGHT}+${categoryPos}+${categoryPosY} --center --columns="3" \ - "${list_items[@]}" --class="LinStore" \ + --class="LinStore" --select-action="bash -c "\""update_fifo %s"\""" --dclick-action="bash -c "\""update_fifo %s"\""" \ --list --image="images/logo/logo-64.png" --window-icon="images/logo/logo-64.png" --image-on-top --title "$APP_STORE_NAME" --column "Icon:IMG" \ --column "Category" --button "!images/button/search.png"!"Search":"bash -c './api search' &" \ --button "!images/button/update.png"!"Updates":"bash -c './update' &" --button "!images/button/settings.png"!"Settings":"bash -c './settings' &" \ - --no-headers --item-height="$welcome_height" --timeout=0 --no-close) + --no-headers --item-height="$welcome_height" --timeout=0 --no-close < <(tail -f $pipe 2>/dev/null) exval=$? ./api info "Exit value: ${exval}" - selected_category="${selected_category_raw//|/}" if [ "$exval" == "44" ]; then ./api search && show_app_store @@ -280,8 +263,6 @@ show_app_store() { pkill -f "yad*" > /dev/null 2>&1 elif [ "$exval" -eq "252" ]; then pkill -f "yad*" > /dev/null 2>&1 - elif [ -n "$selected_category" ]; then - show_apps_in_category "$selected_category" & fi } @@ -301,7 +282,7 @@ if [[ $1 == "showdetails" ]]; then if [ -e /tmp/tmpname ]; then app_details_page "$(cat /tmp/tmpname && rm -r /tmp/tmpname)" else - app_details_page "$(echo $2 | awk -F"'" '{print $4}')" + app_details_page "$2" fi elif [[ $1 == "multi-install" ]]; then multi_install From 8014ce63217be2659995c5c8b743987487e904d7 Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Tue, 12 May 2026 08:29:55 +1200 Subject: [PATCH 5/9] Fix segfault and improve speed of FIFO --- api | 13 +++++++++++-- gui | 43 ++++++++++++++++++++++--------------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/api b/api index eb269ac..b22853e 100755 --- a/api +++ b/api @@ -182,7 +182,11 @@ cache_categories() { for app_dir in "${1}"/*; do app_name=$(basename "${app_dir}") if [ -e "${1}/$app_name/category" ]; then - echo "$app_name|$(cat "${1}/$app_name/category")" >> "${1}/app_categories" + if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install" ]; then + echo "$app_name|$(cat "${1}/$app_name/category")" >> "${1}/app_categories" + fi fi done @@ -190,8 +194,13 @@ cache_categories() { if [ -e "$HOME/pi-apps/etc/categories" ]; then while IFS= read -r line; do app_name=$(echo "$line" | awk -F'|' '{print $1}') + app_dir="$HOME/pi-apps/apps/$app_name" category=$(grep -r "$(echo "$line" | awk -F'|' '{print $2}')" etc/mapping | head -n1 | awk -F'|' '{print $2}') - echo "$app_name|$category" >> "${1}/app_categories" + if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install-$(cat ~/.linstore/architecture.txt)" ] \ + || [ -e "$HOME/pi-apps/apps/$app_name/install" ]; then + echo "$app_name|$category" >> "${1}/app_categories" + fi done < "$HOME/pi-apps/etc/categories" fi fi diff --git a/gui b/gui index 71b4654..70feeea 100755 --- a/gui +++ b/gui @@ -196,6 +196,7 @@ app_details_page() { } update_fifo() { + output=() if [[ "$2" == "Back" ]]; then selected_item="" else @@ -206,39 +207,39 @@ update_fifo() { echo -e "\f" >> "$pipe" sorted_categories=$(printf '%s\n' "$(get_categories)" | sort) - echo "images/categories/All Apps.png" >> "$pipe" - echo "All Apps" >> "$pipe" + output+=("images/categories/All Apps.png" "All Apps") while IFS= read -r category; do category_icon="images/categories/$category.png" # Path to category icons - echo "$category_icon" >> "$pipe" - echo "$category" >> "$pipe" + output+=("$category_icon" "$category") done <<<"$sorted_categories" elif [[ "$selected_item" == "All Apps" ]] || grep -q "$selected_item" "etc/categories"; then echo -e "\f" >> "$pipe" - - echo "images/button/back.png" >> "$pipe" - echo "Back" >> "$pipe" + output+=("images/button/back.png") + output+=("Back") while IFS= read -r line; do [[ $(echo "$line" | awk -F'|' '{print $2}') == "$selected_item" ]] ||\ [[ "$selected_item" == "All Apps" ]] || continue - app_name=$(echo "$line" | awk -F'|' '{print $1}') - app_dir="apps/$app_name" - if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ] \ - || [ -e "$HOME/pi-apps/apps/$app_name/install-$(cat ~/.linstore/architecture.txt)" ] \ - || [ -e "$HOME/pi-apps/apps/$app_name/install" ]; then - app_icon="$(get_app_directory "$app_name")/icon-24.png" - echo "$app_icon" >> "$pipe" - if [ -e "$HOME/.linstore/installscripts/$app_name" ]; then - echo "$app_name" >> "$pipe" - else - echo "$app_name" >> "$pipe" - fi + app_name=$(echo "$line" | awk -F'|' '{print $1}') + app_icon="$(get_app_directory "$app_name")/icon-24.png" + if [[ ! -f "$app_icon" ]]; then + app_icon="application-x-executable" + fi + output+=("$app_icon") + if [ -e "$HOME/.linstore/installscripts/$app_name" ]; then + output+=("$app_name") + else + output+=("$app_name") fi done < "apps/app_categories" else ./gui showdetails "$selected_item" + return fi + + for item in "${output[@]}"; do + echo "$item" >> "$pipe" + done } export -f update_fifo @@ -248,12 +249,12 @@ show_app_store() { update_fifo "" & GTK_THEME="${theme}" GDK_BACKEND=x11 $YAD_COMMAND --text "$random_announcement" \ - --geometry=${APP_STORE_WIDTH}x${APP_STORE_HEIGHT}+${categoryPos}+${categoryPosY} --center --columns="3" \ + --geometry=${APP_STORE_WIDTH}x${APP_STORE_HEIGHT}+${categoryPos}+${categoryPosY} --center \ --class="LinStore" --select-action="bash -c "\""update_fifo %s"\""" --dclick-action="bash -c "\""update_fifo %s"\""" \ --list --image="images/logo/logo-64.png" --window-icon="images/logo/logo-64.png" --image-on-top --title "$APP_STORE_NAME" --column "Icon:IMG" \ --column "Category" --button "!images/button/search.png"!"Search":"bash -c './api search' &" \ --button "!images/button/update.png"!"Updates":"bash -c './update' &" --button "!images/button/settings.png"!"Settings":"bash -c './settings' &" \ - --no-headers --item-height="$welcome_height" --timeout=0 --no-close < <(tail -f $pipe 2>/dev/null) + --no-headers --timeout=0 --no-close < <(tail -f $pipe 2>/dev/null) exval=$? ./api info "Exit value: ${exval}" From decd33e3ed1aee294e6298c1ffda51b35cf68f94 Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Wed, 13 May 2026 08:55:35 +1200 Subject: [PATCH 6/9] New pane to open selected script in editor, stop app creator being frontmost window --- createapp | 99 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/createapp b/createapp index f1349f2..cff19e7 100755 --- a/createapp +++ b/createapp @@ -23,7 +23,7 @@ select_category_pane() { --window-icon="images/logo/logo-64.png" --class="LinStore" \ --text="Choose a category\nLinStore organises apps by category, which allows users to quickly find related apps easier.\nPlease choose a category for your app:" \ --field="Category:" \ - --width="525" --height="550" --center --on-top --borders=10 --columns=1 "${category_list[@]}" \ + --width="525" --height="550" --center --borders=10 --columns=1 "${category_list[@]}" \ --list --column="Icon:IMG" --column="Categories" --column="Description" --no-headers \ --button="Cancel!gtk-cancel":1 \ --button="Next!go-next":0 | awk -F '|' '{print $2}') @@ -63,7 +63,7 @@ create_new_app_pane() { --field="ARM 64-bit (aarch64):CHK" "" \ --field=":LBL" "" \ --field="Separate or combined install scripts?:CB" 'Combined (all architectures in one)!Separate' \ - --width="525" --height="550" --center --on-top --borders=10 --separator="|" \ + --width="525" --height="550" --center --borders=10 --separator="|" \ --button="Cancel!gtk-cancel":1 \ --button="Next!go-next":0) @@ -104,7 +104,7 @@ create_new_app_pane() { --text="App Assets\nYour app needs assets in LinStore, which is currently limited to the app's logo/icon.\nSelect these assets here:" \ --field=":LBL" "" \ --field="Icon/logo:SFL" "" \ - --width="525" --height="550" --center --on-top --borders=10 --separator="|" \ + --width="525" --height="550" --center --borders=10 --separator="|" \ --button="Cancel!gtk-cancel":1 \ --button="Next!go-next":0) @@ -120,52 +120,67 @@ create_new_app_pane() { convert "$icon_file" -resize 24x24 "$app_directory/icon-24.png" convert "$icon_file" -resize 16x16 "$app_directory/icon-16.png" fi - + + # Create or update the install scripts based on user preferences + if [[ "$separate_scripts" == "Combined (all architectures in one)" ]]; then + touch "$app_directory/install" & + else + if [ "$install_x64" == "TRUE" ]; then + touch "$app_directory/install-x64" & + fi + if [ "$install_x86" == "TRUE" ]; then + touch "$app_directory/install-x86" & + fi + if [ "$install_32" == "TRUE" ]; then + touch "$app_directory/install-32" & + fi + if [ "$install_64" == "TRUE" ]; then + touch "$app_directory/install-64" & + fi + fi + + touch "$app_directory/uninstall" & + + edit_scripts_pane "$app_directory" +} + +edit_scripts_pane() { + app_directory="$1" + editor=$(get_editor) + buttons=() + for file in "$app_directory"/*; do + [ -f "$file" ] || continue + if [[ "$(basename "$file")" == "install"* ]]; then + buttons+=("--field= $(basename "$file")!images/button/install.png:BTN" "$editor \"$file\"") + elif [[ "$(basename "$file")" == "uninstall"* ]]; then + buttons+=("--field= $(basename "$file")!images/button/uninstall.png:BTN" "$editor \"$file\"") + fi + done + yad --form \ --title="Create New App" \ --image="images/logo/logo-64.png" --image-on-top \ --window-icon="images/logo/logo-64.png" --class="LinStore" \ - --text="Installer Scripts\nYour app has been created!" \ + --text="Edit App Scripts\nEdit your app's install and uninstall scripts." \ --field=":LBL" "" \ - --field="You now need to write an Installer and an Uninstaller script. These are the scripts executed when users click \"Install\" and \"Uninstall\" in LinStore.\n\nIf you would like to create these now, press 'Next'. Else, press 'Cancel'.:LBL" "" \ - --width="525" --height="550" --center --on-top --borders=10 --separator="|" \ + --field="Listed below are the scripts used by LinStore when installing or uninstalling your app. Click on one to create or edit it.:LBL" "" \ + "${buttons[@]}" \ + --width="525" --height="550" --center --borders=10 --separator="|" \ --button="Cancel!gtk-cancel":1 \ - --button="Next!go-next":0 > /dev/null 2>&1 + --button="Next!go-next":0 > /dev/null 2>&1 - # Create or update the install scripts based on user preferences if [ $? -eq 0 ]; then - if [[ "$separate_scripts" == "Combined (all architectures in one)" ]]; then - gedit "$app_directory/install" & - else - if [ "$install_x64" == "TRUE" ]; then - gedit "$app_directory/install-x64" & - fi - if [ "$install_x86" == "TRUE" ]; then - gedit "$app_directory/install-x86" & - fi - if [ "$install_32" == "TRUE" ]; then - gedit "$app_directory/install-32" & - fi - if [ "$install_64" == "TRUE" ]; then - gedit "$app_directory/install-64" & - fi - fi - - gedit "$app_directory/uninstall" - wait - elif [ $? -eq 252 ]; then - echo $? + yad --form \ + --title="Create New App" \ + --image="images/logo/logo-64.png" --image-on-top \ + --window-icon="images/logo/logo-64.png" --class="LinStore" \ + --text="Thank you!\nThank you for using LinStore's app creation wizard." \ + --field=":LBL" "" \ + --field="Next Steps:\nSubmit your app for addition to LinStore's app library. You can do this by 'zipping' the new app's directory and uploading it to an issue at our GitHub.\n\nIf you do not wish to do so, you can still distribute your app's zip file by specifying to your users to use LinStore's 'Import App' function.:LBL" "" \ + --width="525" --height="550" --center --borders=10 --separator="|" \ + --button="Exit!window-close":0 > /dev/null 2>&1 fi - - yad --form \ - --title="Create New App" \ - --image="images/logo/logo-64.png" --image-on-top \ - --window-icon="images/logo/logo-64.png" --class="LinStore" \ - --text="Thank you!\nThank you for using LinStore's app creation wizard." \ - --field=":LBL" "" \ - --field="Next Steps:\nSubmit your app for addition to LinStore's app library. You can do this by 'zipping' the new app's directory and uploading it to an issue at our GitHub.\n\nIf you do not wish to do so, you can still distribute your app's zip file by specifying to your users to use LinStore's 'Import App' function.:LBL" "" \ - --width="525" --height="550" --center --on-top --borders=10 --separator="|" \ - --button="Exit!window-close":0 > /dev/null 2>&1 + } welcome() { @@ -176,7 +191,7 @@ welcome() { --text="App Creator\nWelcome to the LinStore's app creator!" \ --field=":LBL" "" \ --field="What is this?\nThis is a wizard that will guide you through the necessary steps in order to create an app to be displayed in LinStore.\n\nIf you're ready, press 'Next'.\nIf you got here by accident, press 'Cancel'.:LBL" "" \ - --width="525" --height="550" --center --on-top --borders=10 --separator="|" \ + --width="525" --height="550" --center --borders=10 --separator="|" \ --button="Cancel!gtk-cancel":1 \ --button="Next!go-next":0 > /dev/null 2>&1 if [ $? -eq 0 ]; then @@ -196,7 +211,7 @@ import_zip_file() { --field=":LBL" "" \ --field="Some app developers distribute ZIP files to let you import into LinStore.\n\nTo import such a ZIP file, select it below and we'll import it for you.:LBL" "" \ --field="ZIP File: :SFL" "" \ - --width="525" --height="550" --center --on-top --borders=10 --separator="|" \ + --width="525" --height="550" --center --borders=10 --separator="|" \ --button="Cancel!gtk-cancel":1 \ --button="Next!go-next":0 | awk -F '|' '{print $3}') From bdf86be0bbe49fdf0d3a5b7569e8a59ec394f6ce Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Thu, 14 May 2026 08:18:50 +1200 Subject: [PATCH 7/9] Fix settings not opening --- gui | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gui b/gui index 70feeea..5424f68 100755 --- a/gui +++ b/gui @@ -253,17 +253,16 @@ show_app_store() { --class="LinStore" --select-action="bash -c "\""update_fifo %s"\""" --dclick-action="bash -c "\""update_fifo %s"\""" \ --list --image="images/logo/logo-64.png" --window-icon="images/logo/logo-64.png" --image-on-top --title "$APP_STORE_NAME" --column "Icon:IMG" \ --column "Category" --button "!images/button/search.png"!"Search":"bash -c './api search' &" \ - --button "!images/button/update.png"!"Updates":"bash -c './update' &" --button "!images/button/settings.png"!"Settings":"bash -c './settings' &" \ + --button "!images/button/update.png"!"Updates":"bash -c './update' &" --button "!images/button/settings.png"!"Settings":"bash -c './settings'" \ --no-headers --timeout=0 --no-close < <(tail -f $pipe 2>/dev/null) exval=$? ./api info "Exit value: ${exval}" if [ "$exval" == "44" ]; then ./api search && show_app_store - elif [ "$exval" -eq "143" ]; then - pkill -f "yad*" > /dev/null 2>&1 elif [ "$exval" -eq "252" ]; then pkill -f "yad*" > /dev/null 2>&1 + exit 1 fi } From 6c9691ef0b895e32da349d4fe60f2538139b79b8 Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Thu, 14 May 2026 08:36:40 +1200 Subject: [PATCH 8/9] Switch to using cached category data for multi-install --- gui | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/gui b/gui index 5424f68..8db4cec 100755 --- a/gui +++ b/gui @@ -97,15 +97,11 @@ theme=$(theme_get) multi_install() { all_apps_list=() - for app_dir in apps/*; do - app_name=$(basename "$app_dir") - if [ -e "$app_dir/install" ] || [ -e "$app_dir/install-$(cat ~/.linstore/architecture.txt)" ]; then - app_icon="apps/$app_name/icon-24.png" - all_apps_list+=("FALSE") - all_apps_list+=("$app_icon") - all_apps_list+=("$app_name") - fi - done + while IFS= read -r app_name; do + app_name=$(echo "$app_name" | awk -F'|' '{print $1}') + app_icon="$(get_app_directory "$app_name")/icon-24.png" + all_apps_list+=("FALSE" "$app_icon" "$app_name") + done < "apps/app_categories" APPS=$(GTK_THEME="${theme}" GDK_BACKEND=x11 $YAD_COMMAND --text "Multi Installer\nInstall multiple apps at once" --geometry=600x${APP_STORE_HEIGHT} --center --columns="3" \ --list --checklist --image="images/logo/logo-64.png" --window-icon="images/logo/logo-64.png" --image-on-top --title "LinStore" --column="Select":chk --column "Icon:IMG" --column "Apps" \ @@ -116,6 +112,7 @@ multi_install() { if [[ "$APPS" != "" ]]; then list="" while IFS= read -r line; do + echo "Selected: $line" list+="$(echo -e "$line" | awk -F "|" '{print $3}')" list+=$'\n' done <<< "$APPS" From 3b18a07b8ee52258fb3e1bd1be043e8e96046caf Mon Sep 17 00:00:00 2001 From: techguy16 <88870951+techguy16@users.noreply.github.com> Date: Thu, 14 May 2026 08:55:48 +1200 Subject: [PATCH 9/9] Simplify parameters for `install` and `uninstall` api functions --- api | 18 +++++++++--------- gui | 4 ++-- manage | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/api b/api index b22853e..df118ec 100755 --- a/api +++ b/api @@ -31,8 +31,8 @@ logo() { # Function to install an app install_app() { - local app_directory="$(get_app_directory "$2")" - local selected_app_name="$2" + local app_directory="$(get_app_directory "$1")" + local selected_app_name="$1" local installed_file="$HOME/.linstore/installed" local temp_script=$(mktemp) @@ -73,8 +73,8 @@ open_app() { # Function to install an app installation_script() { - local app_directory="$(get_app_directory "$2")" - local selected_app_name="$2" + local app_directory="$(get_app_directory "$1")" + local selected_app_name="$1" local installed_file="$HOME/.linstore/installed" if [ -e "$app_directory/install" ]; then @@ -97,8 +97,8 @@ installation_script() { # Function to uninstall an app uninstall_app() { - local app_directory="$(get_app_directory "$2")" - local selected_app_name="$2" + local app_directory="$(get_app_directory "$1")" + local selected_app_name="$1" local uninstalled_file="$HOME/.linstore/uninstalled" local temp_script=$(mktemp) @@ -331,11 +331,11 @@ export -f get_categories if [[ $1 == "search" ]]; then search_apps elif [[ $1 == "install" ]]; then - install_app "$2" "$3" + install_app "$2" elif [[ $1 == "whatscript" ]]; then - installation_script "$2" "$3" + installation_script "$2" elif [[ $1 == "uninstall" ]]; then - uninstall_app "$2" "$3" + uninstall_app "$2" elif [[ $1 == "logo" ]]; then logo elif [[ $1 == "error" ]]; then diff --git a/gui b/gui index 8db4cec..68229d7 100755 --- a/gui +++ b/gui @@ -147,8 +147,8 @@ app_details_page() { installed="false" fi - local install_command=$(./api install "$app_directory" "$selected_app_name") - local uninstall_command=$(./api uninstall "$app_directory" "$selected_app_name") + local install_command=$(./api install "$selected_app_name") + local uninstall_command=$(./api uninstall "$selected_app_name") local open_command=$(./api open "$app_directory") buttons=() diff --git a/manage b/manage index 36e2d36..ebe47de 100755 --- a/manage +++ b/manage @@ -4,25 +4,25 @@ # Very basic, sorry! install() { - local install_command=$(./api install "apps/$1" "$1") + local install_command=$(./api install "$1") bash -c "$install_command" } multi_install() { while IFS= read -r line; do - local install_command=$(./api install "apps/$line" "$line") + local install_command=$(./api install "$line") bash -c "$install_command" done <<< "$1" } uninstall() { - local uninstall_command=$(./api uninstall "apps/$1" "$1") + local uninstall_command=$(./api uninstall "$1") bash -c "$uninstall_command" } multi_uninstall() { while IFS= read -r line; do - local uninstall_command=$(./api uninstall "apps/$line" "$line") + local uninstall_command=$(./api uninstall "$line") bash -c "$uninstall_command" done <<< "$1" }