runable
This commit is contained in:
223
lib/core/providers/sync_status_provider.dart
Normal file
223
lib/core/providers/sync_status_provider.dart
Normal file
@@ -0,0 +1,223 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import '../../features/products/presentation/providers/products_provider.dart';
|
||||
import '../../features/categories/presentation/providers/categories_provider.dart';
|
||||
import '../../features/settings/presentation/providers/settings_provider.dart';
|
||||
import 'network_info_provider.dart';
|
||||
|
||||
part 'sync_status_provider.g.dart';
|
||||
|
||||
/// Sync status provider - manages data synchronization state
|
||||
@riverpod
|
||||
class SyncStatus extends _$SyncStatus {
|
||||
@override
|
||||
Future<SyncResult> build() async {
|
||||
// Initialize with idle state
|
||||
return const SyncResult(
|
||||
status: SyncState.idle,
|
||||
lastSyncTime: null,
|
||||
message: 'Ready to sync',
|
||||
);
|
||||
}
|
||||
|
||||
/// Perform full sync of all data
|
||||
Future<void> syncAll() async {
|
||||
// Check network connectivity first
|
||||
final isConnected = await ref.read(isConnectedProvider.future);
|
||||
if (!isConnected) {
|
||||
state = const AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.offline,
|
||||
lastSyncTime: null,
|
||||
message: 'No internet connection',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start sync
|
||||
state = const AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.syncing,
|
||||
lastSyncTime: null,
|
||||
message: 'Syncing data...',
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
// Sync categories first (products depend on categories)
|
||||
await ref.read(categoriesProvider.notifier).syncCategories();
|
||||
|
||||
// Then sync products
|
||||
await ref.read(productsProvider.notifier).syncProducts();
|
||||
|
||||
// Update last sync time in settings
|
||||
await ref.read(settingsProvider.notifier).updateLastSyncTime();
|
||||
|
||||
// Sync completed successfully
|
||||
state = AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.success,
|
||||
lastSyncTime: DateTime.now(),
|
||||
message: 'Sync completed successfully',
|
||||
),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
// Sync failed
|
||||
state = AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.failed,
|
||||
lastSyncTime: null,
|
||||
message: 'Sync failed: ${error.toString()}',
|
||||
error: error,
|
||||
),
|
||||
);
|
||||
|
||||
// Also set error state for proper error handling
|
||||
state = AsyncValue.error(error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync only products
|
||||
Future<void> syncProducts() async {
|
||||
final isConnected = await ref.read(isConnectedProvider.future);
|
||||
if (!isConnected) {
|
||||
state = const AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.offline,
|
||||
lastSyncTime: null,
|
||||
message: 'No internet connection',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
state = const AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.syncing,
|
||||
lastSyncTime: null,
|
||||
message: 'Syncing products...',
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
await ref.read(productsProvider.notifier).syncProducts();
|
||||
await ref.read(settingsProvider.notifier).updateLastSyncTime();
|
||||
|
||||
state = AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.success,
|
||||
lastSyncTime: DateTime.now(),
|
||||
message: 'Products synced successfully',
|
||||
),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
state = AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.failed,
|
||||
lastSyncTime: null,
|
||||
message: 'Product sync failed: ${error.toString()}',
|
||||
error: error,
|
||||
),
|
||||
);
|
||||
state = AsyncValue.error(error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync only categories
|
||||
Future<void> syncCategories() async {
|
||||
final isConnected = await ref.read(isConnectedProvider.future);
|
||||
if (!isConnected) {
|
||||
state = const AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.offline,
|
||||
lastSyncTime: null,
|
||||
message: 'No internet connection',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
state = const AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.syncing,
|
||||
lastSyncTime: null,
|
||||
message: 'Syncing categories...',
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
await ref.read(categoriesProvider.notifier).syncCategories();
|
||||
await ref.read(settingsProvider.notifier).updateLastSyncTime();
|
||||
|
||||
state = AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.success,
|
||||
lastSyncTime: DateTime.now(),
|
||||
message: 'Categories synced successfully',
|
||||
),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
state = AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.failed,
|
||||
lastSyncTime: null,
|
||||
message: 'Category sync failed: ${error.toString()}',
|
||||
error: error,
|
||||
),
|
||||
);
|
||||
state = AsyncValue.error(error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset sync status to idle
|
||||
void resetStatus() {
|
||||
state = const AsyncValue.data(
|
||||
SyncResult(
|
||||
status: SyncState.idle,
|
||||
lastSyncTime: null,
|
||||
message: 'Ready to sync',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync state enum
|
||||
enum SyncState {
|
||||
idle,
|
||||
syncing,
|
||||
success,
|
||||
failed,
|
||||
offline,
|
||||
}
|
||||
|
||||
/// Sync result model
|
||||
class SyncResult {
|
||||
final SyncState status;
|
||||
final DateTime? lastSyncTime;
|
||||
final String message;
|
||||
final Object? error;
|
||||
|
||||
const SyncResult({
|
||||
required this.status,
|
||||
required this.lastSyncTime,
|
||||
required this.message,
|
||||
this.error,
|
||||
});
|
||||
|
||||
bool get isSyncing => status == SyncState.syncing;
|
||||
bool get isSuccess => status == SyncState.success;
|
||||
bool get isFailed => status == SyncState.failed;
|
||||
bool get isOffline => status == SyncState.offline;
|
||||
bool get isIdle => status == SyncState.idle;
|
||||
}
|
||||
|
||||
/// Provider for last sync time from settings
|
||||
@riverpod
|
||||
DateTime? lastSyncTime(Ref ref) {
|
||||
final settingsAsync = ref.watch(settingsProvider);
|
||||
return settingsAsync.when(
|
||||
data: (settings) => settings.lastSyncAt,
|
||||
loading: () => null,
|
||||
error: (_, __) => null,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user