feat: 폼 필드 컴포넌트 분리 및 구독 카드 인터랙션 개선
- billing_cycle_selector, category_selector, currency_selector 컴포넌트 분리 - 구독 카드 클릭 이슈 해결을 위한 리팩토링 - SMS 스캔 화면 UI/UX 개선 및 기능 강화 - 상세 화면 컨트롤러 로직 개선 - 알림 서비스 및 구독 URL 매칭 기능 추가 - CLAUDE.md 프로젝트 가이드라인 대폭 확장 - 전반적인 코드 구조 개선 및 타입 안정성 강화 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../providers/subscription_provider.dart';
|
||||
import '../widgets/glassmorphic_app_bar.dart';
|
||||
import '../widgets/native_ad_widget.dart';
|
||||
import '../widgets/analysis/analysis_screen_spacer.dart';
|
||||
import '../widgets/analysis/subscription_pie_chart_card.dart';
|
||||
@@ -100,10 +99,10 @@ class _AnalysisScreenState extends State<AnalysisScreen>
|
||||
controller: _scrollController,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
slivers: <Widget>[
|
||||
const GlassmorphicSliverAppBar(
|
||||
title: '분석',
|
||||
pinned: true,
|
||||
expandedHeight: kToolbarHeight,
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: kToolbarHeight + MediaQuery.of(context).padding.top,
|
||||
),
|
||||
),
|
||||
|
||||
// 네이티브 광고 위젯
|
||||
@@ -148,7 +147,12 @@ class _AnalysisScreenState extends State<AnalysisScreen>
|
||||
animationController: _animationController,
|
||||
),
|
||||
|
||||
const AnalysisScreenSpacer(height: 32),
|
||||
// FloatingNavigationBar를 위한 충분한 하단 여백
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: 120 + MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../models/subscription_model.dart';
|
||||
import '../controllers/detail_screen_controller.dart';
|
||||
import '../widgets/detail/detail_header_section.dart';
|
||||
@@ -46,9 +47,11 @@ class _DetailScreenState extends State<DetailScreen>
|
||||
Widget build(BuildContext context) {
|
||||
final baseColor = _controller.getCardColor();
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.backgroundColor,
|
||||
body: CustomScrollView(
|
||||
return ChangeNotifierProvider<DetailScreenController>.value(
|
||||
value: _controller,
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.backgroundColor,
|
||||
body: CustomScrollView(
|
||||
controller: _controller.scrollController,
|
||||
slivers: [
|
||||
// 상단 헤더 섹션
|
||||
@@ -74,8 +77,19 @@ class _DetailScreenState extends State<DetailScreen>
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: baseColor.withValues(alpha: 0.1),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
baseColor.withValues(alpha: 0.15),
|
||||
baseColor.withValues(alpha: 0.08),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: baseColor.withValues(alpha: 0.2),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
@@ -98,7 +112,7 @@ class _DetailScreenState extends State<DetailScreen>
|
||||
'변경사항은 저장 후 적용됩니다',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: baseColor.withValues(alpha: 0.8),
|
||||
color: AppColors.darkNavy,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -141,6 +155,7 @@ class _DetailScreenState extends State<DetailScreen>
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -183,10 +183,10 @@ class _MainScreenState extends State<MainScreen>
|
||||
backgroundColor: AppColors.successColor,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
margin: EdgeInsets.only(
|
||||
top: MediaQuery.of(context).padding.top + 16, // 상단 여백
|
||||
top: MediaQuery.of(context).padding.top + 8, // 더 상단으로
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: MediaQuery.of(context).size.height - 120, // 상단에 위치하도록 bottom 마진 설정
|
||||
bottom: MediaQuery.of(context).size.height - 100, // 더 상단으로
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
|
||||
@@ -9,6 +9,7 @@ import '../providers/theme_provider.dart';
|
||||
import '../theme/adaptive_theme.dart';
|
||||
import '../widgets/glassmorphism_card.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
import '../widgets/native_ad_widget.dart';
|
||||
|
||||
class SettingsScreen extends StatelessWidget {
|
||||
const SettingsScreen({super.key});
|
||||
@@ -70,81 +71,18 @@ class SettingsScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
children: [
|
||||
// 테마 설정
|
||||
GlassmorphismCard(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Text(
|
||||
'테마 설정',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
// 테마 모드 선택
|
||||
ListTile(
|
||||
title: const Text('테마 모드'),
|
||||
subtitle: Text(_getThemeModeText(themeProvider.themeMode)),
|
||||
leading: Icon(
|
||||
_getThemeModeIcon(themeProvider.themeMode),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
trailing: DropdownButton<AppThemeMode>(
|
||||
value: themeProvider.themeMode,
|
||||
underline: Container(),
|
||||
onChanged: (mode) {
|
||||
if (mode != null) {
|
||||
themeProvider.setThemeMode(mode);
|
||||
}
|
||||
},
|
||||
items: AppThemeMode.values.map((mode) =>
|
||||
DropdownMenuItem(
|
||||
value: mode,
|
||||
child: Text(_getThemeModeText(mode)),
|
||||
),
|
||||
).toList(),
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
|
||||
// 접근성 설정
|
||||
SwitchListTile(
|
||||
title: const Text('큰 텍스트'),
|
||||
subtitle: const Text('텍스트 크기를 크게 표시합니다'),
|
||||
secondary: const Icon(Icons.text_fields),
|
||||
value: themeProvider.largeText,
|
||||
onChanged: themeProvider.setLargeText,
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text('모션 감소'),
|
||||
subtitle: const Text('애니메이션 효과를 줄입니다'),
|
||||
secondary: const Icon(Icons.slow_motion_video),
|
||||
value: themeProvider.reduceMotion,
|
||||
onChanged: themeProvider.setReduceMotion,
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text('고대비 모드'),
|
||||
subtitle: const Text('더 선명한 색상으로 표시합니다'),
|
||||
secondary: const Icon(Icons.contrast),
|
||||
value: themeProvider.highContrast,
|
||||
onChanged: themeProvider.setHighContrast,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: kToolbarHeight + MediaQuery.of(context).padding.top,
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
children: [
|
||||
// 광고 위젯 추가
|
||||
const NativeAdWidget(key: ValueKey('settings_ad')),
|
||||
const SizedBox(height: 16),
|
||||
// 앱 잠금 설정 UI 숨김
|
||||
// Card(
|
||||
// margin: const EdgeInsets.all(16),
|
||||
@@ -392,24 +330,6 @@ class SettingsScreen extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
|
||||
// 데이터 관리
|
||||
const GlassmorphismCard(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: const Column(
|
||||
children: [
|
||||
// 데이터 백업 기능 비활성화
|
||||
// ListTile(
|
||||
// title: const Text('데이터 백업'),
|
||||
// subtitle: const Text('구독 데이터를 백업합니다'),
|
||||
// leading: const Icon(Icons.backup),
|
||||
// onTap: () => _backupData(context),
|
||||
// ),
|
||||
// const Divider(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 앱 정보
|
||||
GlassmorphismCard(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
@@ -485,11 +405,15 @@ class SettingsScreen extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
// FloatingNavigationBar를 위한 충분한 하단 여백
|
||||
SizedBox(
|
||||
height: 20 + MediaQuery.of(context).padding.bottom, // 하단 여백
|
||||
height: 120 + MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
],
|
||||
);
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String _getThemeModeText(AppThemeMode mode) {
|
||||
|
||||
@@ -14,6 +14,10 @@ import '../widgets/common/snackbar/app_snackbar.dart';
|
||||
import '../widgets/common/buttons/primary_button.dart';
|
||||
import '../widgets/common/buttons/secondary_button.dart';
|
||||
import '../widgets/common/form_fields/base_text_field.dart';
|
||||
import '../providers/category_provider.dart';
|
||||
import '../models/category_model.dart';
|
||||
import '../widgets/common/form_fields/category_selector.dart';
|
||||
import '../widgets/native_ad_widget.dart';
|
||||
|
||||
class SmsScanScreen extends StatefulWidget {
|
||||
const SmsScanScreen({super.key});
|
||||
@@ -35,6 +39,9 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
|
||||
// 웹사이트 URL 컨트롤러
|
||||
final TextEditingController _websiteUrlController = TextEditingController();
|
||||
|
||||
// 선택된 카테고리 ID 저장
|
||||
String? _selectedCategoryId;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -113,6 +120,25 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
'첫 번째 필터링된 구독: ${filteredSubscriptions[0].serviceName}, 반복 횟수: ${filteredSubscriptions[0].repeatCount}');
|
||||
}
|
||||
|
||||
// 중복 제거 후 신규 구독이 없는 경우
|
||||
if (filteredSubscriptions.isEmpty) {
|
||||
print('중복 제거 후 신규 구독이 없음');
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
|
||||
// 스낵바로 안내 메시지 표시
|
||||
if (mounted) {
|
||||
AppSnackBar.showInfo(
|
||||
context: context,
|
||||
message: '신규 구독 관련 SMS를 찾을 수 없습니다',
|
||||
icon: Icons.search_off_rounded,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_scannedSubscriptions = filteredSubscriptions;
|
||||
_isLoading = false;
|
||||
@@ -349,7 +375,7 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
isAutoDetected: true,
|
||||
repeatCount: safeRepeatCount,
|
||||
lastPaymentDate: subscription.lastPaymentDate,
|
||||
categoryId: subscription.category,
|
||||
categoryId: _selectedCategoryId ?? subscription.category,
|
||||
currency: subscription.currency, // 통화 단위 정보 추가
|
||||
);
|
||||
|
||||
@@ -399,6 +425,7 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
setState(() {
|
||||
_currentIndex++;
|
||||
_websiteUrlController.text = ''; // URL 입력 필드 초기화
|
||||
_selectedCategoryId = null; // 카테고리 선택 초기화
|
||||
|
||||
// 모든 구독을 처리했으면 홈 화면으로 이동
|
||||
if (_currentIndex >= _scannedSubscriptions.length) {
|
||||
@@ -493,15 +520,90 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
return '$count회 결제 감지됨';
|
||||
}
|
||||
|
||||
// 카테고리 칩 빌드
|
||||
Widget _buildCategoryChip(String? categoryId, CategoryProvider categoryProvider) {
|
||||
final category = categoryId != null
|
||||
? categoryProvider.getCategoryById(categoryId)
|
||||
: null;
|
||||
|
||||
// 카테고리가 없으면 기타 카테고리 찾기
|
||||
final defaultCategory = category ?? categoryProvider.categories.firstWhere(
|
||||
(cat) => cat.name == '기타',
|
||||
orElse: () => categoryProvider.categories.first,
|
||||
);
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.navyGray.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 카테고리 아이콘 표시
|
||||
Icon(
|
||||
_getCategoryIcon(defaultCategory),
|
||||
size: 16,
|
||||
color: AppColors.darkNavy,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
ThemedText(
|
||||
defaultCategory.name,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
forceDark: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 카테고리 아이콘 반환
|
||||
IconData _getCategoryIcon(CategoryModel category) {
|
||||
switch (category.name) {
|
||||
case '음악':
|
||||
return Icons.music_note_rounded;
|
||||
case 'OTT(동영상)':
|
||||
return Icons.movie_filter_rounded;
|
||||
case '저장/클라우드':
|
||||
return Icons.cloud_outlined;
|
||||
case '통신 · 인터넷 · TV':
|
||||
return Icons.wifi_rounded;
|
||||
case '생활/라이프스타일':
|
||||
return Icons.home_outlined;
|
||||
case '쇼핑/이커머스':
|
||||
return Icons.shopping_cart_outlined;
|
||||
case '프로그래밍':
|
||||
return Icons.code_rounded;
|
||||
case '협업/오피스':
|
||||
return Icons.business_center_outlined;
|
||||
case 'AI 서비스':
|
||||
return Icons.smart_toy_outlined;
|
||||
case '기타':
|
||||
default:
|
||||
return Icons.category_outlined;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: _isLoading
|
||||
? _buildLoadingState()
|
||||
: (_scannedSubscriptions.isEmpty
|
||||
? _buildInitialState()
|
||||
: _buildSubscriptionState()),
|
||||
child: Column(
|
||||
children: [
|
||||
_isLoading
|
||||
? _buildLoadingState()
|
||||
: (_scannedSubscriptions.isEmpty
|
||||
? _buildInitialState()
|
||||
: _buildSubscriptionState()),
|
||||
// FloatingNavigationBar를 위한 충분한 하단 여백
|
||||
SizedBox(
|
||||
height: 120 + MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -525,10 +627,16 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
|
||||
// 초기 상태 UI
|
||||
Widget _buildInitialState() {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
return Column(
|
||||
children: [
|
||||
// 광고 위젯 추가
|
||||
const NativeAdWidget(key: ValueKey('sms_scan_start_ad')),
|
||||
const SizedBox(height: 48),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (_errorMessage != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
@@ -564,8 +672,10 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
height: 56,
|
||||
backgroundColor: AppColors.primaryColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -579,6 +689,7 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
}
|
||||
|
||||
final subscription = _scannedSubscriptions[_currentIndex];
|
||||
final categoryProvider = Provider.of<CategoryProvider>(context, listen: false);
|
||||
|
||||
// 구독 리스트 카드를 표시할 때 URL 필드 자동 설정
|
||||
if (_websiteUrlController.text.isEmpty && subscription.websiteUrl != null) {
|
||||
@@ -588,6 +699,9 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// 광고 위젯 추가
|
||||
const NativeAdWidget(key: ValueKey('sms_scan_result_ad')),
|
||||
const SizedBox(height: 16),
|
||||
// 진행 상태 표시
|
||||
LinearProgressIndicator(
|
||||
value: (_currentIndex + 1) / _scannedSubscriptions.length,
|
||||
@@ -634,7 +748,7 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 금액 및 반복 횟수
|
||||
// 금액 및 결제 주기
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@@ -667,33 +781,6 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const ThemedText(
|
||||
'반복 횟수',
|
||||
fontWeight: FontWeight.w500,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
ThemedText(
|
||||
_getRepeatCountText(subscription.repeatCount),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 결제 주기
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -714,28 +801,51 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const ThemedText(
|
||||
'결제일',
|
||||
fontWeight: FontWeight.w500,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
ThemedText(
|
||||
_getNextBillingText(subscription.nextBillingDate),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
forceDark: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 다음 결제일
|
||||
const ThemedText(
|
||||
'다음 결제일',
|
||||
fontWeight: FontWeight.w500,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
ThemedText(
|
||||
_getNextBillingText(subscription.nextBillingDate),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 카테고리 선택
|
||||
const ThemedText(
|
||||
'카테고리',
|
||||
fontWeight: FontWeight.w500,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
CategorySelector(
|
||||
categories: categoryProvider.categories,
|
||||
selectedCategoryId: _selectedCategoryId ?? subscription.category,
|
||||
onChanged: (categoryId) {
|
||||
setState(() {
|
||||
_selectedCategoryId = categoryId;
|
||||
});
|
||||
},
|
||||
baseColor: (() {
|
||||
final categoryId = _selectedCategoryId ?? subscription.category;
|
||||
if (categoryId == null) return null;
|
||||
final category = categoryProvider.getCategoryById(categoryId);
|
||||
if (category == null) return null;
|
||||
return Color(int.parse(category.color.replaceFirst('#', '0xFF')));
|
||||
})(),
|
||||
isGlassmorphism: true,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 웹사이트 URL 입력 필드 추가/수정
|
||||
|
||||
@@ -265,7 +265,8 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.shadowBlack,
|
||||
color:
|
||||
AppColors.shadowBlack,
|
||||
spreadRadius: 0,
|
||||
blurRadius: 30,
|
||||
offset: const Offset(0, 10),
|
||||
@@ -280,9 +281,8 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
return ShaderMask(
|
||||
blendMode:
|
||||
BlendMode.srcIn,
|
||||
shaderCallback:
|
||||
(bounds) =>
|
||||
const LinearGradient(
|
||||
shaderCallback: (bounds) =>
|
||||
const LinearGradient(
|
||||
colors: AppColors
|
||||
.blueGradient,
|
||||
begin:
|
||||
@@ -323,11 +323,12 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'SubManager',
|
||||
'Digital Rent Manager',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.pureWhite,
|
||||
color: AppColors.primaryColor
|
||||
.withValues(alpha: 0.9),
|
||||
letterSpacing: 1.2,
|
||||
),
|
||||
),
|
||||
@@ -352,7 +353,8 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
'구독 서비스 관리를 더 쉽게',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.pureWhite.withValues(alpha: 0.7),
|
||||
color: AppColors.primaryColor
|
||||
.withValues(alpha: 0.7),
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
@@ -373,11 +375,12 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
height: 60,
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.pureWhite.withValues(alpha: 0.1),
|
||||
color: AppColors.pureWhite
|
||||
.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
border: Border.all(
|
||||
color:
|
||||
AppColors.pureWhite.withValues(alpha: 0.2),
|
||||
color: AppColors.pureWhite
|
||||
.withValues(alpha: 0.2),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
@@ -401,7 +404,7 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
child: FadeTransition(
|
||||
opacity: _fadeAnimation,
|
||||
child: Text(
|
||||
'© 2023 CClabs. All rights reserved.',
|
||||
'© 2025 NatureBridgeAI. All rights reserved.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.pureWhite.withValues(alpha: 0.6),
|
||||
|
||||
Reference in New Issue
Block a user