// Version: 1.0 - 汎用マスタ編集フィールド(Flutter 標準) import 'package:flutter/material.dart'; /// マスタ編集用の統一 TextField class MasterTextField extends StatelessWidget { final String label; final TextEditingController controller; final String? hint; final TextInputType keyboardType; final bool obscureText; final int maxLines; final TextInputAction textInputAction; final FormFieldValidator? validator; // TextEditingController を直接使うため、onChanged は不要。nullable の形に定義する final void Function(String)? onChanged; const MasterTextField({ super.key, required this.label, required this.controller, this.hint, this.keyboardType = TextInputType.text, this.obscureText = false, this.maxLines = 1, this.textInputAction = TextInputAction.next, this.validator, this.onChanged, }); @override Widget build(BuildContext context) { return TextFormField( controller: controller, decoration: InputDecoration( labelText: label, hintText: hint, border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), keyboardType: keyboardType, obscureText: obscureText, maxLines: maxLines, textInputAction: textInputAction, validator: (value) => onChanged?.call(value) ?? validator?.call(value), onChanged: onChanged, ); } } /// マスタ編集用の数値入力 TextField class MasterNumberField extends StatelessWidget { final String label; final TextEditingController controller; final String? hint; final FormFieldValidator? validator; // Nullable の形で定義 final void Function(String)? onChanged; const MasterNumberField({ super.key, required this.label, required this.controller, this.hint, this.validator, this.onChanged, }); @override Widget build(BuildContext context) { return TextFormField( controller: controller, decoration: InputDecoration( labelText: label, hintText: hint, border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), keyboardType: TextInputType.number, validator: (value) => onChanged?.call(value) ?? validator?.call(value), onChanged: onChanged, ); } } /// ドロップダウンフィールド class MasterDropdownField extends StatelessWidget { final String label; final TextEditingController controller; final T? initialSelectedValue; final List dataSource; final FormFieldValidator? validator; // DropdownButtonFormField の onChanged は void Function(T)? を要求 final void Function(T)? onChanged; const MasterDropdownField({ super.key, required this.label, required this.controller, this.initialSelectedValue, required this.dataSource, this.validator, this.onChanged, }); @override Widget build(BuildContext context) { final items = dataSource.map((value) => DropdownMenuItem( value: value, child: Text(value.toString()), )).toList(); return DropdownButtonFormField( decoration: InputDecoration( labelText: label, hintText: '選択してください', border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), value: initialSelectedValue != null ? initialSelectedValue : null, items: items, onChanged: onChanged, ); } } /// テキストエリアフィールド(長文章用) class MasterTextArea extends StatelessWidget { final String label; final TextEditingController controller; final String? hint; final FormFieldValidator? validator; // Nullable の形で定義 final void Function(String)? onChanged; final bool readOnly; const MasterTextArea({ super.key, required this.label, required this.controller, this.hint, this.validator, this.onChanged, this.readOnly = false, }); @override Widget build(BuildContext context) { return TextFormField( controller: controller, decoration: InputDecoration( labelText: label, hintText: hint, border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), maxLines: 4, readOnly: readOnly, validator: (value) => onChanged?.call(value) ?? validator?.call(value), onChanged: onChanged, ); } } /// チェックボックスフィールド(フラグ用) class MasterCheckBox extends StatelessWidget { final String label; final bool initialValue; final FormFieldValidator? validator; // SwitchListTile の onChanged は void Function(bool)? を要求 // Validator とコールバックを分離する形に final VoidCallback? onCheckedCallback; const MasterCheckBox({ super.key, required this.label, required this.initialValue, this.validator, this.onCheckedCallback, }); @override Widget build(BuildContext context) { return SwitchListTile( title: Text(label), subtitle: initialValue ? const Text('有効') : const Text('無効'), value: initialValue, onChanged: (value) { if (validator?.call(value) != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(validator!.call(value) ?? ''), backgroundColor: Colors.red), ); } else if (onCheckedCallback?.call() ?? false) { onCheckedCallback?.call(); } }, ); } }