Files
asciinevrdie/lib/src/features/front/save_picker_dialog.dart
JiWoong Sul 08054d97c1 feat: 초기 커밋
- Progress Quest 6.4 Flutter 포팅 프로젝트
- 게임 루프, 상태 관리, UI 구현
- 캐릭터 생성, 인벤토리, 장비, 주문 시스템
- 시장/판매/구매 메커니즘
2025-12-09 17:24:04 +09:00

108 lines
3.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:askiineverdie/src/core/storage/save_service.dart'
show SaveFileInfo;
/// 저장 파일 선택 다이얼로그
/// 선택된 파일명을 반환하거나, 취소 시 null 반환
class SavePickerDialog extends StatelessWidget {
const SavePickerDialog({super.key, required this.saves});
final List<SaveFileInfo> saves;
/// 다이얼로그 표시 및 결과 반환
static Future<String?> show(
BuildContext context,
List<SaveFileInfo> saves,
) async {
if (saves.isEmpty) {
// 저장 파일이 없으면 안내 메시지
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('저장된 게임이 없습니다.')));
return null;
}
return showDialog<String>(
context: context,
builder: (context) => SavePickerDialog(saves: saves),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
return AlertDialog(
title: Row(
children: [
Icon(Icons.folder_open, color: colorScheme.primary),
const SizedBox(width: 12),
const Text('Load Game'),
],
),
content: SizedBox(
width: 400,
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 400),
child: ListView.separated(
shrinkWrap: true,
itemCount: saves.length,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (context, index) {
final save = saves[index];
return _SaveListTile(
save: save,
onTap: () => Navigator.of(context).pop(save.fileName),
);
},
),
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
child: const Text('Cancel'),
),
],
);
}
}
class _SaveListTile extends StatelessWidget {
const _SaveListTile({required this.save, required this.onTap});
final SaveFileInfo save;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final dateFormat = DateFormat('yyyy-MM-dd HH:mm');
return ListTile(
leading: const Icon(Icons.save),
title: Text(
save.displayName,
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
subtitle: Text(
'${dateFormat.format(save.modifiedAt)} · ${_formatSize(save.sizeBytes)}',
style: theme.textTheme.bodySmall,
),
trailing: const Icon(Icons.chevron_right),
onTap: onTap,
);
}
String _formatSize(int bytes) {
if (bytes < 1024) return '$bytes B';
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
}
}