From 4e8b619ec2a383be6b0431ac88714bc437758136 Mon Sep 17 00:00:00 2001 From: Ponshu Developer Date: Tue, 13 Jan 2026 11:56:17 +0900 Subject: [PATCH] UI Polish: Remove redundant header icon, update usage guide assets, add close button to dialog --- lib/screens/home_screen.dart | 26 +-- lib/widgets/onboarding_dialog.dart | 256 ++++++++++++++++------------- 2 files changed, 154 insertions(+), 128 deletions(-) diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index bfee7bd..2b0d07b 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -93,17 +93,7 @@ class HomeScreen extends ConsumerWidget { actions: [ // Normal Actions - if (isBusinessMode) - IconButton( - icon: const Icon(LucideIcons.plus), - tooltip: 'セット商品を追加', - onPressed: () { - showDialog( - context: context, - builder: (context) => const AddSetItemDialog(), - ); - }, - ), + if (!isSearching) // Show Sort button here if not searching IconButton( @@ -395,29 +385,29 @@ class HomeScreen extends ConsumerWidget { final userProfile = ref.read(userProfileProvider); final isBusinessMode = userProfile.isBusinessMode; - List>? pages; + List>? pages; if (isBusinessMode) { pages = [ { 'title': 'ビジネスモードへようこそ', 'description': '飲食店様向けの機能を集約しました。\n在庫管理からメニュー作成まで、\nプロの仕事を強力にサポートします。', - 'icon': '💼', + 'icon': LucideIcons.briefcase, }, { 'title': 'セット商品の作成', 'description': '飲み比べセットやコース料理など、\n複数のお酒をまとめた「セット商品」を\n簡単に作成・管理できます。', - 'icon': '🍱', + 'icon': LucideIcons.packagePlus, }, { - 'title': '販促ツール(インスタ)', + 'title': 'インスタ販促', 'description': '本日のおすすめをSNSですぐに発信。\nInstaタブから、美しい画像を\nワンタップで生成できます。', - 'icon': '📸', + 'icon': LucideIcons.instagram, }, { - 'title': '高度な分析', + 'title': '売上分析', 'description': '売れ筋や味の傾向を分析。\nお客様に喜ばれるラインナップ作りを\nデータで支援します。', - 'icon': '📊', + 'icon': LucideIcons.barChartBig, }, ]; } diff --git a/lib/widgets/onboarding_dialog.dart b/lib/widgets/onboarding_dialog.dart index 5314312..65329b8 100644 --- a/lib/widgets/onboarding_dialog.dart +++ b/lib/widgets/onboarding_dialog.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:lucide_icons/lucide_icons.dart'; class OnboardingDialog extends StatefulWidget { final VoidCallback onFinish; - final List>? pages; // Optional content + final List>? pages; // Support dynamic for IconData const OnboardingDialog({super.key, required this.onFinish, this.pages}); @@ -15,7 +16,7 @@ class _OnboardingDialogState extends State { final PageController _controller = PageController(); int _currentPage = 0; - late final List> _pages; + late final List> _pages; @override void initState() { @@ -24,22 +25,22 @@ class _OnboardingDialogState extends State { { 'title': '日本酒の『魂』を保存する', 'description': 'Ponshu Roomへようこそ。\n飲んだ日本酒のラベルを撮影するだけで、\nAIが情報を解析し、あなたのリストに加えます。', - 'icon': '🍶', + 'icon': LucideIcons.wine, }, { 'title': 'ラベルを撮るだけ', 'description': '面倒な入力は不要です。\nラベルの写真を撮れば、銘柄、蔵元、味わいまで\nAIが自動でデータベース化します。', - 'icon': '📸', + 'icon': LucideIcons.camera, }, { 'title': 'あなただけのお品書き', 'description': '集めたコレクションから、\nボタンひとつで美しいお品書きPDFを作成。\n飲食店の方も、個人の方も楽しめます。', - 'icon': '📜', + 'icon': LucideIcons.scrollText, }, { 'title': 'さあ、始めましょう', 'description': 'AIの力で、日本酒ライフをもっと豊かに。\n右下のカメラボタンからスタートしてください。', - 'icon': '✨', + 'icon': LucideIcons.sparkles, }, ]; } @@ -49,118 +50,153 @@ class _OnboardingDialogState extends State { return Dialog( backgroundColor: Colors.transparent, // Custom shape insetPadding: const EdgeInsets.all(20), - child: Container( - height: 500, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: BorderRadius.circular(24), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.3), - blurRadius: 20, - offset: const Offset(0, 10), - ) - ], - ), - child: Column( - children: [ - Expanded( - child: PageView.builder( - controller: _controller, - onPageChanged: (index) => setState(() => _currentPage = index), - itemCount: _pages.length, - itemBuilder: (context, index) { - final page = _pages[index]; - return Center( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(32.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - page['icon']!, - style: const TextStyle(fontSize: 80), + child: Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + Container( + height: 500, + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.3), + blurRadius: 20, + offset: const Offset(0, 10), + ) + ], + ), + child: Column( + children: [ + Expanded( + child: PageView.builder( + controller: _controller, + onPageChanged: (index) => setState(() => _currentPage = index), + itemCount: _pages.length, + itemBuilder: (context, index) { + final page = _pages[index]; + final iconData = page['icon']; + + return Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(32.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (iconData is IconData) + Icon(iconData, size: 80, color: Theme.of(context).primaryColor) + else + Text( + iconData.toString(), + style: const TextStyle(fontSize: 80), + ), + const SizedBox(height: 32), + Text( + page['title']!, + textAlign: TextAlign.center, + style: GoogleFonts.zenOldMincho( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Theme.of(context).textTheme.bodyLarge?.color, + ), + ), + const SizedBox(height: 16), + Text( + page['description']!, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + height: 1.6, + color: Colors.grey, + ), + ), + ], ), - const SizedBox(height: 32), - Text( - page['title']!, - textAlign: TextAlign.center, - style: GoogleFonts.zenOldMincho( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Theme.of(context).textTheme.bodyLarge?.color, - ), - ), - const SizedBox(height: 16), - Text( - page['description']!, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - height: 1.6, - color: Colors.grey, - ), - ), - ], + ), ), - ), - ), - ); - }, - ), - ), - // Indicators - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: List.generate(_pages.length, (index) { - return AnimatedContainer( - duration: const Duration(milliseconds: 300), - margin: const EdgeInsets.symmetric(horizontal: 4), - height: 8, - width: _currentPage == index ? 24 : 8, - decoration: BoxDecoration( - color: _currentPage == index - ? Theme.of(context).primaryColor - : Colors.grey[300], - borderRadius: BorderRadius.circular(4), - ), - ); - }), - ), - const SizedBox(height: 24), - // Button - Padding( - padding: const EdgeInsets.symmetric(horizontal: 32.0, vertical: 24.0), - child: SizedBox( - width: double.infinity, - height: 50, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 0, - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - ), - onPressed: () { - if (_currentPage < _pages.length - 1) { - _controller.nextPage( - duration: const Duration(milliseconds: 300), - curve: Curves.easeIn, ); - } else { - widget.onFinish(); - } - }, - child: Text( - _currentPage < _pages.length - 1 ? '次へ' : 'はじめる', - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + }, ), ), + // Indicators + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(_pages.length, (index) { + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + margin: const EdgeInsets.symmetric(horizontal: 4), + height: 8, + width: _currentPage == index ? 24 : 8, + decoration: BoxDecoration( + color: _currentPage == index + ? Theme.of(context).primaryColor + : Colors.grey[300], + borderRadius: BorderRadius.circular(4), + ), + ); + }), + ), + const SizedBox(height: 24), + // Button + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32.0, vertical: 24.0), + child: SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 0, + backgroundColor: Theme.of(context).primaryColor, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + ), + onPressed: () { + if (_currentPage < _pages.length - 1) { + _controller.nextPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeIn, + ); + } else { + widget.onFinish(); + } + }, + child: Text( + _currentPage < _pages.length - 1 ? '次へ' : 'はじめる', + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + ), + ), + ), + ], + ), + ), + // Close Button + Positioned( + top: -12, + right: -12, + child: GestureDetector( + onTap: widget.onFinish, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.2), + blurRadius: 8, + offset: const Offset(0, 4), + ) + ], + ), + child: const Icon(LucideIcons.x, size: 24), ), ), - ], - ), + ), + ], ), ); } } +