How to Pause and Resume the qr_code_scanner using the NavigationBar - flutter

I have a NavigationBar with 3 Destinations and I want to pause or resume the qr_code_scanner depending on what destination is focused, to do this i use a if to evaluate the index and pause or resume the scanner, but i dont now how pass the controller between classes.
My NavigationBar
bottomNavigationBar: NavigationBar(
elevation: 2,
labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
selectedIndex: index,
onDestinationSelected: (index) {
setState(() => this.index = index);
if (index == 1) {
widget.controller!.resumeCamera();
} else {
widget.controller!.pauseCamera();
}
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.store_outlined),
selectedIcon: Icon(Icons.store),
label: 'Tienda',
),
NavigationDestination(
icon: Icon(Icons.qr_code_scanner_outlined),
selectedIcon: Icon(Icons.qr_code_scanner),
label: 'Escaner',
),
NavigationDestination(
icon: Icon(Icons.shopping_cart_outlined),
selectedIcon: Icon(Icons.shopping_cart),
label: 'Carrito',
),
],
),
The Home class
class Home extends StatefulWidget {
final QRViewController? controller;
const Home({Key? key, this.controller}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
My QrScan Class
class QRScanner extends StatefulWidget {
const QRScanner({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => QRScannerState();
}
class QRScannerState extends State<QRScanner> {
Barcode? result;
QRViewController? controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller!.pauseCamera();
}
controller!.resumeCamera();
}
#override
Widget build(BuildContext context) {
void home() {
Home(
controller: controller,
);
}
home();
return Scaffold(
body: Column(
children: <Widget>[
Expanded(child: buildQrView(context)),
Align(
alignment: Alignment.bottomCenter,
child: Container(
alignment: Alignment.center,
height: 100,
color: Colors.black,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.toggleFlash();
setState(() {});
},
child: FutureBuilder(
future: controller?.getFlashStatus(),
builder: (context, snapshot) {
if (snapshot.data == true) {
return const Icon(Icons.flash_on);
} else {
return const Icon(Icons.flash_off);
}
// Text('Flash: ${snapshot.data}');
},
)),
),
const Padding(padding: EdgeInsets.fromLTRB(37, 0, 0, 0)),
if (result != null)
Text('ID:${result!.code}')
else
const Text('Escanee el QR del producto'),
],
),
),
)
],
),
);
}
Widget buildQrView(BuildContext context) {
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery.of(context).size.width < 400 ||
MediaQuery.of(context).size.height < 400)
? 150.0
: 300.0;
// To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller
return QRView(
key: qrKey,
onQRViewCreated: onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.white,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
onPermissionSet: (ctrl, p) => onPermissionSet(context, ctrl, p),
);
}
void onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) {
setState(() {
result = scanData;
});
controller.pauseCamera();
Stream<List<Products>> readProducts() => FirebaseFirestore.instance
.collection('products')
.where('id', isEqualTo: '${result!.code}')
.snapshots()
.map((snapshot) => snapshot.docs
.map((doc) => Products.fromJson(doc.data()))
.toList());
Future<bool> onWillPop() async {
return false;
}
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) => WillPopScope(
onWillPop: () async => false,
child: WillPopScope(
onWillPop: onWillPop,
child: Dialog(
insetPadding: const EdgeInsets.all(8),
child: StreamBuilder<List<Products>>(
stream: readProducts(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Algo ha ocurrido! ${snapshot.error}');
} else if (snapshot.hasData) {
final products = snapshot.data!;
return Container(
margin: const EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: products
.map((p) => BuildProducts(
products: p, controller: controller))
.toList()),
);
} else {
return const Center(child: CircularProgressIndicator());
}
}),
),
),
),
);
});
}
void onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
}

Related

Error: Could not find the correct Provider<RecipeProvider> above this AddRecipe Widget

