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]