Skip to content

Overview ​

  • File: lib/views/new_scanner_page.dart

The NewScannerPage is a Flutter widget that provides QR code scanning functionality for the HVC Mobile application. It supports both login and meeting QR codes, with PIN verification capabilities for secure access.

Class Structure ​

Class Definition ​

dart
class NewScannerPage extends StatelessWidget {
  static const String routeName = '/NewScannerPage';
  NewScannerPage({Key? key}) : super(key: key);

  MobileScannerController cameraController = MobileScannerController();
  final AuthController authController = Get.find();
  final ContactsController contactsController = Get.find();
  final MeetingsController meetingsController = Get.find();
  final RealTimeController realTimeController = Get.find();
  final messagesController = Get.put(MessagesController());

  String qrcode = '';
  String? pin;
  late Timer timer;
  late PinType pinType;
  final TextEditingController textEditingController = TextEditingController();
  RxBool shouldTakePin = false.obs, showInfo = true.obs;
  final FocusNode focusNode = FocusNode();
}

Dependencies ​

Required Packages ​

  • flutter/material.dart - Core Flutter UI components
  • get/get.dart - State management and routing
  • get_storage/get_storage.dart - Local storage
  • mobile_scanner/mobile_scanner.dart - QR code scanning
  • pin_code_fields/pin_code_fields.dart - PIN input field

Internal Dependencies ​

  • controllers/auth_controller.dart - Authentication management
  • controllers/contacts_controller.dart - Contact management
  • controllers/meetings_controller.dart - Meeting management
  • controllers/messages_controller.dart - Message management
  • controllers/real_time_controller.dart - Real-time communication
  • hlk_helpers/hlk_extension_methods.dart - Extension methods
  • hlk_helpers/hlk_models.dart - Helper models
  • hlk_helpers/hlk_utils.dart - Utility functions
  • hlk_helpers/hlk_widget.dart - Custom widgets
  • models/core_models.dart - Core data models
  • models/dto_models.dart - Data transfer objects
  • shared/config.dart - Configuration
  • shared/constants.dart - Constants

State Management ​

State Variables ​

dart
MobileScannerController cameraController = MobileScannerController();
String qrcode = '';
String? pin;
late Timer timer;
late PinType pinType;
final TextEditingController textEditingController = TextEditingController();
RxBool shouldTakePin = false.obs, showInfo = true.obs;
final FocusNode focusNode = FocusNode();

Controller Initialization ​

dart
final AuthController authController = Get.find();
final ContactsController contactsController = Get.find();
final MeetingsController meetingsController = Get.find();
final RealTimeController realTimeController = Get.find();
final messagesController = Get.put(MessagesController());

QR Code Scanning ​

Scanner Configuration ​

dart
MobileScanner(
  controller: cameraController,
  onDetect: (barcodes) {
    if (barcodes.barcodes.isEmpty) {
      logInfo('Failed to scan Barcode');
    } else {
      qrcode = barcodes.barcodes.first.rawValue!.trim();
      logInfo('scanned data = \n$qrcode');
      // Process QR code...
    }
  },
)

QR Code Processing ​

dart
try {
  if (!GetUtils.isNullOrBlank(qrcode)!) {
    authController.scannerResult.value = ScannerResult.fromJson(qrcode);

    if (authController.scannerResult.value.type.containsIgnoreCase('login')) {
      allowPinEntry(true);
      pinType = PinType.login;
      authController.scannerResult.value.loginData = LoginData.fromMap(
          authController.scannerResult.value.data);
    } else if (authController.scannerResult.value.type
        .containsIgnoreCase('meeting')) {
      pinType = PinType.meeting;
      final MeetingData meetingData = MeetingData.fromMap(
          authController.scannerResult.value.data);
      authController.scannerResult.value.meetingData = meetingData;

      meetingsController.meetingCode.value = meetingData.meetingCode;
      meetingsController.joinMeetingDto.value.meetingToken =
          meetingData.meetingToken;

      allowPinEntry(true);
    } else {
      qrcode = 'unknown data';
      allowPinEntry(false);
      cameraController.start();
    }
  } else {
    qrcode = 'empty data scanned';
    allowPinEntry(false);
    cameraController.start();
  }
} catch (e) {
  qrcode = 'invalid data scanned';
  cameraController.start();
  shouldTakePin.value = false;
  handleException(e);
}

