Files
lunchpick/lib/core/services/bluetooth_service.dart
2025-11-19 16:36:39 +09:00

90 lines
3.0 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:lunchpick/domain/entities/restaurant.dart';
import 'package:lunchpick/domain/entities/share_device.dart';
/// 실제 Bluetooth 통신을 대체하는 간단한 모의(Mock) 서비스.
class BluetoothService {
final _incomingDataController = StreamController<String>.broadcast();
final Map<String, ShareDevice> _listeningDevices = {};
final Random _random = Random();
Stream<String> get onDataReceived => _incomingDataController.stream;
/// 특정 코드로 수신 대기를 시작한다.
Future<void> startListening(String code) async {
await Future<void>.delayed(const Duration(milliseconds: 300));
stopListening();
final shareDevice = ShareDevice(
code: code,
deviceId: 'LP-${_random.nextInt(900000) + 100000}',
discoveredAt: DateTime.now(),
);
_listeningDevices[code] = shareDevice;
}
/// 더 이상 수신 대기하지 않는다.
void stopListening() {
if (_listeningDevices.isEmpty) return;
final codes = List<String>.from(_listeningDevices.keys);
for (final code in codes) {
_listeningDevices.remove(code);
}
}
/// 현재 주변에서 수신 대기 중인 기기 목록을 반환한다.
Future<List<ShareDevice>> scanNearbyDevices() async {
await Future<void>.delayed(const Duration(seconds: 1));
return _listeningDevices.values.toList();
}
/// 대상 코드로 맛집 리스트를 전송한다. 실제 BT 대신 JSON 문자열을 브로드캐스트한다.
Future<void> sendRestaurantList(
String targetCode,
List<Restaurant> restaurants,
) async {
await Future<void>.delayed(const Duration(seconds: 1));
if (!_listeningDevices.containsKey(targetCode)) {
throw Exception('해당 코드를 찾을 수 없습니다.');
}
final payload = jsonEncode(
restaurants
.map((restaurant) => _serializeRestaurant(restaurant))
.toList(),
);
_incomingDataController.add(payload);
}
Map<String, dynamic> _serializeRestaurant(Restaurant restaurant) {
return {
'id': restaurant.id,
'name': restaurant.name,
'category': restaurant.category,
'subCategory': restaurant.subCategory,
'description': restaurant.description,
'phoneNumber': restaurant.phoneNumber,
'roadAddress': restaurant.roadAddress,
'jibunAddress': restaurant.jibunAddress,
'latitude': restaurant.latitude,
'longitude': restaurant.longitude,
'lastVisitDate': restaurant.lastVisitDate?.toIso8601String(),
'source': restaurant.source.name,
'createdAt': restaurant.createdAt.toIso8601String(),
'updatedAt': restaurant.updatedAt.toIso8601String(),
'naverPlaceId': restaurant.naverPlaceId,
'naverUrl': restaurant.naverUrl,
'businessHours': restaurant.businessHours,
'lastVisited': restaurant.lastVisited?.toIso8601String(),
'visitCount': restaurant.visitCount,
};
}
void dispose() {
_incomingDataController.close();
_listeningDevices.clear();
}
}