How to call Void() function in another Stateful widget - flutter

I want to call the void play() method in another stateful widget
main.dart
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:permission_handler/permission_handler.dart';
import 'regitration.dart';
import 'voiceCreate.dart';
import 'stopwatch.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String statusText = "";
bool isComplete = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Scaffold(
drawer: Drawer(
elevation: 2.0,
child: ListView(
children: <Widget>[
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return MyApp();
},
),
);
},
),
ListTile(
title: Text('Sign up'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return StopWatch();
},
),
);
},
),
ListTile(
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
// add sign in page
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return MyHomePage();
}),
);
},
// Add your onPressed code here!
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
backgroundColor: Colors.grey.shade900,
appBar: AppBar(
title: Text('Myvo'),
centerTitle: true,
backgroundColor: Colors.tealAccent.shade700,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 40,
onPressed: () async {
startRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.pause),
color: Colors.white,
iconSize: 40,
onPressed: () async {
pauseRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 40,
onPressed: () async {
stopRecord();
}),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
statusText,
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
play();
},
child: Container(
margin: EdgeInsets.only(top: 30),
alignment: AlignmentDirectional.center,
width: 100,
height: 50,
child: isComplete && recordFilePath != null
? Text(
"play",
style: TextStyle(color: Colors.red, fontSize: 20),
)
: Container(),
),
),
]),
),
),
);
}
Future<bool> checkPermission() async {
if (!await Permission.microphone.isGranted) {
PermissionStatus status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
return false;
}
}
return true;
}
void startRecord() async {
bool hasPermission = await checkPermission();
if (hasPermission) {
statusText = "Recording...";
recordFilePath = await getFilePath();
isComplete = false;
RecordMp3.instance.start(recordFilePath, (type) {
statusText = "Record error--->$type";
setState(() {});
});
} else {
statusText = "No microphone permission";
}
setState(() {});
}
void pauseRecord() {
if (RecordMp3.instance.status == RecordStatus.PAUSE) {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
} else {
bool s = RecordMp3.instance.pause();
if (s) {
statusText = "Recording pause...";
setState(() {});
}
}
}
void stopRecord() {
bool s = RecordMp3.instance.stop();
if (s) {
statusText = "Record complete";
isComplete = true;
setState(() {});
}
}
void resumeRecord() {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
}
String recordFilePath; //maybe**strong text** this need to take
void play() {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
AudioPlayer audioPlayer = AudioPlayer();
audioPlayer.play(recordFilePath, isLocal: true);
}
}
int i = 0;
Future<String> getFilePath() async {
Directory storageDirectory = await getApplicationDocumentsDirectory();
String sdPath = storageDirectory.path + "/record";
var d = Directory(sdPath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
return sdPath + "/test_${i++}.mp3";
}
}
voiceCreate.dart
I want to call here when onPressed
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _isRecording = false;
MyHomePage.play()**//getting error here**
_startRecording() {
this.setState(() {
_isRecording = true;
});
}
_stopRecording() {
this.setState(() {
_isRecording = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.black,
iconSize: 70,
onPressed: () => _startRecording(),
),
IconButton(
icon: Icon(Icons.stop),
color: Colors.black,
iconSize: 70,
onPressed: () => _stopRecording(),
),
IconButton(
icon: Icon(Icons.play_arrow),
color: Colors.black,
onPressed: () => `MyHomePage(title: "My title", play: this.play()),`**// getting error here**
),
already called the starRecording and stopRecording
all three functions are not working when onPressed, these are startRecording, stopRecording and play. these function are working okay in main.dart but not in voiceCreate.dart

Dart functions are first-class, that means you can pass them around like a variable. Have a VoidCallback member on your widget class.
MyHomePage(this.playCallback, {Key key, this.title}) : super(key: key);
final String title;
final VoidCallback playCallback;
You can pass it in the constructor.
child: MyHomePage(play)
Then you can reach it in your state object.
class _MyHomePageState extends State<MyHomePage> {
...
onPressed: widget.playCallback
...
}
Warning
This is not a recommended way to achieve this. Widgets must contain zero business logic if possible. Little hacks like this answer will make your code very complex than it should be. Consider reading state management solutions.

I think the other 2 gave you the rough idea of how to do it the way you want.
There is nothing wrong using those methods. They will work except when the navigation starts to get a little complex you will start using more pages and you might need to keep passing it down the tree.
So like easeccy mention look more into state management.
Things like Blocs, Redux are all very helpful.
Reason being just like how flutter builds things depending on setstate() the state management classes allows you to add the same event at different places as long as they are of the same instance. All the builders will rebuild based off the state they yield.
E.g. for Blocs if you were to add a play event to the bloc. no matter where you are as long as you are able to provide the bloc to the page you can add the event and anything that is on the screen (if you were to have multiple dart files building) will all be rebuilt depending on the state you will yield.
example of bloc
main.dart
void main() async{
runApp(
//Having this before return MaterialApp() ensures that you can call it
//anywhere in the app below this tree
BlocProvider<TheTypeOfBloc>(
create: (context) => TheTypeOfBloc(),
child: App(),
)
}
any other widgets/builds you have
#override
Widget build(BuildContext context) {
return BlocListener<TheTypeOfBloc,TheTypeOfState>(
listener : (context,state){
//tldr of listen = when your state change do something.
//so your void function can be call here
if(state is playState){
_play();
}
}
child:BlocBuilder<TheTypeOfBloc,TheTypeOfState> (
// basically anything below here gets rebuild when you change a state.
builder: (context,state) {
return //what you want to build here like listener based on the
//state or just build normally without the builder.
}
),
);
}

Answer 3.0
As per the full code you have shown, here is the solution as per your code only. I am sure it will clear out some confusions for you.
Passing the play() correctly to your MyHomePage from main.dart in your FloatingActionButton. I am not using full code of main.dart, but specifically your part, where you are moving to the MyHomePage
main.dart
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
// you need to pass two positional arguments
// since your MyHomePage accepts two arguments
// one is your title and one is your function
return MyHomePage(title: "My Title", play: play);
}),
);
}
Secondly, use your method to be passed in your MyHomePage constructor. This will remain as is. Just look at the last line of the code here, and see how are we using the passed play() method from your main.dart
class MyHomePage extends StatefulWidget {
// accepting the method in the constructor
// so you can pass it with the title from your main.dart
MyHomePage({Key key, this.title, this.play}) : super(key: key);
final String title;
final Function play; // this is the function
#override
_MyHomePageState createState() => _MyHomePageState();
}
Now how to use that in your Class
class _MyHomePageState extends State<MyHomePage> {
var _isRecording = false;
_startRecording() {
this.setState(() {
_isRecording = true;
});
}
_stopRecording() {
this.setState(() {
_isRecording = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.black,
iconSize: 70,
onPressed: () => _startRecording(),
),
IconButton(
icon: Icon(Icons.stop),
color: Colors.black,
iconSize: 70,
onPressed: () => _stopRecording(),
),
IconButton(
icon: Icon(Icons.play_arrow),
color: Colors.black,
onPressed: () => widget.play() // call like this
)
Note: Please look at the comments in my code as well
Now check if that works for you. This should probably fix your problem.

Related

Flutter State Management with Bloc/Cubit

for many of you this is an obvious / stupid question, but I've come to a point where I don't have a clue anymore. I have real difficulties understanding State Management with Bloc / Cubit.
Expectation: I have a page with a ListView (recipe_list) of all recipes and an 'add' button. Whenever I click on a ListItem or the 'add' button I go to the next page (recipe_detail). On this page I can create a new recipe (if clicked the 'add' button before), update or delete the existing recipe (if clicked on ListItem before). When I click the 'save' or 'delete' button the Navigator pops and I go back to the previous page (recipe_list). I used Cubit to manage the state of the recipe list. My expectation is that the ListView updates automatically after I clicked 'save' or 'delete'. But I have to refresh the App to display the changes.
main.dart
void main() {
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(
debugShowCheckedModeBanner: false,
title: 'Recipe Demo',
home: BlocProvider<RecipeCubit>(
create: (context) => RecipeCubit(RecipeRepository())..getAllRecipes(),
child: const RecipeList(),
)
);
}
}
recipe_list.dart
class RecipeList extends StatefulWidget {
const RecipeList({Key? key}) : super(key: key);
#override
_RecipeListState createState() => _RecipeListState();
}
class _RecipeListState extends State<RecipeList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 24.0
),
color: const Color(0xFFF6F6F6),
child: Stack(
children: [
Column(
children: [
Container(
margin: const EdgeInsets.only(
top: 32.0,
bottom: 32.0
),
child: const Center(
child: Text('Recipes'),
),
),
Expanded(
child: BlocBuilder<RecipeCubit, RecipeState>(
builder: (context, state) {
if (state is RecipeLoading) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (state is RecipeError) {
return const Center(
child: Icon(Icons.close),
);
} else if (state is RecipeLoaded) {
final recipes = state.recipes;
return ListView.builder(
itemCount: recipes.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return BlocProvider<RecipeCubit>(
create: (context) => RecipeCubit(RecipeRepository()),
child: RecipeDetail(recipe: recipes[index]),
);
}
));
},
child: RecipeCardWidget(
title: recipes[index].title,
description: recipes[index].description,
),
);
},
);
} else {
return const Text('Loading recipes error');
}
}
),
),
],
),
Positioned(
bottom: 24.0,
right: 0.0,
child: FloatingActionButton(
heroTag: 'addBtn',
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return BlocProvider<RecipeCubit>(
create: (context) => RecipeCubit(RecipeRepository()),
child: const RecipeDetail(recipe: null),
);
}
));
},
child: const Icon(Icons.add_rounded),
backgroundColor: Colors.teal,
),
)
],
),
),
),
);
}
}
recipe_detail.dart
class RecipeDetail extends StatefulWidget {
final Recipe? recipe;
const RecipeDetail({Key? key, required this.recipe}) : super(key: key);
#override
_RecipeDetailState createState() => _RecipeDetailState();
}
class _RecipeDetailState extends State<RecipeDetail> {
final RecipeRepository recipeRepository = RecipeRepository();
final int _recipeId = 0;
late String _recipeTitle = '';
late String _recipeDescription = '';
final recipeTitleController = TextEditingController();
final recipeDescriptionController = TextEditingController();
late FocusNode _titleFocus;
late FocusNode _descriptionFocus;
bool _buttonVisible = false;
#override
void initState() {
if (widget.recipe != null) {
_recipeTitle = widget.recipe!.title;
_recipeDescription = widget.recipe!.description;
_buttonVisible = true;
}
_titleFocus = FocusNode();
_descriptionFocus = FocusNode();
super.initState();
}
#override
void dispose() {
recipeTitleController.dispose();
recipeDescriptionController.dispose();
_titleFocus.dispose();
_descriptionFocus.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 24.0
),
color: const Color(0xFFF6F6F6),
child: Stack(
children: [
Column(
children: [
Align(
alignment: Alignment.topLeft,
child: InkWell(
child: IconButton(
highlightColor: Colors.transparent,
color: Colors.black54,
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.arrow_back_ios_new_rounded),
),
),
),
TextField(
focusNode: _titleFocus,
controller: recipeTitleController..text = _recipeTitle,
decoration: const InputDecoration(
hintText: 'Enter recipe title',
border: InputBorder.none
),
style: const TextStyle(
fontSize: 26.0,
fontWeight: FontWeight.bold
),
onSubmitted: (value) => _descriptionFocus.requestFocus(),
),
TextField(
focusNode: _descriptionFocus,
controller: recipeDescriptionController..text = _recipeDescription,
decoration: const InputDecoration(
hintText: 'Enter recipe description',
border: InputBorder.none
),
),
],
),
Positioned(
bottom: 24.0,
left: 0.0,
child: FloatingActionButton(
heroTag: 'saveBtn',
onPressed: () {
if (widget.recipe == null) {
Recipe _newRecipe = Recipe(
_recipeId,
recipeTitleController.text,
recipeDescriptionController.text
);
context.read<RecipeCubit>().createRecipe(_newRecipe);
//recipeRepository.createRecipe(_newRecipe);
Navigator.pop(context);
} else {
Recipe _newRecipe = Recipe(
widget.recipe!.id,
recipeTitleController.text,
recipeDescriptionController.text
);
context.read<RecipeCubit>().updateRecipe(_newRecipe);
//recipeRepository.updateRecipe(_newRecipe);
Navigator.pop(context);
}
},
child: const Icon(Icons.save_outlined),
backgroundColor: Colors.amberAccent,
),
),
Positioned(
bottom: 24.0,
right: 0.0,
child: Visibility(
visible: _buttonVisible,
child: FloatingActionButton(
heroTag: 'deleteBtn',
onPressed: () {
context.read<RecipeCubit>().deleteRecipe(widget.recipe!.id!);
//recipeRepository.deleteRecipe(widget.recipe!.id!);
Navigator.pop(context);
},
child: const Icon(Icons.delete_outline_rounded),
backgroundColor: Colors.redAccent,
),
),
),
],
),
),
),
);
}
}
recipe_state.dart
part of 'recipe_cubit.dart';
abstract class RecipeState extends Equatable {
const RecipeState();
}
class RecipeInitial extends RecipeState {
#override
List<Object> get props => [];
}
class RecipeLoading extends RecipeState {
#override
List<Object> get props => [];
}
class RecipeLoaded extends RecipeState {
final List<Recipe> recipes;
const RecipeLoaded(this.recipes);
#override
List<Object> get props => [recipes];
}
class RecipeError extends RecipeState {
final String message;
const RecipeError(this.message);
#override
List<Object> get props => [message];
}
recipe_cubit.dart
part 'recipe_state.dart';
class RecipeCubit extends Cubit<RecipeState> {
final RecipeRepository recipeRepository;
RecipeCubit(this.recipeRepository) : super(RecipeInitial()) {
getAllRecipes();
}
void getAllRecipes() async {
try {
emit(RecipeLoading());
final recipes = await recipeRepository.getAllRecipes();
emit(RecipeLoaded(recipes));
} catch (e) {
emit(const RecipeError('Error'));
}
}
void createRecipe(Recipe recipe) async {
await recipeRepository.createRecipe(recipe);
final newRecipes = await recipeRepository.getAllRecipes();
emit(RecipeLoaded(newRecipes));
}
void updateRecipe(Recipe recipe) async {
await recipeRepository.updateRecipe(recipe);
final newRecipes = await recipeRepository.getAllRecipes();
emit(RecipeLoaded(newRecipes));
}
void deleteRecipe(int id) async {
await recipeRepository.deleteRecipe(id);
final newRecipes = await recipeRepository.getAllRecipes();
emit(RecipeLoaded(newRecipes));
}
}
It looks like you're creating another BlocProvider when you're navigating to RecipeDetail page. When you're pushing new MaterialPageRoute, this new page gets additionally wrapped in new RecipeCubit. Then, when you're calling context.read<RecipeCubit>(), you're referencing that provider (as this is closest BlocProvider in the widget tree). Your RecipeList can't react to those changes because it's BlocBuilder is looking for a BlocProvider declared above it in the widget tree (the one in MyApp).
Besides that, newly created provider gets removed from the widget tree anyway when you're closing RecipeDetail page as it is declared in the MaterialPageRoute which has just been pushed off the screen.
Try to remove the additional BlocProvider (the one in RecipeList, in OnTap function of RecipeCardWidget):
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return BlocProvider<RecipeCubit>( // remove this BlocProvider
create: (context) => RecipeCubit(RecipeRepository()),
child: RecipeDetail(recipe: recipes[index]),
);
}
));
},