`I want to access the provider in the AddRecipe page in order to save a new recipe and notify the listeners, in my case the list.builder in UserRecipes to rebuild.
Sorry for the big amount of code, I added everything that I thought may be useful. I just can't figure it out, have been trying for hours.
This is the error that I get:
ProviderNotFoundException (Error: Could not find the correct Provider<RecipeProvider> above this AddRecipe Widget
These are the files:
Wrapper.dart:
class Wrapper extends StatelessWidget {
const Wrapper({super.key});
#override
Widget build(BuildContext context) {
final user = Provider.of<User?>(context);
if (user == null) {
return const AuthPage();
} else {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => RecipeProvider(uid: user.uid))
],
child: const HomePage()
);
}
}
}
Home.dart:
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final AuthService _auth = AuthService();
// The 4 main application screens
static const List<Destination> allDestinations = <Destination>[
Destination(0, 'Home', Icons.home, Colors.teal),
Destination(1, 'Meals', Icons.dinner_dining, Colors.orange),
Destination(2, 'Recipes', Icons.restaurant_menu_sharp, Colors.amber),
Destination(3, 'Profile', Icons.person, Colors.blue),
];
int currentPageIndex = 0;
final screens = [
Center(child: Text('Home'),),
Center(child: Text('Meals'),),
RecipesPage(),
Center(child: Text('My profile'),),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(title: allDestinations[currentPageIndex].title, backButton: false, signOutButton: true),
bottomNavigationBar: NavigationBar(
onDestinationSelected: (int index) {
setState(() {
currentPageIndex = index;
});
},
selectedIndex: currentPageIndex,
destinations: allDestinations.map((Destination destination) {
return NavigationDestination(
icon: Icon(destination.icon, color: destination.color),
label: destination.title
);
}).toList(),
),
body: screens[currentPageIndex]
);
}
}
class Destination {
const Destination(this.index, this.title, this.icon, this.color);
final int index;
final String title;
final IconData icon;
final MaterialColor color;
}
Recipes.dart:
const List<Widget> recipes = <Widget>[
Text('My recipes'),
Text('Other recipes')
];
class RecipesPage extends StatefulWidget {
const RecipesPage({super.key});
#override
State<RecipesPage> createState() => _RecipesPageState();
}
class _RecipesPageState extends State<RecipesPage> {
final List<bool> _selectedRecipes = <bool>[true, false];
final _searchContoller = TextEditingController();
#override
void dispose() {
_searchContoller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var provider = context.watch<RecipeProvider>();
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: 20),
ToggleButtons(
direction: Axis.horizontal,
onPressed: (int index) {
setState(() {
for (int i = 0; i < _selectedRecipes.length; i++) {
_selectedRecipes[i] = i == index;
}
});
},
borderRadius: const BorderRadius.all(Radius.circular(12)),
selectedBorderColor: Colors.blue[700],
selectedColor: Colors.white,
fillColor: Colors.blue[200],
color: Colors.blue[400],
constraints: const BoxConstraints(
minHeight: 40.0,
minWidth: 165.0,
),
isSelected: _selectedRecipes,
children: recipes
),
SizedBox(height: 10),
// Search textfield
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: TextField(
controller: _searchContoller,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(12),
),
hintText: 'Search',
fillColor: Colors.grey[250],
filled: true
),
),
),
SizedBox(height: 20),
Expanded(
child: _getRecipePage(),
),
],
)
),
),
floatingActionButton: Consumer<RecipeProvider>(
builder: (context, value, child) {
return _getFAB();
},
)
);
}
Widget _getFAB() {
if (_selectedRecipes[1]) {
return Container();
} else {
return FloatingActionButton(
child: Icon(Icons.add, size: 35),
onPressed: () => {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => AddRecipe()
)
),
},
);
}
}
Widget _getRecipePage() {
if (_selectedRecipes[0]) {
return UserRecipesWidget(search: _searchContoller.text.trim());
} else {
return OtherRecipesWidget();
}
}
}
User_recipes.dart:
class UserRecipesWidget extends StatefulWidget {
UserRecipesWidget({super.key, required this.search});
String search;
#override
State<UserRecipesWidget> createState() => _UserRecipesWidgetState();
}
class _UserRecipesWidgetState extends State<UserRecipesWidget> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
var provider = context.watch<RecipeProvider>();
return FutureBuilder(
future: provider.getUserRecipesFuture,
builder: (BuildContext ctx, AsyncSnapshot asyncSnapshot) {
if (asyncSnapshot.connectionState == ConnectionState.done) {
if (asyncSnapshot.hasError) {
return const Center(child: Text('Could not retreive recipes!'));
}
return ListView.builder(
itemCount: provider.recipes.length,
itemBuilder: (BuildContext ctx, int index) {
return GestureDetector(
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => RecipePage(recipe: provider.recipes[index])
)
),
},
child: RecipeCard(recipe: provider.recipes[index]),
);
}
);
} else {
return Center(child: CircularProgressIndicator());
}
}
);
}
}
RecipeProvider:
class RecipeProvider extends ChangeNotifier {
late RecipeService _recipeService;
List<RecipeModel> recipes = [];
late Future getUserRecipesFuture;
final String uid;
RecipeProvider({ required this.uid }) {
_recipeService = RecipeService(uid: uid);
getUserRecipesFuture = _getUserRecipesFuture();
}
Future _getUserRecipesFuture() async {
recipes = await _recipeService.getUserRecipes();
addDummyRecipe();
}
addDummyRecipe() {
recipes.add(RecipeModel(uid: "test", userId: "test", recipeName: "Pork"));
recipes.add(RecipeModel(uid: "test1", userId: "test1", recipeName: "Pizza"));
recipes.add(RecipeModel(uid: "test2", userId: "test2", recipeName: "Burger"));
notifyListeners();
}
}
And the main one that gives the error, add_recipe.dart:
class AddRecipe extends StatefulWidget {
const AddRecipe({super.key});
#override
State<AddRecipe> createState() => _AddRecipeState();
}
class _AddRecipeState extends State<AddRecipe> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(title: 'Add recipe', backButton: true),
body: SafeArea(
child: Center(
child: Column(
children: [
Text('Add recipe'),
SizedBox(height: 50),
// Add recipe button
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: GestureDetector(
onTap: () async {
context.read<RecipeProvider>().addDummyRecipe();
},
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: Text(
'Save recipe',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
),
),
]
)
)
),
);
}
}
`
the exception happens because you provided the RecipeProvider only for the HomePage(). means when you push a new route, it doesn't have that the RecipeProvider instance.
if you can't provide the RecipeProvider Golobally because it needs the uid, then you must provide it each time you push a new route
change your RecipePage Navigator to this
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider.value(
value: context.read<RecipeProvider>(),
child: RecipePage(recipe: provider.recipes[index]),
),
),
),
and your AddRecipe
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider.value(
value: context.read<RecipeProvider>(),
child: AddRecipe(),
),
),
),

