ShowDialog box is always fullscreen in Flutter? - flutter

I want to create a show dialog box that will act as a disclosure. The one that I've used now gives me a fullscreen dialog, which I don't want. I want it to take the least amount of space that is needed.
This disclosure should pop up immediately as soon as the app opens, therefore, I've added this in the init state. Can someone please tell me how to minimise the size?
The code is as below.`
class LandingScreen extends StatefulWidget {
static const routeName = "/landing_screen";
#override
_LandingScreenState createState() => _LandingScreenState();}
class _LandingScreenState extends State<LandingScreen> {
bool _introDone = false;
#override
void initState() {
// TODO: implement initState
super.initState();
SharedPreferences.getInstance().then((value) {
final introDone = value.getBool("introDone") ?? false;
setState(() {
_introDone = introDone;
});
!_introDone
? showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("DISCLOSURE"),
content: Column(
children: <Widget>[
const Text("This app collects location data to enable location tracking in order to provide location based reminders. This include collecting location data even when the app is running in the background. The data collected will be handled according to the terms of our Privacy notice"),
],
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(primary: Colors.blue),
onPressed: () {},
child: const Text("GOT IT")),
],
);
},
):null;
});
#override
Widget build(BuildContext context) {
return Containter();
}
}

Your problem is in the Column widget. You have to changethe mainAxisSize to min.
builder: (BuildContext context) {
return AlertDialog(
title: const Text("DISCLOSURE"),
content: Column(
mainAxisSize: MainAxisSize.min, // <---
children: <Widget>[
const Text("This app collects location data to enable location tracking in order to provide location based reminders. This include collecting location data even when the app is running in the background. The data collected will be handled according to the terms of our Privacy notice"),
],
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(primary: Colors.blue),
onPressed: () {},
child: const Text("GOT IT")),
],
);
},

Related

Custom Font Size : Increase and Decrease in Flutter

In my flutter application, I have to provide an option to change the font size of the application Text contents.
So, normally, I know that for different screen sizes, We can manage but this is not that case.
I have just gone through this plugin:
https://pub.dev/packages/sizer
But, It's not the case which I am looking for.
The case is to choose particular font size option and according to selected option the font height should be change.
How can I achieve this? Thanks.
If you want the user to be able to change fontsize in your application you could do something like this.
class _MyHomePageState extends State<MyHomePage> {
double? _fontSize = 14;
void _changeFontSize(double fontSize) {
setState(() {
_fontSize = fontSize;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'FontSize is now: $_fontSize',
style: TextStyle(fontSize: _fontSize),
),
ElevatedButton(onPressed: () => _changeFontSize(22), child: const Text("22")),
ElevatedButton(onPressed: () => _changeFontSize(24), child: const Text("24")),
ElevatedButton(onPressed: () => _changeFontSize(26), child: const Text("26")),
],
),
),
);}}

Why is the function not invoke

I am new to coding and to flutter but am attempting to build an app for scanning, creating database, and inventory. I have been attempting to use flutter_barcode_scanner to achieve this along with several others while looking at multiple videos and blogs but have become unsuccessful and am now I'm coming here for help.
Provided is the code that I'm currently attempting to write for it. At this point I've confused myself since I was recently trying to utilize scan_preview also as my goal is to implement the scanner as a stream in half or 1/3rd of the screen and having the rest of the screen as the result that is pulled from the database or to create a new item if no match.
I am looking for some assistance in how to implement the barcode scanner in the fashion where it streams in part of the screen and why I am getting these issues and how to fix them. I have attempted the fixes that androidstudio is providing me but it creates many more issues.
Am I going about this the correct way?
How do I use flutter_barcode_scanner to stream in only a portion of the screen?
Errors from AndroidStudio:
child: ScanMode.BARCODE( Error: The expression doesn't evaluate to a function, so it can't be invoked
Center(child: Text(barcode)) Error: Undefined name 'barcode'
'#ff6666', 'Cancel', true, ScanMode.BARCODE)! Error: This requires the 'non-nullable' language feature to be enabled
return Scaffold(
appBar: AppBar(
title: Text("Barcode Scanner"),
centerTitle: true,
),
body: Column(
children: [
SizedBox(
width: double.infinity,
height: height / 0.6,
child: ScanMode.BARCODE(
onScanResult: (result) {
debugPrint('scan result: $result');
setState(() {
_data = result;
});
},
),
),
SizedBox(height: 20),
Center(child: Text(barcode))
],
));
}
}
class ScannerHelper extends StatefulWidget {
#override
_ScannerHelperState createState() => _ScannerHelperState();
}
class _ScannerHelperState extends State<ScannerHelper> {
String _scanbarcode = 'Unknown';
#override
void initState() {
super.initState();
}
Future<void> startBarcodeScanStream() async {
FlutterBarcodeScanner.getBarcodeStreamReceiver(
'#ff6666', 'Cancel', true, ScanMode.BARCODE)!
.listen((barcode) => print(barcode));
}
//build - to resolve scanner issue
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Barcode scan')),
body: Builder(builder: (BuildContext context) {
return Container(
alignment: Alignment.center,
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => startBarcodeScanStream(),
child: Text('Start barcode scan stream')),
Text('Scan result : $_scanbarcode\n',
style: TextStyle(fontSize: 20))
]));
})));
}

Does watch(provider) update children of parent widget?

I'm trying to update both Pages with one UserInteraction, therefore trying to access the same Stream in both Pages, with the Riverpod library.
Now to explain it further. When I pass the Stream to the CustomerPage I'm able to get the data (the String Anton). and when I click on the Button that triggers the change in FireStore, the String gets updated to "Marco" in the ParentWidget, when I go back to it. But it doesn't change in the CustomerPage unless I reopen the Page via the RaisedButton in the ParentWidget.
But I want it to update after I click the Button on the CustomerPage.
I hope this makes it clearer.
class ParentWidget extends ConsumerWidget{
Widget build(BuildContext context, ScopedReader watch){
Stream<DocumentSnapshot> doc = watch(streamProvider.stream);
return Container(
child: Column(
children: [
Text(doc.name), //Lets say the name is Anton,
RaisedButton(
child: Text(" road to CustomerPage"),
onPressed:(){
Navigator.of(context).pushNamed(RouteGenerator.customerPage, arguments: doc);
},), //RaisedButton
],), //Column
); //Container
}
}
class CustomerPage extends StatelessWidget{
Stream<DocumentSnapshot> docStream
CustomerPage({this.docStream});
Widget build(BuildContext context){
return Column(
children: [
Text(docStream.name) //Here is also Anton
RaisedButton(
child: Text("Change Name"),
onPressed: () {
context.read(streamProvider).changeName("Marco");
},), //RaisedButton
]
); //Column
}
}
On how I've understood so far is that, riverpod allows you to fetch the state of a provider, which basically is a value(?), that's why it's sufficient to just watch it in any Widget you want to access it's data from. There is no need anymore (just speaking for my case), to let Widgets pass the around in the App.
Down below is the solution which i believe to be right.
It also doesn't matter on how many times I call the provider. It's always going to be same Instance. For my case it means, that doc and doc2 are the same.
I hope this makes it clearer.
class ParentWidget extends ConsumerWidget{
Widget build(BuildContext context, ScopedReader watch){
Stream<DocumentSnapshot> doc = watch(streamProvider.stream);
return Container(
child: Column(
children: [
Text(doc.name), //Lets say the name is Anton,
RaisedButton(
child: Text(" road to CustomerPage"),
onPressed:(){
Navigator.of(context).pushNamed(RouteGenerator.customerPage);
},), //RaisedButton
],), //Column
); //Container
}
}
class CustomerPage extends ConsumerWidget{
Widget build(BuildContext context, ScopedReader watch){
Stream<DocumentSnapshot> doc2 = watch(streamProvider.stream);
return Column(
children: [
Text(doc2.name) //Here is also Anton
RaisedButton(
child: Text("Change Name"),
onPressed: () {
context.read(streamProvider).changeName("Marco");
},), //RaisedButton
]
); //Column
}
}

How to display a Cubit state modified in a Widget into another Widget?

Im developing a Shopping cart using the BLoC pattern and I got stuck trying to learn the subset Cubit. My main question is how can I display the state of a previously updated Cubit? My flow is the next...
On the Product Screen I increase/decrease the items I want to use.
To push to change the state, I click a button and send the items as a parameter to the Cubit function.
The item list gets updated and I want to get it into another widget that is outside of the Product Screen.
Here is the code:
main.dart
void main() {HttpOverrides.global = new MyHttpOverrides();
runApp(
RepositoryProvider<AuthenticationService>(
create: (context) {
return AuthService();
},
child: MultiBlocProvider(
providers: [
BlocProvider<AuthenticationBloc>(
create: (context) {
final authService = RepositoryProvider.of<AuthenticationService>(context);
return AuthenticationBloc(authService)..add(AppLoaded());
}
),
BlocProvider<CartCubit>(create: (context) => CartCubit())
],
child: MyApp(),
),
)
);
}
product_screen.dart
BlocBuilder<CartCubit, List<Item>>(
builder: (context, state) {
return Row(
children: [
_shoppingItem(0),
SizedBox(
width: SizeConfig.blockSizeHorizontal * 2,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
color: Color(0xFF48AD71),
),
child: IconButton(
onPressed: () {
for (int i = 1; i <= counter; i++) {
items.add(widget.item);
print('something');
}
context.read<CartCubit>().addToList(items);
},
icon: Icon(
Icons.shopping_bag),
color: Colors.white,
),
),
],
);
},
)
cart_cubit.dart
class CartCubit extends Cubit<List<Item>> {
CartCubit() : super([]);
void addToList(List<Item> items) {
state.addAll(items);
emit(state);
print(state);
}
}
What I should add on my Cart Screen so I can get the value of the Cubit State? Also, do this should be better handled by using a bloc instead of cubit?
Edit: Based on the comment of Loren.A I removed the BlocBuilder of my ProductScreen and I added it to my CartScreen.
class _CartScreenState extends State<CartScreen> {
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return SingleChildScrollView(
child: BlocBuilder<CartCubit, List<Item>>(
builder: (context, state) {
return Column()
...
...
Align(
alignment: Alignment.topRight,
child: Text(
state.length.toString(), // this is not updating
textAlign: TextAlign.end,
style: TextStyle(
fontFamily: 'SinkinSans',
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: Color(0xFFC9C9C9)),
),
),
Cubit is fine for this. You can update widgets anywhere in your app based on that list just by adding another BlocBuilder<CartCubit, List<Item>>. So just add another one to your Cart page and do what ya gotta do inside of it. It will reflect the previous changes.
Edit: Just noticed that it doesn't appear that you're actually rebuilding any widgets in your product screen so that BlocBuilder you have is not really doing anything. You can remove that and just use it where you need to reflect that value of the list. You can still fire that addToList method without being inside a BlocBuilder.

Flutter : using changeNotifier and provider when the context is not available

I'm trying to use the simple state management described in the Flutter docs, using a ChangeNotifier, a Consumer, and a ChangeNotifierProvider.
My problem is that I can't get a hold a on valid context to update my model (details below...). I get an error:
Error: Error: Could not find the correct Provider above this CreateOrganizationDialog Widget
This likely happens because you used a BuildContext that does not include the provider of your choice. There are a few common scenarios:
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that CreateOrganizationDialog is under your MultiProvider/Provider.
This usually happen when you are creating a provider and trying to read it immediately.
Here are extracts of my code:
class OrganizationModel extends ChangeNotifier {
final List<Organization> _items = [];
/// An unmodifiable view of the items in the cart.
UnmodifiableListView<Organization> get items => UnmodifiableListView(_items);
void addList(List<Organization> items) {
_items.addAll(items);
notifyListeners();
}
}
This is my model.
class OrganizationBodyLayout extends StatelessWidget {
Future<void> _showCreateOrganizationDialog() async {
return showDialog<void>(
context: navigatorKey.currentState.overlay.context,
barrierDismissible: false,
child: CreateOrganizationDialog());
}
_onCreateOrganizationPressed() {
_showCreateOrganizationDialog();
}
_onDeleteOrganizationPressed() {
//TODO something
}
_onEditOrganizationPressed() {
//TODO something
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(mainAxisSize: MainAxisSize.max, children: [
ButtonBar(
alignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
RaisedButton(
onPressed: _onCreateOrganizationPressed,
child: Text("New Organization"),
),
],
),
Expanded(
child: Container(
color: Colors.pink,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: ChangeNotifierProvider(
create: (context) => OrganizationModel(),
child: OrganizationListView(),
)),
Expanded(child: Container(color: Colors.brown))
]))),
]));
}
}
A stateless widget that contains a ChangeNotifierProvider just on top of the list widget using the model.
On a button click, a modal dialog is shown, then data is fetched from the network. I should then update my model calling the addList operation.
Below is the code for the stateful dialog box.
class CreateOrganizationDialog extends StatefulWidget {
#override
_CreateOrganizationDialogState createState() =>
_CreateOrganizationDialogState();
}
class _CreateOrganizationDialogState extends State<CreateOrganizationDialog> {
TextEditingController _nametextController;
TextEditingController _descriptionTextController;
#override
initState() {
_nametextController = new TextEditingController();
_descriptionTextController = new TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
return Dialog(
child: Container(
width: 200,
height: 220,
child: Column(
children: [
Text('New organization',
style: Theme.of(context).textTheme.headline6),
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
decoration: new InputDecoration(hintText: "Organization name"),
controller: _nametextController,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
decoration:
new InputDecoration(hintText: "Organization description"),
controller: _descriptionTextController,
),
),
ButtonBar(
children: [
FlatButton(
child: new Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: new Text("Create"),
onPressed: () {
setState(() {
Future<Organization> organization =
backendCreateOrganization(_nametextController.text,
_descriptionTextController.text);
organization.then((value) {
Future<List<Organization>> organizations =
backendReloadOrganizations();
organizations.then((value) {
var model = context.read<OrganizationModel>();
// var model = navigatorKey.currentState.overlay.context.read<OrganizationModel>();
//model.addList(value);
});
});
});
Navigator.of(context).pop();
//context is the one for the create dialog here
},
)
],
)
],
),
));
}
}
My problem happens at the line
var model = context.read<OrganizationModel>();
Thinking of it, the context available here is the modal dialog box context - so it's kind of logical that the Provider is not found in the widget tree.
However, I can't see how to retrieve the proper context (which would be the one for the result list view, where the Provider is located) in order to get the model and then update it.
Any idea is welcome :-)
Solved (kind of).
The only way I've found to solve this is by making my model a global variable:
var globalModel = OrganizationModel();
And referencing this global model in all widgets that consume it. I can't find a way to find the context of a stateless widget from within a callback in another stateful widget.
It works, but it's ugly. Still open to elegant solutions here :-)
Get_it seems to be elegant way of sharing models across the application. Please check the documentation for the different use cases they provide.
You could do something like the following
GetIt getIt = GetIt.instance;
getIt.registerSingleton<AppModel>(AppModelImplementation());
getIt.registerLazySingleton<RESTAPI>(() =>RestAPIImplementation());
And in other parts of your code, you could do something like
var myAppModel = getIt.get<AppModel>();