feat(app): add vworld geocoding and native ads placeholders

This commit is contained in:
JiWoong Sul
2025-12-03 14:30:20 +09:00
parent d101f7d0dc
commit 3ff9e5f837
23 changed files with 1108 additions and 540 deletions

View File

@@ -8,11 +8,13 @@ import 'package:lunchpick/presentation/providers/restaurant_provider.dart';
class RecommendationRecordCard extends ConsumerWidget {
final RecommendationRecord recommendation;
final VoidCallback onConfirmVisit;
final VoidCallback onDelete;
const RecommendationRecordCard({
super.key,
required this.recommendation,
required this.onConfirmVisit,
required this.onDelete,
});
String _formatTime(DateTime dateTime) {
@@ -43,96 +45,127 @@ class RecommendationRecordCard extends ConsumerWidget {
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.orange.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.whatshot,
color: Colors.orange,
size: 24,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
restaurant.name,
style: AppTypography.body1(
isDark,
).copyWith(fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Row(
children: [
Icon(
Icons.category_outlined,
size: 14,
color: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
const SizedBox(width: 4),
Text(
restaurant.category,
style: AppTypography.caption(isDark),
),
const SizedBox(width: 8),
Icon(
Icons.access_time,
size: 14,
color: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
const SizedBox(width: 4),
Text(
_formatTime(recommendation.recommendationDate),
style: AppTypography.caption(isDark),
),
],
),
const SizedBox(height: 8),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
Icons.info_outline,
size: 16,
color: Colors.orange,
),
const SizedBox(width: 6),
Expanded(
child: Text(
'추천만 받은 상태입니다. 방문 후 확인을 눌러 주세요.',
style: AppTypography.caption(isDark).copyWith(
color: Colors.orange,
fontWeight: FontWeight.w600,
),
softWrap: true,
maxLines: 3,
overflow: TextOverflow.visible,
),
),
],
),
],
),
),
const SizedBox(width: 12),
ElevatedButton(
onPressed: onConfirmVisit,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.lightPrimary,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 12),
minimumSize: const Size(0, 40),
),
child: const Text('방문 확인'),
),
],
),
const SizedBox(height: 10),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.orange.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.whatshot,
color: Colors.orange,
size: 24,
),
height: 1,
color: isDark
? AppColors.darkDivider
: AppColors.lightDivider,
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
restaurant.name,
style: AppTypography.body1(
isDark,
).copyWith(fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Row(
children: [
Icon(
Icons.category_outlined,
size: 14,
color: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
const SizedBox(width: 4),
Text(
restaurant.category,
style: AppTypography.caption(isDark),
),
const SizedBox(width: 8),
Icon(
Icons.access_time,
size: 14,
color: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
const SizedBox(width: 4),
Text(
_formatTime(recommendation.recommendationDate),
style: AppTypography.caption(isDark),
),
],
),
const SizedBox(height: 8),
Row(
children: [
const Icon(
Icons.info_outline,
size: 16,
color: Colors.orange,
),
const SizedBox(width: 6),
Text(
'추천만 받은 상태입니다. 방문 후 확인을 눌러 주세요.',
style: AppTypography.caption(isDark).copyWith(
color: Colors.orange,
fontWeight: FontWeight.w600,
),
),
],
),
],
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: onDelete,
style: TextButton.styleFrom(
foregroundColor: Colors.redAccent,
padding: const EdgeInsets.only(top: 6),
minimumSize: const Size(0, 32),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
child: const Text('삭제'),
),
),
const SizedBox(width: 12),
ElevatedButton(
onPressed: onConfirmVisit,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.lightPrimary,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 12),
minimumSize: const Size(0, 40),
),
child: const Text('방문 확인'),
),
],
),
),

View File

@@ -6,6 +6,7 @@ import 'package:lunchpick/core/constants/app_typography.dart';
import 'package:lunchpick/presentation/providers/visit_provider.dart';
import 'package:lunchpick/presentation/providers/restaurant_provider.dart';
import 'package:lunchpick/presentation/pages/calendar/widgets/debug_test_data_banner.dart';
import 'package:lunchpick/presentation/widgets/native_ad_placeholder.dart';
class VisitStatistics extends ConsumerWidget {
final DateTime selectedMonth;
@@ -42,6 +43,9 @@ class VisitStatistics extends ConsumerWidget {
_buildMonthlyStats(monthlyStatsAsync, isDark),
const SizedBox(height: 16),
const NativeAdPlaceholder(),
const SizedBox(height: 16),
// 주간 통계 차트
_buildWeeklyChart(weeklyStatsAsync, isDark),
const SizedBox(height: 16),