feat: 구독 URL 매칭 서비스 개선 및 컨트롤러 최적화

- URL 매칭 로직 개선
- 구독 추가/상세 화면 컨트롤러 리팩토링
- assets 폴더 구조 추가

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-14 19:13:13 +09:00
parent ddf735149a
commit 917a68aa14
5 changed files with 1260 additions and 66 deletions

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:provider/provider.dart';
import '../models/subscription_model.dart';
import '../models/category_model.dart';
@@ -439,9 +440,32 @@ class DetailScreenController extends ChangeNotifier {
/// 해지 페이지 열기
Future<void> openCancellationPage() async {
if (subscription.websiteUrl != null &&
subscription.websiteUrl!.isNotEmpty) {
final Uri url = Uri.parse(subscription.websiteUrl!);
try {
// 1. 현재 언어 설정 가져오기
final locale = Localizations.localeOf(context).languageCode;
// 2. 해지 안내 URL 찾기
String? cancellationUrl = await SubscriptionUrlMatcher.findCancellationUrl(
serviceName: subscription.serviceName,
websiteUrl: subscription.websiteUrl,
locale: locale == 'ko' ? 'kr' : 'en',
);
// 3. 해지 안내 URL이 없으면 구글 검색
if (cancellationUrl == null) {
final searchQuery = '${subscription.serviceName} ${locale == 'ko' ? '해지 방법' : 'cancel subscription'}';
cancellationUrl = 'https://www.google.com/search?q=${Uri.encodeComponent(searchQuery)}';
if (context.mounted) {
AppSnackBar.showInfo(
context: context,
message: '공식 해지 페이지를 찾을 수 없어 구글 검색으로 연결합니다.',
);
}
}
// 4. URL 열기
final Uri url = Uri.parse(cancellationUrl);
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
if (context.mounted) {
AppSnackBar.showError(
@@ -450,12 +474,30 @@ class DetailScreenController extends ChangeNotifier {
);
}
}
} else {
if (context.mounted) {
AppSnackBar.showWarning(
context: context,
message: '웹사이트 정보가 없습니다. 해지는 웹사이트에서 진행해주세요.',
);
} catch (e) {
if (kDebugMode) {
print('DetailScreenController: 해지 페이지 열기 실패 - $e');
}
// 오류 발생시 일반 웹사이트로 폴백
if (subscription.websiteUrl != null &&
subscription.websiteUrl!.isNotEmpty) {
final Uri url = Uri.parse(subscription.websiteUrl!);
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
if (context.mounted) {
AppSnackBar.showError(
context: context,
message: '웹사이트를 열 수 없습니다.',
);
}
}
} else {
if (context.mounted) {
AppSnackBar.showWarning(
context: context,
message: '웹사이트 정보가 없습니다. 해지는 웹사이트에서 진행해주세요.',
);
}
}
}
}