How to load json in main method Flutter? - flutter

I'm trying to load a json file into my main() app method.
Can you tell me if this is possible? I've tryed File and rootBundle but it seems that Assets' folder are not ready yet.
here is my code:
ASSETS
assets:
- assets/settings/settings.json
MAIN METHOD
void main() async {
final file = await rootBundle.loadString('assets/settings/settings.json');
final data = jsonDecode(file);
Settings settings = Get.put(Settings.fromJson(data), permanent: true);
runApp(MyApp());
}

Found the Solution using FutureBuilder
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
_load() async {
final file = await rootBundle.loadString('assets/j.json');
final data = await jsonDecode(file);
print(data.toString());
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _load(),
builder: (_, AsyncSnapshot<dynamic> snapshot) {
return !snapshot.hasData
? Container(
color: Colors.white,
child: Center(
child: Container(
child: CircularProgressIndicator(),
width: 20,
height: 20,
)),
)
: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
appBarTheme: AppBarTheme(
titleTextStyle: Theme.of(context).textTheme.headline1,
),
),
home: Scaffold(
body: Text("Body"),
// MaxWidthButton(),
),
);
});
}
}

I dont seems it is, instead try on MyApp and make it statefullWidget
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
_load();
}
_load() async {
final file = await rootBundle.loadString('assets/j.json');
final data = await jsonDecode(file);
print(data.toString());
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
appBarTheme: AppBarTheme(
titleTextStyle: Theme.of(context).textTheme.headline1,
),
),
home: Scaffold(
body: Text("Body"),
// MaxWidthButton(),
),
);
}
}

Related

CupertinoPicker skip items in Desktop (Windows) in Flutter 3.7

Since updating to Flutter 3.7 i am not able to select cerain items in my CupertienoPicker.
To reproduce this issue run the following code in Windows Desktop:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _index = 0;
List<String> team = <String>["Olaf","Victor","Rita"] ;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: CupertinoPicker(
itemExtent: 50,
onSelectedItemChanged: (selectedIndex) {
_index = selectedIndex;
},
children: List.generate(team.length, (index) {
return Text(team[index]);
}),
),
),
);
}
}
An issue has already filed in github.
First thing to check is your Mouse Settings. It is known that the issue might appear if you have set "Multiple lines at a time". To check this go to Settings -> Devices -> Mouse and set "Choose how many lines to scroll each time" to 1.
If this does not fix your issue read below.
The issue seems in deed a bug in the latest Flutter 3.7.
As a work around i had to add a listener to the CupertinoPicker's scrollerController and perform the jumps programatically as follows
var c = FixedExtentScrollController();
c.addListener(() {
if (previousIndex != c.selectedItem) {
isScrollDown = previousIndex<c.selectedItem;
isScrollUp = previousIndex>c.selectedItem;
var previousIndexTemp = previousIndex;
previousIndex = c.selectedItem;
if (isScrollUp) {
c.jumpToItem(previousIndexTemp - 1);
} else if (isScrollDown) {
c.jumpToItem(previousIndexTemp + 1);
}
}
});
...
CupertinoPicker(
scrollController: c,
...
Here is a modified version of the code above that applies the mentioned work around:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _index = 0;
int previousIndex = 0;
bool isScrollUp = false;
bool isScrollDown = true;
List<String> team = <String>["Olaf","Victor","Rita"] ;
FixedExtentScrollController c = FixedExtentScrollController();
#override
void initState() {
c.addListener(_manageScroll);
super.initState();
}
void _manageScroll () {
if (previousIndex != c.selectedItem) {
isScrollDown = previousIndex<c.selectedItem;
isScrollUp = previousIndex>c.selectedItem;
var previousIndexTemp = previousIndex;
previousIndex = c.selectedItem;
if (isScrollUp) {
c.jumpToItem(previousIndexTemp - 1);
} else if (isScrollDown) {
c.jumpToItem(previousIndexTemp + 1);
}
}
}
#override
void dispose() {
c.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: CupertinoPicker(
scrollController: c,
itemExtent: 50,
onSelectedItemChanged: (selectedIndex) {
_index = selectedIndex;
},
children: List.generate(team.length, (index) {
return Text(team[index]);
}),
),
),
);
}
}

Flutter - How to call an API every n minutes?

