spotube/lib/provider/connect/clients.dart
2024-08-15 22:45:22 +06:00

118 lines
3.3 KiB
Dart

import 'package:bonsoir/bonsoir.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotube/services/device_info/device_info.dart';
import 'package:spotube/services/logger/logger.dart';
class ConnectClientsState {
final List<BonsoirService> services;
final ResolvedBonsoirService? resolvedService;
final BonsoirDiscovery discovery;
ConnectClientsState({
required this.services,
required this.discovery,
this.resolvedService,
});
ConnectClientsState copyWith({
List<BonsoirService>? services,
BonsoirDiscovery? discovery,
ResolvedBonsoirService? resolvedService,
}) {
return ConnectClientsState(
services: services ?? this.services,
discovery: discovery ?? this.discovery,
resolvedService: resolvedService ?? this.resolvedService,
);
}
}
class ConnectClientsNotifier extends AsyncNotifier<ConnectClientsState> {
ConnectClientsNotifier();
@override
build() async {
final discovery = BonsoirDiscovery(type: '_spotube._tcp');
final deviceId = await DeviceInfoService.instance.deviceId();
await discovery.ready;
final subscription = discovery.eventStream?.listen((event) {
// ignore device itself
try {
if (event.service?.attributes["deviceId"] == deviceId) {
return;
}
switch (event.type) {
case BonsoirDiscoveryEventType.discoveryServiceFound:
state = AsyncData(state.value!.copyWith(
services: [
...?state.value?.services,
event.service!,
],
));
break;
case BonsoirDiscoveryEventType.discoveryServiceResolved:
state = AsyncData(
state.value!.copyWith(
resolvedService: event.service as ResolvedBonsoirService,
),
);
break;
case BonsoirDiscoveryEventType.discoveryServiceLost:
state = AsyncData(
ConnectClientsState(
services: state.value!.services
.where((s) => s.name != event.service!.name)
.toList(),
discovery: state.value!.discovery,
resolvedService: state.value?.resolvedService != null &&
event.service?.name ==
state.value?.resolvedService?.name
? null
: state.value!.resolvedService,
),
);
break;
default:
break;
}
} catch (e, stack) {
AppLogger.reportError(e, stack);
}
});
ref.onDispose(() {
subscription?.cancel();
discovery.stop();
});
await discovery.start();
return ConnectClientsState(
services: [],
discovery: discovery,
);
}
Future<void> resolveService(BonsoirService service) async {
if (state.value == null) return;
await service.resolve(state.value!.discovery.serviceResolver);
}
Future<void> clearResolvedService() async {
if (state.value == null) return;
state = AsyncData(
ConnectClientsState(
services: state.value!.services,
discovery: state.value!.discovery,
),
);
}
}
final connectClientsProvider =
AsyncNotifierProvider<ConnectClientsNotifier, ConnectClientsState>(
() => ConnectClientsNotifier(),
);