editihg ui

This commit is contained in:
2025-06-08 11:45:47 +03:00
parent 6cac2381cd
commit 069227abf9
8 changed files with 151 additions and 225 deletions

View File

@@ -4,3 +4,4 @@ kiwy-garden
folium folium
selenium selenium
pillow pillow
geopy

View File

@@ -1 +1 @@
gAAAAABoRIBdnJ4AJNsIIQDrg28lJYh3WTX0jucvpvIuryz4n8sdPxEkR41zu8vmDBs-R6CRWBXnN6JZk4_-E71UVMRmYNlc3mELmowS8BupUW59BuruBiJgV4iepoWnpyj4NuiBnJjG gAAAAABoRU2S6uCg_q0O-jiLHQfi6s7Kw865wYdFsj5SlEo5YG292sdSlabVYW5sEVm8WQgz1iYCyql5F0ODiDKUlXWGeMe3TAk8AyEwWJwPqgZhyWkwDcbRHtE60ip-grWPNHQT4qG_

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 877 KiB

After

Width:  |  Height:  |  Size: 877 KiB

View File

@@ -4,10 +4,12 @@ from kivy.uix.label import Label
from kivy.uix.button import Button from kivy.uix.button import Button
from kivy.uix.textinput import TextInput from kivy.uix.textinput import TextInput
from kivy.uix.filechooser import FileChooserIconView from kivy.uix.filechooser import FileChooserIconView
from kivy.graphics import Color, Rectangle from kivy.uix.widget import Widget
from kivy.graphics import Color, Rectangle, Line
import os import os
import json import json
import shutil import shutil
from geopy.geocoders import Nominatim
def open_pauses_popup(screen_instance, project_name, RESOURCES_FOLDER, on_save_callback=None): def open_pauses_popup(screen_instance, project_name, RESOURCES_FOLDER, on_save_callback=None):
project_folder = os.path.join(RESOURCES_FOLDER, "projects", project_name) project_folder = os.path.join(RESOURCES_FOLDER, "projects", project_name)
@@ -29,290 +31,213 @@ def open_pauses_popup(screen_instance, project_name, RESOURCES_FOLDER, on_save_c
pauses = json.load(f) pauses = json.load(f)
def suggest_location_name(lat, lon): def suggest_location_name(lat, lon):
return f"Lat {round(lat, 4)}, Lon {round(lon, 4)}" try:
geolocator = Nominatim(user_agent="traccar_animation")
location = geolocator.reverse((lat, lon), exactly_one=True, radius=50, timeout=10)
if location and location.address:
return location.address
else:
return "Unknown place"
except Exception as e:
return "Unknown place"
for idx, pause in enumerate(pauses): for idx, pause in enumerate(pauses):
pause_box = BoxLayout(orientation='vertical', spacing=10, padding=[14, 12, 14, 12], size_hint_y=None, height=220) # Main vertical box for this pause
pause_box = BoxLayout(
orientation='vertical',
spacing=12, # <-- Increase this value for more space between children
padding=[6, 0, 6, 4],
size_hint_y=None,
height=170
)
with pause_box.canvas.before: with pause_box.canvas.before:
Color(0.20, 0.20, 0.25, 1) Color(0.20, 0.20, 0.25, 1)
pause_box.bg_rect = Rectangle(pos=pause_box.pos, size=pause_box.size) 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), 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)) size=lambda inst, val: setattr(pause_box.bg_rect, 'size', inst.size))
# Title row # --- Row 1: Name label ---
name_row = BoxLayout(orientation='vertical', size_hint_y=None, height=20, padding=[0,0,0,0])
title_label = Label( title_label = Label(
text=f"[b]Pause {idx+1}[/b]", text=f"[b]Pause {idx+1}[/b]",
markup=True, markup=True,
font_size=18, font_size=15,
color=(1, 1, 1, 1), color=(1, 1, 1, 1),
size_hint_y=None, size_hint_y=None,
height=28, height=20,
halign="left", halign="center",
valign="middle" valign="middle"
) )
def update_title_size(instance, value): def update_title_size(instance, value):
instance.text_size = (instance.width, None) instance.text_size = (instance.width, None)
title_label.bind(width=update_title_size) title_label.bind(width=update_title_size)
pause_box.add_widget(title_label) name_row.add_widget(title_label)
pause_box.add_widget(name_row)
# Info row: Detected location and edit button # --- Row 2: Location group ---
info_box = BoxLayout(orientation='horizontal', spacing=8, size_hint_y=None, height=32) place_group = BoxLayout(orientation='vertical', spacing=1, padding=2, size_hint_y=None, height=34)
location_label = Label( with place_group.canvas.before:
text=pause.get('name', suggest_location_name(pause["location"]["latitude"], pause["location"]["longitude"])), Color(0.3, 0.5, 0.9, 0.3)
font_size=15, place_group.border_rect = Rectangle(pos=place_group.pos, size=place_group.size)
color=(0.8, 0.8, 0.8, 1), Color(0.3, 0.5, 0.9, 1)
size_hint_x=0.7, place_group.border_line = Line(rectangle=(place_group.x, place_group.y, place_group.width, place_group.height), width=1)
def update_place_group(instance, value):
place_group.border_rect.pos = place_group.pos
place_group.border_rect.size = place_group.size
place_group.border_line.rectangle = (place_group.x, place_group.y, place_group.width, place_group.height)
place_group.bind(pos=update_place_group, size=update_place_group)
suggested_place = suggest_location_name(pause["location"]["latitude"], pause["location"]["longitude"])
suggested_label = Label(
text=f"Suggested place: {suggested_place}",
font_size=9,
color=(0.7, 0.9, 1, 1),
size_hint_y=None,
height=12,
halign="left", halign="left",
valign="middle" valign="middle"
) )
location_label.bind(width=update_title_size) suggested_label.bind(width=update_title_size)
place_group.add_widget(suggested_label)
personalized_label = Label(
text=f"Personalized name place: {pause.get('name', '')}",
font_size=9,
color=(1, 1, 1, 1),
size_hint_y=None,
height=12,
halign="left",
valign="middle"
)
personalized_label.bind(width=update_title_size)
edit_loc_btn = Button( edit_loc_btn = Button(
text="Edit Place", text="Edit Place",
size_hint_x=0.3, size_hint_x=None,
font_size=14, width=70,
font_size=10,
background_color=(0.341, 0.235, 0.980, 1), background_color=(0.341, 0.235, 0.980, 1),
color=(1, 1, 1, 1) color=(1, 1, 1, 1),
height=16
) )
def open_edit_popup(instance, pause=pause, location_label=location_label): def open_edit_popup(instance, pause=pause, personalized_label=personalized_label):
edit_layout = BoxLayout(orientation='vertical', spacing=10, padding=10) edit_layout = BoxLayout(orientation='vertical', spacing=4, padding=4)
with edit_layout.canvas.before: with edit_layout.canvas.before:
Color(0.13, 0.13, 0.16, 1) Color(0.13, 0.13, 0.16, 1)
edit_layout.bg_rect = Rectangle(pos=edit_layout.pos, size=edit_layout.size) 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), 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)) 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)) input_field = TextInput(text=pause.get('name', ''), multiline=False, background_color=(0.18,0.18,0.22,1), foreground_color=(1,1,1,1), font_size=10, height=18)
save_btn = Button(text="Save", background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1)) save_btn = Button(text="Save", background_color=(0.341, 0.235, 0.980, 1), color=(1,1,1,1), height=18, font_size=10)
edit_layout.add_widget(Label(text="Edit Place Name:", color=(1,1,1,1))) edit_layout.add_widget(Label(text="Edit Place Name:", color=(1,1,1,1), font_size=10, height=12, size_hint_y=None))
edit_layout.add_widget(input_field) edit_layout.add_widget(input_field)
edit_layout.add_widget(save_btn) edit_layout.add_widget(save_btn)
edit_popup = Popup(title="Edit Place", content=edit_layout, size_hint=(0.7, None), size=(0, 200)) edit_popup = Popup(title="Edit Place", content=edit_layout, size_hint=(0.7, None), size=(0, 80))
def save_name(instance): def save_name(instance):
pause['name'] = input_field.text pause['name'] = input_field.text
location_label.text = input_field.text personalized_label.text = f"Personalized name place: {input_field.text}"
edit_popup.dismiss() edit_popup.dismiss()
save_btn.bind(on_press=save_name) save_btn.bind(on_press=save_name)
edit_popup.open() edit_popup.open()
edit_loc_btn.bind(on_press=open_edit_popup) 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 personalized_row = BoxLayout(orientation='horizontal', spacing=2, size_hint_y=None, height=14)
personalized_row.add_widget(personalized_label)
personalized_row.add_widget(edit_loc_btn)
place_group.add_widget(personalized_row)
pause_box.add_widget(place_group)
# --- Row 3: Pictures group ---
photo_group = BoxLayout(orientation='vertical', spacing=1, padding=2, size_hint_y=None, height=38)
with photo_group.canvas.before:
Color(0.2, 0.8, 0.5, 0.2)
photo_group.border_rect = Rectangle(pos=photo_group.pos, size=photo_group.size)
Color(0.2, 0.8, 0.5, 1)
photo_group.border_line = Line(rectangle=(photo_group.x, photo_group.y, photo_group.width, photo_group.height), width=1)
def update_photo_group(instance, value):
photo_group.border_rect.pos = photo_group.pos
photo_group.border_rect.size = photo_group.size
photo_group.border_line.rectangle = (photo_group.x, photo_group.y, photo_group.width, photo_group.height)
photo_group.bind(pos=update_photo_group, size=update_photo_group)
pause_img_folder = os.path.join(project_folder, f"pause_{idx+1}") pause_img_folder = os.path.join(project_folder, f"pause_{idx+1}")
os.makedirs(pause_img_folder, exist_ok=True) 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))] 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: if img_list:
photo_count_label = Label( photo_count_label = Label(
text=f"You have {len(img_list)} photo(s) for this pause.", text=f"You have {len(img_list)} photo(s) for this pause.",
font_size=13, font_size=9,
color=(0.8, 0.8, 0.8, 1), color=(0.8, 0.8, 0.8, 1),
size_hint_y=None, size_hint_y=None,
height=22 height=12
) )
photo_list_label = Label( photo_list_label = Label(
text=", ".join(img_list), text=", ".join(img_list),
font_size=12, font_size=8,
color=(0.7, 0.7, 0.7, 1), color=(0.7, 0.7, 0.7, 1),
size_hint_y=None, size_hint_y=None,
height=18 height=10
) )
else: else:
photo_count_label = Label( photo_count_label = Label(
text="No photos are set for this pause.", text="No photos are set for this pause.",
font_size=13, font_size=9,
color=(0.8, 0.8, 0.8, 1), color=(0.8, 0.8, 0.8, 1),
size_hint_y=None, size_hint_y=None,
height=22 height=12
) )
photo_list_label = Label( photo_list_label = Label(
text="", text="",
font_size=12, font_size=8,
color=(0.7, 0.7, 0.7, 1), color=(0.7, 0.7, 0.7, 1),
size_hint_y=None, size_hint_y=None,
height=18 height=10
) )
pause_box.add_widget(photo_count_label) photo_group.add_widget(photo_count_label)
pause_box.add_widget(photo_list_label) photo_group.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( browse_btn = Button(
text="Browse", text="Browse",
size_hint_x=0.33, size_hint_x=0.33,
font_size=14, size_hint_y=None,
height=16,
font_size=10,
background_color=(0.341, 0.235, 0.980, 1), background_color=(0.341, 0.235, 0.980, 1),
color=(1,1,1,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( delete_btn = Button(
text="Delete", text="Delete",
size_hint_x=0.34, size_hint_x=0.34,
font_size=14, size_hint_y=None,
height=16,
font_size=10,
background_color=(0.8, 0.1, 0.1, 1), background_color=(0.8, 0.1, 0.1, 1),
color=(1,1,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( save_pause_btn = Button(
text="Save Pause", text="Save Pause",
size_hint_x=0.33, size_hint_x=0.33,
font_size=14, size_hint_y=None,
height=16,
font_size=10,
background_color=(0.341, 0.235, 0.980, 1), background_color=(0.341, 0.235, 0.980, 1),
color=(1,1,1,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 = BoxLayout(orientation='horizontal', spacing=4, size_hint_y=None, height=18)
bottom_box.add_widget(browse_btn) bottom_box.add_widget(browse_btn)
bottom_box.add_widget(delete_btn) bottom_box.add_widget(delete_btn)
bottom_box.add_widget(save_pause_btn) bottom_box.add_widget(save_pause_btn)
pause_box.add_widget(bottom_box) photo_group.add_widget(bottom_box)
pause_box.add_widget(photo_group)
# Separator line # Separator line
from kivy.uix.widget import Widget sep = Widget(size_hint_y=None, height=1)
from kivy.graphics import Line
sep = Widget(size_hint_y=None, height=2)
with sep.canvas: with sep.canvas:
Color(0.25, 0.25, 0.30, 1) Color(0.25, 0.25, 0.30, 1)
Line(points=[0, 1, 1000, 1], width=2) Line(points=[0, 1, 1000, 1], width=1)
pause_box.add_widget(sep) pause_box.add_widget(sep)
layout.add_widget(pause_box) layout.add_widget(pause_box)