refactor: 사용하지 않는 파일 9개 정리
- 코드베이스 분석을 통해 사용되지 않는 파일 식별 및 삭제 - migration, utils, models, screens 등 미사용 파일 제거 - flutter analyze 결과: 63개 → 48개 오류로 개선 - 전체 .dart 파일 수: 365개로 정리 완료 삭제된 파일: - lib/core/migrations/execute_migration.dart - lib/core/utils/login_diagnostics.dart - lib/utils/equipment_display_helper.dart - lib/utils/formatters/business_number_formatter.dart - lib/utils/user_utils.dart - lib/models/user_phone_field.dart - lib/screens/rent/rent_list_screen_simple.dart - lib/screens/common/widgets/category_autocomplete_field.dart - lib/screens/common/widgets/company_branch_dropdown.dart ✅ 빌드 검증 완료: flutter pub get, build_runner 성공 ✅ Phase 10 이후 추가 코드베이스 정리 완료
This commit is contained in:
@@ -1,186 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../custom_widgets.dart'; // AutocompleteDropdown, HighlightText 등 사용
|
||||
|
||||
// 입력 필드 + 자동완성 드롭다운을 하나로 묶은 공통 위젯
|
||||
class CategoryAutocompleteField extends StatefulWidget {
|
||||
// 입력 필드의 힌트 텍스트
|
||||
final String hintText;
|
||||
// 현재 선택된 값
|
||||
final String value;
|
||||
// 항목 리스트
|
||||
final List<String> items;
|
||||
// 필수 입력 여부
|
||||
final bool isRequired;
|
||||
// 선택 시 콜백
|
||||
final void Function(String) onSelect;
|
||||
// 입력값 변경 시 콜백(옵션)
|
||||
final void Function(String)? onChanged;
|
||||
// 비활성화 여부
|
||||
final bool enabled;
|
||||
|
||||
const CategoryAutocompleteField({
|
||||
super.key,
|
||||
required this.hintText,
|
||||
required this.value,
|
||||
required this.items,
|
||||
required this.onSelect,
|
||||
this.isRequired = false,
|
||||
this.onChanged,
|
||||
this.enabled = true,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CategoryAutocompleteField> createState() =>
|
||||
_CategoryAutocompleteFieldState();
|
||||
}
|
||||
|
||||
class _CategoryAutocompleteFieldState extends State<CategoryAutocompleteField> {
|
||||
// 텍스트 입력 컨트롤러
|
||||
late final TextEditingController _controller;
|
||||
// 포커스 노드
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
// 드롭다운 표시 여부
|
||||
bool _showDropdown = false;
|
||||
// 필터링된 항목 리스트
|
||||
List<String> _filteredItems = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TextEditingController(text: widget.value);
|
||||
_filteredItems = List.from(widget.items);
|
||||
_controller.addListener(_onTextChanged);
|
||||
_focusNode.addListener(() {
|
||||
setState(() {
|
||||
if (_focusNode.hasFocus) {
|
||||
_showDropdown = _filteredItems.isNotEmpty;
|
||||
} else {
|
||||
_showDropdown = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant CategoryAutocompleteField oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.value != _controller.text) {
|
||||
_controller.text = widget.value;
|
||||
}
|
||||
if (widget.items != oldWidget.items) {
|
||||
_filteredItems = List.from(widget.items);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// 입력값 변경 시 필터링
|
||||
void _onTextChanged() {
|
||||
final String text = _controller.text;
|
||||
setState(() {
|
||||
if (text.isEmpty) {
|
||||
_filteredItems = List.from(widget.items);
|
||||
} else {
|
||||
_filteredItems =
|
||||
widget.items
|
||||
.where(
|
||||
(item) => item.toLowerCase().contains(text.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
// 시작 부분이 일치하는 항목 우선 정렬
|
||||
_filteredItems.sort((a, b) {
|
||||
bool aStartsWith = a.toLowerCase().startsWith(text.toLowerCase());
|
||||
bool bStartsWith = b.toLowerCase().startsWith(text.toLowerCase());
|
||||
if (aStartsWith && !bStartsWith) return -1;
|
||||
if (!aStartsWith && bStartsWith) return 1;
|
||||
return a.compareTo(b);
|
||||
});
|
||||
}
|
||||
_showDropdown = _filteredItems.isNotEmpty && _focusNode.hasFocus;
|
||||
if (widget.onChanged != null) {
|
||||
widget.onChanged!(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 항목 선택 시 처리
|
||||
void _handleSelect(String value) {
|
||||
setState(() {
|
||||
_controller.text = value;
|
||||
_showDropdown = false;
|
||||
});
|
||||
widget.onSelect(value);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _controller,
|
||||
focusNode: _focusNode,
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.hintText,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 12,
|
||||
),
|
||||
suffixIcon:
|
||||
_controller.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed:
|
||||
widget.enabled
|
||||
? () {
|
||||
setState(() {
|
||||
_controller.clear();
|
||||
_filteredItems = List.from(widget.items);
|
||||
_showDropdown = _focusNode.hasFocus;
|
||||
widget.onSelect('');
|
||||
});
|
||||
}
|
||||
: null,
|
||||
)
|
||||
: IconButton(
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
onPressed:
|
||||
widget.enabled
|
||||
? () {
|
||||
setState(() {
|
||||
_showDropdown = !_showDropdown;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
enabled: widget.enabled,
|
||||
validator: (value) {
|
||||
if (widget.isRequired && (value == null || value.isEmpty)) {
|
||||
return '${widget.hintText}를 선택해주세요';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (!_showDropdown) {
|
||||
_showDropdown = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
AutocompleteDropdown(
|
||||
items: _filteredItems,
|
||||
inputText: _controller.text,
|
||||
onSelect: _handleSelect,
|
||||
showDropdown: _showDropdown,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
// 회사/지점 드롭다운 공통 위젯
|
||||
// 여러 도메인에서 재사용 가능
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../models/company_model.dart';
|
||||
|
||||
class CompanyBranchDropdown extends StatelessWidget {
|
||||
final List<Company> companies;
|
||||
final int? selectedCompanyId;
|
||||
final int? selectedBranchId;
|
||||
final List<Branch> branches;
|
||||
final void Function(int? companyId) onCompanyChanged;
|
||||
final void Function(int? branchId) onBranchChanged;
|
||||
|
||||
const CompanyBranchDropdown({
|
||||
super.key,
|
||||
required this.companies,
|
||||
required this.selectedCompanyId,
|
||||
required this.selectedBranchId,
|
||||
required this.branches,
|
||||
required this.onCompanyChanged,
|
||||
required this.onBranchChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 회사 드롭다운
|
||||
DropdownButtonFormField<int>(
|
||||
value: selectedCompanyId,
|
||||
decoration: const InputDecoration(hintText: '소속 회사를 선택하세요'),
|
||||
items:
|
||||
companies
|
||||
.map(
|
||||
(company) => DropdownMenuItem<int>(
|
||||
value: company.id,
|
||||
child: Text(company.name),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: onCompanyChanged,
|
||||
validator: (value) {
|
||||
if (value == null) {
|
||||
return '소속 회사를 선택해주세요';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 지점 드롭다운 (지점이 있을 때만)
|
||||
if (branches.isNotEmpty)
|
||||
DropdownButtonFormField<int>(
|
||||
value: selectedBranchId,
|
||||
decoration: const InputDecoration(hintText: '소속 지점을 선택하세요'),
|
||||
items:
|
||||
branches
|
||||
.map(
|
||||
(branch) => DropdownMenuItem<int>(
|
||||
value: branch.id,
|
||||
child: Text(branch.name),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: onBranchChanged,
|
||||
validator: (value) {
|
||||
if (branches.isNotEmpty && value == null) {
|
||||
return '소속 지점을 선택해주세요';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user