検索バーを検索窓へ途中
This commit is contained in:
parent
0f86ee14ac
commit
ccd549dc0c
1 changed files with 108 additions and 80 deletions
188
main.py
188
main.py
|
|
@ -243,6 +243,9 @@ class FlutterStyleDashboard:
|
||||||
self._pending_stamp_target: Optional[str] = None
|
self._pending_stamp_target: Optional[str] = None
|
||||||
self._stamp_picker: Optional[ft.FilePicker] = None
|
self._stamp_picker: Optional[ft.FilePicker] = None
|
||||||
self.max_active_bank_accounts = 2
|
self.max_active_bank_accounts = 2
|
||||||
|
self.is_explorer_controls_visible = False
|
||||||
|
self.is_search_overlay_visible = False
|
||||||
|
self._search_field: Optional[ft.TextField] = None
|
||||||
self.edit_button_style = ft.ButtonStyle(
|
self.edit_button_style = ft.ButtonStyle(
|
||||||
bgcolor=ft.Colors.WHITE,
|
bgcolor=ft.Colors.WHITE,
|
||||||
color=ft.Colors.BLUE_GREY_800,
|
color=ft.Colors.BLUE_GREY_800,
|
||||||
|
|
@ -366,6 +369,16 @@ class FlutterStyleDashboard:
|
||||||
visible=False,
|
visible=False,
|
||||||
)
|
)
|
||||||
self.page.overlay.append(self.settings_drawer_overlay)
|
self.page.overlay.append(self.settings_drawer_overlay)
|
||||||
|
self._search_field = ft.TextField(
|
||||||
|
value="",
|
||||||
|
hint_text="顧客名・伝票番号・備考を検索",
|
||||||
|
border=ft.InputBorder.NONE,
|
||||||
|
text_style=ft.TextStyle(size=16, color=ft.Colors.BLUE_GREY_900),
|
||||||
|
cursor_color=ft.Colors.BLUE_GREY_700,
|
||||||
|
on_submit=lambda e: self._apply_search_query(e.control.value),
|
||||||
|
)
|
||||||
|
self.search_overlay = self._build_search_overlay()
|
||||||
|
self.page.overlay.append(self.search_overlay)
|
||||||
|
|
||||||
# 初期表示
|
# 初期表示
|
||||||
self.update_main_content()
|
self.update_main_content()
|
||||||
|
|
@ -788,7 +801,9 @@ class FlutterStyleDashboard:
|
||||||
show_back=False,
|
show_back=False,
|
||||||
show_edit=False,
|
show_edit=False,
|
||||||
trailing_controls=[
|
trailing_controls=[
|
||||||
ft.IconButton(ft.Icons.REFRESH, on_click=lambda _: self.refresh_invoices()),
|
ft.IconButton(ft.Icons.TUNE, tooltip="詳細フィルタ", on_click=self.toggle_explorer_controls),
|
||||||
|
ft.IconButton(ft.Icons.SEARCH, tooltip="検索", on_click=self.open_search_overlay),
|
||||||
|
ft.IconButton(ft.Icons.REFRESH, tooltip="再読込", on_click=lambda _: self.refresh_invoices()),
|
||||||
],
|
],
|
||||||
leading_control=settings_button,
|
leading_control=settings_button,
|
||||||
)
|
)
|
||||||
|
|
@ -806,22 +821,56 @@ class FlutterStyleDashboard:
|
||||||
expand=True,
|
expand=True,
|
||||||
padding=ft.Padding.all(16)
|
padding=ft.Padding.all(16)
|
||||||
),
|
),
|
||||||
# デバッグ用: スナック表示テストボタン(一覧画面下部)
|
|
||||||
ft.Container(
|
|
||||||
content=ft.Row([
|
|
||||||
ft.Button(
|
|
||||||
content=ft.Text("スナックテストを表示"),
|
|
||||||
on_click=lambda _: self._show_snack("テストスナック"),
|
|
||||||
),
|
|
||||||
ft.Text("コンソールに 'show_snack: テストスナック' が出ればハンドラは動作", size=12, color=ft.Colors.BLUE_GREY_600),
|
|
||||||
], spacing=12),
|
|
||||||
padding=ft.Padding.symmetric(horizontal=16, vertical=8),
|
|
||||||
),
|
|
||||||
], expand=True)
|
], expand=True)
|
||||||
|
|
||||||
logging.info("_build_invoice_list_screen: Column作成完了")
|
logging.info("_build_invoice_list_screen: Column作成完了")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def refresh_invoices(self):
|
||||||
|
logging.info("refresh_invoices")
|
||||||
|
try:
|
||||||
|
self.setup_database()
|
||||||
|
self.explorer_state.offset = 0
|
||||||
|
self.update_main_content()
|
||||||
|
self._show_snack("一覧を更新しました", ft.Colors.BLUE_GREY_600)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"refresh_invoices error: {e}")
|
||||||
|
self._show_snack("再読込に失敗しました", ft.Colors.RED_200)
|
||||||
|
|
||||||
|
def toggle_explorer_controls(self, _=None):
|
||||||
|
self.is_explorer_controls_visible = not self.is_explorer_controls_visible
|
||||||
|
self.update_main_content()
|
||||||
|
|
||||||
|
def open_search_overlay(self, _=None):
|
||||||
|
if not hasattr(self, "search_overlay"):
|
||||||
|
return
|
||||||
|
self.is_search_overlay_visible = True
|
||||||
|
self._search_field.value = self.explorer_state.query
|
||||||
|
self.search_overlay.visible = True
|
||||||
|
self.page.update()
|
||||||
|
self.page.set_focus(self._search_field)
|
||||||
|
|
||||||
|
def close_search_overlay(self, _=None):
|
||||||
|
if not hasattr(self, "search_overlay"):
|
||||||
|
return
|
||||||
|
self.is_search_overlay_visible = False
|
||||||
|
self.search_overlay.visible = False
|
||||||
|
self.page.update()
|
||||||
|
|
||||||
|
def _apply_search_query(self, value: Optional[str] = None):
|
||||||
|
query = (value if value is not None else self._search_field.value or "").strip()
|
||||||
|
self.explorer_state.query = query
|
||||||
|
self.explorer_state.offset = 0
|
||||||
|
self.close_search_overlay()
|
||||||
|
self.update_main_content()
|
||||||
|
|
||||||
|
def _prefill_search_keyword(self, keyword: str):
|
||||||
|
if not self._search_field:
|
||||||
|
return
|
||||||
|
self._search_field.value = keyword
|
||||||
|
self.page.update()
|
||||||
|
self.page.set_focus(self._search_field)
|
||||||
|
|
||||||
@log_wrap("_build_invoice_detail_screen")
|
@log_wrap("_build_invoice_detail_screen")
|
||||||
def _build_invoice_detail_screen(self) -> ft.Column:
|
def _build_invoice_detail_screen(self) -> ft.Column:
|
||||||
"""伝票詳細画面を構築"""
|
"""伝票詳細画面を構築"""
|
||||||
|
|
@ -1034,82 +1083,61 @@ class FlutterStyleDashboard:
|
||||||
logging.error(f"チェーン検証エラー: {e}")
|
logging.error(f"チェーン検証エラー: {e}")
|
||||||
|
|
||||||
explorer_controls = ft.Container(
|
explorer_controls = ft.Container(
|
||||||
content=ft.Column(
|
content=ft.Row(
|
||||||
[
|
[
|
||||||
ft.Row(
|
ft.TextField(
|
||||||
[
|
value=self.explorer_state.query,
|
||||||
ft.TextField(
|
hint_text="",
|
||||||
label="検索",
|
prefix_icon=ft.Icons.SEARCH,
|
||||||
hint_text="伝票番号 / 顧客名 / 種別 / 備考",
|
on_change=on_query_change,
|
||||||
value=self.explorer_state.query,
|
expand=True,
|
||||||
prefix_icon=ft.Icons.SEARCH,
|
dense=True,
|
||||||
on_change=on_query_change,
|
height=38,
|
||||||
expand=True,
|
border=ft.InputBorder.OUTLINE,
|
||||||
dense=True,
|
text_style=ft.TextStyle(size=12),
|
||||||
),
|
content_padding=ft.Padding.symmetric(horizontal=8, vertical=0),
|
||||||
ft.Dropdown(
|
|
||||||
label="期間",
|
|
||||||
value=self.explorer_state.period_key,
|
|
||||||
options=[
|
|
||||||
ft.dropdown.Option(k, v)
|
|
||||||
for k, v in EXPLORER_PERIODS.items()
|
|
||||||
],
|
|
||||||
on_select=on_period_change,
|
|
||||||
width=140,
|
|
||||||
dense=True,
|
|
||||||
),
|
|
||||||
ft.Dropdown(
|
|
||||||
label="ソート",
|
|
||||||
value=self.explorer_state.sort_key,
|
|
||||||
options=[
|
|
||||||
ft.dropdown.Option(k, v)
|
|
||||||
for k, v in EXPLORER_SORTS.items()
|
|
||||||
],
|
|
||||||
on_select=on_sort_change,
|
|
||||||
width=150,
|
|
||||||
dense=True,
|
|
||||||
),
|
|
||||||
ft.IconButton(
|
|
||||||
icon=ft.Icons.ARROW_DOWNWARD if self.explorer_state.sort_desc else ft.Icons.ARROW_UPWARD,
|
|
||||||
tooltip="並び順切替",
|
|
||||||
on_click=on_sort_direction_toggle,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
spacing=8,
|
|
||||||
),
|
),
|
||||||
ft.Row(
|
ft.Dropdown(
|
||||||
[
|
value=self.explorer_state.period_key,
|
||||||
ft.Text("赤伝", size=10, color=ft.Colors.WHITE),
|
options=[
|
||||||
ft.Switch(
|
ft.dropdown.Option(k, v)
|
||||||
value=self.explorer_state.include_offsets,
|
for k, v in EXPLORER_PERIODS.items()
|
||||||
on_change=on_toggle_offsets,
|
|
||||||
),
|
|
||||||
ft.Container(width=10),
|
|
||||||
ft.Text("保存後詳細に留まる", size=10, color=ft.Colors.WHITE),
|
|
||||||
ft.Switch(
|
|
||||||
value=self.stay_on_detail_after_save,
|
|
||||||
on_change=lambda e: setattr(self, 'stay_on_detail_after_save', bool(e.control.value)),
|
|
||||||
),
|
|
||||||
ft.Text(
|
|
||||||
f"表示中: {len(slips)}件 / offset={self.explorer_state.offset}",
|
|
||||||
size=12,
|
|
||||||
color=ft.Colors.BLUE_GREY_700,
|
|
||||||
),
|
|
||||||
ft.Container(expand=True),
|
|
||||||
ft.TextButton("◀ 前", on_click=on_prev_page),
|
|
||||||
ft.TextButton("次 ▶", on_click=on_next_page),
|
|
||||||
ft.OutlinedButton("マスタ編集", on_click=self.open_master_editor),
|
|
||||||
ft.OutlinedButton("チェーン検証", on_click=on_verify_chain),
|
|
||||||
],
|
],
|
||||||
alignment=ft.MainAxisAlignment.START,
|
on_select=on_period_change,
|
||||||
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
width=120,
|
||||||
|
dense=True,
|
||||||
|
border=ft.InputBorder.OUTLINE,
|
||||||
),
|
),
|
||||||
|
ft.Dropdown(
|
||||||
|
value=self.explorer_state.sort_key,
|
||||||
|
options=[
|
||||||
|
ft.dropdown.Option(k, v)
|
||||||
|
for k, v in EXPLORER_SORTS.items()
|
||||||
|
],
|
||||||
|
on_select=on_sort_change,
|
||||||
|
width=130,
|
||||||
|
dense=True,
|
||||||
|
border=ft.InputBorder.OUTLINE,
|
||||||
|
),
|
||||||
|
ft.IconButton(
|
||||||
|
icon=ft.Icons.ARROW_DOWNWARD if self.explorer_state.sort_desc else ft.Icons.ARROW_UPWARD,
|
||||||
|
tooltip="並び順切替",
|
||||||
|
on_click=on_sort_direction_toggle,
|
||||||
|
),
|
||||||
|
ft.Text(
|
||||||
|
f"{len(slips)}件", size=12, color=ft.Colors.BLUE_GREY_600,
|
||||||
|
),
|
||||||
|
ft.TextButton("◀", on_click=on_prev_page, tooltip="前へ"),
|
||||||
|
ft.TextButton("▶", on_click=on_next_page, tooltip="次へ"),
|
||||||
|
ft.IconButton(ft.Icons.VERIFIED, tooltip="チェーン検証", on_click=on_verify_chain),
|
||||||
],
|
],
|
||||||
spacing=6,
|
spacing=8,
|
||||||
|
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||||||
),
|
),
|
||||||
padding=ft.Padding.all(10),
|
padding=ft.Padding.symmetric(horizontal=10, vertical=8),
|
||||||
bgcolor=ft.Colors.BLUE_GREY_50,
|
bgcolor=ft.Colors.BLUE_GREY_50,
|
||||||
border_radius=8,
|
border_radius=8,
|
||||||
|
visible=self.is_explorer_controls_visible,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not slips:
|
if not slips:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue