- Progress Quest 6.4 Flutter 포팅 프로젝트 - 게임 루프, 상태 관리, UI 구현 - 캐릭터 생성, 인벤토리, 장비, 주문 시스템 - 시장/판매/구매 메커니즘
108 lines
3.0 KiB
Dart
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';
|
|
}
|
|
}
|