mirror of
https://github.com/immich-app/immich.git
synced 2025-09-29 15:31:13 -04:00
fix: repeat timeline migration for first time user (#21794)
This commit is contained in:
parent
56e5236a39
commit
2d2673c114
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -42,49 +44,13 @@ class _ChangeExperiencePageState extends ConsumerState<ChangeExperiencePage> {
|
|||||||
|
|
||||||
Future<void> _handleMigration() async {
|
Future<void> _handleMigration() async {
|
||||||
try {
|
try {
|
||||||
if (widget.switchingToBeta) {
|
await _performMigrationLogic().timeout(
|
||||||
final assetNotifier = ref.read(assetProvider.notifier);
|
const Duration(minutes: 3),
|
||||||
if (assetNotifier.mounted) {
|
onTimeout: () async {
|
||||||
assetNotifier.dispose();
|
await IsarStoreRepository(ref.read(isarProvider)).upsert(StoreKey.betaTimeline, widget.switchingToBeta);
|
||||||
}
|
await DriftStoreRepository(ref.read(driftProvider)).upsert(StoreKey.betaTimeline, widget.switchingToBeta);
|
||||||
final albumNotifier = ref.read(albumProvider.notifier);
|
},
|
||||||
if (albumNotifier.mounted) {
|
);
|
||||||
albumNotifier.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel uploads
|
|
||||||
await Store.put(StoreKey.backgroundBackup, false);
|
|
||||||
ref
|
|
||||||
.read(backupProvider.notifier)
|
|
||||||
.configureBackgroundBackup(enabled: false, onBatteryInfo: () {}, onError: (_) {});
|
|
||||||
ref.read(backupProvider.notifier).setAutoBackup(false);
|
|
||||||
ref.read(backupProvider.notifier).cancelBackup();
|
|
||||||
ref.read(manualUploadProvider.notifier).cancelBackup();
|
|
||||||
// Start listening to new websocket events
|
|
||||||
ref.read(websocketProvider.notifier).stopListenToOldEvents();
|
|
||||||
ref.read(websocketProvider.notifier).startListeningToBetaEvents();
|
|
||||||
|
|
||||||
final permission = await ref.read(galleryPermissionNotifier.notifier).requestGalleryPermission();
|
|
||||||
|
|
||||||
if (permission.isGranted) {
|
|
||||||
await ref.read(backgroundSyncProvider).syncLocal(full: true);
|
|
||||||
await migrateDeviceAssetToSqlite(ref.read(isarProvider), ref.read(driftProvider));
|
|
||||||
await migrateBackupAlbumsToSqlite(ref.read(isarProvider), ref.read(driftProvider));
|
|
||||||
await migrateStoreToSqlite(ref.read(isarProvider), ref.read(driftProvider));
|
|
||||||
await ref.read(backgroundServiceProvider).disableService();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await ref.read(backgroundSyncProvider).cancel();
|
|
||||||
ref.read(websocketProvider.notifier).stopListeningToBetaEvents();
|
|
||||||
ref.read(websocketProvider.notifier).startListeningToOldEvents();
|
|
||||||
ref.read(readonlyModeProvider.notifier).setReadonlyMode(false);
|
|
||||||
await migrateStoreToIsar(ref.read(isarProvider), ref.read(driftProvider));
|
|
||||||
await ref.read(backgroundServiceProvider).resumeServiceIfEnabled();
|
|
||||||
await ref.read(backgroundWorkerFgServiceProvider).disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
await IsarStoreRepository(ref.read(isarProvider)).upsert(StoreKey.betaTimeline, widget.switchingToBeta);
|
|
||||||
await DriftStoreRepository(ref.read(driftProvider)).upsert(StoreKey.betaTimeline, widget.switchingToBeta);
|
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -102,6 +68,52 @@ class _ChangeExperiencePageState extends ConsumerState<ChangeExperiencePage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _performMigrationLogic() async {
|
||||||
|
if (widget.switchingToBeta) {
|
||||||
|
final assetNotifier = ref.read(assetProvider.notifier);
|
||||||
|
if (assetNotifier.mounted) {
|
||||||
|
assetNotifier.dispose();
|
||||||
|
}
|
||||||
|
final albumNotifier = ref.read(albumProvider.notifier);
|
||||||
|
if (albumNotifier.mounted) {
|
||||||
|
albumNotifier.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel uploads
|
||||||
|
await Store.put(StoreKey.backgroundBackup, false);
|
||||||
|
ref
|
||||||
|
.read(backupProvider.notifier)
|
||||||
|
.configureBackgroundBackup(enabled: false, onBatteryInfo: () {}, onError: (_) {});
|
||||||
|
ref.read(backupProvider.notifier).setAutoBackup(false);
|
||||||
|
ref.read(backupProvider.notifier).cancelBackup();
|
||||||
|
ref.read(manualUploadProvider.notifier).cancelBackup();
|
||||||
|
// Start listening to new websocket events
|
||||||
|
ref.read(websocketProvider.notifier).stopListenToOldEvents();
|
||||||
|
ref.read(websocketProvider.notifier).startListeningToBetaEvents();
|
||||||
|
|
||||||
|
final permission = await ref.read(galleryPermissionNotifier.notifier).requestGalleryPermission();
|
||||||
|
|
||||||
|
if (permission.isGranted) {
|
||||||
|
await ref.read(backgroundSyncProvider).syncLocal(full: true);
|
||||||
|
await migrateDeviceAssetToSqlite(ref.read(isarProvider), ref.read(driftProvider));
|
||||||
|
await migrateBackupAlbumsToSqlite(ref.read(isarProvider), ref.read(driftProvider));
|
||||||
|
await migrateStoreToSqlite(ref.read(isarProvider), ref.read(driftProvider));
|
||||||
|
await ref.read(backgroundServiceProvider).disableService();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await ref.read(backgroundSyncProvider).cancel();
|
||||||
|
ref.read(websocketProvider.notifier).stopListeningToBetaEvents();
|
||||||
|
ref.read(websocketProvider.notifier).startListeningToOldEvents();
|
||||||
|
ref.read(readonlyModeProvider.notifier).setReadonlyMode(false);
|
||||||
|
await migrateStoreToIsar(ref.read(isarProvider), ref.read(driftProvider));
|
||||||
|
await ref.read(backgroundServiceProvider).resumeServiceIfEnabled();
|
||||||
|
await ref.read(backgroundWorkerFgServiceProvider).disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
await IsarStoreRepository(ref.read(isarProvider)).upsert(StoreKey.betaTimeline, widget.switchingToBeta);
|
||||||
|
await DriftStoreRepository(ref.read(driftProvider)).upsert(StoreKey.betaTimeline, widget.switchingToBeta);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@ -167,13 +167,6 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
|||||||
}
|
}
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
_log.severe("Error during background sync", e, stackTrace);
|
_log.severe("Error during background sync", e, stackTrace);
|
||||||
} finally {
|
|
||||||
// Ensure lock is released even if operations fail
|
|
||||||
try {
|
|
||||||
_log.info("Lock released after background sync operations");
|
|
||||||
} catch (lockError) {
|
|
||||||
_log.warning("Failed to release lock after error: $lockError");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,10 @@ Future<void> migrateDatabaseIfNeeded(Isar db, Drift drift) async {
|
|||||||
|
|
||||||
// Handle migration only for this version
|
// Handle migration only for this version
|
||||||
// TODO: remove when old timeline is removed
|
// TODO: remove when old timeline is removed
|
||||||
if (version == 15) {
|
final needBetaMigration = Store.tryGet(StoreKey.needBetaMigration);
|
||||||
|
if (version == 15 && needBetaMigration == null) {
|
||||||
|
// Check both databases directly instead of relying on cache
|
||||||
|
|
||||||
final isBeta = Store.tryGet(StoreKey.betaTimeline);
|
final isBeta = Store.tryGet(StoreKey.betaTimeline);
|
||||||
final isNewInstallation = await _isNewInstallation(db, drift);
|
final isNewInstallation = await _isNewInstallation(db, drift);
|
||||||
|
|
||||||
@ -71,6 +74,7 @@ Future<void> migrateDatabaseIfNeeded(Isar db, Drift drift) async {
|
|||||||
// For existing installations, only migrate if beta timeline is not enabled (null or false)
|
// For existing installations, only migrate if beta timeline is not enabled (null or false)
|
||||||
if (isNewInstallation || isBeta == true) {
|
if (isNewInstallation || isBeta == true) {
|
||||||
await Store.put(StoreKey.needBetaMigration, false);
|
await Store.put(StoreKey.needBetaMigration, false);
|
||||||
|
await Store.put(StoreKey.betaTimeline, true);
|
||||||
} else {
|
} else {
|
||||||
await resetDriftDatabase(drift);
|
await resetDriftDatabase(drift);
|
||||||
await Store.put(StoreKey.needBetaMigration, true);
|
await Store.put(StoreKey.needBetaMigration, true);
|
||||||
|
@ -104,7 +104,6 @@ class SyncStatusAndActions extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.only(top: 16, bottom: 32),
|
padding: const EdgeInsets.only(top: 16, bottom: 32),
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
_SectionHeaderText(text: "assets".t(context: context)),
|
|
||||||
const _SyncStatsCounts(),
|
const _SyncStatsCounts(),
|
||||||
const Divider(height: 1, indent: 16, endIndent: 16),
|
const Divider(height: 1, indent: 16, endIndent: 16),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
@ -270,7 +269,10 @@ class _SyncStatsCounts extends ConsumerWidget {
|
|||||||
final localHashedCount = snapshot.data![4]! as int;
|
final localHashedCount = snapshot.data![4]! as int;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
_SectionHeaderText(text: "assets".t(context: context)),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
||||||
child: Flex(
|
child: Flex(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user