How to call Future Function to another class in flutter? - function

I am new in flutter. I created Drawer and loaded its header data from server by creating a future function. I want to recall this future function again from another class, so how can i do that.
I also tried to call by creating its class object like -
Drawersetting object = new Drawersetting();
then - > object.function_name
But that function is not visible.
How to do that? Following whole class - >
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mera_interest_flutter/Activity/BottomNavBar.dart';
import 'package:mera_interest_flutter/Activity/Login.dart';
import 'package:mera_interest_flutter/Custom/CustomClass.dart';
import 'package:mera_interest_flutter/Fragments/AppHistoryTabScreen.dart';
import 'package:mera_interest_flutter/Fragments/NotificationFragment.dart';
import 'package:mera_interest_flutter/Fragments/PartnersScreen.dart';
import 'package:mera_interest_flutter/Network/BaseURLHeaders.dart';
import 'package:mera_interest_flutter/model/UserInfoDataModel.dart';
import 'package:mera_interest_flutter/model/UserInfoModel.dart';
import 'package:mera_interest_flutter/routes/Routes.dart';
import '../Fragments/DiscoverScreen.dart';
import 'package:flutter_session/flutter_session.dart';
import 'package:mera_interest_flutter/Activity/UserProfileScreen.dart';
import 'package:mera_interest_flutter/Fragments/AddManualFragment.dart';
import 'package:mera_interest_flutter/Fragments/ContactUsScreen.dart';
import 'package:mera_interest_flutter/Fragments/FAQFragment.dart';
import 'package:mera_interest_flutter/Fragments/MessageFragment.dart';
import '../Fragments/HomeFragment.dart';
import '../Fragments/ZeroBalancePortFolioScreen.dart';
import '../Fragments/SupportFragment.dart';
import 'package:flutter_session/flutter_session.dart';
import 'package:http/http.dart' as http;
//for setting title name of side bar items
class DrawerItem {
String title;
IconData icon;
DrawerItem(this.title, this.icon);
}
//for setting title name of bottom bar items
// class widgetBottomItems{
// String title;
// IconData icon;
// widgetBottomItems(this.title, this.icon);
// }
class DrawerSetting extends StatefulWidget {
final drawerItems = [
new DrawerItem("Portfolio", Icons.add),
new DrawerItem("Zero Balance Portfolio", Icons.alarm),
new DrawerItem("Message", Icons.message),
new DrawerItem("My Info & Setting", Icons.settings),
new DrawerItem("Support", Icons.help),
new DrawerItem("FAQ", Icons.book_outlined),
new DrawerItem("Contact Us", Icons.contact_phone_outlined),
new DrawerItem("Logout", Icons.logout)
];
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<DrawerSetting> {
String _title;
var session = FlutterSession();
#override
void initState() {
// TODO: implement initState
super.initState();
getUserData();
_title ="Discover";
}
void didUpdateWidget(covariant DrawerSetting oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
setState(() {
getUserData();
getNewProfile();
});
}
bool is_new_profile = false;
void getNewProfile()async{
is_new_profile = await session.get("is_new_profile");
print("sessionvalue = " + is_new_profile.toString());
if(is_new_profile == true){
setState(() {
getUserData();
});
}
}
final Color myColor = Color(0xFF15A2EB);
final Color myColorLightGray = Color(0xFF989E9E);
final Color text_Semi_Black_Color = Color(0xFF414B51);
final Color text_gray_color = Color(0xFF70787C);
UserInfoDataModel _userInfoDataModel;
String url = BaseURLHeaders().getBaseURl() + "";
Map headers = BaseURLHeaders().getHeader();
//bottom navigation
int _selectedIndex = 0;
var _screens = [
DiscoverScreen(),
HomeFragment(),
PartnersScreen(),
// HistoryScreen(),
AppHistoryTabScreen(),
NotificationFragment(),
];
static const TextStyle optionStyle = TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.red,
fontFamily: "verdana_regular",
);
//for bottom items
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
switch(index) {
case 0: { _title = 'Discover'; }
break;
case 1: { _title = 'Portfolio'; }
break;
case 2: { _title = 'Partners'; }
break;
case 3: { _title = 'History'; }
break;
}
});
}
int _selectedDrawerIndex = 0;
String currentProfilePic =
"https://service2home.in/wp-content/uploads/2021/01/rakesh.jpg";
_getDrawerItemWidget(int pos) {
switch (pos) {
case 0:
return new AddManualFdFragment();
break;
case 1:
return new ZeroBalancePortFolioScreen();
break;
case 2:
return MessageFragment();
break;
case 3:
return new UserProfileScreen("drawer");
break;
case 4:
return new SupportFragment();
break;
case 5:
return new FAQFragment();
break;
case 6:
return new ContactUsScreen();
break;
case 7:
SystemNavigator.pop();
//exit(0);
break;
}
}
//for drawer items
_onSelectItem(int index) {
setState(() => _selectedDrawerIndex = index);
Navigator.of(context).pop(); // close the drawer
}
#override
Widget build(BuildContext context) {
//set portrait by default
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
List<Widget> drawerOptions = [];
for (var i = 0; i < widget.drawerItems.length; i++) {
var d = widget.drawerItems[i];
drawerOptions.add(new ListTile(
leading: new Icon(
d.icon,
),
title: new Text(
d.title,
style: TextStyle(
fontSize: 16,
color: myColorLightGray,
fontFamily: "verdana_regular",
),
),
selected: i == _selectedDrawerIndex,
onTap: () => _onSelectItem(i),
));
}
//on backpress return to home screen , you can use it for drawer items
return WillPopScope(
onWillPop: () {
if (_selectedIndex != 0 || _selectedDrawerIndex != 0) {
setState(() {
_selectedIndex = 0;
});
// _getDrawerItemWidget(_selectedIndex);
} else {
Navigator.pop(context, true);
}
return;
},
child: Scaffold(
appBar: new AppBar(
title: Row(
children: [
Expanded(
child: new Text(
_title,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontFamily: "verdana_regular"),
),
),
Expanded(
flex: 0,
child: Container(
margin: EdgeInsets.only(left: 80),
// width: MediaQuery.of(context).size.width * 0.25,
child: IconButton(
alignment: Alignment.centerRight,
icon: Icon(Icons.notifications_none),
onPressed: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
NotificationFragment())),
}),
),
),
],
),
),
drawer: new Drawer(
child: SingleChildScrollView(
child: new Column(
children: [
//header
UserAccountsDrawerHeader(
currentAccountPicture: Container(
child: new GestureDetector(
child: new Container(
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: _userInfoDataModel != null
? new DecorationImage(
fit: BoxFit.cover,
image: new NetworkImage(
_userInfoDataModel
.profile_url)) :
new DecorationImage(
fit: BoxFit.cover,
image: new AssetImage("assets/images/user.png"),
),
)
),
onTap: () => {
Navigator.of(context).pop(),
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
UserProfileScreen("header")),
),
}),
),
accountName: _userInfoDataModel !=null ? new Text(
_userInfoDataModel.first_name + " " + _userInfoDataModel.last_name,
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontFamily: "verdana_regular",
),
) : null,
accountEmail: _userInfoDataModel !=null ? new Text(
_userInfoDataModel.email,
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontFamily: "verdana_regular",
),
) : null,
),
Column(children: [
ListTile(
leading: Icon(Icons.add),
title: Text(
'Add Manual FD',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
Navigator.of(context).pop();
// Navigator.pushReplacementNamed(context, Routes.addFd);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddManualFdFragment()));
}),
ListTile(
leading: Icon(Icons.alarm),
title: Text(
'Zero Balance Portfolio',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ZeroBalancePortFolioScreen()));
}),
ListTile(
leading: Icon(Icons.message),
title: Text(
'Message',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MessageFragment()));
}),
ListTile(
leading: Icon(Icons.settings),
title: Text(
'MY Info & Setting',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
UserProfileScreen("header")));
}),
ListTile(
leading: Icon(Icons.help),
title: Text(
'Support',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SupportFragment()));
}),
ListTile(
leading: Icon(Icons.bookmarks_outlined),
title: Text(
'FAQ',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FAQFragment()));
}),
ListTile(
leading: Icon(Icons.contact_phone_outlined),
title: Text(
'Contact Us',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ContactUsScreen()));
}),
ListTile(
leading: Icon(Icons.logout),
title: Text(
'Logout',
style: TextStyle(
color: myColorLightGray,
fontSize: 15,
fontFamily: "verdana_regular",
),
),
onTap: () {
goToLogin();
}),
])
],
),
),
),
body: _screens[_selectedIndex],
/*_getDrawerItemWidget(_selectedDrawerIndex),*/
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: myColor,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Discover',
),
BottomNavigationBarItem(
icon: ImageIcon(
AssetImage("assets/images/briefcase.png"),
// color: Colors.grey,
),
label: 'Portfolio',
),
BottomNavigationBarItem(
icon: ImageIcon(
AssetImage("assets/images/partner.png"),
// color: Colors.grey,
),
label: 'Partners',
),
BottomNavigationBarItem(
icon: Icon(Icons.history),
label: 'History',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.black,
unselectedItemColor: Colors.white,
onTap: _onItemTapped,
),
// bottomNavigationBar: BottomNavigationBar(),
),
);
}
//go to news detail page
void goToProfile_Screen(BuildContext ctx) {
Navigator.of(ctx).push(
MaterialPageRoute(
builder: (_) {
return UserProfileScreen("drawer");
},
),
);
}
//logout
Future<void> goToLogin() async {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (BuildContext context) => Login()));
await FlutterSession().set("isLogin", false);
await FlutterSession().set("user_id", "");
await FlutterSession().set("user_name", "");
await FlutterSession().set("email", "");
await FlutterSession().set("phone", "");
await FlutterSession().set("account_status", "");
await FlutterSession().set("isNewData", false);
}
//api get user info
Future<UserInfoModel> getUserData() async {
String user_id = "1";
var mapData = new Map<String, dynamic>();
mapData['user_id'] = user_id;
// mapData['first_name'] = firstName;
var response = await http.post(
url,
headers: headers,
body: mapData,
);
if (response.statusCode == 200) {
var res = json.decode(response.body);
UserInfoModel _userInfoModel = UserInfoModel.fromJson(res);
if (_userInfoModel.success == 1) {
var data = res["data"];
_userInfoDataModel = UserInfoDataModel.fromJson(data);
// Toast.show("User Data Fetched", context,
// duration: Toast.LENGTH_SHORT, gravity: Toast.TOP);
// CustomClass().makeToast("message", context);
setState(() {
print("responseBody: ${res}");
print("responseData: ${data}");
print("userInfoSuccess: ${_userInfoModel.success}");
print("dataVaalue: ${data["email"]}");
print("urlBelow: ${url}");
print("headersBelow: ${headers}");
});
}
}
}
}

