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:
JiWoong Sul
2025-08-29 15:13:56 +09:00
parent d916b281a7
commit 74b13e7080
9 changed files with 0 additions and 1353 deletions

View File

@@ -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,
),
],
);
}
}

View File

@@ -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;
},
),
],
);
}
}

View File

@@ -1,193 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../injection_container.dart';
import 'controllers/rent_controller.dart';
import 'rent_form_dialog.dart';
class RentListScreen extends StatefulWidget {
const RentListScreen({super.key});
@override
State<RentListScreen> createState() => _RentListScreenState();
}
class _RentListScreenState extends State<RentListScreen> {
late final RentController _controller;
final _searchController = TextEditingController();
@override
void initState() {
super.initState();
_controller = getIt<RentController>();
_loadData();
}
@override
void dispose() {
_searchController.dispose();
super.dispose();
}
Future<void> _loadData() async {
await _controller.loadRents();
}
Future<void> _refresh() async {
await _controller.loadRents(refresh: true);
}
void _showCreateDialog() {
showDialog(
context: context,
builder: (context) => RentFormDialog(
onSubmit: (request) async {
final success = await _controller.createRent(
equipmentHistoryId: request.equipmentHistoryId,
startedAt: request.startedAt,
endedAt: request.endedAt,
);
if (success && mounted) {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('임대 계약이 생성되었습니다')),
);
}
return success;
},
),
);
}
void _onSearch(String query) {
_controller.loadRents(search: query.isEmpty ? null : query);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider.value(
value: _controller,
child: Consumer<RentController>(
builder: (context, controller, child) {
return Column(
children: [
// 헤더
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Text(
'임대 관리',
style: Theme.of(context).textTheme.headlineSmall,
),
const Spacer(),
// 검색 필드
SizedBox(
width: 300,
child: TextFormField(
controller: _searchController,
decoration: const InputDecoration(
hintText: '검색...',
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(),
),
onFieldSubmitted: _onSearch,
),
),
const SizedBox(width: 8),
// 새로고침 버튼
IconButton(
onPressed: _refresh,
icon: const Icon(Icons.refresh),
tooltip: '새로고침',
),
const SizedBox(width: 8),
ElevatedButton.icon(
onPressed: _showCreateDialog,
icon: const Icon(Icons.add),
label: const Text('새 임대'),
),
],
),
),
// 콘텐츠
Expanded(
child: controller.isLoading
? const Center(child: CircularProgressIndicator())
: controller.hasError
? Center(child: Text('오류: ${controller.error}'))
: controller.rents.isEmpty
? const Center(child: Text('임대 계약이 없습니다'))
: ListView.builder(
itemCount: controller.rents.length,
itemBuilder: (context, index) {
final rent = controller.rents[index];
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: ListTile(
leading: CircleAvatar(
child: Text(
'${rent.id ?? 0}',
),
),
title: Text('임대 #${rent.id ?? 0}'),
subtitle: Text(
'${_formatDate(rent.startedAt)} ~ ${_formatDate(rent.endedAt)}',
),
trailing: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${_calculateDays(rent.startedAt, rent.endedAt)}',
style: const TextStyle(fontWeight: FontWeight.bold),
),
Text(
controller.getRentStatusDisplayName(controller.getRentStatus(rent)),
style: TextStyle(
color: _getStatusColor(controller.getRentStatus(rent)),
fontSize: 12,
),
),
],
),
),
);
},
),
),
],
);
},
),
),
);
}
Color _getStatusColor(String status) {
switch (status) {
case '진행중':
return Colors.blue;
case '종료':
return Colors.green;
case '예약':
return Colors.orange;
default:
return Colors.grey;
}
}
String _formatDate(DateTime date) {
return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
}
int _calculateDays(DateTime startDate, DateTime endDate) {
return endDate.difference(startDate).inDays;
}
}