Skip to content

Commit

Permalink
Developed the business logic of offline detection mechanism (GSoC) (P…
Browse files Browse the repository at this point in the history
…alisadoesFoundation#2523)

* Developed the business logic of offline detection mechanism

* fixed dropped coverage
  • Loading branch information
Azad99-9 authored Jun 24, 2024
1 parent fd3f777 commit 17c0e3d
Show file tree
Hide file tree
Showing 17 changed files with 413 additions and 135 deletions.
7 changes: 7 additions & 0 deletions lib/locator.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'package:talawa/main.dart';
Expand All @@ -14,6 +15,7 @@ import 'package:talawa/services/org_service.dart';
import 'package:talawa/services/post_service.dart';
import 'package:talawa/services/session_manager.dart';
import 'package:talawa/services/size_config.dart';
import 'package:talawa/services/third_party_service/connectivity_service.dart';
import 'package:talawa/services/third_party_service/multi_media_pick_service.dart';
import 'package:talawa/services/user_config.dart';
import 'package:talawa/utils/queries.dart';
Expand Down Expand Up @@ -68,6 +70,9 @@ final queries = locator<Queries>();
///GetIt for Connectivity.
final connectivity = locator<Connectivity>();

///GetIt for ConnectivityService.
final connectivityService = locator<ConnectivityService>();

///GetIt for OrganizationService.
final organizationService = locator<OrganizationService>();

Expand Down Expand Up @@ -111,6 +116,8 @@ void setupLocator() {
locator.registerLazySingleton(() => ImagePicker());
locator.registerLazySingleton(() => ImageCropper());

locator.registerSingleton(ConnectivityService(client: http.Client()));

//graphql
locator.registerSingleton(GraphqlConfig());

Expand Down
175 changes: 175 additions & 0 deletions lib/services/third_party_service/connectivity_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:http/http.dart' as http;
import 'package:talawa/locator.dart';

/// This class provides services related to network connectivity monitoring and handling.
///
/// It includes methods for:
/// * Initializing the network service - [initConnectivity]
/// * Monitoring connectivity changes - [enableSubscription]
/// * Handling online and offline states - [_handleOnline], [_handleOffline]
/// * Checking reachability of a given URI - [isReachable]
/// * Handling the device's connectivity status - [handleConnection]
/// * Checking if the device has any type of network connection - [hasConnection]
class ConnectivityService {
/// This function is used to initialize the network service.
///
/// **params**:
/// None
///
/// **returns**:
/// None
ConnectivityService({required http.Client client}) {
_client = client;
_connectionStatusController = StreamController<ConnectivityResult>();
initConnectivity();
}

/// Stream controller for network status changes
late StreamController<ConnectivityResult> _connectionStatusController;

/// Getter for the stream of connection status changes.
Stream<ConnectivityResult> get connectionStream =>
_connectionStatusController.stream;

/// Client to access internet.
late final http.Client _client;

/// This function initializes connectivity monitoring.
///
/// **params**:
/// None
///
/// **returns**:
/// None
Future<void> initConnectivity() async {
/// Try getting initial connectivity status
checkInitialConnection();

/// Listen for future changes in connectivity
enableSubscription();
}

/// This function checks the initial connection status.
///
/// **params**:
/// None
///
/// **returns**:
/// None
Future<void> checkInitialConnection() async {
try {
final result = await connectivity.checkConnectivity();
print(result);
_connectionStatusController.add(result);
handleConnection(result);
} catch (e) {
// Handle other exceptions
print('Error checking connectivity: $e');
_connectionStatusController
.add(ConnectivityResult.none); // Assume no connection on error
handleConnection(ConnectivityResult.none);
}
}

/// This function enables the subscription to connectivity changes.
///
/// **params**:
/// None
///
/// **returns**:
/// None
Future<void> enableSubscription() async {
connectivity.onConnectivityChanged.listen(
(ConnectivityResult result) {
print(result);
_connectionStatusController.add(result);
handleConnection(result);
},
onError: (error) {
// Handle errors during listening for changes
print('Error listening for connectivity changes: $error');
},
);
}

/// This function handles the actions to be taken when the device is online.
///
/// **params**:
/// None
///
/// **returns**:
/// None
Future<void> _handleOnline() async {
// To be implemented.
}

/// This function handles the actions to be taken when the device is offline.
///
/// **params**:
/// None
///
/// **returns**:
/// None
Future<void> _handleOffline() async {
// To be implemented.
}

/// This function checks if a given URI is reachable within a specified timeout period.
///
/// **params**:
/// * `client`: An instance of `http.Client` to make the HTTP request.
/// * `uriString`: An optional `String` specifying the URI to check.
/// Defaults to 'http://www.google.com' if not provided.
///
/// **returns**:
/// * `Future<bool>`: indicates if the url is reachable.
Future<bool> isReachable({
http.Client? client,
String? uriString,
}) async {
try {
client ??= _client;
await client
.get(Uri.parse(uriString ?? 'http://www.google.com'))
.timeout(const Duration(seconds: 5));
return true;
} catch (e) {
print('Timeout while checking reachability: $e');
return false;
}
}

/// This function handles the device's connectivity status based on the provided `ConnectivityResult`.
///
/// **params**:
/// * `result`: A `ConnectivityResult` indicating the current connectivity status.
///
/// **returns**:
/// None
Future<void> handleConnection(ConnectivityResult result) async {
if (await hasConnection() && await isReachable(client: _client)) {
_handleOnline();
} else {
_handleOffline();
}
}

/// This function checks if the device currently has any type of network connection.
///
/// **params**:
/// None
///
/// **returns**:
/// * `Future<bool>`: indicating whether the device has a network connection.
Future<bool> hasConnection() async {
try {
final result = await connectivity.checkConnectivity();
return result != ConnectivityResult.none;
} catch (e) {
return false;
}
}
}
24 changes: 21 additions & 3 deletions test/helpers/test_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import 'package:talawa/services/org_service.dart';
import 'package:talawa/services/post_service.dart';
import 'package:talawa/services/session_manager.dart';
import 'package:talawa/services/size_config.dart';
import 'package:talawa/services/third_party_service/connectivity_service.dart';
import 'package:talawa/services/third_party_service/multi_media_pick_service.dart';
import 'package:talawa/services/user_config.dart';
import 'package:talawa/utils/event_queries.dart';
Expand All @@ -50,6 +51,7 @@ import 'package:talawa/view_model/widgets_view_models/like_button_view_model.dar
import 'package:talawa/view_model/widgets_view_models/progress_dialog_view_model.dart';

import '../service_tests/image_service_test.dart';
import '../service_tests/third_party_service_test.dart/connectivity_service_test.dart';
import '../service_tests/user_config_test.dart';
import '../views/main_screen_test.dart';
import 'test_helpers.mocks.dart';
Expand All @@ -68,7 +70,6 @@ import 'test_helpers.mocks.dart';
MockSpec<ChatService>(onMissingStub: OnMissingStub.returnDefault),
MockSpec<UserConfig>(onMissingStub: OnMissingStub.returnDefault),
MockSpec<AppLanguage>(onMissingStub: OnMissingStub.returnDefault),
MockSpec<Connectivity>(onMissingStub: OnMissingStub.returnDefault),
MockSpec<SignupDetailsViewModel>(
onMissingStub: OnMissingStub.returnDefault,
),
Expand Down Expand Up @@ -650,20 +651,35 @@ EventService getAndRegisterEventService() {
return service;
}

/// `getAndRegisterConnectivityService` returns a mock instance of the `Connectivity` class.
/// `getAndRegisterConnectivity` returns a mock instance of the `Connectivity` class.
///
/// **params**:
/// None
///
/// **returns**:
/// * `Connectivity`: A mock instance of the `Connectivity` class.
Connectivity getAndRegisterConnectivityService() {
Connectivity getAndRegisterConnectivity() {
_removeRegistrationIfExists<Connectivity>();
final service = MockConnectivity();
locator.registerSingleton<Connectivity>(service);
return service;
}

/// `getAndRegisterConnectivityService` returns a mock instance of the `ConnectivityService` class.
///
/// **params**:
/// None
///
/// **returns**:
/// * `ConnectivityService`: A mock instance of the `ConnectivityService` class.
ConnectivityService getAndRegisterConnectivityService() {
_removeRegistrationIfExists<ConnectivityService>();
final service = MockConnectivityService();
locator.registerSingleton<ConnectivityService>(service);
// when(service.)
return service;
}

/// `getPostMockModel` returns a mock instance of the `Post` class.
///
/// **params**:
Expand Down Expand Up @@ -862,6 +878,7 @@ void registerServices() {
getAndRegisterPostService();
getAndRegisterEventService();
getAndRegisterMultiMediaPickerService();
getAndRegisterConnectivity();
getAndRegisterConnectivityService();
getAndRegisterDatabaseMutationFunctions();
getAndRegisterOrganizationService();
Expand All @@ -886,6 +903,7 @@ void unregisterServices() {
locator.unregister<EventService>();
locator.unregister<MultiMediaPickerService>();
locator.unregister<Connectivity>();
locator.unregister<ConnectivityService>();
locator.unregister<DataBaseMutationFunctions>();
locator.unregister<OrganizationService>();
locator.unregister<CommentService>();
Expand Down
Loading

0 comments on commit 17c0e3d

Please sign in to comment.