type 'String' is not a subtype of type 'Description'

Hello everyone i am new in flutter. I am trying to take data from API. When i try to take, i can get the body but i cannot get the datas from into it. I get an error like "I/flutter ( 8981): type 'String' is not a subtype of type 'Description'". Here is a screenshot for from my console when i run the code: Console output
and here is my code:
import 'dart:convert';
import 'dart:ffi';
import 'package:feedme_start/main.dart';
import 'package:feedme_start/model/AnaEkran_modeli.dart';
import 'package:feedme_start/model/branch_list.dart';
import 'package:feedme_start/model/restourantList.dart';
import 'package:feedme_start/widgets/Navigation_Drawer_Widget.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class restaurantPage extends StatefulWidget {
const restaurantPage({Key? key}) : super(key: key);
#override
_restaurantPageState createState() => _restaurantPageState();
}
final datas = [];
final datas_oneri = [];
class _restaurantPageState extends State<restaurantPage> {
int counter = 0;
var personalResult;
Future getapidata() async {
//orjinal api denemesi
String url =
"https://www.mobilonsoft.com/fpsapi/default.aspx?op=branch_list&firmuid=feedmekktc&device_id=web_20210813180900001&device_platform=4&lang=en";
try {
Response responsee = await get(Uri.parse(url)); //yanıtı alır
if (responsee.statusCode == 200) {
// yanıt onaylanırsa
Map sonuc = jsonDecode(responsee.body); //içeriği alır
print("apideki veriler ;");
print(sonuc);
**Branchlist liste = Branchlist.fromJson(sonuc);**
print(liste.result.branchList.toString());
} else {}
} catch (e) {
print(e.toString());
print("verileri çekerken hata oluştu");
}
}
#override
void initState() {
getapidata();
}
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
elevation: 0,
leading: IconButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => MyApp()));
},
icon: Icon(Icons.arrow_back)),
backgroundColor: Colors.red,
actions: <Widget>[
IconButton(
onPressed: () {
showSearch(context: context, delegate: dataSearch());
},
icon: Icon(Icons.search)),
],
),
backgroundColor: Colors.white,
body: Center(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.builder(
itemCount: counter,
itemBuilder: (context, index) {
return ListTile(
title: Text(personalResult.data[index].firstName +
" " +
personalResult.data[index].lastName),
subtitle: Text(personalResult.data[index].email),
leading: CircleAvatar(
backgroundImage:
NetworkImage(personalResult.data[index].avatar),
),
);
}),
),
),
),
);
}
}
class dataSearch extends SearchDelegate<String> {
#override
List<Widget> buildActions(BuildContext context) {
// actions for appbar
return [
IconButton(
onPressed: () {
query = "";
},
icon: Icon(Icons.clear))
];
}
#override
Widget buildLeading(BuildContext context) {
// leading icon on the left of the app bar
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
onPressed: () {
close(context, query);
},
);
}
#override
Widget buildResults(BuildContext context) {
// show some result based on the selection
return Container(
color: Colors.red,
child: Card(),
);
throw UnimplementedError();
}
#override
Widget buildSuggestions(BuildContext context) {
// show when someone searches for something
final datasOnerisi = query.isEmpty
? datas_oneri
: datas.where((p) => p.startsWith(query)).toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context);
},
leading: Icon(Icons.search),
title: RichText(
text: TextSpan(
text: datasOnerisi[index].substring(0, query.length),
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
children: [
TextSpan(
text: datasOnerisi[index].substring(query.length),
style: TextStyle(color: Colors.grey))
]),
),
),
itemCount: datasOnerisi.length,
);
throw UnimplementedError();
}
}
I have solved the issue by changing my Model class... There were some mistakes about that. A 'string' was saved as'description' thats why it was giving this error. So i changed it with string and it solved. It was an little easy but sneaky mistake

