Files
traccar_animation/widgets/pause_edit_popup.py
2025-06-07 21:08:23 +03:00

329 lines
14 KiB
Python

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:
thumb_path = os.path.join(pause_img_folder, fname)
# Create a Button for the row
btn = Button(
size_hint_y=None,
height=60,
background_normal='',
background_color=(0.18, 0.18, 0.22, 1),
color=(1,1,1,1)
)
# Layout for image and label inside the button
box = BoxLayout(orientation='horizontal', spacing=8, padding=4)
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)))
box.add_widget(img_widget)
box.add_widget(label)
btn.add_widget(box)
def make_on_release(btn, fname):
def on_release(instance):
if fname in selected_files:
selected_files.remove(fname)
btn.background_color = (0.18, 0.18, 0.22, 1)
else:
selected_files.add(fname)
btn.background_color = (0.8, 0.1, 0.1, 1)
return on_release
btn.bind(on_release=make_on_release(btn, fname))
file_widgets.append(btn)
file_list_box.add_widget(btn)
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()