97 lines
3.8 KiB
Dart
97 lines
3.8 KiB
Dart
// ignore_for_file: deprecated_member_use
|
||
|
||
import 'package:didvan/services/auth/token_storage.dart';
|
||
import 'package:didvan/services/storage/storage.dart';
|
||
import 'package:flutter/foundation.dart';
|
||
import 'package:package_info_plus/package_info_plus.dart';
|
||
|
||
/// سادهساز migrationهای دادهی محلی هنگام آپدیت اپ.
|
||
///
|
||
/// انگیزه: کاربرانی که از نسخههای قبل از سوییچ به API جدید آپدیت میکنند
|
||
/// توکن/cache قدیمی با schema سرور جدید نمیخواند و موقع splash گیر میافتد
|
||
/// (تا اینکه کاربر دستی Clear Data بکند). این کلاس همان clear data را خودش
|
||
/// انجام میدهد — فقط یک بار، روی اولین اجرا با نسخهی جدید.
|
||
class AppMigration {
|
||
/// آخرین نسخهای که schema دادهی محلی را شکست و باید کاربران را خروج کند.
|
||
/// هر کاربر با نسخهی قبل از این، در آپدیت بعدی auto-logout میشود.
|
||
/// اگر در آینده schema باز هم شکست، این عدد را افزایش بده.
|
||
static const int _breakingDataVersion = 2;
|
||
|
||
/// کلید storage برای نگهداری نسخهی schema که آخرین بار کاربر رویش بود.
|
||
static const String _storageKey = '_app_data_schema_version';
|
||
|
||
/// کلیدهایی که هنگام پاکسازی **حفظ** میشوند (UI preferences کاربر).
|
||
static const Set<String> _keysToKeep = {
|
||
'brightness',
|
||
'fontFamily',
|
||
'fontScale',
|
||
'hasSeenOnboarding',
|
||
_storageKey,
|
||
};
|
||
|
||
/// در اولین مرحلهی splash صدا زده میشود (قبل از هر API call).
|
||
/// در صورت لزوم data قدیمی را پاک میکند و سپس نسخهی فعلی را ذخیره میکند.
|
||
static Future<void> runIfNeeded() async {
|
||
try {
|
||
final stored = await StorageService.getValue(key: _storageKey);
|
||
final int previousVersion = _parseInt(stored);
|
||
if (previousVersion >= _breakingDataVersion) {
|
||
return; // نیازی به migration نیست.
|
||
}
|
||
debugPrint(
|
||
'AppMigration: detected previous schema=$previousVersion '
|
||
'(< $_breakingDataVersion), running cleanup...',
|
||
);
|
||
await _clearLegacyData();
|
||
await StorageService.setValue(
|
||
key: _storageKey,
|
||
value: _breakingDataVersion.toString(),
|
||
);
|
||
debugPrint('AppMigration: done, marker set to $_breakingDataVersion');
|
||
} catch (e) {
|
||
// migration نباید app رو crash بده — اگه چیزی شکست، فقط log
|
||
debugPrint('AppMigration failed (non-fatal): $e');
|
||
}
|
||
}
|
||
|
||
/// پاکسازی auth + همهی state صفحهای؛ UI prefs حفظ میشوند.
|
||
static Future<void> _clearLegacyData() async {
|
||
// 1. توکنها (legacy + keycloak)
|
||
try {
|
||
await TokenStorage.clear();
|
||
} catch (e) {
|
||
debugPrint('AppMigration: TokenStorage.clear failed: $e');
|
||
}
|
||
// 2. کلیدهای متفرقهی legacy
|
||
const legacyKeys = [
|
||
'token',
|
||
'refresh_token',
|
||
'user_data',
|
||
'user_id',
|
||
'notification', // پایهی notification ids
|
||
'image-cache',
|
||
];
|
||
for (final k in legacyKeys) {
|
||
try {
|
||
await StorageService.delete(key: k);
|
||
} catch (_) {}
|
||
}
|
||
}
|
||
|
||
static int _parseInt(dynamic v) {
|
||
if (v == null) return 0;
|
||
if (v is int) return v;
|
||
return int.tryParse(v.toString()) ?? 0;
|
||
}
|
||
|
||
/// برای debug — نسخهی فعلی app
|
||
static Future<String> currentAppVersion() async {
|
||
try {
|
||
final info = await PackageInfo.fromPlatform();
|
||
return info.version;
|
||
} catch (_) {
|
||
return 'unknown';
|
||
}
|
||
}
|
||
}
|