1957 lines
64 KiB
Python
1957 lines
64 KiB
Python
# type: ignore
|
|
import kivy
|
|
from kivy.app import App
|
|
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
|
|
from kivy.uix.boxlayout import BoxLayout
|
|
from kivy.uix.gridlayout import GridLayout
|
|
from kivy.uix.scrollview import ScrollView
|
|
from kivy.uix.label import Label
|
|
from kivy.uix.button import Button
|
|
from kivy.uix.textinput import TextInput
|
|
from kivy.uix.popup import Popup
|
|
from kivy.core.window import Window
|
|
from kivy.graphics import Color, RoundedRectangle
|
|
|
|
|
|
class RoundedButton(Button):
|
|
def __init__(self, **kwargs):
|
|
self.btn_color = kwargs.pop("btn_color", [0.0, 0.65, 0.57, 1])
|
|
super(RoundedButton, self).__init__(**kwargs)
|
|
self.background_normal = ""
|
|
self.background_color = [0, 0, 0, 0]
|
|
self.color = [1, 1, 1, 1]
|
|
self.bold = True
|
|
with self.canvas.before:
|
|
self.color_instruction = Color(*self.btn_color)
|
|
self.rect = RoundedRectangle(pos=self.pos, size=self.size, radius=[8])
|
|
self.bind(pos=self.update_rect, size=self.update_rect, state=self.update_state)
|
|
|
|
def update_rect(self, instance, value):
|
|
self.rect.pos = self.pos
|
|
self.rect.size = self.size
|
|
|
|
def update_state(self, instance, value):
|
|
if value == "down":
|
|
self.color_instruction.rgba = [
|
|
self.btn_color[0] * 0.8,
|
|
self.btn_color[1] * 0.8,
|
|
self.btn_color[2] * 0.8,
|
|
1,
|
|
]
|
|
else:
|
|
self.color_instruction.rgba = self.btn_color
|
|
|
|
|
|
class MessagePopup(Popup):
|
|
def __init__(self, title, message, **kwargs):
|
|
content = BoxLayout(orientation="vertical", padding=20, spacing=20)
|
|
lbl = Label(text=message, font_size="16sp", halign="center", valign="middle")
|
|
lbl.bind(size=lbl.setter("text_size"))
|
|
content.add_widget(lbl)
|
|
btn = RoundedButton(
|
|
text="OK", size_hint_y=None, height="50dp", btn_color=[0.0, 0.65, 0.57, 1]
|
|
)
|
|
content.add_widget(btn)
|
|
|
|
super(MessagePopup, self).__init__(
|
|
title=title,
|
|
content=content,
|
|
size_hint=(0.85, None),
|
|
height="250dp",
|
|
title_align="center",
|
|
title_size="18sp",
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs,
|
|
)
|
|
btn.bind(on_release=self.dismiss)
|
|
|
|
|
|
class ConfirmPopup(Popup):
|
|
def __init__(self, title, message, on_confirm, **kwargs):
|
|
self.on_confirm = on_confirm
|
|
content = BoxLayout(orientation="vertical", padding=20, spacing=20)
|
|
lbl = Label(text=message, font_size="16sp", halign="center", valign="middle")
|
|
lbl.bind(size=lbl.setter("text_size"))
|
|
content.add_widget(lbl)
|
|
|
|
btn_box = BoxLayout(
|
|
orientation="horizontal", spacing=10, size_hint_y=None, height="50dp"
|
|
)
|
|
yes_btn = RoundedButton(text="Ja", btn_color=[0.0, 0.65, 0.57, 1])
|
|
no_btn = RoundedButton(text="Nein", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
btn_box.add_widget(yes_btn)
|
|
btn_box.add_widget(no_btn)
|
|
content.add_widget(btn_box)
|
|
|
|
super(ConfirmPopup, self).__init__(
|
|
title=title,
|
|
content=content,
|
|
size_hint=(0.85, None),
|
|
height="250dp",
|
|
title_align="center",
|
|
title_size="18sp",
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs,
|
|
)
|
|
|
|
yes_btn.bind(on_release=self._confirm)
|
|
no_btn.bind(on_release=self.dismiss)
|
|
|
|
def _confirm(self, instance):
|
|
self.dismiss()
|
|
self.on_confirm()
|
|
|
|
|
|
class NumpadPopup(Popup):
|
|
def __init__(self, title, is_password=False, is_float=False, on_submit=None, **kwargs):
|
|
self.is_password = is_password
|
|
self.is_float = is_float
|
|
self.on_submit = on_submit
|
|
self.entered_text = ""
|
|
|
|
content = BoxLayout(orientation='vertical', padding=15, spacing=15)
|
|
|
|
self.display = Label(
|
|
text="PIN eingeben:" if is_password else "Betrag eingeben:",
|
|
font_size='20sp',
|
|
bold=True,
|
|
size_hint_y=0.15,
|
|
halign='center',
|
|
valign='middle'
|
|
)
|
|
self.display.bind(size=self.display.setter('text_size'))
|
|
content.add_widget(self.display)
|
|
|
|
grid = GridLayout(cols=3, spacing=10, size_hint_y=0.6)
|
|
|
|
buttons = [
|
|
'1', '2', '3',
|
|
'4', '5', '6',
|
|
'7', '8', '9',
|
|
',' if is_float else 'C', '0', '⌫'
|
|
]
|
|
|
|
for btn_text in buttons:
|
|
btn = RoundedButton(
|
|
text=btn_text,
|
|
btn_color=[0.15, 0.15, 0.17, 1] if btn_text in ['C', '⌫', ','] else [0.0, 0.65, 0.57, 1]
|
|
)
|
|
btn.bind(on_release=self.on_key_press)
|
|
grid.add_widget(btn)
|
|
|
|
content.add_widget(grid)
|
|
|
|
actions = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=0.25)
|
|
ok_btn = RoundedButton(text="OK", btn_color=[0.0, 0.65, 0.57, 1])
|
|
cancel_btn = RoundedButton(text="Abbrechen", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
actions.add_widget(ok_btn)
|
|
actions.add_widget(cancel_btn)
|
|
content.add_widget(actions)
|
|
|
|
super(NumpadPopup, self).__init__(
|
|
title=title,
|
|
content=content,
|
|
size_hint=(0.85, 0.75),
|
|
title_align='center',
|
|
title_size='18sp',
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs
|
|
)
|
|
|
|
ok_btn.bind(on_release=self.submit)
|
|
cancel_btn.bind(on_release=self.dismiss)
|
|
|
|
def on_key_press(self, instance):
|
|
key = instance.text
|
|
if key == '⌫':
|
|
self.entered_text = self.entered_text[:-1]
|
|
elif key == 'C':
|
|
self.entered_text = ""
|
|
elif key == ',':
|
|
if ',' not in self.entered_text:
|
|
self.entered_text += ','
|
|
else:
|
|
self.entered_text += key
|
|
self.update_display()
|
|
|
|
def update_display(self):
|
|
if not self.entered_text:
|
|
self.display.text = "PIN eingeben:" if self.is_password else "Betrag eingeben:"
|
|
else:
|
|
if self.is_password:
|
|
self.display.text = "*" * len(self.entered_text)
|
|
else:
|
|
self.display.text = self.entered_text
|
|
|
|
def submit(self, instance):
|
|
self.dismiss()
|
|
if self.on_submit:
|
|
self.on_submit(self.entered_text)
|
|
|
|
|
|
class KeyboardPopup(Popup):
|
|
def __init__(self, title, is_password=False, on_submit=None, **kwargs):
|
|
self.is_password = is_password
|
|
self.on_submit = on_submit
|
|
self.entered_text = ""
|
|
|
|
content = BoxLayout(orientation='vertical', padding=15, spacing=15)
|
|
|
|
self.display = Label(
|
|
text="Eingeben:" if not is_password else "****",
|
|
font_size='20sp',
|
|
bold=True,
|
|
size_hint_y=0.15,
|
|
halign='center',
|
|
valign='middle'
|
|
)
|
|
self.display.bind(size=self.display.setter('text_size'))
|
|
content.add_widget(self.display)
|
|
|
|
kbd_layout = BoxLayout(orientation='vertical', spacing=5, size_hint_y=0.6)
|
|
|
|
rows = [
|
|
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
|
|
['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p'],
|
|
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],
|
|
['y', 'x', 'c', 'v', 'b', 'n', 'm', '⌫', 'C']
|
|
]
|
|
|
|
for row in rows:
|
|
row_box = BoxLayout(orientation='horizontal', spacing=5)
|
|
for char in row:
|
|
btn = RoundedButton(
|
|
text=char,
|
|
btn_color=[0.15, 0.15, 0.17, 1] if char in ['C', '⌫'] else [0.0, 0.65, 0.57, 1]
|
|
)
|
|
btn.bind(on_release=self.on_key_press)
|
|
row_box.add_widget(btn)
|
|
kbd_layout.add_widget(row_box)
|
|
|
|
content.add_widget(kbd_layout)
|
|
|
|
actions = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=0.25)
|
|
ok_btn = RoundedButton(text="OK", btn_color=[0.0, 0.65, 0.57, 1])
|
|
cancel_btn = RoundedButton(text="Abbrechen", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
actions.add_widget(ok_btn)
|
|
actions.add_widget(cancel_btn)
|
|
content.add_widget(actions)
|
|
|
|
super(KeyboardPopup, self).__init__(
|
|
title=title,
|
|
content=content,
|
|
size_hint=(0.95, 0.8),
|
|
title_align='center',
|
|
title_size='18sp',
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs
|
|
)
|
|
|
|
ok_btn.bind(on_release=self.submit)
|
|
cancel_btn.bind(on_release=self.dismiss)
|
|
|
|
def on_key_press(self, instance):
|
|
key = instance.text
|
|
if key == '⌫':
|
|
self.entered_text = self.entered_text[:-1]
|
|
elif key == 'C':
|
|
self.entered_text = ""
|
|
else:
|
|
self.entered_text += key
|
|
self.update_display()
|
|
|
|
def update_display(self):
|
|
if not self.entered_text:
|
|
self.display.text = "Eingeben:" if not self.is_password else "****"
|
|
else:
|
|
if self.is_password:
|
|
self.display.text = "*" * len(self.entered_text)
|
|
else:
|
|
self.display.text = self.entered_text
|
|
|
|
def submit(self, instance):
|
|
self.dismiss()
|
|
if self.on_submit:
|
|
self.on_submit(self.entered_text)
|
|
|
|
|
|
class AdjustDebtPopup(Popup):
|
|
def __init__(self, user_id, user_name, current_debt, on_adjust, **kwargs):
|
|
self.on_adjust = on_adjust
|
|
self.user_id = user_id
|
|
|
|
content = BoxLayout(orientation="vertical", padding=15, spacing=15)
|
|
|
|
info = Label(
|
|
text=f"Benutzer: {user_name}\nAktuelle Schulden: {current_debt:.2f} €\n\nGezahlter Betrag (€):",
|
|
halign="center",
|
|
valign="middle",
|
|
size_hint_y=0.4,
|
|
)
|
|
info.bind(size=info.setter("text_size"))
|
|
content.add_widget(info)
|
|
|
|
self.amount_input = TextInput(
|
|
text="",
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.25,
|
|
padding=[10, 10],
|
|
)
|
|
self.amount_input.bind(focus=self.trigger_numpad)
|
|
content.add_widget(self.amount_input)
|
|
|
|
btn_box = BoxLayout(orientation="horizontal", spacing=10, size_hint_y=0.35)
|
|
save_btn = RoundedButton(text="Speichern", btn_color=[0.0, 0.65, 0.57, 1])
|
|
cancel_btn = RoundedButton(text="Abbrechen", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
btn_box.add_widget(save_btn)
|
|
btn_box.add_widget(cancel_btn)
|
|
content.add_widget(btn_box)
|
|
|
|
super(AdjustDebtPopup, self).__init__(
|
|
title="Schulden anpassen",
|
|
content=content,
|
|
size_hint=(0.85, None),
|
|
height="300dp",
|
|
title_align="center",
|
|
title_size="18sp",
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs,
|
|
)
|
|
|
|
save_btn.bind(on_release=self._save)
|
|
cancel_btn.bind(on_release=self.dismiss)
|
|
|
|
def trigger_numpad(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = NumpadPopup(
|
|
title="Betrag eingeben",
|
|
is_password=False,
|
|
is_float=True,
|
|
on_submit=self.on_amount_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_amount_submitted(self, text):
|
|
self.amount_input.text = text
|
|
|
|
def _save(self, instance):
|
|
val = self.amount_input.text.strip()
|
|
try:
|
|
amount = float(val.replace(",", "."))
|
|
if amount < 0:
|
|
raise ValueError
|
|
self.dismiss()
|
|
self.on_adjust(self.user_id, amount)
|
|
except ValueError:
|
|
err = MessagePopup(title="Fehler", message="Ungültiger Betrag!")
|
|
err.open()
|
|
|
|
|
|
class CreateUserPopup(Popup):
|
|
def __init__(self, on_create, **kwargs):
|
|
self.on_create = on_create
|
|
|
|
content = BoxLayout(orientation='vertical', padding=15, spacing=15)
|
|
|
|
info = Label(
|
|
text="Name des neuen Benutzers eingeben:",
|
|
font_size='16sp',
|
|
size_hint_y=0.25,
|
|
halign='center',
|
|
valign='middle'
|
|
)
|
|
info.bind(size=info.setter('text_size'))
|
|
content.add_widget(info)
|
|
|
|
self.name_input = TextInput(
|
|
text="",
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.3,
|
|
padding=[10, 10]
|
|
)
|
|
self.name_input.bind(focus=self.trigger_keyboard)
|
|
content.add_widget(self.name_input)
|
|
|
|
btn_box = BoxLayout(orientation="horizontal", spacing=10, size_hint_y=0.45)
|
|
save_btn = RoundedButton(text="Erstellen", btn_color=[0.0, 0.65, 0.57, 1])
|
|
cancel_btn = RoundedButton(text="Abbrechen", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
btn_box.add_widget(save_btn)
|
|
btn_box.add_widget(cancel_btn)
|
|
content.add_widget(btn_box)
|
|
|
|
super(CreateUserPopup, self).__init__(
|
|
title="Benutzer hinzufügen",
|
|
content=content,
|
|
size_hint=(0.85, None),
|
|
height="260dp",
|
|
title_align="center",
|
|
title_size="18sp",
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs,
|
|
)
|
|
|
|
save_btn.bind(on_release=self._save)
|
|
cancel_btn.bind(on_release=self.dismiss)
|
|
|
|
def trigger_keyboard(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = KeyboardPopup(
|
|
title="Name eingeben",
|
|
is_password=False,
|
|
on_submit=self.on_name_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_name_submitted(self, text):
|
|
self.name_input.text = text
|
|
|
|
def _save(self, instance):
|
|
name = self.name_input.text.strip()
|
|
if not name:
|
|
err = MessagePopup(title="Fehler", message="Name darf nicht leer sein!")
|
|
err.open()
|
|
return
|
|
self.dismiss()
|
|
self.on_create(name)
|
|
|
|
|
|
class EditUserPopup(Popup):
|
|
def __init__(self, user_id, current_name, current_pin, on_save, on_delete, **kwargs):
|
|
self.user_id = user_id
|
|
self.on_save = on_save
|
|
self.on_delete = on_delete
|
|
|
|
content = BoxLayout(orientation='vertical', padding=15, spacing=15)
|
|
|
|
info = Label(
|
|
text="Benutzer bearbeiten:",
|
|
font_size='16sp',
|
|
size_hint_y=0.15,
|
|
halign='center',
|
|
valign='middle'
|
|
)
|
|
info.bind(size=info.setter('text_size'))
|
|
content.add_widget(info)
|
|
|
|
content.add_widget(Label(text="Name:", size_hint_y=0.08, halign="left"))
|
|
self.name_input = TextInput(
|
|
text=current_name,
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.15,
|
|
padding=[10, 10]
|
|
)
|
|
self.name_input.bind(focus=self.trigger_keyboard)
|
|
content.add_widget(self.name_input)
|
|
|
|
content.add_widget(Label(text="PIN:", size_hint_y=0.08, halign="left"))
|
|
self.pin_input = TextInput(
|
|
text=current_pin,
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.15,
|
|
padding=[10, 10]
|
|
)
|
|
self.pin_input.bind(focus=self.trigger_numpad)
|
|
content.add_widget(self.pin_input)
|
|
|
|
btn_box = BoxLayout(orientation="horizontal", spacing=10, size_hint_y=0.25)
|
|
save_btn = RoundedButton(text="Speichern", btn_color=[0.0, 0.65, 0.57, 1])
|
|
delete_btn = RoundedButton(text="Löschen", btn_color=[0.85, 0.35, 0.35, 1])
|
|
cancel_btn = RoundedButton(text="Abbrechen", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
btn_box.add_widget(save_btn)
|
|
btn_box.add_widget(delete_btn)
|
|
btn_box.add_widget(cancel_btn)
|
|
content.add_widget(btn_box)
|
|
|
|
super(EditUserPopup, self).__init__(
|
|
title="Benutzer bearbeiten",
|
|
content=content,
|
|
size_hint=(0.85, None),
|
|
height="400dp",
|
|
title_align="center",
|
|
title_size="18sp",
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs,
|
|
)
|
|
|
|
save_btn.bind(on_release=self._save)
|
|
delete_btn.bind(on_release=self._delete)
|
|
cancel_btn.bind(on_release=self.dismiss)
|
|
|
|
def trigger_keyboard(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = KeyboardPopup(
|
|
title="Name eingeben",
|
|
is_password=False,
|
|
on_submit=self.on_name_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_name_submitted(self, text):
|
|
self.name_input.text = text
|
|
|
|
def trigger_numpad(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = NumpadPopup(
|
|
title="PIN eingeben",
|
|
is_password=False,
|
|
on_submit=self.on_pin_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_pin_submitted(self, text):
|
|
self.pin_input.text = text
|
|
|
|
def _save(self, instance):
|
|
name = self.name_input.text.strip()
|
|
pin = self.pin_input.text.strip()
|
|
if not name:
|
|
err = MessagePopup(title="Fehler", message="Name darf nicht leer sein!")
|
|
err.open()
|
|
return
|
|
if len(pin) < 4:
|
|
err = MessagePopup(title="Fehler", message="Die PIN must mindestens 4 Ziffern lang sein!")
|
|
err.open()
|
|
return
|
|
self.dismiss()
|
|
self.on_save(self.user_id, name, pin)
|
|
|
|
def _delete(self, instance):
|
|
self.dismiss()
|
|
self.on_delete(self.user_id)
|
|
|
|
|
|
class CreateItemPopup(Popup):
|
|
def __init__(self, on_create, **kwargs):
|
|
self.on_create = on_create
|
|
|
|
content = BoxLayout(orientation='vertical', padding=15, spacing=15)
|
|
|
|
info = Label(
|
|
text="Neuen Artikel hinzufügen:",
|
|
font_size='16sp',
|
|
size_hint_y=0.15,
|
|
halign='center',
|
|
valign='middle'
|
|
)
|
|
info.bind(size=info.setter('text_size'))
|
|
content.add_widget(info)
|
|
|
|
content.add_widget(Label(text="Name:", size_hint_y=0.08, halign="left"))
|
|
self.name_input = TextInput(
|
|
text="",
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.15,
|
|
padding=[10, 10]
|
|
)
|
|
self.name_input.bind(focus=self.trigger_keyboard)
|
|
content.add_widget(self.name_input)
|
|
|
|
content.add_widget(Label(text="Preis (€):", size_hint_y=0.08, halign="left"))
|
|
self.price_input = TextInput(
|
|
text="",
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.15,
|
|
padding=[10, 10]
|
|
)
|
|
self.price_input.bind(focus=self.trigger_numpad)
|
|
content.add_widget(self.price_input)
|
|
|
|
btn_box = BoxLayout(orientation="horizontal", spacing=10, size_hint_y=0.25)
|
|
save_btn = RoundedButton(text="Erstellen", btn_color=[0.0, 0.65, 0.57, 1])
|
|
cancel_btn = RoundedButton(text="Abbrechen", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
btn_box.add_widget(save_btn)
|
|
btn_box.add_widget(cancel_btn)
|
|
content.add_widget(btn_box)
|
|
|
|
super(CreateItemPopup, self).__init__(
|
|
title="Artikel hinzufügen",
|
|
content=content,
|
|
size_hint=(0.85, None),
|
|
height="380dp",
|
|
title_align="center",
|
|
title_size="18sp",
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs,
|
|
)
|
|
|
|
save_btn.bind(on_release=self._save)
|
|
cancel_btn.bind(on_release=self.dismiss)
|
|
|
|
def trigger_keyboard(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = KeyboardPopup(
|
|
title="Artikelname eingeben",
|
|
is_password=False,
|
|
on_submit=self.on_name_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_name_submitted(self, text):
|
|
self.name_input.text = text
|
|
|
|
def trigger_numpad(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = NumpadPopup(
|
|
title="Preis eingeben",
|
|
is_password=False,
|
|
is_float=True,
|
|
on_submit=self.on_price_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_price_submitted(self, text):
|
|
self.price_input.text = text
|
|
|
|
def _save(self, instance):
|
|
name = self.name_input.text.strip()
|
|
price_str = self.price_input.text.strip().replace(",", ".")
|
|
if not name:
|
|
err = MessagePopup(title="Fehler", message="Name darf nicht leer sein!")
|
|
err.open()
|
|
return
|
|
try:
|
|
price = float(price_str)
|
|
if price < 0:
|
|
raise ValueError
|
|
except ValueError:
|
|
err = MessagePopup(title="Fehler", message="Ungültiger Preis!")
|
|
err.open()
|
|
return
|
|
|
|
self.dismiss()
|
|
self.on_create(name, price)
|
|
|
|
|
|
class EditItemPopup(Popup):
|
|
def __init__(self, item_id, current_name, current_price, on_save, on_delete, **kwargs):
|
|
self.item_id = item_id
|
|
self.on_save = on_save
|
|
self.on_delete = on_delete
|
|
|
|
content = BoxLayout(orientation='vertical', padding=15, spacing=15)
|
|
|
|
info = Label(
|
|
text="Artikel bearbeiten:",
|
|
font_size='16sp',
|
|
size_hint_y=0.15,
|
|
halign='center',
|
|
valign='middle'
|
|
)
|
|
info.bind(size=info.setter('text_size'))
|
|
content.add_widget(info)
|
|
|
|
content.add_widget(Label(text="Name:", size_hint_y=0.08, halign="left"))
|
|
self.name_input = TextInput(
|
|
text=current_name,
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.15,
|
|
padding=[10, 10]
|
|
)
|
|
self.name_input.bind(focus=self.trigger_keyboard)
|
|
content.add_widget(self.name_input)
|
|
|
|
content.add_widget(Label(text="Preis (€):", size_hint_y=0.08, halign="left"))
|
|
self.price_input = TextInput(
|
|
text=f"{current_price:.2f}".replace(".", ","),
|
|
multiline=False,
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
size_hint_y=0.15,
|
|
padding=[10, 10]
|
|
)
|
|
self.price_input.bind(focus=self.trigger_numpad)
|
|
content.add_widget(self.price_input)
|
|
|
|
btn_box = BoxLayout(orientation="horizontal", spacing=10, size_hint_y=0.25)
|
|
save_btn = RoundedButton(text="Speichern", btn_color=[0.0, 0.65, 0.57, 1])
|
|
delete_btn = RoundedButton(text="Löschen", btn_color=[0.85, 0.35, 0.35, 1])
|
|
cancel_btn = RoundedButton(text="Abbrechen", btn_color=[0.25, 0.25, 0.28, 1])
|
|
|
|
btn_box.add_widget(save_btn)
|
|
btn_box.add_widget(delete_btn)
|
|
btn_box.add_widget(cancel_btn)
|
|
content.add_widget(btn_box)
|
|
|
|
super(EditItemPopup, self).__init__(
|
|
title="Artikel bearbeiten",
|
|
content=content,
|
|
size_hint=(0.85, None),
|
|
height="400dp",
|
|
title_align="center",
|
|
title_size="18sp",
|
|
background_color=[0.08, 0.08, 0.09, 0.95],
|
|
**kwargs,
|
|
)
|
|
|
|
save_btn.bind(on_release=self._save)
|
|
delete_btn.bind(on_release=self._delete)
|
|
cancel_btn.bind(on_release=self.dismiss)
|
|
|
|
def trigger_keyboard(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = KeyboardPopup(
|
|
title="Artikelname eingeben",
|
|
is_password=False,
|
|
on_submit=self.on_name_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_name_submitted(self, text):
|
|
self.name_input.text = text
|
|
|
|
def trigger_numpad(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = NumpadPopup(
|
|
title="Preis eingeben",
|
|
is_password=False,
|
|
is_float=True,
|
|
on_submit=self.on_price_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_price_submitted(self, text):
|
|
self.price_input.text = text
|
|
|
|
def _save(self, instance):
|
|
name = self.name_input.text.strip()
|
|
price_str = self.price_input.text.strip().replace(",", ".")
|
|
if not name:
|
|
err = MessagePopup(title="Fehler", message="Name darf nicht leer sein!")
|
|
err.open()
|
|
return
|
|
try:
|
|
price = float(price_str)
|
|
if price < 0:
|
|
raise ValueError
|
|
except ValueError:
|
|
err = MessagePopup(title="Fehler", message="Ungültiger Preis!")
|
|
err.open()
|
|
return
|
|
|
|
self.dismiss()
|
|
self.on_save(self.item_id, name, price)
|
|
|
|
def _delete(self, instance):
|
|
self.dismiss()
|
|
self.on_delete(self.item_id)
|
|
|
|
|
|
class DebtRow(BoxLayout):
|
|
def __init__(self, name, amount, **kwargs):
|
|
super(DebtRow, self).__init__(
|
|
orientation="horizontal",
|
|
size_hint_y=None,
|
|
height="45dp",
|
|
padding=[15, 0],
|
|
spacing=10,
|
|
**kwargs,
|
|
)
|
|
with self.canvas.before:
|
|
Color(0.15, 0.15, 0.17, 1)
|
|
self.rect = RoundedRectangle(pos=self.pos, size=self.size, radius=[6])
|
|
self.bind(pos=self.update_rect, size=self.update_rect)
|
|
|
|
name_lbl = Label(text=name, font_size="16sp", halign="left", valign="middle")
|
|
name_lbl.bind(size=name_lbl.setter("text_size"))
|
|
amount_lbl = Label(
|
|
text=f"{amount:.2f} €",
|
|
font_size="16sp",
|
|
halign="right",
|
|
valign="middle",
|
|
bold=True,
|
|
)
|
|
amount_lbl.bind(size=amount_lbl.setter("text_size"))
|
|
|
|
self.add_widget(name_lbl)
|
|
self.add_widget(amount_lbl)
|
|
|
|
def update_rect(self, instance, value):
|
|
self.rect.pos = self.pos
|
|
self.rect.size = self.size
|
|
|
|
|
|
class TransactionRow(BoxLayout):
|
|
def __init__(self, date, user_name, item_name, amount, **kwargs):
|
|
super(TransactionRow, self).__init__(
|
|
orientation="horizontal",
|
|
size_hint_y=None,
|
|
height="50dp",
|
|
padding=[15, 5],
|
|
spacing=10,
|
|
**kwargs,
|
|
)
|
|
with self.canvas.before:
|
|
Color(0.15, 0.15, 0.17, 1)
|
|
self.rect = RoundedRectangle(pos=self.pos, size=self.size, radius=[6])
|
|
self.bind(pos=self.update_rect, size=self.update_rect)
|
|
|
|
date_lbl = Label(
|
|
text=date[:10],
|
|
font_size="14sp",
|
|
size_hint_x=0.25,
|
|
halign="left",
|
|
color=[0.7, 0.7, 0.7, 1],
|
|
valign="middle",
|
|
)
|
|
name_lbl = Label(
|
|
text=user_name,
|
|
font_size="15sp",
|
|
size_hint_x=0.35,
|
|
halign="left",
|
|
bold=True,
|
|
valign="middle",
|
|
)
|
|
item_lbl = Label(
|
|
text=item_name,
|
|
font_size="14sp",
|
|
size_hint_x=0.25,
|
|
halign="left",
|
|
valign="middle",
|
|
)
|
|
amount_lbl = Label(
|
|
text=f"{amount:.2f} €",
|
|
font_size="15sp",
|
|
size_hint_x=0.15,
|
|
halign="right",
|
|
color=[0.3, 0.9, 0.3, 1],
|
|
bold=True,
|
|
valign="middle",
|
|
)
|
|
|
|
date_lbl.bind(size=date_lbl.setter("text_size"))
|
|
name_lbl.bind(size=name_lbl.setter("text_size"))
|
|
item_lbl.bind(size=item_lbl.setter("text_size"))
|
|
amount_lbl.bind(size=amount_lbl.setter("text_size"))
|
|
|
|
self.add_widget(date_lbl)
|
|
self.add_widget(name_lbl)
|
|
self.add_widget(item_lbl)
|
|
self.add_widget(amount_lbl)
|
|
|
|
def update_rect(self, instance, value):
|
|
self.rect.pos = self.pos
|
|
self.rect.size = self.size
|
|
|
|
|
|
class StyledScreen(Screen):
|
|
def __init__(self, title_text, show_back=False, back_screen=None, **kwargs):
|
|
super(StyledScreen, self).__init__(**kwargs)
|
|
self.title_text = title_text
|
|
self.show_back = show_back
|
|
self.back_screen = back_screen
|
|
|
|
self.layout = BoxLayout(orientation="vertical", padding=20, spacing=15)
|
|
|
|
header = BoxLayout(
|
|
orientation="horizontal", size_hint_y=None, height="60dp", spacing=10
|
|
)
|
|
|
|
if self.show_back and self.back_screen:
|
|
back_btn = RoundedButton(
|
|
text="Zurück", size_hint_x=0.25, btn_color=[0.25, 0.25, 0.28, 1]
|
|
)
|
|
back_btn.bind(on_release=self.go_back)
|
|
header.add_widget(back_btn)
|
|
|
|
self.title_label = Label(
|
|
text=self.title_text,
|
|
font_size="22sp",
|
|
bold=True,
|
|
color=[1, 1, 1, 1],
|
|
halign="center" if not (self.show_back and self.back_screen) else "left",
|
|
valign="middle",
|
|
)
|
|
self.title_label.bind(size=self.title_label.setter("text_size"))
|
|
header.add_widget(self.title_label)
|
|
|
|
self.layout.add_widget(header)
|
|
|
|
self.content_layout = BoxLayout(orientation="vertical", spacing=15)
|
|
self.layout.add_widget(self.content_layout)
|
|
|
|
self.add_widget(self.layout)
|
|
|
|
def go_back(self, instance):
|
|
if self.back_screen:
|
|
self.manager.current = self.back_screen
|
|
|
|
|
|
class MainMenuScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(MainMenuScreen, self).__init__(title_text="Getränkeliste", **kwargs)
|
|
|
|
self.content_layout.padding = [0, 50, 0, 50]
|
|
self.content_layout.spacing = 20
|
|
|
|
btn_user = RoundedButton(
|
|
text="Benutzer auswählen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_user.bind(on_release=self.go_user_selection)
|
|
self.content_layout.add_widget(btn_user)
|
|
|
|
btn_admin = RoundedButton(
|
|
text="Admin-Bereich",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_admin.bind(on_release=self.go_admin)
|
|
self.content_layout.add_widget(btn_admin)
|
|
|
|
def go_user_selection(self, instance):
|
|
self.manager.current = "user_selection"
|
|
|
|
def go_admin(self, instance):
|
|
app = App.get_running_app()
|
|
if app.admin_password:
|
|
self.manager.current = "admin_menu"
|
|
else:
|
|
self.manager.current = "admin_password"
|
|
|
|
|
|
class UserSelectionScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(UserSelectionScreen, self).__init__(
|
|
title_text="Benutzer auswählen",
|
|
show_back=True,
|
|
back_screen="main_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
self.scroll = ScrollView()
|
|
self.user_layout = BoxLayout(
|
|
orientation="vertical", spacing=10, size_hint_y=None
|
|
)
|
|
self.user_layout.bind(minimum_height=self.user_layout.setter("height"))
|
|
self.scroll.add_widget(self.user_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.user_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
users = app.tracker.get_all_users()
|
|
|
|
for user_id, user in users.items():
|
|
btn = RoundedButton(
|
|
text=user.name,
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.0, 0.65, 0.57, 1],
|
|
)
|
|
btn.bind(on_release=lambda instance, uid=user_id: self.select_user(uid))
|
|
self.user_layout.add_widget(btn)
|
|
|
|
def select_user(self, user_id):
|
|
app = App.get_running_app()
|
|
user = app.tracker.get_user_by_id(user_id)
|
|
|
|
if not user.pin:
|
|
popup = NumpadPopup(
|
|
title=f"PIN einrichten: {user.name}",
|
|
is_password=True,
|
|
on_submit=lambda pin: self.setup_pin_confirm(user_id, pin)
|
|
)
|
|
popup.open()
|
|
else:
|
|
popup = NumpadPopup(
|
|
title=f"PIN eingeben: {user.name}",
|
|
is_password=True,
|
|
on_submit=lambda pin: self.verify_pin(user_id, pin)
|
|
)
|
|
popup.open()
|
|
|
|
def setup_pin_confirm(self, user_id, pin):
|
|
if len(pin) < 4:
|
|
err = MessagePopup(title="Fehler", message="Die PIN muss mindestens 4 Ziffern lang sein!")
|
|
err.open()
|
|
return
|
|
|
|
popup = NumpadPopup(
|
|
title="PIN bestätigen",
|
|
is_password=True,
|
|
on_submit=lambda confirm_pin: self.save_new_pin(user_id, pin, confirm_pin)
|
|
)
|
|
popup.open()
|
|
|
|
def save_new_pin(self, user_id, pin, confirm_pin):
|
|
if pin != confirm_pin:
|
|
err = MessagePopup(title="Fehler", message="PINs stimmen nicht überein!")
|
|
err.open()
|
|
return
|
|
|
|
app = App.get_running_app()
|
|
app.tracker.set_user_pin(user_id, pin)
|
|
app.current_user = user_id
|
|
self.manager.current = 'user_menu'
|
|
|
|
def verify_pin(self, user_id, pin):
|
|
app = App.get_running_app()
|
|
user = app.tracker.get_user_by_id(user_id)
|
|
|
|
if user.pin == pin:
|
|
app.current_user = user_id
|
|
self.manager.current = 'user_menu'
|
|
else:
|
|
err = MessagePopup(title="Fehler", message="Falsche PIN!")
|
|
err.open()
|
|
|
|
|
|
class UserMenuScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(UserMenuScreen, self).__init__(title_text="Benutzermenü", **kwargs)
|
|
|
|
self.info_label = Label(
|
|
text="",
|
|
font_size="18sp",
|
|
halign="center",
|
|
valign="middle",
|
|
size_hint_y=None,
|
|
height="120dp",
|
|
markup=True,
|
|
)
|
|
self.info_label.bind(size=self.info_label.setter("text_size"))
|
|
self.content_layout.add_widget(self.info_label)
|
|
self.content_layout.spacing = 15
|
|
|
|
btn_purchase = RoundedButton(
|
|
text="Kauf hinzufügen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_purchase.bind(on_release=self.go_add_purchase)
|
|
self.content_layout.add_widget(btn_purchase)
|
|
|
|
btn_change_pin = RoundedButton(
|
|
text="PIN ändern",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_change_pin.bind(on_release=self.change_pin)
|
|
self.content_layout.add_widget(btn_change_pin)
|
|
|
|
btn_logout = RoundedButton(
|
|
text="Abmelden",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.25, 0.25, 0.28, 1],
|
|
)
|
|
btn_logout.bind(on_release=self.logout)
|
|
self.content_layout.add_widget(btn_logout)
|
|
|
|
def on_enter(self, *args):
|
|
app = App.get_running_app()
|
|
if not app.current_user:
|
|
self.manager.current = "main_menu"
|
|
return
|
|
user = app.tracker.get_user_by_id(app.current_user)
|
|
debt = app.tracker.get_user_debt(app.current_user)
|
|
self.title_label.text = f"Menü - {user.name}"
|
|
|
|
self.info_label.text = f"Eingeloggt als: [b]{user.name}[/b]\n\nAktuelle Schulden:\n[b][color=ff3333]{debt:.2f} €[/color][/b]"
|
|
|
|
def go_add_purchase(self, instance):
|
|
self.manager.current = "add_purchase"
|
|
|
|
def change_pin(self, instance):
|
|
popup = NumpadPopup(
|
|
title="Aktuelle PIN eingeben",
|
|
is_password=True,
|
|
on_submit=lambda pin: self.verify_current_pin(pin)
|
|
)
|
|
popup.open()
|
|
|
|
def verify_current_pin(self, pin):
|
|
app = App.get_running_app()
|
|
user = app.tracker.get_user_by_id(app.current_user)
|
|
|
|
if user.pin == pin:
|
|
popup = NumpadPopup(
|
|
title="Neue PIN eingeben",
|
|
is_password=True,
|
|
on_submit=lambda new_pin: self.setup_new_pin(new_pin)
|
|
)
|
|
popup.open()
|
|
else:
|
|
err = MessagePopup(title="Fehler", message="Falsche PIN!")
|
|
err.open()
|
|
|
|
def setup_new_pin(self, new_pin):
|
|
if len(new_pin) < 4:
|
|
err = MessagePopup(title="Fehler", message="Die PIN muss mindestens 4 Ziffern lang sein!")
|
|
err.open()
|
|
return
|
|
|
|
popup = NumpadPopup(
|
|
title="Neue PIN bestätigen",
|
|
is_password=True,
|
|
on_submit=lambda confirm_pin: self.save_changed_pin(new_pin, confirm_pin)
|
|
)
|
|
popup.open()
|
|
|
|
def save_changed_pin(self, new_pin, confirm_pin):
|
|
if new_pin != confirm_pin:
|
|
err = MessagePopup(title="Fehler", message="PINs stimmen nicht überein!")
|
|
err.open()
|
|
return
|
|
|
|
app = App.get_running_app()
|
|
app.tracker.set_user_pin(app.current_user, new_pin)
|
|
success = MessagePopup(title="Erfolg", message="PIN erfolgreich geändert!")
|
|
success.open()
|
|
|
|
def logout(self, instance):
|
|
app = App.get_running_app()
|
|
app.current_user = None
|
|
self.manager.current = "main_menu"
|
|
|
|
|
|
class AddPurchaseScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AddPurchaseScreen, self).__init__(
|
|
title_text="Kauf hinzufügen",
|
|
show_back=True,
|
|
back_screen="user_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
self.scroll = ScrollView()
|
|
self.items_layout = BoxLayout(
|
|
orientation="vertical", spacing=10, size_hint_y=None
|
|
)
|
|
self.items_layout.bind(minimum_height=self.items_layout.setter("height"))
|
|
self.scroll.add_widget(self.items_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.items_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
items = app.tracker.get_items()
|
|
|
|
for item_id, item in items.items():
|
|
btn = RoundedButton(
|
|
text=f"{item.name} - {item.price:.2f} €",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.0, 0.65, 0.57, 1],
|
|
)
|
|
btn.bind(
|
|
on_release=lambda instance, iid=item_id: self.confirm_purchase_popup(
|
|
iid
|
|
)
|
|
)
|
|
self.items_layout.add_widget(btn)
|
|
|
|
def confirm_purchase_popup(self, item_id):
|
|
app = App.get_running_app()
|
|
user = app.tracker.get_user_by_id(app.current_user)
|
|
item = app.tracker.get_items()[item_id]
|
|
|
|
popup = ConfirmPopup(
|
|
title="Kauf bestätigen",
|
|
message=f"Möchtest du {item.name} für {item.price:.2f} € zu den Schulden von {user.name} hinzufügen?",
|
|
on_confirm=lambda: self.execute_purchase(item_id),
|
|
)
|
|
popup.open()
|
|
|
|
def execute_purchase(self, item_id):
|
|
app = App.get_running_app()
|
|
result = app.tracker.add_purchase(app.current_user, item_id)
|
|
|
|
if result["status"] == "success":
|
|
popup = MessagePopup(
|
|
title="Erfolg",
|
|
message=f"Kauf erfolgreich!\n\nNeuer Schuldenstand: {result['new_debt']:.2f} €",
|
|
)
|
|
popup.open()
|
|
self.manager.current = "user_menu"
|
|
else:
|
|
popup = MessagePopup(title="Fehler", message=f"Fehler: {result['message']}")
|
|
popup.open()
|
|
|
|
|
|
class AllDebtsScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AllDebtsScreen, self).__init__(
|
|
title_text="Alle Schulden",
|
|
show_back=True,
|
|
back_screen="main_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
self.scroll = ScrollView()
|
|
self.debts_layout = BoxLayout(
|
|
orientation="vertical", spacing=8, size_hint_y=None
|
|
)
|
|
self.debts_layout.bind(minimum_height=self.debts_layout.setter("height"))
|
|
self.scroll.add_widget(self.debts_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.debts_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
all_debts = app.tracker.get_all_debts()
|
|
|
|
if not all_debts:
|
|
no_debts = Label(
|
|
text="Keine Schulden registriert.",
|
|
font_size="16sp",
|
|
size_hint_y=None,
|
|
height="40dp",
|
|
)
|
|
self.debts_layout.add_widget(no_debts)
|
|
return
|
|
|
|
total = 0.0
|
|
|
|
for user_id, debt_info in all_debts.items():
|
|
name = debt_info["name"]
|
|
amount = debt_info["debt"]
|
|
total += amount
|
|
|
|
row = DebtRow(name=name, amount=amount)
|
|
self.debts_layout.add_widget(row)
|
|
|
|
divider = Label(
|
|
text="-" * 40, size_hint_y=None, height="20dp", color=[0.5, 0.5, 0.5, 1]
|
|
)
|
|
self.debts_layout.add_widget(divider)
|
|
|
|
total_row = BoxLayout(
|
|
orientation="horizontal", size_hint_y=None, height="40dp", padding=[15, 0]
|
|
)
|
|
total_name = Label(
|
|
text="GESAMT", font_size="18sp", bold=True, halign="left", valign="middle"
|
|
)
|
|
total_name.bind(size=total_name.setter("text_size"))
|
|
total_val = Label(
|
|
text=f"{total:.2f} €",
|
|
font_size="18sp",
|
|
bold=True,
|
|
color=[1, 0.3, 0.3, 1],
|
|
halign="right",
|
|
valign="middle",
|
|
)
|
|
total_val.bind(size=total_val.setter("text_size"))
|
|
|
|
total_row.add_widget(total_name)
|
|
total_row.add_widget(total_val)
|
|
self.debts_layout.add_widget(total_row)
|
|
|
|
|
|
class AdminPasswordScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AdminPasswordScreen, self).__init__(
|
|
title_text="Admin-Bereich",
|
|
show_back=True,
|
|
back_screen="main_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
self.content_layout.add_widget(
|
|
Label(
|
|
text="Bitte Admin-Passwort eingeben:",
|
|
font_size="16sp",
|
|
size_hint_y=None,
|
|
height="40dp",
|
|
)
|
|
)
|
|
|
|
self.pwd_input = TextInput(
|
|
password=True,
|
|
multiline=False,
|
|
size_hint=(0.7, None),
|
|
height="50dp",
|
|
pos_hint={"center_x": 0.5},
|
|
font_size="18sp",
|
|
background_normal="",
|
|
background_active="",
|
|
background_color=[0.15, 0.15, 0.17, 1],
|
|
foreground_color=[1, 1, 1, 1],
|
|
cursor_color=[1, 1, 1, 1],
|
|
padding=[15, 12, 15, 12],
|
|
)
|
|
self.pwd_input.bind(focus=self.trigger_keyboard)
|
|
self.content_layout.add_widget(self.pwd_input)
|
|
|
|
self.error_label = Label(
|
|
text="",
|
|
font_size="14sp",
|
|
color=[1, 0.3, 0.3, 1],
|
|
size_hint_y=None,
|
|
height="30dp",
|
|
)
|
|
self.content_layout.add_widget(self.error_label)
|
|
|
|
btn_login = RoundedButton(
|
|
text="Einloggen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_login.bind(on_release=self.check_password)
|
|
self.content_layout.add_widget(btn_login)
|
|
|
|
def on_enter(self, *args):
|
|
self.pwd_input.text = ""
|
|
self.error_label.text = ""
|
|
self.pwd_input.focus = True
|
|
|
|
def trigger_keyboard(self, instance, value):
|
|
if value:
|
|
instance.focus = False
|
|
popup = KeyboardPopup(
|
|
title="Admin-Passwort eingeben",
|
|
is_password=True,
|
|
on_submit=self.on_password_submitted
|
|
)
|
|
popup.open()
|
|
|
|
def on_password_submitted(self, text):
|
|
self.pwd_input.text = text
|
|
self.check_password(None)
|
|
|
|
def check_password(self, instance):
|
|
app = App.get_running_app()
|
|
password = self.pwd_input.text.strip()
|
|
|
|
from config import ADMIN_PASSWORD
|
|
|
|
if password == ADMIN_PASSWORD:
|
|
app.admin_password = password
|
|
self.manager.current = "admin_menu"
|
|
else:
|
|
self.error_label.text = "Falsches Passwort!"
|
|
|
|
|
|
class AdminMenuScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AdminMenuScreen, self).__init__(title_text="Admin Panel", **kwargs)
|
|
|
|
scroll = ScrollView()
|
|
box = BoxLayout(orientation="vertical", spacing=15, size_hint_y=None)
|
|
box.bind(minimum_height=box.setter("height"))
|
|
scroll.add_widget(box)
|
|
self.content_layout.add_widget(scroll)
|
|
|
|
btn_debts = RoundedButton(
|
|
text="Alle Schulden anzeigen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_debts.bind(on_release=self.go_all_debts)
|
|
box.add_widget(btn_debts)
|
|
|
|
btn_adjust = RoundedButton(
|
|
text="Schulden anpassen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_adjust.bind(on_release=self.go_adjust_debt)
|
|
box.add_widget(btn_adjust)
|
|
|
|
btn_clear = RoundedButton(
|
|
text="Schulden begleichen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_clear.bind(on_release=self.go_clear_debt)
|
|
box.add_widget(btn_clear)
|
|
|
|
btn_history = RoundedButton(
|
|
text="Transaktionsverlauf anzeigen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_history.bind(on_release=self.go_history)
|
|
box.add_widget(btn_history)
|
|
|
|
btn_manage_users = RoundedButton(
|
|
text="Benutzer verwalten",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_manage_users.bind(on_release=self.go_manage_users)
|
|
box.add_widget(btn_manage_users)
|
|
|
|
btn_manage_items = RoundedButton(
|
|
text="Artikel verwalten",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
)
|
|
btn_manage_items.bind(on_release=self.go_manage_items)
|
|
box.add_widget(btn_manage_items)
|
|
|
|
btn_logout = RoundedButton(
|
|
text="Admin-Bereich verlassen",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.25, 0.25, 0.28, 1],
|
|
)
|
|
btn_logout.bind(on_release=self.logout)
|
|
box.add_widget(btn_logout)
|
|
|
|
def go_all_debts(self, instance):
|
|
self.manager.get_screen("all_debts").back_screen = "admin_menu"
|
|
self.manager.current = "all_debts"
|
|
|
|
def go_adjust_debt(self, instance):
|
|
self.manager.current = "admin_adjust_debt"
|
|
|
|
def go_clear_debt(self, instance):
|
|
self.manager.current = "admin_clear_debt"
|
|
|
|
def go_history(self, instance):
|
|
self.manager.current = "admin_history"
|
|
|
|
def go_manage_users(self, instance):
|
|
self.manager.current = "admin_manage_users"
|
|
|
|
def go_manage_items(self, instance):
|
|
self.manager.current = "admin_manage_items"
|
|
|
|
def logout(self, instance):
|
|
app = App.get_running_app()
|
|
app.admin_password = None
|
|
self.manager.current = "main_menu"
|
|
|
|
|
|
|
|
class AdminAdjustDebtScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AdminAdjustDebtScreen, self).__init__(
|
|
title_text="Schulden anpassen",
|
|
show_back=True,
|
|
back_screen="admin_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
self.scroll = ScrollView()
|
|
self.user_layout = BoxLayout(
|
|
orientation="vertical", spacing=10, size_hint_y=None
|
|
)
|
|
self.user_layout.bind(minimum_height=self.user_layout.setter("height"))
|
|
self.scroll.add_widget(self.user_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.user_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
users = app.tracker.get_all_users()
|
|
|
|
for user_id, user in users.items():
|
|
debt = app.tracker.get_user_debt(user_id)
|
|
btn = RoundedButton(
|
|
text=f"{user.name} (Schulden: {debt:.2f} €)",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.0, 0.65, 0.57, 1],
|
|
)
|
|
btn.bind(
|
|
on_release=lambda instance, uid=user_id, name=user.name, d=debt: (
|
|
self.open_adjust_popup(uid, name, d)
|
|
)
|
|
)
|
|
self.user_layout.add_widget(btn)
|
|
|
|
def open_adjust_popup(self, user_id, user_name, current_debt):
|
|
popup = AdjustDebtPopup(
|
|
user_id=user_id,
|
|
user_name=user_name,
|
|
current_debt=current_debt,
|
|
on_adjust=self.adjust_debt,
|
|
)
|
|
popup.open()
|
|
|
|
def adjust_debt(self, user_id, amount):
|
|
app = App.get_running_app()
|
|
result = app.tracker.adjust_debt(user_id, amount, app.admin_password)
|
|
|
|
if result["status"] == "success":
|
|
popup = MessagePopup(
|
|
title="Erfolg",
|
|
message=f"Schulden erfolgreich angepasst!\n\nNeuer Schuldenstand: {result['new_debt']:.2f} €",
|
|
)
|
|
popup.open()
|
|
self.on_enter()
|
|
else:
|
|
popup = MessagePopup(title="Fehler", message=f"Fehler: {result['message']}")
|
|
popup.open()
|
|
|
|
|
|
class AdminClearDebtScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AdminClearDebtScreen, self).__init__(
|
|
title_text="Schulden begleichen",
|
|
show_back=True,
|
|
back_screen="admin_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
self.scroll = ScrollView()
|
|
self.user_layout = BoxLayout(
|
|
orientation="vertical", spacing=10, size_hint_y=None
|
|
)
|
|
self.user_layout.bind(minimum_height=self.user_layout.setter("height"))
|
|
self.scroll.add_widget(self.user_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.user_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
users = app.tracker.get_all_users()
|
|
|
|
for user_id, user in users.items():
|
|
debt = app.tracker.get_user_debt(user_id)
|
|
btn = RoundedButton(
|
|
text=f"{user.name} (Schulden: {debt:.2f} €)",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.85, 0.35, 0.35, 1] if debt > 0 else [0.25, 0.25, 0.28, 1],
|
|
)
|
|
btn.bind(
|
|
on_release=lambda instance, uid=user_id, name=user.name, d=debt: (
|
|
self.confirm_clear_popup(uid, name, d)
|
|
)
|
|
)
|
|
self.user_layout.add_widget(btn)
|
|
|
|
def confirm_clear_popup(self, user_id, user_name, current_debt):
|
|
if current_debt <= 0:
|
|
popup = MessagePopup(
|
|
title="Info", message=f"{user_name} hat keine Schulden."
|
|
)
|
|
popup.open()
|
|
return
|
|
|
|
popup = ConfirmPopup(
|
|
title="Schulden begleichen",
|
|
message=f"Möchtest du die Schulden von {user_name} in Höhe von {current_debt:.2f} € vollständig begleichen?",
|
|
on_confirm=lambda: self.clear_debt(user_id, current_debt),
|
|
)
|
|
popup.open()
|
|
|
|
def clear_debt(self, user_id, amount):
|
|
app = App.get_running_app()
|
|
result = app.tracker.adjust_debt(user_id, amount, app.admin_password)
|
|
|
|
if result["status"] == "success":
|
|
popup = MessagePopup(
|
|
title="Erfolg",
|
|
message=f"Schulden von {app.tracker.get_user_by_id(user_id).name} wurden vollständig beglichen!",
|
|
)
|
|
popup.open()
|
|
self.on_enter()
|
|
else:
|
|
popup = MessagePopup(title="Fehler", message=f"Fehler: {result['message']}")
|
|
popup.open()
|
|
|
|
|
|
class AdminHistoryScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AdminHistoryScreen, self).__init__(
|
|
title_text="Transaktionsverlauf",
|
|
show_back=True,
|
|
back_screen="admin_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
self.scroll = ScrollView()
|
|
self.history_layout = BoxLayout(
|
|
orientation="vertical", spacing=8, size_hint_y=None
|
|
)
|
|
self.history_layout.bind(minimum_height=self.history_layout.setter("height"))
|
|
self.scroll.add_widget(self.history_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.history_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
transactions = app.tracker.transactions
|
|
|
|
if not transactions:
|
|
no_trans = Label(
|
|
text="Bisher keine Transaktionen.",
|
|
font_size="16sp",
|
|
size_hint_y=None,
|
|
height="40dp",
|
|
)
|
|
self.history_layout.add_widget(no_trans)
|
|
return
|
|
|
|
for t in sorted(transactions, key=lambda x: x.timestamp, reverse=True):
|
|
user = app.tracker.get_user_by_id(t.user_id)
|
|
user_name = user.name if user else "Gelöschter Benutzer"
|
|
|
|
if t.item_id == "adjustment":
|
|
item_name = "Anpassung"
|
|
else:
|
|
item = app.tracker.get_items().get(t.item_id)
|
|
item_name = item.name if item else "Gelöschter Artikel"
|
|
|
|
row = TransactionRow(
|
|
date=t.timestamp,
|
|
user_name=user_name,
|
|
item_name=item_name,
|
|
amount=t.amount,
|
|
)
|
|
self.history_layout.add_widget(row)
|
|
|
|
|
|
class AdminManageUsersScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AdminManageUsersScreen, self).__init__(
|
|
title_text="Benutzer verwalten",
|
|
show_back=True,
|
|
back_screen="admin_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
btn_add = RoundedButton(
|
|
text="Benutzer hinzufügen",
|
|
size_hint=(0.7, None),
|
|
height="50dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.0, 0.65, 0.57, 1]
|
|
)
|
|
btn_add.bind(on_release=self.open_create_user_popup)
|
|
self.content_layout.add_widget(btn_add)
|
|
|
|
self.scroll = ScrollView()
|
|
self.user_layout = BoxLayout(
|
|
orientation="vertical", spacing=10, size_hint_y=None
|
|
)
|
|
self.user_layout.bind(minimum_height=self.user_layout.setter("height"))
|
|
self.scroll.add_widget(self.user_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.refresh_users()
|
|
|
|
def refresh_users(self):
|
|
self.user_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
users = app.tracker.get_all_users()
|
|
|
|
for user_id, user in users.items():
|
|
btn = RoundedButton(
|
|
text=f"{user.name} (PIN: {user.pin})",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.15, 0.15, 0.17, 1],
|
|
)
|
|
btn.bind(
|
|
on_release=lambda instance, uid=user_id, name=user.name, pin=user.pin: (
|
|
self.open_edit_user_popup(uid, name, pin)
|
|
)
|
|
)
|
|
self.user_layout.add_widget(btn)
|
|
|
|
def open_create_user_popup(self, instance):
|
|
popup = CreateUserPopup(on_create=self.create_user)
|
|
popup.open()
|
|
|
|
def create_user(self, name):
|
|
import uuid
|
|
app = App.get_running_app()
|
|
user_id = f"user_{uuid.uuid4().hex[:8]}"
|
|
res = app.tracker.add_user(user_id, name)
|
|
|
|
if res["status"] == "success":
|
|
msg = MessagePopup(
|
|
title="Erfolg",
|
|
message=f"Benutzer {name} erfolgreich erstellt!\n(Standard-PIN: 4242)"
|
|
)
|
|
msg.open()
|
|
self.refresh_users()
|
|
else:
|
|
msg = MessagePopup(
|
|
title="Fehler",
|
|
message=f"Fehler: {res['message']}"
|
|
)
|
|
msg.open()
|
|
|
|
def open_edit_user_popup(self, user_id, name, pin):
|
|
popup = EditUserPopup(
|
|
user_id=user_id,
|
|
current_name=name,
|
|
current_pin=pin,
|
|
on_save=self.save_user,
|
|
on_delete=self.confirm_delete_user
|
|
)
|
|
popup.open()
|
|
|
|
def save_user(self, user_id, name, pin):
|
|
app = App.get_running_app()
|
|
res = app.tracker.edit_user(user_id, name, pin)
|
|
if res["status"] == "success":
|
|
msg = MessagePopup(title="Erfolg", message=f"Benutzer {name} aktualisiert!")
|
|
msg.open()
|
|
self.refresh_users()
|
|
else:
|
|
msg = MessagePopup(title="Fehler", message=f"Fehler: {res['message']}")
|
|
msg.open()
|
|
|
|
def confirm_delete_user(self, user_id):
|
|
app = App.get_running_app()
|
|
user = app.tracker.get_user_by_id(user_id)
|
|
if not user:
|
|
return
|
|
popup = ConfirmPopup(
|
|
title="Benutzer löschen",
|
|
message=f"Möchtest du den Benutzer {user.name} wirklich unwiderruflich löschen?",
|
|
on_confirm=lambda: self.delete_user(user_id)
|
|
)
|
|
popup.open()
|
|
|
|
def delete_user(self, user_id):
|
|
app = App.get_running_app()
|
|
res = app.tracker.remove_user(user_id)
|
|
if res["status"] == "success":
|
|
msg = MessagePopup(title="Erfolg", message="Benutzer gelöscht!")
|
|
msg.open()
|
|
self.refresh_users()
|
|
else:
|
|
msg = MessagePopup(title="Fehler", message=f"Fehler: {res['message']}")
|
|
msg.open()
|
|
|
|
|
|
class AdminManageItemsScreen(StyledScreen):
|
|
def __init__(self, **kwargs):
|
|
super(AdminManageItemsScreen, self).__init__(
|
|
title_text="Artikel verwalten",
|
|
show_back=True,
|
|
back_screen="admin_menu",
|
|
**kwargs,
|
|
)
|
|
|
|
btn_add = RoundedButton(
|
|
text="Artikel hinzufügen",
|
|
size_hint=(0.7, None),
|
|
height="50dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.0, 0.65, 0.57, 1]
|
|
)
|
|
btn_add.bind(on_release=self.open_create_item_popup)
|
|
self.content_layout.add_widget(btn_add)
|
|
|
|
self.scroll = ScrollView()
|
|
self.items_layout = BoxLayout(
|
|
orientation="vertical", spacing=10, size_hint_y=None
|
|
)
|
|
self.items_layout.bind(minimum_height=self.items_layout.setter("height"))
|
|
self.scroll.add_widget(self.items_layout)
|
|
|
|
self.content_layout.add_widget(self.scroll)
|
|
|
|
def on_enter(self, *args):
|
|
self.refresh_items()
|
|
|
|
def refresh_items(self):
|
|
self.items_layout.clear_widgets()
|
|
app = App.get_running_app()
|
|
items = app.tracker.get_items()
|
|
|
|
for item_id, item in items.items():
|
|
btn = RoundedButton(
|
|
text=f"{item.name} ({item.price:.2f} €)",
|
|
size_hint=(0.7, None),
|
|
height="60dp",
|
|
pos_hint={"center_x": 0.5},
|
|
btn_color=[0.15, 0.15, 0.17, 1],
|
|
)
|
|
btn.bind(
|
|
on_release=lambda instance, iid=item_id, name=item.name, price=item.price: (
|
|
self.open_edit_item_popup(iid, name, price)
|
|
)
|
|
)
|
|
self.items_layout.add_widget(btn)
|
|
|
|
def open_create_item_popup(self, instance):
|
|
popup = CreateItemPopup(on_create=self.create_item)
|
|
popup.open()
|
|
|
|
def create_item(self, name, price):
|
|
import uuid
|
|
app = App.get_running_app()
|
|
item_id = f"item_{uuid.uuid4().hex[:8]}"
|
|
res = app.tracker.add_item(item_id, name, price)
|
|
|
|
if res["status"] == "success":
|
|
msg = MessagePopup(title="Erfolg", message=f"Artikel {name} erfolgreich erstellt!")
|
|
msg.open()
|
|
self.refresh_items()
|
|
else:
|
|
msg = MessagePopup(title="Fehler", message=f"Fehler: {res['message']}")
|
|
msg.open()
|
|
|
|
def open_edit_item_popup(self, item_id, name, price):
|
|
popup = EditItemPopup(
|
|
item_id=item_id,
|
|
current_name=name,
|
|
current_price=price,
|
|
on_save=self.save_item,
|
|
on_delete=self.confirm_delete_item
|
|
)
|
|
popup.open()
|
|
|
|
def save_item(self, item_id, name, price):
|
|
app = App.get_running_app()
|
|
res = app.tracker.edit_item(item_id, name, price)
|
|
if res["status"] == "success":
|
|
msg = MessagePopup(title="Erfolg", message=f"Artikel {name} aktualisiert!")
|
|
msg.open()
|
|
self.refresh_items()
|
|
else:
|
|
msg = MessagePopup(title="Fehler", message=f"Fehler: {res['message']}")
|
|
msg.open()
|
|
|
|
def confirm_delete_item(self, item_id):
|
|
app = App.get_running_app()
|
|
items = app.tracker.get_items()
|
|
item = items.get(item_id)
|
|
if not item:
|
|
return
|
|
popup = ConfirmPopup(
|
|
title="Artikel löschen",
|
|
message=f"Möchtest du den Artikel {item.name} wirklich unwiderruflich löschen?",
|
|
on_confirm=lambda: self.delete_item(item_id)
|
|
)
|
|
popup.open()
|
|
|
|
def delete_item(self, item_id):
|
|
app = App.get_running_app()
|
|
res = app.tracker.remove_item(item_id)
|
|
if res["status"] == "success":
|
|
msg = MessagePopup(title="Erfolg", message="Artikel gelöscht!")
|
|
msg.open()
|
|
self.refresh_items()
|
|
else:
|
|
msg = MessagePopup(title="Fehler", message=f"Fehler: {res['message']}")
|
|
msg.open()
|
|
|
|
|
|
class KuehlschrankApp(App):
|
|
def __init__(self, tracker, **kwargs):
|
|
super(KuehlschrankApp, self).__init__(**kwargs)
|
|
self.tracker = tracker
|
|
self.current_user = None
|
|
self.admin_password = None
|
|
|
|
def build(self):
|
|
self.title = "Getränkeliste"
|
|
|
|
Window.size = (450, 700)
|
|
Window.clearcolor = (0.08, 0.08, 0.09, 1)
|
|
|
|
sm = ScreenManager(transition=SlideTransition())
|
|
sm.add_widget(MainMenuScreen(name="main_menu"))
|
|
sm.add_widget(UserSelectionScreen(name="user_selection"))
|
|
sm.add_widget(UserMenuScreen(name="user_menu"))
|
|
sm.add_widget(AddPurchaseScreen(name="add_purchase"))
|
|
sm.add_widget(AllDebtsScreen(name="all_debts"))
|
|
sm.add_widget(AdminPasswordScreen(name="admin_password"))
|
|
sm.add_widget(AdminMenuScreen(name="admin_menu"))
|
|
sm.add_widget(AdminAdjustDebtScreen(name="admin_adjust_debt"))
|
|
sm.add_widget(AdminClearDebtScreen(name="admin_clear_debt"))
|
|
sm.add_widget(AdminHistoryScreen(name="admin_history"))
|
|
sm.add_widget(AdminManageUsersScreen(name="admin_manage_users"))
|
|
sm.add_widget(AdminManageItemsScreen(name="admin_manage_items"))
|
|
|
|
return sm
|
|
|
|
|
|
|
|
class KivyUI:
|
|
def __init__(self, tracker):
|
|
self.tracker = tracker
|
|
|
|
def run(self):
|
|
app = KuehlschrankApp(self.tracker)
|
|
app.run()
|