Files
retail/lib/core/providers/sync_status_provider.dart
2025-10-10 22:49:05 +07:00

224 lines
5.7 KiB
Dart

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).refresh();
// Then sync products
await ref.read(productsProvider.notifier).refresh();
// 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).refresh();
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).refresh();
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,
);
}