From 0420e23939eabbc9c3578994d518d61d4dfe2940 Mon Sep 17 00:00:00 2001 From: Horoli Date: Sun, 15 Feb 2026 15:47:39 +0900 Subject: [PATCH] update --- lib/providers/settings_provider.dart | 21 +++++++ lib/screens/settings_screen.dart | 87 ++++++++++++++++++++++++++++ lib/widgets/battle/shake_widget.dart | 22 +++++-- prompt/69_global_shake_settings.md | 27 +++++++++ 4 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 prompt/69_global_shake_settings.md diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index 8af8404..51354ea 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -7,9 +7,14 @@ class SettingsProvider with ChangeNotifier { bool _enableEnemyAnimations = true; // Default: Enabled double _attackAnimScale = 5.0; // Default: 5.0 + double _shakeOffset = 30.0; // Default: 30.0 + double _shakeCount = + 3.0; // Default: 3.0 (using double for slider convenience, cast to int where needed) bool get enableEnemyAnimations => _enableEnemyAnimations; double get attackAnimScale => _attackAnimScale; + double get shakeOffset => _shakeOffset; + double get shakeCount => _shakeCount; SettingsProvider() { _loadSettings(); @@ -19,6 +24,8 @@ class SettingsProvider with ChangeNotifier { final prefs = await SharedPreferences.getInstance(); _enableEnemyAnimations = prefs.getBool(_keyEnemyAnim) ?? true; _attackAnimScale = prefs.getDouble(_keyAttackAnimScale) ?? 5.0; + _shakeOffset = prefs.getDouble('settings_shake_offset') ?? 30.0; + _shakeCount = prefs.getDouble('settings_shake_count') ?? 3.0; notifyListeners(); } @@ -35,4 +42,18 @@ class SettingsProvider with ChangeNotifier { final prefs = await SharedPreferences.getInstance(); await prefs.setDouble(_keyAttackAnimScale, value); } + + Future setShakeOffset(double value) async { + _shakeOffset = value; + notifyListeners(); + final prefs = await SharedPreferences.getInstance(); + await prefs.setDouble('settings_shake_offset', value); + } + + Future setShakeCount(double value) async { + _shakeCount = value; + notifyListeners(); + final prefs = await SharedPreferences.getInstance(); + await prefs.setDouble('settings_shake_count', value); + } } diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index e9e1284..52ac770 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -84,6 +84,93 @@ class SettingsScreen extends StatelessWidget { ); }, ), + Consumer( + builder: (context, settings, child) { + return SizedBox( + width: 300, + child: Column( + children: [ + const SizedBox(height: 20), + const Text( + 'Shake Offset', + style: TextStyle(color: ThemeConfig.textColorWhite), + ), + Row( + children: [ + const Text( + '0', + style: TextStyle(color: ThemeConfig.textColorGrey), + ), + Expanded( + child: Slider( + value: settings.shakeOffset, + min: 0.0, + max: 100.0, + divisions: 100, + label: settings.shakeOffset.toStringAsFixed(1), + activeColor: ThemeConfig.btnActionActive, + inactiveColor: ThemeConfig.textColorGrey, + onChanged: (value) { + settings.setShakeOffset(value); + }, + ), + ), + const Text( + '100', + style: TextStyle(color: ThemeConfig.textColorGrey), + ), + ], + ), + Text( + 'Current: ${settings.shakeOffset.toStringAsFixed(1)}', + style: const TextStyle( + color: ThemeConfig.textColorWhite, + fontSize: 12, + ), + ), + const SizedBox(height: 20), + const Text( + 'Shake Count', + style: TextStyle(color: ThemeConfig.textColorWhite), + ), + Row( + children: [ + const Text( + '1', + style: TextStyle(color: ThemeConfig.textColorGrey), + ), + Expanded( + child: Slider( + value: settings.shakeCount, + min: 1.0, + max: 10.0, + divisions: 9, + label: settings.shakeCount.toStringAsFixed(0), + activeColor: ThemeConfig.btnActionActive, + inactiveColor: ThemeConfig.textColorGrey, + onChanged: (value) { + settings.setShakeCount(value); + }, + ), + ), + const Text( + '10', + style: TextStyle(color: ThemeConfig.textColorGrey), + ), + ], + ), + Text( + 'Current: ${settings.shakeCount.toStringAsFixed(0)}', + style: const TextStyle( + color: ThemeConfig.textColorWhite, + fontSize: 12, + ), + ), + ], + ), + ); + }, + ), // const SizedBox(height: 20), // const Text( diff --git a/lib/widgets/battle/shake_widget.dart b/lib/widgets/battle/shake_widget.dart index 7456a4a..708f15d 100644 --- a/lib/widgets/battle/shake_widget.dart +++ b/lib/widgets/battle/shake_widget.dart @@ -1,5 +1,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../providers/settings_provider.dart'; class ShakeWidget extends StatefulWidget { final Widget child; @@ -10,7 +12,7 @@ class ShakeWidget extends StatefulWidget { const ShakeWidget({ super.key, required this.child, - this.shakeOffset = 10.0, + this.shakeOffset = 30.0, this.shakeCount = 3, this.duration = const Duration(milliseconds: 400), }); @@ -46,14 +48,24 @@ class ShakeWidgetState extends State @override Widget build(BuildContext context) { + // Read settings from provider (listen: false because we only read in build, + // actually we want to listen to updates if settings change while looking at it? + // But usually ShakeWidget is in BattleScreen. + // However, the previous implementation used `widget.shakeCount` and `widget.shakeOffset`. + // We should prefer provider values if available, or allow overrides? + // The prompt says "shakeWidget에서 shakeCount, shakeOffset을 settings에서 설정할 수 있게 globalOption으로 설정해야해." + // So we use Provider values. + + final settings = context.watch(); + final shakeCount = settings.shakeCount; + final shakeOffset = settings.shakeOffset; + return AnimatedBuilder( animation: _controller, builder: (context, child) { - final double sineValue = sin( - widget.shakeCount * 2 * pi * _controller.value, - ); + final double sineValue = sin(shakeCount * 2 * pi * _controller.value); return Transform.translate( - offset: Offset(sineValue * widget.shakeOffset, 0), + offset: Offset(sineValue * shakeOffset, 0), child: child, ); }, diff --git a/prompt/69_global_shake_settings.md b/prompt/69_global_shake_settings.md new file mode 100644 index 0000000..0a0c637 --- /dev/null +++ b/prompt/69_global_shake_settings.md @@ -0,0 +1,27 @@ +# Task: Global Shake Settings + +**Goal**: Make `shakeCount` and `shakeOffset` in `ShakeWidget` configurable via global settings, similar to `attackAnimationScale`. + +## Context +Currently, `ShakeWidget` uses hardcoded defaults or constructor parameters for `shakeOffset` and `shakeCount`. The user wants to adjust these values globally from the Settings screen to fine-tune the visual feedback. + +## Requirements + +1. **Settings Provider Updates**: + - Add `shakeOffset` (double, default 30.0). + - Add `shakeCount` (int, default 3). + - Implement persistence using `SharedPreferences`. + +2. **Settings UI**: + - Add sliders to the Settings screen to control these values. + - `Shake Offset`: Range approx 0-100? + - `Shake Count`: Range approx 1-10? + +3. **ShakeWidget Updates**: + - Consume `SettingsProvider` to get the global values. + - Apply these values to the shake animation logic. + +## Plan +1. Modify `lib/providers/settings_provider.dart` to add the new settings. +2. Modify `lib/screens/settings_screen.dart` to add the sliders. +3. Modify `lib/widgets/battle/shake_widget.dart` to use the provider.