fix(ad): 스크린샷 모드에서 네이티브 광고 비활성화
This commit is contained in:
@@ -12,6 +12,7 @@ import '../../providers/ad_provider.dart';
|
||||
import '../../providers/location_provider.dart';
|
||||
import '../../providers/recommendation_provider.dart';
|
||||
import '../../providers/restaurant_provider.dart';
|
||||
import '../../providers/settings_provider.dart';
|
||||
import '../../providers/weather_provider.dart';
|
||||
import 'widgets/recommendation_result_dialog.dart';
|
||||
|
||||
@@ -33,6 +34,18 @@ class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final locationAsync = ref.watch(currentLocationWithFallbackProvider);
|
||||
final restaurantsAsync = ref.watch(restaurantListProvider);
|
||||
final categoriesAsync = ref.watch(categoriesProvider);
|
||||
final screenshotModeEnabled = ref
|
||||
.watch(screenshotModeEnabledProvider)
|
||||
.maybeWhen(data: (value) => value, orElse: () => false);
|
||||
final readiness = _evaluateRecommendationReadiness(
|
||||
locationAsync: locationAsync,
|
||||
restaurantsAsync: restaurantsAsync,
|
||||
categoriesAsync: categoriesAsync,
|
||||
screenshotModeEnabled: screenshotModeEnabled,
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: isDark
|
||||
@@ -165,29 +178,31 @@ class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
|
||||
),
|
||||
error: (_, __) => SizedBox(
|
||||
height: sectionHeight,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_buildWeatherInfo(
|
||||
'지금',
|
||||
Icons.wb_sunny,
|
||||
'맑음',
|
||||
20,
|
||||
isDark,
|
||||
const Icon(
|
||||
Icons.cloud_off,
|
||||
color: AppColors.lightWarning,
|
||||
size: 28,
|
||||
),
|
||||
Container(
|
||||
width: 1,
|
||||
height: 50,
|
||||
color: isDark
|
||||
? AppColors.darkDivider
|
||||
: AppColors.lightDivider,
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'날씨 정보를 불러오지 못했습니다.',
|
||||
style: AppTypography.body2(isDark),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
_buildWeatherInfo(
|
||||
'1시간 후',
|
||||
Icons.wb_sunny,
|
||||
'맑음',
|
||||
22,
|
||||
isDark,
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'네트워크/위치 권한을 확인한 뒤 다시 시도해 주세요.',
|
||||
style: AppTypography.caption(isDark),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextButton.icon(
|
||||
onPressed: () => ref.refresh(weatherProvider),
|
||||
icon: const Icon(Icons.refresh),
|
||||
label: const Text('다시 시도'),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -360,7 +375,7 @@ class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
|
||||
|
||||
// 추천받기 버튼
|
||||
ElevatedButton(
|
||||
onPressed: !_isProcessingRecommendation && _canRecommend()
|
||||
onPressed: !_isProcessingRecommendation && readiness.canRecommend
|
||||
? () => _startRecommendation()
|
||||
: null,
|
||||
style: ElevatedButton.styleFrom(
|
||||
@@ -397,6 +412,30 @@ class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
|
||||
),
|
||||
),
|
||||
|
||||
if (readiness.message != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
readiness.icon,
|
||||
size: 18,
|
||||
color: _readinessColor(readiness, isDark),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
readiness.message!,
|
||||
style: AppTypography.caption(
|
||||
isDark,
|
||||
).copyWith(color: _readinessColor(readiness, isDark)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
// const NativeAdPlaceholder(
|
||||
// margin: EdgeInsets.symmetric(vertical: 8),
|
||||
@@ -429,30 +468,6 @@ class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWeatherInfo(
|
||||
String label,
|
||||
IconData icon,
|
||||
String description,
|
||||
int temperature,
|
||||
bool isDark,
|
||||
) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(label, style: AppTypography.caption(isDark)),
|
||||
const SizedBox(height: 8),
|
||||
Icon(icon, color: Colors.orange, size: 32),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'$temperature°C',
|
||||
style: AppTypography.body1(
|
||||
isDark,
|
||||
).copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(description, style: AppTypography.caption(isDark)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAllCategoryChip(
|
||||
bool isDark,
|
||||
bool isSelected,
|
||||
@@ -609,33 +624,113 @@ class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
|
||||
}).length;
|
||||
}
|
||||
|
||||
bool _canRecommend() {
|
||||
final locationAsync = ref.read(currentLocationWithFallbackProvider);
|
||||
final restaurantsAsync = ref.read(restaurantListProvider);
|
||||
final categories = ref
|
||||
.read(categoriesProvider)
|
||||
.maybeWhen(data: (list) => list, orElse: () => const <String>[]);
|
||||
|
||||
final location = locationAsync.maybeWhen(
|
||||
data: (pos) => pos,
|
||||
orElse: () => null,
|
||||
);
|
||||
final restaurants = restaurantsAsync.maybeWhen(
|
||||
data: (list) => list,
|
||||
orElse: () => null,
|
||||
);
|
||||
|
||||
if (location == null || restaurants == null || restaurants.isEmpty) {
|
||||
return false;
|
||||
_RecommendationReadiness _evaluateRecommendationReadiness({
|
||||
required AsyncValue<Position> locationAsync,
|
||||
required AsyncValue<List<Restaurant>> restaurantsAsync,
|
||||
required AsyncValue<List<String>> categoriesAsync,
|
||||
bool screenshotModeEnabled = false,
|
||||
}) {
|
||||
if (screenshotModeEnabled) {
|
||||
return const _RecommendationReadiness(canRecommend: true);
|
||||
}
|
||||
|
||||
if (locationAsync.isLoading) {
|
||||
return const _RecommendationReadiness(
|
||||
canRecommend: false,
|
||||
message: '위치 정보를 불러오는 중입니다. 잠시만 기다려 주세요.',
|
||||
icon: Icons.location_searching,
|
||||
isWarning: true,
|
||||
);
|
||||
}
|
||||
|
||||
if (locationAsync.hasError) {
|
||||
return const _RecommendationReadiness(
|
||||
canRecommend: false,
|
||||
message: '위치 권한 또는 설정을 확인해 주세요.',
|
||||
icon: Icons.gps_off,
|
||||
isError: true,
|
||||
);
|
||||
}
|
||||
|
||||
final location = locationAsync.value;
|
||||
if (location == null) {
|
||||
return const _RecommendationReadiness(
|
||||
canRecommend: false,
|
||||
message: '위치 정보를 확인할 수 없습니다.',
|
||||
icon: Icons.location_disabled,
|
||||
isError: true,
|
||||
);
|
||||
}
|
||||
|
||||
if (restaurantsAsync.isLoading) {
|
||||
return const _RecommendationReadiness(
|
||||
canRecommend: false,
|
||||
message: '맛집 목록을 불러오는 중입니다.',
|
||||
icon: Icons.restaurant_menu,
|
||||
isWarning: true,
|
||||
);
|
||||
}
|
||||
|
||||
final restaurants = restaurantsAsync.value;
|
||||
if (restaurants == null || restaurants.isEmpty) {
|
||||
return const _RecommendationReadiness(
|
||||
canRecommend: false,
|
||||
message: '등록된 맛집이 없습니다. 맛집을 추가해 주세요.',
|
||||
icon: Icons.playlist_remove,
|
||||
isError: true,
|
||||
);
|
||||
}
|
||||
|
||||
if (categoriesAsync.isLoading) {
|
||||
return const _RecommendationReadiness(
|
||||
canRecommend: false,
|
||||
message: '카테고리를 불러오는 중입니다.',
|
||||
icon: Icons.category_outlined,
|
||||
isWarning: true,
|
||||
);
|
||||
}
|
||||
|
||||
final categories = categoriesAsync.value ?? const <String>[];
|
||||
final count = _getRestaurantCountInRange(
|
||||
restaurants,
|
||||
location,
|
||||
_distanceValue,
|
||||
_effectiveSelectedCategories(categories),
|
||||
);
|
||||
return count > 0;
|
||||
if (count == 0) {
|
||||
return const _RecommendationReadiness(
|
||||
canRecommend: false,
|
||||
message: '선택한 거리/카테고리에 해당하는 맛집이 없습니다. 범위를 넓혀 보세요.',
|
||||
icon: Icons.travel_explore,
|
||||
isWarning: true,
|
||||
);
|
||||
}
|
||||
|
||||
final usesFallback = _isFallbackPosition(location);
|
||||
return _RecommendationReadiness(
|
||||
canRecommend: true,
|
||||
message: usesFallback
|
||||
? '기본 위치(서울 시청) 기준으로 추천 중입니다. 위치 권한을 허용하면 더 정확해요.'
|
||||
: null,
|
||||
icon: usesFallback ? Icons.gps_not_fixed : Icons.check_circle,
|
||||
isWarning: usesFallback,
|
||||
);
|
||||
}
|
||||
|
||||
bool _isFallbackPosition(Position position) {
|
||||
final fallback = defaultPosition();
|
||||
return position.latitude == fallback.latitude &&
|
||||
position.longitude == fallback.longitude;
|
||||
}
|
||||
|
||||
Color _readinessColor(_RecommendationReadiness readiness, bool isDark) {
|
||||
if (readiness.isError) {
|
||||
return isDark ? AppColors.darkError : AppColors.lightError;
|
||||
}
|
||||
if (readiness.isWarning) {
|
||||
return isDark ? AppColors.darkWarning : AppColors.lightWarning;
|
||||
}
|
||||
return isDark ? AppColors.darkTextSecondary : AppColors.lightTextSecondary;
|
||||
}
|
||||
|
||||
Future<void> _startRecommendation({
|
||||
@@ -845,4 +940,20 @@ class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
class _RecommendationReadiness {
|
||||
final bool canRecommend;
|
||||
final String? message;
|
||||
final IconData icon;
|
||||
final bool isWarning;
|
||||
final bool isError;
|
||||
|
||||
const _RecommendationReadiness({
|
||||
required this.canRecommend,
|
||||
this.message,
|
||||
this.icon = Icons.info_outline,
|
||||
this.isWarning = false,
|
||||
this.isError = false,
|
||||
});
|
||||
}
|
||||
|
||||
enum _SnackType { info, warning, error, success }
|
||||
|
||||
Reference in New Issue
Block a user