A solution to your problem could be a static function inside a Drawer class. You could use this function in another file without initializing a new instance of a Drawer class by calling Drawer.function(). This function though can access only static variables of the parent class.
Also check this explanation: Class variables and methods - dart.dev
But:
Consider using top-level functions, instead of static methods, for common or widely used utilities and functionality.

You will need to create a function inside the calling class to call the Future function of another class. See the example below:
class ClassName {
Future<void> functionName {
something
}
}
class CallingClassName {
Final ClassName objName = ClassName();
void callingFunciton {
objName.functionName();
}
}

in main.dart write the future method globally (outside any widget or class):
Future<Database> initializeDatabase() async {
var databasesPath = await getDatabasesPath();
var path = join(databasesPath, "tafheemul_quran.db");
// Check if the database exists
var exists = await databaseExists(path);
if (!exists) {
// Should happen only the first time you launch your application
print("Creating new copy from asset");
// Make sure the parent directory exists
try {
await Directory(dirname(path)).create(recursive: true);
} catch (_) {}
// Copy from asset
ByteData data = await rootBundle.load(join("assets", "tafheemul_quran.db"));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
// Write and flush the bytes written
await File(path).writeAsBytes(bytes, flush: true);
} else {
print("Opening existing database");
}
// open the database
var bomDataTable = await openDatabase(path, readOnly: true);
return bomDataTable;
}
then in Another dart, import the main.dart :
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'main.dart';
then in that dart in any class, call the function :
class TokenExplActivity_Main extends State<TokenExplPassDataClass> {
//const TokenExplActivity_Main({Key? key}) : super(key: key);
String rowId = "";
String name = "";
String email = "";
String address = "";
Future<Database> get database async {
Database _database = await initializeDatabase();
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Actually the summary is, make the function globally and call the dart file in import first.

Related

flutter Exception caught by widgets library, IDE says getter was called on null even it isn't null

I am writing a mobile app in flutter, I get a json and I convert it into an object as in the following class:
class UserProfile {
String role;
List<Town> interestingTown;
String sId;
String uid;
Town myTown;
int iV;
UserProfile(
{this.role,
this.interestingTown,
this.sId,
this.uid,
this.myTown,
this.iV});
UserProfile.fromJson(Map<String, dynamic> json) {
role = json['role'];
if (json['interestingTown'] != null) {
interestingTown = new List<Town>();
json['interestingTown'].forEach((v) {
interestingTown.add(new Town.fromJson(v));
});
}
sId = json['_id'];
uid = json['uid'];
myTown = json['myTown'] != null
? new Town.fromJson(json['myTown'])
: null;
iV = json['__v'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['role'] = this.role;
if (this.interestingTown != null) {
data['interestingTown'] =
this.interestingTown.map((v) => v.toJson()).toList();
}
data['_id'] = this.sId;
data['uid'] = this.uid;
if (this.myTown != null) {
data['myTown'] = this.myTown.toJson();
}
data['__v'] = this.iV;
return data;
}
static Resource<myTown> get profile {
return Resource(
url: Constants.HEADLINE_GET_PROFILO,
parse: (response) {
UserProfile profile = UserProfile.fromJson(jsonDecode(response.body));
return profile;
});
}
}
class Town{
bool enabled;
List<String> categories;
String sId;
String nameTown;
int iV;
Town(
{this.enabled,
this.categories,
this.sId,
this.nameTown,
this.iV});
Town.fromJson(Map<String, dynamic> json) {
enabled = json['enabled'];
categories = json['categories'].cast<String>();
sId = json['_id'];
nameTown = json['nameTown'];
iV = json['__v']; }
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['enabled'] = this.enabled;
data['categories'] = this.categories;
data['_id'] = this.sId;
data['nameTown'] = this.nameTown;
data['__v'] = this.iV;
return data; }
}
After, when I run the class below to load a screen, I get this error (with the emulator screen red for almost 5 seconds):
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building MyAccountsPage(dirty, state: MyAccountsPageList#4dae7):
The getter 'myTown' was called on null.
Receiver: null
Tried calling: myTown
The relevant error-causing widget was:
MyAccountsPage file:///C:/Users/StudioProjects/my_project/lib/bloc.navigation_bloc/navigation_bloc.dart:36:15
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 MyAccountsPageList.build (package:civic_points/pages/myaccountspage.dart:145:35)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4612:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4495:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4667:11)
...
====================================================================================================
After the almost five seconds, the screen loads but it doesn't load right because the boolean variables are not set correctly.
But, the problem is that I can print the profile.myTown.nameTown, so myTown isn't null.
The same error happens if I try to print profile.interestingTown[0].nameTown.
Before, I have tried to set the variables using some if statements, but I had the same error and the screen stays red forever, without load after a few seconds.
I can't fix the error, so I post all the code of the classes, hoping someone could help me in solving the issue.
class MyAccountsPage extends StatefulWidget with NavigationStates {
#override
createState() => MyAccountsPageList();
}
class MyAccountsPageList extends State<MyAccountsPage> {
UserProfile profile;
bool boolinterestingTown = true;
bool boolmyTown = true;
int modify;
int myIndex;
bool add = false;
var deleteTown;
#override
void initState() {
super.initState();
_getProfile();
try {
print (profile.myTown.nameTown);
} catch (e) {
boolmyTown = false;
try {
print(profile.interestingTown[0].nameTown);
} catch (e) {
boolinterestingTown = false;
}
}
}
void _getProfile() {
WebserviceToken().load(UserProfile.profile).then((getProfile) => {
setState(() => {this.profile = getProfile}),
});
}
void deleteTownMe() async {
var headers = {'Content-Type': 'application/json',
'Authorization': 'Bearer ${token}'};
var request = http.Request(
'DELETE', Uri.parse('http:..........'));
request.body = '''{
"town": "${deleteTown}"
}''';
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 201) {
print(response.statusCode);
print(await response.stream.bytesToString());
} else {
print(response.reasonPhrase);
}
}
Widget _buildItemsForTownListView(BuildContext context, int index) {
final town = profile.interestingTown[index].nameTown;
return new Container(
child: Column(
children: <Widget>[
Text(
town,
style: TextStyle(
fontSize: 20,
color: Colors.blueGrey,
fontWeight: FontWeight.bold),
),
ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: RaisedButton(
child: Text("Modify"),
textColor: Colors.white,
color: Colors.blueGrey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
onPressed: () {
modify = 2;
myIndex = index;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => citySelection(
profileParameters:
new ProfileParameters(modify, myIndex, add, town),
)));
},
),
),
SizedBox(width: 10),
Flexible(
child: RaisedButton(
child: Text("Delete"),
textColor: Colors.white,
color: Colors.blueGrey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
onPressed: () {
deleteTown = town;
deleteTownMe();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => citySelection()));
},
),
),
],
),
),
SizedBox(height: 20),
],
),
);
}
#override
Widget build(BuildContext context) {
var myTown = profile.myTown.nameTown;
print(profile.myTown.nameTown);
return Scaffold(
appBar: AppBar(
titleSpacing: 50.0,
title: new Text("My profile"),
automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
child: Container(
margin: const EdgeInsets.fromLTRB(16, 16, 0, 0),
width: double.infinity,
color: Colors.white,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(height: 40),
CircleAvatar(
backgroundImage: NetworkImage(
imageUrl,
),
radius: 48,
backgroundColor: Colors.transparent,
),
SizedBox(height: 48),
Text(
'User',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
name,
style: TextStyle(
fontSize: 20,
color: Colors.blueGrey,
fontWeight: FontWeight.bold),
),
SizedBox(height: 20),
if (boolmyTown)
Text(
'My town',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
if (boolmyTown)
Text(
myTown,
style: TextStyle(
fontSize: 20,
color: Colors.blueGrey,
fontWeight: FontWeight.bold),
),
if (boolmyTown)
RaisedButton(
child: Text("Modify"),
textColor: Colors.white,
color: Colors.blueGrey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
onPressed: () {
modify = 1;
myIndex = 0;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => citySelection(
profileParameters:
new ProfileParameters(modify, myIndex, add, ''),
)));
},
),
if (boolinterestingTown && boolmyTown)
SizedBox(height: 20),
if (boolinterestingTown && boolmyTown)
Text(
'Interesting towns',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
if (boolinterestingTown && boolmyTown)
ListView.builder(
itemCount: profile.interestingTowns.length,
shrinkWrap: true,
itemBuilder: _buildItemsForTownListView,
),
if (boolmyTown && !boolinterestingTown)
SizedBox(height: 20),
if (boolmyTown)
RaisedButton(
child: Text("Add ineresting town"),
textColor: Colors.white,
color: Colors.blueGrey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
onPressed: () {
modify = 2;
myIndex = profile.interestingTown.length;
add = true;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => citySelection(
profileParameters:
new ProfileParameters(modify, myIndex, add, ''),
)));
},
),
if (!boolmyTown)
RaisedButton(
child: Text("Add your town"),
textColor: Colors.white,
color: Colors.blueGrey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
onPressed: () {
modify = 1;
myIndex = 0;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => citySelection(
profileParameters:
new ProfileParameters(modify, myIndex, add, ''),
)));
},
),
],
),
),
),
),
);
}
}
You need to confirm variable profile is null or not.
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_getProfile();
});
}
#override
Widget build(BuildContext context) {
var myTown = (profile == null) ? null : profile.myTown.nameTown;
return Scaffold(
appBar: AppBar(
titleSpacing: 50.0,
title: new Text("My profile"),
automaticallyImplyLeading: false,
),
body: (profile == null)
? Center(child: CircularProgressIndicator(),)
: SingleChildScrollView(child: Container(),),
);
}

