import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/widgets.dart'; import 'package:http/http.dart' as http; enum Status { network, maintenance, syncing, apiError } class StatusProvider extends ChangeNotifier { final List _stack = []; double _progress = 0.0; ConnectivityResult _networkType = ConnectivityResult.none; ConnectivityResult get networkType => _networkType; StatusProvider() { _handleNetworkChanges(); _handleDNSFailure(); Connectivity().checkConnectivity().then((value) => _networkType = value[0]); } Status? getStatus() => _stack.isNotEmpty ? _stack[0] : null; // Status progress from 0.0 to 1.0 double get progress => _progress; void _handleNetworkChanges() { Connectivity().onConnectivityChanged.listen((event) { _networkType = event[0]; if (event[0] == ConnectivityResult.none) { if (!_stack.contains(Status.network)) { _stack.remove(Status.apiError); _stack.insert(0, Status.network); notifyListeners(); } } else { if (_stack.contains(Status.network)) { _stack.remove(Status.network); notifyListeners(); } } }); } void _handleDNSFailure() { try { InternetAddress.lookup('api.refilc.hu').then((status) { if (status.isEmpty) { if (!_stack.contains(Status.network)) { _stack.remove(Status.apiError); _stack.insert(0, Status.network); notifyListeners(); } } else { if (_stack.contains(Status.network)) { _stack.remove(Status.network); notifyListeners(); } } }); } on SocketException catch (_) { if (!_stack.contains(Status.network)) { _stack.remove(Status.apiError); _stack.insert(0, Status.network); notifyListeners(); } } } void triggerRequest(http.Response res) { if (res.headers.containsKey("x-maintenance-mode") || res.statusCode == 503) { if (!_stack.contains(Status.maintenance)) { _stack.insert(0, Status.maintenance); notifyListeners(); } } else { if (_stack.contains(Status.maintenance)) { _stack.remove(Status.maintenance); notifyListeners(); } } if (res.body == 'invalid_grant' || res.body.replaceAll(' ', '') == '' || res.statusCode == 400) { if (!_stack.contains(Status.apiError) && !_stack.contains(Status.network)) { if (res.statusCode == 401) return; _stack.insert(0, Status.apiError); notifyListeners(); } } else { if (_stack.contains(Status.apiError) && res.request?.url.path != '/nonce') { _stack.remove(Status.apiError); notifyListeners(); } } } void triggerSync({required int current, required int max}) { double prev = _progress; if (!_stack.contains(Status.syncing)) { _stack.add(Status.syncing); _progress = 0.0; notifyListeners(); } if (max == 0) { _progress = 0.0; } else { _progress = current / max; } if (_progress == 1.0) { notifyListeners(); // Wait for animation Future.delayed(const Duration(milliseconds: 250), () { _stack.remove(Status.syncing); notifyListeners(); }); } else if (progress != prev) { notifyListeners(); } } }