I need to call an API every n minutes. The data should be available across all screens. How can I implement this at app level. I am not using any state management tools.
void main() {
periodicSub = Stream.periodic(const Duration(seconds: 10))
.listen((_) {
///fetch data
someFuture =
Future<List<someObject>>.delayed(
const Duration(milliseconds: 500), () async {
return someFunction();
});
});
someFuntions returns a list. I want a certain FutureBuilder on HomePage to execute whenever the list is updated.
Here is an example using "https://pub.dev/packages/provider"
First create a Notifier:
import 'dart:async';
import 'package:flutter/material.dart';
class CustomNotifier with ChangeNotifier {
int counter = 0;
CustomNotifier() {
Stream.periodic(const Duration(seconds: 10)).listen((_) {
///fetch data
Future<List<dynamic>>.delayed(const Duration(milliseconds: 500),
() async {
return someFunction();
});
});
}
someFunction() {
counter++;
notifyListeners();
}
}
Then you could use it like:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'notifier.dart';
void main() {
final customNotifier = CustomNotifier();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => customNotifier,
),
//You could add more providers
],
builder: (context, _) {
return const MyApp();
},
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var customNotifier = Provider.of<CustomNotifier>(
context,
);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'someFunction runs this many times:',
),
Text(
'${customNotifier.counter}',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
);
}
}

Getting Error In Flutter : RangeError (index) : Invalid value: Not in inclusive range

I am flutter beginner and while practicing the Swipe to dismiss option I have completed the below mentioned code and after deleting few list items I am receiving the below error, I tried to solve the problem but couldn't,
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHome(),
);
}
}
class MyHome extends StatelessWidget {
final List<String> items = new List<String>.generate(30, (i) => "Items ${i+1}");
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Swipe To Dismiss"),
centerTitle: true,
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context,int index){
return Dismissible(
key: Key(items[index]),
onDismissed: (direction){
items.removeAt(index);
Scaffold.of(context).showSnackBar(new SnackBar(
content: Text("ITEM IS SUCCESSFULLY REMOVED")));
},
background: Container(
color: Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
),
child: ListTile(
title: Text("${items[index]}"),
),
);
}),
);
}
}
error while deleting list items and then scrolling down
Convert stateless widget into statefull and use setState so that ListView gets rebuilded.
Below code is tested & working. You can test it here.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHome(),
);
}
}
class MyHome extends StatefulWidget {
#override
createState() => _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
final List<String> items =
new List<String>.generate(30, (i) => "Items ${i + 1}");
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Swipe To Dismiss"),
centerTitle: true,
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, int index) {
return Dismissible(
key: Key(items[index]),
onDismissed: (direction) {
items.removeAt(index);
Scaffold.of(context).showSnackBar(new SnackBar(
content: Text("ITEM IS SUCCESSFULLY REMOVED")));
setState((){});
},
background: Container(
color: Color((math.Random().nextDouble() * 0xFFFFFF).toInt())
.withOpacity(1.0),
),
child: ListTile(
title: Text("${items[index]}"),
),
);
}),
);
}
}
I have sucessfully fixed the issue . I converted MyHome from Stateless to StateFul Widget and added setState in onDismissed . Here is the changed code.
onDismissed: (direction){
setState(() {
items.removeAt(index);
});
Scaffold.of(context).showSnackBar(new SnackBar(
content: Text("ITEM IS SUCCESSFULLY REMOVED")));
},

Flutter countdown start on button press