login page in bottomNavigationBar with flutter bloc

need help.. I am new flutter bloc. I am trying implement login page in bottom navigation bar with bloc but not success. the navbar is:
beranda
pelatihan
pengetahuan
bantuan
profil (in profil if AuthenticationStatus.authenticated route to home page, if AuthenticationStatus.unauthenticated route to login page).
following code navigation cubit from https://medium.com/#antoniodominikovic/implementing-in-app-navigation-with-the-flutter-bottom-navigation-bar-using-the-bloc-architecture-84cda9c74dda and login bloc from https://bloclibrary.dev/#/flutterlogintutorial.
main class
void main() {
BlocOverrides.runZoned(
() async{
// Use blocs...
WidgetsFlutterBinding.ensureInitialized();
final userRepository = UserRepository();
userRepository.user?.id;
runApp(App(
authenticationRepository: AuthenticationRepository(),
userRepository: UserRepository(), connectivity: Connectivity(),
));
},
blocObserver: AppBlocObserver(),
);
}
app class:
class App extends StatelessWidget {
const App({
Key? key,
required this.authenticationRepository,
required this.userRepository,
required this.connectivity,
}) : super(key: key);
final AuthenticationRepository authenticationRepository;
final UserRepository userRepository;
final Connectivity connectivity;
#override
Widget build(BuildContext context) {
return RepositoryProvider.value(
value: authenticationRepository,
child: MultiBlocProvider(
providers: [
BlocProvider<NavigationCubit>(
create: (context) => NavigationCubit(),
),
BlocProvider<InternetCubit>(
create: (context) => InternetCubit(connectivity: connectivity)),
BlocProvider<AuthenticationBloc>(
create: (context) => AuthenticationBloc(
authenticationRepository: authenticationRepository,
userRepository: userRepository,
),
)
],
child: AppView(),
),
);
}
}
appview class:
class AppView extends StatefulWidget {
#override
_AppViewState createState() => _AppViewState();
}
class _AppViewState extends State<AppView> {
final _navigatorKey = GlobalKey<NavigatorState>();
NavigatorState get _navigator => _navigatorKey.currentState!;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
bottomNavigationBar: BlocBuilder<NavigationCubit, NavigationInitial>(
builder: (context, state) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 20,
color: Colors.black.withOpacity(.1),
)
],
),
child: SafeArea(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 15.0, vertical: 8),
child: GNav(
rippleColor: Colors.grey[300]!,
hoverColor: Colors.grey[100]!,
gap: 8,
activeColor: Colors.black,
iconSize: 24,
padding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 12),
duration: const Duration(milliseconds: 400),
tabBackgroundColor: Colors.grey[100]!,
color: Colors.black,
tabs: const [
GButton(
icon: LineIcons.home,
text: 'Home',
),
GButton(
icon: LineIcons.book,
text: 'Pelatihan',
),
GButton(
icon: LineIcons.search,
text: 'Pengetahuan',
),
GButton(
icon: LineIcons.facebookMessenger,
text: 'Bantuan',
),
GButton(
icon: LineIcons.user,
text: 'Profil',
),
],
selectedIndex: state.index,
onTabChange: (index) {
setState(() {
if (index == 0) {
BlocProvider.of<NavigationCubit>(context)
.getNavBarItem(NavbarItem.beranda);
} else if (index == 1) {
BlocProvider.of<NavigationCubit>(context)
.getNavBarItem(NavbarItem.pelatihan);
} else if (index == 2) {
BlocProvider.of<NavigationCubit>(context)
.getNavBarItem(NavbarItem.pengetahuan);
} else if (index == 3) {
BlocProvider.of<NavigationCubit>(context)
.getNavBarItem(NavbarItem.bantuan);
} else if (index == 4) {
BlocProvider.of<NavigationCubit>(context)
.getNavBarItem(NavbarItem.profil);
}
});
},
),
),
),
);
},
),
body: BlocBuilder<NavigationCubit, NavigationInitial>(
builder: (context, statenav) {
if (statenav.navbarItem == NavbarItem.beranda) {
return const BerandaPage();
} else if (statenav.navbarItem == NavbarItem.pelatihan) {
return const PelatihanPage();
} else if (statenav.navbarItem == NavbarItem.pengetahuan) {
return const PengetahuanPage();
} else if (statenav.navbarItem == NavbarItem.bantuan) {
return const BantuanPage();
} else if (statenav.navbarItem == NavbarItem.profil) {
// return LoginPage();
return MaterialApp(
navigatorKey: _navigatorKey,
builder: (context, child) {
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
switch (state.status) {
case AuthenticationStatus.authenticated:
_navigator.pushAndRemoveUntil<void>(
HomePage.route(),
(route) => false,
);
statenav.navbarItem == NavbarItem.profil;
break;
case AuthenticationStatus.unauthenticated:
_navigator.pushAndRemoveUntil<void>(
LoginPage.route(),
(route) => false,
);
statenav.navbarItem == NavbarItem.profil;
break;
default:
break;
}
},
child: child,
);
},
onGenerateRoute: (_) => SplashPage.route(),
);
}
return Container();
}),
),
);
}
}
there is no error code, when the first time I select the profile tab, the login page appears. But when I select another tab and go back to the profile tab, CircularProgressIndicator from the splash page is appear. please tell me and teach me or any references?, thanks

