I have a Dialog Widget, there are a Button and Text field there. On pressing the button there is a function which setState() and variable change. I do not see these changes instantly on a screen in the text field, I need to close and open Dialog again. Why and how can I make it happen (so the whole class/parent will be rebuilt? (It is about "Get location" button and next field)
class MyDialog extends StatefulWidget {
MyDialogState createState() => MyDialogState();
}
class MyDialogState extends State<MyDialog> {
String userLocation;
double sleepLength;
#override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)
),
elevation: 20,
child: ListView(
children: <Widget>[
FlatButton(
child: Text("Get location $userLocation"),
onPressed: () {
final Geolocator geolocator = Geolocator();
geolocator
.getCurrentPosition()
.then((Position position) async {
List<Placemark> place = await geolocator
.placemarkFromCoordinates(position.latitude, position.longitude);
Placemark p = place[0];
setState(() {
//userLocation = "${p.locality}, ${p.country}";
userLocation = Random().nextInt(10).toString();
print("A");
});
}).catchError((e) {
print("------------");
print(e);
print("------------");
});
},
),
Padding(
padding: EdgeInsets.all(10),
child: Center(child: Text("$userLocation"))
),
Divider(),
FlatButton(
child: Text("Set sleep length"),
onPressed: () {
//TODO
},
),
Padding(
padding: EdgeInsets.all(10),
child: Center(child: Text("$sleepLength"))
),
Divider(),
],
)
);
}
);
},
child: Icon(
Icons.settings
),
backgroundColor: Colors.black12,
);
}
}
In my case StatefulBuilder works.
StatefulBuilder is best used in situations where you have a medium/large widget tree and state needs to be introduced for a small subsection of that tree.
wrap you child with StatefulBuilder hope it helps..
Using StatefulBuilder you can solve this problem
Replace your MyDialogState with:
class MyDialogState extends State<MyDialog> {
String userLocation;
double sleepLength;
#override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)
),
elevation: 20,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return ListView(
children: <Widget>[
FlatButton(
child: Text("Get location $userLocation"),
onPressed: () {
final Geolocator geolocator = Geolocator();
geolocator
.getCurrentPosition()
.then((Position position) async {
List<Placemark> place = await geolocator
.placemarkFromCoordinates(position.latitude, position.longitude);
Placemark p = place[0];
setState(() {
//userLocation = "${p.locality}, ${p.country}";
userLocation = Random().nextInt(10).toString();
print("A");
});
}).catchError((e) {
print("------------");
print(e);
print("------------");
});
},
),
Padding(
padding: EdgeInsets.all(10),
child: Center(child: Text("$userLocation"))
),
Divider(),
FlatButton(
child: Text("Set sleep length"),
onPressed: () {
//TODO
},
),
Padding(
padding: EdgeInsets.all(10),
child: Center(child: Text("$sleepLength"))
),
Divider(),
],
);
},
)
);
}
);
},
child: Icon(
Icons.settings
),
backgroundColor: Colors.black12,
);
}
}
You have to wrap Dialog with return StatefulBuilder builder: ...
and carefully about } and ); because in this case it is a long string
code snippet
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Dialog(
...
);
},
);
your code with StatefulBuilder
class MyDialog extends StatefulWidget {
MyDialogState createState() => MyDialogState();
}
class MyDialogState extends State<MyDialog> {
String userLocation;
double sleepLength;
#override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)),
elevation: 20,
child: ListView(
children: <Widget>[
FlatButton(
child: Text("Get location $userLocation"),
onPressed: () {
final Geolocator geolocator = Geolocator();
geolocator
.getCurrentPosition()
.then((Position position) async {
List<Placemark> place =
await geolocator.placemarkFromCoordinates(
position.latitude, position.longitude);
Placemark p = place[0];
setState(() {
//userLocation = "${p.locality}, ${p.country}";
userLocation = Random().nextInt(10).toString();
print("A");
});
}).catchError((e) {
print("------------");
print(e);
print("------------");
});
},
),
Padding(
padding: EdgeInsets.all(10),
child: Center(child: Text("$userLocation"))),
Divider(),
FlatButton(
child: Text("Set sleep length"),
onPressed: () {
//TODO
},
),
Padding(
padding: EdgeInsets.all(10),
child: Center(child: Text("$sleepLength"))),
Divider(),
],
));
});
});
},
child: Icon(Icons.settings),
backgroundColor: Colors.black12,
);
}
}
Related
I have made an to do list with firebase. but when i click to create a new to do, i can't see anything apear on my page but in firebase it does show the string.
How can i fix this
(this is in flutter)
logcat:
2022-10-19 15:24:50.758 23369-23584 flutter com.example.voorbeeld I apen created
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class video_info extends StatefulWidget {
#override
_video_infoState createState() => _video_infoState();
}
class _video_infoState extends State<video_info> {
String todoTitle = "";
createTodos() {
DocumentReference documentReference =
FirebaseFirestore.instance.collection("MyTodos").doc(todoTitle);
//Map
Map<String, String> todos = {"todoTitle": todoTitle};
documentReference.set(todos).whenComplete(() {
print("$todoTitle created");
});
}
deleteTodos(item) {
DocumentReference documentReference =
FirebaseFirestore.instance.collection("MyTodos").doc(item);
documentReference.delete().whenComplete(() {
print("$item deleted");
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("mytodos"),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
title: Text("Add Todolist"),
content: TextField(
onChanged: (String value) {
todoTitle = value;
},
),
actions: <Widget>[
TextButton(
onPressed:() {
createTodos();
Navigator.of(context).pop();
},
child: Text("Add"))
],
);
});
},
child: Icon(
Icons.add,
color: Colors.white,
),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection("Mytodos").snapshots(),
builder: (context, snapshots) {
if (snapshots.hasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshots.data?.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot documentSnapshot =
snapshots.data!.docs[index];
return Dismissible(
onDismissed: (direction) {
deleteTodos(documentSnapshot["todoTitle"]);
},
key: Key(documentSnapshot["todoTitle"]),
child: Card(
elevation: 4,
margin: EdgeInsets.all(8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
child: ListTile(
title: Text(documentSnapshot["todoTitle"]),
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
deleteTodos(documentSnapshot["todoTitle"]);
}),
),
));
});
} else {
return Align(
alignment: FractionalOffset.bottomCenter,
child: CircularProgressIndicator(),
);
}
}),
);
}}
also does anyone know a link to an tuturial where they explain how i can link the database to a user login.
You're using another collection.
You are adding your todo to this collection:
FirebaseFirestore.instance.collection("MyTodos")
But in your StreamBuilder you use the collection "Mytodos":
stream: FirebaseFirestore.instance.collection("Mytodos").snapshots(),
Try creating a stream variable on state class
late final myStream = FirebaseFirestore.instance.collection("MyTodos").snapshots();
#override
Widget build(BuildContext context) {
....
body: StreamBuilder(
stream: myStream
Frontend looks of read and write command.
I need to change the design of read and write command on the bluetooth devcie screen.
I used the code from pauldemarco git repository.
But the device screen frontend design does not suit good for my application.
Can anyone share how to change the design of upload and download signal button on the user interface?
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'widgets.dart';
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
import 'package:dproject/qrcode.dart';
void main() {
// RenderErrorBox.backgroundColor = Colors.transparent;
ErrorWidget.builder = (FlutterErrorDetails details) => Scaffold(body:Center(child: Text("Click the Refresh Button"),));
runApp(FlutterBlueApp());
// static ErrorWidgetBuilder builder = _defaultErrorWidgetBuilder;
// RenderErrorBox.textStyle = ui.TextStyle(color: Colors.transparent);
}
class FlutterBlueApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.lightBlue,
home: StreamBuilder<BluetoothState>(
stream: FlutterBlue.instance.state,
initialData: BluetoothState.unknown,
builder: (c, snapshot) {
final state = snapshot.data;
if (state == BluetoothState.on) {
return FindDevicesScreen();
}
return BluetoothOffScreen(state: state);
}),
);
}
}
class BluetoothOffScreen extends StatelessWidget {
const BluetoothOffScreen({Key? key, this.state}) : super(key: key);
final BluetoothState? state;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.white54,
),
Text(
'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.',
// style: Theme.of(context)
// .primaryTextTheme
// .subhead
// ?.copyWith(color: Colors.white),
),
],
),
),
);
}
}
class FindDevicesScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Find Devices'),
),
body: RefreshIndicator(
onRefresh: () =>
FlutterBlue.instance.startScan(timeout: Duration(seconds: 8)),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
StreamBuilder<List<BluetoothDevice>>(
stream: Stream.periodic(Duration(seconds: 2))
.asyncMap((_) => FlutterBlue.instance.connectedDevices),
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data!
.map((d) => ListTile(
// title: Text(d.toString()),
// subtitle: Text(d.id.toString()),
trailing: StreamBuilder<BluetoothDeviceState>(
stream: d.state,
initialData: BluetoothDeviceState.disconnected,
builder: (c, snapshot) {
if (snapshot.data ==
BluetoothDeviceState.connected) {
return ElevatedButton(
child: Text('OPEN'),
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
DeviceScreen(device: d))),
);
}
return Text(snapshot.data.toString());
},
),
))
.toList(),
),
),
StreamBuilder<List<ScanResult>>(
stream: FlutterBlue.instance.scanResults,
initialData: [],
builder: (c, snapshot){
List<ScanResult> data = [];
// print("sh");
for(int i=0;i<snapshot.data!.length;i++)
{
// print("sh");
// print(snapshot.data![i]);
if(snapshot.data![i].device.id.toString()=='FC:67:78:5D:96:EF'){
data.add(snapshot.data![i]);
}
}
// print(data);
return Column(
children: data
.map(
(r) => ScanResultTile(
result: r,
onTap: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
r.device.connect();
return DeviceScreen(device: r.device); //FlutterBlueApp();
})),
),
)
.toList(),
);
},
),
],
),
),
),
floatingActionButton: StreamBuilder<bool>(
stream: FlutterBlue.instance.isScanning,
initialData: false,
builder: (c, snapshot) {
if (snapshot.data!) {
return FloatingActionButton(
child: Icon(Icons.stop),
onPressed: () => FlutterBlue.instance.stopScan(),
backgroundColor: Colors.red,
);
} else {
return FloatingActionButton(
child: Icon(Icons.search),
onPressed: () => FlutterBlue.instance
.startScan(timeout: Duration(seconds: 8)));
}
},
),
);
}
}
class DeviceScreen extends StatelessWidget {
const DeviceScreen({Key? key, required this.device}) : super(key: key);
final BluetoothDevice device;
List<int> _getRandomBytes() {
final math = Random();
return [
math.nextInt(255),
math.nextInt(255),
math.nextInt(255),
math.nextInt(255)
];
}
List<Widget> _buildServiceTiles(List<BluetoothService> services) {
List<BluetoothService> data = [];
print("sh%%%%%%%%%%%%%%%%%%%%%%####");
for(int i=0;i<services.length;i++)
{
print("sh####################################");
// print(services[i]);
if(i==2){
data.add(services[i]);
}
}
// print(data);
return data //services
.map(
(s) => ServiceTile(
service: s,
characteristicTiles: s.characteristics
.map(
(c) => CharacteristicTile(
characteristic: c,
onReadPressed: () {
c.read();
},
onWritePressed: () async {
await c.write([1], withoutResponse: false);
await c.read();
// ElevatedButton(
// // style: style,
// onPressed: null,
// child: const Text('Disabled'),
// );
},
onNotificationPressed: () async {
await c.setNotifyValue(!c.isNotifying);
await c.read();
},
descriptorTiles: c.descriptors
.map(
(d) => DescriptorTile(
descriptor: d,
onReadPressed: () => d.read(),
onWritePressed: () => d.write([1]),
),
)
.toList(),
),
)
.toList(),
),
)
.toList();
// print(c.read);
}
// #override
// State<DeviceScreen> createState() => _DeviceScreenState();
// }
// class _DeviceScreenState extends State<DeviceScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("BITLOCK"),//device.name
actions: <Widget>[
StreamBuilder<BluetoothDeviceState>(
stream: device.state,
initialData: BluetoothDeviceState.connecting,
builder: (c, snapshot) {
VoidCallback? onPressed;
String text;
switch (snapshot.data) {
case BluetoothDeviceState.connected:
onPressed = () => device.disconnect();
text = 'DISCONNECT';
break;
case BluetoothDeviceState.disconnected:
onPressed = () => device.connect();
text = 'CONNECT';
break;
default:
onPressed = null;
text = snapshot.data.toString().substring(21).toUpperCase();
break;
}
return TextButton(
onPressed: onPressed,
child: Text(
text,
style: Theme.of(context)
.primaryTextTheme
.button
?.copyWith(color: Colors.white),
));
},
)
],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
StreamBuilder<BluetoothDeviceState>(
stream: device.state,
initialData: BluetoothDeviceState.connecting,
builder: (c, snapshot) => ListTile(
leading: (snapshot.data == BluetoothDeviceState.connected)
? Icon(Icons.bluetooth_connected)
: Icon(Icons.bluetooth_disabled),
title: Text(((){
if(snapshot.data.toString().split('.')[1]=="connected"){
return 'Your Lock is ${snapshot.data.toString().split('.')[1]} to your device.';
}
return 'Your Lock is ${snapshot.data.toString().split('.')[1]} from your device.';
})()),
// subtitle: Text('${device.id}'),
trailing: StreamBuilder<bool>(
stream: device.isDiscoveringServices,
initialData: false,
builder: (c, snapshot) => IndexedStack(
index: snapshot.data! ? 1 : 0,
children: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () => device.discoverServices(),
),
IconButton(
icon: SizedBox(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(Colors.grey),
),
width: 18.0,
height: 18.0,
),
onPressed: null,
)
],
),
),
),
),
StreamBuilder<int>(
stream: device.mtu,
initialData: 0,
builder: (c, snapshot) => ListTile(
// title: Text('MTU Size'),
// subtitle: Text('${snapshot.data} bytes'),
trailing: IconButton(
icon: Icon(Icons.lock_open),
onPressed: () => device.requestMtu(223),
),
),
),
StreamBuilder<List<BluetoothService>>(
stream: device.services,
initialData: [],
builder: (c, snapshot) {
return Column(
children: _buildServiceTiles(snapshot.data!),
);
},
),
],
),
),
);
}
}
Thanks in advance.
Here is the solution I found.
You will find widgets.dart in the lib folder in which you are working with main.dart and other files.
You can edit this file according to required design.
In my case, I need to change Iconbutton icon in characteristics tile to change the design of read and write button.
I am currently running into an issue with my ble project for flutter. I am using the flutter blue package by Paul DeMarco and the additional page for the app is based on "ThatProject" dust sensor from youtube. I have an Adafruit Feather 32u4 board, and I am attempting to notify the client (my flutter app) that It has a series of numbers to send, but I am not getting any output. I am able to connect to the device, and seem to properly send the service UUID and characteristic UUID, but im not sure if it is coming with proper properties.
I am using the adafruit BLE code to program the board, and I can get the values if I use adafruit's app. I am just trying to get the values on my own flutter app.
I am running into an error as follows:
E/flutter (32139): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: PlatformException(set_notification_error, could not locate CCCD descriptor for characteristic: 6e400002-b5a3-f393-e0a9-e50e24dcca9e, null, null)
Here is my code. I believe the missing CCCD is coming from this part:
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:oscilloscope/oscilloscope.dart';
class SensorPage extends StatefulWidget {
const SensorPage({Key key, this.device}) : super(key: key);
final BluetoothDevice device;
#override
_SensorPageState createState() => _SensorPageState();
}
class _SensorPageState extends State<SensorPage> {
final String SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
final String CHARACTERISTIC_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
bool isReady;
Stream<List<int>> stream;
List<double> traceDust = List();
#override
void initState() {
super.initState();
isReady = false;
connectToDevice();
}
connectToDevice() async {
// if (widget.device == null) {
// // _Pop();
// return;
// }
//timeout timer, watchdog timer if you will
new Timer(const Duration(seconds: 15), () {
if (!isReady) {
disconnectFromDevice();
// _Pop();
}
});
await widget.device.connect();
discoverServices();
}
disconnectFromDevice() {
if (widget.device == null) {
//_Pop();
return;
}
widget.device.disconnect();
}
discoverServices() async {
// if (widget.device == null) {
// // _Pop();
// return;
// }
BluetoothCharacteristic ss;
List<BluetoothService> services = await widget.device.discoverServices();
services.forEach((service) {
debugPrint("This Service UUID is!${service.uuid.toString()}");
if (service.uuid.toString() == SERVICE_UUID) {
service.characteristics.forEach((characteristic) {
debugPrint("This char UUID is!${characteristic.uuid.toString()}");
if (characteristic.uuid.toString() == CHARACTERISTIC_UUID) {
debugPrint("Here is !isNotifying: ${!characteristic.isNotifying}");
debugPrint("Here is characteristic.value: ${characteristic.value}");
ss = characteristic;
stream = ss.value;
setState(() {
isReady = true;
});
} //this one
});
} //this one
});
await ss.setNotifyValue(true);
stream = ss.value;
if (!isReady) {
// _Pop();
}
}
Future<bool> _onWillPop() {
return showDialog(
context: context,
builder: (context) =>
new AlertDialog(
title: Text('Are you sure?'),
content: Text('Do you want to disconnect device and go back?'),
actions: <Widget>[
new FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: new Text('No')),
new FlatButton(
onPressed: () {
disconnectFromDevice();
Navigator.of(context).pop(true);
},
child: new Text('Yes')),
],
) ??
false);
}
// _Pop() {
// Navigator.of(context).pop(true);
// }
String _dataParser(List<int> dataFromDevice) {
debugPrint("current value is-> ${utf8.decode(dataFromDevice)}");
return utf8.decode(dataFromDevice);
}
#override
Widget build(BuildContext context) {
Oscilloscope oscilloscope = Oscilloscope(
showYAxis: true,
padding: 0.0,
backgroundColor: Colors.black,
traceColor: Colors.white,
yAxisMax: 3000.0,
yAxisMin: 0.0,
dataSet: traceDust,
);
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text('Optical Dust Sensor'),
),
body: Container(
child: !isReady
? Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
if (snapshot.connectionState ==
ConnectionState.active) {
debugPrint("snapshot.error: ${snapshot.error}.");
debugPrint("snapshot.data: ${snapshot.error}.");
debugPrint(
"snapshot.connectionState: ${snapshot.connectionState}.");
debugPrint("snapshot.hasdata?: ${snapshot.hasData}.");
var currentValue = _dataParser(snapshot.data);
traceDust.add(double.tryParse(currentValue) ?? 0);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Current value from Sensor',
style: TextStyle(fontSize: 14)),
Text('$currentValue ug/m3',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24))
]),
),
Expanded(
flex: 1,
child: oscilloscope,
)
],
));
} else {
return Text('Check the stream');
}
},
),
)),
),
);
}
}
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:K9Harness/Pages/Sensor_page.dart';
import 'package:K9Harness/Bluetooth/widgets.dart';
import 'package:flutter_blue/flutter_blue.dart';
class MyBluetoothPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
color: Colors.lightBlue,
home: StreamBuilder<BluetoothState>(
stream: FlutterBlue.instance.state,
initialData: BluetoothState.unknown,
builder: (c, snapshot) {
final state = snapshot.data;
if (state == BluetoothState.on) {
return FindDevicesScreen();
}
return BluetoothOffScreen(state: state);
}),
);
}
}
class BluetoothOffScreen extends StatelessWidget {
const BluetoothOffScreen({Key key, this.state}) : super(key: key);
final BluetoothState state;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.white54,
),
Text(
'Bluetooth Adapter is ${state.toString().substring(15)}.',
style: Theme.of(context)
.primaryTextTheme
.subhead
.copyWith(color: Colors.white),
),
],
),
),
);
}
}
class FindDevicesScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Find Devices'),
),
body: RefreshIndicator(
onRefresh: () => FlutterBlue.instance
.startScan(
scanMode: ScanMode.balanced,
withServices: [
Guid("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
], //FIXME check the other ways where ".startScan" is implemented
timeout: Duration(seconds: 4))
.catchError((error) {
print("error starting scan $error");
}),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
StreamBuilder<List<BluetoothDevice>>(
stream: Stream.periodic(Duration(seconds: 2))
.asyncMap((_) => FlutterBlue.instance.connectedDevices),
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map((d) => ListTile(
title: Text(d.name),
subtitle: Text(d.id.toString()),
trailing: StreamBuilder<BluetoothDeviceState>(
stream: d.state,
initialData: BluetoothDeviceState.disconnected,
builder: (c, snapshot) {
if (snapshot.data ==
BluetoothDeviceState.connected) {
return RaisedButton(
child: Text('OPEN'),
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
DeviceScreen(device: d))),
);
}
return Text(snapshot.data.toString());
},
),
))
.toList(),
),
),
StreamBuilder<List<ScanResult>>(
stream: FlutterBlue.instance.scanResults,
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map(
(r) => ScanResultTile(
result: r,
onTap: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
r.device.connect();
return SensorPage(device: r.device);
})),
),
)
.toList(),
),
),
],
),
),
),
floatingActionButton: StreamBuilder<bool>(
stream: FlutterBlue.instance.isScanning,
initialData: false,
builder: (c, snapshot) {
if (snapshot.data) {
return FloatingActionButton(
child: Icon(Icons.stop),
onPressed: () => FlutterBlue.instance.stopScan(),
backgroundColor: Colors.red,
);
} else {
return FloatingActionButton(
child: Icon(Icons.search),
onPressed: () => FlutterBlue.instance
.startScan(
scanMode: ScanMode.balanced,
withServices: [
Guid("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
], //FIXME check the other ways where ".startScan" is implemented
timeout: Duration(seconds: 4))
.catchError((error) {
print("error starting scan $error");
}));
}
},
),
);
}
}
class DeviceScreen extends StatelessWidget {
const DeviceScreen({Key key, this.device}) : super(key: key);
final BluetoothDevice device;
List<Widget> _buildServiceTiles(List<BluetoothService> services) {
return services
.map(
(s) => ServiceTile(
service: s,
characteristicTiles: s.characteristics
.map(
(c) => CharacteristicTile(
characteristic: c,
onReadPressed: () => c.read(),
onWritePressed: () => c.write([13, 24]),
onNotificationPressed: () =>
c.setNotifyValue(!c.isNotifying),
descriptorTiles: c.descriptors
.map(
(d) => DescriptorTile(
descriptor: d,
onReadPressed: () => d.read(),
onWritePressed: () => d.write([11, 12]),
),
)
.toList(),
),
)
.toList(),
),
)
.toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(device.name),
actions: <Widget>[
StreamBuilder<BluetoothDeviceState>(
stream: device.state,
initialData: BluetoothDeviceState.connecting,
builder: (c, snapshot) {
VoidCallback onPressed;
String text;
switch (snapshot.data) {
case BluetoothDeviceState.connected:
onPressed = () => device.disconnect();
text = 'DISCONNECT';
break;
case BluetoothDeviceState.disconnected:
onPressed = () => device.connect();
text = 'CONNECT';
break;
default:
onPressed = null;
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>[
StreamBuilder<BluetoothDeviceState>(
stream: device.state,
initialData: BluetoothDeviceState.connecting,
builder: (c, snapshot) => ListTile(
leading: (snapshot.data == BluetoothDeviceState.connected)
? Icon(Icons.bluetooth_connected)
: Icon(Icons.bluetooth_disabled),
title: Text(
'Device is ${snapshot.data.toString().split('.')[1]}.'),
subtitle: Text('${device.id}'),
trailing: StreamBuilder<bool>(
stream: device.isDiscoveringServices,
initialData: false,
builder: (c, snapshot) => IndexedStack(
index: snapshot.data ? 1 : 0,
children: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () => device.discoverServices(),
),
IconButton(
icon: SizedBox(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(Colors.grey),
),
width: 18.0,
height: 18.0,
),
onPressed: null,
)
],
),
),
),
),
StreamBuilder<int>(
stream: device.mtu,
initialData: 0,
builder: (c, snapshot) => ListTile(
title: Text('MTU Size'),
subtitle: Text('${snapshot.data} bytes'),
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () => device.requestMtu(223),
),
),
),
StreamBuilder<List<BluetoothService>>(
stream: device.services,
initialData: [],
builder: (c, snapshot) {
return Column(
children: _buildServiceTiles(snapshot.data),
);
},
),
],
),
),
);
}
}
I figured it out, I had my characteristic UUID to be 6e400002-b5a3-f393-e0a9-e50e24dcca9e and it should have been 6e400003-b5a3-f393-e0a9-e50e24dcca9e because for the feather, the notification/notify characteristic is mandatory to be 0x0003 instead of the 2. It then passed the CCCD properly when I changed this value.
I have a video in my assets folder, and when I am trying the code, it is giving some exceptions. Can anyone help me?
class VideoExample extends StatefulWidget {
#override
VideoState createState() => VideoState();
}
class VideoState extends State<VideoExample> {
VideoPlayerController playerController;
VoidCallback listener;
#override
void initState() {
super.initState();
listener = () {
setState(() {});
};
}
void createVideo() {
if (playerController == null) {
playerController = VideoPlayerController.asset("assets/videos/video.mp4")
..addListener(listener)
..setVolume(1.0)
..initialize();
}
}
#override
void deactivate() {
playerController.setVolume(0.0);
playerController.removeListener(listener);
super.deactivate();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Video'),
),
body: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
child: (playerController != null
? VideoPlayer(
playerController,
)
: Container()),
))),
floatingActionButton: FloatingActionButton(
onPressed: () {
createVideo();
playerController.play();
},
child: Icon(Icons.play_arrow),
),
);
}
}
I just want that the video should run in the full screen with landscape mode.
I had imported every essential package and changed the pubspec.yaml file.
It is playing the video but not playing it in full-screen landscape mode.
You can copy paste run full code below
You can use package https://pub.dev/packages/chewie and https://pub.dev/packages/auto_orientation
You can enter full screen mode with _chewieController.enterFullScreen()
code snippet
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController1,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
routePageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondAnimation, provider) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
return VideoScaffold(
child: Scaffold(
resizeToAvoidBottomPadding: false,
body: Container(
alignment: Alignment.center,
color: Colors.black,
child: provider,
),
),
);
},
);
}
FlatButton(
onPressed: () {
_chewieController.enterFullScreen();
},
child: Text('Fullscreen'),
),
working demo
full code
import 'package:auto_orientation/auto_orientation.dart';
import 'package:chewie/chewie.dart';
import 'package:chewie/src/chewie_player.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(
ChewieDemo(),
);
}
class ChewieDemo extends StatefulWidget {
ChewieDemo({this.title = 'Chewie Demo'});
final String title;
#override
State<StatefulWidget> createState() {
return _ChewieDemoState();
}
}
class _ChewieDemoState extends State<ChewieDemo> {
TargetPlatform _platform;
VideoPlayerController _videoPlayerController1;
VideoPlayerController _videoPlayerController2;
ChewieController _chewieController;
#override
void initState() {
super.initState();
_videoPlayerController1 = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');
_videoPlayerController2 = VideoPlayerController.network(
'https://www.sample-videos.com/video123/mp4/480/big_buck_bunny_480p_20mb.mp4');
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController1,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
routePageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondAnimation, provider) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
return VideoScaffold(
child: Scaffold(
resizeToAvoidBottomPadding: false,
body: Container(
alignment: Alignment.center,
color: Colors.black,
child: provider,
),
),
);
},
);
}
// Try playing around with some of these other options:
// showControls: false,
// materialProgressColors: ChewieProgressColors(
// playedColor: Colors.red,
// handleColor: Colors.blue,
// backgroundColor: Colors.grey,
// bufferedColor: Colors.lightGreen,
// ),
// placeholder: Container(
// color: Colors.grey,
// ),
// autoInitialize: true,
);
}
#override
void dispose() {
_videoPlayerController1.dispose();
_videoPlayerController2.dispose();
_chewieController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: widget.title,
theme: ThemeData.light().copyWith(
platform: _platform ?? Theme.of(context).platform,
),
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: <Widget>[
Expanded(
child: Center(
child: Chewie(
controller: _chewieController,
),
),
),
FlatButton(
onPressed: () {
_chewieController.enterFullScreen();
},
child: Text('Fullscreen'),
),
Row(
children: <Widget>[
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_chewieController.dispose();
_videoPlayerController2.pause();
_videoPlayerController2.seekTo(Duration(seconds: 0));
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController1,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
);
});
},
child: Padding(
child: Text("Video 1"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_chewieController.dispose();
_videoPlayerController1.pause();
_videoPlayerController1.seekTo(Duration(seconds: 0));
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController2,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
);
});
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Text("Video 2"),
),
),
)
],
),
Row(
children: <Widget>[
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_platform = TargetPlatform.android;
});
},
child: Padding(
child: Text("Android controls"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_platform = TargetPlatform.iOS;
});
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Text("iOS controls"),
),
),
)
],
)
],
),
),
);
}
}
class VideoScaffold extends StatefulWidget {
const VideoScaffold({Key key, this.child}) : super(key: key);
final Widget child;
#override
State<StatefulWidget> createState() => _VideoScaffoldState();
}
class _VideoScaffoldState extends State<VideoScaffold> {
#override
void initState() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
AutoOrientation.landscapeAutoMode();
super.initState();
}
#override
dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
AutoOrientation.portraitAutoMode();
super.dispose();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
I'm getting started with flutter/dart and I'm trying to implement a simple note app using InheritedWidget and TextControllers, but when I add or edit some note it doesn't update the main screen. I printed the new notes list in console and it is updated with the addings and editings but is not updated in main screen, still showing the initial note list ({'title': 'someTitle1', 'text': 'someText1'}, ...).
main.dart :
void main() => runApp(NoteInheritedWidget(
MaterialApp(
title: 'Notes App',
home: HomeList(),
),
));
home screen scaffold body :
List<Map<String, String>> get _notes => NoteInheritedWidget.of(context).notes;
...
body: ListView.builder(
itemCount: _notes.length,
itemBuilder: (context, index) {
return Card(
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 7),
child: ListTile(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => NotePage(noteMode: NoteMode.Editing, index: index))
);
print(_notes);
},
trailing: Icon(Icons.more_vert),
title: _NoteTitle(_notes[index]['title']),
subtitle: _NoteText(_notes[index]['text']),
),
);
},
),
Add/Edit Note page :
enum NoteMode {
Adding,
Editing
}
class NotePage extends StatefulWidget {
final NoteMode noteMode;
final int index;
const NotePage ({this.noteMode, this.index});
#override
_NotePageState createState() => _NotePageState();
}
class _NotePageState extends State<NotePage> {
final TextEditingController _titleController = TextEditingController();
final TextEditingController _textController = TextEditingController();
List<Map<String, String>> get _notes => NoteInheritedWidget.of(context).notes;
#override
void didChangeDependencies() {
if (widget.noteMode == NoteMode.Editing) {
_titleController.text = _notes[widget.index]['text'];
_textController.text = _notes[widget.index]['title'];
}
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.noteMode == NoteMode.Adding ? 'Add Note' : 'Edit Note'
),
centerTitle: true,
backgroundColor: Colors.indigo[700],
),
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextField(
controller: _titleController,
decoration: InputDecoration(
hintText: 'Note Title',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
TextField(
controller: _textController,
maxLines: 20,
decoration: InputDecoration(
hintText: 'Note Text',
border: OutlineInputBorder(),
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
_NoteButton(Icons.save, 'Save', () {
final title = _titleController.text;
final text = _textController.text;
if (widget.noteMode == NoteMode.Adding) {
_notes.add({'title': title, 'text': text});
print(_notes);
} else if (widget.noteMode == NoteMode.Editing) {
_notes[widget.index] = {'title': title, 'text': text};
print(_notes);
}
Navigator.pop(context);
}),
_NoteButton(Icons.clear, 'Discard', () {
Navigator.pop(context);
}),
if (widget.noteMode == NoteMode.Editing)
_NoteButton(Icons.delete, 'Delete', () {
_notes.removeAt(widget.index);
Navigator.pop(context);
}),
],
),
],
),
),
),
);
}
}
InheritedWidget :
class NoteInheritedWidget extends InheritedWidget {
final notes = [
{'title': 'someTitle1', 'text': 'someText1'},
{'title': 'someTitle2', 'text': 'someText2'},
{'title': 'someTitle3', 'text': 'someText3'}
];
NoteInheritedWidget(Widget child) : super(child: child);
static NoteInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<NoteInheritedWidget>();
}
#override
bool updateShouldNotify(NoteInheritedWidget old) {
return old.notes != notes;
}
}
Home screen after add a note :
HomeScreen
List of notes printed in console after add a note :
I/flutter (18079): [{title: someTitle1, text: someText1}, {title: someTitle2, text: someText2}, {title: someTitle3, text: someText3}, {title: NewAddNoteTitle, text: NewAddNoteText}]
I'm using Android Studio and a real device instead an emulator.
I can't find the error and if you have another way to do this 'update' please show me.
I found a solution using the onPressed method as async and then an empty setState, is there any problem for the code doing this?
code:
child: ListTile(
onTap: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => NotePage(noteMode: NoteMode.Editing, index: index))
);
setState(() {});
print(_notes);
},
...
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => NotePage(noteMode: NoteMode.Adding))
);
setState(() {});
print(_notes.length);
print(_notes);
},