Setting up Stream for real-time user data - android

I'm trying to set up a stream such that if a user updates their data(like their name), it's displayed in real-time. Currently, It's already being updated in the firestore collection but I have to reload the in-app home page to actually see the updated value. I'm also using a custom UserData class.
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final AuthService _auth = AuthService();
User user = FirebaseAuth.instance.currentUser;
DatabaseService db = DatabaseService(uid: FirebaseAuth.instance.currentUser.uid);
void _showSettingsPanel(){
showModalBottomSheet(context: context, builder: (context){
return Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 60.0),
child: SettingsForm(),
);
});
}
#override
Widget build(BuildContext context) {
return StreamProvider<UserData>.value( // need to setup this stream
value: DatabaseService().userData,
child: Scaffold(
backgroundColor: Colors.redAccent,
appBar: AppBar(
title: Text('Signed in'),
backgroundColor: Colors.blueAccent,
elevation: 0.0, //no drop shadow
actions: <Widget>[
FlatButton.icon(
onPressed: () async {
await _auth.signOutUser();
},
icon: Icon(Icons.person),
label: Text('logout')),
FlatButton.icon(
icon: Icon(Icons.settings),
label: Text('Settings'),
onPressed: () => _showSettingsPanel(),
)
],
),
body: FutureBuilder(
future: db.getProfile(),
builder: (context, snapshot){
if (snapshot.connectionState == ConnectionState.done){
return ListTile(
leading: CircleAvatar(
radius: 25.0,
backgroundColor: Colors.brown,
),
title: Text(snapshot.data),
tileColor: Colors.white,
);
}
else {
return CircularProgressIndicator();
}
},
)
),
);
}
}

No need for a StreamProvider, you just need a StreamBuilder!
You already have the uid, so you just have to listen to the stream from Firestore.
Here is an example.
StreamBuilder<DocumentSnapshot>(
stream:
FirebaseFirestore.instance.collection('users').doc(uid).snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.active) {
return Center(child: CircularProgressIndicator());
}
return ListTile(
leading: CircleAvatar(
radius: 25.0,
backgroundColor: Colors.brown,
),
title: Text(snapshot.data.data()['name']),
tileColor: Colors.white,
);
},
);

Related

how can i fix this error of my todo list?

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

How to change Flutter_blue read and write button designs

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.

Getting Album Artwork in flutter

I am trying to create a music app. I managed to get all the songs list but I cannot seem to get album artwork from the song metadata. I am using flutter_audio_query: ^0.3.5+6 plugin for this.
I cannot get the artwork by using songs[index].albumArtwork. It always returns null instead of the image path. What is the problem with my code?
Here is my code
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_audio_query/flutter_audio_query.dart';
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final FlutterAudioQuery audioQuery = FlutterAudioQuery();
List<SongInfo> songs = [];
#override
void initState() {
super.initState();
checkPermission();
getAllSongs();
}
Future<void> getAllSongs() async {
songs = await audioQuery.getSongs();
}
Future<void> checkPermission() async {
if (await Permission.storage.request().isGranted) {
setState(() {});
} else {
_showDialog();
}
}
void _showDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Warning'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('The app needs storage permission in order to work'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () async {
Navigator.of(context).pop();
await checkPermission();
},
),
],
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF3C3C3C),
appBar: AppBar(
elevation: 0.0,
centerTitle: true,
toolbarHeight: 64.0,
leading: Icon(
Icons.music_note_rounded,
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(Icons.search_rounded),
),
],
backgroundColor: Colors.transparent,
title: Text(
"All Songs",
style: GoogleFonts.expletusSans(
fontWeight: FontWeight.bold,
),
),
),
body: ListView.builder(
itemCount: songs.length,
itemBuilder: (context, index) {
return ListTile(
leading: Image.asset(
songs[index].albumArtwork != null
? songs[index].albumArtwork
: "assets/placeholder.png",
),
title: Text(songs[index].title),
subtitle: Text(songs[index].artist),
);
},
),
);
}
}
Sometimes albumArtwork will return a null value. In this case you need to use [FlutterAudioQuery().getArtwork()].
Documentation
Use ResourceType.ALBUM to get album image and ResourceType.SONG to song image.
Example:
// check if artistArtPath isn't available.
(song.artwork == null)
? FutureBuilder<Uint8List>(
future: audioQuery.getArtwork(
type: ResourceType.SONG, id: song.id),
builder: (_, snapshot) {
if (snapshot.data == null)
return Container(
height: 250.0,
child: Center(
child: CircularProgressIndicator(),
),
);
return CardItemWidget(
height: 250.0,
title: artist.name,
// The image bytes
// You can use Image.memory widget constructor
// or MemoryImage image provider class to load image from bytes
// or a different approach.
rawImage: snapshot.data,
);
}) :
// or you can load image from File path if available.
Image.file( File( artist.artistArtPath ) )

Flutter_blue and Adafruit Bluefruit BLE characteristic error: could not locate CCCD descriptor for characteristic

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.

Firebase Voting App to only allow users vote only once in android studio

