11import 'package:bluez/bluez.dart' ;
2+ import 'package:flutter/foundation.dart' ;
23import 'package:flutter/material.dart' ;
4+ import 'package:provider/provider.dart' ;
5+ import 'package:settings/view/pages/bluetooth/BluetoothDeviceModel.dart' ;
36import 'package:settings/view/pages/bluetooth/bluetooth_device_types.dart' ;
4- import 'package:settings/view/pages/bluetooth/bluetooth_model.dart' ;
5- import 'package:yaru_icons/widgets/yaru_icons.dart' ;
67import 'package:yaru_widgets/yaru_widgets.dart' ;
78
89class BluetoothDeviceRow extends StatefulWidget {
9- const BluetoothDeviceRow (
10- {Key ? key, required this .device, required this .model})
10+ const BluetoothDeviceRow ({Key ? key, required this .removeDevice})
1111 : super (key: key);
1212
13- final BlueZDevice device;
14- final BluetoothModel model;
13+ final AsyncCallback removeDevice;
14+
15+ static Widget create (
16+ BuildContext context, BlueZDevice device, AsyncCallback removeDevice) {
17+ return ChangeNotifierProvider (
18+ create: (_) => BluetoothDeviceModel (device),
19+ child: BluetoothDeviceRow (
20+ removeDevice: removeDevice,
21+ ),
22+ );
23+ }
1524
1625 @override
1726 State <BluetoothDeviceRow > createState () => _BluetoothDeviceRowState ();
@@ -22,140 +31,139 @@ class _BluetoothDeviceRowState extends State<BluetoothDeviceRow> {
2231
2332 @override
2433 void initState () {
25- status = widget.device.connected ? 'connected' : 'disconnected' ;
34+ final model = context.read <BluetoothDeviceModel >();
35+ model.init ();
2636
2737 super .initState ();
2838 }
2939
3040 @override
3141 Widget build (BuildContext context) {
32- status = widget.device.connected ? 'connected' : 'disconnected' ;
42+ final model = context. watch < BluetoothDeviceModel >() ;
3343 return InkWell (
3444 borderRadius: BorderRadius .circular (4.0 ),
3545 onTap: () => setState (() {
36- showSimpleDeviceDialog (context);
46+ showDialog (
47+ context: context,
48+ builder: (context) => StatefulBuilder (builder: (context, setState) {
49+ return AlertDialog (
50+ title: Padding (
51+ padding:
52+ const EdgeInsets .only (right: 8 , left: 8 , bottom: 8 ),
53+ child: Row (
54+ mainAxisAlignment: MainAxisAlignment .spaceBetween,
55+ children: [
56+ Flexible (
57+ child: RichText (
58+ text: TextSpan (
59+ text: model.name,
60+ style: Theme .of (context).textTheme.headline6),
61+ maxLines: 10 ,
62+ overflow: TextOverflow .ellipsis,
63+ ),
64+ ),
65+ Padding (
66+ padding: const EdgeInsets .only (left: 10 ),
67+ child: Icon (
68+ BluetoothDeviceTypes .getIconForAppearanceCode (
69+ model.appearance)),
70+ )
71+ ],
72+ ),
73+ ),
74+ content: SizedBox (
75+ height: model.errorMessage.isEmpty ? 270 : 320 ,
76+ width: 300 ,
77+ child: SingleChildScrollView (
78+ child: Column (
79+ children: [
80+ YaruRow (
81+ trailingWidget: model.connected
82+ ? const Text ('Connected' )
83+ : const Text ('Disconnected' ),
84+ actionWidget: Switch (
85+ value: model.connected,
86+ onChanged: (connectRequested) async {
87+ connectRequested
88+ ? await model.connect ()
89+ : await model.disconnect ();
90+ setState (() {});
91+ })),
92+ YaruRow (
93+ trailingWidget: const Text ('Paired' ),
94+ actionWidget: Padding (
95+ padding: const EdgeInsets .only (right: 8 ),
96+ child: Text (model.paired ? 'Yes' : 'No' ),
97+ )),
98+ YaruRow (
99+ trailingWidget: const Text ('Address' ),
100+ actionWidget: Padding (
101+ padding: const EdgeInsets .only (right: 8 ),
102+ child: Text (model.address),
103+ )),
104+ YaruRow (
105+ trailingWidget: const Text ('Type' ),
106+ actionWidget: Padding (
107+ padding: const EdgeInsets .only (right: 8 ),
108+ child: Text (BluetoothDeviceTypes
109+ .map[model.appearance] ??
110+ 'Unkown' ),
111+ )),
112+ Padding (
113+ padding: const EdgeInsets .only (
114+ top: 16 , bottom: 8 , right: 8 , left: 8 ),
115+ child: SizedBox (
116+ width: 300 ,
117+ child: OutlinedButton (
118+ onPressed: () {
119+ if (BluetoothDeviceTypes .isMouse (
120+ model.appearance)) {
121+ // TODO: get route name from model
122+ Navigator .of (context)
123+ .pushNamed ('routeName' );
124+ }
125+ },
126+ child: const Text ('Open device settings' )),
127+ ),
128+ ),
129+ Padding (
130+ padding: const EdgeInsets .all (8 ),
131+ child: SizedBox (
132+ width: 300 ,
133+ child: TextButton (
134+ onPressed: () async {
135+ await model.disconnect ();
136+ widget.removeDevice;
137+
138+ Navigator .of (context).pop ();
139+ },
140+ child: const Text ('Remove device' )),
141+ ),
142+ ),
143+ if (model.errorMessage.isNotEmpty)
144+ Text (
145+ model.errorMessage,
146+ style: TextStyle (
147+ color: Theme .of (context).errorColor),
148+ )
149+ ],
150+ ),
151+ ),
152+ ),
153+ );
154+ }));
37155 }),
38156 child: Padding (
39157 padding: const EdgeInsets .all (8.0 ),
40158 child: YaruRow (
41- trailingWidget: Text (widget.device .name),
159+ trailingWidget: Text (model .name),
42160 actionWidget: Text (
43- widget.device .connected ? 'connected' : 'disconnected' ,
161+ model .connected ? 'connected' : 'disconnected' ,
44162 style: TextStyle (
45163 color:
46164 Theme .of (context).colorScheme.onSurface.withOpacity (0.7 )),
47165 )),
48166 ),
49167 );
50168 }
51-
52- void showSimpleDeviceDialog (BuildContext context) {
53- showDialog (
54- context: context,
55- builder: (context) => StatefulBuilder (builder: (context, setState) {
56- return AlertDialog (
57- title: Padding (
58- padding: const EdgeInsets .only (right: 8 , left: 8 , bottom: 8 ),
59- child: Row (
60- mainAxisAlignment: MainAxisAlignment .spaceBetween,
61- children: [
62- Flexible (
63- child: RichText (
64- text: TextSpan (
65- text: widget.device.name,
66- style: Theme .of (context).textTheme.headline6),
67- maxLines: 10 ,
68- overflow: TextOverflow .ellipsis,
69- ),
70- ),
71- Padding (
72- padding: const EdgeInsets .only (left: 10 ),
73- child: Icon (
74- BluetoothDeviceTypes .getIconForAppearanceCode (
75- widget.device.appearance)),
76- )
77- ],
78- ),
79- ),
80- content: SizedBox (
81- height: 270 ,
82- width: 300 ,
83- child: SingleChildScrollView (
84- child: Column (
85- children: [
86- YaruRow (
87- trailingWidget: widget.device.connected
88- ? const Text ('Connected' )
89- : const Text ('Disconnected' ),
90- actionWidget: Switch (
91- value: widget.device.connected,
92- onChanged: (newValue) async {
93- widget.device.connected
94- ? await widget.device.disconnect ()
95- : await widget.device
96- .connect ()
97- .catchError ((ioError) => {});
98- Navigator .of (context).pop ();
99- setState (() {});
100- })),
101- YaruRow (
102- trailingWidget: widget.device.paired
103- ? const Text ('Paired' )
104- : const Text ('Unpaired' ),
105- actionWidget: Padding (
106- padding: const EdgeInsets .only (right: 8 ),
107- child: Text (widget.device.paired ? 'Yes' : 'No' ),
108- )),
109- YaruRow (
110- trailingWidget: const Text ('Address' ),
111- actionWidget: Padding (
112- padding: const EdgeInsets .only (right: 8 ),
113- child: Text (widget.device.address),
114- )),
115- YaruRow (
116- trailingWidget: const Text ('Type' ),
117- actionWidget: Padding (
118- padding: const EdgeInsets .only (right: 8 ),
119- child: Text (BluetoothDeviceTypes
120- .map[widget.device.appearance] ??
121- 'Unkown' ),
122- )),
123- Padding (
124- padding: const EdgeInsets .only (
125- top: 16 , bottom: 8 , right: 8 , left: 8 ),
126- child: SizedBox (
127- width: 300 ,
128- child: OutlinedButton (
129- onPressed: () {
130- if (BluetoothDeviceTypes .isMouse (
131- widget.device.appearance)) {
132- // TODO: get route name from model
133- Navigator .of (context)
134- .pushNamed ('routeName' );
135- }
136- },
137- child: const Text ('Open device settings' )),
138- ),
139- ),
140- Padding (
141- padding: const EdgeInsets .all (8 ),
142- child: SizedBox (
143- width: 300 ,
144- child: TextButton (
145- onPressed: () async {
146- await widget.device.disconnect ().then (
147- (value) => widget.model
148- .removeDevice (widget.device));
149- Navigator .of (context).pop ();
150- },
151- child: const Text ('Remove device' )),
152- ),
153- )
154- ],
155- ),
156- ),
157- ),
158- );
159- })).then ((value) => setState (() {}));
160- }
161169}
0 commit comments