""" 顧客選択モーダルコンポーネント Flutter風のModalBottomSheetをFletで実装 """ import sys import os sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import flet as ft from typing import List, Callable, Optional from models.invoice_models import Customer class CustomerPickerModal: """顧客選択モーダル""" def __init__(self, page: ft.Page, customers: List[Customer], on_customer_selected: Callable[[Customer], None], on_customer_deleted: Callable[[Customer], None] = None): self.page = page self.customers = customers self.on_customer_selected = on_customer_selected self.on_customer_deleted = on_customer_deleted self.is_open = False def open(self): """モーダルを開く""" self.is_open = True self.show_modal() def close(self): """モーダルを閉じる""" self.is_open = False self.hide_modal() def show_modal(self): """モーダル表示""" # 検索テキストフィールド search_field = ft.TextField( label="顧客検索", prefix_icon=ft.Icons.SEARCH, on_change=self.filter_customers, expand=True, ) # 顧客リスト customer_list = ft.Column([], scroll=ft.ScrollMode.AUTO, expand=True) # モーダルダイアログ modal_dialog = ft.AlertDialog( title=ft.Text("顧客選択"), content=ft.Column([ search_field, ft.Container(height=10), ft.Container( content=customer_list, height=300, width=400, ), ft.Container(height=10), ft.Button( content=ft.Row([ ft.Icon(ft.Icons.ADD), ft.Text("新規顧客を登録"), ], alignment=ft.MainAxisAlignment.CENTER), on_click=self.add_new_customer, bgcolor=ft.Colors.BLUE_GREY_800, ), ], tight=True), actions=[ ft.TextButton("キャンセル", on_click=lambda _: self.close()), ], actions_alignment=ft.MainAxisAlignment.END, ) # ダイアログを開く self.page.dialog = modal_dialog modal_dialog.open = True self.page.update() # 初期データ表示 self.update_customer_list_simple(customer_list, self.customers) def hide_modal(self): """モーダルを非表示""" self.page.overlay.clear() self.page.update() def filter_customers(self, e=None): """顧客フィルタリング""" search_text = e.control.value.lower() if e else "" filtered_customers = [ customer for customer in self.customers if search_text in customer.name.lower() or search_text in customer.formal_name.lower() ] self.update_customer_list(filtered_customers) def update_customer_list_simple(self, customer_list, customers: List[Customer]): """顧客リスト更新(シンプル版)""" customer_list.controls.clear() for customer in customers: card = self.create_customer_card(customer) customer_list.controls.append(card) self.page.update() def update_customer_list(self, customers: List[Customer]): """顧客リスト更新""" # ダイアログの顧客リストを更新 if hasattr(self.page, 'dialog') and self.page.dialog: customer_list = self.page.dialog.content.controls[2].content self.update_customer_list_simple(customer_list, customers) def create_customer_card(self, customer: Customer) -> ft.Container: """顧客カード作成""" return ft.Container( content=ft.Card( content=ft.Container( content=ft.Column([ ft.Row([ ft.Text( customer.formal_name, size=16, weight=ft.FontWeight.BOLD, expand=True, ), ft.IconButton( ft.Icons.DELETE, on_click=lambda _, c=customer: self.delete_customer(c), icon_color=ft.Colors.RED_400, ), ]), ft.Container(height=5), ft.Text(customer.address, size=12, color=ft.Colors.GREY_600), ft.Text(customer.phone, size=12, color=ft.Colors.GREY_600), ]), padding=ft.padding.all(15), ), elevation=2, ), on_click=lambda _, c=customer: self.select_customer(c), ) def select_customer(self, customer: Customer): """顧客選択""" if self.on_customer_selected: self.on_customer_selected(customer) self.close() def delete_customer(self, customer: Customer): """顧客削除""" if self.on_customer_deleted: self.on_customer_deleted(customer) def add_new_customer(self, e=None): """新規顧客追加""" # TODO: 新規顧客登録画面を開く logging.info("新規顧客登録")