feat(app): add manual entry and sharing flows

This commit is contained in:
JiWoong Sul
2025-11-19 16:36:39 +09:00
parent 5ade584370
commit 947fe59486
110 changed files with 5937 additions and 3781 deletions

View File

@@ -22,7 +22,9 @@ class NotificationPayload {
try {
final parts = payload.split('|');
if (parts.length < 4) {
throw FormatException('Invalid payload format - expected 4 parts but got ${parts.length}: $payload');
throw FormatException(
'Invalid payload format - expected 4 parts but got ${parts.length}: $payload',
);
}
// 각 필드 유효성 검증
@@ -66,11 +68,14 @@ class NotificationPayload {
/// 알림 핸들러 StateNotifier
class NotificationHandlerNotifier extends StateNotifier<AsyncValue<void>> {
final Ref _ref;
NotificationHandlerNotifier(this._ref) : super(const AsyncValue.data(null));
/// 알림 클릭 처리
Future<void> handleNotificationTap(BuildContext context, String? payload) async {
Future<void> handleNotificationTap(
BuildContext context,
String? payload,
) async {
if (payload == null || payload.isEmpty) {
print('Notification payload is null or empty');
return;
@@ -83,12 +88,13 @@ class NotificationHandlerNotifier extends StateNotifier<AsyncValue<void>> {
if (payload.startsWith('visit_reminder:')) {
final restaurantName = payload.substring(15);
print('Legacy format - Restaurant name: $restaurantName');
// 맛집 이름으로 ID 찾기
final restaurantsAsync = await _ref.read(restaurantListProvider.future);
final restaurant = restaurantsAsync.firstWhere(
(r) => r.name == restaurantName,
orElse: () => throw Exception('Restaurant not found: $restaurantName'),
orElse: () =>
throw Exception('Restaurant not found: $restaurantName'),
);
// 방문 확인 다이얼로그 표시
@@ -97,17 +103,21 @@ class NotificationHandlerNotifier extends StateNotifier<AsyncValue<void>> {
context: context,
restaurantId: restaurant.id,
restaurantName: restaurant.name,
recommendationTime: DateTime.now().subtract(const Duration(hours: 2)),
recommendationTime: DateTime.now().subtract(
const Duration(hours: 2),
),
);
}
} else {
// 새로운 형식의 payload 처리
print('Attempting to parse new format payload');
try {
final notificationPayload = NotificationPayload.fromString(payload);
print('Successfully parsed payload - Type: ${notificationPayload.type}, RestaurantId: ${notificationPayload.restaurantId}');
print(
'Successfully parsed payload - Type: ${notificationPayload.type}, RestaurantId: ${notificationPayload.restaurantId}',
);
if (notificationPayload.type == 'visit_reminder') {
// 방문 확인 다이얼로그 표시
if (context.mounted) {
@@ -127,7 +137,7 @@ class NotificationHandlerNotifier extends StateNotifier<AsyncValue<void>> {
} catch (parseError) {
print('Failed to parse new format, attempting fallback parsing');
print('Parse error: $parseError');
// Fallback: 간단한 파싱 시도
if (payload.contains('|')) {
final parts = payload.split('|');
@@ -135,16 +145,14 @@ class NotificationHandlerNotifier extends StateNotifier<AsyncValue<void>> {
// 최소한 캘린더로 이동
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('알림을 처리했습니다. 방문 기록을 확인해주세요.'),
),
const SnackBar(content: Text('알림을 처리했습니다. 방문 기록을 확인해주세요.')),
);
context.go('/home?tab=calendar');
}
return;
}
}
// 파싱 실패 시 원래 에러 다시 발생
rethrow;
}
@@ -153,7 +161,7 @@ class NotificationHandlerNotifier extends StateNotifier<AsyncValue<void>> {
print('Error handling notification: $e');
print('Stack trace: $stackTrace');
state = AsyncValue.error(e, stackTrace);
// 에러 발생 시 기본적으로 캘린더 화면으로 이동
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
@@ -169,6 +177,7 @@ class NotificationHandlerNotifier extends StateNotifier<AsyncValue<void>> {
}
/// NotificationHandler Provider
final notificationHandlerProvider = StateNotifierProvider<NotificationHandlerNotifier, AsyncValue<void>>((ref) {
return NotificationHandlerNotifier(ref);
});
final notificationHandlerProvider =
StateNotifierProvider<NotificationHandlerNotifier, AsyncValue<void>>((ref) {
return NotificationHandlerNotifier(ref);
});