Scan for bluetooth devices Flutter - flutter

I am new to Bluetooth and this is the first time I am trying it, so I am trying to develop an application that scans for nearby Bluetooth devices and connects,
I am using flutter_blue package and I wrote this simple code to scan for devices, and there are two devices near it but when I run the app (real phone) it does not discover them, I want to know what is wrong with my code, I need help please.
class _MyHomePageState extends State<MyHomePage> {
final FlutterBlue flutterBlue= FlutterBlue.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("BLE"),),
body: StreamBuilder<BluetoothState>(
stream:flutterBlue.state,
builder: (context, snapshot){
if(snapshot.data == BluetoothState.on)
{
return ScanForDevices(flutterBlue: flutterBlue,);
//return Center(child: Text("${snapshot.data!.toString()}"),);
}
else if(snapshot.hasError ||snapshot.data == BluetoothState.unauthorized)
{
return Center(child: Text("Error"),);
}
else{
return Center(child: CircularProgressIndicator(),);
}
},
),
);
}
}
class _ScanForDevicesState extends State<ScanForDevices> {
late List<ScanResult> result ;
#override
void initState() {
// TODO: implement initState
super.initState();
widget.flutterBlue.startScan();
// scanning();
}
scanning() {
widget.flutterBlue.scanResults.listen((event) {
for(ScanResult r in event)
{
result.add(r);
print(r.device.id.toString() + "\n");
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<List<ScanResult>>(
stream:FlutterBlue.instance.scanResults,
builder: (context, snapshot){
if(snapshot.hasData)
{
return ListView(
// children: snapshot.data!.map((e) {
// return Text("${e.device.id.toString()}");
// }).toList(),
children: snapshot.data!.map((e) => ListTile(
leading: IconButton(
icon: Icon(Icons.present_to_all_sharp),
onPressed: (){e.device.connect(timeout: Duration(seconds: 4),);},),
subtitle: Text("${e.device.name }\n ${e.device.id.id}"),
title: Text(e.device.id.toString()))).toList()
// result.map((e) {
// return Text(e.device.id.toString());
// }).toList(),
);
}
if(snapshot.hasError)
{
return Text("Error");
}
else {
return CircularProgressIndicator();
}
},
),
);
}
}
and it shows these log messages

Related

Why can i see black screen when using BlocBuilder though i have taken all possible measures?

This is my main file, I am trying to check for internet connection.And showing dialog if there is no internet connection using flutter cubit.
But the only hurdle is for a flicker of second the screen goes black and then dialog is displayed , how can i avoid this?
main.file
void main() {
runApp(BlocProvider(
create: (BuildContext context) => ConnectivityCubit()..checkConnectivity(),
lazy: false,
child: MaterialApp(home: MyApp()),
));
}
class MyApp extends StatelessWidget {
MyApp({super.key});
bool _isDialogDisplayed = false;
#override
Widget build(BuildContext context) {
return BlocConsumer<ConnectivityCubit, ConnectivityState>(
listener: (context, state) {
if (state == ConnectivityState.disconnected) {
_isDialogDisplayed = true;
showDialog(
context: context,
builder: (context) => const AlertDialog(
title: Text('No Internet'),
content: Text('Please check your internet connection.'),
),
);
}
if (state == ConnectivityState.connected &&
_isDialogDisplayed == true) {
Navigator.of(context).pop();
_isDialogDisplayed = false;
}
},
builder: (context, state) {
if (state == ConnectivityState.init) {
return const CircularProgressIndicator();
}
return MaterialApp( // <-- This is causing problem
home: Scaffold(
body: state == ConnectivityState.connected
? const Center(
child: Text('Hello World'),
)
: const Center(child: CircularProgressIndicator()),
),
);
},
);
}
}
cubit.file
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
enum ConnectivityState { connected, disconnected, init }
class ConnectivityCubit extends Cubit<ConnectivityState> {
final Connectivity _connectivity = Connectivity();
StreamSubscription<ConnectivityResult>? _subscription;
late Stream<ConnectivityResult> streamValue;
ConnectivityCubit() : super(ConnectivityState.init) {
streamValue = _connectivity.onConnectivityChanged;
_subscription = _connectivity.onConnectivityChanged.listen((result) {
if (result == ConnectivityResult.none) {
emit(ConnectivityState.disconnected);
} else {
emit(ConnectivityState.connected);
}
});
}
checkConnectivity() async {
final result = await _connectivity.checkConnectivity();
if (result == ConnectivityResult.none) {
emit(ConnectivityState.disconnected);
} else {
emit(ConnectivityState.connected);
}
}
#override
Future<void> close() {
_subscription?.cancel();
return super.close();
}
}
I have tried to simply use this way
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('Hello World'),
)),
);
The above code solves black screen issue but it will show Hello World for fraction of second i.e because of the time taken to build dialog by the BlocListener. To overcome that I tried the above method. Though i have things wrapped inside the MaterialApp why do i see black screen?
you want builder part in check status and then showDialog()
MyApp({super.key});
bool _isDialogDisplayed = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: BlocConsumer<ConnectivityCubit, ConnectivityState>(
listener: (context, state) {
if (state == ConnectivityState.disconnected) {
_isDialogDisplayed = true;
showDialog(
context: context,
builder: (context) => const AlertDialog(
title: Text('No Internet'),
content: Text('Please check your internet connection.'),
),
);
}
if (state == ConnectivityState.connected &&
_isDialogDisplayed == true) {
Navigator.of(context).pop();
_isDialogDisplayed = false;
}
},
builder: (context, state) {
if (state == ConnectivityState.init) {
return const CircularProgressIndicator();
}
else if(state == ConnectivityState.disconnected){
_isDialogDisplayed = true;
showDialog(
context: context,
builder: (context) => const AlertDialog(
title: Text('No Internet'),
content: Text('Please check your internet connection.'),
),
);
}
},
);
);
}
}

is there a better way to write a document stream builder?

Is there a better way to write this code?
The application is about jobs and job applications.
Each job can have multiple job applications.
if the job is fulfilled, all the job applications should be closed so that people are not applying to a job that is closed.
I don't like the way the code is written but it achieves the functionality that I wanted.
to get to the 'JobApplicationView' I have to go through a page that displays all the current job applications, once I click on one of the job application, the job application.
here is the snip of code from the 'job application list view'
StreamBuilder(
stream: _jobsService.allJobApplications(userId),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
case ConnectionState.active:
if (snapshot.hasData) {
final allJobApplications =
snapshot.data as Iterable<CloudJobApplication>;
return JobApplicationsListView(
allowScroll: false,
jobApplications: allJobApplications,
onTap: (job) {
Navigator.of(context).pushNamed(
myJobApplicationsRoute,
arguments: job,
);
},
);
} else {
return const CircularProgressIndicator();
}
default:
return const CircularProgressIndicator();
}
},
),
Below is the really ugly code that performs the functionality that i want
class JobApplicationView extends StatefulWidget {
const JobApplicationView({Key? key}) : super(key: key);
#override
_JobApplicationViewState createState() => _JobApplicationViewState();
}
class _JobApplicationViewState extends State<JobApplicationView> {
final _formKey = GlobalKey<FormState>();
late final FirebaseCloudStorage _cloudFunctions;
final currentUser = AuthService.firebase().currentUser!;
#override
void initState() {
super.initState();
_cloudFunctions = FirebaseCloudStorage();
}
getExistingJobApplication(BuildContext context) {
return FirebaseFirestore.instance
.collection('job application')
.doc(context.getArgument<CloudJobApplication>()!.documentId)
.snapshots();
}
submitProposal(localStates) {
submitProposal() async {
await _cloudFunctions.updateJobApplicationColumn(
documentId: context.getArgument<CloudJobApplication>()!.documentId,
fieldNameColumn: jobApplicationStateColumn,
fieldNameColumnValue: jobApplicationStateOpen);
await _cloudFunctions.updateJobApplicationColumn(
documentId: context.getArgument<CloudJobApplication>()!.documentId,
fieldNameColumn: jobApplicationSubStateColumn,
fieldNameColumnValue: 'Awaiting client proposal');
}
// job applicator can submit proposal if the state is new
if (localStates['jobApplicatotIsSameAsCurrentUser'] &&
localStates['jobApplication'][jobApplicationStateColumn] ==
jobApplicationStateNew) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
textStyle: const TextStyle(fontSize: 13),
backgroundColor: Colors.blue,
),
onPressed: () => submitProposal(),
child: const Text('Submit proposal'),
);
// job creator can accept the proposal if state is open
// job creator can deny job proposal if state is open
} else {
return Container();
}
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('update job application'),
actions: [],
),
body: StreamBuilder(
stream: getExistingJobApplication(context),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
// this is where I saved the local states
var localStates = {};
localStates['width'] = MediaQuery.of(context).size.width;
localStates['jobApplication'] = snapshot.data;
localStates['formFieldsEditable'] = localStates['jobApplication']
[jobApplicationStateColumn] ==
jobApplicationStateNew &&
currentUser.id ==
localStates['jobApplication'][jobApplicatorIdColumn]
? true
: false;
localStates['jobApplicatotIsSameAsCurrentUser'] = currentUser.id ==
localStates['jobApplication'][jobApplicatorIdColumn];
localStates['jobCreatorIsSameAsCurrentUser'] = currentUser.id ==
localStates['jobApplication'][jobCreatorIdColumn];
return Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(32.0),
children: [
submitProposal(localStates),
],
),
);
}),
);
}
}

Run bloc only when list is empty

Why my function in initState - the loop doesnt work?
I mean that I just wanna run function
_newsBloc.add(GetCompanyList());
Only in first time app run when list of users is empty.
I just wanna make it because when I'm changing activities to other I have to wait again to fetch data from my api, but i dont want it.
If it ask Api 1 time I do not need it anymore.
Then I'm checkig length of list in init state it always return 0.
Any ideas?
This is my code:
class _CompanyActivityState extends State<CompanyActivity> with SingleTickerProviderStateMixin {
List<Company> _users = [];
final CompanyBloc _newsBloc = CompanyBloc();
#override
void initState() {
super.initState();
if(_users.length < 0 ) {
_newsBloc.add(GetCompanyList());
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavigationDrawerWidget(),
appBar: buildAppBar(),
floatingActionButton: Stack(
children: <Widget>[
Stack(
body: createListViewWidgets());
}
Widget createListViewWidgets() {
return Container(
margin: EdgeInsets.all(8.0),
child: BlocProvider(
create: (_) => _newsBloc,
child: BlocListener<CompanyBloc, CompanyState>(
listener: (context, state) {
if (state is CompanyError) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(state.message),
));
}
},
child: BlocBuilder<CompanyBloc, CompanyState>(
builder: (context, state) {
if (state is CompanyInitial) {
return _buildLoading();
} else if (state is CompanyLoading) {
return _buildLoading();
} else if (state is CompanyLoaded) {
_users = state.company;
return _listViewCard(context, state.company);
} else if (state is CompanyError) {
return Container();
} else {
return Container();
}
},
),
),
),
);
}
}
Bloc which works;
class CompanyBloc extends Bloc<CompanyEvent, CompanyState> {
List<Company> mList = [];
final ApiRepository _apiRepository = ApiRepository();
CompanyBloc() : super(CompanyInitial()) {
on<GetCompanyList>((event, emit) async {
try {
emit(CompanyLoading());
mList.addAll(await _apiRepository.fetchCompanyList());
emit(CompanyLoaded(mList));
if (mList.length == 0) {
emit(CompanyError('List is empty'));
}
} on NetworkError {
emit(CompanyError("Failed to fetch data. is your device online?"));
}
});
}
}
And state which is used to create _users list:
class CompanyLoaded extends CompanyState {
final List<Company> company;
const CompanyLoaded(this.company);
#override
List<Object> get props => throw UnimplementedError();
}

Widget doesn't return

