fix(new-character): 캐릭터 생성 화면 UX 개선

- 굴리기 버튼 연속 클릭 방지 (100ms 딜레이)
- 스크롤 애니메이션 대신 jumpTo 사용 (WASM 안정성)
- Row를 Wrap으로 변경하여 버튼 레이아웃 개선
This commit is contained in:
JiWoong Sul
2025-12-26 16:12:29 +09:00
parent e1e310c162
commit 74a159d534

View File

@@ -61,6 +61,9 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
// 테스트 모드 (웹에서 모바일 캐로셀 레이아웃 활성화) // 테스트 모드 (웹에서 모바일 캐로셀 레이아웃 활성화)
bool _testModeEnabled = false; bool _testModeEnabled = false;
// 굴리기 버튼 연속 클릭 방지
bool _isRolling = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -96,23 +99,22 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
const itemHeight = 48.0; const itemHeight = 48.0;
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
// 스크롤 애니메이션 대신 즉시 점프 (WASM 모드 안정성)
if (_raceScrollController.hasClients) { if (_raceScrollController.hasClients) {
final raceOffset = _selectedRaceIndex * itemHeight; final raceOffset = _selectedRaceIndex * itemHeight;
_raceScrollController.animateTo( _raceScrollController.jumpTo(
raceOffset.clamp(0.0, _raceScrollController.position.maxScrollExtent), raceOffset.clamp(0.0, _raceScrollController.position.maxScrollExtent),
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
); );
} }
if (_klassScrollController.hasClients) { if (_klassScrollController.hasClients) {
final klassOffset = _selectedKlassIndex * itemHeight; final klassOffset = _selectedKlassIndex * itemHeight;
_klassScrollController.animateTo( _klassScrollController.jumpTo(
klassOffset.clamp( klassOffset.clamp(
0.0, 0.0,
_klassScrollController.position.maxScrollExtent, _klassScrollController.position.maxScrollExtent,
), ),
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
); );
} }
}); });
@@ -134,6 +136,10 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
/// Re-Roll 버튼 클릭 /// Re-Roll 버튼 클릭
/// 원본 NewGuy.pas RerollClick: 스탯, 종족, 클래스 모두 랜덤화 /// 원본 NewGuy.pas RerollClick: 스탯, 종족, 클래스 모두 랜덤화
void _onReroll() { void _onReroll() {
// 연속 클릭 방지
if (_isRolling) return;
_isRolling = true;
// 현재 시드를 이력에 저장 // 현재 시드를 이력에 저장
_rollHistory.insert(0, _currentSeed); _rollHistory.insert(0, _currentSeed);
@@ -156,6 +162,11 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
// 선택된 종족/직업으로 스크롤 // 선택된 종족/직업으로 스크롤
_scrollToSelectedItems(); _scrollToSelectedItems();
// 짧은 딜레이 후 다시 클릭 가능
Future.delayed(const Duration(milliseconds: 100), () {
if (mounted) _isRolling = false;
});
} }
/// Unroll 버튼 클릭 (이전 롤로 복원) /// Unroll 버튼 클릭 (이전 롤로 복원)
@@ -401,8 +412,10 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
const SizedBox(height: 12), const SizedBox(height: 12),
// Roll 버튼들 // Roll 버튼들
Row( Wrap(
mainAxisAlignment: MainAxisAlignment.center, alignment: WrapAlignment.center,
spacing: 16,
runSpacing: 8,
children: [ children: [
OutlinedButton.icon( OutlinedButton.icon(
onPressed: _onUnroll, onPressed: _onUnroll,
@@ -412,7 +425,6 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
foregroundColor: _rollHistory.isEmpty ? Colors.grey : null, foregroundColor: _rollHistory.isEmpty ? Colors.grey : null,
), ),
), ),
const SizedBox(width: 16),
FilledButton.icon( FilledButton.icon(
onPressed: _onReroll, onPressed: _onReroll,
icon: const Icon(Icons.casino), icon: const Icon(Icons.casino),