flutter_reactive_ble code for the main page which will connect to a device name "BT05" when we press the button and send a string value "B" and receive the value response from the device and print it on the screen, I have posted my code here as well for reference but I don't know what I'm doing wrong here, please help me with this as I'm stuck for long enough now and tried many ways to it. i have also used some other flutter libraries but none of them worked well
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Reactive BLE',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Reactive BLE'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _deviceName = "BT05";
String _value = "B";
String _responseValue = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter BLE Demo'),
),
body: Column(
children: <Widget>[
ElevatedButton(
child: Text('Connect to $_deviceName'),
onPressed: () async {
// Connect to device
final stateUpdate = await FlutterReactiveBle.instance
.connectToDevice(_deviceName);
stateUpdate.listen((s) {
if (s == ConnectionState.disconnected) {
// Disconnected state
} else if (s == ConnectionState.connected) {
// Connected state
// Send value
FlutterReactiveBle.instance
.writeCharacteristic(_deviceName, _value)
.then((value) {
// Response value
_responseValue = value;
});
}
});
},
),
Text('Response value: $_responseValue')
],
),
);
}
}
Related
If flutter app starts with:
void main() {
WidgetsFlutterBinding.ensureInitialized();
Then clock.now() prints not mocked value if outside of build method.
Since I am using withClock in my tests, it makes my app unable to be properly tested as sometimes clock.now() returns mocked value, and sometimes real current time.
Please find the following example, and note that _printClockNow prints DateTime.now(), but it should print year 1990.
If you removed line WidgetsFlutterBinding.ensureInitialized() then it works as expected.
Minimum reproduceable code:
import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
withClock(Clock.fixed(DateTime(1990)), () {
runApp(const MyApp());
});
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _printClockNow() {
print('_printClockNow is: ${clock.now()}'); // prints real NOW
setState(() {});
}
#override
Widget build(BuildContext context) {
print('build clock.now() is: ${clock.now()}'); // prints mocked NOW
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Dummy()],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _printClockNow,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
class Dummy extends StatelessWidget {
#override
Widget build(Object context) {
return Text('t: ${clock.now()}');
}
}
Try with putting WidgetsFlutterBinding inside withClock.
void main() {
withClock(Clock.fixed(DateTime(1990)), () {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
});
}
I am trying to use hive to store data on a local machine using hive but each time when I compile the code it gives the error "The box "notebook" is already open and of type Box."
Can someone help me to resolve the issue as I am new to it? Thanks
I am just trying to add data to the database in this app without any change to the state of the app interface. I have tried to change the main method to void but no luck on this.
All the code is located in the main file
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'notes.dart';
import 'notesStoring.dart';
Future main() async{
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(NotesAdapter());
await Hive.openBox<NotesAdapter>('noteBook');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void dispose() {
Hive.close();
// TODO: implement dispose
super.dispose();
}
#override
Future incrementCounter(String title) async {
final notes = Notes()
..title = title;
final box =Boxes.getNotesValues();
box.add(notes);
}
final titleForNotes=TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body:
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
TextField(
controller: titleForNotes,
cursorColor: Colors.pink,
),
ValueListenableBuilder<Box<Notes>>(valueListenable: Boxes.getNotesValues().listenable(), builder: (context,box,_){
final noteBook =box.values.toList().cast<Notes>();
return buildContent(noteBook);
})
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
incrementCounter(titleForNotes.text);
},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class Boxes {
static Box<Notes> getNotesValues()=>Hive.box<Notes>('noteBook');
}
Widget buildContent(List<Notes> noteBook){
return Column(
children: [
Expanded(child:
ListView.builder(
padding: EdgeInsets.all(8),
itemCount: noteBook.length,
itemBuilder: (BuildContext context, int index){
final notes= noteBook[index];
return buildTransaction(context, notes);
}
)
)
],
);
}
Widget buildTransaction(
BuildContext context,
Notes notes,
){
return Card(
color: Colors.green,
child: Text(notes.title),
);
}
1.You can open your notebook Box in the main method of your app:
Future<void> main() async {
...
final appDocumentDirectory = await
path_provider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path);
Hive.registerAdapter(UserAdapter());
// open the user box
await Hive.openBox('notebook');
_setUpLogging();
runApp(MultiProvider(providers: providers, child:
StartupApplication()));
}
2 Access the previously opened box like below:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// user box
Box notebookBox;
#override
void initState() {
super.initState();
// get the previously opened user box
notebookBox = Hive.box('notebook');
}
#override
Widget build(BuildContext context) {
// check for your conditions
return (notebookBox.values.isNotEmpty && notebookBox.get(0).active == 1)
? HomeView()
: Intro();
}
}
I'm moving to Riverpod and starting with what should be a very simple boolean state management to switch the app theme. I've read many "how to" to do this exact thing, but none focus on the basics itself, are using outdated API, use different notifiers and providers, and add more features than needed. So now I'm lost.
versions:
shared_preferences: ^2.0.13
flutter_riverpod: ^1.0.3
Simple story:
A model class that extends StateNotifier and has accessor and mutators in it for 1 single boolean value
Very basic app + stateful widget
Problem: I can see, via prints, the state is being altered, but the UI is not changing to when the state is changed. Am I not using StateNotifier and StateProvider properly for a simple boolean state?
Thank you for any insight and guidance! Code follows:
===
model class with accessors / mutators
class RiverThemeDarkModel extends StateNotifier<bool> {
RiverThemeDarkModel() : super(false) {}
bool get isDark {
print("model asked for dark status: ${state}");
return state;
}
toggleDark() {
print("toggler has listeners: ${hasListeners}");
state = !state;
print("toggled to: ${state}");
}
set isDark(bool value) {
state = value;
}
}
Very basic app + stateful widget
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
final themeProvider = StateProvider((ref) => RiverThemeDarkModel());
class MyApp extends ConsumerWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
final darkValueModel = ref.watch(themeProvider);
print("consumer widget: dark value is ${darkValueModel.state} and listeners: ${darkValueModel.hasListeners}");
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: darkValueModel.isDark? ThemeData.dark() : ThemeData.light(),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends ConsumerStatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
ConsumerState<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends ConsumerState<MyHomePage> {
#override
Widget build(BuildContext context) {
final darkValueModel = ref.watch(themeProvider);
print("build of state");
return Scaffold(
appBar: AppBar(
title: Text(darkValueModel.isDark ? "Dark Mode" : "Light Mode"),
actions: [
IconButton(
icon: Icon(darkValueModel.isDark
? Icons.nightlight_round
: Icons.wb_sunny),
onPressed: () {
ref.read(themeProvider).toggleDark();
print("Got pressed button, after setting is ${ref.read(themeProvider).isDark} \n\n");
})
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Something',
),
],
),
),
);
}
}
From your code snippet, what you did here
final themeProvider = StateProvider((ref) => RiverThemeDarkModel());
was to provide to your UI access to the default state of your class which is false. thus if you change it to true and rerun the app it changes the theme. now what you want to do is expose access to the stateNotifier of your class which listens to the state changes of the class and notifies its listeners. To achieve this you need to use a StateNotifierProvider this way...
final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
(ref) => RiverThemeDarkModel());
Now the rest of the code to help your implementation is as follows
For your Model.
class RiverThemeDarkModel extends StateNotifier<bool> {
RiverThemeDarkModel() : super(false) {}
//u don't need this 'getter' piece of code
bool get isDark {
print("model asked for dark status: ${state}");
return state;
}
toggleDark() {
print("toggler has listeners: ${hasListeners}");
state = !state;
print("toggled to: ${state}");
}
//neither do you need this
set isDark(bool value) {
state = value;
}
}
For your UI...
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
(ref) => RiverThemeDarkModel());
class MyApp extends ConsumerWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
final darkValueModel = ref.watch(themeProvider);
print("consumer widget: dark value is ${darkValueModel.state} and listeners: ${darkValueModel.hasListeners}");
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: darkValueModel? ThemeData.dark() : ThemeData.light(),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends ConsumerStatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
ConsumerState<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends ConsumerState<MyHomePage> {
#override
Widget build(BuildContext context) {
final darkValueModel = ref.watch(themeProvider);
print("build of state");
return Scaffold(
appBar: AppBar(
title: Text(darkValueModel ? "Dark Mode" : "Light Mode"),
actions: [
IconButton(
icon: Icon(darkValueModel
? Icons.nightlight_round
: Icons.wb_sunny),
onPressed: () {
ref.read(themeProvider.notifier).toggleDark();
print("Got pressed button, after setting is ${ref.read(themeProvider)} \n\n");
})
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Something',
),
],
),
),
);
}
}
Check out the documentation too. It clarifies some things you won't get from most tutorials. https://riverpod.dev/docs/concepts/reading
use this
final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
(ref) => RiverThemeDarkModel());
Instead of this
final themeProvider = StateProvider(
(ref) => RiverThemeDarkModel());
Small Change on your code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
(ref) => RiverThemeDarkModel());
class MyApp extends ConsumerWidget {
MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
final darkValueModel = ref.watch(themeProvider);
print(
"consumer widget: dark value is ${ref.read(themeProvider.notifier).state} and listeners: ${ref.read(themeProvider.notifier).hasListeners}");
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme:darkValueModel
? ThemeData.dark()
: ThemeData.light(),
home: MyHomePage(title: 'Flutter Demo Home Page${ref.read(themeProvider.notifier).isDark}'),
);
}
}
class MyHomePage extends ConsumerStatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
ConsumerState<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends ConsumerState<MyHomePage> {
#override
Widget build(BuildContext context) {
final darkValueModel = ref.watch(themeProvider);
print("build of state");
return Scaffold(
appBar: AppBar(
title: Text(ref.read(themeProvider.notifier).isDark
? "Dark Mode${widget.title}"
: "Light Mode"),
actions: [
IconButton(
icon: Icon(ref.read(themeProvider.notifier).isDark
? Icons.nightlight_round
: Icons.wb_sunny),
onPressed: () {
ref.read(themeProvider.notifier).toggleDark();
print(
"Got pressed button, after setting is ${ref.read(themeProvider.notifier).isDark} \n\n");
})
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Something ${ref.read(themeProvider.notifier).isDark} ",
),
],
),
),
);
}
}
class RiverThemeDarkModel extends StateNotifier<bool> {
RiverThemeDarkModel() : super(false) {}
bool get isDark {
print("model asked for dark status: ${state}");
return state;
}
toggleDark() {
print("toggler has listeners: ${hasListeners}");
state = !state;
print("toggled to: ${state}");
}
set isDark(bool value) {
state = value;
}
}
enter image description here
Here I want to change the button which depends on a text field, like when the text field is filled then show the button C, and when clicked the C button then change the button name C to AC and also need to change text field fill to empty.
check this example to demonstrate the output you need
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Location',
theme: ThemeData(
primarySwatch: Colors.amber,
),
home: const MyHomePage(title: 'Flutter Location Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();
String? buttonText;
#override
void initState() {
_controller.addListener(_checkTextIsEmpty);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: Column(
children: [
TextField(
controller: _controller,
onChanged: (value) {},
),
Text(buttonText ?? ''),
],
),
),
);
}
void _checkTextIsEmpty() {
final value = _controller.text.isEmpty ? "AC" : "C";
setState(() {
buttonText = value;
});
}
}
I'm very new to flutter.
I've created an app that should open up google maps on click but it wont open.
Please help me out.
forMap.dart file (This is the file which has the method to launch google maps):
import 'package:url_launcher/url_launcher.dart';
class MapUtils {
MapUtils._();
static Future<void>openMap(double latitude,double longitude) async {
String googleUrl = 'https://www.google.com/maps/search/?api=1&query=$latitude,$longitude';
if(await canLaunch(googleUrl) != null) {
await canLaunch(googleUrl);
} else {
throw 'Could not open the map.';
}
}
}
main.dart file (This is the file which will use the method of the forMap.dart file and launch it):
import 'package:flutter/material.dart';
import 'forMap.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: (){
MapUtils.openMap(38.8977,77.0365);
},
child: Text('get map'),
),
],
),
),
);
}
}
It is because you have incorrectly calling a function. You're using await canLaunch(googleUrl); instead of await launch(googleUrl); in the if part.
So, your code should be like this:
static Future<void> openMap(double latitude,double longitude) async {
String googleUrl = 'https://www.google.com/maps/search/?api=1&query=$latitude,$longitude';
if(await canLaunch(googleUrl) != null) {
await launch(googleUrl);
} else {
throw 'Could not open the map.';
}
}
You probably don't need to use Future<void> so, change the function name to:
static void openMap(double latitude,double longitude) async {
...
}