Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Developed the business logic of offline detection mechanism (GSoC) #2523

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading