feat: integrate NFC functionality for reading and writing tags
- Added NFCManagerRepository to handle NFC operations using react-native-nfc-manager. - Implemented ReadNFCTagUseCase and WriteNFCTagUseCase for reading and writing NFC tags. - Updated app layout to include NFC reader screen. - Created WriteNFCScreen for writing NFC tags with filament data. - Enhanced HomeScreen to support NFC reading and added NFC button in FilamentDetailScreen. - Updated app.json to include react-native-nfc-manager dependency. - Added animations and user feedback for NFC operations in the UI.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import NfcManager, { Ndef, NfcTech } from 'react-native-nfc-manager';
|
||||
import { NativeModules } from 'react-native';
|
||||
import { INFCRepository } from '@ports/INFCRepository';
|
||||
|
||||
export class NFCManagerRepository implements INFCRepository {
|
||||
private started = false;
|
||||
|
||||
private get nativeModuleAvailable(): boolean {
|
||||
return NativeModules.NfcManager != null;
|
||||
}
|
||||
|
||||
private async ensureStarted(): Promise<void> {
|
||||
if (!this.nativeModuleAvailable) {
|
||||
throw new Error('Módulo NFC não disponível. Reinstale o app.');
|
||||
}
|
||||
if (!this.started) {
|
||||
await NfcManager.start();
|
||||
this.started = true;
|
||||
}
|
||||
}
|
||||
|
||||
async isSupported(): Promise<boolean> {
|
||||
if (!this.nativeModuleAvailable) return false;
|
||||
try {
|
||||
return await NfcManager.isSupported();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async readTag(): Promise<string | null> {
|
||||
await this.ensureStarted();
|
||||
await NfcManager.requestTechnology(NfcTech.Ndef);
|
||||
try {
|
||||
const tag = await NfcManager.getTag();
|
||||
const ndefRecords = tag?.ndefMessage;
|
||||
if (!ndefRecords || ndefRecords.length === 0) return null;
|
||||
|
||||
const firstRecord = ndefRecords[0];
|
||||
const uri = Ndef.uri.decodePayload(firstRecord.payload as unknown as Uint8Array);
|
||||
return uri ?? null;
|
||||
} finally {
|
||||
NfcManager.cancelTechnologyRequest();
|
||||
}
|
||||
}
|
||||
|
||||
async writeTag(uri: string): Promise<void> {
|
||||
await this.ensureStarted();
|
||||
await NfcManager.requestTechnology(NfcTech.Ndef);
|
||||
try {
|
||||
const bytes = Ndef.encodeMessage([Ndef.uriRecord(uri)]);
|
||||
await NfcManager.ndefHandler.writeNdefMessage(bytes);
|
||||
} finally {
|
||||
NfcManager.cancelTechnologyRequest();
|
||||
}
|
||||
}
|
||||
|
||||
async cancelSession(): Promise<void> {
|
||||
await NfcManager.cancelTechnologyRequest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { INFCRepository } from '@ports/INFCRepository';
|
||||
|
||||
const FILAMENT_URI_PREFIX = 'meowspool://filament/';
|
||||
|
||||
export class ReadNFCTagUseCase {
|
||||
constructor(private readonly nfcRepository: INFCRepository) {}
|
||||
|
||||
async execute(): Promise<string> {
|
||||
const uri = await this.nfcRepository.readTag();
|
||||
if (!uri) throw new Error('Tag sem dados NDEF.');
|
||||
|
||||
if (!uri.startsWith(FILAMENT_URI_PREFIX)) {
|
||||
throw new Error('Tag não reconhecida pelo MeowSpool.');
|
||||
}
|
||||
|
||||
const filamentId = uri.slice(FILAMENT_URI_PREFIX.length);
|
||||
if (!filamentId) throw new Error('ID do filamento inválido na tag.');
|
||||
|
||||
return filamentId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { INFCRepository } from '@ports/INFCRepository';
|
||||
|
||||
export class WriteNFCTagUseCase {
|
||||
constructor(private readonly nfcRepository: INFCRepository) {}
|
||||
|
||||
async execute(filamentId: string): Promise<void> {
|
||||
const uri = `meowspool://filament/${filamentId}`;
|
||||
await this.nfcRepository.writeTag(uri);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
import { NFCManagerRepository } from '@adapters/nfc/NFCManagerRepository';
|
||||
import { ReadNFCTagUseCase } from '@application/nfc/ReadNFCTagUseCase';
|
||||
import { WriteNFCTagUseCase } from '@application/nfc/WriteNFCTagUseCase';
|
||||
import { ApiAuthRepository } from '@adapters/remote/ApiAuthRepository';
|
||||
import { ApiFilamentRepository } from '@adapters/remote/ApiFilamentRepository';
|
||||
import { ApiSpoolPresetRepository } from '@adapters/remote/ApiSpoolPresetRepository';
|
||||
@@ -42,3 +45,9 @@ export const listPresetsUseCase = new ListPresetsUseCase(presetRepository);
|
||||
export const createPresetUseCase = new CreatePresetUseCase(presetRepository);
|
||||
export const updatePresetUseCase = new UpdatePresetUseCase(presetRepository);
|
||||
export const deletePresetUseCase = new DeletePresetUseCase(presetRepository);
|
||||
|
||||
// NFC
|
||||
const nfcRepository = new NFCManagerRepository();
|
||||
export const readNFCTagUseCase = new ReadNFCTagUseCase(nfcRepository);
|
||||
export const writeNFCTagUseCase = new WriteNFCTagUseCase(nfcRepository);
|
||||
export { nfcRepository };
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface INFCRepository {
|
||||
isSupported(): Promise<boolean>;
|
||||
readTag(): Promise<string | null>;
|
||||
writeTag(uri: string): Promise<void>;
|
||||
cancelSession(): Promise<void>;
|
||||
}
|
||||
Reference in New Issue
Block a user