-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into leaderboard
- Loading branch information
Showing
9 changed files
with
411 additions
and
104 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import 'utils.dart'; | ||
|
||
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; | ||
|
||
final Map<DeviceIdentifier, StreamControllerReemit<bool>> _global = {}; | ||
|
||
/// connect & disconnect + update stream | ||
extension Extra on BluetoothDevice { | ||
// convenience | ||
StreamControllerReemit<bool> get _stream { | ||
_global[remoteId] ??= StreamControllerReemit(initialValue: false); | ||
return _global[remoteId]!; | ||
} | ||
|
||
// get stream | ||
Stream<bool> get isConnectingOrDisconnecting { | ||
return _stream.stream; | ||
} | ||
|
||
// connect & update stream | ||
Future<void> connectAndUpdateStream() async { | ||
_stream.add(true); | ||
try { | ||
await connect(); | ||
} finally { | ||
_stream.add(false); | ||
} | ||
} | ||
|
||
// disconnect & update stream | ||
Future<void> disconnectAndUpdateStream() async { | ||
_stream.add(true); | ||
try { | ||
await disconnect(); | ||
} finally { | ||
_stream.add(false); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import 'dart:async'; | ||
|
||
// It is essentially a stream but: | ||
// 1. we cache the latestValue of the stream | ||
// 2. the "latestValue" is re-emitted whenever the stream is listened to | ||
class StreamControllerReemit<T> { | ||
T? _latestValue; | ||
|
||
final StreamController<T> _controller = StreamController<T>.broadcast(); | ||
|
||
StreamControllerReemit({T? initialValue}) : _latestValue = initialValue; | ||
|
||
Stream<T> get stream { | ||
return _latestValue != null | ||
? _controller.stream.newStreamWithInitialValue(_latestValue!) | ||
: _controller.stream; | ||
} | ||
|
||
T? get value => _latestValue; | ||
|
||
void add(T newValue) { | ||
_latestValue = newValue; | ||
_controller.add(newValue); | ||
} | ||
|
||
Future<void> close() { | ||
return _controller.close(); | ||
} | ||
} | ||
|
||
// return a new stream that imediately emits an initial value | ||
extension _StreamNewStreamWithInitialValue<T> on Stream<T> { | ||
Stream<T> newStreamWithInitialValue(T initialValue) { | ||
return transform(_NewStreamWithInitialValueTransformer(initialValue)); | ||
} | ||
} | ||
|
||
// Helper for 'newStreamWithInitialValue' method for streams. | ||
class _NewStreamWithInitialValueTransformer<T> | ||
extends StreamTransformerBase<T, T> { | ||
final T initialValue; | ||
|
||
_NewStreamWithInitialValueTransformer(this.initialValue); | ||
|
||
@override | ||
Stream<T> bind(Stream<T> stream) { | ||
if (stream.isBroadcast) { | ||
return _bind(stream).asBroadcastStream(); | ||
} else { | ||
return _bind(stream); | ||
} | ||
} | ||
|
||
Stream<T> _bind(Stream<T> stream) { | ||
StreamController<T>? controller; | ||
StreamSubscription<T>? subscription; | ||
|
||
controller = StreamController<T>( | ||
onListen: () { | ||
// Emit the initial value | ||
controller?.add(initialValue); | ||
|
||
subscription = stream.listen( | ||
controller?.add, | ||
onError: (Object error) { | ||
controller?.addError(error); | ||
controller?.close(); | ||
}, | ||
onDone: controller?.close, | ||
); | ||
}, | ||
onPause: ([Future<dynamic>? resumeSignal]) { | ||
subscription?.pause(resumeSignal); | ||
}, | ||
onResume: () { | ||
subscription?.resume(); | ||
}, | ||
onCancel: () { | ||
return subscription?.cancel(); | ||
}, | ||
sync: true, | ||
); | ||
|
||
return controller.stream; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; | ||
|
||
class ConnectedDeviceTile extends StatefulWidget { | ||
final BluetoothDevice device; | ||
final VoidCallback onConnect; | ||
|
||
const ConnectedDeviceTile({ | ||
required this.device, | ||
required this.onConnect, | ||
Key? key, | ||
}) : super(key: key); | ||
|
||
@override | ||
State<ConnectedDeviceTile> createState() => _ConnectedDeviceTileState(); | ||
} | ||
|
||
class _ConnectedDeviceTileState extends State<ConnectedDeviceTile> { | ||
BluetoothConnectionState _connectionState = | ||
BluetoothConnectionState.disconnected; | ||
|
||
late StreamSubscription<BluetoothConnectionState> | ||
_connectionStateSubscription; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
|
||
_connectionStateSubscription = | ||
widget.device.connectionState.listen((state) { | ||
_connectionState = state; | ||
setState(() {}); | ||
}); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_connectionStateSubscription.cancel(); | ||
super.dispose(); | ||
} | ||
|
||
bool get isConnected { | ||
return _connectionState == BluetoothConnectionState.connected; | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return ListTile( | ||
title: Text(widget.device.platformName), | ||
subtitle: Text(widget.device.remoteId.toString()), | ||
trailing: ElevatedButton( | ||
onPressed: isConnected ? null : widget.onConnect, | ||
child: isConnected ? const Text('OPEN') : const Text('CONNECT'), | ||
), | ||
); | ||
} | ||
} |
Oops, something went wrong.