PIN Verification ​

PIN Entry UI ​

dart
PinCodeTextField(
  focusNode: focusNode,
  enabled: shouldTakePin.value,
  appContext: context,
  autoDismissKeyboard: true,
  keyboardType: TextInputType.number,
  length: 4,
  obscureText: false,
  animationType: AnimationType.fade,
  pinTheme: PinTheme(
    activeColor: kAppColorBlack,
    activeFillColor: kAppColorWhite.withOpacity(0.4),
    inactiveFillColor: kAppColorWhite.withOpacity(0.4),
    selectedFillColor: kAppColorBlack,
    inactiveColor: kAppColorWhite,
    selectedColor: kAppColorBlue,
    shape: PinCodeFieldShape.box,
    fieldWidth: getWidth(0.14),
  ),
  cursorColor: kAppColorWhite,
  animationDuration: const Duration(milliseconds: 300),
  textStyle: bigTextStyle.copyWith(height: 1.6),
  enableActiveFill: true,
  controller: textEditingController,
  onCompleted: (v) async {
    // Handle PIN completion...
  },
  onChanged: (value) {
    if (value.isNumericOnly) {
      pin = value.numericOnly(firstWordOnly: true);
      logInfo(pin);
    } else {
      pin = '';
      textEditingController.clear();
    }
  },
)

PIN Processing ​

dart
onCompleted: (v) async {
  if (pinType == PinType.login) {
    await authController
        .login(authController.scannerResult.value.url, pin)
        .whenComplete(
      () async {
        contactsController.clearAll();
        await messagesController.clearAll();
        await realTimeController.onInit();
        await contactsController.getMe();
        await messagesController.getAll();
      },
    );
  } else if (pinType == PinType.meeting) {
    authController.loading.value = true;
    meetingsController.joinMeetingDto.value.pin = pin;
    JoinDetails? callDetails = await meetingsController.joinMeeting(
        authController.scannerResult.value.url);

    if (callDetails != null) {
      // Handle meeting join...
    } else {
      logInfo('WRONG PIN-TYPE IDENTIFIED');
      Get.back();
    }
  }
}

UI Components ​

Main Layout ​

dart
PageWithBackground(
  assetImagePath: 'assets/images/hvc_xr_bg.jpeg',
  child: Scaffold(
    backgroundColor: Colors.transparent,
    appBar: Platform.isIOS ? AppBar() : null,
    floatingActionButton: Obx(() => showInfo.value
        ? FloatingActionButton(
            child: Icon(Icons.info_outline),
            onPressed: () => HlkDialog.showMessageInAlertDialog(
                title: 'Info',
                message: 'If you dont have a login QrCode...',
                dialogContent: [
                  AlertDialogContent('OK', (otherContext) => Get.back())
                ]),
          )
        : SizedBox.shrink()),
    body: GestureDetector(
      onTap: () {
        showInfo.value = true;
        timer = Timer(const Duration(seconds: 5), () => showInfo.value = false);
      },
      child: SafeArea(
        child: Center(
          child: Obx(() => shouldTakePin.value
              ? Column(
                  // PIN entry UI
                )
              : MobileScanner(
                  // Scanner UI
                )),
        ),
      ),
    ),
  ),
)

Info Button ​

dart
FloatingActionButton(
  child: Icon(Icons.info_outline),
  onPressed: () => HlkDialog.showMessageInAlertDialog(
      title: 'Info',
      message: 'If you dont have a login QrCode...',
      dialogContent: [
        AlertDialogContent('OK', (otherContext) => Get.back())
      ]),
)

Released under the MIT License.