feat: 글래스모피즘 디자인 시스템 및 색상 가이드 전면 적용

- @doc/color.md 가이드라인에 따른 색상 시스템 전면 개편
- 딥 블루(#2563EB), 스카이 블루(#60A5FA) 메인 컬러로 변경
- 모든 화면과 위젯에 글래스모피즘 효과 일관성 있게 적용
- darkNavy, navyGray 등 새로운 텍스트 색상 체계 도입
- 공통 스낵바 및 다이얼로그 컴포넌트 추가
- Claude AI 프로젝트 컨텍스트 파일(CLAUDE.md) 추가

영향받은 컴포넌트:
- 10개 스크린 (main, settings, detail, splash 등)
- 30개 이상 위젯 (buttons, cards, forms 등)
- 테마 시스템 (AppColors, AppTheme)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-11 18:41:05 +09:00
parent 83c5e3d64e
commit 2f60ef585a
46 changed files with 1096 additions and 580 deletions

View File

@@ -7,6 +7,8 @@ import '../providers/category_provider.dart';
import '../services/subscription_url_matcher.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:intl/intl.dart';
import '../widgets/dialogs/delete_confirmation_dialog.dart';
import '../widgets/common/snackbar/app_snackbar.dart';
/// DetailScreen의 비즈니스 로직을 관리하는 Controller
class DetailScreenController {
@@ -313,20 +315,9 @@ class DetailScreenController {
await provider.updateSubscription(subscription);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Row(
children: [
Icon(Icons.check_circle_rounded, color: Colors.white),
SizedBox(width: 12),
Text('구독 정보가 업데이트되었습니다.'),
],
),
behavior: SnackBarBehavior.floating,
backgroundColor: const Color(0xFF10B981),
duration: const Duration(seconds: 2),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
AppSnackBar.showSuccess(
context: context,
message: '구독 정보가 업데이트되었습니다.',
);
// 변경 사항이 반영될 시간을 주기 위해 짧게 지연 후 결과 반환
@@ -340,26 +331,27 @@ class DetailScreenController {
/// 구독 삭제
Future<void> deleteSubscription() async {
if (context.mounted) {
final provider = Provider.of<SubscriptionProvider>(context, listen: false);
await provider.deleteSubscription(subscription.id);
// 삭제 확인 다이얼로그 표시
final shouldDelete = await DeleteConfirmationDialog.show(
context: context,
serviceName: subscription.serviceName,
);
if (!shouldDelete) return;
// 사용자가 확인한 경우에만 삭제 진행
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Row(
children: [
Icon(Icons.delete_forever_rounded, color: Colors.white),
SizedBox(width: 12),
Text('구독이 삭제되었습니다.'),
],
),
behavior: SnackBarBehavior.floating,
backgroundColor: const Color(0xFFDC2626),
duration: const Duration(seconds: 2),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
);
Navigator.of(context).pop();
final provider = Provider.of<SubscriptionProvider>(context, listen: false);
await provider.deleteSubscription(subscription.id);
if (context.mounted) {
AppSnackBar.showSuccess(
context: context,
message: '구독이 삭제되었습니다.',
icon: Icons.delete_forever_rounded,
);
Navigator.of(context).pop();
}
}
}
}
@@ -371,21 +363,17 @@ class DetailScreenController {
final Uri url = Uri.parse(subscription.websiteUrl!);
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('웹사이트를 열 수 없습니다.'),
backgroundColor: Colors.red,
),
AppSnackBar.showError(
context: context,
message: '웹사이트를 열 수 없습니다.',
);
}
}
} else {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('웹사이트 정보가 없습니다. 해지는 웹사이트에서 진행해주세요.'),
backgroundColor: Colors.orange,
),
AppSnackBar.showWarning(
context: context,
message: '웹사이트 정보가 없습니다. 해지는 웹사이트에서 진행해주세요.',
);
}
}