feat: SMS 스캔 전면광고 및 Isolate 버그 수정

## 전면 광고 (AdService)
- AdService 클래스 신규 생성 (lunchpick 패턴 참조)
- Completer 패턴으로 광고 완료 대기 구현
- 로딩 오버레이로 앱 foreground 상태 유지
- 몰입형 모드 (immersiveSticky) 적용
- iOS 테스트 광고 ID 설정

## SMS 스캔 버그 수정
- Isolate 내 Flutter 바인딩 접근 오류 해결
- _isoExtractServiceNameFromSender()에서 하드코딩 사용
- 로딩 위젯 화면 정중앙 배치 수정

## 문서 및 설정
- CLAUDE.md 최적화 (글로벌 규칙 중복 제거)
- Claude Code Skills 5개 추가
  - flutter-build: 빌드/분석
  - hive-model: Hive 모델 관리
  - release-deploy: 릴리즈 배포
  - sms-scanner: SMS 스캔 디버깅
  - admob: 광고 구현

## 버전
- 1.0.1+2 → 1.0.1+3
This commit is contained in:
JiWoong Sul
2025-12-08 18:14:52 +09:00
parent bac4acf9a3
commit 83c43fb61f
12 changed files with 639 additions and 434 deletions

View File

@@ -47,7 +47,7 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
_controller.initializeWebsiteUrl();
_controller.initializeWebsiteUrl(context);
}
Widget _buildContent() {
@@ -161,83 +161,26 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
@override
Widget build(BuildContext context) {
return Stack(
children: [
SingleChildScrollView(
controller: _scrollController,
padding: EdgeInsets.zero,
child: Padding(
padding: const EdgeInsets.only(top: UIConstants.pageTopPadding),
child: Column(
children: [
_buildContent(),
// FloatingNavigationBar를 위한 충분한 하단 여백
SizedBox(
height: 120 + MediaQuery.of(context).padding.bottom,
),
],
// 로딩 중일 때는 화면 정중앙에 표시
if (_controller.isLoading) {
return const ScanLoadingWidget();
}
return SingleChildScrollView(
controller: _scrollController,
padding: EdgeInsets.zero,
child: Padding(
padding: const EdgeInsets.only(top: UIConstants.pageTopPadding),
child: Column(
children: [
_buildContent(),
// FloatingNavigationBar를 위한 충분한 하단 여백
SizedBox(
height: 120 + MediaQuery.of(context).padding.bottom,
),
),
],
),
if (_controller.isAdInProgress)
Positioned.fill(
child: IgnorePointer(
child: Stack(
children: [
Container(
color: Theme.of(context)
.colorScheme
.surface
.withValues(alpha: 0.4),
),
Center(
child: DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.surfaceContainerHighest
.withValues(alpha: 0.9),
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 16),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.primary,
),
),
),
const SizedBox(width: 12),
Text(
AppLocalizations.of(context).scanningMessages,
style: Theme.of(context)
.textTheme
.titleMedium
?.copyWith(
color:
Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center,
),
],
),
),
),
),
],
),
),
),
],
),
);
}
}