fixed GUI update issue on successive transfers
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script to verify progress callback is working
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, "src")
|
||||
|
||||
from adb_manager import ADBManager
|
||||
import time
|
||||
|
||||
|
||||
def test_progress_callback():
|
||||
"""Test the progress callback functionality."""
|
||||
print("Testing progress callback...")
|
||||
|
||||
# Track progress updates
|
||||
progress_updates = []
|
||||
|
||||
def progress_callback(percentage):
|
||||
progress_updates.append(percentage)
|
||||
print(f"Progress update: {percentage}%")
|
||||
|
||||
def status_callback(message):
|
||||
print(f"Status: {message}")
|
||||
|
||||
# Create ADB manager and set callbacks
|
||||
adb = ADBManager()
|
||||
adb.set_progress_callback(progress_callback)
|
||||
adb.set_status_callback(status_callback)
|
||||
|
||||
# Test manual progress updates
|
||||
print("\nTesting manual progress updates:")
|
||||
for i in range(0, 101, 25):
|
||||
adb._update_progress(i)
|
||||
time.sleep(0.1)
|
||||
|
||||
print(f"\nProgress updates received: {progress_updates}")
|
||||
print(f"Total updates: {len(progress_updates)}")
|
||||
|
||||
# Test progress parsing
|
||||
print("\nTesting progress parsing:")
|
||||
test_lines = [
|
||||
"Pulling: /sdcard/DCIM/Camera/IMG_20250815_123456.jpg... (25%)",
|
||||
"/sdcard/Documents/file.txt: 1 file pulled. (50%)",
|
||||
"Pulling: /sdcard/Music/song.mp3... (75%)",
|
||||
"3 files pulled. (100%)",
|
||||
"No progress info here",
|
||||
"",
|
||||
]
|
||||
|
||||
for line in test_lines:
|
||||
progress = adb.parse_progress(line)
|
||||
print(f"Line: {repr(line[:50])} -> Progress: {progress}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_progress_callback()
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Debug successive transfers to understand progress bar issue
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
sys.path.insert(0, "src")
|
||||
|
||||
from adb_manager import ADBManager
|
||||
|
||||
|
||||
def test_successive_transfers():
|
||||
"""Test multiple transfers to debug progress issues."""
|
||||
print("Testing successive transfer callbacks...")
|
||||
|
||||
# Track progress updates for each transfer
|
||||
transfer1_progress = []
|
||||
transfer2_progress = []
|
||||
current_transfer = 1
|
||||
|
||||
def progress_callback(percentage):
|
||||
if current_transfer == 1:
|
||||
transfer1_progress.append(percentage)
|
||||
print(f"Transfer 1 - Progress: {percentage}%")
|
||||
else:
|
||||
transfer2_progress.append(percentage)
|
||||
print(f"Transfer 2 - Progress: {percentage}%")
|
||||
|
||||
def status_callback(message):
|
||||
print(f"Transfer {current_transfer} - Status: {message}")
|
||||
|
||||
# Create ADB manager and set callbacks
|
||||
adb = ADBManager()
|
||||
adb.set_progress_callback(progress_callback)
|
||||
adb.set_status_callback(status_callback)
|
||||
|
||||
# Test first transfer simulation
|
||||
print("\n=== FIRST TRANSFER ===")
|
||||
current_transfer = 1
|
||||
print("Simulating first transfer...")
|
||||
adb._update_progress(0)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(25)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(50)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(75)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(100)
|
||||
|
||||
print(f"First transfer progress updates: {transfer1_progress}")
|
||||
|
||||
# Test second transfer simulation
|
||||
print("\n=== SECOND TRANSFER ===")
|
||||
current_transfer = 2
|
||||
print("Simulating second transfer...")
|
||||
adb._update_progress(0)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(30)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(60)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(90)
|
||||
time.sleep(0.5)
|
||||
adb._update_progress(100)
|
||||
|
||||
print(f"Second transfer progress updates: {transfer2_progress}")
|
||||
|
||||
# Check if callbacks are still working
|
||||
print(f"\nCallback function still set: {adb.progress_callback is not None}")
|
||||
print(f"Status callback still set: {adb.status_callback is not None}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_successive_transfers()
|
||||
+30
-2
@@ -157,6 +157,10 @@ class ADBManager:
|
||||
cmd = [ADB_BINARY_PATH, "pull", remote_path, local_path]
|
||||
|
||||
try:
|
||||
# Start with initial progress
|
||||
self._update_progress(0)
|
||||
self._update_status("Starting transfer...")
|
||||
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
@@ -165,11 +169,22 @@ class ADBManager:
|
||||
bufsize=1,
|
||||
)
|
||||
|
||||
line_count = 0
|
||||
last_progress = 0
|
||||
if proc.stdout:
|
||||
for line in proc.stdout:
|
||||
line_count += 1
|
||||
pct = self.parse_progress(line)
|
||||
if pct is not None:
|
||||
self._update_progress(pct)
|
||||
last_progress = pct
|
||||
else:
|
||||
# If no explicit progress, simulate some progress based on activity
|
||||
if line_count % 5 == 0 and last_progress < 90:
|
||||
estimated_progress = min(last_progress + 5, 90)
|
||||
self._update_progress(estimated_progress)
|
||||
last_progress = estimated_progress
|
||||
|
||||
self._update_status(line.strip())
|
||||
|
||||
proc.wait()
|
||||
@@ -190,6 +205,10 @@ class ADBManager:
|
||||
cmd = [ADB_BINARY_PATH, "push", local_path, remote_path]
|
||||
|
||||
try:
|
||||
# Start with initial progress
|
||||
self._update_progress(0)
|
||||
self._update_status("Starting transfer...")
|
||||
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
@@ -201,13 +220,22 @@ class ADBManager:
|
||||
self._update_status(f"Failed to start adb: {e}")
|
||||
return False
|
||||
|
||||
self._update_status("Transferring files...")
|
||||
|
||||
line_count = 0
|
||||
last_progress = 0
|
||||
if proc.stdout:
|
||||
for line in proc.stdout:
|
||||
line_count += 1
|
||||
pct = self.parse_progress(line)
|
||||
if pct is not None:
|
||||
self._update_progress(pct)
|
||||
last_progress = pct
|
||||
else:
|
||||
# If no explicit progress, simulate some progress based on activity
|
||||
if line_count % 5 == 0 and last_progress < 90:
|
||||
estimated_progress = min(last_progress + 5, 90)
|
||||
self._update_progress(estimated_progress)
|
||||
last_progress = estimated_progress
|
||||
|
||||
self._update_status(line.strip())
|
||||
|
||||
proc.wait()
|
||||
|
||||
+72
-16
@@ -39,6 +39,9 @@ class AndroidFileHandlerGUI(tk.Tk):
|
||||
self.adb_manager.set_progress_callback(self.update_progress)
|
||||
self.adb_manager.set_status_callback(self.set_status)
|
||||
|
||||
# Transfer tracking for thread safety
|
||||
self.current_transfer_id = 0
|
||||
|
||||
if get_platform_type().startswith("linux"):
|
||||
self.mtp_manager = LinuxMTPManager()
|
||||
else:
|
||||
@@ -590,7 +593,12 @@ class AndroidFileHandlerGUI(tk.Tk):
|
||||
self.start_btn.config(state="disabled")
|
||||
|
||||
def enable_controls(self):
|
||||
"""Enable UI controls after operations."""
|
||||
"""Enable UI controls after operations (thread-safe)."""
|
||||
# Schedule UI update on main thread
|
||||
self.after(0, self._enable_controls_ui)
|
||||
|
||||
def _enable_controls_ui(self):
|
||||
"""Internal method to enable controls on main thread."""
|
||||
self.remote_path_entry.config(state="normal")
|
||||
self.local_path_entry.config(state="normal")
|
||||
self.start_btn.config(state="normal")
|
||||
@@ -609,7 +617,12 @@ class AndroidFileHandlerGUI(tk.Tk):
|
||||
messagebox.showinfo("Enable USB Debugging", msg)
|
||||
|
||||
def show_disable_debugging_reminder(self):
|
||||
"""Show reminder to disable USB debugging after transfer."""
|
||||
"""Show reminder to disable USB debugging after transfer (thread-safe)."""
|
||||
# Schedule UI update on main thread
|
||||
self.after(0, self._show_debugging_reminder_ui)
|
||||
|
||||
def _show_debugging_reminder_ui(self):
|
||||
"""Internal method to show debugging reminder on main thread."""
|
||||
msg = (
|
||||
"Transfer completed.\n\n"
|
||||
"For security, disable USB debugging when done:\n"
|
||||
@@ -634,57 +647,100 @@ class AndroidFileHandlerGUI(tk.Tk):
|
||||
return
|
||||
|
||||
# Start transfer
|
||||
self.current_transfer_id += 1
|
||||
transfer_id = self.current_transfer_id
|
||||
|
||||
self.disable_controls()
|
||||
self.progress["value"] = 0
|
||||
# Reset progress bar in thread-safe way
|
||||
self._update_progress_ui(0)
|
||||
|
||||
if direction == "pull":
|
||||
self.set_status("Starting pull transfer...")
|
||||
threading.Thread(
|
||||
target=self._pull_thread, args=(remote_path, local_path), daemon=True
|
||||
target=self._pull_thread,
|
||||
args=(remote_path, local_path, transfer_id),
|
||||
daemon=True,
|
||||
).start()
|
||||
elif direction == "push":
|
||||
self.set_status("Starting push transfer...")
|
||||
threading.Thread(
|
||||
target=self._push_thread, args=(local_path, remote_path), daemon=True
|
||||
target=self._push_thread,
|
||||
args=(local_path, remote_path, transfer_id),
|
||||
daemon=True,
|
||||
).start()
|
||||
else:
|
||||
self.report_error("Invalid transfer direction selected.")
|
||||
self.enable_controls()
|
||||
|
||||
def _pull_thread(self, remote_path: str, local_path: str):
|
||||
def _pull_thread(self, remote_path: str, local_path: str, transfer_id: int):
|
||||
"""Thread function for pull operations."""
|
||||
try:
|
||||
# Check if this transfer is still current
|
||||
if self.current_transfer_id != transfer_id:
|
||||
return
|
||||
|
||||
success = self.adb_manager.pull_folder(remote_path, local_path)
|
||||
if success:
|
||||
if success and self.current_transfer_id == transfer_id:
|
||||
self.show_disable_debugging_reminder()
|
||||
except Exception as e:
|
||||
self.report_error(f"Pull operation failed: {e}")
|
||||
if self.current_transfer_id == transfer_id:
|
||||
self.report_error(f"Pull operation failed: {e}")
|
||||
finally:
|
||||
self.enable_controls()
|
||||
if self.current_transfer_id == transfer_id:
|
||||
self.enable_controls()
|
||||
|
||||
def _push_thread(self, local_path: str, remote_path: str):
|
||||
def _push_thread(self, local_path: str, remote_path: str, transfer_id: int):
|
||||
"""Thread function for push operations."""
|
||||
try:
|
||||
# Check if this transfer is still current
|
||||
if self.current_transfer_id != transfer_id:
|
||||
return
|
||||
|
||||
success = self.adb_manager.push_folder(local_path, remote_path)
|
||||
if success:
|
||||
if success and self.current_transfer_id == transfer_id:
|
||||
self.show_disable_debugging_reminder()
|
||||
except Exception as e:
|
||||
self.report_error(f"Push operation failed: {e}")
|
||||
if self.current_transfer_id == transfer_id:
|
||||
self.report_error(f"Push operation failed: {e}")
|
||||
finally:
|
||||
self.enable_controls()
|
||||
if self.current_transfer_id == transfer_id:
|
||||
self.enable_controls()
|
||||
|
||||
def update_progress(self, percentage: int):
|
||||
"""Update the progress bar."""
|
||||
"""Update the progress bar (thread-safe)."""
|
||||
|
||||
# Schedule UI update on main thread using a proper closure
|
||||
def update_ui():
|
||||
self._update_progress_ui(percentage)
|
||||
|
||||
self.after(0, update_ui)
|
||||
|
||||
def _update_progress_ui(self, percentage: int):
|
||||
"""Internal method to update progress bar on main thread."""
|
||||
self.progress["value"] = percentage
|
||||
self.update_idletasks()
|
||||
|
||||
def set_status(self, message: str):
|
||||
"""Update the status label."""
|
||||
"""Update the status label (thread-safe)."""
|
||||
|
||||
# Schedule UI update on main thread using a proper closure
|
||||
def update_ui():
|
||||
self._set_status_ui(message)
|
||||
|
||||
self.after(0, update_ui)
|
||||
|
||||
def _set_status_ui(self, message: str):
|
||||
"""Internal method to update status on main thread."""
|
||||
self.status_label.config(text=f"Status: {message}")
|
||||
self.update_idletasks()
|
||||
|
||||
def report_error(self, message: str):
|
||||
"""Report an error to the user."""
|
||||
"""Report an error to the user (thread-safe)."""
|
||||
# Schedule UI update on main thread
|
||||
self.after(0, lambda: self._report_error_ui(message))
|
||||
|
||||
def _report_error_ui(self, message: str):
|
||||
"""Internal method to report error on main thread."""
|
||||
self.status_label.config(text=f"Error: {message}")
|
||||
messagebox.showerror("Error", message)
|
||||
self.enable_controls()
|
||||
|
||||
Reference in New Issue
Block a user