mirror of
https://github.com/OMGeeky/Kivy-Shopping-List.git
synced 2026-02-23 15:38:26 +01:00
Save on change & Sort & fix dismiss error
Co-Authored-By: fadam2104 <119661061+fadam2104@users.noreply.github.com> Co-Authored-By: tomw41 <118167823+tomw41@users.noreply.github.com> Co-Authored-By: Jan <49588429+MapManagement@users.noreply.github.com>
This commit is contained in:
171
src/main.py
171
src/main.py
@@ -38,12 +38,34 @@ class ShoppingEntry(OneLineAvatarIconListItem):
|
||||
|
||||
def __init__(self, text, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.initialized = False
|
||||
self.text = text
|
||||
self.is_checked = False
|
||||
self.initialized = True
|
||||
|
||||
# region events
|
||||
|
||||
def on_is_checked(self, *_):
|
||||
if not self.initialized:
|
||||
return
|
||||
|
||||
list = self.get_shopping_list()
|
||||
if list:
|
||||
list.update_entry(self)
|
||||
|
||||
# endregion
|
||||
def get_shopping_list(self):
|
||||
if not self.initialized:
|
||||
return None
|
||||
if self.parent:
|
||||
return self.parent.parent.parent.parent
|
||||
|
||||
return None
|
||||
|
||||
def delete(self, shopping_entry):
|
||||
self.parent.remove_widget(shopping_entry)
|
||||
list = self.get_shopping_list()
|
||||
if list:
|
||||
list.delete_entry(shopping_entry)
|
||||
|
||||
def edit_popup(self):
|
||||
if self.edit_dialog:
|
||||
@@ -51,11 +73,12 @@ class ShoppingEntry(OneLineAvatarIconListItem):
|
||||
|
||||
buttons = [
|
||||
MDFlatButton(
|
||||
text=self.get_translated("cancel"), on_release=self.close_edit_popup
|
||||
text=self.get_translated("cancel"),
|
||||
on_release=lambda _: self.edit_dialog.dismiss() # type: ignore
|
||||
),
|
||||
MDFlatButton(
|
||||
text=self.get_translated("confirm"),
|
||||
on_release=lambda args: self.save_changes(args),
|
||||
on_release=lambda _: self.save_changes(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -66,9 +89,10 @@ class ShoppingEntry(OneLineAvatarIconListItem):
|
||||
buttons=buttons,
|
||||
)
|
||||
|
||||
self.edit_dialog.on_dismiss = lambda: self.close_edit_popup()
|
||||
self.edit_dialog.open()
|
||||
|
||||
def save_changes(self, *_):
|
||||
def save_changes(self):
|
||||
if self.edit_dialog is None:
|
||||
return
|
||||
|
||||
@@ -79,20 +103,23 @@ class ShoppingEntry(OneLineAvatarIconListItem):
|
||||
|
||||
self.text = changed_text
|
||||
|
||||
self.close_edit_popup()
|
||||
self.edit_dialog.dismiss()
|
||||
list = self.get_shopping_list()
|
||||
if list:
|
||||
list.update_entry(self)
|
||||
|
||||
def get_translated(self, key: str) -> str:
|
||||
settings = AppSettings.get_or_create()
|
||||
return TranslationProvider.get_translated(key, settings.language)
|
||||
|
||||
# *args bzw. *_ ist noetig, da weitere Parameter mitgegeben werden, die aber nicht genutzt werden
|
||||
def close_edit_popup(self, *_):
|
||||
def close_edit_popup(self):
|
||||
if not self.edit_dialog:
|
||||
return
|
||||
|
||||
self.edit_dialog.dismiss()
|
||||
self.edit_dialog = None
|
||||
|
||||
def __str__(self) -> str:
|
||||
return super().__str__() + f"is_checked: {self.is_checked} text: {self.text}"
|
||||
|
||||
class AddDialog(MDBoxLayout):
|
||||
text = StringProperty("")
|
||||
@@ -109,24 +136,15 @@ class AddDialog(MDBoxLayout):
|
||||
class ShoppingEntryScreen(Screen):
|
||||
add_dialog = None
|
||||
entries = ListProperty([])
|
||||
sort_reverse = BooleanProperty(False)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.from_mqtt = False
|
||||
self.initialized = False
|
||||
self.update_from_file()
|
||||
self.initialized = True
|
||||
|
||||
def update_from_file(self):
|
||||
try:
|
||||
entries = read_entries_from_files()
|
||||
except OSError:
|
||||
return
|
||||
|
||||
self.set_entries(entries["entries"])
|
||||
|
||||
def update_from_mqtt(self, msg_dict):
|
||||
self.from_mqtt = True
|
||||
self.entries = msg_dict["entries"]
|
||||
# region events
|
||||
|
||||
def on_bestaetigen(self, *_):
|
||||
if self.add_dialog is None:
|
||||
@@ -139,6 +157,40 @@ class ShoppingEntryScreen(Screen):
|
||||
|
||||
self.add_shopping_entry(text)
|
||||
|
||||
def on_entries(self, *_):
|
||||
print("on_entries called", self)
|
||||
self.set_entries_widgets()
|
||||
|
||||
def on_sort_reverse(self, *_):
|
||||
print("on_sort_reverse", self.sort_reverse)
|
||||
self.entries = self.get_entires()
|
||||
|
||||
# endregion
|
||||
|
||||
# region entries
|
||||
|
||||
# region update entries
|
||||
|
||||
def update_from_file(self):
|
||||
try:
|
||||
entries = read_entries_from_files()
|
||||
except OSError:
|
||||
return
|
||||
|
||||
self.set_entries(entries["entries"])
|
||||
|
||||
def update_from_mqtt(self, msg_dict):
|
||||
self.from_mqtt = True
|
||||
self.set_entries(msg_dict["entries"], from_mqtt=True)
|
||||
|
||||
def update_entry(self, entry: ShoppingEntry):
|
||||
print("update entry called", entry)
|
||||
self.export_entries()
|
||||
|
||||
# endregion
|
||||
|
||||
# region add entry
|
||||
|
||||
def open_add_popup(self):
|
||||
if self.add_dialog:
|
||||
return
|
||||
@@ -172,33 +224,47 @@ class ShoppingEntryScreen(Screen):
|
||||
self.add_dialog = None
|
||||
|
||||
def add_shopping_entry(self, text):
|
||||
self.ids["shopping_list"].add_widget(ShoppingEntry(text=text))
|
||||
entry = ShoppingEntry(text=text)
|
||||
self.ids["shopping_list"].add_widget(entry)
|
||||
self.update_entry(entry)
|
||||
self.close_add_popup()
|
||||
|
||||
def export_entries(self):
|
||||
entries = self.get_entires()
|
||||
entries_dict = {"entries": entries}
|
||||
try:
|
||||
write_entries_to_files(entries_dict)
|
||||
except OSError:
|
||||
return
|
||||
|
||||
# dont push to mqtt if coming from mqtt
|
||||
if not self.from_mqtt:
|
||||
app.mqtt.publish(entries_dict)
|
||||
else:
|
||||
self.from_mqtt = False
|
||||
# endregion
|
||||
|
||||
@mainthread
|
||||
def on_entries(self, *_):
|
||||
print("on_entries called")
|
||||
def set_entries_widgets(self):
|
||||
print("set_entries_widgets", self)
|
||||
self.ids["shopping_list"].clear_widgets()
|
||||
for entry in self.entries:
|
||||
shopping_entry = ShoppingEntry(text=entry["text"])
|
||||
shopping_entry.is_checked = entry["is_checked"] # type: ignore
|
||||
self.ids["shopping_list"].add_widget(shopping_entry)
|
||||
|
||||
self.export_entries()
|
||||
def delete_entry(self, entry: ShoppingEntry):
|
||||
print("remove_entry called", entry)
|
||||
self.ids.shopping_list.remove_widget(entry)
|
||||
|
||||
def export_entries(self, from_mqtt=False):
|
||||
"""
|
||||
Speichert die einträge in einer JSON datei und wenn "from_mqtt" == False ist
|
||||
sendet es die daten an MQTT zur synchronisation
|
||||
|
||||
:param from_mqtt: ob der aufruf von MQTT kommt und nicht auf MQTT zurück geschrieben werden soll
|
||||
"""
|
||||
if not self.initialized:
|
||||
return
|
||||
|
||||
print("exporting entries", from_mqtt)
|
||||
self.entries = self.get_entires()
|
||||
entries_dict = {"entries": self.sort(self.entries, False)}
|
||||
try:
|
||||
write_entries_to_files(entries_dict)
|
||||
except OSError:
|
||||
return
|
||||
|
||||
# dont push to mqtt if coming from mqtt
|
||||
if not from_mqtt:
|
||||
app.mqtt.publish(entries_dict)
|
||||
|
||||
def get_entires(self):
|
||||
entries = []
|
||||
@@ -206,13 +272,32 @@ class ShoppingEntryScreen(Screen):
|
||||
entry_dict = {"is_checked": entry.is_checked, "text": entry.text}
|
||||
entries.append(entry_dict)
|
||||
|
||||
entries.sort(key=lambda entry: (entry["is_checked"], entry["text"]))
|
||||
entries = self.sort(entries, self.sort_reverse)
|
||||
return entries
|
||||
|
||||
def set_entries(self, entries: List[Dict[str, Union[str, bool]]]):
|
||||
@staticmethod
|
||||
def sort(entries, reverse) -> list:
|
||||
return sorted(entries, key=lambda entry: (entry["is_checked"], entry["text"]), reverse=reverse)
|
||||
|
||||
def set_entries(self, entries: List[Dict[str, Union[str, bool]]], from_mqtt=False):
|
||||
"""
|
||||
Setzt die werte der liste auf die mitgegebenen einträge und speichert diese
|
||||
|
||||
:param entries: die neuen einträge
|
||||
:param from_mqtt: ob der aufruf von MQTT kommt und nicht auf MQTT zurück geschrieben werden soll
|
||||
"""
|
||||
self.entries = entries
|
||||
self.export_entries(from_mqtt=from_mqtt)
|
||||
|
||||
# endregion
|
||||
|
||||
# region general
|
||||
|
||||
def toggle_sort(self):
|
||||
self.sort_reverse = not self.sort_reverse
|
||||
|
||||
def navigate_to_settings(self):
|
||||
"""Navigiert zur Einstellungs-Seite"""
|
||||
self.export_entries()
|
||||
self.manager.transition.direction = "left"
|
||||
self.manager.current = "settings"
|
||||
@@ -221,6 +306,10 @@ class ShoppingEntryScreen(Screen):
|
||||
language = app.settings.language
|
||||
return TranslationProvider.get_translated(key, language)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return super().__str__() + f"count: {len(self.entries)}"
|
||||
|
||||
# endregion
|
||||
|
||||
class SettingsScreen(Screen):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
MDTopAppBar:
|
||||
title: root.get_translated('app_title')
|
||||
md_bg_color: app.theme_cls.primary_color
|
||||
right_action_items: [['res/settings.png', lambda x: root.navigate_to_settings()]]
|
||||
right_action_items: [['sort-variant', lambda x: root.toggle_sort()],['cog', lambda x: root.navigate_to_settings()]]
|
||||
|
||||
ScrollView:
|
||||
size_hint: 0.85, 0.85
|
||||
@@ -56,7 +56,7 @@
|
||||
MDTopAppBar:
|
||||
title: root.get_translated('settings')
|
||||
md_bg_color: app.theme_cls.primary_color
|
||||
left_action_items: [['res/arrow_back.png', lambda x: root.navigate_to_shopping_list()]]
|
||||
left_action_items: [['arrow-left', lambda x: root.navigate_to_shopping_list()]]
|
||||
|
||||
MDGridLayout:
|
||||
pos_hint: { 'center_x': 0.5 }
|
||||
|
||||
Reference in New Issue
Block a user