Flutter How to set Boolean from Settingpage

How to turn On/Off vibration on Homepage from Settings page with boolean SwitchListTile?
I want if the SwitchListTile in the Settings page is On, the Homepage will vibrate every time I tap it, and vice versa. basically I don't know how to control certain pages from other pages
this is MySettingPage
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class MySettingPage extends StatefulWidget {
const MySettingPage({Key key}) : super(key: key);
#override
_MySettingPageState createState() => _MySettingPageState();
}
class _MySettingPageState extends State<MySettingPage> {
bool isVibrate = false;
#override
void initState() {
super.initState();
getSwitchValues();
}
getSwitchValues() async {
isVibrate = await getSwitchState();
setState(() {});
}
Future<bool> saveSwitchState(bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("switchState", value);
return prefs.setBool("switchState", value);
}
Future<bool> getSwitchState() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isVibrate = prefs.getBool("switchState");
return isVibrate;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 0,
title: Text("Pengaturan"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.of(context).pop();
}),
),
body: Container(
padding: EdgeInsets.all(10),
child: ListView(
children: [
SwitchListTile(
title: Text("Getar"),
value: isVibrate,
onChanged: (bool value) async {
setState(() {
isVibrate = value;
saveSwitchState(value);
});
},
),
//
],
),
),
);
}
}
this is MyHomePage
import 'package:flutter/material.dart';
import 'package:vibration/vibration.dart';
import 'mysettingpage.dart';
class MyHomePage extends StatefulWidget {
final bool isVibrate;
MyHomePage({Key key, this.isVibrate}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
if (widget.isVibrate == true) {
Vibration.vibrate(duration: 70);
}
if (widget.isVibrate == false) {
Vibration.cancel();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My Homepage"),
titleSpacing: 0,
leading: IconButton(
icon: Icon(Icons.settings),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => MySettingPage(),
));
},
),
),
body: GestureDetector(
onTap: () {
_incrementCounter();
},
child: Container(
height: double.infinity,
width: double.infinity,
child: Padding(
padding: const EdgeInsets.only(bottom: 120),
child: Column(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: FittedBox(
child: Text(
'$_counter',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 200,
fontFamily: 'DS-Digital',
color: Color(0xFF24F3E2),
),
),
),
),
],
),
),
],
),
),
),
),
);
}
}
To continue on the response from Allan C with the changes to your code: (untested)
HomePage:
import 'package:flutter/material.dart';
import 'package:vibration/vibration.dart';
import 'mysettingpage.dart';
class MyHomePage extends StatefulWidget {
final bool isVibrate;
MyHomePage({Key key, this.isVibrate}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
bool _isVibrate;
#override
void initState() {
super.initState();
_isVibrate = widget.isVibrate;
}
void _onVibrateChange(bool value) {
setState(() {
_isVibrate = value;
})
}
void _incrementCounter() {
setState(() {
_counter++;
if (_isVibrate) {
Vibration.vibrate(duration: 70);
}
if (_isVibrate) {
Vibration.cancel();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My Homepage"),
titleSpacing: 0,
leading: IconButton(
icon: Icon(Icons.settings),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => MySettingPage(
onChange: _onVibrateChange
),
));
},
),
),
body: GestureDetector(
onTap: () {
_incrementCounter();
},
child: Container(
height: double.infinity,
width: double.infinity,
child: Padding(
padding: const EdgeInsets.only(bottom: 120),
child: Column(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: FittedBox(
child: Text(
'$_counter',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 200,
fontFamily: 'DS-Digital',
color: Color(0xFF24F3E2),
),
),
),
),
],
),
),
],
),
),
),
),
);
}
}
using the initState() you set a default value of _isVibrate from the passed value from the widget.isVibrate.
The method _onVibrateChange(bool value) (as a callback) will update the local variable within the state. This method needs to be passed to the MySettingsPage also.
MySettingsPage:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class MySettingPage extends StatefulWidget {
const MySettingPage({Key key, this.onChange}) : super(key: key);
final Function(bool value) onChange;
#override
_MySettingPageState createState() => _MySettingPageState();
}
class _MySettingPageState extends State<MySettingPage> {
bool isVibrate = false;
#override
void initState() {
super.initState();
getSwitchValues();
}
getSwitchValues() async {
isVibrate = await getSwitchState();
setState(() {});
}
Future<bool> saveSwitchState(bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("switchState", value);
widget.onChange(value);
return prefs.setBool("switchState", value);
}
Future<bool> getSwitchState() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isVibrate = prefs.getBool("switchState");
return isVibrate;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 0,
title: Text("Pengaturan"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.of(context).pop();
}),
),
body: Container(
padding: EdgeInsets.all(10),
child: ListView(
children: [
SwitchListTile(
title: Text("Getar"),
value: isVibrate,
onChanged: (bool value) async {
setState(() {
isVibrate = value;
saveSwitchState(value);
});
},
),
//
],
),
),
);
}
}
I have included a new variable passed to the Statefulwidget (Function(bool value) onChange), this will be the callback for when the switch changes it's value.
In the method Future saveSwitchState(bool value) async there is a call to the passed callback with the updated value from the SwitchListTiles onChange method.
Hope this clarifies what he meant in his answer.
One way to do this is to use a callback function.
So in MySettingPage(), add a constructor such as below:
MySettingPage({this.callback})
final void Function(bool) callback;
In MySettingPage, if you want to update the value of isVibrate in MyHomePage(), you can call widget.callback(true);
In MyHomePage, you can create a method to update the isVibrate variable.
void _updateIsVibrate(bool isVibrate){//...}
When you call MySettingsPage, you can pass in the method you created.
All my problems related to booleans above have been resolved by implementing MultiProvider. Thanks to the above masters who have helped me. have a nice day

How to show a text after onPressed function

I want to show a text after onPressed function happened, this function is a recording function and wants to show a text 'recording' when the function happening
voiceCreate.dart
import 'package:flutter/material.dart';
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
**main.dart**
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:permission_handler/permission_handler.dart';
import 'regitration.dart';
import 'voiceCreate.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String statusText = "";
bool isComplete = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Scaffold(
drawer: Drawer(
elevation: 2.0,
child: ListView(
children: <Widget>[
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return MyApp();
},
),
);
},
),
ListTile(
title: Text('Sign up'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
},
),
ListTile(
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
// add sign in page
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return VoiceCreate(onPressed: startRecord);
}),
);
},
// Add your onPressed code here!
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
backgroundColor: Colors.grey.shade900,
appBar: AppBar(
title: Text('Myvo'),
centerTitle: true,
backgroundColor: Colors.tealAccent.shade700,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 40,
onPressed: () async {
startRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.pause),
color: Colors.white,
iconSize: 40,
onPressed: () async {
pauseRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 40,
onPressed: () async {
stopRecord();
}),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
statusText,
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
play();
},
child: Container(
margin: EdgeInsets.only(top: 30),
alignment: AlignmentDirectional.center,
width: 100,
height: 50,
child: isComplete && recordFilePath != null
? Text(
"play",
style: TextStyle(color: Colors.red, fontSize: 20),
)
: Container(),
),
),
]),
),
),
);
}
Future<bool> checkPermission() async {
if (!await Permission.microphone.isGranted) {
PermissionStatus status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
return false;
}
}
return true;
}
void startRecord() async {
bool hasPermission = await checkPermission();
if (hasPermission) {
statusText = "Recording...";
recordFilePath = await getFilePath();
isComplete = false;
RecordMp3.instance.start(recordFilePath, (type) {
statusText = "Record error--->$type";
setState(() {});
});
} else {
statusText = "No microphone permission";
}
setState(() {});
}
void pauseRecord() {
if (RecordMp3.instance.status == RecordStatus.PAUSE) {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
} else {
bool s = RecordMp3.instance.pause();
if (s) {
statusText = "Recording pause...";
setState(() {});
}
}
}
void stopRecord() {
bool s = RecordMp3.instance.stop();
if (s) {
statusText = "Record complete";
isComplete = true;
setState(() {});
}
}
void resumeRecord() {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
}
String recordFilePath;
void play() {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
AudioPlayer audioPlayer = AudioPlayer();
audioPlayer.play(recordFilePath, isLocal: true);
}
}
int i = 0;
Future<String> getFilePath() async {
Directory storageDirectory = await getApplicationDocumentsDirectory();
String sdPath = storageDirectory.path + "/record";
var d = Directory(sdPath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
return sdPath + "/test_${i++}.mp3";
}
}
VoiceCreate function will happen on a new page when clicking on the Floating button in main.dart and recording will happen when click on mic Icon, want show the text 'recording' whine the fuction happening.
First of all, you need to have StatefulWidget to manage changes in state, then you can use two functions startRecording and stopRecording to toggle the isRecording variable. Then based on the value of isRecording you can make changes in the view, e.g., displaying a text. For displaying the text you can use a Visibility widget and set its visible parameter to isRecording.
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _isRecording = false;
_startRecording() {
this.setState(() {
_isRecording = true;
});
}
_stopRecording() {
this.setState(() {
_isRecording = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () => _startRecording(),
),
IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 70,
onPressed: () => _stopRecording(),
),
Visibility(
visible: _isRecording,
child: Text(
'recording',
style: TextStyle(
color: Colors.red
),
),
)
],
),
),
),
);
}
}
Maybe a snackbar could be useful here, something like:
class VoiceCreate extends StatefulWidget {
VoiceCreate({Key key, this.title}) : super(key: key);
final String title;
#override
_VoiceCreateState createState() => _VoiceCreateState();
}
class _VoiceCreateState extends State<VoiceCreate> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
var isRecording = false;
void showRecordingMessage(String message, [Color color = Colors.red]) {
_scaffoldKey.currentState.showSnackBar(
new SnackBar(backgroundColor: color, content: new Text(message)));
}
void setRecordingState() {
this.setState(() {
isRecording = true;
});
print("isRecording is set to $isRecording");
showRecordingMessage('Recording now!');
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.blueGrey,
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () {
setRecordingState();
},
),
],
),
),
);
}
}