I am trying to return a ListView.builder but it doesn't seem to happen with the code below. I have just started to learn to use flutter and I am trying to implement flutter_insta before moving to the actual API. With the code below I receive the first debug message to the console but the second one never comes. Does anyone have any idea why does this happen? I don't get any error messages either.
class _HomePageState extends State<HomePage> {
String _username = "xxx";
FlutterInsta flutterInsta = FlutterInsta();
List<String> images = new List<String>();
bool pressed = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Feed preview'),
),
body: homePage(),
);
}
Widget homePage(){
return Center(
child: Column(
children: [
RaisedButton(
child: Text("Load photos"),
onPressed: () async {
setState(() {
pressed = true;
printDetails(_username);
});//get Data
},
),
]
)
);
}
Future printDetails(String username) async {
await flutterInsta.getProfileData(username);
setState(() {
this.images = flutterInsta.feedImagesUrl;
});
_buildSuggestions();
}
Widget _buildSuggestions() {
print("debug");
return ListView.builder(
itemBuilder: /*1*/ (context, i) {
print("debug1");
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
return _buildRow(images[index]);
});
}
Widget _buildRow(String url) {
print("moi");
return ListTile(
trailing: Image.network(url)
);
}
}
_buildSuggestions have to be used somewhere in the widget tree.
class _HomePageState extends State<HomePage> {
String _username = "xxx";
FlutterInsta flutterInsta = FlutterInsta();
List<String> images = new List<String>();
bool pressed = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Feed preview'),
),
body: homePage(),
);
}
Widget homePage(){
return Center(
child: Column(
children: [
Expanded(child: _buildSuggestions()),
RaisedButton(
child: Text("Load photos"),
onPressed: () async {
setState(() {
pressed = true;
printDetails(_username);
});//get Data
},
),
]
)
);
}
Future printDetails(String username) async {
await flutterInsta.getProfileData(username);
setState(() {
this.images = flutterInsta.feedImagesUrl;
});
}
Widget _buildSuggestions() {
print("debug");
return ListView.builder(
itemBuilder: /*1*/ (context, i) {
print("debug1");
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
return _buildRow(images[index]);
});
}
Widget _buildRow(String url) {
print("moi");
return ListTile(
trailing: Image.network(url)
);
}
}
You need to render to _buildSuggestion in widget tree first.
You need to put itemCount to ListView.Builder
Checkout: https://api.flutter.dev/flutter/widgets/ListView/ListView.builder.html

Button pressed return a future builder

I have a button and if pressed should return a future builder here is my code.
I already search some examples on the web but no luck, Im new in flutter development and trying to create a simple login with api call.
Future<AccessToken>fetchAccessToken() async{final token = await _repository.fetchToKen();
>>return token;
}
onPressed: () {FutureBuilder<AccessToken>(future:bloc.fetchAccessToken(),builder: (context, snapshot) {if (snapshot.hasError) {return Text('Error');} else if (snapshot.hasData) {return Text('data');} else {return `Center`(child: CircularProgressIndicator(),);}},);}
I want to show a progress indicator while waiting for the api response, but after I receive the response, my builder inside the future builder is not called.
You can't simply return a widget and place it in the widget tree like that. Maybe you can use conditional list for hiding and showing the FutureBuilder widget.
import 'package:flutter/material.dart';
class ApiWidget extends StatefulWidget {
#override
_ApiWidgetState createState() => _ApiWidgetState();
}
class _ApiWidgetState extends State<ApiWidget> {
Repository _repository = Repository();
Future<AccessToken> accessTokenFuture;
bool isButtonPressed = false;
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
FloatingActionButton(onPressed: () {
setState(() {
try {
isButtonPressed = true;
accessTokenFuture = fetchAccessToken();
} catch (_) {
print('Fetch error');
}
});
}, child: Icon(Icons.add),),
if(isButtonPressed)
FutureBuilder<AccessToken>(
future: bloc.fetchAccessToken(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Text('Error');
}
Column(
children: <Widget>[Text(snapshot.data)],
);
},
),
],);
}
}
You can do something like that:
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
FloatingActionButton(onPressed: () {
setState(() {
try {
isLoading = true;
accessTokenFuture = await fetchAccessToken();
isLoading = false;
} catch (_) {
isLoading = false;
print('Fetch error');
}
});
}, child: Icon(Icons.add),),
_buildAsyncInfo(),
],);
}
Widget _buildAsyncInfo() {
return isLoading ?
CircularProgressIndicator() :
Column(
children: <Widget>[Text(snapshot.data)],
);
}