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

Migrating qr_code_scanner to mobile_scanner in talawa mobile #2717

Closed
Show file tree
Hide file tree
Changes from 4 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
3 changes: 3 additions & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
1 change: 1 addition & 0 deletions lib/locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ final actionHandlerService = locator<ActionHandlerService>();
///
/// **returns**:
/// None

Future<void> setupLocator() async {
locator.registerSingleton(DataBaseMutationFunctions());

Expand Down
6 changes: 2 additions & 4 deletions lib/models/chats/chat_list_tile_data_model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions lib/services/graphql_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class GraphqlConfig {
late HttpLink httpLink;
late WebSocketLink webSocketLink;



//prefix route for showing images
String? displayImgRoute;

Expand Down
16 changes: 12 additions & 4 deletions lib/splash_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ import 'package:talawa/utils/app_localization.dart';

/// This widget return the SplashScreen. Splash Screen is the first screen that we see when we run our application. It is also known as Launch Screen.
class SplashScreen extends StatefulWidget {
const SplashScreen({required Key key, this.mainScreenIndex = 0})
: super(key: key);
const SplashScreen({
required Key key,
this.mainScreenIndex = 0,
this.isTesting = false,
}) : super(key: key);

/// This is required if url requires us to push different Screen to Home Screen.
final int mainScreenIndex;

/// for testing purpose.
final bool isTesting;

@override
_SplashScreenState createState() => _SplashScreenState();
}
Expand Down Expand Up @@ -206,6 +212,8 @@ class _SplashScreenState extends State<SplashScreen> {
/// **returns**:
/// None
void _handleUserLogIn(bool userLoggedIn) {
print(widget.isTesting);
if (widget.isTesting) return;
Future.delayed(const Duration(milliseconds: 750)).then((value) async {
final pushReplacementScreen = navigationService.pushReplacementScreen;
if (!userLoggedIn) {
Expand Down Expand Up @@ -239,9 +247,9 @@ class _SplashScreenState extends State<SplashScreen> {
}

@override
void dispose() {
_sub.cancel();
Future<void> dispose() async {
super.dispose();
await _sub.cancel();
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
// import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:talawa/constants/routing_constants.dart';
import 'package:talawa/enums/enums.dart';
import 'package:talawa/locator.dart';
Expand Down
123 changes: 65 additions & 58 deletions lib/view_model/pre_auth_view_models/set_url_view_model.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:talawa/constants/app_strings.dart';
import 'package:talawa/enums/enums.dart';
import 'package:talawa/locator.dart';
Expand Down Expand Up @@ -56,6 +55,9 @@ class SetUrlViewModel extends BaseModel {
/// qrValidator.
AutovalidateMode validate = AutovalidateMode.disabled;

/// qrController.
final MobileScannerController controller = MobileScannerController();

Comment on lines +58 to +60
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Manage controller lifecycle

Dispose of the MobileScannerController when it’s no longer needed to avoid memory leaks. For instance, add a cleanup method to this ViewModel or handle disposal if the user exits before any scan completes.

🧰 Tools
🪛 GitHub Actions: PR Workflow

[warning] File required formatting changes

/// This function initialises the variables.
///
/// **params**:
Expand Down Expand Up @@ -239,18 +241,44 @@ class SetUrlViewModel extends BaseModel {
SizedBox(
height: 250,
width: 250,
child: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderRadius: 10,
borderLength: 20,
borderWidth: 10,
cutOutSize: 250,
),
/*overlayMargin: EdgeInsets.all(50)*/
child: MobileScanner(
fit: BoxFit.contain,
controller: controller,
errorBuilder: (ctx, error, _) {
String errorMessage = '';
switch (error.errorCode) {
case MobileScannerErrorCode.controllerUninitialized:
errorMessage = 'camera is not ready';
break;
case MobileScannerErrorCode.permissionDenied:
errorMessage =
'Please provide camera permission to scan QR code';
break;
case MobileScannerErrorCode.unsupported:
errorMessage =
'This device does not support scanning.';
break;
default:
errorMessage = 'An unkonwn error occurred';
}

WidgetsBinding.instance.addPostFrameCallback((_) {
navigationService.showTalawaErrorSnackBar(
errorMessage,
MessageType.error,
);
});

return Center(
child: Text(
errorMessage,
),
);
},
onDetect: _onQRViewCreated,
),
),

SizedBox(
height: SizeConfig.safeBlockVertical! * 4,
),
Expand All @@ -269,56 +297,35 @@ class SetUrlViewModel extends BaseModel {
/// This is the helper function which execute when the on QR view created.
///
/// **params**:
/// * `controller`: QRViewController
/// * `scanData`: BarcodeCapture
///
/// **returns**:
/// None

void _onQRViewCreated(QRViewController controller) {
controller.scannedDataStream.listen((scanData) {
/// if the scanData is not empty.
if (scanData.code!.isNotEmpty) {
print(scanData.code);
try {
final List<String> data = scanData.code!.split('?');
url.text = data[0];
final List<String> queries = data[1].split('&');
orgId = queries[0].split('=')[1];
Vibration.vibrate(duration: 100);
controller.stopCamera();
controller.dispose();
final box = Hive.box('url');
box.put(urlKey, url.text);
box.put(imageUrlKey, "${url.text}/talawa/");
graphqlConfig.getOrgUrl();
Navigator.pop(navigationService.navigatorKey.currentContext!);
navigationService.pushScreen('/selectOrg', arguments: orgId);
} on CameraException catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorSnackBar(
"The Camera is not working",
MessageType.error,
);
} on QrEmbeddedImageException catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorDialog(
"The QR is not Working",
MessageType.error,
);
} on QrUnsupportedVersionException catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorDialog(
"This QR version is not Supported.",
MessageType.error,
);
} on Exception catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorSnackBar(
"This QR is not for the App",
MessageType.error,
);
}
void _onQRViewCreated(BarcodeCapture scanData) {
if (scanData.raw != null && scanData.barcodes.isNotEmpty) {
final String code = scanData.barcodes.first.displayValue!;
try {
final List<String> data = code.split('?');
url.text = data[0];
final List<String> queries = data[1].split('&');
orgId = queries[0].split('=')[1];
Vibration.vibrate(duration: 100);
controller.stop();
controller.dispose();
final box = Hive.box('url');
box.put(urlKey, url.text);
box.put(imageUrlKey, "${url.text}/talawa/");
graphqlConfig.getOrgUrl();
Navigator.pop(navigationService.navigatorKey.currentContext!);
navigationService.pushScreen('/selectOrg', arguments: orgId);
} on Exception catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorSnackBar(
"The Camera is not working",
MessageType.error,
);
}
});
}
Comment on lines +304 to +328
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling and URL validation

The current implementation has two issues:

  1. The error message "The Camera is not working" is misleading as the exception could be due to invalid QR code format.
  2. The URL parsing assumes a specific format without validation.

Consider this improved implementation:

   void _onQRViewCreated(BarcodeCapture scanData) {
     if (scanData.raw != null && scanData.barcodes.isNotEmpty) {
       final String code = scanData.barcodes.first.displayValue!;
       try {
+        // Validate QR code format
+        if (!code.contains('?') || !code.contains('=')) {
+          throw FormatException('Invalid QR code format');
+        }
         final List<String> data = code.split('?');
         url.text = data[0];
         final List<String> queries = data[1].split('&');
         orgId = queries[0].split('=')[1];
         Vibration.vibrate(duration: 100);
         controller.stop();
         controller.dispose();
         final box = Hive.box('url');
         box.put(urlKey, url.text);
         box.put(imageUrlKey, "${url.text}/talawa/");
         graphqlConfig.getOrgUrl();
         Navigator.pop(navigationService.navigatorKey.currentContext!);
         navigationService.pushScreen('/selectOrg', arguments: orgId);
-      } on Exception catch (e) {
+      } on FormatException catch (e) {
+        debugPrint(e.toString());
+        navigationService.showTalawaErrorSnackBar(
+          "Invalid QR code format. Please scan a valid organization QR code.",
+          MessageType.error,
+        );
+      } catch (e) {
         debugPrint(e.toString());
         navigationService.showTalawaErrorSnackBar(
-          "The Camera is not working",
+          "Failed to process QR code. Please try again.",
           MessageType.error,
         );
       }
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void _onQRViewCreated(BarcodeCapture scanData) {
if (scanData.raw != null && scanData.barcodes.isNotEmpty) {
final String code = scanData.barcodes.first.displayValue!;
try {
final List<String> data = code.split('?');
url.text = data[0];
final List<String> queries = data[1].split('&');
orgId = queries[0].split('=')[1];
Vibration.vibrate(duration: 100);
controller.stop();
controller.dispose();
final box = Hive.box('url');
box.put(urlKey, url.text);
box.put(imageUrlKey, "${url.text}/talawa/");
graphqlConfig.getOrgUrl();
Navigator.pop(navigationService.navigatorKey.currentContext!);
navigationService.pushScreen('/selectOrg', arguments: orgId);
} on Exception catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorSnackBar(
"The Camera is not working",
MessageType.error,
);
}
});
}
void _onQRViewCreated(BarcodeCapture scanData) {
if (scanData.raw != null && scanData.barcodes.isNotEmpty) {
final String code = scanData.barcodes.first.displayValue!;
try {
// Validate QR code format
if (!code.contains('?') || !code.contains('=')) {
throw FormatException('Invalid QR code format');
}
final List<String> data = code.split('?');
url.text = data[0];
final List<String> queries = data[1].split('&');
orgId = queries[0].split('=')[1];
Vibration.vibrate(duration: 100);
controller.stop();
controller.dispose();
final box = Hive.box('url');
box.put(urlKey, url.text);
box.put(imageUrlKey, "${url.text}/talawa/");
graphqlConfig.getOrgUrl();
Navigator.pop(navigationService.navigatorKey.currentContext!);
navigationService.pushScreen('/selectOrg', arguments: orgId);
} on FormatException catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorSnackBar(
"Invalid QR code format. Please scan a valid organization QR code.",
MessageType.error,
);
} catch (e) {
debugPrint(e.toString());
navigationService.showTalawaErrorSnackBar(
"Failed to process QR code. Please try again.",
MessageType.error,
);
}
}

}
}
Loading
Loading