diff --git a/lib/screens/features/sommelier_screen.dart b/lib/screens/features/sommelier_screen.dart index b49bffd..81e8d5a 100644 --- a/lib/screens/features/sommelier_screen.dart +++ b/lib/screens/features/sommelier_screen.dart @@ -91,7 +91,29 @@ class _SommelierScreenState extends ConsumerState { userProfile.gender ); - return SingleChildScrollView( + return Stack( + children: [ + // Ambient Glow — 右上の薄い光 + Positioned( + top: -60, + right: -60, + child: IgnorePointer( + child: Container( + width: 280, + height: 280, + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: RadialGradient( + colors: [ + Theme.of(context).extension()!.brandAccent.withValues(alpha: 0.07), + Colors.transparent, + ], + ), + ), + ), + ), + ), + SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -122,7 +144,9 @@ class _SommelierScreenState extends ConsumerState { const SizedBox(height: 32), ], ), - ); + ), // SingleChildScrollView + ], // Stack children + ); // Stack }, loading: () => const Center(child: CircularProgressIndicator()), error: (err, stack) => ErrorRetryWidget( diff --git a/lib/screens/soul_screen.dart b/lib/screens/soul_screen.dart index a2edfd3..9b3025d 100644 --- a/lib/screens/soul_screen.dart +++ b/lib/screens/soul_screen.dart @@ -34,7 +34,29 @@ class _SoulScreenState extends ConsumerState { title: Text(t['myPage']), centerTitle: true, ), - body: ListView( + body: Stack( + children: [ + // Ambient Glow — 左上の薄い光 + Positioned( + top: -80, + left: -60, + child: IgnorePointer( + child: Container( + width: 320, + height: 320, + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: RadialGradient( + colors: [ + appColors.brandPrimary.withValues(alpha: 0.07), + Colors.transparent, + ], + ), + ), + ), + ), + ), + ListView( padding: const EdgeInsets.all(16), children: [ @@ -126,7 +148,9 @@ class _SoulScreenState extends ConsumerState { const SizedBox(height: 24), BackupSettingsSection(), ], - ), + ), // ListView + ], // Stack children + ), // Stack ); } diff --git a/lib/widgets/common/pressable.dart b/lib/widgets/common/pressable.dart new file mode 100644 index 0000000..16ea056 --- /dev/null +++ b/lib/widgets/common/pressable.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +/// タップ時に軽く沈み込むスケールアニメーションを付与するラッパー。 +/// 既存の GestureDetector / InkWell の代わりに使用する。 +class Pressable extends StatefulWidget { + const Pressable({ + super.key, + required this.child, + this.onTap, + this.scale = 0.97, + this.duration = const Duration(milliseconds: 100), + }); + + final Widget child; + final VoidCallback? onTap; + final double scale; + final Duration duration; + + @override + State createState() => _PressableState(); +} + +class _PressableState extends State { + bool _pressed = false; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: (_) => setState(() => _pressed = true), + onTapUp: (_) { + setState(() => _pressed = false); + widget.onTap?.call(); + }, + onTapCancel: () => setState(() => _pressed = false), + child: AnimatedScale( + scale: _pressed ? widget.scale : 1.0, + duration: widget.duration, + curve: Curves.easeOut, + child: widget.child, + ), + ); + } +} diff --git a/lib/widgets/gamification/level_title_card.dart b/lib/widgets/gamification/level_title_card.dart index e48fad8..18b49e3 100644 --- a/lib/widgets/gamification/level_title_card.dart +++ b/lib/widgets/gamification/level_title_card.dart @@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../providers/theme_provider.dart'; import 'package:google_fonts/google_fonts.dart'; import '../contextual_help_icon.dart'; +import '../common/pressable.dart'; import '../../theme/app_colors.dart'; class LevelTitleCard extends ConsumerWidget { @@ -20,7 +21,8 @@ class LevelTitleCard extends ConsumerWidget { final progress = userProfile.nextLevelProgress; final expToNext = userProfile.expToNextLevel; - return Container( + return Pressable( + child: Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -58,8 +60,10 @@ class LevelTitleCard extends ConsumerWidget { children: [ Text( '現在の称号', - style: Theme.of(context).textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.bold, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + fontWeight: FontWeight.w500, + color: appColors.textSecondary, + letterSpacing: 0.5, ), ), const SizedBox(width: 4), @@ -77,9 +81,10 @@ class LevelTitleCard extends ConsumerWidget { child: Text( title, style: GoogleFonts.zenOldMincho( - fontSize: 28, + fontSize: 36, fontWeight: FontWeight.bold, color: appColors.brandPrimary, + height: 1.1, ), ), ), @@ -142,9 +147,10 @@ class LevelTitleCard extends ConsumerWidget { ), ], ), - ); + ), // Container + ); // Pressable } - + static Widget _buildLevelHelpContent(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start,