In the code below, I seek to make users vote only once in my Voting App.
At the moment users can vote more than once. I have created hasVoted field(a map with the UID of users and true as a value to indicate the user has voted) in the item being voted for as shown in my Firestore backend, however this does not seem to work as i want it to. What could be wrong. Does anyone here know a way around this?
Please i am new to flutter and dart so kindly forgive petty mistake that i make in posting this question
Below is my code
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:compuvote/models/finance_model.dart';
import 'package:compuvote/routes/home_page.dart';
import 'package:compuvote/routes/transitionroute.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
class FinanceResult extends StatefulWidget {
#override
_FinanceResultState createState() {
return _FinanceResultState();
}
}
class _FinanceResultState extends State<FinanceResult> {
List<charts.Series<Record, String>> _seriesBarData;
List<Record> mydata;
_generateData(mydata) {
_seriesBarData = List<charts.Series<Record, String>>();
_seriesBarData.add(
charts.Series(
domainFn: (Record record, _) => record.name.toString(),
measureFn: (Record record, _) => record.totalVotes,
//colorFn: (Record record, _) => record.color,
id: 'Record',
data: mydata,
// Set a label accessor to control the text of the arc label.
labelAccessorFn: (Record row, _) => '${row.name}: ${row.totalVotes}',
colorFn: (_, __) => charts.MaterialPalette.cyan.shadeDefault,
fillColorFn: (_, __) => charts.MaterialPalette.transparent,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Finance Result'),
leading: IconButton(
icon: Icon(Icons.home),
onPressed: () {
Navigator.push(context, TransitionPageRoute(widget: HomePage()));
},
),
),
body: Container(
color: Colors.grey.shade100,
child: _buildBody(context),
));
}
/// ****** This code is suppose to build the body ***********/
Widget _buildBody(BuildContext context) {
return Column(
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('finance').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: LinearProgressIndicator(
valueColor: AlwaysStoppedAnimation(
Theme.of(context).primaryColor,
),
),
);
} else {
List<Record> finance = snapshot.data.documents
.map((documentSnapshot) =>
Record.fromMap(documentSnapshot.data))
.toList();
return _buildChart(context, finance);
}
},
),
],
);
}
Widget _buildChart(BuildContext context, List<Record> recorddata) {
mydata = recorddata;
_generateData(mydata);
return Padding(
padding: EdgeInsets.all(8.0),
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height / 1.2,
child: Center(
child: Column(
children: <Widget>[
SizedBox(
height: 10.0,
),
Expanded(
child: charts.PieChart(
_seriesBarData,
animate: true,
animationDuration: Duration(seconds: 3),
//For adding labels to the chart
defaultRenderer: new charts.ArcRendererConfig(
strokeWidthPx: 2.0,
arcWidth: 100,
arcRendererDecorators: [
// <-- add this to the code
charts.ArcLabelDecorator(
labelPosition: charts.ArcLabelPosition.auto,
labelPadding: 3,
showLeaderLines: true,
insideLabelStyleSpec: charts.TextStyleSpec(
color: charts.Color.white,
fontSize: 12,
),
outsideLabelStyleSpec: charts.TextStyleSpec(
color: charts.Color.black,
fontSize: 12,
),
),
]),
),
),
Container(
width: MediaQuery.of(context).size.width / 3.5,
height: 1,
color: Colors.black38,
),
Expanded(
child: Scaffold(
backgroundColor: Colors.grey.shade100,
body: _castVote(context),
),
),
],
),
),
),
);
}
/// ****** This code is suppose to link to the Firestore collection ***********/
Widget _castVote(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('finance').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(
child: LinearProgressIndicator(
valueColor: AlwaysStoppedAnimation(
Theme.of(context).primaryColor,
),
),
);
return _buildList(context, snapshot.data.documents);
},
);
}
/// ****** This code is suppose to build the List ***********/
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 20.0),
// ignore: missing_return
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
/// ****** This code is suppose to build the List Items ***********/
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
return Padding(
key: ValueKey(record.name),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Card(
elevation: 2,
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade100),
borderRadius: BorderRadius.circular(5.0),
),
child: ListTile(
title: Text(record.name),
trailing: Text(record.totalVotes.toString()),
onTap: () => {
_checkHasVoted(context, data),
}
//onTap: () => {record.reference.updateData({'votes': record.votes + 1}),
),
),
),
);
}
/// ****** This code is suppose to force users to vote only once ***********/
Widget _checkHasVoted(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
StreamSubscription<DocumentSnapshot> subscription;
final DocumentReference documentReference =
Firestore.instance.collection("finance").document() as DocumentReference;
#override
void initState() {
super.initState();
subscription = documentReference.snapshots().listen((datasnapshot) {
if ((datasnapshot.data
.containsKey(FirebaseAuth.instance.currentUser()))) {
setState(() {
return Text("Sorry you have voted in this category already");
});
}
else if (!datasnapshot.data.containsKey(FirebaseAuth.instance.currentUser())){
setState(() {
record.reference.updateData({'votes':record.totalVotes + 1});
});
}
});
}
}
}

Categories

Resources