So i am trying to make a SMS verifier. I need a button which i press to send the sms and after that it needs to start a countdown so you cannot press the button anymore. I found this code on the internet (https://dartpad.dev/23c25b17a8d663ea8c01b18eae38b2ab?) the problem with this is that it first starts the countdown once the page is open and i need exactly the opposite, once the page is opened first you press the button and than see the countdown and the cycle repeats.
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const _timerDuration = 30;
StreamController _timerStream = new StreamController<int>();
int timerCounter;
Timer _resendCodeTimer;
#override
void initState() {
activeCounter();
super.initState();
}
#override
dispose(){
_timerStream.close();
_resendCodeTimer.cancel();
super.dispose();
}
activeCounter(){
_resendCodeTimer =
new Timer.periodic(Duration(seconds: 1), (Timer timer) {
if (_timerDuration - timer.tick > 0)
_timerStream.sink.add(_timerDuration - timer.tick);
else {
_timerStream.sink.add(0);
_resendCodeTimer.cancel();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: StreamBuilder(
stream: _timerStream.stream,
builder: (BuildContext ctx,
AsyncSnapshot snapshot) {
return SizedBox(
width: 300,
height: 30,
child:RaisedButton(
textColor: Theme.of(context)
.accentColor,
child: Center(
child:
snapshot.data == 0 ?
Text('send code again')
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(' button will be enable after ${snapshot.hasData ? snapshot.data.toString() : 30} seconds '),
],)
),
onPressed: snapshot.data == 0 ? () {
// your sending code method
_timerStream.sink.add(30);
activeCounter();
} : null,
)
);
},
),
),
);
}
}
Just change your initState() like this:
#override
void initState() {
_timerStream.sink.add(0); //add this line
super.initState();
}
Delete activeCounter() from initState() and call it whenever you want to start timer.
Complete Example:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({this.title}) : super();
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const _timerDuration = 30;
StreamController _timerStream = new StreamController<int>();
int timerCounter;
Timer _resendCodeTimer;
#override
void initState() {
_timerStream.sink.add(0);
super.initState();
}
#override
dispose(){
_timerStream.close();
_resendCodeTimer.cancel();
super.dispose();
}
activeCounter(){
_resendCodeTimer =
new Timer.periodic(Duration(seconds: 1), (Timer timer) {
if (_timerDuration - timer.tick > 0)
_timerStream.sink.add(_timerDuration - timer.tick);
else {
_timerStream.sink.add(0);
_resendCodeTimer.cancel();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: StreamBuilder(
stream: _timerStream.stream,
builder: (BuildContext ctx,
AsyncSnapshot snapshot) {
print('Data: ${snapshot.data}');
return SizedBox(
width: 300,
height: 30,
child:RaisedButton(
textColor: Theme.of(context)
.accentColor,
child: Center(
child:
snapshot.data == 0 ?
Text('send code again')
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(' button will be enable after ${snapshot.hasData ? snapshot.data.toString() : 30} seconds '),
],)
),
onPressed: snapshot.data == 0 ? () {
// your sending code method
_timerStream.sink.add(30);
activeCounter();
} : null,
)
);
},
),
),
);
}
}

Navigating through flutter screens automatically

I'm developing an app that is using location data. So in the landing screen, I will check whether the permission to access location data is granted or not. I do this using the geolocator package. When the user grants permission, I will collect the data like current location and then I want to automatically move into another screen, which is the main screen of the app. Is there any way that I'm able to do that?
I'm making a simple app to demonstrate the permission checking and proper handling of the navigation based on the outcome. You can check the below code and commentation to understand the flow:
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SomeScreen(),
);
}
}
class SomeScreen extends StatelessWidget {
final _scaffoldKey = GlobalKey<ScaffoldState>();
void _determinePosition(context) async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
// Checking if the service is enabled
if (!serviceEnabled) {
// If not, display a Snackbar
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text('Location services are disabled.'),
duration: Duration(seconds: 2),
));
}
// Checking the permission here
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.deniedForever) {
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
'Location permissions are permanently denied, we cannot request permissions.'),
duration: Duration(seconds: 2),
));
}
if (permission == LocationPermission.denied) {
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text('Location permissions are denied'),
duration: Duration(seconds: 2),
));
}
}
// Finally if the permission is granted, navigate the user to new screen
Position position = await Geolocator.getCurrentPosition();
Navigator.push(context,
MaterialPageRoute(builder: (context) => Home(position: position)));
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Container(
alignment: Alignment.center,
color: Colors.blue,
child: FlatButton(
onPressed: () => _determinePosition(context),
child: Text("Check permission"),
color: Colors.red,
),
),
);
}
}
// A simple screen to display the position
class Home extends StatefulWidget {
final Position position;
Home({this.position});
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Text(
'Location: ${widget.position.altitude} ${widget.position.longitude}'),
),
),
);
}
}
If you want your main screen depend on a value or condition I think you could simply use a Streambuilder at your home, whose streamcontroller receives a boolean, depending on which it'll return one screen or another.
Here for example I used this Streambuilder that listens to a boolean. I will change the value of this boolean to true by pressing a button. In my Streambuilder at my home I have the condition that, if the info received, the snapshot.data is true, then it should not return the MyHomePage but instead TheOtherRoute.
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
final StreamController<bool> _streamController =
StreamController<bool>.broadcast();
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: StreamBuilder(
stream: _streamController.stream,
builder: (context, snapshot) {
if(snapshot.data == true){
return TheOtherRoute();
}
return MyHomePage();
},
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('this is a testo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: FlatButton(
color: Colors.black38,
child: Text('Change boolean'),
onPressed: () {
_streamController.add(true);
},
),
),
],
),
),
);
}
}
class FirstRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: Text('Your boolean changed. Your home page is now FirstRoute()'),
),
);
}
}
Try it out and let me know.