How to refresh data after returning to a screen in flutter

I have the following cart screen which contains the address fields. When a user wants to update their address, they click on Update button, which takes them to the address screen where they can update the address. Although when the back button is clicked to return back to the cart screen,the print function shows the updated value but the UI still shows the old value.
class CartScreen extends StatefulWidget {
static const routeName = '/cart';
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen> {
Future _addressFuture;
String value = 'deliver';
var address;
void initState() {
_addressFuture = _obtainAddressFuture();
super.initState();
}
Future _obtainAddressFuture() async {
address = await Provider.of<Addresses>(context, listen: false).fetchMyAddress();
}
void didChangeDependencies() async {
print('inside didchange');
super.didChangeDependencies();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
print('Rebuild cart');
return GestureDetector(
child: Scaffold(
appBar: AppBar(
title: Text('Your Cart'),
),
body: FutureBuilder(
future: _addressFuture,
builder: (ctx, dataSnapshot) {
if (dataSnapshot.error != null) {
print('Data snapshot error is ' +
dataSnapshot.error.toString());
return Center(
child: Text('Something went wrong!'),
);
} else if (dataSnapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: Loading(),
);
} else {
return Container(
child: SingleChildScrollView(
child: Column(
children: [
Card(
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 4,
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
new GestureDetector(
onTap: () async{
_awaitReturnValueFromSecondScreen(context);
},
child: Container(
padding: EdgeInsets.all(10),
child: const Text("Update",
style: TextStyle(
color: Colors.blue))),
)
],
),
TextFormField(
initialValue: address.name,
readOnly: true,
decoration: InputDecoration(
border: InputBorder.none,
prefixIcon: Icon(Icons.person,
color: Colors.orangeAccent),
labelText: 'Contact name'),
),
],
)),
],
)));
}
})));
}
void _awaitReturnValueFromSecondScreen(BuildContext context) async {
// start the SecondScreen and wait for it to finish with a result
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddressScreen('cartScreen'),
));
setState(() {
address = result;
});
print(address.name);
}
}
please check the below example as it requires async and await to get the data from 2nd screen
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Location',
theme: ThemeData(
primarySwatch: Colors.amber,
),
home: Provider(
create: (context) => Addresses(),
child: CartScreen(),
),
);
}
}
class CartScreen extends StatefulWidget {
static const routeName = '/cart';
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen> {
Future? _addressFuture;
String value = 'deliver';
var address;
void initState() {
_addressFuture = _obtainAddressFuture();
super.initState();
}
Future _obtainAddressFuture() async {
address =
await Provider.of<Addresses>(context, listen: false).fetchMyAddress();
}
void didChangeDependencies() async {
super.didChangeDependencies();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Scaffold(
appBar: AppBar(
title: Text('Your Cart'),
),
body: FutureBuilder(
future: _addressFuture,
builder: (ctx, dataSnapshot) {
if (dataSnapshot.error != null) {
print('Data snapshot error is ' + dataSnapshot.error.toString());
return const Center(
child: Text('Something went wrong!'),
);
} else if (dataSnapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return SingleChildScrollView(
child: Column(
children: [
Card(
margin: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 4,
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () async {
// Here you have to wait for the screen to retrun data so we use asyn await
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
AddressScreen(title: 'cartScreen'),
),
);
print(result);
},
child: Container(
padding: EdgeInsets.all(10),
child: const Text(
"Update",
style: TextStyle(
color: Colors.blue,
),
),
),
)
],
),
TextFormField(
// initialValue: address.name,
readOnly: true,
decoration: InputDecoration(
border: InputBorder.none,
prefixIcon: Icon(Icons.person,
color: Colors.orangeAccent),
labelText: 'Contact name',
),
),
],
),
),
],
),
);
}
},
),
),
);
}
}
class AddressScreen extends StatelessWidget {
const AddressScreen({
Key? key,
required this.title,
}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: TextButton(
onPressed: () {
// Here you have pass the data that you want
Navigator.pop(context, 'Data pass here ');
},
child: Text('Pass data back'),
),
),
);
}
}
class Addresses {
Future fetchMyAddress() async {}
}