How to call child method from parent for another widget

main.dart
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:permission_handler/permission_handler.dart';
import 'regitration.dart';
//import 'voiceCreate.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String statusText = "";
bool isComplete = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Scaffold(
drawer: Drawer(
elevation: 2.0,
child: ListView(
children: <Widget>[
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return MyApp();
},
),
);
},
),
ListTile(
title: Text('Sign up'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
},
),
ListTile(
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
// add sign in page
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
backgroundColor: Colors.grey.shade900,
appBar: AppBar(
title: Text('Myvo'),
centerTitle: true,
backgroundColor: Colors.tealAccent.shade700,
),
body: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 40,
onPressed: () async {
startRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.pause),
color: Colors.white,
iconSize: 40,
onPressed: () async {
pauseRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 40,
onPressed: () async {
stopRecord();
}),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
statusText,
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
play();
},
child: Container(
margin: EdgeInsets.only(top: 30),
alignment: AlignmentDirectional.center,
width: 100,
height: 50,
child: isComplete && recordFilePath != null
? Text(
"play",
style: TextStyle(color: Colors.red, fontSize: 20),
)
: Container(),
),
),
]),
),
),
);
}
Future<bool> checkPermission() async {
if (!await Permission.microphone.isGranted) {
PermissionStatus status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
return false;
}
}
return true;
}
void startRecord() async {
bool hasPermission = await checkPermission();
if (hasPermission) {
statusText = "Recording...";
recordFilePath = await getFilePath();
isComplete = false;
RecordMp3.instance.start(recordFilePath, (type) {
statusText = "Record error--->$type";
setState(() {});
});
} else {
statusText = "No microphone permission";
}
setState(() {});
}
void pauseRecord() {
if (RecordMp3.instance.status == RecordStatus.PAUSE) {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
} else {
bool s = RecordMp3.instance.pause();
if (s) {
statusText = "Recording pause...";
setState(() {});
}
}
}
void stopRecord() {
bool s = RecordMp3.instance.stop();
if (s) {
statusText = "Record complete";
isComplete = true;
setState(() {});
}
}
void resumeRecord() {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
}
String recordFilePath;
void play() {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
AudioPlayer audioPlayer = AudioPlayer();
audioPlayer.play(recordFilePath, isLocal: true);
}
}
int i = 0;
Future<String> getFilePath() async {
Directory storageDirectory = await getApplicationDocumentsDirectory();
String sdPath = storageDirectory.path + "/record";
var d = Directory(sdPath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
return sdPath + "/test_${i++}.mp3";
}
}
I want to call the VoiceCreate function when clicking on onPressed
voiceCreate.dart
import 'package:flutter/material.dart';
import 'main.dart';
class VoiceCreate extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () {}),
),
),
);
}
}
I want to call startRecord method from main.dart when clicking on onPressed
If you check the code of IconButton you'll see that onPressed is a VoidCallback, you can try to imitate the logic to do the same
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
And in main just call your widget VoiceCreate with an onPressed parameter
VoiceCreate(
onPressed: () => startRecord
)
edited code here. Still the startRecord() is not working. VoiceCreate() is working
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return VoiceCreate(onPressed: startRecord);
}),
);
},
// Add your onPressed code here!
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
You could do this by using shared view model across need widgets, like so:
I'd recommend to use this approach instead of callbacks and Stateful widgets
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Parent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetBuilder<CommonViewModel>(
init: CommonViewModel(),
builder: (model) {
return Scaffold(
body: Column(
children: [
RaisedButton(onPressed: () => model.parentMethod(0)),
RaisedButton(onPressed: () => model.childMethod('call from parent')),
],
),
);
},
);
}
}
class Child extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetBuilder<CommonViewModel>(
builder: (model) {
return Scaffold(
body: Column(
children: [
RaisedButton(onPressed: () => model.childMethod('call from child')),
RaisedButton(onPressed: () => model.parentMethod(100)),
],
),
);
},
);
}
}
class CommonViewModel extends GetxController {
void parentMethod(int argument) {
print('Parent method $argument');
}
void childMethod(String argument) {
print('Child method $argument');
}
}