Fix image editing bug: ensure edits persist and upload correctly
Critical fixes for image editing workflow: 1. Keep local edited files as backup (don't delete after server upload) - Server may not process upload immediately - Keeps edits safe locally in case server fails - Prevents loss of edited images 2. Include original filename in metadata sent to server - Server needs to know which file was edited - Allows proper tracking and versioning 3. Improved error logging for server upload - Now logs detailed errors (404, 401, timeout, connection) - Shows clear messages when server doesn't support endpoint - Helps diagnose why edits aren't syncing to server 4. Better user feedback during save - Shows 'Saved to device' status first - Then 'Upload in progress' to show server sync happening - Clarifies local vs server save status Bug symptoms fixed: - Edited images now persist locally after restart - Server upload now sends correct file information - Clear error messages if server upload fails - User understands 'local save' vs 'server sync' steps
This commit is contained in:
+71
-40
@@ -341,10 +341,14 @@ class EditPopup(Popup):
|
||||
|
||||
# NOW show saving popup AFTER everything is done
|
||||
def show_saving_and_dismiss(dt):
|
||||
# Create label with background
|
||||
# Create label with background showing detailed save status
|
||||
save_msg = (
|
||||
'Saved locally!\n'
|
||||
'Uploading to server...'
|
||||
)
|
||||
save_label = Label(
|
||||
text='Saved! Reloading player...',
|
||||
font_size='36sp',
|
||||
text=save_msg,
|
||||
font_size='24sp',
|
||||
color=(1, 1, 1, 1),
|
||||
bold=True
|
||||
)
|
||||
@@ -352,7 +356,7 @@ class EditPopup(Popup):
|
||||
saving_popup = Popup(
|
||||
title='',
|
||||
content=save_label,
|
||||
size_hint=(0.8, 0.3),
|
||||
size_hint=(0.85, 0.4),
|
||||
auto_dismiss=False,
|
||||
separator_height=0,
|
||||
background_color=(0.2, 0.7, 0.2, 0.95) # Green background
|
||||
@@ -360,13 +364,23 @@ class EditPopup(Popup):
|
||||
saving_popup.open()
|
||||
Logger.info("EditPopup: Saving confirmation popup opened")
|
||||
|
||||
# Dismiss both popups after 2 seconds
|
||||
# Update message after 3 seconds to show upload is happening
|
||||
def update_message(dt):
|
||||
if saving_popup:
|
||||
save_label.text = (
|
||||
'✓ Saved to device\n'
|
||||
'Upload in progress...'
|
||||
)
|
||||
|
||||
Clock.schedule_once(update_message, 3.0)
|
||||
|
||||
# Dismiss both popups after 4 seconds
|
||||
def dismiss_all(dt):
|
||||
saving_popup.dismiss()
|
||||
Logger.info(f"EditPopup: Dismissing to resume playback...")
|
||||
self.dismiss()
|
||||
|
||||
Clock.schedule_once(dismiss_all, 2.0)
|
||||
Clock.schedule_once(dismiss_all, 4.0)
|
||||
|
||||
# Small delay to ensure UI is ready, then show popup
|
||||
Clock.schedule_once(show_saving_and_dismiss, 0.1)
|
||||
@@ -420,7 +434,8 @@ class EditPopup(Popup):
|
||||
# Get authenticated instance
|
||||
auth = get_auth_instance()
|
||||
if not auth or not auth.is_authenticated():
|
||||
Logger.warning("EditPopup: Cannot upload - not authenticated (server will not receive edited media)")
|
||||
Logger.warning("EditPopup: Cannot upload - not authenticated (edited media saved locally only)")
|
||||
Logger.warning("EditPopup: Server will NOT receive this edit")
|
||||
return False
|
||||
|
||||
server_url = auth.auth_data.get('server_url')
|
||||
@@ -434,60 +449,76 @@ class EditPopup(Popup):
|
||||
with open(metadata_path, 'r') as meta_file:
|
||||
metadata = json.load(meta_file)
|
||||
|
||||
# Prepare upload URL
|
||||
# Prepare upload URL - send to the original file endpoint
|
||||
upload_url = f"{server_url}/api/player-edit-media"
|
||||
headers = {'Authorization': f'Bearer {auth_code}'}
|
||||
|
||||
# Add the original filename to metadata so server knows which file was edited
|
||||
metadata['original_filename'] = os.path.basename(metadata['original_path'])
|
||||
|
||||
# Prepare file and data for upload
|
||||
with open(image_path, 'rb') as img_file:
|
||||
files = {
|
||||
'image_file': (metadata['new_name'], img_file, 'image/jpeg')
|
||||
'image_file': (metadata['original_filename'], img_file, 'image/jpeg')
|
||||
}
|
||||
|
||||
# Send metadata as JSON string in form data
|
||||
data = {
|
||||
'metadata': json.dumps(metadata)
|
||||
'metadata': json.dumps(metadata),
|
||||
'original_file': metadata['original_filename']
|
||||
}
|
||||
|
||||
Logger.info(f"EditPopup: Uploading edited media to {upload_url}")
|
||||
response = requests.post(upload_url, headers=headers, files=files, data=data, timeout=30)
|
||||
Logger.info(f"EditPopup: 📤 Uploading edited media to {upload_url}")
|
||||
Logger.info(f"EditPopup: - Original file: {metadata['original_filename']}")
|
||||
Logger.info(f"EditPopup: - Edited image: {image_path}")
|
||||
Logger.info(f"EditPopup: - Metadata: {metadata_path}")
|
||||
|
||||
if response.status_code == 200:
|
||||
response_data = response.json()
|
||||
Logger.info(f"EditPopup: ✅ Successfully uploaded edited media to server: {response_data}")
|
||||
try:
|
||||
response = requests.post(upload_url, headers=headers, files=files, data=data, timeout=30)
|
||||
|
||||
# Delete local files after successful upload
|
||||
try:
|
||||
if os.path.exists(image_path):
|
||||
os.remove(image_path)
|
||||
Logger.info(f"EditPopup: Deleted local image file: {os.path.basename(image_path)}")
|
||||
if response.status_code == 200:
|
||||
response_data = response.json()
|
||||
Logger.info(f"EditPopup: ✅ Successfully uploaded edited media to server")
|
||||
Logger.info(f"EditPopup: Server response: {response_data}")
|
||||
|
||||
if os.path.exists(metadata_path):
|
||||
os.remove(metadata_path)
|
||||
Logger.info(f"EditPopup: Deleted local metadata file: {os.path.basename(metadata_path)}")
|
||||
# DO NOT delete local files - keep them as backup
|
||||
# In case the server doesn't process them, we want to keep the edits locally
|
||||
Logger.info(f"EditPopup: ✓ Keeping local edited files as backup:")
|
||||
Logger.info(f" - Image: {image_path}")
|
||||
Logger.info(f" - Metadata: {metadata_path}")
|
||||
|
||||
Logger.info("EditPopup: ✅ Local edited files cleaned up after successful upload")
|
||||
except Exception as e:
|
||||
Logger.warning(f"EditPopup: Could not delete local files: {e}")
|
||||
|
||||
return True
|
||||
elif response.status_code == 404:
|
||||
Logger.warning("EditPopup: ⚠️ Upload endpoint not available on server (404) - edited media saved locally only")
|
||||
return True
|
||||
elif response.status_code == 404:
|
||||
Logger.error("EditPopup: ❌ Upload endpoint not found on server (404)")
|
||||
Logger.error("EditPopup: Server may not support edited media uploads")
|
||||
Logger.error("EditPopup: Edited media is saved locally only")
|
||||
return False
|
||||
elif response.status_code == 401:
|
||||
Logger.error("EditPopup: ❌ Authentication failed (401) - check auth credentials")
|
||||
Logger.error("EditPopup: Edited media is saved locally only")
|
||||
return False
|
||||
else:
|
||||
Logger.error(f"EditPopup: ❌ Upload failed with status {response.status_code}")
|
||||
Logger.error(f"EditPopup: Response: {response.text}")
|
||||
Logger.error("EditPopup: Edited media is saved locally only")
|
||||
return False
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
Logger.error("EditPopup: ❌ Upload timed out after 30 seconds")
|
||||
Logger.error("EditPopup: Check network connection")
|
||||
Logger.error("EditPopup: Edited media is saved locally only")
|
||||
return False
|
||||
else:
|
||||
Logger.warning(f"EditPopup: ⚠️ Upload failed with status {response.status_code} - edited media saved locally only")
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
Logger.error(f"EditPopup: ❌ Cannot connect to server: {e}")
|
||||
Logger.error("EditPopup: Check server URL and network connection")
|
||||
Logger.error("EditPopup: Edited media is saved locally only")
|
||||
return False
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
Logger.warning("EditPopup: ⚠️ Upload timed out - edited media saved locally only")
|
||||
return False
|
||||
except requests.exceptions.ConnectionError:
|
||||
Logger.warning("EditPopup: ⚠️ Cannot connect to server - edited media saved locally only")
|
||||
return False
|
||||
except Exception as e:
|
||||
Logger.warning(f"EditPopup: ⚠️ Upload failed: {e} - edited media saved locally only")
|
||||
Logger.error(f"EditPopup: ❌ Unexpected error during upload: {e}")
|
||||
import traceback
|
||||
Logger.debug(f"EditPopup: Upload traceback: {traceback.format_exc()}")
|
||||
Logger.error(f"EditPopup: Traceback: {traceback.format_exc()}")
|
||||
Logger.error("EditPopup: Edited media is saved locally only")
|
||||
return False
|
||||
|
||||
def close_without_saving(self, instance):
|
||||
|
||||
Reference in New Issue
Block a user