123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869 |
- import 'dart:async';
- import 'dart:io';
- import 'dart:math';
- import 'dart:typed_data';
- import 'package:android_intent/android_intent.dart';
- import 'package:broadcast/broadcast.dart';
- import 'package:device_info/device_info.dart';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/scheduler.dart';
- import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
- import 'package:get_it/get_it.dart';
- import 'package:permission_handler/permission_handler.dart';
- import 'package:sport/application.dart';
- import 'package:sport/db/bluetooth_db.dart';
- import 'package:sport/provider/bluetooth.dart';
- import 'package:sport/utils/toast.dart';
- import 'package:sport/widgets/appbar.dart';
- import 'package:sport/widgets/button_cancel.dart';
- import 'package:sport/widgets/button_primary.dart';
- import 'package:sport/widgets/dialog/alert_dialog.dart';
- import 'package:sport/widgets/dialog/request_dialog.dart';
- import 'package:sport/widgets/dialog/search_device_connect.dart';
- import 'package:sport/widgets/image.dart';
- import 'package:sport/widgets/misc.dart';
- import 'package:umeng_common_sdk/umeng_common_sdk.dart';
- import 'package:url_launcher/url_launcher.dart';
- openSearchDeviceDialog(BuildContext context) async {
- if (Platform.isAndroid) {
- DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
- AndroidDeviceInfo info = await deviceInfo.androidInfo;
- if (info.version.sdkInt < 31) {
- final isLocationEnabled = await Broadcast.isLocationEnabled();
- if (!isLocationEnabled) {
- if (await showDialog(
- context: context,
- builder: (context) => CustomAlertDialog(
- title: '打开定位信息服务才能正常连接蓝牙设备',
- ok: () => Navigator.of(context).pop(true),
- textOk: "去打开",
- ),
- ) ==
- true) {
- await Broadcast.openSetting();
- }
- return;
- }
- PermissionStatus permissions = await Permission.locationWhenInUse.request();
- if (permissions.isGranted) {
- showDialog(context: context, barrierDismissible: false, builder: (_) => SearchDeviceDialog());
- } else {
- if (await showDialog(
- context: context,
- builder: (context) => CustomAlertDialog(title: '使用蓝牙功能需授权定位权限', ok: () => Navigator.of(context).pop(true)),
- ) ==
- true) {
- openAppSettings();
- } else {
- ToastUtil.show('使用蓝牙设备需要授权定位权限!');
- }
- return false;
- }
- } else {
- Map<Permission, PermissionStatus> statuses = await [
- Permission.bluetoothScan,
- Permission.bluetoothConnect,
- ].request();
- if (statuses.isNotEmpty == true && statuses.values.every((element) => element.isGranted)) {
- showDialog(context: context, barrierDismissible: false, builder: (_) => SearchDeviceDialog());
- } else {
- if (await showDialog(
- context: context,
- builder: (context) => CustomAlertDialog(title: '使用蓝牙功相应的系统权限', ok: () => Navigator.of(context).pop(true)),
- ) ==
- true) {
- openAppSettings();
- } else {
- ToastUtil.show('使用蓝牙设备需要蓝牙搜索权限和连接权限!');
- }
- return false;
- }
- }
- } else if (Platform.isIOS) {
- showDialog(context: context, barrierDismissible: false, builder: (_) => SearchDeviceDialog());
- }
- return true;
- }
- class SearchDeviceDialog extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- double height = MediaQuery.of(context).size.height / 5 * 3;
- return Dialog(
- elevation: 0,
- shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
- child: ConstrainedBox(
- constraints: BoxConstraints(minHeight: height, minWidth: double.infinity, maxHeight: height),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Stack(
- alignment: Alignment.center,
- children: <Widget>[
- Center(
- child: Padding(
- padding: const EdgeInsets.all(6.0),
- child: Text("请选择鞋子", style: Theme.of(context).textTheme.headline3),
- ),
- ),
- Positioned(
- right: 0,
- top: 0,
- child: GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () => Navigator.pop(context),
- child: Padding(
- padding: const EdgeInsets.all(6.0),
- child: Image.asset("lib/assets/img/btn_close_big.png"),
- ),
- ),
- ),
- ],
- ),
- Expanded(
- child: StreamBuilder<BleStatus>(
- stream: FlutterReactiveBle().statusStream,
- initialData: BleStatus.unknown,
- builder: (c, snapshot) {
- final state = snapshot.data ?? BleStatus.unknown;
- if (state == BleStatus.ready) {
- return FindDevicesScreen();
- } else if (state == BleStatus.poweredOff) {
- return BluetoothOffScreen(state: state);
- }
- return Container(
- child: Center(child: SizedBox(
- width: 100,
- height: 100,
- child: CircularProgressIndicator(
- )),),
- );
- }),
- ),
- ],
- ),
- )),
- );
- }
- }
- class BluetoothOffScreen extends StatelessWidget {
- final BleStatus state;
- const BluetoothOffScreen({Key? key, required this.state}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- SizedBox(
- height: 20,
- ),
- Image.asset("lib/assets/img/pop_icon_bluetooth.png"),
- SizedBox(
- height: 20,
- ),
- Text(
- '蓝牙未开启',
- style: Theme.of(context).textTheme.bodyText2!,
- ),
- SizedBox(
- height: 10,
- ),
- GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () async {
- if (Platform.isAndroid) {
- AndroidIntent intent = AndroidIntent(action: "android.bluetooth.adapter.action.REQUEST_ENABLE");
- await intent.launch();
- } else if (Platform.isIOS) {
- launch("App-Prefs:root=Bluetooth");
- }
- },
- child: Center(
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Text(
- '打开蓝牙设置',
- style: Theme.of(context).textTheme.bodyText2!.copyWith(color: Theme.of(context).accentColor),
- ),
- SizedBox(
- width: 6,
- ),
- arrowRight6()
- ],
- ),
- ),
- ),
- Divider(
- height: 32,
- ),
- Text(
- '下窗弹窗点击如图所示位置',
- style: Theme.of(context).textTheme.subtitle2,
- ),
- Container(
- padding: EdgeInsets.fromLTRB(25.0, 7, 25.0, 16.0),
- child: Platform.isAndroid ? Image.asset("lib/assets/img/pop_img_bluetooth_android.png") : Image.asset("lib/assets/img/pop_img_bluetooth_ios.png"),
- ),
- ],
- );
- }
- }
- class FindDevicesScreen extends StatefulWidget {
- @override
- State<StatefulWidget> createState() => _FindDevicesScreen();
- }
- class _FindDevicesScreen extends State<FindDevicesScreen> with SingleTickerProviderStateMixin {
- late AnimationController _animationController;
- late Animation<double> _animation;
- bool _search = true;
- bool _error = false;
- int _time = 0;
- int _timeout = 10;
- List<DiscoveredDevice> scanResults = <DiscoveredDevice>[];
- late Bluetooth bluetooth;
- Map<String, Map<String, dynamic>> history = {};
- Timer? timer;
- late FlutterReactiveBle flutterReactiveBle;
- StreamSubscription? scanForDevices;
- @override
- void initState() {
- super.initState();
- bluetooth = GetIt.I<Bluetooth>();
- flutterReactiveBle = FlutterReactiveBle();
- _animationController = AnimationController(duration: Duration(seconds: 2), vsync: this);
- _animation = Tween(begin: .0, end: 1.0).animate(_animationController)
- ..addStatusListener((status) {
- if (status == AnimationStatus.completed) {
- _animationController.repeat();
- }
- });
- //开始动画
- _animationController.forward();
- startScan();
- SchedulerBinding.instance?.addPostFrameCallback((timeStamp) {
- if (bluetooth.isRightError) bluetooth.disconnectDevice("打开搜索界面时右鞋状态异常");
- });
- UmengCommonSdk.onEvent("shoe_search", {});
- }
- @override
- void dispose() {
- scanForDevices?.cancel();
- _animationController.dispose();
- super.dispose();
- }
- startScan() {
- timer?.cancel();
- scanForDevices?.cancel();
- history.clear();
- BluetoothDB().find().then((value) {
- value.forEach((e) {
- history[e[BluetoothDB.C_ID]] = e;
- });
- setState(() {});
- });
- setState(() {
- _time = 0;
- scanResults = [];
- _search = true;
- _error = false;
- });
- timer = Timer.periodic(Duration(seconds: 1), (timer) {
- if (!mounted) return;
- int t = ++_time;
- if (t % 3 == 0) {
- _updateData();
- }
- if (_time >= 10) {
- scanForDevices?.cancel();
- scanForDevices = null;
- timer.cancel();
- _updateData();
- }
- setState(() {
- });
- });
- scanForDevices = flutterReactiveBle.scanForDevices(withServices: [Uuid.parse(BLE_UUID)], scanMode: ScanMode.lowPower).listen((e) {
- if (e.name.isEmpty) return;
- // if (e.id == bluetooth.deviceId) return;
- if (e.name.toUpperCase().startsWith("SH") || e.name.toUpperCase().startsWith("FUN")) {
- final knownDeviceIndex = scanResults.indexWhere((d) => d.id == e.id);
- if (knownDeviceIndex >= 0) {
- scanResults[knownDeviceIndex] = e;
- } else {
- scanResults.add(e);
- }
- }
- })
- ..onDone(() {});
- }
- _updateData() {
- _search = scanForDevices != null;
- scanResults.sort((a, b) {
- int r = (history[b.id]?[BluetoothDB.C_TIMES] ?? 0).compareTo(history[a.id]?[BluetoothDB.C_TIMES] ?? 0);
- return r == 0
- ? a.rssi.abs() > b.rssi.abs()
- ? 1
- : -1
- : r;
- });
- }
- @override
- Widget build(BuildContext context) {
- int maxRssi = scanResults.isEmpty ? 0 : scanResults.reduce((value, element) => value.rssi > element.rssi ? value : element).rssi;
- return Column(
- children: <Widget>[
- Expanded(
- child: RefreshIndicator(
- color: Theme.of(context).colorScheme.secondary,
- onRefresh: () async {
- if (!_search) startScan();
- },
- child: CustomScrollView(
- slivers: [
- SliverToBoxAdapter(
- child: Column(
- children: [
- ValueListenableBuilder(
- valueListenable: bluetooth.deviceNotifier,
- builder: (BuildContext context, DiscoveredDevice? d, Widget? child) {
- if (d == null) return Container();
- return Column(
- children: <Widget>[
- Container(
- margin: const EdgeInsets.symmetric(vertical: 12.0),
- decoration: BoxDecoration(border: Border.all(color: Theme.of(context).accentColor), borderRadius: const BorderRadius.all(Radius.circular(10.0))),
- child: ListTile(
- contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6.0),
- title: Row(
- children: <Widget>[
- (history.containsKey(d.id) && (history[d.id]?[BluetoothDB.C_MARK] as String?)?.isNotEmpty == true)
- ? Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- "${(history[d.id]?[BluetoothDB.C_MARK])}",
- overflow: TextOverflow.ellipsis,
- style: Theme.of(context).textTheme.subtitle1,
- ),
- Padding(
- padding: const EdgeInsets.only(top: 4.0),
- child: Text(
- d.name,
- overflow: TextOverflow.ellipsis,
- style: Theme.of(context).textTheme.bodyText1,
- ),
- ),
- ],
- )
- : Text(
- d.name,
- overflow: TextOverflow.ellipsis,
- style: Theme.of(context).textTheme.subtitle1,
- ),
- const SizedBox(
- height: 4,
- ),
- ],
- ),
- trailing: Padding(
- padding: const EdgeInsets.symmetric(vertical: 8.0),
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Icon(
- Icons.link_off,
- color: Theme.of(context).accentColor,
- ),
- SizedBox(
- width: 4,
- ),
- Text(
- "断开连接",
- style: TextStyle(
- color: Theme.of(context).accentColor,
- fontSize: 12,
- ),
- strutStyle: fixedLine,
- )
- ],
- ),
- ),
- onTap: (){GetIt.I<Bluetooth>().clearDevice(deleteStep: true);},
- ),
- ),
- SizedBox(
- height: 16.0,
- ),
- Align(
- alignment: Alignment.centerLeft,
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 8.0),
- child: Text(
- "附近的设备",
- style: Theme.of(context).textTheme.bodyText1,
- ),
- ),
- ),
- ],
- );
- },
- ),
- Divider(),
- ],
- ),
- ),
- for (var i = 0; i < scanResults.length; i++)
- SliverPadding(
- padding: const EdgeInsets.symmetric(horizontal: 8.0),
- sliver: SliverToBoxAdapter(
- child: Column(
- children: <Widget>[
- ListTile(
- contentPadding: const EdgeInsets.symmetric(horizontal: 0),
- title: Row(
- children: [
- (history.containsKey(scanResults[i].id) && (history[scanResults[i].id]?[BluetoothDB.C_MARK] as String?)?.isNotEmpty == true)
- ? Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- "${(history[scanResults[i].id]?[BluetoothDB.C_MARK])}",
- overflow: TextOverflow.ellipsis,
- style: Theme.of(context).textTheme.subtitle1,
- ),
- Padding(
- padding: const EdgeInsets.only(top: 4.0),
- child: Text(
- scanResults[i].name,
- overflow: TextOverflow.ellipsis,
- style: Theme.of(context).textTheme.bodyText1,
- ),
- ),
- ],
- )
- : Text(
- scanResults[i].name,
- overflow: TextOverflow.ellipsis,
- style: Theme.of(context).textTheme.subtitle1,
- ),
- const SizedBox(
- width: 10,
- ),
- Rssi(
- rssi: scanResults[i].rssi,
- index: maxRssi
- ),
- if (isDebugShoe)
- Text(
- "${scanResults[i].rssi}",
- style: Theme.of(context).textTheme.bodyText1?.copyWith(fontSize: 8),
- ),
- if (history.containsKey(scanResults[i].id))
- history.keys.first == scanResults[i].id
- ? Container(
- margin: const EdgeInsets.symmetric(horizontal: 8),
- padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(50),
- border: Border.all(
- color: Theme.of(context).accentColor,
- width: .5,
- )),
- child: Text(
- "最近使用",
- style: Theme.of(context).textTheme.bodyText1!.copyWith(fontSize: 8, color: Theme.of(context).accentColor),
- ),
- )
- : Container(
- margin: const EdgeInsets.symmetric(horizontal: 8),
- padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(50),
- border: Border.all(
- color: const Color(0xff999999),
- width: .5,
- )),
- child: Text(
- "曾经使用",
- style: Theme.of(context).textTheme.bodyText1!.copyWith(fontSize: 8),
- ),
- ),
- ],
- ),
- trailing: Container(
- width: 64,
- height: 30,
- alignment: Alignment.center,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.all(Radius.circular(100)),
- border: Border.all(
- color: Theme.of(context).accentColor,
- )),
- child: Text(
- "连接",
- style: Theme.of(context).textTheme.bodyText1?.copyWith(color: Theme.of(context).colorScheme.secondary),
- ),
- ),
- onTap: () async{
- UmengCommonSdk.onEvent("shoe_search_connect", {});
- // await request(context, () async {
- // await scanForDevices?.cancel();
- // await GetIt.I<Bluetooth>().clearDevice(deleteStep: true);
- // await Future.delayed(Duration(seconds: 2));
- // return 1;
- // });
- await scanForDevices?.cancel();
- await GetIt.I<Bluetooth>().clearDevice(deleteStep: true);
- Navigator.pop(context);
- await showDialog(context: context, barrierDismissible: false, builder: (_) => SearchDeviceConnectDialog(device: scanResults[i], alias: history[scanResults[i].id]?[BluetoothDB.C_MARK],));
- },
- ),
- const Divider()
- ],
- ),
- ),
- ),
- if (_search && scanResults.isEmpty)
- SliverFillRemaining(
- child: Center(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Stack(
- alignment: Alignment.center,
- children: <Widget>[RotationTransition(turns: _animation, child: Image.asset("lib/assets/img/pop_image_circle.png")), Image.asset("lib/assets/img/pop_image_shoes.png")],
- ),
- SizedBox(
- height: 12,
- ),
- Text("搜索中...")
- ],
- ),
- ),
- ),
- if (!_search && _error)
- SliverFillRemaining(
- child: Center(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Image.asset("lib/assets/img/pop_image_noequipment.png"),
- SizedBox(
- height: 10,
- ),
- Text("蓝牙搜索异常,请重新尝试")
- ],
- ),
- ),
- ),
- if (!_search && scanResults.isEmpty)
- SliverFillRemaining(
- child: Center(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Image.asset("lib/assets/img/pop_image_noequipment.png"),
- SizedBox(
- height: 10,
- ),
- Text("暂无设备")
- ],
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- Padding(
- padding: const EdgeInsets.all(8.0),
- child: _search
- ? CancelButton(
- height: 35,
- content: "搜索中(${max(0, _timeout - _time)})...",
- callback: () {
- // FlutterBluePlus.instance.stopScan().then((value) {
- // setState(() {
- // _search = false;
- // });
- // });
- },
- )
- : PrimaryButton(height: 35, content: "重新搜索", callback: () => startScan()),
- ),
- ],
- );
- }
- }
- class DeviceScreen extends StatefulWidget {
- const DeviceScreen({Key? key, required this.device}) : super(key: key);
- final DiscoveredDevice device;
- @override
- State<StatefulWidget> createState() {
- return _DeviceScreenState();
- }
- }
- class _DeviceScreenState extends State<DeviceScreen> {
- late TextEditingController _textEditingController;
- @override
- void initState() {
- super.initState();
- _textEditingController = TextEditingController();
- }
- List<int> _getRandomBytes() {
- final math = Random();
- return [math.nextInt(255), math.nextInt(255), math.nextInt(255), math.nextInt(255)];
- }
- @override
- Widget build(BuildContext context) {
- DiscoveredDevice device = widget.device;
- final bluetooth = GetIt.I<Bluetooth>();
- return Scaffold(
- appBar: buildAppBar(
- context,
- title: device.name,
- actions: <Widget>[
- StreamBuilder<ConnectionStateUpdate>(
- stream: FlutterReactiveBle().connectedDeviceStream.where((event) => event.deviceId == device.id),
- initialData: ConnectionStateUpdate(
- deviceId: device.id,
- connectionState: DeviceConnectionState.disconnected,
- failure: null,
- ),
- builder: (c, snapshot) {
- VoidCallback? onPressed;
- String text;
- switch (snapshot.data?.connectionState) {
- case DeviceConnectionState.connected:
- onPressed = () => FlutterReactiveBle().connectToDevice(id: device.id);
- text = 'DISCONNECT';
- break;
- case DeviceConnectionState.disconnected:
- onPressed = () => FlutterReactiveBle().clearGattCache(device.id);
- text = 'CONNECT';
- break;
- default:
- text = snapshot.data.toString().substring(21).toUpperCase();
- break;
- }
- return FlatButton(
- onPressed: onPressed,
- child: Text(
- text,
- style: Theme.of(context).primaryTextTheme.button!.copyWith(color: Colors.white),
- ));
- },
- )
- ],
- ),
- body: SingleChildScrollView(
- child: Column(
- children: <Widget>[
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- ValueListenableBuilder(
- valueListenable: bluetooth.deviceReadNotifier,
- builder: (BuildContext context, bool value, Widget? child) => Container(
- width: 50,
- height: 50,
- color: value ? Colors.green : Colors.red,
- child: Center(
- child: Text(
- "读",
- style: TextStyle(color: Colors.white),
- ))),
- ),
- ValueListenableBuilder(
- valueListenable: bluetooth.deviceWriteNotifier,
- builder: (BuildContext context, bool value, Widget? child) => Container(width: 50, height: 50, color: value ? Colors.green : Colors.red, child: Center(child: Text("写", style: TextStyle(color: Colors.white)))),
- ),
- ValueListenableBuilder(
- valueListenable: bluetooth.deviceReadNotifyNotifier,
- builder: (BuildContext context, bool value, Widget? child) => Container(width: 50, height: 50, color: value ? Colors.green : Colors.red, child: Center(child: Text("通知", style: TextStyle(color: Colors.white)))),
- ),
- ],
- ),
- Padding(
- padding: const EdgeInsets.all(16.0),
- child: Row(
- children: [
- Expanded(
- child: CupertinoTextField(
- cursorColor: const Color(0xffFFC400),
- controller: _textEditingController,
- )),
- SizedBox(
- width: 10,
- ),
- RaisedButton(
- onPressed: () {
- var data = _textEditingController.value.text;
- if (data.isEmpty) return;
- List<int> list = data.split(" ").where((element) => element.isNotEmpty).map((e) => int.parse(e, radix: 16)).toList();
- print("test write $list --> ${Uint8List.fromList(list)}");
- bluetooth.writeUintList(Uint8List.fromList(list));
- },
- child: Text("发送"))
- ],
- ),
- ),
- Row(
- children: [
- RaisedButton(
- onPressed: () {
- bluetooth.queryDeviceStep(test: true);
- },
- child: Text("同步步数"),
- ),
- ValueListenableBuilder(
- valueListenable: GetIt.I<Bluetooth>().stepTotalNotifier,
- builder: (BuildContext context, int value, Widget? child) {
- if (value < 0) {
- return CircularProgressIndicator();
- }
- return Text(" 获得步数: $value");
- },
- ),
- ],
- ),
- RaisedButton(
- onPressed: () {
- bluetooth.resetData();
- },
- child: Text("清零"),
- ),
- RaisedButton(
- onPressed: () {
- bluetooth.setupGameMode(true);
- },
- child: Text("游戏模式开"),
- ),
- RaisedButton(
- onPressed: () {
- bluetooth.setupGameMode(false);
- },
- child: Text("游戏模式关"),
- ),
- RaisedButton(
- onPressed: () async {
- bluetooth.vibrate(GetIt.I<Bluetooth>().vibrateNotifier.value);
- },
- child: Text("发送震动"),
- ),
- ValueListenableBuilder(
- valueListenable: GetIt.I<Bluetooth>().vibrateNotifier,
- builder: (BuildContext context, int v, Widget? child) => Row(
- children: <Widget>[
- Slider(
- divisions: 9,
- value: v.toDouble(),
- min: 100,
- max: 1000,
- onChanged: (double value) {
- bluetooth.vibrateNotifier.value = value.toInt();
- },
- ),
- Text("$v")
- ],
- ),
- ),
- ValueListenableBuilder(
- valueListenable: GetIt.I<Bluetooth>().actionNotifier,
- builder: (BuildContext context, int value, Widget? child) => Text("当前动作: $value"),
- ),
- ValueListenableBuilder(
- valueListenable: GetIt.I<Bluetooth>().stepTotalNotifier,
- builder: (BuildContext context, int value, Widget? child) => Text("同步步数: $value"),
- ),
- ValueListenableBuilder(
- valueListenable: GetIt.I<Bluetooth>().stepNotifier,
- builder: (BuildContext context, int value, Widget? child) => Text("相对步数: $value"),
- ),
- ValueListenableBuilder(
- valueListenable: GetIt.I<Bluetooth>().byteNotifier,
- builder: (BuildContext context, List<int> value, Widget? child) => ConstrainedBox(
- constraints: BoxConstraints(minHeight: 200),
- child: Text(
- "接收: $value",
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
- }
- class Rssi extends StatelessWidget {
- final int rssi;
- final int index;
- const Rssi({Key? key, this.rssi = 0, this.index = 0}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- int r = this.rssi.abs();
- int total = 4;
- int level = 1;
- if(r == index.abs()){
- level = 4;
- } else if(r <= 60){
- level = 3;
- }else if(r <= 80){
- level = 2;
- }
- double height = 12;
- return Container(
- height: height,
- child: Row(crossAxisAlignment: CrossAxisAlignment.end, children: [
- for (var i = 0; i < total; i++)
- Container(
- width: 3,
- margin: EdgeInsets.only(right: 2),
- height: height - (total - i - 1) * 2,
- decoration: BoxDecoration(color: level > i ? Theme.of(context).colorScheme.secondary : const Color(0xffdcdcdc), borderRadius: BorderRadius.circular(3)),
- ),
- ]),
- );
- }
- }
|