from kivy.uix.popup import Popup from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.textinput import TextInput from kivy.uix.filechooser import FileChooserIconView from kivy.graphics import Color, Rectangle import os import json import shutil def open_pauses_popup(screen_instance, project_name, RESOURCES_FOLDER, on_save_callback=None): project_folder = os.path.join(RESOURCES_FOLDER, "projects", project_name) pauses_path = os.path.join(project_folder, "pauses.json") # Main layout with dark background layout = BoxLayout(orientation='vertical', spacing=14, padding=14) with layout.canvas.before: Color(0.13, 0.13, 0.16, 1) layout.bg_rect = Rectangle(pos=layout.pos, size=layout.size) def update_bg_rect(instance, value): layout.bg_rect.pos = layout.pos layout.bg_rect.size = layout.size layout.bind(pos=update_bg_rect, size=update_bg_rect) pauses = [] if os.path.exists(pauses_path): with open(pauses_path, "r") as f: pauses = json.load(f) def suggest_location_name(lat, lon): return f"Lat {round(lat, 4)}, Lon {round(lon, 4)}" for idx, pause in enumerate(pauses): pause_box = BoxLayout(orientation='vertical', spacing=10, padding=[14, 12, 14, 12], size_hint_y=None, height=220) with pause_box.canvas.before: Color(0.20, 0.20, 0.25, 1) pause_box.bg_rect = Rectangle(pos=pause_box.pos, size=pause_box.size) pause_box.bind(pos=lambda inst, val: setattr(pause_box.bg_rect, 'pos', inst.pos), size=lambda inst, val: setattr(pause_box.bg_rect, 'size', inst.size)) # Title row title_label = Label( text=f"[b]Pause {idx+1}[/b]", markup=True, font_size=18, color=(1, 1, 1, 1), size_hint_y=None, height=28, halign="left", valign="middle" ) def update_title_size(instance, value): instance.text_size = (instance.width, None) title_label.bind(width=update_title_size) pause_box.add_widget(title_label) # Info row: Detected location and edit button info_box = BoxLayout(orientation='horizontal', spacing=8, size_hint_y=None, height=32) location_label = Label( text=pause.get('name', suggest_location_name(pause["location"]["latitude"], pause["location"]["longitude"])), font_size=15, color=(0.8, 0.8, 0.8, 1), size_hint_x=0.7, halign="left", valign="middle" ) location_label.bind(width=update_title_size) edit_loc_btn = Button( text="Edit Place", size_hint_x=0.3, font_size=14, background_color=(0.341, 0.235, 0.980, 1), color=(1, 1, 1, 1) ) def open_edit_popup(instance, pause=pause, location_label=location_label): edit_layout = BoxLayout(orientation='vertical', spacing=10, padding=10) with edit_layout.canvas.before: Color(0.13, 0.13, 0.16, 1) edit_layout.bg_rect = Rectangle(pos=edit_layout.pos, size=edit_layout.size) edit_layout.bind(pos=lambda inst, val: setattr(edit_layout.bg_rect, 'pos', inst.pos), size=lambda inst, val: setattr(edit_layout.bg_rect, 'size', inst.size)) input_field = TextInput(text=pause.get('name', ''), multiline=False, background_color=(0.18,0.18,0.22,1), foreground_color=(1,1,1,1)) save_btn = Button(text="Save", background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1)) edit_layout.add_widget(Label(text="Edit Place Name:", color=(1,1,1,1))) edit_layout.add_widget(input_field) edit_layout.add_widget(save_btn) edit_popup = Popup(title="Edit Place", content=edit_layout, size_hint=(0.7, None), size=(0, 200)) def save_name(instance): pause['name'] = input_field.text location_label.text = input_field.text edit_popup.dismiss() save_btn.bind(on_press=save_name) edit_popup.open() edit_loc_btn.bind(on_press=open_edit_popup) info_box.add_widget(location_label) info_box.add_widget(edit_loc_btn) pause_box.add_widget(info_box) # Pictures folder and list pause_img_folder = os.path.join(project_folder, f"pause_{idx+1}") os.makedirs(pause_img_folder, exist_ok=True) img_list = [f for f in os.listdir(pause_img_folder) if os.path.isfile(os.path.join(pause_img_folder, f))] # Photo count label if img_list: photo_count_label = Label( text=f"You have {len(img_list)} photo(s) for this pause.", font_size=13, color=(0.8, 0.8, 0.8, 1), size_hint_y=None, height=22 ) photo_list_label = Label( text=", ".join(img_list), font_size=12, color=(0.7, 0.7, 0.7, 1), size_hint_y=None, height=18 ) else: photo_count_label = Label( text="No photos are set for this pause.", font_size=13, color=(0.8, 0.8, 0.8, 1), size_hint_y=None, height=22 ) photo_list_label = Label( text="", font_size=12, color=(0.7, 0.7, 0.7, 1), size_hint_y=None, height=18 ) pause_box.add_widget(photo_count_label) pause_box.add_widget(photo_list_label) # Bottom row: Browse, Delete, and Save Pause bottom_box = BoxLayout(orientation='horizontal', spacing=8, size_hint_y=None, height=36) browse_btn = Button( text="Browse", size_hint_x=0.33, font_size=14, background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1) ) def open_filechooser(instance, pause_img_folder=pause_img_folder, photo_count_label=photo_count_label, photo_list_label=photo_list_label): chooser_layout = BoxLayout(orientation='vertical', spacing=10, padding=10) with chooser_layout.canvas.before: Color(0.13, 0.13, 0.16, 1) chooser_layout.bg_rect = Rectangle(pos=chooser_layout.pos, size=chooser_layout.size) chooser_layout.bind(pos=lambda inst, val: setattr(chooser_layout.bg_rect, 'pos', inst.pos), size=lambda inst, val: setattr(chooser_layout.bg_rect, 'size', inst.size)) chooser = FileChooserIconView(path=".", filters=['*.png', '*.jpg', '*.jpeg'], multiselect=True) upload_btn = Button(text="Upload Selected", size_hint_y=None, height=40, background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1)) chooser_layout.add_widget(chooser) chooser_layout.add_widget(upload_btn) popup = Popup(title="Select Images", content=chooser_layout, size_hint=(0.9, 0.9)) def upload_files(instance): selections = chooser.selection if selections: for selected_file in selections: dest = os.path.join(pause_img_folder, os.path.basename(selected_file)) shutil.copy(selected_file, dest) img_list = [f for f in os.listdir(pause_img_folder) if os.path.isfile(os.path.join(pause_img_folder, f))] if img_list: photo_count_label.text = f"You have {len(img_list)} photo(s) for this pause." photo_list_label.text = ", ".join(img_list) else: photo_count_label.text = "No photos are set for this pause." photo_list_label.text = "" popup.dismiss() upload_btn.bind(on_press=upload_files) popup.open() browse_btn.bind(on_press=open_filechooser) # --- Delete Button --- delete_btn = Button( text="Delete", size_hint_x=0.34, font_size=14, background_color=(0.8, 0.1, 0.1, 1), color=(1,1,1,1) ) def open_delete_popup(instance, pause_img_folder=pause_img_folder, photo_count_label=photo_count_label, photo_list_label=photo_list_label): from kivy.uix.scrollview import ScrollView from kivy.uix.image import Image as KivyImage from kivy.uix.widget import Widget delete_layout = BoxLayout(orientation='vertical', spacing=10, padding=10) files = [f for f in os.listdir(pause_img_folder) if f.lower().endswith(('.jpg', '.jpeg', '.png')) and os.path.isfile(os.path.join(pause_img_folder, f)) ] file_list_box = BoxLayout(orientation='vertical', spacing=8, size_hint_y=None) file_list_box.bind(minimum_height=file_list_box.setter('height')) selected_files = set() file_widgets = [] for fname in files: row = BoxLayout(orientation='horizontal', size_hint_y=None, height=60, padding=4, spacing=8) thumb_path = os.path.join(pause_img_folder, fname) img_widget = KivyImage(source=thumb_path, size_hint_x=None, width=60, allow_stretch=True, keep_ratio=True) label = Label(text=fname, color=(1,1,1,1), size_hint_x=1, halign="left", valign="middle") label.bind(size=lambda inst, val: setattr(inst, 'text_size', (inst.width, None))) row.add_widget(img_widget) row.add_widget(label) # Background color for selection with row.canvas.before: from kivy.graphics import Color, Rectangle row.bg_color = Color(0.18, 0.18, 0.22, 1) row.bg_rect = Rectangle(pos=row.pos, size=row.size) def update_bg(instance, value): row.bg_rect.pos = row.pos row.bg_rect.size = row.size row.bind(pos=update_bg, size=update_bg) # Selection logic def make_on_touch_down(row, fname): def on_touch_down(instance, touch): if row.collide_point(*touch.pos): if fname in selected_files: selected_files.remove(fname) row.bg_color.rgba = (0.18, 0.18, 0.22, 1) else: selected_files.add(fname) row.bg_color.rgba = (0.8, 0.1, 0.1, 1) return False return on_touch_down row.bind(on_touch_down=make_on_touch_down(row, fname)) file_widgets.append(row) file_list_box.add_widget(row) scroll = ScrollView(size_hint=(1, 0.7)) scroll.add_widget(file_list_box) delete_file_btn = Button( text="Delete Selected", size_hint_y=None, height=40, background_color=(0.8,0.1,0.1,1), color=(1,1,1,1) ) close_btn = Button( text="Close", size_hint_y=None, height=40, background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1) ) def delete_selected(instance): for fname in list(selected_files): fpath = os.path.join(pause_img_folder, fname) if os.path.exists(fpath): os.remove(fpath) # Update labels in main popup img_list = [f for f in os.listdir(pause_img_folder) if os.path.isfile(os.path.join(pause_img_folder, f))] if img_list: photo_count_label.text = f"You have {len(img_list)} photo(s) for this pause." photo_list_label.text = ", ".join(img_list) else: photo_count_label.text = "No photos are set for this pause." photo_list_label.text = "" popup.dismiss() delete_file_btn.bind(on_press=delete_selected) close_btn.bind(on_press=lambda x: popup.dismiss()) delete_layout.add_widget(Label(text="Tap to select images to delete:", color=(1,1,1,1), size_hint_y=None, height=30)) delete_layout.add_widget(scroll) delete_layout.add_widget(delete_file_btn) delete_layout.add_widget(close_btn) popup = Popup( title="Delete Photo(s)", content=delete_layout, size_hint=(0.8, 0.8), background_color=(0.13, 0.13, 0.16, 1) ) popup.open() delete_btn.bind(on_press=open_delete_popup) save_pause_btn = Button( text="Save Pause", size_hint_x=0.33, font_size=14, background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1) ) def save_pause(instance, pause=pause): with open(pauses_path, "w") as f: json.dump(pauses, f, indent=2) save_pause_btn.bind(on_press=save_pause) bottom_box.add_widget(browse_btn) bottom_box.add_widget(delete_btn) bottom_box.add_widget(save_pause_btn) pause_box.add_widget(bottom_box) # Separator line from kivy.uix.widget import Widget from kivy.graphics import Line sep = Widget(size_hint_y=None, height=2) with sep.canvas: Color(0.25, 0.25, 0.30, 1) Line(points=[0, 1, 1000, 1], width=2) pause_box.add_widget(sep) layout.add_widget(pause_box) # Save all and close save_all_btn = Button(text="Save All & Close", size_hint_y=None, height=44, background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1)) def save_all(instance): with open(pauses_path, "w") as f: json.dump(pauses, f, indent=2) if on_save_callback: on_save_callback() popup.dismiss() save_all_btn.bind(on_press=save_all) layout.add_widget(save_all_btn) popup = Popup(title="Edit Pauses", content=layout, size_hint=(0.95, 0.95), background_color=(0.13, 0.13, 0.16, 1)) popup.open()