1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-14 16:27:28 +00:00

🎨 Uninstalling and cleaning is a cleaner experience

This commit is contained in:
Tw93
2025-10-04 17:59:12 +08:00
parent a3c3975f5f
commit a830123ac4
5 changed files with 86 additions and 71 deletions

View File

@@ -257,65 +257,66 @@ safe_clean() {
} }
start_cleanup() { start_cleanup() {
clear
echo ""
echo -e "${PURPLE}🧹 Clean Your Mac${NC}"
echo "" echo ""
echo "Mole will remove app caches, browser data, developer tools, and temporary files." echo "Mole will remove app caches, browser data, developer tools, and temporary files."
echo ""
if [[ "$DRY_RUN" != "true" && -t 0 ]]; then if [[ "$DRY_RUN" != "true" && -t 0 ]]; then
echo -e "${BLUE}Tip:${NC} Want a preview first? Run 'mole clean --dry-run'."
echo "" echo ""
echo -e "${BLUE}Tip:${NC} Want a preview first? Run 'mole clean --dry-run'."
fi fi
if [[ "$DRY_RUN" == "true" ]]; then if [[ "$DRY_RUN" == "true" ]]; then
echo ""
echo -e "${YELLOW}🧪 Dry Run mode:${NC} showing what would be removed (no deletions)." echo -e "${YELLOW}🧪 Dry Run mode:${NC} showing what would be removed (no deletions)."
echo "" echo ""
SYSTEM_CLEAN=false SYSTEM_CLEAN=false
return return
fi fi
local password=""
if [[ -t 0 ]]; then if [[ -t 0 ]]; then
echo "Enter admin password for system-level cleanup (or press Enter to skip):" echo ""
echo -n "> " echo "System-level cleanup removes system caches and temp files, optional."
echo -en "${BLUE}Enter admin password to enable, or press Enter to skip: ${NC}"
read -s password read -s password
echo "" echo ""
else
password="" if [[ -n "$password" ]] && echo "$password" | sudo -S true 2>/dev/null; then
echo "" SYSTEM_CLEAN=true
echo -e "${BLUE}${NC} Running in non-interactive mode" # Start sudo keepalive with error handling
echo " • System-level cleanup will be skipped (requires password)" (
echo " • User-level cleanup will proceed automatically" local retry_count=0
echo "" while true; do
fi if ! sudo -n true 2>/dev/null; then
((retry_count++))
if [[ -n "$password" ]] && echo "$password" | sudo -S true 2>/dev/null; then if [[ $retry_count -ge 3 ]]; then
SYSTEM_CLEAN=true exit 1
# Start sudo keepalive with error handling and shorter intervals fi
( sleep 5
local retry_count=0 continue
while true; do
if ! sudo -n true 2>/dev/null; then
((retry_count++))
if [[ $retry_count -ge 3 ]]; then
log_warning "Sudo keepalive failed, system-level cleanup may be interrupted" >&2
exit 1
fi fi
sleep 5 retry_count=0
continue sleep 30
fi kill -0 "$$" 2>/dev/null || exit
retry_count=0 done
sleep 30 ) 2>/dev/null &
kill -0 "$$" 2>/dev/null || exit SUDO_KEEPALIVE_PID=$!
done else
) 2>/dev/null & SYSTEM_CLEAN=false
SUDO_KEEPALIVE_PID=$! if [[ -n "$password" ]]; then
log_info "Starting comprehensive cleanup with admin privileges..." echo ""
echo -e "${YELLOW}⚠️ Invalid password, continuing with user-level cleanup${NC}"
fi
fi
else else
SYSTEM_CLEAN=false SYSTEM_CLEAN=false
log_info "Starting user-level cleanup..." echo ""
if [[ -n "$password" ]]; then echo -e "${BLUE}${NC} Running in non-interactive mode"
echo -e "${YELLOW}⚠️ Invalid password, continuing with user-level cleanup${NC}" echo " • System-level cleanup skipped (requires interaction)"
fi echo " • User-level cleanup will proceed automatically"
echo ""
fi fi
} }

