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.