I have a response of json body from a login API . I made a model class for that json. Now how to use it in my pages to fetch data?

I have logged in from a api . Then i got a response of json . I can fetch data from login to homepage . For that i created a constructor in homepage and pass it in Login page where i made navigator for the homepage . But i know it's not good practice to fetch data like it. using model class is more smart way. I added my code here of login, homepage and model . Now my data can only communicate between these two page . But i need to fetch data to another pages too.
login.dart
import 'package:api_login/model/response_model.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import '../sharePreference.dart';
import 'homepage.dart';
class Login extends StatefulWidget {
UserDetails userDetails = new UserDetails();
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
var notification ;
bool isprocesscomplete = false;
TextEditingController _userController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
final _scaffoldKey = GlobalKey<ScaffoldState>();
String BaseUrl = "my url";
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: SingleChildScrollView(
child: Center(
child: Container(
height: 770,
color: Colors. lightBlue,
padding: EdgeInsets.fromLTRB(20, 100, 20, 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Login",
style: TextStyle(fontSize: 32),
),
SizedBox(
height: 30,
),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
height: 220,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(30),
child: TextField(
controller: _userController,
decoration: InputDecoration(hintText: "Username"),
),
),
Padding(
padding: const EdgeInsets.all(30),
child: TextField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(hintText: "Password"),
),
),
],
),
),
),
SizedBox(
height: 60,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
color: Colors.blue,
onPressed: () {
if (_userController.text == "" ||
_passwordController.text == "") {
final snackBar = SnackBar(
content: Text("Enter Username and Password"));
_scaffoldKey.currentState.showSnackBar(snackBar);
} else {
signIn(_userController.text, _passwordController.text);
}
},
child: ProgressButton(),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(16),
),
),
),
SizedBox(
height: 20,
),
FlatButton(
child: Text("Forgot password"),
onPressed: () {},
),
],
),
),
),
),
);
}
Widget ProgressButton() {
if (isprocesscomplete != false) {
return CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white));
} else {
return new Text(
"Sign In",
style: const TextStyle(
color: Colors.white,
fontSize: 15.0,
),
);
}
}
void signIn(String username, String password) async {
setState(() {
isprocesscomplete = true;
});
var response = await http.post(BaseUrl,
headers: {"Content-Type": "application/json"},
body: json.encode({
"username": username,
"password": password,
}));
Map<String, dynamic> value = json.decode(response.body);
notification = value["notifications"];
// print('Response ${response.body}');
if (response.statusCode == 200) {
try {
///You don't need it but it will be cool for show progress dialgo for 4 second then redirect even if we get reslut
Future.delayed(Duration(seconds: 4), () {
// 5s over make it false
setState(() {
isprocesscomplete = true;
});
});
Map<String, dynamic> value = json.decode(response.body);
print('Response ${response.body}');
SharedPrefrence().setToken(value['api_token'].toString());
SharedPrefrence().setName(value['user_name']);
SharedPrefrence().setUserId(value['user_id'].toString());
///This is used when user loged in you can set this true,
///next time you open you need to check loginc in main.dart or splashscreen if this is true if it is true then
///redirect to home page it is false then redirect to Login page
///When you logout the app make sure you set this as false like "SharedPrefrence().setLoggedIn(false);"
SharedPrefrence().setLoggedIn(true);
///Redirect to Home page
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => HomePage(
user_name: value['user_name'],
api_token: value['api_token'],
notification: notification,
// payment: payment ,
)),
ModalRoute.withName("/login"));
} catch (e) {
e.toString();
final snackBar =
SnackBar(
content: Text("something wrong,Try again 😑"),
behavior: SnackBarBehavior.floating,
);
_scaffoldKey.currentState.showSnackBar(snackBar);
}
} else {
var message = value['error'];
final snackBar = SnackBar( backgroundColor: Colors.redAccent[700],
content: Text(message.toString()),
behavior: SnackBarBehavior.floating, );
_scaffoldKey.currentState.showSnackBar(snackBar);
}
}
}
homepage.dart
import 'package:api_login/model/response_model.dart';
import 'package:api_login/pages/details.dart';
import 'package:api_login/pages/settingPage.dart';
import 'package:api_login/widget/neumorphsm.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../sharePreference.dart';
import 'login.dart';
import 'login.dart';
class HomePage extends StatefulWidget {
final payment;
final count ;
String user_name;
final api_token;
final user_id ;
final payment_id;
final List<dynamic> notification ;
// List data ;
HomePage({ this.user_name, this.api_token , this.user_id, #required this.notification ,
this.count, this.payment, this.payment_id});
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String arrayLength ;
String nametoprint;
String tokentoprint;
#override
void initState() {
super.initState();
Future name = SharedPrefrence().getName();
name.then((data) async {
nametoprint = data;
print(nametoprint);
});
Future token= SharedPrefrence().getToken();
token.then((data) async {
tokentoprint= data;
print(tokentoprint);
});
}
int counter ;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Cash-Management"),
backgroundColor: Colors.blue,
actions: [
new Stack(
children: <Widget>[
new IconButton(icon: Icon(Icons.notifications), onPressed: () {
setState(() {
counter = 0;
});
}),
counter != 0 ? new Positioned(
right: 11,
top: 11,
child: new Container(
padding: EdgeInsets.all(2),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(6),
),
constraints: BoxConstraints(
minWidth: 14,
minHeight: 14,
),
child: Text(
" ${widget.notification.length} ",
style: TextStyle(
color: Colors.white,
fontSize: 8,
),
textAlign: TextAlign.center,
),
),
) : new Container()
],
),
IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Login()),
);
}),
],
),
body: ListView(
children: <Widget>[
Card(
color: Colors.lightBlue,
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new SettingPage()));
},
child: Container(
height: 120,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Profile",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Text(
"Name:${widget.user_name}",
// " ${widget.username} ",
style: TextStyle(fontSize: 16),
),
// Text(
// " ${widget.notification.length} ",),
// Text(" ${nametoprint} "),
],
),
),
),
),
Container(
color: Colors.lightBlue,
height: 400,
child: ListView.builder(
itemCount: widget.notification == null ? 0 : widget.notification.length,
itemBuilder: (context, index){
final count = widget.notification ;
print(count.length);
return Card(
color: Colors.blue,
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new DetailPage()));
},
child: Column(
children:<Widget>[
Text('Amount'),
ListTile(
title: Text(widget.notification[index] ["data"]["amount"].toString()),
subtitle: Text(widget.notification[index]["data"]["message"].toString()),
) ,
Text('Created at '),
ListTile(
title: Text(widget.notification[index] ["created_at"].toString()),
),
Text('updated at'),
ListTile(
title: Text(widget.notification[index] ["updated_at"].toString()),
),
],
),
),
);
}),
),
Container(
color: Colors.blue,
height: 130,
child: Button()
),
],
),
// floatingActionButton: FloatingActionButton(onPressed: () {
// print("Increment Counter");
// setState(() {
// counter++;
// });
// }, child: Icon(Icons.add),),
),
);
}
}
response_model.dart
class UserDetails {
int userId;
String userName;
String apiToken;
List<Notifications> notifications;
UserDetails({this.userId, this.userName, this.apiToken, this.notifications});
UserDetails.fromJson(Map<String, dynamic> json) {
userId = json['user_id'];
userName = json['user_name'];
apiToken = json['api_token'];
if (json['notifications'] != null) {
notifications = new List<Notifications>();
json['notifications'].forEach((v) {
notifications.add(new Notifications.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['user_id'] = this.userId;
data['user_name'] = this.userName;
data['api_token'] = this.apiToken;
if (this.notifications != null) {
data['notifications'] =
this.notifications.map((v) => v.toJson()).toList();
}
return data;
}
}
class Notifications {
String id;
String type;
int notifiableId;
String notifiableType;
Data data;
Null readAt;
String createdAt;
String updatedAt;
Notifications(
{this.id,
this.type,
this.notifiableId,
this.notifiableType,
this.data,
this.readAt,
this.createdAt,
this.updatedAt});
Notifications.fromJson(Map<String, dynamic> json) {
id = json['id'];
type = json['type'];
notifiableId = json['notifiable_id'];
notifiableType = json['notifiable_type'];
data = json['data'] != null ? new Data.fromJson(json['data']) : null;
readAt = json['read_at'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['type'] = this.type;
data['notifiable_id'] = this.notifiableId;
data['notifiable_type'] = this.notifiableType;
if (this.data != null) {
data['data'] = this.data.toJson();
}
data['read_at'] = this.readAt;
data['created_at'] = this.createdAt;
data['updated_at'] = this.updatedAt;
return data;
}
}
class Data {
int paymentId;
String generatePaymentId;
String message;
int amount;
Data({this.paymentId, this.generatePaymentId, this.message, this.amount});
Data.fromJson(Map<String, dynamic> json) {
paymentId = json['payment_id'];
generatePaymentId = json['generate_payment_id'];
message = json['message'];
amount = json['amount'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['payment_id'] = this.paymentId;
data['generate_payment_id'] = this.generatePaymentId;
data['message'] = this.message;
data['amount'] = this.amount;
return data;
}
}
It will be helpful if anyone let e know how to show detail page from this section.
ListView.builder(
itemCount: widget.notification == null ? 0 : widget.notification.length,
itemBuilder: (context, index){
final count = widget.notification ;
print(count.length);
return Card(
color: Colors.blue,
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new DetailPage()));
},
You can use widget.user_name, widget.api_token in HomePage, and pass it to Details Page.
Home Page
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new DetailPage(userName :widget.user_name, apiToken: widget.api_token)));
If you want the data to be used globally in your application, perhaps you can fetch your data from API before MaterialApp() so that your data can be used globally.
Other way is you can pass your UserDetails() data to next page by calling them inside your Navigator.push(). You can read more detail example here

Access function from another class

Hello guys I'm trying to access function from another class becuse this function establish call and navigat to call page so for sure there will be setState function to update the UI but here is the problem whene the UI got updated from another class the app will go out of the widget tree so i have to use callBack function which is i dont know how pleass help
this is the perant class:
import 'dart:async';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:flutter_social_messenger/src/modules/auth/domain/entities/user.dart';
import 'package:flutter_social_messenger/src/modules/auth/export.dart';
import 'package:flutter_social_messenger/src/modules/notifications/domain/entities/call_msg.dart';
import 'package:flutter_social_messenger/src/modules/notifications/domain/entities/notification.dart';
import 'package:flutter_social_messenger/src/modules/notifications/domain/repository/repo.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../export.dart';
import './call.dart';
class IndexPage extends StatefulWidget {
String userId;
IndexPage(String this.userId);
#override
State<StatefulWidget> createState() => IndexState();
}
class IndexState extends State<IndexPage> {
/// create a channelController to retrieve text value
final _channelController = TextEditingController();
/// if channel textField is validated to have error
bool _validateError = false;
ClientRole _role = ClientRole.Broadcaster;
User currentUser = Modular.get<AuthController>().currentUser;
#override
void dispose() {
// dispose input controller
_channelController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
print("target : " + widget.userId.toString() ) ;
return Scaffold(
appBar: AppBar(
title: Text('Make a Call'),
),
body: Center(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
height: 400,
child: Column(
children: <Widget>[
/*
Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _channelController..text = 'call-' + currentUser.id + "-" + widget.userId ,
decoration: InputDecoration(
errorText:
_validateError ? 'Channel name is mandatory' : null,
border: UnderlineInputBorder(
borderSide: BorderSide(width: 1),
),
hintText: 'call-' + widget.userId + "-" + currentUser.id ,
),
))
],
),
Column(
children: [
ListTile(
title: Text(ClientRole.Broadcaster.toString()),
leading: Radio(
value: ClientRole.Broadcaster,
groupValue: _role,
onChanged: (ClientRole value) {
setState(() {
_role = value;
});
},
),
),
ListTile(
title: Text(ClientRole.Audience.toString()),
leading: Radio(
value: ClientRole.Audience,
groupValue: _role,
onChanged: (ClientRole value) {
setState(() {
_role = value;
});
},
),
)
],
),
*/
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child:
Row( children: <Widget>[
// Expanded(child: Text('call-' + currentUser.id + "-" + widget.userId ) ),
Expanded( child:
RawMaterialButton(
onPressed: () => onJoin(widget.userId,context,currentUser.id) ,
child: Icon(
Icons.call_end,
color: Colors.white,
size: 35.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Colors.green,
padding: const EdgeInsets.all(15.0),
)
// RaisedButton(
// onPressed: onJoin,
// child: Text('Dial'),
// color: Colors.blueAccent,
// textColor: Colors.white,
// ),
) ], ),
)
],
),
),
),
);
}
DateTime get now => DateTime.now().toUtc();
Future<void> sendFollowNotification() {
String sendToId = widget.userId;
final followerId = currentUser.id;
print("trying to send call notification Id : " + "call-$followerId-$sendToId") ;
final not = CallNotification(
id: "call-$followerId-$sendToId",
sendTo: followerId,
senderId: sendToId,
senderName: currentUser.name,
time: now,
);
return repository.sendNotificaion(not);
}
Future<void> sendCallAlert() async {
String sendToId = widget.userId;
final followerId = currentUser.id;
print("trying to send call notification Id : " + "call-$followerId-$sendToId") ;
final not = CallNotification(
id: "call-$followerId-$sendToId",
sendTo: followerId,
senderId: sendToId,
senderName: currentUser.name,
time: now,
);
await Modular.get<NotificationsHelper>()
.registerNotification(followerId, true);
_callDocument("call-$followerId-$sendToId").setData(not.toJson());
// return _callCollection.document(currentUser.id).setData(not.toJson()) ;
// return repository.sendNotificaion(not);
}
final repository = Modular.get<NotificationReposity>();
final appStore = Modular.get<AppStore>();
final _firestore = Firestore.instance;
DocumentReference _callDocument(String callId) =>
_callCollection.document(callId);
CollectionReference get _callCollection => _firestore.collection("calls");
Future<void> onJoin(String userId,BuildContext context,final _followerId) async {
// print("qqqq") ;
String sendToId = userId;
final followerId = _followerId;
// print(userId+" i'm");
// print(_followerId+" his");
_channelController.text = "call-$followerId-$sendToId" ;
print("diallllll : " + _channelController.text ) ;
// /*
// update input validation
setState(() {
_channelController.text.isEmpty
? _validateError = true
: _validateError = false;
});
sendFollowNotification();
sendCallAlert();
if (_channelController.text.isNotEmpty) {
print('hiiiiissss');
// await for camera and mic permissions before pushing video page
await _handleCameraAndMic();
// push video page with given channel name
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CallPage(
channelName: _channelController.text,
role: _role,
),
),
);
}
// */
}
Future<void> _handleCameraAndMic() async {
// if (kIsWeb || !Platform.isAndroid) return true;
if (!await Permission.camera.isGranted && !await Permission.microphone.isGranted) {
var rr = ((await Permission.camera.request()).isGranted && (await Permission.microphone.request()).isGranted) ;
print("rr : " + rr.toString()) ;
}
}
// Future<bool> checkStoragePermission() async {
// if (kIsWeb || !Platform.isAndroid) return true;
// if (!await Permission.storage.isGranted) {
// return (await Permission.storage.request()).isGranted;
// }
// return true;
// }
}
and this is the child:
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:styled_widget/styled_widget.dart';
import '../../../../../chat/presentation/calling/index.dart';
import '../../../../../chat/presentation/calling/index.dart';
import '../../../../../chat/presentation/calling/index.dart';
import '../../../../../chat/presentation/calling/index.dart';
import '../../../../../chat/presentation/calling/index.dart';
import '../../../../export.dart';
import '../controller.dart';
import '../../widgets/profile_avatar.dart';
import 'package:flutter_social_messenger/src/modules/chat/presentation/calling/index.dart';
import 'package:flutter_social_messenger/src/modules/chat/presentation/calling/call.dart';
class OProfileHeader extends StatelessWidget implements PreferredSizeWidget {
final OtherUserProfileController controller;
OProfileHeader({Key key, #required this.controller}) : super(key: key);
User get user => controller.otherUser;
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
print("OProfileHeader : " + controller.isFollowing.toString() ) ;
return Stack(
children: <Widget>[
Positioned(
bottom: 200,
left: 0,
right: 0,
child: SizedBox(height: 200)
.decorated(gradient: AppTheme.primaryGradient),
),
Positioned(
bottom: 150,
left: 1,
right: 1,
child: Center(
child: Material(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 5.0,
color: theme.scaffoldBackgroundColor,
child: Column(
children: <Widget>[
Observer(
builder: (_) => Text(
user.name ?? "",
style: GoogleFonts.basic().copyWith(fontSize: 28),
maxLines: 1,
),
).padding(top: 40),
Text(user.status ?? "").padding(bottom: 10),
],
),
).width(MediaQuery.of(context).size.width * 4 / 5),
),
),
Positioned(
left: 0,
right: 0,
bottom: 300,
child: AppBar(
backgroundColor: Colors.transparent,
iconTheme: IconThemeData(),
elevation: 0,
),
),
Positioned(
left: 0,
right: 0,
bottom: 210,
child: Center(
child: Material(
elevation: 5.0,
shape: CircleBorder(),
child: Observer(
builder: (_) => ProfileAvatarWidget(
photoUrl: user.photoUrl,
// isLoading: state is LoadingProfilePic,
),
),
),
),
),
Positioned(
right: 200,
left: 0,
bottom: 60,
child: Center(
child: Observer(
builder: (_) {
controller.currentUser.following;
return RaisedButton(
color: controller.isFollowing
? Colors.black
: theme.primaryColor,
onPressed: () => controller.followUser(user.id),
child: Text(
controller.isFollowing ? "UnFollow" : "Follow",
style: GoogleFonts.alike().copyWith(
fontSize: 16,
color: Colors.white,
),
textAlign: TextAlign.center,
).width(70),
);
},
),
),
),
Positioned(
right: 0,
left: 200,
bottom: 60,
child: Center(
child: Observer(
builder: (_) {
controller.currentUser.following;
return RaisedButton(
color: Colors.green,
onPressed: ()=> {
IndexState().onJoin(user.id,context,controller.currentUser.id),
print(controller.currentUser.id+" "+controller.currentUser.phoneNumber),
print(user.id+" "+user.phoneNumber)
},
child: Text(
"Call",
style: GoogleFonts.alike().copyWith(
fontSize: 16,
color: Colors.white,
),
textAlign: TextAlign.center,
).width(70),
);
},
),
),
),
],
).height(500).backgroundColor(theme.scaffoldBackgroundColor);
}
#override
Size get preferredSize => Size.fromHeight(400);
//----------------------------------------------------
// */
}
I dont understand exactly what you want, but if its how to call a method from a parent widget, if would be something like this:
class ParentWidget extends StatelessWidget{
#override
Widget build(BuildContext context) {
return ChildWidget(onAction: (resultValue){
//Do something with the value
});
}
}
class ChildWidget extends StatelessWidget{
final Function onAction;
ChildWidget({Key key, #required this.onAction}) : super(key: key);
#override
Widget build(BuildContext context) {
return Inkwell(
onTap: (){
onAction(someValue);
}
child: AnyOtherWidget
);
}
}

Exception has occurred. _TypeError (type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>')

I have problem with getruangfasiliti method. Is there any way to fix this error? I have been working this for weeks.
Tried this but it is not what i want. I want to get the every data of the object
Future<List> getruangfasiliti() async {
final response = await http.get(BaseUrl.lihatruangfasiliti(widget.barcode));
return jsonDecode(response.body);
}
So, below is my code and how i can fix the error. I do not know where my wrong is
modelAduan.dart
class Aduan {
final String aduan_id;
final String tarikhaduan;
final String ruang_id;
final String fasiliti_id;
final String maklumat;
final String gambaraduan;
final String status;
final String idpengguna;
final String namaruang;
final String namafasiliti;
Aduan({
this.aduan_id,
this.tarikhaduan,
this.ruang_id,
this.fasiliti_id,
this.maklumat,
this.gambaraduan,
this.status,
this.idpengguna,
this.namaruang,
this.namafasiliti
});
factory Aduan.fromJson(Map<String, dynamic> json) {
return Aduan(
aduan_id: json['aduan_id'],
tarikhaduan: json['tarikhaduan'],
ruang_id: json['ruang_id'],
fasiliti_id: json['fasiliti_id'],
maklumat: json['maklumat'],
gambaraduan: json['gambaraduan'],
status: json['status'],
idpengguna: json['idpengguna'],
namaruang: json['namaruang'],
namafasiliti: json['namafasiliti'],
);
}
}
aduan.dart
import 'dart:convert';
import 'package:eaduanfsktm/api.dart';
import 'package:eaduanfsktm/sejarahaduan.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:eaduanfsktm/model/modelRuangFasiliti.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'dart:math' as Math;
import 'package:image/image.dart' as Img;
import 'package:path_provider/path_provider.dart';
import 'dart:async';
import 'package:async/async.dart';
import 'package:path/path.dart';
class BorangAduan extends StatefulWidget {
final String idpengguna, barcode;
BorangAduan(this.idpengguna, this.barcode);
#override
_BorangAduanState createState() => _BorangAduanState();
}
class _BorangAduanState extends State<BorangAduan> {
final _key = new GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
RuangFasiliti ruangfasiliti;
TextEditingController controllerruang_id;
TextEditingController controllerfasiliti_id;
TextEditingController controller_namaruang;
TextEditingController controller_namafasiliti;
TextEditingController controllermaklumat = new TextEditingController();
File _image;
Future<RuangFasiliti> getruangfasiliti() async {
final response = await http.get(BaseUrl.lihatruangfasiliti(widget.barcode));
if (response.statusCode == 200) {
setState(() {
ruangfasiliti = RuangFasiliti.fromJson(jsonDecode(response.body));
});
setState(() {
controllerruang_id =
new TextEditingController(text: "${ruangfasiliti.ruang_id}");
controllerfasiliti_id =
new TextEditingController(text: "${ruangfasiliti.fasiliti_id}");
controller_namaruang =
new TextEditingController(text: " ${ruangfasiliti.namaruang}");
controller_namafasiliti =
new TextEditingController(text: " ${ruangfasiliti.namafasiliti}");
});
return ruangfasiliti;
}
}
// #override
// void dispose() {
// controllerruang_id.dispose();
// controllerfasiliti_id.dispose();
// controller_namaruang.dispose();
// controllerruang_id.dispose();
// controller_namafasiliti.dispose();
// super.dispose();
// }
#override
void initState() {
getruangfasiliti();
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text("Borang Aduan"),
),
body: ListView(
padding: EdgeInsets.all(2.0),
children: <Widget>[
FutureBuilder<RuangFasiliti>(
future: getruangfasiliti(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return aduanbox();
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Center(child: CircularProgressIndicator());
},
),
SizedBox(height: 10.0),
],
),
),
);
}
Widget aduanbox() {
return Center(
child: Form(
key: _key,
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
new Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
child: new TextFormField(
controller: controllerfasiliti_id,
readOnly: true,
decoration: InputDecoration(
labelText: "KOD FASILITI",
),
),
),
flex: 2,
),
SizedBox(width: 10.0),
Expanded(
child: Container(
child: new TextFormField(
controller: controller_namafasiliti,
readOnly: true,
decoration: InputDecoration(
labelText: "NAMA FASILITI",
),
),
),
flex: 2,
),
],
),
new Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
child: new TextFormField(
controller: controllerruang_id,
readOnly: true,
decoration: InputDecoration(
labelText: "KOD LOKASI",
),
),
),
flex: 2,
),
SizedBox(width: 10.0),
Expanded(
child: Container(
child: new TextFormField(
controller: controller_namaruang,
readOnly: true,
decoration: InputDecoration(
labelText: "LOKASI",
),
),
),
flex: 2,
),
],
),
TextFormField(
controller: controllermaklumat,
validator: (value) {
if (value.isEmpty) {
return 'Masukkan Maklumat Kerosakan';
}
return null;
},
decoration: InputDecoration(
labelText: "MAKLUMAT",
hintText: "Masukkan maklumat kerosakan"),
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
RaisedButton(
child: Icon(Icons.image),
onPressed: getImageGallery,
),
SizedBox(width: 5.0),
RaisedButton(
child: Icon(Icons.camera_alt),
onPressed: getImageCamera,
),
],
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
child: _image == null
? new Text("Tiada imej !")
: new Image.file(_image),
),
SizedBox(height: 10.0),
Container(
height: 45.0,
child: GestureDetector(
onTap: () {
if (_key.currentState.validate()) {
tambahaduan(_image);
}
},
child: Material(
borderRadius: BorderRadius.circular(10.0),
color: Colors.blueAccent,
elevation: 7.0,
child: Center(
child: Text(
'HANTAR',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat'),
),
),
),
),
),
],
),
),
),
),
);
}
Future getImageGallery() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
int rand = new Math.Random().nextInt(100000);
Img.Image image = Img.decodeImage(imageFile.readAsBytesSync());
Img.Image smallerImg = Img.copyResize(image, width: 500);
var compressImg = new File("$path/image_$rand.jpg")
..writeAsBytesSync(Img.encodeJpg(smallerImg, quality: 85));
setState(() {
_image = compressImg;
});
}
Future getImageCamera() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.camera);
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
int rand = new Math.Random().nextInt(100000);
Img.Image image = Img.decodeImage(imageFile.readAsBytesSync());
Img.Image smallerImg = Img.copyResize(image, width: 500);
var compressImg = new File("$path/image_$rand.jpg")
..writeAsBytesSync(Img.encodeJpg(smallerImg, quality: 85));
setState(() {
_image = compressImg;
});
}
Future tambahaduan(File _image) async {
var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
var length = await _image.length();
var uri = Uri.parse((BaseUrl.tambahaduan()));
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile("aduanimages", stream, length,
filename: basename(_image.path));
request.fields['fasiliti_id'] = controllerfasiliti_id.text;
request.fields['ruang_id'] = controllerruang_id.text;
request.fields['maklumat'] = controllermaklumat.text;
request.fields['idpengguna'] = widget.idpengguna;
request.files.add(multipartFile);
var response = await request.send();
if (response.statusCode == 200) {
print("Image Uploaded");
setState(
() {
Fluttertoast.showToast(
msg: "Aduan Berjaya",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.black,
textColor: Colors.white,
fontSize: 18.0,
);
Navigator.of(this.context).push(CupertinoPageRoute(
builder: (BuildContext context) => SejarahAduan()));
},
);
} else {
print("Upload Failed");
}
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
}
this is my error
List<RuangFasiliti> ruangfasiliti;
Future<RuangFasiliti> getruangfasiliti() async {
final response = await http.get(BaseUrl.lihatruangfasiliti(widget.barcode));
if (response.statusCode == 200) {
var body = jsonDecode(response.body);
setState(() {
if(body is List) //check if it's a List
ruangfasiliti = List<RuangFasiliti>.from(body.map(map) => RuangFasiliti.fromJson(map));
if(body is Map) //check if it's a Map
ruangfasiliti = [RuangFasiliti.fromJson(body)];
controllerruang_id =
new TextEditingController(text: "${ruangfasiliti.ruang_id}");
controllerfasiliti_id =
new TextEditingController(text: "${ruangfasiliti.fasiliti_id}");
controller_namaruang =
new TextEditingController(text: " ${ruangfasiliti.namaruang}");
controller_namafasiliti =
new TextEditingController(text: " ${ruangfasiliti.namafasiliti}");
});
return ruangfasiliti;
}
}
This code allows you to save a List ruangfasiliti, checks if the decoded json is a map or a list and saves it accordingly, but as the other comments said, you should provide and check the form of your JSON file to avoid this types of problems. If your JSON always returns a list it will be easy to just create a List body variable without checking the type of object

