From 433957cd6c2c4af82abad01b7c9e3ca1f4a15c43 Mon Sep 17 00:00:00 2001 From: eobarretooo Date: Sat, 23 May 2026 23:09:16 -0300 Subject: [PATCH 1/3] =?UTF-8?q?Melhora=20instala=C3=A7=C3=A3o=20do=20ambie?= =?UTF-8?q?nte=20gr=C3=A1fico=20no=20Termux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script-termux.sh | 813 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 686 insertions(+), 127 deletions(-) diff --git a/script-termux.sh b/script-termux.sh index 01b1a00..c6c5161 100644 --- a/script-termux.sh +++ b/script-termux.sh @@ -1,149 +1,708 @@ #!/data/data/com.termux/files/usr/bin/bash +# Instalador de ambiente gráfico para Termux + Termux-X11 -# Script Linux simplificado para Termux +set -Eeuo pipefail +IFS=$'\n\t' -# ============== CONFIGURAÇÃO BÁSICA ============== -DE_CHOICE="1" +# ========================= +# Configuração +# ========================= +LOG="${HOME}/termux-linux-install.log" +START_LOG="${HOME}/termux-linux-start.log" +STATE_DIR="${HOME}/.termux-linux" +SPINNER_PID="" +TOTAL=11 +CURRENT=0 + +DE_INPUT="1" DE_NAME="XFCE4" -GPU_DRIVER="" +DE_COMMAND="startxfce4" +GPU_DRIVER="software" +GPU_ENABLED="false" +INSTALL_WINE="n" + +mkdir -p "$STATE_DIR" +: > "$LOG" + +# ========================= +# Cores e mensagens +# ========================= +if [ -t 1 ]; then + RED='\033[31m' + GREEN='\033[32m' + YELLOW='\033[33m' + BLUE='\033[34m' + BOLD='\033[1m' + RESET='\033[0m' +else + RED='' + GREEN='' + YELLOW='' + BLUE='' + BOLD='' + RESET='' +fi -# ============== FUNÇÕES SIMPLIFICADAS ============== -print_step() { - echo "[$1/$2] $3" -} +log_line() { + printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG" +} -install_pkg() { - echo " -> Instalando $1..." - apt-get install -y -q $1 > /dev/null 2>&1 +info() { + printf " ${BLUE}->${RESET} %s\n" "$*" + log_line "INFO: $*" } -# ============== DETECÇÃO DO DISPOSITIVO ============== -echo "=== Configurando Termux Linux ===" -echo "" +ok() { + printf " ${GREEN}✓${RESET} %s\n" "$*" + log_line "OK: $*" +} -DEVICE_BRAND=$(getprop ro.product.brand 2>/dev/null || echo "Unknown") -GPU_VENDOR=$(getprop ro.hardware.egl 2>/dev/null || echo "") +warn() { + printf " ${YELLOW}!${RESET} %s\n" "$*" + log_line "AVISO: $*" +} -echo "Dispositivo: $DEVICE_BRAND" +_stop_spinner() { + if [ -n "${SPINNER_PID:-}" ]; then + kill "$SPINNER_PID" 2>/dev/null || true + wait "$SPINNER_PID" 2>/dev/null || true + printf "\r\033[K" + SPINNER_PID="" + fi +} -# ============== SELEÇÃO DO DESKTOP ============== -echo "" -echo "Escolha o Desktop:" -echo "1) XFCE4 (recomendado)" -echo "2) LXQt (leve)" -echo "3) MATE (médio)" -echo "4) KDE (pesado)" -read -p "Opção [1-4, padrão=1]: " DE_INPUT -DE_INPUT=${DE_INPUT:-1} - -case $DE_INPUT in - 1) DE_NAME="XFCE4";; - 2) DE_NAME="LXQt";; - 3) DE_NAME="MATE";; - 4) DE_NAME="KDE Plasma";; -esac -echo "Selecionado: $DE_NAME" - -# ============== INSTALAÇÃO (11 PASSOS) ============== -TOTAL=11 -CURRENT=0 +show_log_tail() { + if [ -s "$LOG" ]; then + echo "" + echo " Últimas linhas do log:" + tail -n 25 "$LOG" | sed 's/^/ /' + fi +} + +die() { + _stop_spinner + echo "" + printf " ${RED}ERRO:${RESET} %s\n" "$*" >&2 + echo " Log completo: $LOG" >&2 + show_log_tail >&2 + exit 1 +} + +on_error() { + local line="$1" + local cmd="$2" + _stop_spinner + echo "" + printf " ${RED}ERRO inesperado na linha %s:${RESET} %s\n" "$line" "$cmd" >&2 + echo " Log completo: $LOG" >&2 + show_log_tail >&2 + exit 1 +} + +trap 'on_error "$LINENO" "$BASH_COMMAND"' ERR +trap '_stop_spinner' EXIT + +start_step() { + _stop_spinner + CURRENT=$((CURRENT + 1)) + local msg="$1" + local pct=$((CURRENT * 100 / TOTAL)) + local filled=$((pct * 24 / 100)) + local bar_fill="" + local bar="" + + if [ "$filled" -gt 0 ]; then + bar_fill=$(printf '%*s' "$filled" '' | tr ' ' '=') + fi + + if [ "$filled" -lt 24 ]; then + bar=$(printf "%-24s" "${bar_fill}>") + else + bar="$bar_fill" + fi + + echo "" + printf " ${BOLD}[%02d/%02d]${RESET} %s\n" "$CURRENT" "$TOTAL" "$msg" + log_line "PASSO $CURRENT/$TOTAL: $msg" + + ( + i=0 + chars='|/-\' + while true; do + printf "\r [%-24s] %3d%% %s" "$bar" "$pct" "${chars:$((i % 4)):1}" + i=$((i + 1)) + sleep 0.2 + done + ) & + SPINNER_PID=$! +} + +end_step() { + _stop_spinner + ok "Passo $CURRENT/$TOTAL concluído" +} + +run_cmd() { + local desc="$1" + shift + log_line "CMD: $*" + if ! "$@" >> "$LOG" 2>&1; then + die "Falha em: $desc" + fi +} + +install_required() { + local label="$1" + shift + info "Instalando: $*" + run_cmd "instalar $label" pkg install -y "$@" +} + +install_optional_packages() { + local pkg_name="" + for pkg_name in "$@"; do + info "Tentando instalar pacote opcional: $pkg_name" + if pkg install -y "$pkg_name" >> "$LOG" 2>&1; then + ok "Instalado: $pkg_name" + else + warn "Pacote opcional indisponível ou falhou: $pkg_name" + fi + done +} + +install_any_required() { + local label="$1" + shift + local pkg_name="" + + for pkg_name in "$@"; do + info "Tentando instalar $label: $pkg_name" + if pkg install -y "$pkg_name" >> "$LOG" 2>&1; then + ok "Instalado: $pkg_name" + return 0 + fi + done + + die "Nenhuma opção disponível para instalar: $label ($*)" +} + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +require_termux() { + if [ "${PREFIX:-}" != "/data/data/com.termux/files/usr" ]; then + die "Este script deve ser executado dentro do Termux normal, não em Linux/PC/proot." + fi + + command_exists pkg || die "Comando 'pkg' não encontrado. Atualize/reinstale o Termux." +} + +check_internet() { + if command_exists curl; then + curl -fsI --connect-timeout 12 https://packages.termux.dev >/dev/null 2>>"$LOG" && return 0 + curl -fsI --connect-timeout 12 https://google.com >/dev/null 2>>"$LOG" && return 0 + fi + + ping -c 1 -W 8 packages.termux.dev >> "$LOG" 2>&1 && return 0 + ping -c 1 -W 8 google.com >> "$LOG" 2>&1 && return 0 + + return 1 +} + +wait_package_manager() { + local waited=0 + while pgrep -x apt >/dev/null 2>&1 || \ + pgrep -x apt-get >/dev/null 2>&1 || \ + pgrep -x dpkg >/dev/null 2>&1; do + if [ "$waited" -ge 90 ]; then + die "Outro processo do apt/dpkg está travado há muito tempo. Feche outros Termux e tente novamente." + fi + warn "Aguardando outro processo apt/dpkg terminar..." + sleep 3 + waited=$((waited + 3)) + done +} + +read_choice() { + local prompt="$1" + local default="$2" + local pattern="$3" + local value="" + + while true; do + read -r -p "$prompt" value || value="$default" + value="${value:-$default}" + if [[ "$value" =~ $pattern ]]; then + printf '%s\n' "$value" + return 0 + fi + echo " Opção inválida. Tente novamente." + done +} + +read_yes_no() { + local prompt="$1" + local default="$2" + local value="" + + while true; do + read -r -p "$prompt" value || value="$default" + value="${value:-$default}" + value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]')" + case "$value" in + s|sim|y|yes) printf 's\n'; return 0 ;; + n|nao|não|no) printf 'n\n'; return 0 ;; + *) echo " Responda com s ou n." ;; + esac + done +} + +banner() { + clear 2>/dev/null || true + echo "" + cat << 'ART' +| | |\ | | | \_/ +|___ | | \| \__/ / \ + + __ __ __ __ + /\ |\ | | \ |__) / \ | | \ +/~~\ | \| |__/ | \ \__/ | |__/ +ART + echo "" + echo " ======================================" + echo " Configurando Termux Linux/X11" + echo " ======================================" + echo "" +} + +collect_device_info() { + ARCH="$(uname -m)" + DEVICE_BRAND="$(getprop ro.product.brand 2>/dev/null || echo 'Unknown')" + DEVICE_MODEL="$(getprop ro.product.model 2>/dev/null || echo 'Unknown')" + GPU_INFO="$( + { + getprop ro.hardware.egl + getprop ro.hardware.vulkan + getprop ro.board.platform + getprop ro.hardware + } 2>/dev/null | tr '[:upper:]' '[:lower:]' + )" -# Passo 1 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Atualizando sistema" -apt-get update -y -q > /dev/null 2>&1 -apt-get upgrade -y -q > /dev/null 2>&1 - -# Passo 2 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Adicionando repositórios" -apt-get install -y -q x11-repo tur-repo > /dev/null 2>&1 - -# Passo 3 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Instalando servidor gráfico" -apt-get install -y -q termux-x11-nightly xorg-xrandr > /dev/null 2>&1 - -# Passo 4 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Instalando $DE_NAME" -case $DE_INPUT in - 1) install_pkg "xfce4 xfce4-terminal xfce4-whiskermenu-plugin plank-reloaded thunar mousepad";; - 2) install_pkg "lxqt qterminal pcmanfm-qt featherpad";; - 3) install_pkg "mate mate-tweak plank-reloaded mate-terminal";; - 4) install_pkg "plasma-desktop konsole dolphin";; -esac - -# Passo 5 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Instalando drivers GPU" -apt-get install -y -q mesa-zink vulkan-loader-android > /dev/null 2>&1 -[ "$GPU_DRIVER" == "freedreno" ] && apt-get install -y -q mesa-vulkan-icd-freedreno > /dev/null 2>&1 - -# Passo 6 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Instalando áudio" -apt-get install -y -q pulseaudio > /dev/null 2>&1 - -# Passo 7 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Instalando apps" -apt-get install -y -q firefox vlc git wget curl > /dev/null 2>&1 - -# Passo 8 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Instalando Python" -apt-get install -y -q python > /dev/null 2>&1 -pip install flask > /dev/null 2>&1 - -# Passo 9 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Instalando Wine" -apt-get remove -y wine-stable > /dev/null 2>&1 -apt-get install -y -q hangover-wine hangover-wowbox64 > /dev/null 2>&1 -ln -sf /data/data/com.termux/files/usr/opt/hangover-wine/bin/wine /data/data/com.termux/files/usr/bin/wine 2>/dev/null - -# Passo 10 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Criando scripts" -cat > ~/start-linux.sh << 'EOF' + info "Arquitetura: $ARCH" + info "Dispositivo: $DEVICE_BRAND $DEVICE_MODEL" + + if [ "$ARCH" != "aarch64" ]; then + warn "Wine/Hangover e aceleração gráfica costumam funcionar melhor em ARM64/aarch64." + fi +} + +choose_gpu() { + echo "" + echo " -- Configuração de GPU --" + echo " 1) Automático (recomendado)" + echo " 2) Forçar aceleração GPU Adreno/Freedreno" + echo " 3) Desativar aceleração GPU/usar software" + echo "" + + local gpu_option="" + gpu_option="$(read_choice ' Opção [1-3, padrão=1]: ' '1' '^[1-3]$')" + + case "$gpu_option" in + 1) + if printf '%s' "$GPU_INFO" | grep -Eq 'adreno|qcom|qualcomm|msm'; then + GPU_DRIVER="freedreno" + GPU_ENABLED="true" + ok "GPU Qualcomm/Adreno detectada. Aceleração será ativada." + else + GPU_DRIVER="software" + GPU_ENABLED="false" + warn "GPU Adreno não detectada. Usarei modo compatível sem aceleração forçada." + fi + ;; + 2) + GPU_DRIVER="freedreno" + GPU_ENABLED="true" + warn "Aceleração GPU foi forçada. Se a tela ficar preta/travar, rode novamente e escolha a opção 3." + ;; + 3) + GPU_DRIVER="software" + GPU_ENABLED="false" + ok "Aceleração GPU desativada." + ;; + esac +} + +choose_desktop() { + echo "" + echo " -- Escolha o Desktop --" + echo " 1) XFCE4 (recomendado/mais estável)" + echo " 2) LXQt (leve)" + echo " 3) MATE (médio)" + echo " 4) KDE Plasma (pesado/experimental)" + echo "" + + DE_INPUT="$(read_choice ' Opção [1-4, padrão=1]: ' '1' '^[1-4]$')" + + case "$DE_INPUT" in + 1) + DE_NAME="XFCE4" + DE_COMMAND="startxfce4" + DE_CORE_PACKAGES=(xfce4 dbus pulseaudio) + DE_EXTRA_PACKAGES=(xfce4-terminal thunar mousepad pavucontrol shared-mime-info fontconfig) + ;; + 2) + DE_NAME="LXQt" + DE_COMMAND="startlxqt" + DE_CORE_PACKAGES=(lxqt-session openbox dbus pulseaudio) + DE_EXTRA_PACKAGES=(lxqt-panel pcmanfm-qt qterminal featherpad gtk3 pavucontrol shared-mime-info fontconfig) + ;; + 3) + DE_NAME="MATE" + DE_COMMAND="mate-session" + DE_CORE_PACKAGES=(mate-session-manager marco dbus pulseaudio) + DE_EXTRA_PACKAGES=(mate-panel mate-terminal fontconfig shared-mime-info) + ;; + 4) + DE_NAME="KDE Plasma" + DE_COMMAND="startplasma-x11" + DE_CORE_PACKAGES=(plasma-desktop dbus pulseaudio) + DE_EXTRA_PACKAGES=(konsole fontconfig shared-mime-info) + ;; + esac + + ok "Desktop escolhido: $DE_NAME" +} + +prepare_environment() { + export DEBIAN_FRONTEND=noninteractive + export LANG=C.UTF-8 + export LC_ALL=C.UTF-8 + export TMPDIR="${TMPDIR:-$PREFIX/tmp}" + + mkdir -p "$TMPDIR" + mkdir -p "$PREFIX/etc/apt/apt.conf.d" + + cat > "$PREFIX/etc/apt/apt.conf.d/99termux-noninteractive" <<'APTCONF' +DPkg::Options { + "--force-confdef"; + "--force-confold"; +}; +APTCONF +} + +install_desktop() { + # No Termux atual, o pacote dbus-x11 pode não existir. Por isso ele não é usado + # como dependência obrigatória. O script usa dbus-launch apenas se o comando existir. + local pkg_name="" + + for pkg_name in "${DE_CORE_PACKAGES[@]}"; do + install_required "pacote obrigatório do $DE_NAME: $pkg_name" "$pkg_name" + done + + install_optional_packages "${DE_EXTRA_PACKAGES[@]}" + + if ! command_exists "$DE_COMMAND"; then + die "O comando '$DE_COMMAND' não foi encontrado após instalar $DE_NAME. Veja o log e tente outro desktop." + fi +} + +install_gpu_drivers() { + if [ "$GPU_ENABLED" = "true" ]; then + info "Instalando base gráfica Vulkan/Zink" + if pkg install -y mesa-zink vulkan-loader-android >> "$LOG" 2>&1; then + ok "Base gráfica instalada" + else + warn "Drivers mesa-zink/vulkan-loader-android falharam. Vou continuar em modo software." + GPU_ENABLED="false" + GPU_DRIVER="software" + return 0 + fi + + if [ "$GPU_DRIVER" = "freedreno" ]; then + install_optional_packages mesa-vulkan-icd-freedreno vulkan-tools + fi + else + ok "Modo software selecionado. Drivers GPU extras não serão forçados." + fi +} + +install_wine_if_requested() { + if [ "$INSTALL_WINE" != "s" ]; then + ok "Wine/Hangover ignorado." + return 0 + fi + + if [ "${ARCH:-}" != "aarch64" ]; then + warn "Seu aparelho não parece ser ARM64/aarch64. Wine/Hangover pode não funcionar bem." + fi + + if dpkg -s wine-stable >/dev/null 2>&1; then + run_cmd "remover wine-stable antigo" pkg remove -y wine-stable + fi + + install_optional_packages hangover-wine hangover-wowbox64 + + if [ -x "$PREFIX/opt/hangover-wine/bin/wine" ]; then + ln -sf "$PREFIX/opt/hangover-wine/bin/wine" "$PREFIX/bin/wine" + ok "Atalho 'wine' criado." + else + warn "Hangover Wine não parece ter sido instalado completamente." + fi +} + +write_start_script() { + cat > "${HOME}/start-linux.sh" </dev/null -pulseaudio --kill 2>/dev/null -sleep 1 -pulseaudio --start --exit-idle-time=-1 -export PULSE_SERVER=127.0.0.1 -termux-x11 :0 -ac & -sleep 2 +set -Eeuo pipefail + +LOG="${START_LOG}" +: > "\$LOG" + +export LANG=C.UTF-8 +export LC_ALL=C.UTF-8 +export TMPDIR="\${TMPDIR:-/data/data/com.termux/files/usr/tmp}" +mkdir -p "\$TMPDIR" + +export XDG_RUNTIME_DIR="\$TMPDIR" export DISPLAY=:0 -EOF - -if [ "$DE_INPUT" == "1" ]; then - echo "exec startxfce4" >> ~/start-linux.sh -elif [ "$DE_INPUT" == "2" ]; then - echo "exec startlxqt" >> ~/start-linux.sh -elif [ "$DE_INPUT" == "3" ]; then - echo "exec mate-session" >> ~/start-linux.sh -else - echo "exec startplasma-x11" >> ~/start-linux.sh -fi +export XDG_SESSION_TYPE=x11 +export QT_X11_NO_MITSHM=1 +export NO_AT_BRIDGE=1 +export PULSE_SERVER=127.0.0.1 +EOF_START + + if [ "$GPU_ENABLED" = "true" ]; then + cat >> "${HOME}/start-linux.sh" <<'EOF_GPU' +export GALLIUM_DRIVER=zink +export MESA_LOADER_DRIVER_OVERRIDE=zink +export MESA_NO_ERROR=1 +EOF_GPU + else + cat >> "${HOME}/start-linux.sh" <<'EOF_GPU' +export LIBGL_ALWAYS_SOFTWARE=1 +EOF_GPU + fi + + cat >> "${HOME}/start-linux.sh" </dev/null || true + pkill -f "termux-x11.*:0" 2>/dev/null || true + pulseaudio --kill >/dev/null 2>&1 || true +} + +start_audio() { + pulseaudio --start --exit-idle-time=-1 >> "\$LOG" 2>&1 || true + pactl load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1 >> "\$LOG" 2>&1 || true +} + +start_x11() { + am start --user 0 -n com.termux.x11/com.termux.x11.MainActivity >> "\$LOG" 2>&1 || true + termux-x11 :0 >> "\$LOG" 2>&1 & + sleep 3 +} + +echo "Iniciando Termux Linux/X11..." +stop_old_sessions +sleep 1 +start_audio +start_x11 + +start_desktop() { + cd "\$HOME" + + if command -v dbus-launch >/dev/null 2>&1; then + exec dbus-launch --exit-with-session ${DE_COMMAND} + fi + + echo "Aviso: dbus-launch não encontrado. Iniciando ${DE_NAME} sem dbus-launch." >> "\$LOG" + exec ${DE_COMMAND} +} + +start_desktop +EOF_START2 + + chmod +x "${HOME}/start-linux.sh" +} + +write_stop_script() { + cat > "${HOME}/stop-linux.sh" <<'EOF_STOP' +#!/data/data/com.termux/files/usr/bin/bash + +pkill -f "startxfce4|startlxqt|mate-session|startplasma-x11|xfce4-session|lxqt-session" 2>/dev/null || true +pkill -f "termux-x11.*:0" 2>/dev/null || true +pulseaudio --kill >/dev/null 2>&1 || true + +echo "Desktop finalizado." +EOF_STOP + + chmod +x "${HOME}/stop-linux.sh" +} -cat > ~/stop-linux.sh << 'EOF' +write_info_script() { + cat > "${HOME}/linux-info.sh" <<'EOF_INFO' #!/data/data/com.termux/files/usr/bin/bash -pkill -9 -f "termux.x11" 2>/dev/null -pkill -9 pulseaudio 2>/dev/null -echo "Desktop finalizado" -EOF -chmod +x ~/stop-linux.sh - -# Passo 11 -CURRENT=$((CURRENT+1)); print_step $CURRENT $TOTAL "Criando atalhos" -mkdir -p ~/Desktop -cat > ~/Desktop/Firefox.desktop << 'EOF' + +echo "===== Termux Linux/X11 - Diagnóstico =====" +echo "Data: $(date)" +echo "Arquitetura: $(uname -m)" +echo "PREFIX: ${PREFIX:-desconhecido}" +echo "DISPLAY: ${DISPLAY:-não definido}" +echo "" +echo "Comandos encontrados:" +for cmd in termux-x11 dbus-launch startxfce4 startlxqt mate-session startplasma-x11 pulseaudio; do + if command -v "$cmd" >/dev/null 2>&1; then + echo " ✓ $cmd -> $(command -v "$cmd")" + else + echo " - $cmd não encontrado" + fi +done + +echo "" +echo "Últimas linhas do log de instalação:" +tail -n 30 "$HOME/termux-linux-install.log" 2>/dev/null || true + +echo "" +echo "Últimas linhas do log de inicialização:" +tail -n 30 "$HOME/termux-linux-start.log" 2>/dev/null || true +EOF_INFO + + chmod +x "${HOME}/linux-info.sh" +} + +create_desktop_shortcuts() { + mkdir -p "${HOME}/Desktop" + + if command_exists firefox; then + cat > "${HOME}/Desktop/Firefox.desktop" <<'EOF_FIREFOX' [Desktop Entry] Name=Firefox Exec=firefox Type=Application -EOF -chmod +x ~/Desktop/*.desktop 2>/dev/null +Categories=Network;WebBrowser; +Terminal=false +EOF_FIREFOX + fi -# ============== FINALIZAÇÃO ============== -echo "" -echo "=== INSTALAÇÃO CONCLUÍDA ===" -echo "" -echo "Para iniciar o desktop: ./start-linux.sh" -echo "Para parar: ./stop-linux.sh" -echo "Abra o app Termux-X11 para ver a interface" -echo "" + if command_exists code-oss; then + cat > "${HOME}/Desktop/CodeOSS.desktop" <<'EOF_CODE' +[Desktop Entry] +Name=Code OSS +Exec=code-oss --no-sandbox +Type=Application +Categories=Development; +Terminal=false +EOF_CODE + fi + + chmod +x "${HOME}/Desktop"/*.desktop 2>/dev/null || true +} + +save_config() { + cat > "${STATE_DIR}/config.env" < Date: Sat, 23 May 2026 23:13:45 -0300 Subject: [PATCH 2/3] =?UTF-8?q?Corrigi=20o=20comando=20de=20permiss=C3=A3o?= =?UTF-8?q?=20do=20script,=20alterando=20chmod=20+X=20script-termux.sh=20p?= =?UTF-8?q?ara=20chmod=20+x=20script-termux.sh,=20garantindo=20que=20o=20a?= =?UTF-8?q?rquivo=20receba=20permiss=C3=A3o=20de=20execu=C3=A7=C3=A3o=20co?= =?UTF-8?q?rretamente.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3ce53a..d8c65fa 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ git clone https://github.com/lucasaguiar-la/linux-android.git cd linux-android # Da permissões para executar o script -chmod +X script-termux.sh +chmod +x script-termux.sh # Executa o script de instalação ./script-termux.sh From d3f715540aca52160009b442db4cc6af8b1dee44 Mon Sep 17 00:00:00 2001 From: eobarretooo Date: Sun, 24 May 2026 15:53:02 -0300 Subject: [PATCH 3/3] feat: modularizacao, menus interativos, suporte bilingue i18n e correcoes visuais e de robustez no script-termux --- README.md | 414 ++++++++++++++++++----- apps.conf | 48 +++ lang/en.sh | 233 +++++++++++++ lang/pt.sh | 233 +++++++++++++ lib/apps.sh | 164 +++++++++ lib/backup.sh | 153 +++++++++ lib/checks.sh | 37 +++ lib/common.sh | 315 ++++++++++++++++++ lib/desktop.sh | 144 ++++++++ lib/device.sh | 80 +++++ lib/i18n.sh | 79 +++++ lib/menu.sh | 346 +++++++++++++++++++ lib/scripts.sh | 159 +++++++++ lib/themes.sh | 133 ++++++++ lib/wine.sh | 86 +++++ script-termux.sh | 839 +++++++++-------------------------------------- 16 files changed, 2692 insertions(+), 771 deletions(-) create mode 100644 apps.conf create mode 100644 lang/en.sh create mode 100644 lang/pt.sh create mode 100644 lib/apps.sh create mode 100644 lib/backup.sh create mode 100644 lib/checks.sh create mode 100644 lib/common.sh create mode 100644 lib/desktop.sh create mode 100644 lib/device.sh create mode 100644 lib/i18n.sh create mode 100644 lib/menu.sh create mode 100644 lib/scripts.sh create mode 100644 lib/themes.sh create mode 100644 lib/wine.sh diff --git a/README.md b/README.md index d8c65fa..76a3820 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,372 @@ -# 🎀 Tutorial de criação de cyberdeck usando um celular antigo ✨ +# Termux Linux-Android Suite -## O que é um cyberdeck? 💻🩷 +Transforme seu Android em um desktop Linux completo usando Termux + Termux-X11 com um script modular, interativo e biligue (PT-BR / EN). -image +> **Creditos**: Este projeto e um fork do repositorio de [giovn-aguiar](https://github.com/giovn-aguiar/linux-android), que por sua vez e um fork do projeto original de [Lucas Aguiar](https://github.com/lucasaguiar-la/linux-android). Esta versao estende o conceito original para uma suite modular completa. +--- +## Indice +- [Recursos](#recursos) +- [Tutorial de Instalacao](#tutorial-de-instalacao) +- [Uso por Linha de Comando](#uso-por-linha-de-comando) +- [Aplicativos Disponiveis](#aplicativos-disponiveis) +- [Aplicativos Futuros](#aplicativos-futuros) +- [Desktops Suportados](#desktops-suportados) +- [Arquitetura do Projeto](#arquitetura-do-projeto) +- [FAQ e Solucao de Problemas](#faq-e-solucao-de-problemas) +- [Creditos e Licenca](#creditos-e-licenca) -Cyberdecks são computadores portáteis personalizados inspirados em ficção científica, cultura hacker e estética cyberpunk. -Normalmente são feitos reaproveitando hardware antigo, adicionando acessórios, modificações estéticas e sistemas Linux personalizados ✨ +--- -A ideia é transformar um dispositivo comum em algo único, funcional e com muita personalidade ♡ - -Neste tutorial, vamos utilizar um celular Android antigo para criar um ambiente Linux completo usando o Termux, transformando o aparelho em um mini computador portátil 💿⚡ +## Recursos -## O que você vai precisar 🧃 +- **Menu interativo no terminal** com submenus para cada funcionalidade +- **Biligue** (Portugues / English) com deteccao automatica do idioma do sistema +- **Instalacao modular** - instale, remova ou troque desktops e apps individualmente +- **Catalogo de apps** editavel (`apps.conf`) organizado por categoria +- **Configuracao de GPU** automatica (Adreno/Freedreno) ou manual +- **Temas e personalizacao** - temas escuros, icones, fontes, wallpapers +- **Wine/Hangover** para rodar apps Windows em ARM64 +- **Backup e restauracao** de todas as configuracoes +- **Diagnostico** de integridade e visualizacao de logs -Lembrando que aqui estou mostrando o que vou utilizar no cyberdeck que estou criando 🎀 -Mas o mais legal de cyberdecks é que literalmente não existe regra — você pode criar utilizando até uma TV Box no lugar do celular e adaptar tudo do seu jeito ♡ +--- -- Um celular ou tablet Android 📱 -- Powerbank 🔋 -- Teclado Bluetooth ou USB ⌨️ -- Mouse Bluetooth ou USB 🖱️ -- Hub USB 🌐 -- Aproximadamente 2GB livres 💾 -- Criatividade para personalizar seu cyberdeck 💻🩷✨ +## Tutorial de Instalacao -# Projeto Android Linux - Termux +### Pre-requisitos -## Descrição +1. **Termux** instalado (versao do [F-Droid](https://f-droid.org/packages/com.termux/) ou [GitHub](https://github.com/termux/termux-app/releases) - NAO use a versao da Play Store, ela esta desatualizada) +2. **Termux-X11** instalado ([GitHub Releases](https://github.com/nicknisi/termux-x11/releases)) +3. Conexao com a internet -Script de configuração automatizada para instalar e gerenciar um ambiente Linux completo no Termux. +### Passo 1: Preparar o Termux -## Recursos +Abra o Termux e atualize os pacotes: -- Detecção automática do dispositivo e GPU -- Suporte a múltiplos ambientes desktop (XFCE4, LXQt, MATE, KDE) -- Aceleração gráfica otimizada por GPU -- Instalação simplificada e automatizada -- Compatibilidade com smartphones e tablets +```bash +pkg update -y && pkg upgrade -y +``` -## Ambientes Desktop Suportados +### Passo 2: Instalar o Git -| Desktop | Peso | Recomendação | -|---------|------|--------------| -| XFCE4 | Médio | Recomendado | -| LXQt | Leve | Para dispositivos antigos | -| MATE | Médio | Alternativa estável | -| KDE | Pesado | Para dispositivos poderosos | +```bash +pkg install -y git +``` -## Instalação +### Passo 3: Clonar o projeto -1. Instale o [Termux](https://f-droid.org/pt_BR/packages/com.termux/) do F-Droid -2. Abra o Termux e dê permissões para acesso ao armazenamento do celular: +```bash +git clone https://github.com/eobarretooo/linux-android.git +cd linux-android ``` -termux-setup-storage + +### Passo 4: Dar permissao de execucao + +```bash +chmod +x script-termux.sh ``` -3. Desbloqueie o modo Desenvolvedor no seu aparelho -4. Em 'Opções do Desenvolvedor' desabilite a opção 'Desativar restrições de processos filhos' (ou 'Disable child process restrictions') -5. Instale o git: + +### Passo 5: Rodar o script + +```bash +./script-termux.sh ``` -pkg install git + +Na primeira execucao, o script ira: + +1. Pedir para selecionar o **idioma** (Portugues ou English) +2. Abrir o **menu principal** com todas as opcoes + +### Passo 6: Instalacao Completa (Opcao 1 do menu) + +Ao selecionar "Instalacao Completa", o script faz tudo automaticamente: + +| Etapa | O que acontece | +|-------|----------------| +| 1 | Prepara o ambiente e corrige pacotes pendentes | +| 2 | Atualiza o sistema (`pkg update && upgrade`) | +| 3 | Adiciona repositorios (`x11-repo`, `tur-repo`) | +| 4 | Instala o servidor grafico (Termux-X11) | +| 5 | Instala o desktop escolhido (XFCE4, LXQt, MATE ou KDE) | +| 6 | Configura drivers de GPU | +| 7 | Instala audio (PulseAudio) | +| 8 | Instala apps e utilitarios basicos | +| 9 | Configura Wine/Hangover (opcional) | +| 10 | Cria scripts de start/stop/info | +| 11 | Cria atalhos no desktop | + +### Passo 7: Iniciar o desktop + +Depois da instalacao, basta rodar: + +```bash +~/start-linux.sh ``` -6. Clone este repositório: + +E abrir o app **Termux-X11** no seu celular para ver a interface grafica. + +Para parar: + +```bash +~/stop-linux.sh ``` -git clone https://github.com/lucasaguiar-la/linux-android.git + +Para ver o diagnostico: + +```bash +~/linux-info.sh ``` -7. Após execute: + +--- + +## Uso por Linha de Comando + +Alem do menu interativo, voce pode usar flags para automatizar: + +```bash +# Mostra ajuda +./script-termux.sh --help + +# Forca idioma +./script-termux.sh --lang en + +# Instalacao completa automatizada +./script-termux.sh --install + +# Instala apenas um desktop especifico +./script-termux.sh --desktop xfce4 + +# Instala um app do catalogo +./script-termux.sh --app firefox ``` -# Acessa a pasta clonada -cd linux-android -# Da permissões para executar o script -chmod +x script-termux.sh +--- + +## Aplicativos Disponiveis + +Estes sao os apps que vem no catalogo (`apps.conf`) e podem ser instalados pelo menu: + +### Navegadores + +| App | Pacote | Descricao | +|-----|--------|-----------| +| Firefox | `firefox` | Navegador completo com suporte a extensoes | +| Chromium | `chromium` | Navegador baseado no motor do Chrome | + +### Editores de Codigo + +| App | Pacote | Descricao | +|-----|--------|-----------| +| Code OSS | `code-oss` | VS Code open-source para Termux | +| Neovim | `neovim` | Editor de texto avancado no terminal | +| Nano | `nano` | Editor simples para terminal | +| Micro | `micro` | Editor moderno para terminal com mouse | + +### Ferramentas de Desenvolvimento + +| App | Pacote | Descricao | +|-----|--------|-----------| +| Git | `git` | Controle de versao | +| Python | `python` | Linguagem Python 3 + pip | +| Node.js | `nodejs` | Runtime JavaScript + npm | +| Clang | `clang` | Compilador C/C++ | +| Rust | `rust` | Linguagem Rust + cargo | +| Go | `golang` | Linguagem Go | +| Ruby | `ruby` | Linguagem Ruby + gem | + +### Multimidia + +| App | Pacote | Descricao | +|-----|--------|-----------| +| VLC | `vlc` | Player de video e audio universal | +| MPV | `mpv` | Player leve de video | +| GIMP | `gimp` | Editor de imagens profissional | +| FFmpeg | `ffmpeg` | Conversor e encoder de midia | + +### Utilitarios + +| App | Pacote | Descricao | +|-----|--------|-----------| +| Neofetch | `neofetch` | Mostra info do sistema com estilo | +| htop | `htop` | Monitor de processos interativo | +| tmux | `tmux` | Multiplexador de terminal | +| Thunar | `thunar` | Gerenciador de arquivos grafico | +| Ranger | `ranger` | Gerenciador de arquivos no terminal | +| bat | `bat` | Substituto do `cat` com syntax highlight | +| ripgrep | `ripgrep` | Busca rapida em arquivos (substituto do grep) | +| fzf | `fzf` | Buscador fuzzy interativo | +| zip/unzip | `zip unzip` | Compactador/descompactador ZIP | +| tar | `tar` | Compactador/descompactador TAR | + +### Rede + +| App | Pacote | Descricao | +|-----|--------|-----------| +| curl | `curl` | Transferencia de dados via URL | +| wget | `wget` | Download de arquivos | +| OpenSSH | `openssh` | Cliente e servidor SSH | +| Nmap | `nmap` | Scanner de rede e portas | +| WoL | `wol` | Wake-on-LAN para ligar PCs remotamente | +| iproute2 | `iproute2` | Ferramentas de rede (ip, ss, etc) | + +--- + +## Aplicativos Futuros + +Estes apps ja funcionam ou tem potencial para funcionar bem no Termux com X11, e podem ser adicionados ao catalogo no futuro: + +### Produtividade e Escritorio + +| App | Pacote | Status | Notas | +|-----|--------|--------|-------| +| LibreOffice | `libreoffice` | Funcional | Suite de escritorio completa (pesado, ~500MB) | +| Thunderbird | `thunderbird` | Funcional | Cliente de email | +| Evince | `evince` | Funcional | Leitor de PDF leve | +| Zathura | `zathura` | Funcional | Leitor de PDF minimalista | +| Galculator | `galculator` | Funcional | Calculadora grafica | +| Mousepad | `mousepad` | Funcional | Editor de texto simples (XFCE) | + +### Desenvolvimento + +| App | Pacote | Status | Notas | +|-----|--------|--------|-------| +| MariaDB | `mariadb` | Funcional | Banco de dados SQL | +| PostgreSQL | `postgresql` | Funcional | Banco de dados avancado | +| Redis | `redis` | Funcional | Cache e banco NoSQL | +| SQLite | `sqlite` | Funcional | Banco de dados em arquivo | +| PHP | `php` | Funcional | Linguagem web + composer | +| Perl | `perl` | Funcional | Linguagem de script | +| Lua | `lua54` | Funcional | Linguagem leve e rapida | +| CMake | `cmake` | Funcional | Sistema de build | +| Meson | `meson` | Funcional | Sistema de build moderno | +| Docker (via proot) | N/A | Experimental | Precisa de proot-distro | + +### Multimidia (Futuro) + +| App | Pacote | Status | Notas | +|-----|--------|--------|-------| +| Inkscape | `inkscape` | Funcional | Editor de vetores SVG | +| Audacity | N/A | Experimental | Editor de audio (precisa compilar) | +| OBS Studio | N/A | Nao funcional | Precisa de GPU real e pipewire | +| Blender | N/A | Nao funcional | Muito pesado para Android | +| ImageMagick | `imagemagick` | Funcional | Manipulacao de imagens via CLI | + +### Rede e Seguranca + +| App | Pacote | Status | Notas | +|-----|--------|--------|-------| +| Wireshark (tshark) | `tshark` | Funcional | Analise de pacotes de rede (CLI) | +| Hydra | `hydra` | Funcional | Teste de forca bruta | +| John the Ripper | `john` | Funcional | Cracker de senhas | +| Aircrack-ng | `aircrack-ng` | Funcional | Suite de auditoria WiFi | +| Metasploit | N/A | Via proot | Framework de pentesting | +| SQLMap | `python` + pip | Funcional | Teste de injecao SQL | +| Nikto | `perl` + git | Funcional | Scanner de vulnerabilidades web | + +### Terminais e Shells + +| App | Pacote | Status | Notas | +|-----|--------|--------|-------| +| Zsh | `zsh` | Funcional | Shell avancado | +| Fish | `fish` | Funcional | Shell amigavel com autocomplete | +| Oh My Zsh | via curl | Funcional | Framework de configuracao do Zsh | +| Starship | `starship` | Funcional | Prompt customizavel multi-shell | +| Alacritty | `alacritty` | Funcional | Terminal acelerado por GPU | + +> **Como adicionar novos apps**: Edite o arquivo `apps.conf` seguindo o formato `categoria|Nome|pacote`. O app vai aparecer automaticamente no menu. + +--- + +## Desktops Suportados + +| Desktop | Peso | Estabilidade | Recomendacao | +|---------|------|-------------|--------------| +| **XFCE4** | Leve (~150MB) | Muito estavel | Recomendado para todos | +| **LXQt** | Muito leve (~120MB) | Estavel | Bom para dispositivos fracos | +| **MATE** | Medio (~200MB) | Estavel | Para quem prefere estilo GNOME 2 | +| **KDE Plasma** | Pesado (~400MB) | Experimental | Bonito mas pode travar em devices fracos | + +--- + +## Arquitetura do Projeto -# Executa o script de instalação -./script-termux.sh ``` -8. Selecione o ambiente desktop desejado -9. Aguarde a instalação ser concluída -10. Rode o script: +linux-android/ +|-- script-termux.sh # Ponto de entrada principal +|-- apps.conf # Catalogo de apps editavel +|-- lang/ +| |-- pt.sh # Strings em Portugues +| |-- en.sh # Strings em English +|-- lib/ + |-- common.sh # Cores, logs, spinner, helpers + |-- i18n.sh # Sistema de traducao + |-- checks.sh # Validacoes de ambiente + |-- device.sh # Deteccao de hardware/GPU + |-- desktop.sh # Gerenciamento de desktops + |-- apps.sh # Instalacao de apps do catalogo + |-- wine.sh # Gerenciamento de Wine/Hangover + |-- themes.sh # Temas, icones, fontes, wallpapers + |-- scripts.sh # Geracao de start/stop/info scripts + |-- backup.sh # Backup e restauracao + |-- menu.sh # Sistema de menus interativos ``` -# Voltar para a home -cd -#Executa o script -./start-linux.sh -``` -11. Instale o [Termux X11](https://github.com/termux/termux-x11/releases/tag/nightly) para acessar a interface gráfica -12. Abra o Termux X11 e o provedor gráfico já estará funcionando +--- -## Detecção de Hardware +## FAQ e Solucao de Problemas -O script detecta automaticamente: -- **Marca do dispositivo**: Samsung, Xiaomi, etc. -- **GPU**: Adreno (Samsung/Qualcomm) ou genérica -- **Driver gráfico**: Freedom ou Zink (compatibilidade) +### "Tela preta ao abrir o Termux-X11" -## Requisitos +- Rode `~/stop-linux.sh` e depois `~/start-linux.sh` novamente +- Se persistir, va em **Menu > GPU > Desativar aceleracao** e reinicie -- Android 5.0+ -- Termux instalado -- Termux: X11 -- ~2GB de espaço livre -- Conexão com internet +### "Termux-X11 nao abre / app nao instalado" -## Notas +- Instale o APK do Termux-X11 pelo [GitHub](https://github.com/nicknisi/termux-x11/releases) +- O script instala o pacote `termux-x11` interno, mas o app Android precisa ser instalado manualmente -- Use XFCE4 para melhor equilíbrio entre performance e funcionalidade -- Dispositivos antigos: prefira LXQt -- Dispositivos topo de linha: experimente KDE -- Para executar automatizamente o `./start-linux.sh` toda vez que abrir o Termux, faça o seguinte: -``` -nano ~/.bashrc +### "Sem audio" + +- Va em **Menu > Audio > Reinstalar PulseAudio** +- Depois rode `~/stop-linux.sh` e `~/start-linux.sh` -# Cole o conteúdo abaixo: -./start-linux.sh +### "Wine nao funciona" + +- Wine/Hangover so funciona em dispositivos **ARM64 (aarch64)** +- Rode `uname -m` para verificar sua arquitetura + +### "Erro de dpkg travado" + +- O script detecta isso automaticamente e espera ate 90 segundos +- Se persistir, rode manualmente: `dpkg --configure -a` + +### "Quero adicionar um app novo" + +Edite o arquivo `apps.conf`: + +``` +# Formato: categoria|Nome|pacote +utilities|Meu App|meu-pacote ``` -## Licença +O app aparece automaticamente no menu na proxima execucao. + +### "Quero trocar de desktop" + +Va em **Menu > Configurar Desktop > Trocar ambiente** e selecione o novo. O anterior nao e removido automaticamente. + +--- + +## Creditos e Licenca + +- **Projeto original**: [Lucas Aguiar - linux-android](https://github.com/lucasaguiar-la/linux-android) +- **Fork intermediario**: [giovn-aguiar - linux-android](https://github.com/giovn-aguiar/linux-android) +- **Versao modular**: Extensao com menus, i18n, catalogo de apps e sistema de backup +- **Licenca**: MIT + +--- -MIT +> Feito para quem quer um Linux de verdade no bolso. diff --git a/apps.conf b/apps.conf new file mode 100644 index 0000000..85374f0 --- /dev/null +++ b/apps.conf @@ -0,0 +1,48 @@ +# Catálogo de Aplicativos / Application Catalog +# Formato: categoria|nome_exibicao|pacote_termux +# Format: category|display_name|termux_package + +# Navegadores / Browsers +browsers|Firefox|firefox +browsers|Chromium|chromium + +# Editores / Editors +editors|Code OSS (VS Code)|code-oss +editors|Neovim|neovim +editors|Nano|nano +editors|Micro|micro + +# Ferramentas de Dev / Dev Tools +devtools|Git|git +devtools|Python|python +devtools|Node.js|nodejs +devtools|Clang (C/C++)|clang +devtools|Rust|rust +devtools|Go|golang +devtools|Ruby|ruby + +# Multimídia / Multimedia +multimedia|VLC|vlc +multimedia|MPV|mpv +multimedia|GIMP|gimp +multimedia|FFmpeg|ffmpeg + +# Utilitários / Utilities +utilities|Neofetch|neofetch +utilities|htop|htop +utilities|tmux|tmux +utilities|Thunar (File Manager)|thunar +utilities|Ranger (TUI File Manager)|ranger +utilities|bat (cat replacement)|bat +utilities|ripgrep|ripgrep +utilities|fzf|fzf +utilities|zip/unzip|zip unzip +utilities|tar|tar + +# Rede / Network +network|curl|curl +network|wget|wget +network|OpenSSH|openssh +network|Nmap|nmap +network|WoL|wol +network|iproute2|iproute2 diff --git a/lang/en.sh b/lang/en.sh new file mode 100644 index 0000000..f070101 --- /dev/null +++ b/lang/en.sh @@ -0,0 +1,233 @@ +# ===== General ===== +STRINGS[lang_name]="English" +STRINGS[yes_chars]="y|yes|s|sim" +STRINGS[no_chars]="n|no|nao|não" +STRINGS[yes_letter]="y" +STRINGS[no_letter]="n" +STRINGS[yes_no_prompt]="y/n" +STRINGS[invalid_option]="Invalid option. Try again." +STRINGS[answer_yes_no]="Answer with y or n." +STRINGS[press_enter]="Press ENTER to continue..." +STRINGS[back]="Back" +STRINGS[exit]="Exit" +STRINGS[or]="or" + +# ===== Banner ===== +STRINGS[banner_title]="Configuring Termux Linux/X11" +STRINGS[banner_status_desktop]="Desktop" +STRINGS[banner_status_gpu]="GPU" +STRINGS[banner_status_wine]="Wine" +STRINGS[banner_status_status]="Status" +STRINGS[status_running]="running" +STRINGS[status_stopped]="stopped" +STRINGS[status_installed]="installed" +STRINGS[status_not_installed]="not installed" +STRINGS[status_enabled]="enabled" +STRINGS[status_disabled]="disabled" + +# ===== Logging ===== +STRINGS[install_log_at]="Installation log: %s" +STRINGS[log_complete]="Full log: %s" +STRINGS[last_log_lines]="Last log lines:" +STRINGS[error_prefix]="ERROR" +STRINGS[unexpected_error_line]="Unexpected ERROR at line %s: %s" +STRINGS[step_completed]="Step %s/%s completed" +STRINGS[failed_at]="Failed at: %s" +STRINGS[attempt_failed]="Attempt %s/%s failed for %s. Retrying in %ss..." + +# ===== Installation ===== +STRINGS[installing]="Installing: %s" +STRINGS[trying_install_optional]="Trying to install optional package: %s" +STRINGS[installed]="Installed: %s" +STRINGS[optional_pkg_failed]="Optional package unavailable or failed: %s" +STRINGS[trying_install]="Trying to install %s: %s" +STRINGS[no_option_available]="No option available to install: %s (%s)" +STRINGS[already_installed]="Already installed: %s" +STRINGS[not_installed]="Not installed: %s" + +# ===== Checks ===== +STRINGS[checking_internet]="Checking internet..." +STRINGS[no_internet]="No internet connection or DNS unavailable." +STRINGS[must_run_in_termux]="This script must be run inside regular Termux, not in Linux/PC/proot." +STRINGS[pkg_not_found]="Command 'pkg' not found. Update/reinstall Termux." +STRINGS[waiting_apt]="Waiting for another apt/dpkg process to finish..." +STRINGS[apt_stuck]="Another apt/dpkg process has been stuck for too long. Close other Termux sessions and try again." + +# ===== Device ===== +STRINGS[architecture]="Architecture: %s" +STRINGS[device_info]="Device: %s %s" +STRINGS[wine_arm64_warning]="Wine/Hangover and GPU acceleration work best on ARM64/aarch64." + +# ===== GPU ===== +STRINGS[gpu_config_title]="GPU Configuration" +STRINGS[gpu_auto]="Automatic (recommended)" +STRINGS[gpu_force_adreno]="Force Adreno/Freedreno GPU acceleration" +STRINGS[gpu_disable]="Disable GPU acceleration / use software" +STRINGS[gpu_prompt]="Option [1-3, default=1]: " +STRINGS[gpu_adreno_detected]="Qualcomm/Adreno GPU detected. Acceleration will be enabled." +STRINGS[gpu_adreno_not_detected]="Adreno GPU not detected. Using compatible mode without forced acceleration." +STRINGS[gpu_forced_warning]="GPU acceleration was forced. If the screen goes black/freezes, run again and choose option 3." +STRINGS[gpu_disabled]="GPU acceleration disabled." +STRINGS[gpu_base_installed]="Graphics base installed" +STRINGS[gpu_base_install]="Installing Vulkan/Zink graphics base" +STRINGS[gpu_base_failed]="mesa-zink/vulkan-loader-android drivers failed. Continuing in software mode." +STRINGS[gpu_software_mode]="Software mode selected. Extra GPU drivers will not be forced." + +# ===== Desktop ===== +STRINGS[desktop_title]="Choose Desktop" +STRINGS[desktop_xfce4]="XFCE4 (recommended/most stable)" +STRINGS[desktop_lxqt]="LXQt (lightweight)" +STRINGS[desktop_mate]="MATE (medium)" +STRINGS[desktop_kde]="KDE Plasma (heavy/experimental)" +STRINGS[desktop_prompt]="Option [1-4, default=1]: " +STRINGS[desktop_chosen]="Desktop chosen: %s" +STRINGS[desktop_command_not_found]="Command '%s' was not found after installing %s. Check the log and try another desktop." +STRINGS[desktop_current]="Current desktop: %s" +STRINGS[desktop_change]="Change desktop environment" +STRINGS[desktop_reinstall]="Reinstall current desktop" +STRINGS[desktop_remove]="Remove current desktop" +STRINGS[desktop_view_status]="View installed desktop" +STRINGS[desktop_remove_confirm]="Are you sure you want to remove %s? [y/N]: " +STRINGS[desktop_removed]="Desktop %s removed." +STRINGS[desktop_none_installed]="No desktop installed." +STRINGS[desktop_config_title]="Configure Desktop" + +# ===== Apps ===== +STRINGS[apps_title]="Manage Applications" +STRINGS[apps_browsers]="Browsers" +STRINGS[apps_editors]="Code Editors" +STRINGS[apps_devtools]="Dev Tools" +STRINGS[apps_multimedia]="Multimedia" +STRINGS[apps_utilities]="Utilities" +STRINGS[apps_network]="Network" +STRINGS[apps_install_all]="Install All" +STRINGS[apps_install_category]="Install category: %s" +STRINGS[apps_select_prompt]="Select apps (e.g.: 1 3 5 or 'all'): " +STRINGS[apps_none_in_category]="No apps in this category." +STRINGS[apps_basic_tools]="basic tools" + +# ===== Wine ===== +STRINGS[wine_title]="Manage Wine/Hangover" +STRINGS[wine_install_prompt]="Install Wine/Hangover? [y/N]: " +STRINGS[wine_not_arm64]="Your device doesn't appear to be ARM64/aarch64. Wine/Hangover may not work well." +STRINGS[wine_shortcut_created]="Wine shortcut created." +STRINGS[wine_not_complete]="Hangover Wine doesn't appear to be fully installed." +STRINGS[wine_skipped]="Wine/Hangover skipped." +STRINGS[wine_install]="Install Wine/Hangover" +STRINGS[wine_remove]="Remove Wine/Hangover" +STRINGS[wine_status]="Wine status" +STRINGS[wine_remove_confirm]="Are you sure you want to remove Wine/Hangover? [y/N]: " +STRINGS[wine_removed]="Wine/Hangover removed." +STRINGS[wine_config_title]="Configure Wine/Hangover" + +# ===== Themes ===== +STRINGS[themes_title]="Themes & Personalization" +STRINGS[themes_dark]="Install dark theme" +STRINGS[themes_icons]="Install icon pack" +STRINGS[themes_wallpaper]="Set wallpaper" +STRINGS[themes_fonts]="Install fonts" +STRINGS[themes_dracula]="Dracula" +STRINGS[themes_nord]="Nord" +STRINGS[themes_gruvbox]="Gruvbox" +STRINGS[themes_arc_dark]="Arc Dark" +STRINGS[themes_papirus]="Papirus" +STRINGS[themes_adwaita]="Adwaita" +STRINGS[themes_select_theme]="Select theme: " +STRINGS[themes_select_icons]="Select icons: " +STRINGS[themes_installed]="Theme %s installed." +STRINGS[themes_icons_installed]="Icons %s installed." +STRINGS[themes_fonts_installed]="Fonts installed." +STRINGS[themes_wallpaper_set]="Wallpaper set." +STRINGS[themes_wallpaper_path]="Wallpaper path: " +STRINGS[themes_wallpaper_not_found]="Wallpaper file not found." + +# ===== Scripts ===== +STRINGS[creating_scripts]="Creating startup scripts" +STRINGS[scripts_created]="Scripts created." +STRINGS[creating_shortcuts]="Creating shortcuts" + +# ===== Backup ===== +STRINGS[backup_title]="Backup / Restore Config" +STRINGS[backup_save]="Save current configuration" +STRINGS[backup_restore]="Restore previous configuration" +STRINGS[backup_export]="Export to external storage" +STRINGS[backup_saved]="Configuration saved to: %s" +STRINGS[backup_restored]="Configuration restored from: %s" +STRINGS[backup_not_found]="No backup found." +STRINGS[backup_exported]="Backup exported to: %s" +STRINGS[backup_export_path]="/sdcard/termux-linux-backup" +STRINGS[backup_list]="Available backups:" +STRINGS[backup_select]="Select backup: " +STRINGS[backup_config_loaded]="Previous configuration loaded: Desktop=%s, GPU=%s" + +# ===== Maintenance ===== +STRINGS[maint_title]="Maintenance & Diagnostics" +STRINGS[maint_update]="Update system" +STRINGS[maint_check_integrity]="Check installation integrity" +STRINGS[maint_view_install_log]="View installation logs" +STRINGS[maint_view_start_log]="View startup logs" +STRINGS[maint_clean_cache]="Clean package cache" +STRINGS[maint_diagnostics]="Run full diagnostics" +STRINGS[maint_recreate_scripts]="Recreate start/stop scripts" +STRINGS[maint_cache_cleaned]="Cache cleaned." +STRINGS[maint_updating]="Updating system..." +STRINGS[maint_updated]="System updated." +STRINGS[maint_components_missing]="%s component(s) missing. Use the menu to reinstall." +STRINGS[maint_all_ok]="All components are installed." +STRINGS[maint_found]="found" +STRINGS[maint_not_found]="NOT found" + +# ===== Main menu ===== +STRINGS[menu_title]="Main Menu" +STRINGS[menu_full_install]="Full Installation" +STRINGS[menu_apps]="Manage Applications" +STRINGS[menu_desktop]="Configure Desktop" +STRINGS[menu_gpu]="Configure GPU" +STRINGS[menu_audio]="Configure Audio" +STRINGS[menu_wine]="Manage Wine/Hangover" +STRINGS[menu_themes]="Themes & Personalization" +STRINGS[menu_maintenance]="Maintenance & Diagnostics" +STRINGS[menu_backup]="Backup / Restore Config" +STRINGS[menu_exit]="Exit" +STRINGS[menu_prompt]="Choose an option: " +STRINGS[menu_invalid]="Invalid option." +STRINGS[menu_goodbye]="Goodbye!" + +# ===== Full install steps ===== +STRINGS[step_preparing]="Preparing environment" +STRINGS[step_updating]="Updating system" +STRINGS[step_adding_repos]="Adding repositories" +STRINGS[step_graphics_server]="Installing graphics server" +STRINGS[step_installing_desktop]="Installing %s" +STRINGS[step_configuring_gpu]="Configuring GPU" +STRINGS[step_installing_audio]="Installing audio" +STRINGS[step_installing_apps]="Installing apps and utilities" +STRINGS[step_configuring_wine]="Configuring Wine/Hangover" +STRINGS[step_creating_scripts]="Creating startup scripts" +STRINGS[step_creating_shortcuts]="Creating shortcuts" + +# ===== Completion ===== +STRINGS[install_complete]="INSTALLATION COMPLETE" +STRINGS[install_desktop_label]="Desktop" +STRINGS[install_gpu_label]="GPU" +STRINGS[install_start_cmd]="Start" +STRINGS[install_stop_cmd]="Stop" +STRINGS[install_info_cmd]="Info" +STRINGS[install_log_label]="Log" +STRINGS[install_open_x11]="After starting, open the Termux-X11 app to see the interface." +STRINGS[install_start_now]="Start the desktop now? [y/N]: " + +# ===== Audio ===== +STRINGS[audio_title]="Configure Audio" +STRINGS[audio_install]="Install PulseAudio" +STRINGS[audio_test]="Test audio" +STRINGS[audio_restart]="Restart PulseAudio" +STRINGS[audio_status]="PulseAudio status" +STRINGS[audio_installed]="PulseAudio installed." +STRINGS[audio_running]="PulseAudio is running." +STRINGS[audio_not_running]="PulseAudio is not running." +STRINGS[audio_restarted]="PulseAudio restarted." + +# ===== Language ===== +STRINGS[lang_title]="Selecione o idioma / Select language" +STRINGS[lang_prompt]="Opção / Option [1-2]: " diff --git a/lang/pt.sh b/lang/pt.sh new file mode 100644 index 0000000..4e9fc4f --- /dev/null +++ b/lang/pt.sh @@ -0,0 +1,233 @@ +# ===== Geral ===== +STRINGS[lang_name]="Português" +STRINGS[yes_chars]="s|sim|y|yes" +STRINGS[no_chars]="n|nao|não|no" +STRINGS[yes_letter]="s" +STRINGS[no_letter]="n" +STRINGS[yes_no_prompt]="s/n" +STRINGS[invalid_option]="Opção inválida. Tente novamente." +STRINGS[answer_yes_no]="Responda com s ou n." +STRINGS[press_enter]="Pressione ENTER para continuar..." +STRINGS[back]="Voltar" +STRINGS[exit]="Sair" +STRINGS[or]="ou" + +# ===== Banner ===== +STRINGS[banner_title]="Configurando Termux Linux/X11" +STRINGS[banner_status_desktop]="Desktop" +STRINGS[banner_status_gpu]="GPU" +STRINGS[banner_status_wine]="Wine" +STRINGS[banner_status_status]="Status" +STRINGS[status_running]="rodando" +STRINGS[status_stopped]="parado" +STRINGS[status_installed]="instalado" +STRINGS[status_not_installed]="não instalado" +STRINGS[status_enabled]="ativada" +STRINGS[status_disabled]="desativada" + +# ===== Logging ===== +STRINGS[install_log_at]="Log da instalação: %s" +STRINGS[log_complete]="Log completo: %s" +STRINGS[last_log_lines]="Últimas linhas do log:" +STRINGS[error_prefix]="ERRO" +STRINGS[unexpected_error_line]="ERRO inesperado na linha %s: %s" +STRINGS[step_completed]="Passo %s/%s concluído" +STRINGS[failed_at]="Falha em: %s" +STRINGS[attempt_failed]="Tentativa %s/%s falhou para %s. Retentando em %ss..." + +# ===== Instalação ===== +STRINGS[installing]="Instalando: %s" +STRINGS[trying_install_optional]="Tentando instalar pacote opcional: %s" +STRINGS[installed]="Instalado: %s" +STRINGS[optional_pkg_failed]="Pacote opcional indisponível ou falhou: %s" +STRINGS[trying_install]="Tentando instalar %s: %s" +STRINGS[no_option_available]="Nenhuma opção disponível para instalar: %s (%s)" +STRINGS[already_installed]="Já instalado: %s" +STRINGS[not_installed]="Não instalado: %s" + +# ===== Verificações ===== +STRINGS[checking_internet]="Verificando internet..." +STRINGS[no_internet]="Sem conexão com internet ou DNS indisponível." +STRINGS[must_run_in_termux]="Este script deve ser executado dentro do Termux normal, não em Linux/PC/proot." +STRINGS[pkg_not_found]="Comando 'pkg' não encontrado. Atualize/reinstale o Termux." +STRINGS[waiting_apt]="Aguardando outro processo apt/dpkg terminar..." +STRINGS[apt_stuck]="Outro processo do apt/dpkg está travado há muito tempo. Feche outros Termux e tente novamente." + +# ===== Dispositivo ===== +STRINGS[architecture]="Arquitetura: %s" +STRINGS[device_info]="Dispositivo: %s %s" +STRINGS[wine_arm64_warning]="Wine/Hangover e aceleração gráfica costumam funcionar melhor em ARM64/aarch64." + +# ===== GPU ===== +STRINGS[gpu_config_title]="Configuração de GPU" +STRINGS[gpu_auto]="Automático (recomendado)" +STRINGS[gpu_force_adreno]="Forçar aceleração GPU Adreno/Freedreno" +STRINGS[gpu_disable]="Desativar aceleração GPU/usar software" +STRINGS[gpu_prompt]="Opção [1-3, padrão=1]: " +STRINGS[gpu_adreno_detected]="GPU Qualcomm/Adreno detectada. Aceleração será ativada." +STRINGS[gpu_adreno_not_detected]="GPU Adreno não detectada. Usarei modo compatível sem aceleração forçada." +STRINGS[gpu_forced_warning]="Aceleração GPU foi forçada. Se a tela ficar preta/travar, rode novamente e escolha a opção 3." +STRINGS[gpu_disabled]="Aceleração GPU desativada." +STRINGS[gpu_base_installed]="Base gráfica instalada" +STRINGS[gpu_base_install]="Instalando base gráfica Vulkan/Zink" +STRINGS[gpu_base_failed]="Drivers mesa-zink/vulkan-loader-android falharam. Vou continuar em modo software." +STRINGS[gpu_software_mode]="Modo software selecionado. Drivers GPU extras não serão forçados." + +# ===== Desktop ===== +STRINGS[desktop_title]="Escolha o Desktop" +STRINGS[desktop_xfce4]="XFCE4 (recomendado/mais estável)" +STRINGS[desktop_lxqt]="LXQt (leve)" +STRINGS[desktop_mate]="MATE (médio)" +STRINGS[desktop_kde]="KDE Plasma (pesado/experimental)" +STRINGS[desktop_prompt]="Opção [1-4, padrão=1]: " +STRINGS[desktop_chosen]="Desktop escolhido: %s" +STRINGS[desktop_command_not_found]="O comando '%s' não foi encontrado após instalar %s. Veja o log e tente outro desktop." +STRINGS[desktop_current]="Desktop atual: %s" +STRINGS[desktop_change]="Trocar ambiente desktop" +STRINGS[desktop_reinstall]="Reinstalar desktop atual" +STRINGS[desktop_remove]="Remover desktop atual" +STRINGS[desktop_view_status]="Ver desktop instalado" +STRINGS[desktop_remove_confirm]="Tem certeza que deseja remover %s? [s/N]: " +STRINGS[desktop_removed]="Desktop %s removido." +STRINGS[desktop_none_installed]="Nenhum desktop instalado." +STRINGS[desktop_config_title]="Configurar Desktop" + +# ===== Aplicativos ===== +STRINGS[apps_title]="Gerenciar Aplicativos" +STRINGS[apps_browsers]="Navegadores" +STRINGS[apps_editors]="Editores de Código" +STRINGS[apps_devtools]="Ferramentas de Dev" +STRINGS[apps_multimedia]="Multimídia" +STRINGS[apps_utilities]="Utilitários" +STRINGS[apps_network]="Rede" +STRINGS[apps_install_all]="Instalar Todos" +STRINGS[apps_install_category]="Instalar categoria: %s" +STRINGS[apps_select_prompt]="Selecione os apps (ex: 1 3 5 ou 'todos'): " +STRINGS[apps_none_in_category]="Nenhum app nesta categoria." +STRINGS[apps_basic_tools]="ferramentas básicas" + +# ===== Wine ===== +STRINGS[wine_title]="Gerenciar Wine/Hangover" +STRINGS[wine_install_prompt]="Instalar Wine/Hangover? [s/N]: " +STRINGS[wine_not_arm64]="Seu aparelho não parece ser ARM64/aarch64. Wine/Hangover pode não funcionar bem." +STRINGS[wine_shortcut_created]="Atalho 'wine' criado." +STRINGS[wine_not_complete]="Hangover Wine não parece ter sido instalado completamente." +STRINGS[wine_skipped]="Wine/Hangover ignorado." +STRINGS[wine_install]="Instalar Wine/Hangover" +STRINGS[wine_remove]="Remover Wine/Hangover" +STRINGS[wine_status]="Status do Wine" +STRINGS[wine_remove_confirm]="Tem certeza que deseja remover Wine/Hangover? [s/N]: " +STRINGS[wine_removed]="Wine/Hangover removido." +STRINGS[wine_config_title]="Configurar Wine/Hangover" + +# ===== Temas ===== +STRINGS[themes_title]="Temas e Personalização" +STRINGS[themes_dark]="Instalar tema escuro" +STRINGS[themes_icons]="Instalar pacote de ícones" +STRINGS[themes_wallpaper]="Definir wallpaper" +STRINGS[themes_fonts]="Instalar fontes" +STRINGS[themes_dracula]="Dracula" +STRINGS[themes_nord]="Nord" +STRINGS[themes_gruvbox]="Gruvbox" +STRINGS[themes_arc_dark]="Arc Dark" +STRINGS[themes_papirus]="Papirus" +STRINGS[themes_adwaita]="Adwaita" +STRINGS[themes_select_theme]="Selecione o tema: " +STRINGS[themes_select_icons]="Selecione os ícones: " +STRINGS[themes_installed]="Tema %s instalado." +STRINGS[themes_icons_installed]="Ícones %s instalados." +STRINGS[themes_fonts_installed]="Fontes instaladas." +STRINGS[themes_wallpaper_set]="Wallpaper definido." +STRINGS[themes_wallpaper_path]="Caminho do wallpaper: " +STRINGS[themes_wallpaper_not_found]="Arquivo de wallpaper não encontrado." + +# ===== Scripts ===== +STRINGS[creating_scripts]="Criando scripts de inicialização" +STRINGS[scripts_created]="Scripts criados." +STRINGS[creating_shortcuts]="Criando atalhos" + +# ===== Backup ===== +STRINGS[backup_title]="Backup / Restaurar Config" +STRINGS[backup_save]="Salvar configuração atual" +STRINGS[backup_restore]="Restaurar configuração anterior" +STRINGS[backup_export]="Exportar para armazenamento externo" +STRINGS[backup_saved]="Configuração salva em: %s" +STRINGS[backup_restored]="Configuração restaurada de: %s" +STRINGS[backup_not_found]="Nenhum backup encontrado." +STRINGS[backup_exported]="Backup exportado para: %s" +STRINGS[backup_export_path]="/sdcard/termux-linux-backup" +STRINGS[backup_list]="Backups disponíveis:" +STRINGS[backup_select]="Selecione o backup: " +STRINGS[backup_config_loaded]="Configuração anterior carregada: Desktop=%s, GPU=%s" + +# ===== Manutenção ===== +STRINGS[maint_title]="Manutenção e Diagnóstico" +STRINGS[maint_update]="Atualizar sistema" +STRINGS[maint_check_integrity]="Verificar integridade da instalação" +STRINGS[maint_view_install_log]="Ver logs de instalação" +STRINGS[maint_view_start_log]="Ver logs de inicialização" +STRINGS[maint_clean_cache]="Limpar cache de pacotes" +STRINGS[maint_diagnostics]="Executar diagnóstico completo" +STRINGS[maint_recreate_scripts]="Recriar scripts de start/stop" +STRINGS[maint_cache_cleaned]="Cache limpo." +STRINGS[maint_updating]="Atualizando sistema..." +STRINGS[maint_updated]="Sistema atualizado." +STRINGS[maint_components_missing]="%s componente(s) ausente(s). Use o menu para reinstalar." +STRINGS[maint_all_ok]="Todos os componentes estão instalados." +STRINGS[maint_found]="encontrado" +STRINGS[maint_not_found]="NÃO encontrado" + +# ===== Menu principal ===== +STRINGS[menu_title]="Menu Principal" +STRINGS[menu_full_install]="Instalação Completa" +STRINGS[menu_apps]="Gerenciar Aplicativos" +STRINGS[menu_desktop]="Configurar Desktop" +STRINGS[menu_gpu]="Configurar GPU" +STRINGS[menu_audio]="Configurar Áudio" +STRINGS[menu_wine]="Gerenciar Wine/Hangover" +STRINGS[menu_themes]="Temas e Personalização" +STRINGS[menu_maintenance]="Manutenção e Diagnóstico" +STRINGS[menu_backup]="Backup / Restaurar Config" +STRINGS[menu_exit]="Sair" +STRINGS[menu_prompt]="Escolha uma opção: " +STRINGS[menu_invalid]="Opção inválida." +STRINGS[menu_goodbye]="Ate mais!" + +# ===== Instalação completa (passos) ===== +STRINGS[step_preparing]="Preparando ambiente" +STRINGS[step_updating]="Atualizando sistema" +STRINGS[step_adding_repos]="Adicionando repositórios" +STRINGS[step_graphics_server]="Instalando servidor gráfico" +STRINGS[step_installing_desktop]="Instalando %s" +STRINGS[step_configuring_gpu]="Configurando GPU" +STRINGS[step_installing_audio]="Instalando áudio" +STRINGS[step_installing_apps]="Instalando apps e utilitários" +STRINGS[step_configuring_wine]="Configurando Wine/Hangover" +STRINGS[step_creating_scripts]="Criando scripts de inicialização" +STRINGS[step_creating_shortcuts]="Criando atalhos" + +# ===== Conclusão ===== +STRINGS[install_complete]="INSTALAÇÃO CONCLUÍDA" +STRINGS[install_desktop_label]="Desktop" +STRINGS[install_gpu_label]="GPU" +STRINGS[install_start_cmd]="Iniciar" +STRINGS[install_stop_cmd]="Parar" +STRINGS[install_info_cmd]="Info" +STRINGS[install_log_label]="Log" +STRINGS[install_open_x11]="Depois de iniciar, abra o app Termux-X11 para ver a interface." +STRINGS[install_start_now]="Deseja iniciar o desktop agora? [s/N]: " + +# ===== Áudio ===== +STRINGS[audio_title]="Configurar Áudio" +STRINGS[audio_install]="Instalar PulseAudio" +STRINGS[audio_test]="Testar áudio" +STRINGS[audio_restart]="Reiniciar PulseAudio" +STRINGS[audio_status]="Status do PulseAudio" +STRINGS[audio_installed]="PulseAudio instalado." +STRINGS[audio_running]="PulseAudio está rodando." +STRINGS[audio_not_running]="PulseAudio não está rodando." +STRINGS[audio_restarted]="PulseAudio reiniciado." + +# ===== Idioma ===== +STRINGS[lang_title]="Selecione o idioma / Select language" +STRINGS[lang_prompt]="Opção / Option [1-2]: " diff --git a/lib/apps.sh b/lib/apps.sh new file mode 100644 index 0000000..4988719 --- /dev/null +++ b/lib/apps.sh @@ -0,0 +1,164 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/apps.sh — Gerenciamento de aplicativos via catalogo +# Sourced by script-termux.sh — NAO executar diretamente. + +# Categorias suportadas (devem coincidir com apps.conf) +APP_CATEGORIES=("browsers" "editors" "devtools" "multimedia" "utilities" "network") + +# Mapeia categoria -> chave de traducao +declare -gA APP_CAT_KEYS +APP_CAT_KEYS[browsers]="apps_browsers" +APP_CAT_KEYS[editors]="apps_editors" +APP_CAT_KEYS[devtools]="apps_devtools" +APP_CAT_KEYS[multimedia]="apps_multimedia" +APP_CAT_KEYS[utilities]="apps_utilities" +APP_CAT_KEYS[network]="apps_network" + +# Le apps de uma categoria do apps.conf +# Retorna linhas no formato: nome_exibicao|pacote +get_apps_in_category() { + local category="$1" + local conf_file="${SCRIPT_DIR}/apps.conf" + + if [ ! -f "$conf_file" ]; then + return 0 + fi + + local grep_out="" + grep_out="$(grep "^${category}|" "$conf_file" 2>/dev/null || true)" + if [ -n "$grep_out" ]; then + echo "$grep_out" | while IFS='|' read -r _cat name pkg; do + printf '%s|%s\n' "$name" "$pkg" + done + fi +} + +# Lista apps de uma categoria com status de instalacao +list_category_apps() { + local category="$1" + local index=1 + + while IFS='|' read -r name pkg; do + local first_pkg="" + first_pkg="$(echo "$pkg" | awk '{print $1}')" + if is_pkg_installed "$first_pkg"; then + printf " %s[x]%s %2d) %s\n" "$GREEN" "$RESET" "$index" "$name" + else + printf " %s[ ]%s %2d) %s\n" "$DIM" "$RESET" "$index" "$name" + fi + index=$((index + 1)) + done < <(get_apps_in_category "$category") +} + +# Instala app(s) de uma categoria por indice +install_category_app() { + local category="$1" + local indices="$2" + local apps=() + + # Coleta todos os apps da categoria + while IFS='|' read -r name pkg; do + apps+=("$name|$pkg") + done < <(get_apps_in_category "$category") + + if [ "${#apps[@]}" -eq 0 ]; then + warn "$(t apps_none_in_category)" + return 0 + fi + + # Se 'all' ou 'todos', instala todos + if [[ "$indices" == "all" ]] || [[ "$indices" == "todos" ]]; then + for entry in "${apps[@]}"; do + local name="${entry%%|*}" + local pkg="${entry#*|}" + info "$(t installing "$name")" + # shellcheck disable=SC2086 + install_with_retry $pkg || warn "$(t optional_pkg_failed "$name")" + done + return 0 + fi + + # Instala por indices selecionados + local idx="" + for idx in $indices; do + if [[ "$idx" =~ ^[0-9]+$ ]] && [ "$idx" -ge 1 ] && [ "$idx" -le "${#apps[@]}" ]; then + local entry="${apps[$((idx - 1))]}" + local name="${entry%%|*}" + local pkg="${entry#*|}" + info "$(t installing "$name")" + # shellcheck disable=SC2086 + install_with_retry $pkg || warn "$(t optional_pkg_failed "$name")" + else + warn "$(t invalid_option): $idx" + fi + done +} + +# Submenu de uma categoria +category_submenu() { + local category="$1" + local cat_name="" + cat_name="$(t "${APP_CAT_KEYS[$category]}")" + + echo "" + echo " -- $cat_name --" + echo "" + list_category_apps "$category" + echo "" + + local selection="" + read -r -p " $(t apps_select_prompt)" selection || selection="" + + if [ -n "$selection" ]; then + install_category_app "$category" "$selection" + fi +} + +# Menu principal de aplicativos +apps_menu() { + while true; do + echo "" + _header "$(t apps_title)" + + local i=1 + for cat in "${APP_CATEGORIES[@]}"; do + local cat_name="" + cat_name="$(t "${APP_CAT_KEYS[$cat]}")" + _item "$i" "$cat_name" + i=$((i + 1)) + done + + _item "7" "$(t apps_install_all)" + _item "0" "$(t back)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + [1-6]) + local cat_index=$((choice - 1)) + if [ "$cat_index" -lt "${#APP_CATEGORIES[@]}" ]; then + category_submenu "${APP_CATEGORIES[$cat_index]}" + fi + ;; + 7) + info "$(t apps_install_all)..." + for cat in "${APP_CATEGORIES[@]}"; do + install_category_app "$cat" "all" + done + ;; + 0) return ;; + *) warn "$(t menu_invalid)" ;; + esac + + pause_prompt + done +} + +# Instalacao de apps basicos (usado na instalacao completa) +install_basic_apps() { + install_required "$(t apps_basic_tools)" git wget curl python nano tar unzip zip openssl + install_optional_packages neofetch vlc firefox code-oss wol +} diff --git a/lib/backup.sh b/lib/backup.sh new file mode 100644 index 0000000..3066b4e --- /dev/null +++ b/lib/backup.sh @@ -0,0 +1,153 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/backup.sh — Backup e restauração de configuração +# Sourced by script-termux.sh — NÃO executar diretamente. + +BACKUP_DIR="${STATE_DIR}/backups" + +backup_save() { + mkdir -p "$BACKUP_DIR" + + local timestamp="" + timestamp="$(date '+%Y%m%d_%H%M%S')" + local backup_path="${BACKUP_DIR}/backup_${timestamp}" + mkdir -p "$backup_path" + + # Salva config atual + if [ -f "${STATE_DIR}/config.env" ]; then + cp "${STATE_DIR}/config.env" "$backup_path/" + fi + + # Salva scripts gerados + for script in start-linux.sh stop-linux.sh linux-info.sh; do + if [ -f "${HOME}/${script}" ]; then + cp "${HOME}/${script}" "$backup_path/" + fi + done + + # Salva configurações de desktop (XFCE4) + if [ -d "${HOME}/.config/xfce4" ]; then + cp -r "${HOME}/.config/xfce4" "$backup_path/" 2>/dev/null || true + fi + + # Salva configurações de Termux + if [ -d "${HOME}/.termux" ]; then + cp -r "${HOME}/.termux" "$backup_path/dot-termux" 2>/dev/null || true + fi + + ok "$(t backup_saved "$backup_path")" +} + +backup_restore() { + if [ ! -d "$BACKUP_DIR" ] || [ -z "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]; then + warn "$(t backup_not_found)" + return 1 + fi + + echo "" + echo " $(t backup_list)" + echo "" + + local backups=() + local i=1 + local dir="" + + for dir in "$BACKUP_DIR"/backup_*; do + if [ -d "$dir" ]; then + local name="" + name="$(basename "$dir")" + backups+=("$dir") + printf " %d) %s\n" "$i" "$name" + i=$((i + 1)) + fi + done + + if [ "${#backups[@]}" -eq 0 ]; then + warn "$(t backup_not_found)" + return 1 + fi + + echo "" + local choice="" + read -r -p " $(t backup_select)" choice || return + + if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#backups[@]}" ]; then + local selected="${backups[$((choice - 1))]}" + + # Restaura config.env + if [ -f "$selected/config.env" ]; then + cp "$selected/config.env" "${STATE_DIR}/" + load_config + fi + + # Restaura scripts + for script in start-linux.sh stop-linux.sh linux-info.sh; do + if [ -f "$selected/$script" ]; then + cp "$selected/$script" "${HOME}/" + chmod +x "${HOME}/${script}" + fi + done + + # Restaura configs de desktop + if [ -d "$selected/xfce4" ]; then + mkdir -p "${HOME}/.config" + cp -r "$selected/xfce4" "${HOME}/.config/" 2>/dev/null || true + fi + + # Restaura configs de Termux + if [ -d "$selected/dot-termux" ]; then + cp -r "$selected/dot-termux" "${HOME}/.termux" 2>/dev/null || true + fi + + ok "$(t backup_restored "$selected")" + else + warn "$(t invalid_option)" + fi +} + +backup_export() { + local export_dir="" + export_dir="$(t backup_export_path)" + mkdir -p "$export_dir" + + local timestamp="" + timestamp="$(date '+%Y%m%d_%H%M%S')" + local export_file="${export_dir}/termux-linux-backup_${timestamp}.tar.gz" + + if [ -d "$STATE_DIR" ]; then + tar -czf "$export_file" -C "$HOME" \ + ".termux-linux" \ + "start-linux.sh" \ + "stop-linux.sh" \ + "linux-info.sh" \ + 2>/dev/null || true + ok "$(t backup_exported "$export_file")" + else + warn "$(t backup_not_found)" + fi +} + +backup_menu() { + while true; do + echo "" + _header "$(t backup_title)" + _item "1" "$(t backup_save)" + _item "2" "$(t backup_restore)" + _item "3" "$(t backup_export)" + _item "0" "$(t back)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + 1) backup_save ;; + 2) backup_restore ;; + 3) backup_export ;; + 0) return ;; + *) warn "$(t menu_invalid)" ;; + esac + + pause_prompt + done +} diff --git a/lib/checks.sh b/lib/checks.sh new file mode 100644 index 0000000..623b26b --- /dev/null +++ b/lib/checks.sh @@ -0,0 +1,37 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/checks.sh — Verificações de sistema +# Sourced by script-termux.sh — NÃO executar diretamente. + +require_termux() { + if [ "${PREFIX:-}" != "/data/data/com.termux/files/usr" ]; then + die "$(t must_run_in_termux)" + fi + + command_exists pkg || die "$(t pkg_not_found)" +} + +check_internet() { + if command_exists curl; then + curl -fsI --connect-timeout 12 https://packages.termux.dev >/dev/null 2>>"$LOG" && return 0 + curl -fsI --connect-timeout 12 https://google.com >/dev/null 2>>"$LOG" && return 0 + fi + + ping -c 1 -W 8 packages.termux.dev >> "$LOG" 2>&1 && return 0 + ping -c 1 -W 8 google.com >> "$LOG" 2>&1 && return 0 + + return 1 +} + +wait_package_manager() { + local waited=0 + while pgrep -x apt >/dev/null 2>&1 || \ + pgrep -x apt-get >/dev/null 2>&1 || \ + pgrep -x dpkg >/dev/null 2>&1; do + if [ "$waited" -ge 90 ]; then + die "$(t apt_stuck)" + fi + warn "$(t waiting_apt)" + sleep 3 + waited=$((waited + 3)) + done +} diff --git a/lib/common.sh b/lib/common.sh new file mode 100644 index 0000000..9f43f48 --- /dev/null +++ b/lib/common.sh @@ -0,0 +1,315 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/common.sh — Cores, logging, spinner, helpers compartilhados +# Sourced by script-termux.sh — NÃO executar diretamente. + +# ========================= +# Configuração global +# ========================= +LOG="${HOME}/termux-linux-install.log" +START_LOG="${HOME}/termux-linux-start.log" +STATE_DIR="${HOME}/.termux-linux" +SPINNER_PID="" +TOTAL=11 +CURRENT=0 + +DE_INPUT="1" +DE_NAME="" +DE_COMMAND="" +DE_CORE_PACKAGES=() +DE_EXTRA_PACKAGES=() +GPU_DRIVER="software" +GPU_ENABLED="false" +GPU_INFO="" +INSTALL_WINE="n" +ARCH="" +DEVICE_BRAND="" +DEVICE_MODEL="" + +mkdir -p "$STATE_DIR" + +# ========================= +# Cores +# ========================= +if [ -t 1 ]; then + RED=$'\e[31m' + GREEN=$'\e[32m' + YELLOW=$'\e[33m' + BLUE=$'\e[34m' + CYAN=$'\e[36m' + MAGENTA=$'\e[35m' + BOLD=$'\e[1m' + DIM=$'\e[2m' + RESET=$'\e[0m' +else + RED='' + GREEN='' + YELLOW='' + BLUE='' + CYAN='' + MAGENTA='' + BOLD='' + DIM='' + RESET='' +fi + +# ========================= +# Logging +# ========================= +log_line() { + printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG" +} + +info() { + printf " %s->%s %s\n" "$BLUE" "$RESET" "$*" + log_line "INFO: $*" +} + +ok() { + printf " %s[OK]%s %s\n" "$GREEN" "$RESET" "$*" + log_line "OK: $*" +} + +warn() { + printf " %s[!]%s %s\n" "$YELLOW" "$RESET" "$*" + log_line "AVISO: $*" +} + +show_log_tail() { + if [ -s "$LOG" ]; then + echo "" + echo " $(t last_log_lines)" + tail -n 25 "$LOG" | sed 's/^/ /' + fi +} + +die() { + _stop_spinner + echo "" + printf " %s%s:%s %s\n" "$RED" "$(t error_prefix)" "$RESET" "$*" >&2 + printf " %s\n" "$(t log_complete "$LOG")" >&2 + show_log_tail >&2 + exit 1 +} + +on_error() { + local line="$1" + local cmd="$2" + _stop_spinner + echo "" + printf " %s%s%s\n" "$RED" "$(t unexpected_error_line "$line" "$cmd")" "$RESET" >&2 + printf " %s\n" "$(t log_complete "$LOG")" >&2 + show_log_tail >&2 + exit 1 +} + +# ========================= +# Spinner e Progresso +# ========================= +_stop_spinner() { + if [ -n "${SPINNER_PID:-}" ]; then + kill "$SPINNER_PID" 2>/dev/null || true + wait "$SPINNER_PID" 2>/dev/null || true + printf "\r\033[K" + SPINNER_PID="" + fi + return 0 +} + +start_step() { + _stop_spinner + CURRENT=$((CURRENT + 1)) + local msg="$1" + local pct=$((CURRENT * 100 / TOTAL)) + local filled=$((pct * 24 / 100)) + local bar_fill="" + local bar="" + + if [ "$filled" -gt 0 ]; then + bar_fill=$(printf '%*s' "$filled" '' | tr ' ' '=') + fi + + if [ "$filled" -lt 24 ]; then + bar=$(printf "%-24s" "${bar_fill}>") + else + bar="$bar_fill" + fi + + echo "" + printf " %s[%02d/%02d]%s %s\n" "$BOLD" "$CURRENT" "$TOTAL" "$RESET" "$msg" + log_line "PASSO $CURRENT/$TOTAL: $msg" + + ( + i=0 + chars='|/-\' + while true; do + printf "\r [%-24s] %3d%% %s" "$bar" "$pct" "${chars:$((i % 4)):1}" + i=$((i + 1)) + sleep 0.2 + done + ) & + SPINNER_PID=$! +} + +end_step() { + _stop_spinner + ok "$(printf "$(t step_completed)" "$CURRENT" "$TOTAL")" +} + +# ========================= +# Comandos e instalação +# ========================= +run_cmd() { + local desc="$1" + shift + log_line "CMD: $*" + if ! "$@" >> "$LOG" 2>&1; then + die "$(printf "$(t failed_at)" "$desc")" + fi +} + +install_with_retry() { + local pkg="$1" + local max_attempts="${2:-3}" + local attempt=1 + + while [ "$attempt" -le "$max_attempts" ]; do + if pkg install -y "$pkg" >> "$LOG" 2>&1; then + ok "$(printf "$(t installed)" "$pkg")" + return 0 + fi + warn "$(printf "$(t attempt_failed)" "$attempt" "$max_attempts" "$pkg" "$attempt")" + sleep "$attempt" + attempt=$((attempt + 1)) + done + + return 1 +} + +install_required() { + local label="$1" + shift + local pkg_name="" + for pkg_name in "$@"; do + info "$(printf "$(t installing)" "$pkg_name")" + run_cmd "instalar $label: $pkg_name" pkg install -y "$pkg_name" + done +} + +install_optional_packages() { + local pkg_name="" + for pkg_name in "$@"; do + info "$(printf "$(t trying_install_optional)" "$pkg_name")" + if pkg install -y "$pkg_name" >> "$LOG" 2>&1; then + ok "$(printf "$(t installed)" "$pkg_name")" + else + warn "$(printf "$(t optional_pkg_failed)" "$pkg_name")" + fi + done +} + +install_any_required() { + local label="$1" + shift + local pkg_name="" + + for pkg_name in "$@"; do + info "$(printf "$(t trying_install)" "$label" "$pkg_name")" + if pkg install -y "$pkg_name" >> "$LOG" 2>&1; then + ok "$(printf "$(t installed)" "$pkg_name")" + return 0 + fi + done + + die "$(printf "$(t no_option_available)" "$label" "$*")" +} + +# ========================= +# Helpers +# ========================= +command_exists() { + command -v "$1" >/dev/null 2>&1 || return 1 +} + +is_pkg_installed() { + dpkg -s "$1" > /dev/null 2>&1 || return 1 +} + +read_choice() { + local prompt="$1" + local default="$2" + local pattern="$3" + local value="" + + while true; do + read -r -p "$prompt" value || value="$default" + value="${value:-$default}" + if [[ "$value" =~ $pattern ]]; then + printf '%s\n' "$value" + return 0 + fi + echo " $(t invalid_option)" + done +} + +read_yes_no() { + local prompt="$1" + local default="$2" + local value="" + + while true; do + read -r -p "$prompt" value || value="$default" + value="${value:-$default}" + value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]')" + case "$value" in + s|sim|y|yes) printf 'y\n'; return 0 ;; + n|nao|não|no) printf 'n\n'; return 0 ;; + *) echo " $(t answer_yes_no)" ;; + esac + done +} + +pause_prompt() { + echo "" + read -r -p " $(t press_enter) " || true +} + +# ========================= +# Config +# ========================= +save_config() { + cat > "${STATE_DIR}/config.env" < "$PREFIX/etc/apt/apt.conf.d/99termux-noninteractive" <<'APTCONF' +DPkg::Options { + "--force-confdef"; + "--force-confold"; +}; +APTCONF +} diff --git a/lib/desktop.sh b/lib/desktop.sh new file mode 100644 index 0000000..626d508 --- /dev/null +++ b/lib/desktop.sh @@ -0,0 +1,144 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/desktop.sh — Gerenciamento de ambientes desktop +# Sourced by script-termux.sh — NAO executar diretamente. + +choose_desktop() { + echo "" + echo " -- $(t desktop_title) --" + echo " 1) $(t desktop_xfce4)" + echo " 2) $(t desktop_lxqt)" + echo " 3) $(t desktop_mate)" + echo " 4) $(t desktop_kde)" + echo "" + + DE_INPUT="$(read_choice " $(t desktop_prompt)" '1' '^[1-4]$')" + _set_desktop_vars "$DE_INPUT" + ok "$(t desktop_chosen "$DE_NAME")" +} + +_set_desktop_vars() { + case "$1" in + 1) + DE_NAME="XFCE4" + DE_COMMAND="startxfce4" + DE_CORE_PACKAGES=(xfce4 dbus pulseaudio) + DE_EXTRA_PACKAGES=(xfce4-terminal thunar mousepad pavucontrol shared-mime-info fontconfig) + ;; + 2) + DE_NAME="LXQt" + DE_COMMAND="startlxqt" + DE_CORE_PACKAGES=(lxqt-session openbox dbus pulseaudio) + DE_EXTRA_PACKAGES=(lxqt-panel pcmanfm-qt qterminal featherpad gtk3 pavucontrol shared-mime-info fontconfig) + ;; + 3) + DE_NAME="MATE" + DE_COMMAND="mate-session" + DE_CORE_PACKAGES=(mate-session-manager marco dbus pulseaudio) + DE_EXTRA_PACKAGES=(mate-panel mate-terminal fontconfig shared-mime-info) + ;; + 4) + DE_NAME="KDE Plasma" + DE_COMMAND="startplasma-x11" + DE_CORE_PACKAGES=(plasma-desktop dbus pulseaudio) + DE_EXTRA_PACKAGES=(konsole fontconfig shared-mime-info) + ;; + esac +} + +install_desktop() { + local pkg_name="" + + for pkg_name in "${DE_CORE_PACKAGES[@]}"; do + install_required "$(t step_installing_desktop "$DE_NAME"): $pkg_name" "$pkg_name" + done + + install_optional_packages "${DE_EXTRA_PACKAGES[@]}" + + if ! command_exists "$DE_COMMAND"; then + die "$(t desktop_command_not_found "$DE_COMMAND" "$DE_NAME")" + fi +} + +remove_desktop() { + if [ -z "$DE_NAME" ]; then + warn "$(t desktop_none_installed)" + return 1 + fi + + local confirm="" + confirm="$(read_yes_no " $(t desktop_remove_confirm "$DE_NAME")" 'n')" + if [ "$confirm" != "y" ]; then + return 0 + fi + + info "$(t desktop_remove "$DE_NAME")" + + case "$DE_NAME" in + XFCE4) + pkg remove -y xfce4 xfce4-terminal thunar mousepad >> "$LOG" 2>&1 || true + ;; + LXQt) + pkg remove -y lxqt-session openbox lxqt-panel pcmanfm-qt qterminal featherpad >> "$LOG" 2>&1 || true + ;; + MATE) + pkg remove -y mate-session-manager marco mate-panel mate-terminal >> "$LOG" 2>&1 || true + ;; + "KDE Plasma") + pkg remove -y plasma-desktop konsole >> "$LOG" 2>&1 || true + ;; + esac + + pkg autoremove -y >> "$LOG" 2>&1 || true + ok "$(t desktop_removed "$DE_NAME")" + DE_NAME="" + DE_COMMAND="" + save_config +} + +get_desktop_status() { + if [ -n "$DE_NAME" ] && command_exists "$DE_COMMAND"; then + printf '%s [OK]' "$DE_NAME" + elif [ -n "$DE_NAME" ]; then + printf '%s [!]' "$DE_NAME" + else + t status_not_installed + fi +} + +desktop_menu() { + while true; do + echo "" + _header "$(t desktop_config_title)" + printf " | %-36s|\n" "$(t desktop_current "$(get_desktop_status)")" + _line + _item "1" "$(t desktop_change)" + _item "2" "$(t desktop_reinstall)" + _item "3" "$(t desktop_remove)" + _item "0" "$(t back)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + 1) + choose_desktop + install_desktop + save_config + ;; + 2) + if [ -n "$DE_NAME" ]; then + install_desktop + else + warn "$(t desktop_none_installed)" + fi + ;; + 3) remove_desktop ;; + 0) return ;; + *) warn "$(t menu_invalid)" ;; + esac + + pause_prompt + done +} diff --git a/lib/device.sh b/lib/device.sh new file mode 100644 index 0000000..e7fb605 --- /dev/null +++ b/lib/device.sh @@ -0,0 +1,80 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/device.sh — Detecção de hardware e configuração de GPU +# Sourced by script-termux.sh — NÃO executar diretamente. + +collect_device_info() { + ARCH="$(uname -m)" + DEVICE_BRAND="$(getprop ro.product.brand 2>/dev/null || echo 'Unknown')" + DEVICE_MODEL="$(getprop ro.product.model 2>/dev/null || echo 'Unknown')" + GPU_INFO="$( + { + getprop ro.hardware.egl + getprop ro.hardware.vulkan + getprop ro.board.platform + getprop ro.hardware + } 2>/dev/null | tr '[:upper:]' '[:lower:]' + )" + + info "$(t architecture "$ARCH")" + info "$(t device_info "$DEVICE_BRAND" "$DEVICE_MODEL")" + + if [ "$ARCH" != "aarch64" ]; then + warn "$(t wine_arm64_warning)" + fi +} + +choose_gpu() { + echo "" + echo " -- $(t gpu_config_title) --" + echo " 1) $(t gpu_auto)" + echo " 2) $(t gpu_force_adreno)" + echo " 3) $(t gpu_disable)" + echo "" + + local gpu_option="" + gpu_option="$(read_choice " $(t gpu_prompt)" '1' '^[1-3]$')" + + case "$gpu_option" in + 1) + if printf '%s' "$GPU_INFO" | grep -Eq 'adreno|qcom|qualcomm|msm'; then + GPU_DRIVER="freedreno" + GPU_ENABLED="true" + ok "$(t gpu_adreno_detected)" + else + GPU_DRIVER="software" + GPU_ENABLED="false" + warn "$(t gpu_adreno_not_detected)" + fi + ;; + 2) + GPU_DRIVER="freedreno" + GPU_ENABLED="true" + warn "$(t gpu_forced_warning)" + ;; + 3) + GPU_DRIVER="software" + GPU_ENABLED="false" + ok "$(t gpu_disabled)" + ;; + esac +} + +install_gpu_drivers() { + if [ "$GPU_ENABLED" = "true" ]; then + info "$(t gpu_base_install)" + if pkg install -y mesa-zink vulkan-loader-android >> "$LOG" 2>&1; then + ok "$(t gpu_base_installed)" + else + warn "$(t gpu_base_failed)" + GPU_ENABLED="false" + GPU_DRIVER="software" + return 0 + fi + + if [ "$GPU_DRIVER" = "freedreno" ]; then + install_optional_packages mesa-vulkan-icd-freedreno vulkan-tools + fi + else + ok "$(t gpu_software_mode)" + fi +} diff --git a/lib/i18n.sh b/lib/i18n.sh new file mode 100644 index 0000000..be3bd44 --- /dev/null +++ b/lib/i18n.sh @@ -0,0 +1,79 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/i18n.sh — Sistema de internacionalização +# Sourced by script-termux.sh — NÃO executar diretamente. + +CURRENT_LANG="${CURRENT_LANG:-pt}" +declare -gA STRINGS + +# Traduz uma chave. Se houver argumentos extras, usa printf para interpolar. +# Uso: +# t "key" -> retorna string traduzida +# t "key" "arg1" "arg2" -> printf com a string como template +t() { + local key="$1" + shift + local template="${STRINGS[$key]:-$key}" + if [ $# -gt 0 ]; then + # shellcheck disable=SC2059 + printf "$template" "$@" + else + printf '%s' "$template" + fi +} + +# Carrega o arquivo de idioma +load_language() { + local lang="${1:-$CURRENT_LANG}" + local lang_file="${SCRIPT_DIR}/lang/${lang}.sh" + + if [ -f "$lang_file" ]; then + # shellcheck disable=SC1090 + source "$lang_file" + CURRENT_LANG="$lang" + else + # Fallback para inglês + # shellcheck disable=SC1090 + source "${SCRIPT_DIR}/lang/en.sh" + CURRENT_LANG="en" + fi +} + +choose_language() { + echo "" + _header "Idioma / Language" + _item "1" "Portugues" + _item "2" "English" + _footer + echo "" + + local choice="" + read -r -p " Opção / Option [1-2, padrão/default=1]: " choice || choice="1" + choice="${choice:-1}" + + case "$choice" in + 1) load_language "pt" ;; + 2) load_language "en" ;; + *) load_language "pt" ;; + esac +} + +# Detecta idioma do sistema (fallback automático) +detect_language() { + # Primeiro checa se já tem config salva + if [ -f "${STATE_DIR:-}/config.env" ]; then + local saved_lang="" + saved_lang="$(grep '^CURRENT_LANG=' "${STATE_DIR}/config.env" 2>/dev/null | cut -d'"' -f2 || true)" + if [ -n "$saved_lang" ]; then + load_language "$saved_lang" + return 0 + fi + fi + + # Detecta pelo locale do sistema + local sys_lang="${LANG:-}" + case "$sys_lang" in + pt*) load_language "pt" ;; + en*) load_language "en" ;; + *) load_language "pt" ;; # Padrão: português + esac +} diff --git a/lib/menu.sh b/lib/menu.sh new file mode 100644 index 0000000..595183e --- /dev/null +++ b/lib/menu.sh @@ -0,0 +1,346 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/menu.sh — Sistema de menus interativo +# Sourced by script-termux.sh — NAO executar diretamente. + +# ========================= +# Helpers de desenho de menu +# ========================= +_line() { + echo " +--------------------------------------+" +} + +_header() { + _line + printf " | %-36s|\n" "$1" + _line +} + +_item() { + printf " | %s) %-33s|\n" "$1" "$2" +} + +_footer() { + _line +} + +# ========================= +# Banner com status +# ========================= +banner() { + clear 2>/dev/null || true + echo "" + cat << 'ART' + | | |\ | | | \_/ + |___ | | \| \__/ / \ + + __ __ __ __ + /\ |\ | | \ |__) / \ | | \ + /~~\ | \| |__/ | \ \__/ | |__/ +ART + echo "" + _header "$(t banner_title)" + + # Mostrar status se tiver config carregada + if [ -n "$DE_NAME" ] || [ "$GPU_ENABLED" = "true" ]; then + echo "" + printf " %s%-10s%s %s\n" "$DIM" "$(t banner_status_desktop):" "$RESET" "$(get_desktop_status)" + if [ "$GPU_ENABLED" = "true" ]; then + printf " %s%-10s%s %s (%s)\n" "$DIM" "$(t banner_status_gpu):" "$RESET" "$GPU_DRIVER" "$(t status_enabled)" + else + printf " %s%-10s%s software (%s)\n" "$DIM" "$(t banner_status_gpu):" "$RESET" "$(t status_disabled)" + fi + printf " %s%-10s%s %s\n" "$DIM" "$(t banner_status_wine):" "$RESET" "$(get_wine_status)" + fi + + echo "" +} + +# ========================= +# Audio +# ========================= +audio_menu() { + while true; do + echo "" + _header "$(t audio_title)" + _item "1" "$(t audio_install)" + _item "2" "$(t audio_restart)" + _item "3" "$(t audio_status)" + _item "0" "$(t back)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + 1) + install_required "$(t audio_install)" pulseaudio + ok "$(t audio_installed)" + ;; + 2) + pulseaudio --kill >/dev/null 2>&1 || true + pulseaudio --start --exit-idle-time=-1 >> "$LOG" 2>&1 || true + ok "$(t audio_restarted)" + ;; + 3) + if pgrep -x pulseaudio >/dev/null 2>&1; then + ok "$(t audio_running)" + else + warn "$(t audio_not_running)" + fi + ;; + 0) return ;; + *) warn "$(t menu_invalid)" ;; + esac + + pause_prompt + done +} + +# ========================= +# GPU (submenu) +# ========================= +gpu_menu() { + choose_gpu + install_gpu_drivers + save_config + pause_prompt +} + +# ========================= +# Manutencao +# ========================= +check_integrity() { + local missing=0 + local cmds_to_check=(termux-x11 pulseaudio) + + if [ -n "$DE_COMMAND" ]; then + cmds_to_check+=("$DE_COMMAND") + fi + + for cmd in "${cmds_to_check[@]}"; do + if command_exists "$cmd"; then + ok "$cmd -- $(t maint_found)" + else + warn "$cmd -- $(t maint_not_found)" + missing=$((missing + 1)) + fi + done + + echo "" + if [ "$missing" -gt 0 ]; then + warn "$(t maint_components_missing "$missing")" + else + ok "$(t maint_all_ok)" + fi +} + +maintenance_menu() { + while true; do + echo "" + _header "$(t maint_title)" + _item "1" "$(t maint_update)" + _item "2" "$(t maint_check_integrity)" + _item "3" "$(t maint_view_install_log)" + _item "4" "$(t maint_view_start_log)" + _item "5" "$(t maint_clean_cache)" + _item "6" "$(t maint_recreate_scripts)" + _item "7" "$(t maint_diagnostics)" + _item "0" "$(t back)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + 1) + info "$(t maint_updating)" + run_cmd "pkg update" pkg update -y + run_cmd "pkg upgrade" pkg upgrade -y + ok "$(t maint_updated)" + ;; + 2) check_integrity ;; + 3) + echo "" + if [ -s "$LOG" ]; then + tail -n 50 "$LOG" | sed 's/^/ /' + else + warn "Log vazio." + fi + ;; + 4) + echo "" + if [ -s "$START_LOG" ]; then + tail -n 50 "$START_LOG" | sed 's/^/ /' + else + warn "Log vazio." + fi + ;; + 5) + info "$(t maint_clean_cache)..." + pkg clean >> "$LOG" 2>&1 || true + apt autoclean >> "$LOG" 2>&1 || true + ok "$(t maint_cache_cleaned)" + ;; + 6) + if [ -n "$DE_NAME" ]; then + write_all_scripts + else + warn "$(t desktop_none_installed)" + fi + ;; + 7) + if [ -x "${HOME}/linux-info.sh" ]; then + bash "${HOME}/linux-info.sh" + else + check_integrity + fi + ;; + 0) return ;; + *) warn "$(t menu_invalid)" ;; + esac + + pause_prompt + done +} + +# ========================= +# Instalacao Completa (fluxo linear original) +# ========================= +full_install() { + banner + + info "$(t checking_internet)" + check_internet || die "$(t no_internet)" + + collect_device_info + choose_gpu + choose_desktop + + echo "" + local wine_answer="" + wine_answer="$(read_yes_no " $(t wine_install_prompt)" 'n')" + if [ "$wine_answer" = "y" ]; then + INSTALL_WINE="y" + fi + + : > "$LOG" + + start_step "$(t step_preparing)" + prepare_environment + wait_package_manager + run_cmd "corrigir dpkg pendente" dpkg --configure -a + end_step + + start_step "$(t step_updating)" + run_cmd "pkg update" pkg update -y + run_cmd "pkg upgrade" pkg upgrade -y + end_step + + start_step "$(t step_adding_repos)" + install_required "repositorios" x11-repo tur-repo + run_cmd "atualizar lista apos repositorios" pkg update -y + end_step + + start_step "$(t step_graphics_server)" + install_any_required "Termux-X11" termux-x11 termux-x11-nightly + install_required "ferramentas X11" xorg-xrandr xorg-xhost xorg-xsetroot + end_step + + start_step "$(t step_installing_desktop "$DE_NAME")" + install_desktop + end_step + + start_step "$(t step_configuring_gpu)" + install_gpu_drivers + end_step + + start_step "$(t step_installing_audio)" + install_required "audio" pulseaudio + end_step + + start_step "$(t step_installing_apps)" + install_basic_apps + end_step + + start_step "$(t step_configuring_wine)" + install_wine_if_requested + end_step + + start_step "$(t step_creating_scripts)" + write_start_script + write_stop_script + write_info_script + save_config + end_step + + start_step "$(t step_creating_shortcuts)" + create_desktop_shortcuts + end_step + + _stop_spinner + echo "" + if command_exists neofetch; then + neofetch || true + fi + + echo "" + _header "$(t install_complete)" + echo "" + echo " $(t install_desktop_label) : $DE_NAME" + echo " $(t install_gpu_label) : $GPU_DRIVER / enabled=$GPU_ENABLED" + echo "" + echo " $(t install_start_cmd) : ~/start-linux.sh" + echo " $(t install_stop_cmd) : ~/stop-linux.sh" + echo " $(t install_info_cmd) : ~/linux-info.sh" + echo " $(t install_log_label) : $LOG" + echo "" + echo " $(t install_open_x11)" + echo "" +} + +# ========================= +# Menu principal +# ========================= +main_menu() { + while true; do + banner + + _header "$(t menu_title)" + _item "1" "$(t menu_full_install)" + _item "2" "$(t menu_apps)" + _item "3" "$(t menu_desktop)" + _item "4" "$(t menu_gpu)" + _item "5" "$(t menu_audio)" + _item "6" "$(t menu_wine)" + _item "7" "$(t menu_themes)" + _item "8" "$(t menu_maintenance)" + _item "9" "$(t menu_backup)" + _item "0" "$(t menu_exit)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + 1) full_install ; pause_prompt ;; + 2) apps_menu ;; + 3) desktop_menu ;; + 4) gpu_menu ;; + 5) audio_menu ;; + 6) wine_menu ;; + 7) themes_menu ;; + 8) maintenance_menu ;; + 9) backup_menu ;; + 0) + echo "" + echo " $(t menu_goodbye)" + echo "" + exit 0 + ;; + *) warn "$(t menu_invalid)" ; sleep 1 ;; + esac + done +} diff --git a/lib/scripts.sh b/lib/scripts.sh new file mode 100644 index 0000000..8b14264 --- /dev/null +++ b/lib/scripts.sh @@ -0,0 +1,159 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/scripts.sh — Geração de scripts auxiliares (start, stop, info) +# Sourced by script-termux.sh — NÃO executar diretamente. + +write_start_script() { + cat > "${HOME}/start-linux.sh" < "\$LOG" + +export LANG=C.UTF-8 +export LC_ALL=C.UTF-8 +export TMPDIR="\${TMPDIR:-/data/data/com.termux/files/usr/tmp}" +mkdir -p "\$TMPDIR" + +export XDG_RUNTIME_DIR="\$TMPDIR" +export DISPLAY=:0 +export XDG_SESSION_TYPE=x11 +export QT_X11_NO_MITSHM=1 +export NO_AT_BRIDGE=1 +export PULSE_SERVER=127.0.0.1 +EOF_START + + if [ "$GPU_ENABLED" = "true" ]; then + cat >> "${HOME}/start-linux.sh" <<'EOF_GPU' +export GALLIUM_DRIVER=zink +export MESA_LOADER_DRIVER_OVERRIDE=zink +export MESA_NO_ERROR=1 +EOF_GPU + else + cat >> "${HOME}/start-linux.sh" <<'EOF_GPU' +export LIBGL_ALWAYS_SOFTWARE=1 +EOF_GPU + fi + + cat >> "${HOME}/start-linux.sh" </dev/null || true + pkill -f "termux-x11.*:0" 2>/dev/null || true + pulseaudio --kill >/dev/null 2>&1 || true +} + +start_audio() { + pulseaudio --start --exit-idle-time=-1 >> "\$LOG" 2>&1 || true + pactl load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1 >> "\$LOG" 2>&1 || true +} + +start_x11() { + am start --user 0 -n com.termux.x11/com.termux.x11.MainActivity >> "\$LOG" 2>&1 || true + termux-x11 :0 >> "\$LOG" 2>&1 & + sleep 3 +} + +echo "Iniciando Termux Linux/X11..." +stop_old_sessions +sleep 1 +start_audio +start_x11 + +start_desktop() { + cd "\$HOME" + + if command -v dbus-launch >/dev/null 2>&1; then + exec dbus-launch --exit-with-session ${DE_COMMAND} + fi + + echo "Aviso: dbus-launch não encontrado. Iniciando ${DE_NAME} sem dbus-launch." >> "\$LOG" + exec ${DE_COMMAND} +} + +start_desktop +EOF_START2 + + chmod +x "${HOME}/start-linux.sh" +} + +write_stop_script() { + cat > "${HOME}/stop-linux.sh" <<'EOF_STOP' +#!/data/data/com.termux/files/usr/bin/bash + +pkill -f "startxfce4|startlxqt|mate-session|startplasma-x11|xfce4-session|lxqt-session" 2>/dev/null || true +pkill -f "termux-x11.*:0" 2>/dev/null || true +pulseaudio --kill >/dev/null 2>&1 || true + +echo "Desktop finalizado." +EOF_STOP + + chmod +x "${HOME}/stop-linux.sh" +} + +write_info_script() { + cat > "${HOME}/linux-info.sh" <<'EOF_INFO' +#!/data/data/com.termux/files/usr/bin/bash + +echo "===== Termux Linux/X11 - Diagnóstico =====" +echo "Data: $(date)" +echo "Arquitetura: $(uname -m)" +echo "PREFIX: ${PREFIX:-desconhecido}" +echo "DISPLAY: ${DISPLAY:-não definido}" +echo "" +echo "Comandos encontrados:" +for cmd in termux-x11 dbus-launch startxfce4 startlxqt mate-session startplasma-x11 pulseaudio; do + if command -v "$cmd" >/dev/null 2>&1; then + echo " [OK] $cmd -> $(command -v "$cmd")" + else + echo " - $cmd não encontrado" + fi +done + +echo "" +echo "Últimas linhas do log de instalação:" +tail -n 30 "$HOME/termux-linux-install.log" 2>/dev/null || true + +echo "" +echo "Últimas linhas do log de inicialização:" +tail -n 30 "$HOME/termux-linux-start.log" 2>/dev/null || true +EOF_INFO + + chmod +x "${HOME}/linux-info.sh" +} + +create_desktop_shortcuts() { + mkdir -p "${HOME}/Desktop" + + if command_exists firefox; then + cat > "${HOME}/Desktop/Firefox.desktop" <<'EOF_FIREFOX' +[Desktop Entry] +Name=Firefox +Exec=firefox +Type=Application +Categories=Network;WebBrowser; +Terminal=false +EOF_FIREFOX + fi + + if command_exists code-oss; then + cat > "${HOME}/Desktop/CodeOSS.desktop" <<'EOF_CODE' +[Desktop Entry] +Name=Code OSS +Exec=code-oss --no-sandbox +Type=Application +Categories=Development; +Terminal=false +EOF_CODE + fi + + chmod +x "${HOME}/Desktop"/*.desktop 2>/dev/null || true +} + +write_all_scripts() { + write_start_script + write_stop_script + write_info_script + create_desktop_shortcuts + ok "$(t scripts_created)" +} diff --git a/lib/themes.sh b/lib/themes.sh new file mode 100644 index 0000000..9ab8a73 --- /dev/null +++ b/lib/themes.sh @@ -0,0 +1,133 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/themes.sh — Temas e personalização +# Sourced by script-termux.sh — NÃO executar diretamente. + +install_dark_theme() { + echo "" + echo " -- $(t themes_dark) --" + echo " 1) $(t themes_arc_dark)" + echo " 2) $(t themes_gruvbox)" + echo "" + + local choice="" + choice="$(read_choice " $(t themes_select_theme)" '1' '^[1-2]$')" + + case "$choice" in + 1) + install_optional_packages arc-theme + # Aplicar tema no XFCE4 se disponível + if command_exists xfconf-query; then + xfconf-query -c xsettings -p /Net/ThemeName -s "Arc-Dark" 2>/dev/null || true + xfconf-query -c xfwm4 -p /general/theme -s "Arc-Dark" 2>/dev/null || true + fi + ok "$(t themes_installed "Arc Dark")" + ;; + 2) + install_optional_packages gruvbox-dark-gtk + if command_exists xfconf-query; then + xfconf-query -c xsettings -p /Net/ThemeName -s "Gruvbox-Dark" 2>/dev/null || true + fi + ok "$(t themes_installed "Gruvbox Dark")" + ;; + esac +} + +install_icon_pack() { + echo "" + echo " -- $(t themes_icons) --" + echo " 1) $(t themes_papirus)" + echo " 2) $(t themes_adwaita)" + echo "" + + local choice="" + choice="$(read_choice " $(t themes_select_icons)" '1' '^[1-2]$')" + + case "$choice" in + 1) + install_optional_packages papirus-icon-theme + if command_exists xfconf-query; then + xfconf-query -c xsettings -p /Net/IconThemeName -s "Papirus-Dark" 2>/dev/null || true + fi + ok "$(t themes_icons_installed "Papirus")" + ;; + 2) + install_optional_packages adwaita-icon-theme + if command_exists xfconf-query; then + xfconf-query -c xsettings -p /Net/IconThemeName -s "Adwaita" 2>/dev/null || true + fi + ok "$(t themes_icons_installed "Adwaita")" + ;; + esac +} + +install_fonts() { + info "$(t themes_fonts)..." + install_optional_packages \ + fontconfig \ + font-dejavu \ + font-noto \ + font-noto-emoji + + # Rebuild font cache + if command_exists fc-cache; then + fc-cache -fv >> "$LOG" 2>&1 || true + fi + + ok "$(t themes_fonts_installed)" +} + +set_wallpaper() { + local wallpaper_path="" + read -r -p " $(t themes_wallpaper_path)" wallpaper_path || return + + if [ -z "$wallpaper_path" ]; then + return + fi + + if [ ! -f "$wallpaper_path" ]; then + warn "$(t themes_wallpaper_not_found)" + return 1 + fi + + # Copia para pasta local + mkdir -p "${HOME}/.local/share/wallpapers" + cp "$wallpaper_path" "${HOME}/.local/share/wallpapers/current-wallpaper" 2>/dev/null || true + + # Tenta aplicar no XFCE4 + if command_exists xfconf-query; then + local monitor="" + for monitor in $(xfconf-query -c xfce4-desktop -l 2>/dev/null | grep "last-image$"); do + xfconf-query -c xfce4-desktop -p "$monitor" -s "$wallpaper_path" 2>/dev/null || true + done + fi + + ok "$(t themes_wallpaper_set)" +} + +themes_menu() { + while true; do + echo "" + _header "$(t themes_title)" + _item "1" "$(t themes_dark)" + _item "2" "$(t themes_icons)" + _item "3" "$(t themes_wallpaper)" + _item "4" "$(t themes_fonts)" + _item "0" "$(t back)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + 1) install_dark_theme ;; + 2) install_icon_pack ;; + 3) set_wallpaper ;; + 4) install_fonts ;; + 0) return ;; + *) warn "$(t menu_invalid)" ;; + esac + + pause_prompt + done +} diff --git a/lib/wine.sh b/lib/wine.sh new file mode 100644 index 0000000..7c568fc --- /dev/null +++ b/lib/wine.sh @@ -0,0 +1,86 @@ +#!/data/data/com.termux/files/usr/bin/bash +# lib/wine.sh — Gerenciamento de Wine/Hangover +# Sourced by script-termux.sh — NÃO executar diretamente. + +install_wine() { + if [ "${ARCH:-}" != "aarch64" ]; then + warn "$(t wine_not_arm64)" + fi + + if is_pkg_installed wine-stable; then + run_cmd "remover wine-stable antigo" pkg remove -y wine-stable + fi + + install_optional_packages hangover-wine hangover-wowbox64 + + if [ -x "$PREFIX/opt/hangover-wine/bin/wine" ]; then + ln -sf "$PREFIX/opt/hangover-wine/bin/wine" "$PREFIX/bin/wine" + ok "$(t wine_shortcut_created)" + else + warn "$(t wine_not_complete)" + fi + + INSTALL_WINE="y" + save_config +} + +remove_wine() { + local confirm="" + confirm="$(read_yes_no " $(t wine_remove_confirm)" 'n')" + if [ "$confirm" != "y" ]; then + return 0 + fi + + info "$(t wine_remove)..." + pkg remove -y hangover-wine hangover-wowbox64 >> "$LOG" 2>&1 || true + rm -f "$PREFIX/bin/wine" 2>/dev/null || true + pkg autoremove -y >> "$LOG" 2>&1 || true + ok "$(t wine_removed)" + + INSTALL_WINE="n" + save_config +} + +get_wine_status() { + if command_exists wine; then + t status_installed + else + t status_not_installed + fi +} + +wine_menu() { + while true; do + echo "" + _header "$(t wine_config_title)" + printf " | Wine: %-30s|\n" "$(get_wine_status)" + _line + _item "1" "$(t wine_install)" + _item "2" "$(t wine_remove)" + _item "0" "$(t back)" + _footer + echo "" + + local choice="" + read -r -p " $(t menu_prompt)" choice || choice="0" + + case "$choice" in + 1) install_wine ;; + 2) remove_wine ;; + 0) return ;; + *) warn "$(t menu_invalid)" ;; + esac + + pause_prompt + done +} + +# Usado na instalação completa +install_wine_if_requested() { + if [ "$INSTALL_WINE" != "y" ]; then + ok "$(t wine_skipped)" + return 0 + fi + + install_wine +} diff --git a/script-termux.sh b/script-termux.sh index c6c5161..c4d6d64 100644 --- a/script-termux.sh +++ b/script-termux.sh @@ -1,708 +1,171 @@ #!/data/data/com.termux/files/usr/bin/bash -# Instalador de ambiente gráfico para Termux + Termux-X11 +# Ponto de entrada modular para Configuração do Termux Linux/X11 +# Entrypoint for Termux Linux/X11 Configuration set -Eeuo pipefail IFS=$'\n\t' -# ========================= -# Configuração -# ========================= -LOG="${HOME}/termux-linux-install.log" -START_LOG="${HOME}/termux-linux-start.log" -STATE_DIR="${HOME}/.termux-linux" -SPINNER_PID="" -TOTAL=11 -CURRENT=0 - -DE_INPUT="1" -DE_NAME="XFCE4" -DE_COMMAND="startxfce4" -GPU_DRIVER="software" -GPU_ENABLED="false" -INSTALL_WINE="n" - -mkdir -p "$STATE_DIR" -: > "$LOG" - -# ========================= -# Cores e mensagens -# ========================= -if [ -t 1 ]; then - RED='\033[31m' - GREEN='\033[32m' - YELLOW='\033[33m' - BLUE='\033[34m' - BOLD='\033[1m' - RESET='\033[0m' -else - RED='' - GREEN='' - YELLOW='' - BLUE='' - BOLD='' - RESET='' -fi - -log_line() { - printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG" -} - -info() { - printf " ${BLUE}->${RESET} %s\n" "$*" - log_line "INFO: $*" -} - -ok() { - printf " ${GREEN}✓${RESET} %s\n" "$*" - log_line "OK: $*" -} - -warn() { - printf " ${YELLOW}!${RESET} %s\n" "$*" - log_line "AVISO: $*" -} - -_stop_spinner() { - if [ -n "${SPINNER_PID:-}" ]; then - kill "$SPINNER_PID" 2>/dev/null || true - wait "$SPINNER_PID" 2>/dev/null || true - printf "\r\033[K" - SPINNER_PID="" - fi -} - -show_log_tail() { - if [ -s "$LOG" ]; then - echo "" - echo " Últimas linhas do log:" - tail -n 25 "$LOG" | sed 's/^/ /' - fi -} - -die() { - _stop_spinner - echo "" - printf " ${RED}ERRO:${RESET} %s\n" "$*" >&2 - echo " Log completo: $LOG" >&2 - show_log_tail >&2 - exit 1 -} - -on_error() { - local line="$1" - local cmd="$2" - _stop_spinner - echo "" - printf " ${RED}ERRO inesperado na linha %s:${RESET} %s\n" "$line" "$cmd" >&2 - echo " Log completo: $LOG" >&2 - show_log_tail >&2 - exit 1 -} - +# Define o diretório do script +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +export SCRIPT_DIR + +# 1. Carrega o core (common e i18n) +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/common.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/i18n.sh" + +# 2. Carrega todos os outros módulos de biblioteca +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/checks.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/device.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/desktop.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/apps.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/wine.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/themes.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/scripts.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/backup.sh" +# shellcheck disable=SC1091 +source "${SCRIPT_DIR}/lib/menu.sh" + +# Armadilha de erro configurada no common.sh trap 'on_error "$LINENO" "$BASH_COMMAND"' ERR trap '_stop_spinner' EXIT -start_step() { - _stop_spinner - CURRENT=$((CURRENT + 1)) - local msg="$1" - local pct=$((CURRENT * 100 / TOTAL)) - local filled=$((pct * 24 / 100)) - local bar_fill="" - local bar="" - - if [ "$filled" -gt 0 ]; then - bar_fill=$(printf '%*s' "$filled" '' | tr ' ' '=') - fi - - if [ "$filled" -lt 24 ]; then - bar=$(printf "%-24s" "${bar_fill}>") - else - bar="$bar_fill" - fi - - echo "" - printf " ${BOLD}[%02d/%02d]${RESET} %s\n" "$CURRENT" "$TOTAL" "$msg" - log_line "PASSO $CURRENT/$TOTAL: $msg" - - ( - i=0 - chars='|/-\' - while true; do - printf "\r [%-24s] %3d%% %s" "$bar" "$pct" "${chars:$((i % 4)):1}" - i=$((i + 1)) - sleep 0.2 - done - ) & - SPINNER_PID=$! -} - -end_step() { - _stop_spinner - ok "Passo $CURRENT/$TOTAL concluído" -} - -run_cmd() { - local desc="$1" - shift - log_line "CMD: $*" - if ! "$@" >> "$LOG" 2>&1; then - die "Falha em: $desc" - fi -} - -install_required() { - local label="$1" - shift - info "Instalando: $*" - run_cmd "instalar $label" pkg install -y "$@" -} - -install_optional_packages() { - local pkg_name="" - for pkg_name in "$@"; do - info "Tentando instalar pacote opcional: $pkg_name" - if pkg install -y "$pkg_name" >> "$LOG" 2>&1; then - ok "Instalado: $pkg_name" - else - warn "Pacote opcional indisponível ou falhou: $pkg_name" - fi - done -} - -install_any_required() { - local label="$1" - shift - local pkg_name="" - - for pkg_name in "$@"; do - info "Tentando instalar $label: $pkg_name" - if pkg install -y "$pkg_name" >> "$LOG" 2>&1; then - ok "Instalado: $pkg_name" - return 0 - fi - done - - die "Nenhuma opção disponível para instalar: $label ($*)" -} - -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -require_termux() { - if [ "${PREFIX:-}" != "/data/data/com.termux/files/usr" ]; then - die "Este script deve ser executado dentro do Termux normal, não em Linux/PC/proot." - fi - - command_exists pkg || die "Comando 'pkg' não encontrado. Atualize/reinstale o Termux." -} - -check_internet() { - if command_exists curl; then - curl -fsI --connect-timeout 12 https://packages.termux.dev >/dev/null 2>>"$LOG" && return 0 - curl -fsI --connect-timeout 12 https://google.com >/dev/null 2>>"$LOG" && return 0 - fi - - ping -c 1 -W 8 packages.termux.dev >> "$LOG" 2>&1 && return 0 - ping -c 1 -W 8 google.com >> "$LOG" 2>&1 && return 0 - - return 1 -} - -wait_package_manager() { - local waited=0 - while pgrep -x apt >/dev/null 2>&1 || \ - pgrep -x apt-get >/dev/null 2>&1 || \ - pgrep -x dpkg >/dev/null 2>&1; do - if [ "$waited" -ge 90 ]; then - die "Outro processo do apt/dpkg está travado há muito tempo. Feche outros Termux e tente novamente." - fi - warn "Aguardando outro processo apt/dpkg terminar..." - sleep 3 - waited=$((waited + 3)) - done -} - -read_choice() { - local prompt="$1" - local default="$2" - local pattern="$3" - local value="" - - while true; do - read -r -p "$prompt" value || value="$default" - value="${value:-$default}" - if [[ "$value" =~ $pattern ]]; then - printf '%s\n' "$value" - return 0 - fi - echo " Opção inválida. Tente novamente." - done -} - -read_yes_no() { - local prompt="$1" - local default="$2" - local value="" - - while true; do - read -r -p "$prompt" value || value="$default" - value="${value:-$default}" - value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]')" - case "$value" in - s|sim|y|yes) printf 's\n'; return 0 ;; - n|nao|não|no) printf 'n\n'; return 0 ;; - *) echo " Responda com s ou n." ;; - esac - done -} - -banner() { - clear 2>/dev/null || true - echo "" - cat << 'ART' -| | |\ | | | \_/ -|___ | | \| \__/ / \ - - __ __ __ __ - /\ |\ | | \ |__) / \ | | \ -/~~\ | \| |__/ | \ \__/ | |__/ -ART - echo "" - echo " ======================================" - echo " Configurando Termux Linux/X11" - echo " ======================================" - echo "" -} - -collect_device_info() { - ARCH="$(uname -m)" - DEVICE_BRAND="$(getprop ro.product.brand 2>/dev/null || echo 'Unknown')" - DEVICE_MODEL="$(getprop ro.product.model 2>/dev/null || echo 'Unknown')" - GPU_INFO="$( - { - getprop ro.hardware.egl - getprop ro.hardware.vulkan - getprop ro.board.platform - getprop ro.hardware - } 2>/dev/null | tr '[:upper:]' '[:lower:]' - )" - - info "Arquitetura: $ARCH" - info "Dispositivo: $DEVICE_BRAND $DEVICE_MODEL" - - if [ "$ARCH" != "aarch64" ]; then - warn "Wine/Hangover e aceleração gráfica costumam funcionar melhor em ARM64/aarch64." - fi -} - -choose_gpu() { - echo "" - echo " -- Configuração de GPU --" - echo " 1) Automático (recomendado)" - echo " 2) Forçar aceleração GPU Adreno/Freedreno" - echo " 3) Desativar aceleração GPU/usar software" - echo "" - - local gpu_option="" - gpu_option="$(read_choice ' Opção [1-3, padrão=1]: ' '1' '^[1-3]$')" - - case "$gpu_option" in - 1) - if printf '%s' "$GPU_INFO" | grep -Eq 'adreno|qcom|qualcomm|msm'; then - GPU_DRIVER="freedreno" - GPU_ENABLED="true" - ok "GPU Qualcomm/Adreno detectada. Aceleração será ativada." +# Processamento de flags da CLI +show_help() { + echo "Uso / Usage: ./script-termux.sh [opções / options]" + echo "" + echo "Opções / Options:" + echo " --help, -h Mostra esta mensagem de ajuda / Show this help message" + echo " --install Inicia a instalação completa automática / Start automated full installation" + echo " --desktop [de] Instala um desktop específico (xfce4, lxqt, mate, kde) / Install specific desktop" + echo " --app [nome] Instala um aplicativo específico do catálogo / Install a specific app from catalog" + echo " --lang [pt|en] Força o idioma do script / Force script language" + echo "" + exit 0 +} + +# Define variáveis para as ações CLI +ACTION="menu" +DESKTOP_ARG="" +APP_ARG="" +FORCE_LANG="" + +# Processamento de argumentos +while (( "$#" )); do + case "$1" in + -h|--help) + show_help + ;; + --install) + ACTION="install" + shift + ;; + --desktop) + ACTION="desktop" + if [ -n "${2:-}" ]; then + DESKTOP_ARG="$2" + shift 2 else - GPU_DRIVER="software" - GPU_ENABLED="false" - warn "GPU Adreno não detectada. Usarei modo compatível sem aceleração forçada." + echo "Erro: Faltou especificar o desktop (xfce4, lxqt, mate, kde)." >&2 + exit 1 fi - ;; - 2) - GPU_DRIVER="freedreno" - GPU_ENABLED="true" - warn "Aceleração GPU foi forçada. Se a tela ficar preta/travar, rode novamente e escolha a opção 3." - ;; - 3) - GPU_DRIVER="software" - GPU_ENABLED="false" - ok "Aceleração GPU desativada." - ;; + ;; + --app) + ACTION="app" + if [ -n "${2:-}" ]; then + APP_ARG="$2" + shift 2 + else + echo "Erro: Faltou especificar o nome do aplicativo." >&2 + exit 1 + fi + ;; + --lang) + if [ -n "${2:-}" ]; then + FORCE_LANG="$2" + shift 2 + else + echo "Erro: Faltou especificar o idioma (pt, en)." >&2 + exit 1 + fi + ;; + *) + echo "Erro: Flag não suportada / Unsupported flag: $1" >&2 + show_help + ;; esac -} - -choose_desktop() { - echo "" - echo " -- Escolha o Desktop --" - echo " 1) XFCE4 (recomendado/mais estável)" - echo " 2) LXQt (leve)" - echo " 3) MATE (médio)" - echo " 4) KDE Plasma (pesado/experimental)" - echo "" +done - DE_INPUT="$(read_choice ' Opção [1-4, padrão=1]: ' '1' '^[1-4]$')" +# Inicialização e detecção de idioma +load_config || true - case "$DE_INPUT" in - 1) - DE_NAME="XFCE4" - DE_COMMAND="startxfce4" - DE_CORE_PACKAGES=(xfce4 dbus pulseaudio) - DE_EXTRA_PACKAGES=(xfce4-terminal thunar mousepad pavucontrol shared-mime-info fontconfig) - ;; - 2) - DE_NAME="LXQt" - DE_COMMAND="startlxqt" - DE_CORE_PACKAGES=(lxqt-session openbox dbus pulseaudio) - DE_EXTRA_PACKAGES=(lxqt-panel pcmanfm-qt qterminal featherpad gtk3 pavucontrol shared-mime-info fontconfig) - ;; - 3) - DE_NAME="MATE" - DE_COMMAND="mate-session" - DE_CORE_PACKAGES=(mate-session-manager marco dbus pulseaudio) - DE_EXTRA_PACKAGES=(mate-panel mate-terminal fontconfig shared-mime-info) - ;; - 4) - DE_NAME="KDE Plasma" - DE_COMMAND="startplasma-x11" - DE_CORE_PACKAGES=(plasma-desktop dbus pulseaudio) - DE_EXTRA_PACKAGES=(konsole fontconfig shared-mime-info) - ;; +if [ -n "$FORCE_LANG" ]; then + case "$FORCE_LANG" in + pt|en) load_language "$FORCE_LANG" ;; + *) echo "Idioma inválido. Opções: pt, en. / Invalid language. Options: pt, en." >&2; exit 1 ;; esac +else + detect_language +fi - ok "Desktop escolhido: $DE_NAME" -} - -prepare_environment() { - export DEBIAN_FRONTEND=noninteractive - export LANG=C.UTF-8 - export LC_ALL=C.UTF-8 - export TMPDIR="${TMPDIR:-$PREFIX/tmp}" - - mkdir -p "$TMPDIR" - mkdir -p "$PREFIX/etc/apt/apt.conf.d" - - cat > "$PREFIX/etc/apt/apt.conf.d/99termux-noninteractive" <<'APTCONF' -DPkg::Options { - "--force-confdef"; - "--force-confold"; -}; -APTCONF -} - -install_desktop() { - # No Termux atual, o pacote dbus-x11 pode não existir. Por isso ele não é usado - # como dependência obrigatória. O script usa dbus-launch apenas se o comando existir. - local pkg_name="" - - for pkg_name in "${DE_CORE_PACKAGES[@]}"; do - install_required "pacote obrigatório do $DE_NAME: $pkg_name" "$pkg_name" - done - - install_optional_packages "${DE_EXTRA_PACKAGES[@]}" +# Agora executa a verificação obrigatória de ambiente +require_termux - if ! command_exists "$DE_COMMAND"; then - die "O comando '$DE_COMMAND' não foi encontrado após instalar $DE_NAME. Veja o log e tente outro desktop." - fi -} +# Executa a ação selecionada +case "$ACTION" in + install) + full_install + ;; + desktop) + case "$(echo "$DESKTOP_ARG" | tr '[:upper:]' '[:lower:]')" in + xfce4) _set_desktop_vars 1 ;; + lxqt) _set_desktop_vars 2 ;; + mate) _set_desktop_vars 3 ;; + kde) _set_desktop_vars 4 ;; + *) die "Desktop inválido. Opções: xfce4, lxqt, mate, kde." ;; + esac + install_desktop + save_config + ;; + app) + # Procura o app no catálogo apps.conf + app_found=false + app_pkg="" + app_name="" + while IFS='|' read -r _cat name pkg; do + clean_name="$(echo "$name" | tr '[:upper:]' '[:lower:]')" + clean_pkg="$(echo "$pkg" | tr '[:upper:]' '[:lower:]')" + target_arg="$(echo "$APP_ARG" | tr '[:upper:]' '[:lower:]')" + if [[ "$clean_name" == *"$target_arg"* ]] || [[ "$clean_pkg" == *"$target_arg"* ]]; then + app_pkg="$pkg" + app_name="$name" + app_found=true + break + fi + done < "${SCRIPT_DIR}/apps.conf" -install_gpu_drivers() { - if [ "$GPU_ENABLED" = "true" ]; then - info "Instalando base gráfica Vulkan/Zink" - if pkg install -y mesa-zink vulkan-loader-android >> "$LOG" 2>&1; then - ok "Base gráfica instalada" + if [ "$app_found" = true ]; then + info "$(t installing "$app_name")" + # shellcheck disable=SC2086 + install_with_retry $app_pkg || die "$(t optional_pkg_failed "$app_name")" else - warn "Drivers mesa-zink/vulkan-loader-android falharam. Vou continuar em modo software." - GPU_ENABLED="false" - GPU_DRIVER="software" - return 0 + die "Aplicativo '$APP_ARG' não encontrado no catálogo apps.conf." fi - - if [ "$GPU_DRIVER" = "freedreno" ]; then - install_optional_packages mesa-vulkan-icd-freedreno vulkan-tools + ;; + menu) + # Se for a primeira execução (sem desktop configurado no config.env), perguntar o idioma primeiro. + if [ -z "${DE_NAME:-}" ] && [ ! -f "${STATE_DIR}/config.env" ]; then + choose_language fi - else - ok "Modo software selecionado. Drivers GPU extras não serão forçados." - fi -} - -install_wine_if_requested() { - if [ "$INSTALL_WINE" != "s" ]; then - ok "Wine/Hangover ignorado." - return 0 - fi - - if [ "${ARCH:-}" != "aarch64" ]; then - warn "Seu aparelho não parece ser ARM64/aarch64. Wine/Hangover pode não funcionar bem." - fi - - if dpkg -s wine-stable >/dev/null 2>&1; then - run_cmd "remover wine-stable antigo" pkg remove -y wine-stable - fi - - install_optional_packages hangover-wine hangover-wowbox64 - - if [ -x "$PREFIX/opt/hangover-wine/bin/wine" ]; then - ln -sf "$PREFIX/opt/hangover-wine/bin/wine" "$PREFIX/bin/wine" - ok "Atalho 'wine' criado." - else - warn "Hangover Wine não parece ter sido instalado completamente." - fi -} - -write_start_script() { - cat > "${HOME}/start-linux.sh" < "\$LOG" - -export LANG=C.UTF-8 -export LC_ALL=C.UTF-8 -export TMPDIR="\${TMPDIR:-/data/data/com.termux/files/usr/tmp}" -mkdir -p "\$TMPDIR" - -export XDG_RUNTIME_DIR="\$TMPDIR" -export DISPLAY=:0 -export XDG_SESSION_TYPE=x11 -export QT_X11_NO_MITSHM=1 -export NO_AT_BRIDGE=1 -export PULSE_SERVER=127.0.0.1 -EOF_START - - if [ "$GPU_ENABLED" = "true" ]; then - cat >> "${HOME}/start-linux.sh" <<'EOF_GPU' -export GALLIUM_DRIVER=zink -export MESA_LOADER_DRIVER_OVERRIDE=zink -export MESA_NO_ERROR=1 -EOF_GPU - else - cat >> "${HOME}/start-linux.sh" <<'EOF_GPU' -export LIBGL_ALWAYS_SOFTWARE=1 -EOF_GPU - fi - - cat >> "${HOME}/start-linux.sh" </dev/null || true - pkill -f "termux-x11.*:0" 2>/dev/null || true - pulseaudio --kill >/dev/null 2>&1 || true -} - -start_audio() { - pulseaudio --start --exit-idle-time=-1 >> "\$LOG" 2>&1 || true - pactl load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1 >> "\$LOG" 2>&1 || true -} - -start_x11() { - am start --user 0 -n com.termux.x11/com.termux.x11.MainActivity >> "\$LOG" 2>&1 || true - termux-x11 :0 >> "\$LOG" 2>&1 & - sleep 3 -} - -echo "Iniciando Termux Linux/X11..." -stop_old_sessions -sleep 1 -start_audio -start_x11 - -start_desktop() { - cd "\$HOME" - - if command -v dbus-launch >/dev/null 2>&1; then - exec dbus-launch --exit-with-session ${DE_COMMAND} - fi - - echo "Aviso: dbus-launch não encontrado. Iniciando ${DE_NAME} sem dbus-launch." >> "\$LOG" - exec ${DE_COMMAND} -} - -start_desktop -EOF_START2 - - chmod +x "${HOME}/start-linux.sh" -} - -write_stop_script() { - cat > "${HOME}/stop-linux.sh" <<'EOF_STOP' -#!/data/data/com.termux/files/usr/bin/bash - -pkill -f "startxfce4|startlxqt|mate-session|startplasma-x11|xfce4-session|lxqt-session" 2>/dev/null || true -pkill -f "termux-x11.*:0" 2>/dev/null || true -pulseaudio --kill >/dev/null 2>&1 || true - -echo "Desktop finalizado." -EOF_STOP - - chmod +x "${HOME}/stop-linux.sh" -} - -write_info_script() { - cat > "${HOME}/linux-info.sh" <<'EOF_INFO' -#!/data/data/com.termux/files/usr/bin/bash - -echo "===== Termux Linux/X11 - Diagnóstico =====" -echo "Data: $(date)" -echo "Arquitetura: $(uname -m)" -echo "PREFIX: ${PREFIX:-desconhecido}" -echo "DISPLAY: ${DISPLAY:-não definido}" -echo "" -echo "Comandos encontrados:" -for cmd in termux-x11 dbus-launch startxfce4 startlxqt mate-session startplasma-x11 pulseaudio; do - if command -v "$cmd" >/dev/null 2>&1; then - echo " ✓ $cmd -> $(command -v "$cmd")" - else - echo " - $cmd não encontrado" - fi -done - -echo "" -echo "Últimas linhas do log de instalação:" -tail -n 30 "$HOME/termux-linux-install.log" 2>/dev/null || true - -echo "" -echo "Últimas linhas do log de inicialização:" -tail -n 30 "$HOME/termux-linux-start.log" 2>/dev/null || true -EOF_INFO - - chmod +x "${HOME}/linux-info.sh" -} - -create_desktop_shortcuts() { - mkdir -p "${HOME}/Desktop" - - if command_exists firefox; then - cat > "${HOME}/Desktop/Firefox.desktop" <<'EOF_FIREFOX' -[Desktop Entry] -Name=Firefox -Exec=firefox -Type=Application -Categories=Network;WebBrowser; -Terminal=false -EOF_FIREFOX - fi - - if command_exists code-oss; then - cat > "${HOME}/Desktop/CodeOSS.desktop" <<'EOF_CODE' -[Desktop Entry] -Name=Code OSS -Exec=code-oss --no-sandbox -Type=Application -Categories=Development; -Terminal=false -EOF_CODE - fi - - chmod +x "${HOME}/Desktop"/*.desktop 2>/dev/null || true -} - -save_config() { - cat > "${STATE_DIR}/config.env" <