이벤트 가져오기 위젯 테스트 추가 및 테스트 훅 도입

This commit is contained in:
2025-09-12 06:33:44 +09:00
parent 107abc963f
commit a5f2544d11
121 changed files with 39277 additions and 3911 deletions
+28
View File
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
class DialogActions {
static List<Widget> confirm({
required VoidCallback onConfirm,
required VoidCallback onCancel,
String confirmText = '확인',
String cancelText = '취소',
bool destructive = false,
}) {
return [
TextButton(
onPressed: onCancel,
child: Text(cancelText),
),
ElevatedButton(
style: destructive
? ElevatedButton.styleFrom(
backgroundColor: Colors.redAccent,
foregroundColor: Colors.white,
)
: null,
onPressed: onConfirm,
child: Text(confirmText),
),
];
}
}
@@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import '../widgets/dialog_actions.dart';
class ImportResultDialog extends StatelessWidget {
final String fileName;
final int processedRows;
final int createdCount;
final int invalidRows;
final List<String> invalidRowIndices;
final Map<String, String> invalidRowReasons;
final VoidCallback onClose;
const ImportResultDialog({
super.key,
required this.fileName,
required this.processedRows,
required this.createdCount,
required this.invalidRows,
required this.invalidRowIndices,
required this.invalidRowReasons,
required this.onClose,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('파일 처리 결과'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('파일명: $fileName'),
const SizedBox(height: 8),
Text('처리된 행: $processedRows개'),
Text('생성된 이벤트: $createdCount개'),
if (invalidRows > 0) ...[
const SizedBox(height: 8),
Text('유효하지 않은 행: $invalidRows개', style: const TextStyle(color: Colors.red)),
if (invalidRowIndices.isNotEmpty)
Text(
'실패 행(최대 10개 미리보기): ${invalidRowIndices.take(10).join(', ')}',
style: const TextStyle(fontSize: 12, color: Colors.redAccent),
),
if (invalidRowReasons.isNotEmpty) ...[
const SizedBox(height: 6),
const Text('실패 사유(일부):', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600)),
...invalidRowReasons.entries.take(5).map(
(e) => Text('${e.key}: ${e.value}', style: const TextStyle(fontSize: 12, color: Colors.redAccent)),
),
if (invalidRowReasons.length > 5)
Text('... 외 ${invalidRowReasons.length - 5}', style: const TextStyle(fontSize: 12, color: Colors.redAccent)),
],
],
],
),
actions: DialogActions.confirm(
onCancel: onClose,
onConfirm: onClose,
confirmText: '닫기',
),
);
}
}
+54
View File
@@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import '../models/member_model.dart';
import '../utils/enum_mappings.dart';
class OwnerDropdown extends StatelessWidget {
const OwnerDropdown({
super.key,
required this.members,
required this.value,
required this.onChanged,
this.enabled = true,
this.onItemsBuilt,
});
final List<Member> members;
final String? value;
final ValueChanged<String?> onChanged;
final bool enabled;
/// 테스트 전용: 빌드된 항목 수를 알리기 위한 콜백(프로덕션에서는 사용하지 않음)
final ValueChanged<int>? onItemsBuilt;
@override
Widget build(BuildContext context) {
final items = members.map((member) {
return DropdownMenuItem<String>(
value: member.userId,
child: Text(
'${member.name} (${getMemberTypeLabel(member.memberType)})',
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
);
}).toList();
// 테스트에서만 사용
if (onItemsBuilt != null) {
// scheduleMicrotask로 프레임 안전하게 호출
Future.microtask(() => onItemsBuilt!(items.length));
}
return DropdownButtonFormField<String>(
decoration: const InputDecoration(
labelText: '모임장 설정',
border: OutlineInputBorder(),
),
isExpanded: true,
value: value,
items: items,
onChanged: enabled ? onChanged : null,
);
}
}
+7 -7
View File
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
/// PrimeVue 스타일의 뱃지 위젯
///
///
/// [label] - 뱃지에 표시할 텍스트
/// [color] - 뱃지의 배경색
/// [icon] - 뱃지 앞에 표시할 아이콘 (선택사항)
@@ -19,7 +19,7 @@ class PrimeBadge extends StatelessWidget {
final bool rounded;
const PrimeBadge({
Key? key,
super.key,
required this.label,
this.color,
this.icon,
@@ -27,22 +27,22 @@ class PrimeBadge extends StatelessWidget {
this.size = 'normal',
this.outlined = false,
this.rounded = true,
}) : super(key: key);
});
@override
Widget build(BuildContext context) {
// 색상 결정 (severity 또는 직접 지정된 색상)
Color backgroundColor = _getBackgroundColor();
Color textColor = _getTextColor(backgroundColor);
// 크기에 따른 패딩 및 폰트 크기 설정
EdgeInsets padding = _getPadding();
double fontSize = _getFontSize();
double iconSize = _getIconSize();
// 테두리 반경 설정
double borderRadius = rounded ? 16.0 : 4.0;
return Container(
padding: padding,
decoration: BoxDecoration(
@@ -78,7 +78,7 @@ class PrimeBadge extends StatelessWidget {
if (color != null) {
return color!;
}
switch (severity) {
case 'info':
return Colors.blue;
@@ -16,8 +16,8 @@ class SubscriptionAlertWidget extends StatelessWidget {
listen: true,
);
// 구독 서비스 가져오기
final subscriptionService = Provider.of<SubscriptionService>(
// 구독 서비스 가져오기 (현재 위젯에서는 직접 사용하지 않음)
Provider.of<SubscriptionService>(
context,
listen: false,
);