feat(contacts): обмен контактами NFC→BLE

This commit is contained in:
klockky
2026-06-21 10:18:48 +00:00
parent f20a818825
commit 6b082a81fe
6 changed files with 490 additions and 16 deletions
+12 -6
View File
@@ -3,13 +3,14 @@ import 'dart:io';
import 'package:flutter/services.dart';
enum NfcEventType { received, cancelled }
enum NfcEventType { received, cancelled, error }
class NfcEvent {
final NfcEventType type;
final int? id;
final String? reason;
const NfcEvent(this.type, this.id);
const NfcEvent(this.type, this.id, {this.reason});
}
class NfcStatus {
@@ -59,9 +60,14 @@ class NfcExchangeService {
NfcEvent _decodeEvent(dynamic raw) {
final map = raw is Map ? raw : const {};
final id = map['id'];
final type = map['event'] == 'received'
? NfcEventType.received
: NfcEventType.cancelled;
return NfcEvent(type, id is int ? id : (id is num ? id.toInt() : null));
final parsedId = id is int ? id : (id is num ? id.toInt() : null);
switch (map['event']) {
case 'received':
return NfcEvent(NfcEventType.received, parsedId);
case 'error':
return NfcEvent(NfcEventType.error, null, reason: map['reason'] as String?);
default:
return const NfcEvent(NfcEventType.cancelled, null);
}
}
}
@@ -12,7 +12,7 @@ import '../../../main.dart';
import '../../widgets/custom_notification.dart';
import '../../widgets/komet_avatar.dart';
enum _Stage { checking, unsupported, disabled, scanning, found, adding, added }
enum _Stage { checking, unsupported, disabled, failed, scanning, found, adding, added }
class NfcExchangeSheet extends StatefulWidget {
const NfcExchangeSheet({super.key});
@@ -30,6 +30,7 @@ class _NfcExchangeSheetState extends State<NfcExchangeSheet>
_Stage _stage = _Stage.checking;
int? _peerId;
Map<String, dynamic>? _peerInfo;
String _failReason = '';
@override
void initState() {
@@ -78,6 +79,15 @@ class _NfcExchangeSheetState extends State<NfcExchangeSheet>
}
return;
}
if (event.type == NfcEventType.error) {
if (mounted && _peerId == null) {
setState(() {
_failReason = _reasonText(event.reason);
_stage = _Stage.failed;
});
}
return;
}
final id = event.id;
if (id == null || _peerId != null) return;
_peerId = id;
@@ -141,6 +151,17 @@ class _NfcExchangeSheetState extends State<NfcExchangeSheet>
}
}
String _reasonText(String? reason) {
switch (reason) {
case 'bluetooth_off':
return 'Включите Bluetooth и попробуйте снова';
case 'permission':
return 'Нужны разрешения Bluetooth для обмена';
default:
return 'Не удалось установить соединение';
}
}
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
@@ -191,6 +212,8 @@ class _NfcExchangeSheetState extends State<NfcExchangeSheet>
Symbols.nfc,
'Включите NFC в настройках телефона и попробуйте снова',
);
case _Stage.failed:
return _message(cs, Symbols.bluetooth_disabled, _failReason);
case _Stage.scanning:
return _scanning(cs);
case _Stage.found: