init cc
This commit is contained in:
22
lib/shared/domain/usecases/usecase.dart
Normal file
22
lib/shared/domain/usecases/usecase.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import '../../../core/utils/typedef.dart';
|
||||
|
||||
/// Base usecase class for implementing clean architecture use cases
|
||||
abstract class UseCase<T, Params> {
|
||||
const UseCase();
|
||||
|
||||
/// Execute the use case with given parameters
|
||||
AsyncResult<T> call(Params params);
|
||||
}
|
||||
|
||||
/// Use case that doesn't require any parameters
|
||||
abstract class UseCaseWithoutParams<T> {
|
||||
const UseCaseWithoutParams();
|
||||
|
||||
/// Execute the use case without parameters
|
||||
AsyncResult<T> call();
|
||||
}
|
||||
|
||||
/// No parameters class for use cases that don't need parameters
|
||||
class NoParams {
|
||||
const NoParams();
|
||||
}
|
||||
95
lib/shared/presentation/providers/app_providers.dart
Normal file
95
lib/shared/presentation/providers/app_providers.dart
Normal file
@@ -0,0 +1,95 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import '../../../core/constants/storage_constants.dart';
|
||||
import '../../../core/network/dio_client.dart';
|
||||
import '../../../core/providers/network_providers.dart';
|
||||
|
||||
/// Secure storage provider
|
||||
final secureStorageProvider = Provider<FlutterSecureStorage>(
|
||||
(ref) => const FlutterSecureStorage(
|
||||
aOptions: AndroidOptions(
|
||||
encryptedSharedPreferences: true,
|
||||
),
|
||||
iOptions: IOSOptions(),
|
||||
),
|
||||
);
|
||||
|
||||
/// HTTP client provider
|
||||
final httpClientProvider = Provider<DioClient>(
|
||||
(ref) {
|
||||
final networkInfo = ref.watch(networkInfoProvider);
|
||||
final secureStorage = ref.watch(secureStorageProvider);
|
||||
|
||||
return DioClient(
|
||||
networkInfo: networkInfo,
|
||||
secureStorage: secureStorage,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
/// App settings Hive box provider
|
||||
final appSettingsBoxProvider = Provider<Box>(
|
||||
(ref) => Hive.box(StorageConstants.appSettingsBox),
|
||||
);
|
||||
|
||||
/// Cache Hive box provider
|
||||
final cacheBoxProvider = Provider<Box>(
|
||||
(ref) => Hive.box(StorageConstants.cacheBox),
|
||||
);
|
||||
|
||||
/// User data Hive box provider
|
||||
final userDataBoxProvider = Provider<Box>(
|
||||
(ref) => Hive.box(StorageConstants.userDataBox),
|
||||
);
|
||||
|
||||
/// Theme mode provider
|
||||
final themeModeProvider = StateNotifierProvider<ThemeModeNotifier, ThemeMode>(
|
||||
(ref) => ThemeModeNotifier(ref.watch(appSettingsBoxProvider)),
|
||||
);
|
||||
|
||||
/// Theme mode notifier
|
||||
class ThemeModeNotifier extends StateNotifier<ThemeMode> {
|
||||
final Box _box;
|
||||
|
||||
ThemeModeNotifier(this._box) : super(ThemeMode.system) {
|
||||
_loadThemeMode();
|
||||
}
|
||||
|
||||
void _loadThemeMode() {
|
||||
final isDarkMode = _box.get(StorageConstants.isDarkModeKey, defaultValue: null);
|
||||
if (isDarkMode == null) {
|
||||
state = ThemeMode.system;
|
||||
} else {
|
||||
state = isDarkMode ? ThemeMode.dark : ThemeMode.light;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setThemeMode(ThemeMode mode) async {
|
||||
state = mode;
|
||||
switch (mode) {
|
||||
case ThemeMode.system:
|
||||
await _box.delete(StorageConstants.isDarkModeKey);
|
||||
break;
|
||||
case ThemeMode.light:
|
||||
await _box.put(StorageConstants.isDarkModeKey, false);
|
||||
break;
|
||||
case ThemeMode.dark:
|
||||
await _box.put(StorageConstants.isDarkModeKey, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleTheme() async {
|
||||
switch (state) {
|
||||
case ThemeMode.system:
|
||||
case ThemeMode.light:
|
||||
await setThemeMode(ThemeMode.dark);
|
||||
break;
|
||||
case ThemeMode.dark:
|
||||
await setThemeMode(ThemeMode.light);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
345
lib/shared/presentation/providers/connectivity_providers.dart
Normal file
345
lib/shared/presentation/providers/connectivity_providers.dart
Normal file
@@ -0,0 +1,345 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
part 'connectivity_providers.g.dart';
|
||||
|
||||
/// Network connection type
|
||||
enum NetworkConnectionType {
|
||||
wifi,
|
||||
mobile,
|
||||
ethernet,
|
||||
bluetooth,
|
||||
vpn,
|
||||
other,
|
||||
none,
|
||||
}
|
||||
|
||||
/// Network status data class
|
||||
class NetworkStatus {
|
||||
final bool isConnected;
|
||||
final NetworkConnectionType connectionType;
|
||||
final DateTime lastUpdated;
|
||||
final String? errorMessage;
|
||||
|
||||
const NetworkStatus({
|
||||
required this.isConnected,
|
||||
required this.connectionType,
|
||||
required this.lastUpdated,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
NetworkStatus copyWith({
|
||||
bool? isConnected,
|
||||
NetworkConnectionType? connectionType,
|
||||
DateTime? lastUpdated,
|
||||
String? errorMessage,
|
||||
}) {
|
||||
return NetworkStatus(
|
||||
isConnected: isConnected ?? this.isConnected,
|
||||
connectionType: connectionType ?? this.connectionType,
|
||||
lastUpdated: lastUpdated ?? this.lastUpdated,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NetworkStatus{isConnected: $isConnected, connectionType: $connectionType, lastUpdated: $lastUpdated}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is NetworkStatus &&
|
||||
other.isConnected == isConnected &&
|
||||
other.connectionType == connectionType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return isConnected.hashCode ^ connectionType.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert ConnectivityResult to NetworkConnectionType
|
||||
NetworkConnectionType _getConnectionType(List<ConnectivityResult> results) {
|
||||
if (results.isEmpty || results.contains(ConnectivityResult.none)) {
|
||||
return NetworkConnectionType.none;
|
||||
}
|
||||
|
||||
if (results.contains(ConnectivityResult.wifi)) {
|
||||
return NetworkConnectionType.wifi;
|
||||
}
|
||||
|
||||
if (results.contains(ConnectivityResult.mobile)) {
|
||||
return NetworkConnectionType.mobile;
|
||||
}
|
||||
|
||||
if (results.contains(ConnectivityResult.ethernet)) {
|
||||
return NetworkConnectionType.ethernet;
|
||||
}
|
||||
|
||||
if (results.contains(ConnectivityResult.bluetooth)) {
|
||||
return NetworkConnectionType.bluetooth;
|
||||
}
|
||||
|
||||
if (results.contains(ConnectivityResult.vpn)) {
|
||||
return NetworkConnectionType.vpn;
|
||||
}
|
||||
|
||||
if (results.contains(ConnectivityResult.other)) {
|
||||
return NetworkConnectionType.other;
|
||||
}
|
||||
|
||||
return NetworkConnectionType.none;
|
||||
}
|
||||
|
||||
/// Connectivity instance provider
|
||||
@riverpod
|
||||
Connectivity connectivity(ConnectivityRef ref) {
|
||||
return Connectivity();
|
||||
}
|
||||
|
||||
/// Network connectivity stream provider
|
||||
@riverpod
|
||||
Stream<NetworkStatus> networkConnectivityStream(NetworkConnectivityStreamRef ref) {
|
||||
final connectivity = ref.watch(connectivityProvider);
|
||||
|
||||
return connectivity.onConnectivityChanged.map((results) {
|
||||
final connectionType = _getConnectionType(results);
|
||||
final isConnected = connectionType != NetworkConnectionType.none;
|
||||
|
||||
return NetworkStatus(
|
||||
isConnected: isConnected,
|
||||
connectionType: connectionType,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}).handleError((error) {
|
||||
debugPrint('❌ Connectivity stream error: $error');
|
||||
return NetworkStatus(
|
||||
isConnected: false,
|
||||
connectionType: NetworkConnectionType.none,
|
||||
lastUpdated: DateTime.now(),
|
||||
errorMessage: error.toString(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Current network status provider
|
||||
@riverpod
|
||||
class NetworkStatusNotifier extends _$NetworkStatusNotifier {
|
||||
@override
|
||||
NetworkStatus build() {
|
||||
// Start listening to connectivity changes
|
||||
final streamValue = ref.watch(networkConnectivityStreamProvider);
|
||||
streamValue.whenData((status) {
|
||||
state = status;
|
||||
_logConnectionChange(status);
|
||||
});
|
||||
|
||||
// Get initial connectivity state
|
||||
_checkInitialConnectivity();
|
||||
|
||||
// Return initial state
|
||||
return NetworkStatus(
|
||||
isConnected: false,
|
||||
connectionType: NetworkConnectionType.none,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _checkInitialConnectivity() async {
|
||||
try {
|
||||
final connectivity = ref.read(connectivityProvider);
|
||||
final result = await connectivity.checkConnectivity();
|
||||
final connectionType = _getConnectionType(result);
|
||||
final isConnected = connectionType != NetworkConnectionType.none;
|
||||
|
||||
state = NetworkStatus(
|
||||
isConnected: isConnected,
|
||||
connectionType: connectionType,
|
||||
lastUpdated: DateTime.now(),
|
||||
);
|
||||
|
||||
debugPrint('📡 Initial connectivity: ${isConnected ? '✅ Connected' : '❌ Disconnected'} ($connectionType)');
|
||||
} catch (error) {
|
||||
debugPrint('❌ Error checking initial connectivity: $error');
|
||||
state = NetworkStatus(
|
||||
isConnected: false,
|
||||
connectionType: NetworkConnectionType.none,
|
||||
lastUpdated: DateTime.now(),
|
||||
errorMessage: error.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _logConnectionChange(NetworkStatus status) {
|
||||
final icon = status.isConnected ? '📶' : '📵';
|
||||
final statusText = status.isConnected ? 'Connected' : 'Disconnected';
|
||||
debugPrint('$icon Network status changed: $statusText (${status.connectionType})');
|
||||
}
|
||||
|
||||
/// Force refresh network status
|
||||
Future<void> refresh() async {
|
||||
await _checkInitialConnectivity();
|
||||
}
|
||||
|
||||
/// Get connection strength (mock implementation)
|
||||
double getConnectionStrength() {
|
||||
switch (state.connectionType) {
|
||||
case NetworkConnectionType.wifi:
|
||||
return 1.0; // Assume strong Wi-Fi
|
||||
case NetworkConnectionType.ethernet:
|
||||
return 1.0; // Assume strong ethernet
|
||||
case NetworkConnectionType.mobile:
|
||||
return 0.7; // Assume moderate mobile
|
||||
case NetworkConnectionType.bluetooth:
|
||||
return 0.5; // Assume weak bluetooth
|
||||
case NetworkConnectionType.vpn:
|
||||
return 0.8; // Assume good VPN
|
||||
case NetworkConnectionType.other:
|
||||
return 0.6; // Assume moderate other
|
||||
case NetworkConnectionType.none:
|
||||
return 0.0; // No connection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple connectivity status provider
|
||||
@riverpod
|
||||
bool isConnected(IsConnectedRef ref) {
|
||||
final networkStatus = ref.watch(networkStatusNotifierProvider);
|
||||
return networkStatus.isConnected;
|
||||
}
|
||||
|
||||
/// Connection type provider
|
||||
@riverpod
|
||||
NetworkConnectionType connectionType(ConnectionTypeRef ref) {
|
||||
final networkStatus = ref.watch(networkStatusNotifierProvider);
|
||||
return networkStatus.connectionType;
|
||||
}
|
||||
|
||||
/// Is Wi-Fi connected provider
|
||||
@riverpod
|
||||
bool isWifiConnected(IsWifiConnectedRef ref) {
|
||||
final networkStatus = ref.watch(networkStatusNotifierProvider);
|
||||
return networkStatus.isConnected && networkStatus.connectionType == NetworkConnectionType.wifi;
|
||||
}
|
||||
|
||||
/// Is mobile data connected provider
|
||||
@riverpod
|
||||
bool isMobileConnected(IsMobileConnectedRef ref) {
|
||||
final networkStatus = ref.watch(networkStatusNotifierProvider);
|
||||
return networkStatus.isConnected && networkStatus.connectionType == NetworkConnectionType.mobile;
|
||||
}
|
||||
|
||||
/// Network quality indicator provider
|
||||
@riverpod
|
||||
String networkQuality(NetworkQualityRef ref) {
|
||||
final networkStatus = ref.watch(networkStatusNotifierProvider);
|
||||
|
||||
if (!networkStatus.isConnected) {
|
||||
return 'No Connection';
|
||||
}
|
||||
|
||||
switch (networkStatus.connectionType) {
|
||||
case NetworkConnectionType.wifi:
|
||||
return 'Excellent';
|
||||
case NetworkConnectionType.ethernet:
|
||||
return 'Excellent';
|
||||
case NetworkConnectionType.mobile:
|
||||
return 'Good';
|
||||
case NetworkConnectionType.vpn:
|
||||
return 'Good';
|
||||
case NetworkConnectionType.other:
|
||||
return 'Fair';
|
||||
case NetworkConnectionType.bluetooth:
|
||||
return 'Poor';
|
||||
case NetworkConnectionType.none:
|
||||
return 'No Connection';
|
||||
}
|
||||
}
|
||||
|
||||
/// Network history provider for tracking connection changes
|
||||
@riverpod
|
||||
class NetworkHistoryNotifier extends _$NetworkHistoryNotifier {
|
||||
static const int _maxHistorySize = 50;
|
||||
|
||||
@override
|
||||
List<NetworkStatus> build() {
|
||||
// Listen to network status changes and add to history
|
||||
ref.listen(networkStatusNotifierProvider, (previous, next) {
|
||||
if (previous != next) {
|
||||
_addToHistory(next);
|
||||
}
|
||||
});
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
void _addToHistory(NetworkStatus status) {
|
||||
final newHistory = [...state, status];
|
||||
|
||||
// Keep only the last _maxHistorySize entries
|
||||
if (newHistory.length > _maxHistorySize) {
|
||||
newHistory.removeRange(0, newHistory.length - _maxHistorySize);
|
||||
}
|
||||
|
||||
state = newHistory;
|
||||
}
|
||||
|
||||
/// Get recent connection changes
|
||||
List<NetworkStatus> getRecentChanges({int count = 10}) {
|
||||
return state.reversed.take(count).toList();
|
||||
}
|
||||
|
||||
/// Get connection uptime percentage
|
||||
double getUptimePercentage({Duration? period}) {
|
||||
if (state.isEmpty) return 0.0;
|
||||
|
||||
final now = DateTime.now();
|
||||
final startTime = period != null ? now.subtract(period) : state.first.lastUpdated;
|
||||
|
||||
final relevantEntries = state.where((status) => status.lastUpdated.isAfter(startTime)).toList();
|
||||
|
||||
if (relevantEntries.isEmpty) return 0.0;
|
||||
|
||||
final connectedCount = relevantEntries.where((status) => status.isConnected).length;
|
||||
return connectedCount / relevantEntries.length;
|
||||
}
|
||||
|
||||
/// Clear history
|
||||
void clearHistory() {
|
||||
state = [];
|
||||
}
|
||||
|
||||
/// Get connection statistics
|
||||
Map<String, dynamic> getConnectionStats() {
|
||||
if (state.isEmpty) {
|
||||
return {
|
||||
'totalChanges': 0,
|
||||
'uptimePercentage': 0.0,
|
||||
'mostCommonConnection': 'Unknown',
|
||||
'connectionTypes': <String, int>{},
|
||||
};
|
||||
}
|
||||
|
||||
final connectionTypeCounts = <NetworkConnectionType, int>{};
|
||||
for (final status in state) {
|
||||
connectionTypeCounts[status.connectionType] = (connectionTypeCounts[status.connectionType] ?? 0) + 1;
|
||||
}
|
||||
|
||||
final mostCommonType = connectionTypeCounts.entries.reduce((a, b) => a.value > b.value ? a : b).key;
|
||||
|
||||
return {
|
||||
'totalChanges': state.length,
|
||||
'uptimePercentage': getUptimePercentage(),
|
||||
'mostCommonConnection': mostCommonType.toString().split('.').last,
|
||||
'connectionTypes': connectionTypeCounts.map((key, value) => MapEntry(key.toString().split('.').last, value)),
|
||||
};
|
||||
}
|
||||
}
|
||||
169
lib/shared/presentation/providers/connectivity_providers.g.dart
Normal file
169
lib/shared/presentation/providers/connectivity_providers.g.dart
Normal file
@@ -0,0 +1,169 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'connectivity_providers.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$connectivityHash() => r'da8080dfc40288eff97ff9cb96e9d9577714a9a0';
|
||||
|
||||
/// Connectivity instance provider
|
||||
///
|
||||
/// Copied from [connectivity].
|
||||
@ProviderFor(connectivity)
|
||||
final connectivityProvider = AutoDisposeProvider<Connectivity>.internal(
|
||||
connectivity,
|
||||
name: r'connectivityProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$connectivityHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef ConnectivityRef = AutoDisposeProviderRef<Connectivity>;
|
||||
String _$networkConnectivityStreamHash() =>
|
||||
r'0850402a3f1ed68481cfa9b8a3a371c804c358f3';
|
||||
|
||||
/// Network connectivity stream provider
|
||||
///
|
||||
/// Copied from [networkConnectivityStream].
|
||||
@ProviderFor(networkConnectivityStream)
|
||||
final networkConnectivityStreamProvider =
|
||||
AutoDisposeStreamProvider<NetworkStatus>.internal(
|
||||
networkConnectivityStream,
|
||||
name: r'networkConnectivityStreamProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$networkConnectivityStreamHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef NetworkConnectivityStreamRef
|
||||
= AutoDisposeStreamProviderRef<NetworkStatus>;
|
||||
String _$isConnectedHash() => r'89efbfc9ecb21e2ff1a7f6eea736457e35bed181';
|
||||
|
||||
/// Simple connectivity status provider
|
||||
///
|
||||
/// Copied from [isConnected].
|
||||
@ProviderFor(isConnected)
|
||||
final isConnectedProvider = AutoDisposeProvider<bool>.internal(
|
||||
isConnected,
|
||||
name: r'isConnectedProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$isConnectedHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef IsConnectedRef = AutoDisposeProviderRef<bool>;
|
||||
String _$connectionTypeHash() => r'fd1d65f0ae9afe2b04b358755ed4347e27a0515f';
|
||||
|
||||
/// Connection type provider
|
||||
///
|
||||
/// Copied from [connectionType].
|
||||
@ProviderFor(connectionType)
|
||||
final connectionTypeProvider =
|
||||
AutoDisposeProvider<NetworkConnectionType>.internal(
|
||||
connectionType,
|
||||
name: r'connectionTypeProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$connectionTypeHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef ConnectionTypeRef = AutoDisposeProviderRef<NetworkConnectionType>;
|
||||
String _$isWifiConnectedHash() => r'6ab4a8f83d5073544d77620bea093f4b34d61e05';
|
||||
|
||||
/// Is Wi-Fi connected provider
|
||||
///
|
||||
/// Copied from [isWifiConnected].
|
||||
@ProviderFor(isWifiConnected)
|
||||
final isWifiConnectedProvider = AutoDisposeProvider<bool>.internal(
|
||||
isWifiConnected,
|
||||
name: r'isWifiConnectedProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$isWifiConnectedHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef IsWifiConnectedRef = AutoDisposeProviderRef<bool>;
|
||||
String _$isMobileConnectedHash() => r'1e03a490b5a59ac598fe75b45c42b353cec26129';
|
||||
|
||||
/// Is mobile data connected provider
|
||||
///
|
||||
/// Copied from [isMobileConnected].
|
||||
@ProviderFor(isMobileConnected)
|
||||
final isMobileConnectedProvider = AutoDisposeProvider<bool>.internal(
|
||||
isMobileConnected,
|
||||
name: r'isMobileConnectedProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$isMobileConnectedHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef IsMobileConnectedRef = AutoDisposeProviderRef<bool>;
|
||||
String _$networkQualityHash() => r'b72cb19e0b8537514827d11fbe2f46bba4e94ac2';
|
||||
|
||||
/// Network quality indicator provider
|
||||
///
|
||||
/// Copied from [networkQuality].
|
||||
@ProviderFor(networkQuality)
|
||||
final networkQualityProvider = AutoDisposeProvider<String>.internal(
|
||||
networkQuality,
|
||||
name: r'networkQualityProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$networkQualityHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef NetworkQualityRef = AutoDisposeProviderRef<String>;
|
||||
String _$networkStatusNotifierHash() =>
|
||||
r'adebb286dce36d8cb54504f04a67dd4c00dceade';
|
||||
|
||||
/// Current network status provider
|
||||
///
|
||||
/// Copied from [NetworkStatusNotifier].
|
||||
@ProviderFor(NetworkStatusNotifier)
|
||||
final networkStatusNotifierProvider =
|
||||
AutoDisposeNotifierProvider<NetworkStatusNotifier, NetworkStatus>.internal(
|
||||
NetworkStatusNotifier.new,
|
||||
name: r'networkStatusNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$networkStatusNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$NetworkStatusNotifier = AutoDisposeNotifier<NetworkStatus>;
|
||||
String _$networkHistoryNotifierHash() =>
|
||||
r'6498139c6e6e8472c81cb3f1789bcabfc4779943';
|
||||
|
||||
/// Network history provider for tracking connection changes
|
||||
///
|
||||
/// Copied from [NetworkHistoryNotifier].
|
||||
@ProviderFor(NetworkHistoryNotifier)
|
||||
final networkHistoryNotifierProvider = AutoDisposeNotifierProvider<
|
||||
NetworkHistoryNotifier, List<NetworkStatus>>.internal(
|
||||
NetworkHistoryNotifier.new,
|
||||
name: r'networkHistoryNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$networkHistoryNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$NetworkHistoryNotifier = AutoDisposeNotifier<List<NetworkStatus>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
44
lib/shared/widgets/custom_app_bar.dart
Normal file
44
lib/shared/widgets/custom_app_bar.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
const CustomAppBar({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.actions,
|
||||
this.leading,
|
||||
this.backgroundColor,
|
||||
this.foregroundColor,
|
||||
this.elevation = 0,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final List<Widget>? actions;
|
||||
final Widget? leading;
|
||||
final Color? backgroundColor;
|
||||
final Color? foregroundColor;
|
||||
final double elevation;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
|
||||
return AppBar(
|
||||
title: Text(
|
||||
title,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
leading: leading,
|
||||
actions: actions,
|
||||
elevation: elevation,
|
||||
backgroundColor: backgroundColor ?? colorScheme.surfaceVariant,
|
||||
foregroundColor: foregroundColor ?? colorScheme.onSurfaceVariant,
|
||||
centerTitle: true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
}
|
||||
61
lib/shared/widgets/empty_state_widget.dart
Normal file
61
lib/shared/widgets/empty_state_widget.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class EmptyStateWidget extends StatelessWidget {
|
||||
const EmptyStateWidget({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
this.actionButton,
|
||||
this.iconSize = 64.0,
|
||||
});
|
||||
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final Widget? actionButton;
|
||||
final double iconSize;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: iconSize,
|
||||
color: colorScheme.onSurfaceVariant.withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
title,
|
||||
style: theme.textTheme.headlineSmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
subtitle,
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant.withOpacity(0.7),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (actionButton != null) ...[
|
||||
const SizedBox(height: 32),
|
||||
actionButton!,
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
71
lib/shared/widgets/loading_widget.dart
Normal file
71
lib/shared/widgets/loading_widget.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoadingWidget extends StatelessWidget {
|
||||
const LoadingWidget({
|
||||
super.key,
|
||||
this.message,
|
||||
this.size = 24.0,
|
||||
});
|
||||
|
||||
final String? message;
|
||||
final double size;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: size,
|
||||
height: size,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2.0,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
),
|
||||
if (message != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
message!,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LoadingOverlay extends StatelessWidget {
|
||||
const LoadingOverlay({
|
||||
super.key,
|
||||
required this.isLoading,
|
||||
required this.child,
|
||||
this.message,
|
||||
});
|
||||
|
||||
final bool isLoading;
|
||||
final Widget child;
|
||||
final String? message;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
child,
|
||||
if (isLoading)
|
||||
Container(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
child: LoadingWidget(message: message),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user