255 lines
8.0 KiB
Python
255 lines
8.0 KiB
Python
|
||
from kivy.uix.screenmanager import Screen
|
||
from kivy.uix.boxlayout import BoxLayout
|
||
from kivy.uix.scrollview import ScrollView
|
||
from kivy.uix.gridlayout import GridLayout
|
||
from kivy.uix.button import Button
|
||
from kivy.uix.textinput import TextInput
|
||
from kivy.metrics import dp
|
||
from kivy.clock import Clock
|
||
from kivy.effects.scroll import ScrollEffect
|
||
from kivy.logger import Logger
|
||
from ui_utils import ucet_ui_type, UCET_COLORS
|
||
|
||
import math
|
||
import data
|
||
|
||
import numberpad
|
||
from accountselect_base import BaseAccountSelectScreen
|
||
from ui_utils import _popup_info
|
||
|
||
COLS = 7
|
||
BTN_W = dp(150)
|
||
BTN_H = dp(120)
|
||
SP = dp(10)
|
||
PAD = dp(10)
|
||
|
||
class ClosedAccountSelectScreen(BaseAccountSelectScreen):
|
||
def __init__(
|
||
self,
|
||
*,
|
||
controller,
|
||
operation: str,
|
||
get_ucty,
|
||
on_done,
|
||
on_cancel,
|
||
allow_manual: bool = True,
|
||
**kwargs,):
|
||
super().__init__(**kwargs)
|
||
self.controller = controller
|
||
self.operation = operation
|
||
self.get_ucty = get_ucty
|
||
self.on_done = on_done
|
||
self.on_cancel = on_cancel
|
||
self.allow_manual = allow_manual
|
||
self._all_ucty: list[data.UcetSelect] = []
|
||
root = BoxLayout(orientation="vertical", spacing=dp(10), padding=dp(10))
|
||
self.search_input = TextInput(
|
||
hint_text="HLEDAT",
|
||
multiline=False,
|
||
size_hint_y=None,
|
||
height=dp(52),
|
||
font_size=dp(20),
|
||
padding=(dp(12), dp(12), dp(12), dp(8)),
|
||
)
|
||
self.search_input.bind(text=self._on_search_text)
|
||
root.add_widget(self.search_input)
|
||
self.scroll = ScrollView(
|
||
size_hint=(1, 1),
|
||
do_scroll_x=True,
|
||
do_scroll_y=True,
|
||
bar_width=dp(14),
|
||
scroll_type=["bars", "content"],
|
||
effect_cls=ScrollEffect,)
|
||
self.grid = GridLayout(
|
||
cols=COLS,
|
||
spacing=SP,
|
||
padding=PAD,
|
||
size_hint=(None, None),)
|
||
self.grid.bind(minimum_height=self.grid.setter("height"))
|
||
self.grid.width = COLS * BTN_W + (COLS - 1) * SP + 2 * PAD
|
||
self.scroll.add_widget(self.grid)
|
||
root.add_widget(self.scroll)
|
||
bottom = BoxLayout(size_hint_y=None, height=dp(70), spacing=dp(10))
|
||
if self.allow_manual:
|
||
bottom.add_widget(Button(
|
||
text="ZADAT ÚČET",
|
||
on_press=self._manual, # <- musí existovat
|
||
))
|
||
bottom.add_widget(Button(
|
||
text="ZPĚT",
|
||
on_press=lambda *_: self.on_cancel(),
|
||
))
|
||
root.add_widget(bottom)
|
||
self.add_widget(root)
|
||
|
||
def _manual(self, *_):
|
||
import numberpad
|
||
from kivy.uix.popup import Popup
|
||
pad = numberpad.NumberPad(
|
||
mode="number",
|
||
max_len=10,
|
||
allow_fraction=False,
|
||
on_accept=self._manual_accept,
|
||
on_cancel=self._manual_cancel,
|
||
)
|
||
self._manual_popup = Popup(
|
||
title="Zadat číslo účtu",
|
||
content=pad,
|
||
size_hint=(None, None),
|
||
size=(dp(360), dp(420)),
|
||
auto_dismiss=False,
|
||
)
|
||
self._manual_popup.open()
|
||
|
||
def _manual_accept(self, value: str):
|
||
if getattr(self, "_manual_popup", None):
|
||
self._manual_popup.dismiss()
|
||
self._manual_popup = None
|
||
value = (value or "").strip()
|
||
if not value:
|
||
return
|
||
self._select(value)
|
||
|
||
def _manual_cancel(self):
|
||
if getattr(self, "_manual_popup", None):
|
||
self._manual_popup.dismiss()
|
||
self._manual_popup = None
|
||
|
||
def on_enter(self):
|
||
self.refresh()
|
||
|
||
def _select(self, ucislo: int):
|
||
Logger.info(f"ClosedSelect: picked ucislo={ucislo} op={self.operation}")
|
||
self.on_done(self.operation, ucislo)
|
||
|
||
def _update_scroll(self, *_):
|
||
if not self.scroll or not self.grid:
|
||
return
|
||
|
||
count = len(self.grid.children)
|
||
if count == 0:
|
||
self.scroll.do_scroll_x = False
|
||
self.scroll.do_scroll_y = False
|
||
return
|
||
|
||
rows = math.ceil(count / COLS)
|
||
content_h = rows * BTN_H + (rows - 1) * SP + 2 * PAD
|
||
self.scroll.do_scroll_y = content_h > self.scroll.height
|
||
|
||
def _create_ucet_button(self, u: data.UcetSelect):
|
||
ui_type = ucet_ui_type(u)
|
||
color = UCET_COLORS.get(ui_type, (0.3, 0.3, 0.3, 1))
|
||
txt = self._format_closed_ucet(u) or ""
|
||
if not txt.strip():
|
||
txt = f"ID {getattr(u, 'id', '')}"
|
||
btn = Button(
|
||
text=txt,
|
||
size_hint=(None, None),
|
||
background_color=color,
|
||
width=BTN_W,
|
||
height=dp(130), # lehce vyšší pro 4–5 řádků
|
||
font_size=dp(12), # trochu menší
|
||
halign="center",
|
||
valign="top", )
|
||
btn.bind(
|
||
size=lambda b, *_: setattr(
|
||
b, "text_size", (b.width - dp(10), None)
|
||
))
|
||
ucislo = getattr(u, "ucislo", None)
|
||
if ucislo is None:
|
||
btn.disabled = True
|
||
btn.opacity = 0.4
|
||
return btn
|
||
btn.ucislo = ucislo
|
||
btn.bind(on_press=lambda b: self._select(b.ucislo))
|
||
return btn
|
||
|
||
def _format_closed_ucet(self, u):
|
||
lines = []
|
||
# --- měna (fallback) potreba najit alesponmenu s s kurzem 1!!!
|
||
unit = (
|
||
getattr(u, "unit", None)
|
||
or getattr(u, "mena", None)
|
||
or getattr(u, "currency", None)
|
||
or "Kč"
|
||
)
|
||
# 1) origin + stůl
|
||
txt = ""
|
||
if getattr(u, "origin", None):
|
||
txt += f"{u.origin}"
|
||
if getattr(u, "stul", None):
|
||
if txt:
|
||
txt += " "
|
||
txt += f"stůl {u.stul}"
|
||
if txt:
|
||
lines.append(txt)
|
||
# 2) číslo účtu + čas uzavření
|
||
txt = ""
|
||
if getattr(u, "ucislo", None):
|
||
txt += f"{u.ucislo}"
|
||
if getattr(u, "autor", None):
|
||
if txt:
|
||
txt += f" | by {u.autor}"
|
||
if txt:
|
||
lines.append(txt)
|
||
txt = ""
|
||
if getattr(u, "closed_at", None): #zatim nech
|
||
if txt:
|
||
txt += " | "
|
||
txt += f"{u.closed_at}"
|
||
if txt:
|
||
lines.append(txt)
|
||
# 3) suma
|
||
if getattr(u,"total_base_currency", None):
|
||
lines.append(f"{u.total_base_currency:,.2f} {unit}")
|
||
if getattr(u, "is_storno", None):
|
||
lines.append(f"Puvodni ucet {u.is_storno}")
|
||
return "\n".join(lines)
|
||
|
||
def _matches_filter(self, u: data.UcetSelect, query: str) -> bool:
|
||
if not query:
|
||
return True
|
||
fields = [
|
||
getattr(u, "ucislo", ""),
|
||
getattr(u, "stul", ""),
|
||
getattr(u, "closed_at", ""),
|
||
getattr(u, "autor", ""),
|
||
getattr(u, "origin", ""),
|
||
f"{getattr(u, 'total_base_currency', 0) or 0:.2f}",
|
||
]
|
||
text = " ".join(str(v or "") for v in fields).lower()
|
||
return query.lower() in text
|
||
|
||
def _on_search_text(self, *_):
|
||
self._render_ucty()
|
||
|
||
def _render_ucty(self):
|
||
if not getattr(self, "grid", None):
|
||
return
|
||
self.grid.clear_widgets()
|
||
query = (self.search_input.text or "").strip()
|
||
ucty = [u for u in self._all_ucty if self._matches_filter(u, query)]
|
||
# seřadit podle čísla účtu vzestupně
|
||
ucty_sorted = sorted(
|
||
ucty,
|
||
key=lambda u: u.ucislo or "", reverse=True )
|
||
for u in ucty_sorted:
|
||
btn = self._create_ucet_button(u)
|
||
if btn:
|
||
self.grid.add_widget(btn)
|
||
Clock.schedule_once(self._update_scroll, 0)
|
||
|
||
def _load_ucty(self, ucty: list[data.UcetSelect]):
|
||
self._all_ucty = list(ucty or [])
|
||
self._render_ucty()
|
||
|
||
def refresh(self):
|
||
ucty = self.get_ucty() or []
|
||
self._load_ucty(ucty)
|
||
|
||
|
||
def load_closed_ucty(self):
|
||
return [u for u in self.load_stoly() if u.closed]
|
||
|