Ontap is not working on Google Maps marker in flutter

I am working on a project, i am using google_maps_flutter to show maps and markers on the screen & search_map_place to search places on the map, i have provided the source code below, there is a bug in the source code, whole project is control through bottom navigation, when first time i run the app, i navigate to the map screen, it displays markers from database and onTap also works perfectly, but when i navigate to any other screen and navigate back to map screen again, onTap doesn't work on the markers.
displaying markers on the map:
_onMapCreated() async {
// print(customerInfo);
for (var item in ud.customerInfo) {
if (item['customer_latitude'] == "" && item['customer_longitude'] == "") {
continue;
} else {
final MarkerId markerId = MarkerId((markers.length + 1).toString());
LatLng markerPos = LatLng(double.parse(item['customer_latitude']),
double.parse(item['customer_longitude']));
final Marker marker = Marker(
infoWindow: InfoWindow(
title: item['customer_name'],
snippet: item['customer_desc'],
),
// onTap: () => _onMarkerTapped(markerId),
icon: BitmapDescriptor.defaultMarkerWithHue(
item['customer_status'] == 'red'
? BitmapDescriptor.hueRed
: item['customer_status'] == 'yellow'
? BitmapDescriptor.hueYellow
: BitmapDescriptor.hueGreen),
markerId: markerId,
consumeTapEvents: true,
position: markerPos,
onTap: () {
Navigator.push(
context,
MaterialPageRoute<Null>(
builder: (BuildContext context) {
return CustomerDetail(
item['customer_id'],
item['customer_name'],
item['customer_email'],
item['customer_desc'],
item['customer_phone'],
item['customer_status']);
},
fullscreenDialog: true,
));
});
_markers = null;
markers[markerId] = marker;
}
}
setState(() {});
}
complete code:
String _mapStyle;
GoogleMapController controller;
List<Map> customerInfo;
class MapS extends StatefulWidget {
#override
_MapSState createState() => _MapSState();
}
class _MapSState extends State<MapS> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Search Map Place Demo',
home: MainScreen(),
);
}
}
MapType _mapType = MapType.normal;
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
class MapSample extends StatefulWidget {
#override
State<MapSample> createState() => MapSampleState();
}
class MapSampleState extends State<MapSample> {
#override
void initState() {
super.initState();
getCustomerInfo();
rootBundle.loadString('assets/map_style.txt').then((string) {
_mapStyle = string;
});
getCurrentLocation();
setCustomMapPin();
// _onMapCreated(controller);
setState(() {
_onMapCreated();
});
}
Future getCustomerInfo() async {
// getting customer info using saleManagerID
var customerInfoUrl = "http://.../calender/getCustomerInfo.php";
customerInfoResponse = await http.post(customerInfoUrl, body: {
"sm_id": sm.sm_id,
});
if (jsonDecode(customerInfoResponse.body) == "No Customers") {
String noCustomers = jsonDecode(customerInfoResponse.body);
ud.customerInfo = [];
} else {
ud.customerInfo = jsonDecode(customerInfoResponse.body);
print('user data got!');
}
// print(ud.customerInfo);
}
Widget _mapTypeSwitcher() => Align(
alignment: const Alignment(0.95, -0.7),
child: FloatingActionButton(
mini: true,
heroTag: null,
tooltip: 'Map Type',
child: const Icon(Icons.layers),
onPressed: () {
final MapType nextType =
MapType.values[_mapType.index == 2 ? 1 : 2];
setState(() {
print(nextType.toString());
_mapType = nextType;
});
},
),
);
_onMapCreated() async {
// print(customerInfo);
for (var item in ud.customerInfo) {
if (item['customer_latitude'] == "" && item['customer_longitude'] == "") {
continue;
} else {
final MarkerId markerId = MarkerId((markers.length + 1).toString());
LatLng markerPos = LatLng(double.parse(item['customer_latitude']),
double.parse(item['customer_longitude']));
final Marker marker = Marker(
infoWindow: InfoWindow(
title: item['customer_name'],
snippet: item['customer_desc'],
),
// onTap: () => _onMarkerTapped(markerId),
icon: BitmapDescriptor.defaultMarkerWithHue(
item['customer_status'] == 'red'
? BitmapDescriptor.hueRed
: item['customer_status'] == 'yellow'
? BitmapDescriptor.hueYellow
: BitmapDescriptor.hueGreen),
markerId: markerId,
consumeTapEvents: true,
position: markerPos,
onTap: () {
Navigator.push(
context,
MaterialPageRoute<Null>(
builder: (BuildContext context) {
return CustomerDetail(
item['customer_id'],
item['customer_name'],
item['customer_email'],
item['customer_desc'],
item['customer_phone'],
item['customer_status']);
},
fullscreenDialog: true,
));
});
_markers = null;
markers[markerId] = marker;
}
}
setState(() {});
}
void getCurrentLocation() async {
Position res = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
setState(() {
position = res;
// _child = mapWidget();
print(res);
mapToggle = true;
});
}
Completer<GoogleMapController> mapController = Completer();
Set<Marker> _markers = Set();
// custom marker
BitmapDescriptor pinLocationIcon;
void setCustomMapPin() async {
pinLocationIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 4.5), 'assets/red_marker.png');
}
IconData fontAwesomeIconFromString(String name) {
switch (name) {
case 'website':
return Icons.web;
case 'phone_no':
return Icons.phone_android;
case 'desc':
return Icons.lock_outline;
case 'place':
return Icons.place;
case 'city':
return Icons.location_city;
case 'country':
return Icons.my_location;
}
}
String iconfromApi;
// textfield in bottomsheet
Widget _entryField(String title, TextEditingController tcont, String ic) {
iconfromApi = ic;
return Container(
margin: EdgeInsets.symmetric(vertical: 5),
padding: new EdgeInsets.fromLTRB(2.0, 2.0, 2.0, 2.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: tcont,
// obscureText: isPassword,
style: TextStyle(color: Colors.black, fontFamily: 'Montserrat'),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: title,
prefixIcon: Icon(fontAwesomeIconFromString(iconfromApi)),
labelStyle: TextStyle(fontSize: 15)),
)
],
),
);
}
Future addData(String phone, web) async {
var url = "http://.../addData.php";
var response = await http.post(url, body: {
"name": userD.name,
"desc": userD.desc,
"status": userD.status,
"latitude": userD.latitide,
"longitude": userD.longitude,
"phone": phone != null ? phone : "n/a",
"web": web != null ? web : "n/a",
"sm_id": sm.sm_id
});
// print('Response status: ${response.statusCode}');
// print('Response body: ${response.body}');
response.body == '1' ? confirmDialog(context) : errorDialog(context);
}
Future<void> confirmDialog(BuildContext context) {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Response'),
content: const Text('Record Added!'),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => MainScreen()),
(Route<dynamic> route) => false);
},
),
],
);
},
);
}
Future<void> errorDialog(BuildContext context) {
return showDialog<void>(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Response'),
content: const Text('Record submission failed'),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => MainScreen()),
(Route<dynamic> route) => false);
},
),
],
);
},
);
}
Widget _submitButton() {
return InkWell(
onTap: () {
print(ud.phone);
print(ud.web);
addData(ud.phone, ud.web);
},
child: Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.symmetric(vertical: 15),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5)),
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Hexcolor("#2a7837"), Hexcolor("#2a7837")])),
child: Text(
'Save In Database',
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat'),
),
),
);
}
Widget addButon = Container();
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
return Stack(
children: <Widget>[
GoogleMap(
myLocationEnabled: true,
myLocationButtonEnabled: true,
compassEnabled: false,
tiltGesturesEnabled: false,
mapType: _mapType,
initialCameraPosition: CameraPosition(
target: LatLng(position.latitude, position.longitude),
zoom: 15),
onMapCreated: (controller) {
mapController.complete(controller);
_onMapCreated();
// add things here on map, markers, design etc
controller.setMapStyle(_mapStyle);
},
markers:
_markers == null ? Set<Marker>.of(markers.values) : _markers
// markers: Set<Marker>.of(markers.values),
),
_mapTypeSwitcher(),
Positioned(
top: 60,
left: MediaQuery.of(context).size.width * 0.05,
// width: MediaQuery.of(context).size.width * 0.9,
child: SearchMapPlaceWidget(
apiKey: apiKEY,
location: CameraPosition(
target: LatLng(position.latitude, position.longitude),
zoom: 18)
.target,
radius: 30000,
onSelected: (place) async {
// declaring some variables
final geolocation = await place.geolocation;
// final js = geolocation.fullJSON;
controller = await mapController.future;
// get latLong in a
var latLong = geolocation.coordinates;
// to save latLong in array for db
var latLongList = new List(2);
// to save place, city & country in array for db
var loctionList = new List();
controller.animateCamera(
CameraUpdate.newLatLng(geolocation.coordinates));
controller.animateCamera(
CameraUpdate.newLatLngBounds(geolocation.bounds, 0));
print(place.fullJSON);
// converting LatLong to string and then array
latLong = latLong.toString().replaceAll(RegExp("[a-zA-Z]"), '');
latLong =
latLong.toString().replaceAll(RegExp("[\\[\\](){}]"), '');
ud.customerDetials = place.fullJSON['place_id'];
latLongList = latLong.split(', ');
print(latLongList[0]);
print(latLongList[1]);
// print(prettyJson(place.fullJSON, indent: 2));
// print(a.runtimeType);
// adding retrived values to object
userD.name = place.fullJSON['structured_formatting']['main_text'];
// place.fullJSON['structured_formatting']['secondary_text'] == null
// ? userD.desc = c_desc.text
// : userD.desc =
// place.fullJSON['structured_formatting']['secondary_text'];
// c_phone_no.text = c_place.text =
// c_city.text = c_country.text = c_desc.text = '';
// userD.place = c_place.text;
// userD.city = c_city.text;
// userD.country = c_country.text;
userD.phone = ud.phone;
userD.web = ud.web;
userD.latitide = latLongList[0];
userD.longitude = latLongList[1];
userD.status = "red";
setState(() {
markers = <MarkerId, Marker>{};
_markers = new Set();
_markers.add(
Marker(
markerId: MarkerId(place.fullJSON['place_id']),
position: geolocation.coordinates,
icon: pinLocationIcon,
infoWindow: InfoWindow(
title: place.fullJSON['structured_formatting']
['main_text'],
snippet: place.fullJSON['structured_formatting']
['secondary_text'])),
);
// markers = null;
});
// print(js);
// savejson(js);
addButon = new RawMaterialButton(
onPressed: () async {
var responseDetails =
await getLocationDetails(place.fullJSON['place_id']);
ud.phone =
responseDetails.data["result"]["formatted_phone_number"];
ud.web = responseDetails.data["result"]["website"];
showStopper(
context: context,
stops: [0.5 * height, height],
builder:
(context, scrollController, scrollPhysics, stop) {
return Padding(
padding: const EdgeInsets.all(18.0),
child: ListView(
controller: scrollController,
physics: scrollPhysics,
children: [
// show location name
Text(
userD.name,
style: TextStyle(
color: Colors.black,
fontSize: 30,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat'),
),
SizedBox(
height: 50,
),
// location desc
Text(
'Description:',
style: TextStyle(
color: Colors.black,
fontSize: 20,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat'),
),
SizedBox(
height: 10,
),
userD.desc == null
? _entryField("Description", c_desc, 'desc')
: Text(
userD.desc,
style: TextStyle(
color: Colors.black,
fontSize: 15,
fontFamily: 'Montserrat'),
),
SizedBox(
height: 20,
),
// add website, phone, place, city, country
Text(
ud.phone != null ? ud.phone : "phone: n/a"),
Text(ud.web != null ? ud.web : "website: n/a"),
// _userInfoWidget(),
// _entryField("Website", c_websitee, 'website'),
SizedBox(
height: 20,
),
_submitButton()
]),
);
});
},
child: new Icon(
Icons.add_location,
color: Hexcolor('#2a7837'),
size: 35.0,
),
shape: new CircleBorder(),
elevation: 2.0,
fillColor: Colors.white,
padding: const EdgeInsets.all(15.0),
);
},
),
),
// 2 floating buttons
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
addButon,
new RawMaterialButton(
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute<Null>(
// builder: (BuildContext context) {
// return MyApp();
// },
// fullscreenDialog: true,
// ));
_markers = null;
_onMapCreated();
},
child: new Icon(
Icons.person,
color: Hexcolor('#2a7837'),
size: 35.0,
),
shape: new CircleBorder(),
elevation: 2.0,
fillColor: Colors.white,
padding: const EdgeInsets.all(15.0),
),
// feedback button
new RawMaterialButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<Null>(
builder: (BuildContext context) {
return FeedBackModal();
},
fullscreenDialog: true,
));
},
child: new Icon(
Icons.feedback,
color: Hexcolor('#2a7837'),
size: 35.0,
),
shape: new CircleBorder(),
elevation: 2.0,
fillColor: Colors.white,
padding: const EdgeInsets.all(15.0),
),
],
)
],
),
)
],
);
}
Future getLocationDetails(placeId) async {
try {
String requestUrl =
"https://maps.googleapis.com/maps/api/place/details/json?place_id=$placeId&fields=website,formatted_phone_number&key=$apiKEY";
Response placeDetails = await Dio().get(requestUrl);
return placeDetails;
} catch (e) {
print(e);
}
// ud.phone= placeDetails.data["result"]["formatted_phone_number"];
// ud.web= placeDetails.data["result"]["web"];
}
}
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
// bottom navigation variables
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
List<Widget> _widgetOptions = <Widget>[
Kpi(),
Customers(),
MapSample(),
AddMeeting(),
Customers(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
fd.indexForFeedback = _selectedIndex;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOptions.elementAt(fd.indexForFeedback),
),
bottomNavigationBar: BottomNavigationBar(
unselectedItemColor: Colors.white,
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.black,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.insert_chart),
title: Text('KPI'),
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('Customers'),
),
BottomNavigationBarItem(
icon: Icon(Icons.add_location),
title: Text('Map'),
),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today),
title: Text('Calender'),
),
BottomNavigationBarItem(
icon: Icon(Icons.group_add),
title: Text('Quotes'),
),
],
currentIndex: fd.indexForFeedback,
selectedItemColor: Hexcolor('#2a7837'),
onTap: _onItemTapped,
),
);
}
}
Replace
child: _widgetOptions.elementAt(fd.indexForFeedback),
With
child: IndexedStack(
children: _widgetOptions,
index: fd.indexForFeedback,
),
It prevents from redrawing the map every time you switch between tabs, and avoid memory leaks.
See also: https://www.youtube.com/watch?v=_O0PPD1Xfbk