How to hide or show widget built inside FutureBuilder based on daynamic changes

Am able to show and hide the widget i want but it keeps flickering or rebuilding its self every time.
i just want to show the the capture icon button when the compass degree reaches 190 degree
this is my main widget
late List<CameraDescription> cameras;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: CameraApp(),
);
}
}
class CameraApp extends StatefulWidget {
#override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
String? imagePath;
XFile? imageFile;
late CameraController controller;
late Future<void> _initializeControllerFuture;
int? angleResult;
bool showCaptureButton = false;
String? getLocation;
bool k = false;
void getAngleFromCompass(newResult) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
setState(() {
angleResult = newResult;
});
});
}
void getLocationRes(newResult) {
getLocation = newResult;
}
#override
void initState() {
super.initState();
controller = CameraController(
// Get a specific camera from the list of available cameras.
cameras[0],
// Define the resolution to use.
ResolutionPreset.high,
imageFormatGroup: ImageFormatGroup.yuv420,
);
_initializeControllerFuture = controller.initialize().then((value) {
setState(() {});
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
void _captureImage() async {
await takePicture().then((filePath) {
if (mounted) {
setState(() {
imagePath = filePath;
});
}
});
}
Widget cameraWidget(context) {
var camera = controller.value;
final size = MediaQuery.of(context).size;
var scale = size.aspectRatio * camera.aspectRatio;
if (scale < 1) scale = 1 / scale;
return Transform.scale(
scale: scale,
child: Center(
child: CameraPreview(controller),
),
);
}
#override
Widget build(BuildContext context) {
if (!controller.value.isInitialized) {
return Container();
}
theCompassApp(getAngleFromCompass) keeps flikering here
return Scaffold(
body: FutureBuilder(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Stack(
children: [
cameraWidget(context),
Align(
alignment: Alignment.topCenter,
child: LocationApp(getLocationRes),
),
Align(
child: CompassApp(getAngleFromCompass),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Color(0xAA333639),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
angleResult == 190 ? IconButton(
onPressed: () => _captureImage(),
iconSize: 40,
icon: Icon(
Icons.camera_alt,
color: Colors.white,
),
) : Text(''),
],
),
),
)
],
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
Compass App Widget
class CompassApp extends StatefulWidget {
final getAngleValue;
CompassApp(this.getAngleValue);
#override
_CompassAppState createState() => _CompassAppState();
}
class _CompassAppState extends State<CompassApp> {
bool _hasPermissions = false;
#override
void initState() {
super.initState();
_fetchPermissionStatus();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.transparent,
body: Builder(builder: (context) {
if (_hasPermissions) {
return Column(
children: <Widget>[
Expanded(child: _buildCompass()),
],
);
} else {
return Text('');
}
}),
),
);
}
Widget _buildCompass() {
return StreamBuilder<CompassEvent>(
stream: FlutterCompass.events,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 30),
child: Text('Error reading heading not support'),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
double? direction = snapshot.data!.heading;
int ang = direction!.round();
Compass angle passed to main widget here
widget.getAngleValue(ang);
if (direction.isNaN)
return Center(
child: Text("Device does not have sensors !"),
);
return Material(
color: Colors.transparent,
child: Column(
children: [
RotatedBox(
quarterTurns: 1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 41),
child: Text(
'$ang',
style: TextStyle(
fontSize: 50,
color: Colors.white,
backgroundColor: Colors.black26),
),
),
),
],
),
);
},
);
}
void _fetchPermissionStatus() {
Permission.locationWhenInUse.status.then((status) {
if (mounted) {
setState(() => _hasPermissions = status == PermissionStatus.granted);
}
});
}
}
Have you tried Visibility or Opacity?
Visibility
Visibility(
visible: true, //false for invisible
child: Text('I am visible'),
),
Opacity
Opacity(
opacity: 1.0, //0.0 for invisible
child: Text('I am visible'),
),

Sort dynamically ListView in Flutter

I would like to sort a ListView based on a StreamController in a BottomNavigationBar.
The problem is that the Listview doesn't refresh when I click the button on the app bar.
I would like to pass as parameter the function (Comparable of Company) which the user chooses.
Here's my code:
Home.dart
final CompanyService _companyService = CompanyService();
final AuthService _auth = AuthService();
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
Home createState() => Home();
}
class Home extends State<HomePage> {
Comparator<Company> _sortFunction;
int _currentIndex;
var _tabs = [];
#override
void initState() {
super.initState();
_currentIndex = 0;
_sortFunction = (a, b) => a.name.compareTo(b.name);
}
PreferredSize getDoubleHomeAppBar() {
return PreferredSize(
preferredSize: Size.fromHeight(55.0),
child: Row(
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(left: 12.0),
margin:
const EdgeInsets.only(left: 12.0, bottom: 8.0, right: 12.0),
color: PRIMARY_COLOR,
),
),
FlatButton.icon(
icon: Icon(Icons.sort_by_alpha),
label: Text(
'Sort',
),
onPressed: () {
setState(() {
_sortFunction = (a, b) => b.city.compareTo(a.city);
_tabs[0] = CompanyTab(sortFunction: _sortFunction);
});
},
),
],
));
}
#override
Widget build(BuildContext context) {
_tabs = [
CompanyTab(sortFunction: _sortFunction),
MapTab(),
Center(child: Text('Profile')),
Center(child: Text('Settings')),
];
return Scaffold(
backgroundColor: BACKGROUND_COLOR,
appBar: AppBar(
elevation: 0.0,
centerTitle: true,
title: Text(
'JobAdvisor',
style: TextStyle(
fontSize: MediaQuery.of(context).size.height / 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
bottom: _currentIndex == 0 ? getDoubleHomeAppBar() : null,
actions: <Widget>[...],
),
body: _tabs[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
backgroundColor: BACKGROUND_COLOR,
type: BottomNavigationBarType.fixed,
items: [
...
],
onTap: (index) {
setState(() {
_currentIndex = index;
print('Index: $index');
print('Current index: $_currentIndex');
});
},
),
);
}
}
CompanyTab.dart
#immutable
class CompanyTab extends StatefulWidget {
final CompanyService _companyService = CompanyService();
final Comparator<Company> sortFunction;
CompanyTab({Key key, this.sortFunction}) : super(key: key);
#override
_CompanyTabState createState() =>
_CompanyTabState(_companyService, sortFunction);
}
class _CompanyTabState extends State<CompanyTab> {
StreamController<List<Company>> _streamController;
final CompanyService _companyService;
Comparator<Company> sortFunction;
_CompanyTabState(this._companyService, this.sortFunction);
#override
void initState() {
super.initState();
}
StreamBuilder companyList() {
return StreamBuilder<List<Company>>(
initialData: [],
stream: _streamController.stream,
builder: (BuildContext context, AsyncSnapshot<List<Company>> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.waiting ||
snapshot.connectionState == ConnectionState.none ||
snapshot.data == null) {
return LoadingWidget();
} else {
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Company company = snapshot.data.elementAt(index);
...
}
}
});
}
#override
void dispose() {
_streamController.close();
super.dispose();
}
void _getData() {
_streamController = new StreamController<List<Company>>();
_companyService.getCompanies().then((value) => {_elaborateList(value)});
}
void _elaborateList(List<Company> list) {
List<Company> tmp = list;
tmp.sort(sortFunction);
print(tmp.toString());
_streamController.sink.add(tmp);
}
#override
Widget build(BuildContext context) {
_getData();
return Center(
child: Container(
child: companyList(),
),
);
}
}
I think the problem is in your sort method. It should be like this:
_sortFunction.sort((a, b) => a.name.compareTo(b.name));
You can read from the official document.
EDIT:
And you need to use sortFunction of the widget in here:
tmp.sort(widget.sortFunction);
You are not using the same sortFunction in CompanyTab. You should use the sortFunction which comes as a parameter. Here is a blog about it.