feat(app): add manual entry and sharing flows
This commit is contained in:
89
lib/core/services/bluetooth_service.dart
Normal file
89
lib/core/services/bluetooth_service.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user