feat: 초기 커밋
- Progress Quest 6.4 Flutter 포팅 프로젝트 - 게임 루프, 상태 관리, UI 구현 - 캐릭터 생성, 인벤토리, 장비, 주문 시스템 - 시장/판매/구매 메커니즘
This commit is contained in:
107
lib/src/features/front/save_picker_dialog.dart
Normal file
107
lib/src/features/front/save_picker_dialog.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
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';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user