2026-01-11 08:17:29 +00:00
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
|
|
import 'package:flutter_localizations/flutter_localizations.dart'; // Localization
|
|
|
|
|
|
import 'package:hive_flutter/hive_flutter.dart';
|
|
|
|
|
|
import 'models/sake_item.dart';
|
|
|
|
|
|
import 'models/user_profile.dart';
|
|
|
|
|
|
import 'models/menu_settings.dart';
|
|
|
|
|
|
import 'providers/theme_provider.dart';
|
|
|
|
|
|
import 'screens/main_screen.dart';
|
2026-04-10 15:05:53 +00:00
|
|
|
|
import 'screens/license_screen.dart';
|
2026-01-11 08:17:29 +00:00
|
|
|
|
import 'services/migration_service.dart';
|
|
|
|
|
|
|
2026-04-11 00:19:03 +00:00
|
|
|
|
/// ビルド時Pro解放フラグ(現在未使用 — 実行時ライセンスはisProProviderで管理)
|
|
|
|
|
|
/// 将来的に削除予定。isProProvider (license_provider.dart) を使うこと。
|
2026-02-15 15:13:12 +00:00
|
|
|
|
const bool isProVersion = bool.fromEnvironment('IS_PRO_VERSION', defaultValue: false);
|
2026-01-30 08:34:39 +00:00
|
|
|
|
|
2026-04-04 14:13:40 +00:00
|
|
|
|
/// 店舗向けビルドかどうかを判定するビルド時フラグ
|
|
|
|
|
|
///
|
|
|
|
|
|
/// ビルドコマンド:
|
|
|
|
|
|
/// - 消費者向け: flutter build apk --release --dart-define=IS_BUSINESS_APP=false
|
|
|
|
|
|
/// - 店舗向け: flutter build apk --release --dart-define=IS_BUSINESS_APP=true
|
|
|
|
|
|
///
|
|
|
|
|
|
/// デフォルトはfalse(消費者向け)
|
|
|
|
|
|
const bool isBusinessApp = bool.fromEnvironment('IS_BUSINESS_APP', defaultValue: false);
|
|
|
|
|
|
|
2026-01-11 08:17:29 +00:00
|
|
|
|
void main() async {
|
|
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
2026-01-30 16:00:37 +00:00
|
|
|
|
|
2026-01-11 08:17:29 +00:00
|
|
|
|
await Hive.initFlutter();
|
2026-04-04 14:02:52 +00:00
|
|
|
|
|
2026-01-11 08:17:29 +00:00
|
|
|
|
Hive.registerAdapter(SakeItemAdapter());
|
|
|
|
|
|
Hive.registerAdapter(UserProfileAdapter());
|
|
|
|
|
|
Hive.registerAdapter(MenuSettingsAdapter());
|
|
|
|
|
|
Hive.registerAdapter(DisplayDataAdapter());
|
|
|
|
|
|
Hive.registerAdapter(HiddenSpecsAdapter());
|
|
|
|
|
|
Hive.registerAdapter(UserDataAdapter());
|
|
|
|
|
|
Hive.registerAdapter(GamificationAdapter());
|
|
|
|
|
|
Hive.registerAdapter(MetadataAdapter());
|
2026-01-29 15:54:22 +00:00
|
|
|
|
Hive.registerAdapter(ItemTypeAdapter()); // Restored missing adapter
|
|
|
|
|
|
// Open all boxes first (faster to open them together)
|
|
|
|
|
|
// Reverted to synchronous wait to ensure Providers have data immediately
|
|
|
|
|
|
// Open all boxes in parallel (Much faster than sequential)
|
|
|
|
|
|
await Future.wait([
|
|
|
|
|
|
Hive.openBox('settings'),
|
|
|
|
|
|
Hive.openBox<UserProfile>('user_profile'),
|
|
|
|
|
|
Hive.openBox<SakeItem>('sake_items'),
|
|
|
|
|
|
Hive.openBox<MenuSettings>('menu_settings'),
|
|
|
|
|
|
]);
|
2026-01-11 08:17:29 +00:00
|
|
|
|
|
2026-04-09 23:26:53 +00:00
|
|
|
|
// Migration — バージョン番号で管理(単一フラグだと将来の追加マイグレーションが走らないため)
|
|
|
|
|
|
// migration_completed=true の旧ユーザーはバージョン 1 扱いとして互換性を維持する
|
|
|
|
|
|
const int currentMigrationVersion = 1;
|
2026-01-29 15:54:22 +00:00
|
|
|
|
final box = Hive.box('settings');
|
2026-04-09 23:26:53 +00:00
|
|
|
|
final legacyCompleted = box.get('migration_completed', defaultValue: false) as bool;
|
|
|
|
|
|
final storedVersion = legacyCompleted
|
|
|
|
|
|
? box.get('migration_version', defaultValue: 1) as int // 旧ユーザー: 既に完了済み=v1
|
|
|
|
|
|
: box.get('migration_version', defaultValue: 0) as int; // 新規ユーザー: 未実行=v0
|
|
|
|
|
|
|
|
|
|
|
|
if (storedVersion < currentMigrationVersion) {
|
|
|
|
|
|
debugPrint('🚀 Running MigrationService (v$storedVersion → v$currentMigrationVersion)...');
|
2026-01-29 15:54:22 +00:00
|
|
|
|
await MigrationService.runMigration();
|
2026-04-09 23:26:53 +00:00
|
|
|
|
await box.put('migration_version', currentMigrationVersion);
|
|
|
|
|
|
await box.put('migration_completed', true); // 旧フラグも維持(後方互換)
|
2026-01-29 15:54:22 +00:00
|
|
|
|
} else {
|
2026-04-09 23:26:53 +00:00
|
|
|
|
debugPrint('✅ Migration up to date (v$storedVersion). Skipping.');
|
2026-01-29 15:54:22 +00:00
|
|
|
|
}
|
2026-01-11 08:17:29 +00:00
|
|
|
|
|
2026-01-29 15:54:22 +00:00
|
|
|
|
// ✅ AI解析キャッシュは使うときに初期化する(Lazy initialization)
|
|
|
|
|
|
// AnalysisCacheService.init()はサービス内でLazy実装されているため、
|
|
|
|
|
|
// ここで呼び出すと起動が遅くなる。必要なときに自動初期化される。
|
2026-01-11 08:17:29 +00:00
|
|
|
|
|
|
|
|
|
|
runApp(
|
2026-01-29 15:54:22 +00:00
|
|
|
|
const ProviderScope(
|
|
|
|
|
|
child: MyApp(),
|
2026-01-11 08:17:29 +00:00
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class MyApp extends ConsumerWidget {
|
|
|
|
|
|
const MyApp({super.key});
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
|
|
|
|
final lightTheme = ref.watch(lightThemeProvider);
|
|
|
|
|
|
final darkTheme = ref.watch(darkThemeProvider);
|
|
|
|
|
|
final themeMode = ref.watch(themeModeProvider);
|
2026-01-29 15:54:22 +00:00
|
|
|
|
final locale = ref.watch(localeProvider); // NEW: User-selected locale
|
2026-01-11 08:17:29 +00:00
|
|
|
|
|
|
|
|
|
|
return MaterialApp(
|
|
|
|
|
|
debugShowCheckedModeBanner: false,
|
|
|
|
|
|
title: 'Ponshu Room Lite',
|
|
|
|
|
|
theme: lightTheme,
|
|
|
|
|
|
darkTheme: darkTheme,
|
|
|
|
|
|
themeMode: themeMode,
|
2026-01-29 15:54:22 +00:00
|
|
|
|
locale: locale, // NEW: Apply user's locale choice
|
|
|
|
|
|
|
|
|
|
|
|
// Localization (UPDATED)
|
2026-01-11 08:17:29 +00:00
|
|
|
|
localizationsDelegates: const [
|
|
|
|
|
|
GlobalMaterialLocalizations.delegate,
|
|
|
|
|
|
GlobalWidgetsLocalizations.delegate,
|
|
|
|
|
|
GlobalCupertinoLocalizations.delegate,
|
|
|
|
|
|
],
|
|
|
|
|
|
supportedLocales: const [
|
2026-04-04 14:02:52 +00:00
|
|
|
|
Locale('ja'),
|
|
|
|
|
|
Locale('en'),
|
2026-01-11 08:17:29 +00:00
|
|
|
|
],
|
|
|
|
|
|
|
2026-01-29 15:54:22 +00:00
|
|
|
|
navigatorObservers: [routeObserver],
|
2026-01-11 08:17:29 +00:00
|
|
|
|
home: const MainScreen(),
|
2026-04-10 15:05:53 +00:00
|
|
|
|
routes: {
|
|
|
|
|
|
'/upgrade': (context) => const LicenseScreen(),
|
|
|
|
|
|
},
|
2026-01-11 08:17:29 +00:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-29 15:54:22 +00:00
|
|
|
|
|
|
|
|
|
|
// Global RouteObserver
|
|
|
|
|
|
final RouteObserver<ModalRoute<void>> routeObserver = RouteObserver<ModalRoute<void>>();
|