Skip to content
Open
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
2 changes: 2 additions & 0 deletions lib/core/core_locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:bb_mobile/core/fees/fees_locator.dart';
import 'package:bb_mobile/features/labels/labels_facade.dart';
import 'package:bb_mobile/core/ledger/ledger_locator.dart';
import 'package:bb_mobile/core/mempool/mempool_locator.dart';
import 'package:bb_mobile/core/nfc/nfc_locator.dart';
import 'package:bb_mobile/core/payjoin/payjoin_locator.dart';
import 'package:bb_mobile/core/recoverbull/recoverbull_locator.dart';
import 'package:bb_mobile/core/seed/seed_locator.dart';
Expand Down Expand Up @@ -40,6 +41,7 @@ class CoreLocator {
Bip85DerivationsLocator.registerDatasources(locator);
LedgerLocator.registerDatasources(locator);
BitBoxCoreLocator.registerDatasources(locator);
NfcLocator.registerDatasources(locator);
}

static void registerPorts(GetIt locator) {
Expand Down
46 changes: 46 additions & 0 deletions lib/core/nfc/data/nfc_error_mapper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'dart:async';

import 'package:bb_mobile/core/nfc/domain/nfc_failure.dart';
import 'package:flutter/services.dart';

const _userCancelledMarker = 'Session invalidated by user';

const _tagLostMarkers = [
'Tag connection lost',
'Read NDEF error',
'Error connecting to card',
'Tag already removed',
];

NfcFailure nfcFailureFromError(Object error, {required bool isWrite}) {
final details = error.toString();

if (details.contains(_userCancelledMarker)) {
return NfcCancelledFailure(details);
}

if (error is TimeoutException) return NfcTimeoutFailure(details);

if (error is PlatformException) {
switch (error.code) {
case '400':
return NfcInvalidPayloadFailure(details);
case '404':
return NfcDisabledFailure(details);
case '405':
return NfcUnsupportedTagFailure(details);
case '406':
return NfcBusyFailure(details);
case '408':
return NfcTimeoutFailure(details);
case '409':
return NfcCancelledFailure(details);
case '503':
return NfcTagLostFailure(details);
}
}

if (_tagLostMarkers.any(details.contains)) return NfcTagLostFailure(details);

return isWrite ? NfcWriteFailure(details) : NfcUnexpectedFailure(details);
}
66 changes: 66 additions & 0 deletions lib/core/nfc/data/nfc_kit_datasource.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:ndef/ndef.dart' as ndef;

abstract interface class NfcKitDatasource {
Future<NFCAvailability> availability();

Future<NFCTag> poll({
required Duration timeout,
required String iosAlertMessage,
});

Future<List<ndef.NDEFRecord>> readNdefRecords();

Future<void> writeTextRecord(String data);

Future<void> finish({String? iosAlertMessage, String? iosErrorMessage});

Future<void> setIosAlertMessage(String message);

Future<void> iosRestartPolling();
}

final class FlutterNfcKitDatasource implements NfcKitDatasource {
const FlutterNfcKitDatasource();

@override
Future<NFCAvailability> availability() => FlutterNfcKit.nfcAvailability;

@override
Future<NFCTag> poll({
required Duration timeout,
required String iosAlertMessage,
}) => FlutterNfcKit.poll(
timeout: timeout,
iosAlertMessage: iosAlertMessage,
readIso15693: true,
readIso18092: false,
);

@override
Future<List<ndef.NDEFRecord>> readNdefRecords() =>
FlutterNfcKit.readNDEFRecords();

@override
Future<void> writeTextRecord(String data) => FlutterNfcKit.writeNDEFRecords([
ndef.TextRecord(
text: data,
language: 'en',
encoding: ndef.TextEncoding.UTF8,
),
]);

@override
Future<void> finish({String? iosAlertMessage, String? iosErrorMessage}) =>
FlutterNfcKit.finish(
iosAlertMessage: iosAlertMessage,
iosErrorMessage: iosErrorMessage,
);

@override
Future<void> setIosAlertMessage(String message) =>
FlutterNfcKit.setIosAlertMessage(message);

@override
Future<void> iosRestartPolling() => FlutterNfcKit.iosRestartPolling();
}
Loading
Loading