View File

@@ -19,29 +19,29 @@ source "$SCRIPT_DIR/../lib/batch_uninstall.sh"
# Help information # Help information
show_help() { show_help() {
echo "App Uninstaller" echo "Usage: mole uninstall"
echo "==============="
echo "" echo ""
echo "Uninstall applications and clean their data completely." echo "Interactive application uninstaller - Remove apps completely"
echo "" echo ""
echo "Controls:" echo "Keyboard Controls:"
echo " ↑/↓ Navigate" echo " ↑/↓ Navigate items"
echo " SPACE Select/deselect" echo " Space Select/deselect"
echo " ENTER Confirm" echo " Enter Confirm and uninstall"
echo " Q Quit" echo " Q / ESC Quit"
echo ""
echo "Usage:"
echo " ./uninstall.sh Launch interactive uninstaller"
echo " ./uninstall.sh --help Show this help message"
echo "" echo ""
echo "What gets cleaned:" echo "What gets cleaned:"
echo " • Application bundle" echo " • Application bundle"
echo " • Application Support data" echo " • Application Support data (12+ locations)"
echo " • Cache files" echo " • Cache files"
echo " • Preference files" echo " • Preference files"
echo " • Log files" echo " • Log files"
echo " • Saved application state" echo " • Saved application state"
echo " • Container data (sandboxed apps)" echo " • Container data (sandboxed apps)"
echo " • WebKit storage, HTTP storage, cookies"
echo " • Extensions, plugins, services"
echo ""
echo "Examples:"
echo " mole uninstall Launch interactive uninstaller"
echo "" echo ""
} }
@@ -116,11 +116,13 @@ scan_applications() {
local temp_file=$(mktemp) local temp_file=$(mktemp)
echo -n "Scanning... " >&2
# Pre-cache current epoch to avoid repeated calls # Pre-cache current epoch to avoid repeated calls
local current_epoch=$(date "+%s") local current_epoch=$(date "+%s")
# Spinner for scanning feedback
local spinner_chars="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
local spinner_idx=0
# First pass: quickly collect all valid app paths and bundle IDs # First pass: quickly collect all valid app paths and bundle IDs
local -a app_data_tuples=() local -a app_data_tuples=()
while IFS= read -r -d '' app_path; do while IFS= read -r -d '' app_path; do
@@ -279,8 +281,10 @@ scan_applications() {
process_app_metadata "$app_data_tuple" "$temp_file" "$current_epoch" & process_app_metadata "$app_data_tuple" "$temp_file" "$current_epoch" &
pids+=($!) pids+=($!)
# Update progress # Update progress with spinner
echo -ne "\rScanning... $app_count/$total_apps" >&2 local spinner_char="${spinner_chars:$((spinner_idx % 10)):1}"
echo -ne "\r🗑 ${spinner_char} Scanning... $app_count/$total_apps" >&2
((spinner_idx++))
# Wait if we've hit max parallel limit # Wait if we've hit max parallel limit
if (( ${#pids[@]} >= max_parallel )); then if (( ${#pids[@]} >= max_parallel )); then
@@ -294,7 +298,8 @@ scan_applications() {
wait "$pid" 2>/dev/null wait "$pid" 2>/dev/null
done done
echo -e "\rFound $app_count applications " >&2 echo -e "\r🗑️ ✓ Found $app_count applications " >&2
echo "" >&2
# Check if we found any applications # Check if we found any applications
if [[ ! -s "$temp_file" ]]; then if [[ ! -s "$temp_file" ]]; then

View File

@@ -37,17 +37,11 @@ select_apps_for_uninstall() {
menu_options+=("$(format_app_display "$display_name" "$size" "$last_used")") menu_options+=("$(format_app_display "$display_name" "$size" "$last_used")")
done done
echo ""
echo "🗑️ App Uninstaller"
echo ""
echo "Mole will uninstall selected apps and clean all their related files."
echo ""
echo "Found ${#apps_data[@]} apps. Select apps to remove:"
echo "" echo ""
# Use paginated menu - result will be stored in MOLE_SELECTION_RESULT # Use paginated menu - result will be stored in MOLE_SELECTION_RESULT
MOLE_SELECTION_RESULT="" MOLE_SELECTION_RESULT=""
paginated_multi_select "Select Apps to Remove" "${menu_options[@]}" paginated_multi_select "🗑️ Select Apps to Remove" "${menu_options[@]}"
local exit_code=$? local exit_code=$?
if [[ $exit_code -ne 0 ]]; then if [[ $exit_code -ne 0 ]]; then

View File

@@ -20,8 +20,18 @@ batch_uninstall_applications() {
local -a app_details=() local -a app_details=()
echo "" echo ""
echo -e "${BLUE}📋 Analyzing selected applications...${NC}"
# Show analyzing message with spinner
local spinner_chars="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
local spinner_idx=0
local analyzed=0
for selected_app in "${selected_apps[@]}"; do for selected_app in "${selected_apps[@]}"; do
# Update spinner
local spinner_char="${spinner_chars:$((spinner_idx % 10)):1}"
((analyzed++))
echo -ne "\r🗑 ${spinner_char} Analyzing... $analyzed/${#selected_apps[@]}" >&2
((spinner_idx++))
IFS='|' read -r epoch app_path app_name bundle_id size last_used <<< "$selected_app" IFS='|' read -r epoch app_path app_name bundle_id size last_used <<< "$selected_app"
# Check if app is running # Check if app is running
@@ -47,6 +57,9 @@ batch_uninstall_applications() {
app_details+=("$app_name|$app_path|$bundle_id|$total_kb|$encoded_files") app_details+=("$app_name|$app_path|$bundle_id|$total_kb|$encoded_files")
done done
# Clear spinner line
echo -ne "\r\033[K" >&2
# Format size display # Format size display
if [[ $total_estimated_size -gt 1048576 ]]; then if [[ $total_estimated_size -gt 1048576 ]]; then
local size_display=$(echo "$total_estimated_size" | awk '{printf "%.2fGB", $1/1024/1024}') local size_display=$(echo "$total_estimated_size" | awk '{printf "%.2fGB", $1/1024/1024}')

View File

@@ -63,8 +63,12 @@ paginated_multi_select() {
draw_menu() { draw_menu() {
printf "\033[H\033[J" >&2 # Clear screen and move to top printf "\033[H\033[J" >&2 # Clear screen and move to top
# Header # Header - strip emoji for length calculation
printf "%s\n%s\n" "$title" "$(printf '=%.0s' $(seq 1 ${#title}))" >&2 local title_clean="${title//[^[:print:]]/}"
local title_len_approx=$(( ${#title_clean} - 4 )) # Rough adjustment for emoji
[[ $title_len_approx -lt 10 ]] && title_len_approx=10
printf "${PURPLE}%s${NC}\n%s\n" "$title" "$(printf '=%.0s' $(seq 1 $title_len_approx))" >&2
# Status # Status
local selected_count=0 local selected_count=0
@@ -92,7 +96,7 @@ paginated_multi_select() {
done done
print_line "" print_line ""
print_line "↑↓: Navigate | Space: Select | Enter: Confirm | Q: Exit" print_line "${GRAY}↑/↓${NC} Navigate ${GRAY}|${NC} ${GRAY}Space${NC} Select ${GRAY}|${NC} ${GRAY}Enter${NC} Confirm ${GRAY}|${NC} ${GRAY}Q/ESC${NC} Quit"
} }
# Show help screen # Show help screen
@@ -105,9 +109,7 @@ Help - Navigation Controls
↑ / ↓ Navigate up/down ↑ / ↓ Navigate up/down
Space Select/deselect item Space Select/deselect item
Enter Confirm selection Enter Confirm selection
A Select all Q / ESC Exit
N Deselect all
Q Exit
Press any key to continue... Press any key to continue...
EOF EOF