feat(app): add manual entry and sharing flows
This commit is contained in:
47
lib/core/constants/api_keys.dart
Normal file
47
lib/core/constants/api_keys.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'dart:convert';
|
||||
|
||||
/// ApiKeys는 네이버 API 인증 정보를 환경 변수로 로드한다.
|
||||
///
|
||||
/// - `NAVER_CLIENT_ID`, `NAVER_CLIENT_SECRET`는 `flutter run`/`flutter test`
|
||||
/// 실행 시 `--dart-define`으로 주입한다.
|
||||
/// - 민감 정보는 base64(난독화) 형태로 전달하고, 런타임에서 복호화한다.
|
||||
class ApiKeys {
|
||||
static const String _encodedClientId = String.fromEnvironment(
|
||||
'NAVER_CLIENT_ID',
|
||||
defaultValue: '',
|
||||
);
|
||||
static const String _encodedClientSecret = String.fromEnvironment(
|
||||
'NAVER_CLIENT_SECRET',
|
||||
defaultValue: '',
|
||||
);
|
||||
|
||||
static String get naverClientId => _decodeIfNeeded(_encodedClientId);
|
||||
static String get naverClientSecret => _decodeIfNeeded(_encodedClientSecret);
|
||||
|
||||
static const String naverLocalSearchEndpoint =
|
||||
'https://openapi.naver.com/v1/search/local.json';
|
||||
|
||||
static bool areKeysConfigured() {
|
||||
return naverClientId.isNotEmpty && naverClientSecret.isNotEmpty;
|
||||
}
|
||||
|
||||
/// 배포 스크립트에서 사용할 수 있는 편의 메서드.
|
||||
static String obfuscate(String value) {
|
||||
if (value.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
return base64.encode(utf8.encode(value));
|
||||
}
|
||||
|
||||
static String _decodeIfNeeded(String value) {
|
||||
if (value.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
return utf8.decode(base64.decode(value));
|
||||
} on FormatException {
|
||||
// base64가 아니면 일반 문자열로 간주 (로컬 개발 편의용)
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ class AppColors {
|
||||
static const lightError = Color(0xFFFF5252);
|
||||
static const lightText = Color(0xFF222222); // 추가
|
||||
static const lightCard = Colors.white; // 추가
|
||||
|
||||
// Dark Theme Colors
|
||||
|
||||
// Dark Theme Colors
|
||||
static const darkPrimary = Color(0xFF03C75A);
|
||||
static const darkSecondary = Color(0xFF00BF63);
|
||||
static const darkBackground = Color(0xFF121212);
|
||||
@@ -24,4 +24,4 @@ class AppColors {
|
||||
static const darkError = Color(0xFFFF5252);
|
||||
static const darkText = Color(0xFFFFFFFF); // 추가
|
||||
static const darkCard = Color(0xFF1E1E1E); // 추가
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,33 +3,35 @@ class AppConstants {
|
||||
static const String appName = '오늘 뭐 먹Z?';
|
||||
static const String appDescription = '점심 메뉴 추천 앱';
|
||||
static const String appVersion = '1.0.0';
|
||||
static const String appCopyright = '© 2025. NatureBridgeAI. All rights reserved.';
|
||||
|
||||
static const String appCopyright =
|
||||
'© 2025. NatureBridgeAI. All rights reserved.';
|
||||
|
||||
// Animation Durations
|
||||
static const Duration splashAnimationDuration = Duration(seconds: 3);
|
||||
static const Duration defaultAnimationDuration = Duration(milliseconds: 300);
|
||||
|
||||
|
||||
// API Keys (These should be moved to .env in production)
|
||||
static const String naverMapApiKey = 'YOUR_NAVER_MAP_API_KEY';
|
||||
static const String weatherApiKey = 'YOUR_WEATHER_API_KEY';
|
||||
|
||||
|
||||
// AdMob IDs (Test IDs - Replace with real IDs in production)
|
||||
static const String androidAdAppId = 'ca-app-pub-3940256099942544~3347511713';
|
||||
static const String iosAdAppId = 'ca-app-pub-3940256099942544~1458002511';
|
||||
static const String interstitialAdUnitId = 'ca-app-pub-3940256099942544/1033173712';
|
||||
|
||||
static const String interstitialAdUnitId =
|
||||
'ca-app-pub-3940256099942544/1033173712';
|
||||
|
||||
// Hive Box Names
|
||||
static const String restaurantBox = 'restaurants';
|
||||
static const String visitRecordBox = 'visit_records';
|
||||
static const String recommendationBox = 'recommendations';
|
||||
static const String settingsBox = 'settings';
|
||||
|
||||
|
||||
// Default Settings
|
||||
static const int defaultDaysToExclude = 7;
|
||||
static const int defaultNotificationMinutes = 90;
|
||||
static const int defaultMaxDistanceNormal = 1000; // meters
|
||||
static const int defaultMaxDistanceRainy = 500; // meters
|
||||
|
||||
|
||||
// Categories
|
||||
static const List<String> foodCategories = [
|
||||
'한식',
|
||||
@@ -41,4 +43,4 @@ class AppConstants {
|
||||
'패스트푸드',
|
||||
'기타',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,28 +7,28 @@ class AppTypography {
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isDark ? AppColors.darkTextPrimary : AppColors.lightTextPrimary,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle heading2(bool isDark) => TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isDark ? AppColors.darkTextPrimary : AppColors.lightTextPrimary,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle body1(bool isDark) => TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: isDark ? AppColors.darkTextPrimary : AppColors.lightTextPrimary,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle body2(bool isDark) => TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: isDark ? AppColors.darkTextSecondary : AppColors.lightTextSecondary,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle caption(bool isDark) => TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: isDark ? AppColors.darkTextSecondary : AppColors.lightTextSecondary,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user