I'm currently using the shared preferences to save a string list. Every time the page is opened, for every string entry from the list I create a list tile inside a list view. But now I don't want to only save the string, I even want to save an icon with it. But I have absolutely no idea on how to solve this
Here is my current code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:trainings_app/widgets/alertbox_widget.dart';
import 'package:trainings_app/widgets/team_widget.dart';
class TeamScreen extends StatefulWidget {
#override
_TeamScreenState createState() => _TeamScreenState();
}
class _TeamScreenState extends State<TeamScreen> {
late SharedPreferences sharedPreferences;
List<String> teams = [];
IconData? currentIcon;
#override
void initState() {
tryFetchData();
super.initState();
}
void tryFetchData() async {
sharedPreferences = await SharedPreferences.getInstance();
if (!sharedPreferences.containsKey('teams')) {
sharedPreferences.setStringList('teams', []);
return;
}
teams = sharedPreferences.getStringList('teams') as List<String>;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: teams.length,
itemBuilder: (context, index) {
return Team(
teams[index],
Icon(currentIcon),
() => removeTeam(teams[index]),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
newTeam();
},
child: Icon(
CupertinoIcons.add,
),
),
);
}
void newTeam() {
showDialog<Alertbox>(
context: context,
builder: (BuildContext context) {
return Alertbox('Namen auswählen:', addTeam);
},
);
}
void addTeam(String name, IconData? icon) {
if (name.isNotEmpty) {
setState(() {
currentIcon = icon;
teams.add(name);
});
}
Navigator.pop(context);
sharedPreferences.setStringList('teams', teams);
}
void removeTeam(String name) {
setState(() {
teams.remove(name);
});
sharedPreferences.setStringList('teams', teams);
}
}
class Team extends StatelessWidget {
final String name;
final Icon icon;
final Function remove;
const Team(this.name, this.icon, this.remove);
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 22),
child: ListTile(
leading: Icon(icon.icon),
contentPadding: EdgeInsets.symmetric(vertical: 8.0),
title: Text(
name,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w600,
),
),
trailing: IconButton(
icon: Icon(CupertinoIcons.delete),
onPressed: () => remove(),
),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => TeamWidget(name, icon)));
},
),
);
}
}
you can use each Icon specific id instead of IconData and store it as a List of Json:
Json.encode({title:"test", icon:61668}
and then save it in sharedPref. after that you can recall it as follows:
Icon(IconData(**YOUR SELECTED ID**, fontFamily: 'MaterialIcons'));
check the id of each icon here: link
The other solution can be using images instead of icons! or using this site to convert image to font icon and use it as follows:
Icon(IconData(int.parse('0x${e90a}',
fontFamily: 'family name given in the link above'));
Flutter Logout directs to login page but after re-login it does not redirects to the intended home page.
I have used the below navigation for login
Navigator.of(context).pushReplacement(PageRouteBuilder(pageBuilder: (_, __, ___) => Home()));
My app is consist of three bottom navigation bar.Home Page is in second navigation bar. I have to logout from third navigation bar.
I have used the below code for logout
Navigator.pushNamedAndRemoveUntil(context, '/Login', (_) => false);
Also i have tried the codes too
Navigator.popAndPushNamed(context, "/Login");
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => Login(),), (Route route) => false);
Please help me to find a solution.
This is my splash screen
class SplashState extends State<SplashScreen>{
bool isLogged = false;
startTime(){
return new Timer(Duration(milliseconds: 3000), navigateUser);
}
#override
void initState() {
super.initState();
getStoredValue();
}
void getStoredValue() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('isLoggin')) {
prefs.setBool('isLoggin', false);
print("login set to False");
}
isLogged = prefs.getBool('isLoggin');
print("Status in splash -----------$isLogged");
startTime();
}
#override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIOverlays([]);
return Container(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(
gradient:LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[
colorStyle.splashPink,
colorStyle.splashOrange,
],
)
),
child: Center(
child: Image.asset("assets/images/splash_logo.png", height: 85.0),
),
);
}
void navigateUser() {
if (isLogged == true) {
Navigator.of(context).pushReplacement(
PageRouteBuilder(pageBuilder: (_, __, ___) => Home()));
}
else {
Navigator.of(context).pushReplacement(
PageRouteBuilder(pageBuilder: (_, __, ___) => Login()));
}
}
}
Logout
void logoutUser()async{
LogoutUser objLog = await createPost(logoutUrl,body);
if(objLog.statusCode == 10000){
print(("response is $resp"));
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('isLoggin', false);
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => Login()));
}
else showToast(objLog.message, duration: Toast.LENGTH_LONG);
}
Try to use shared preference to store as login key and check if it is true then go to main screen or else redirect to login screen.
First of all add shared preference dependency in your pubspec.yaml
dependencies:
flutter:
sdk: flutter
shared_preferences: ^0.5.6+2
SplashScreen.dart
This is first screen where we are check that if isLogin is true then go to HomeScreen or else redirect to LoginScreen
_autoLogin() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('isLogin')) {
prefs.setBool('isLogin', false);
}
if (prefs.getBool('isLogin')) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
));
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => LoginScreen(),
));;
}
}
LoginScreen.dart
_setIsLogin() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('isLogin', true);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
));
}
MaterialButton(
minWidth: MediaQuery.of(context).size.width,
padding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
onPressed: () {
_setIsLogin();
},
child: Text("LOGIN",
textAlign: TextAlign.center,
style: style.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18.0)),
),
HomeScreen.dart
Set isLogin as false when click on Logout
_logout() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('isLogin', false);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => LoginScreen(),
));
}
I hope this can help you!
I tried to print in a ZEBRA ez320 Bluetooth printer I found out that it only works using cpcl code, the good news is I have the sample code for cpcl but I don't know how to integrate it on my Flutter project.
Can someone help me out?
This github https://github.com/devinim/flutter-zsdk has Zebra SDK Kit Flutter Integration
code snippet
devices = await FlutterZsdk.discoverBluetoothDevices();
devices.forEach((d) {
print('Device: ${d.friendlyName} [${d.mac}]');
});
...
d.sendZplOverBluetooth(FLUTTER_LOGO_ZPL),
full example code https://github.com/devinim/flutter-zsdk/blob/master/example/lib/main.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_zsdk/flutter_zsdk.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
static const String FLUTTER_LOGO_ZPL = "^XA^CI28^PON^PW560^MNN^LL460^LH0,0^LT60" +
"^GFA,6150,6150,25,,gP01XFCgP03XF8gP07XF,gP0XFE,gO01XFC,gO03XF8,gO07XF,gO0XFE,gN01XFC,gN03XF8,gN0YF,gN0XFE,gM01XFC,gM03XF8,gM0YF,gL01XFE"
",gL01XFC,gL07XF8,gL0YF,gK01XFE,gK03XFC,gK07XF8,gK0YF,gJ01XFE,gJ03XFC,gJ07XF8,gJ0YF,gI01XFE,gI03XFC,gI07XF8,gI0YF,gH01XFE,gH03XFC,gH07XF8"
",gH0YF,gG01XFE,gG03XFC,gG07XF8,gG0YF,g01XFE,g03XFC,g07XF8,g0YF,Y01XFE,Y03XFC,Y07XF8,Y0YF,X01XFE,X03XFC,X07XF8,X0YF,W01XFE,W03XFC,W07XF8"
",W0YF,V01XFE,V03XFC,V07XF8,V0YF,U01XFE,U03XFC,U07XF8,U0YF,T01XFE,T03XFC,T07XF8,T0YF,S01XFE,S03XFC,S07XF8,S0YF,R01XFE,R03XFC,R07XF8"
",R0YF,Q01XFE,Q03XFC,Q07XF8,Q0YF,P01XFE,P03XFC,P07XF8,P0YF,O01XFE,O03XFC,O07XF8,O0YF,N01XFE,N03XFC,N07XF8,N0YF,M01XFE,M03XFC,M07XF8"
",M0YF,L01XFE,L03XFC,L07XF8,L0YF,K01XFE,K03XFC,K07XF8,K0YF,J01XFE,J03XFC,J07XF8,J0YF,I01XFE,I03XFC,I07XF8,I0XFE,001XFE,003XFCN03XF"
",007XF8N07XF,00XFEO0XFE,01XFCN01XFC,03XFCN03XF8,07XF8N07XF,0XFEO0XFE,1XFCN01XFC,3XF8N03XF8,7XF8N07XF,3WFEO0XFE,1WFCN01XFC,0WF8N03XF8"
",07VFO07XF,03UFEO0XFE,01UFCN01XFC,00UF8N03XF8,007TFO07XF,003SFEO0XFE,001SFCN01XFC,I0SF8N03XF8,I07RFO07XF,I03QFEO0XFE,I01QFCN01XFC,J0QF8N03XF8"
",J07PFO07XF,J03OFEO0XFE,J01OFCN01XFC,K0OF8N03XF8,K07NFO07XF,K03MFEO0XFE,K01MFCN01XFC,L0MF8N03XF8,L07LFO07XF,L03KFEO0XFE,L01KFCN01XFC,M0KF8N03XF8"
",M07JFO07XF,M03IFEO0XFE,M01IFCN01XFC,N0IF8N03XF8,N07FFO07XF,N03FEO0XFE,N01FCN01XFC,O0F8N03XF8,O07O07XF,O02O0XFE,X01XFC,X03XF8,X07XF,X0XFE,W01XFC"
",W03XF8,W07XF,W0XFE,V01XFC,V03XF8,V07XF,V0XFE,U01XFC,U03XF8,U07XF,U0XFE,T01XFC,T07XF8,T07XF,T03XF8,T01XFC,U0XFE,U07XF,U03XF8,U01XFC,V0XFE,V07XF"
",V03XF8,V01XFC,W0XFE,W07XF,W07XF8,W03XFC,X0XFE,X07XF,X07XF8,X03XFC,X01XFE,Y07XF,Y07XF8,Y03XFC,Y01XFE,g0YF,g07XF8,g03XFC,g01XFE,gG0YF,gG07XF8,gG03XFC"
",gG01XFE,gH0YF,gH07XF8,gH03XFC,gH01XFE,gI0YF,gI07XF8,gI03XFC,gI01XFC,gJ0XFE,gJ07XF,gJ03XF8,gJ01XFC,gK0XFE,gK07XF,gK03XF8,gK01XFC,gL0XFE,gL07XF,gL03XF8"
",gL01XFC,gM0XFE,gM07XF,gM03XF8,gM01XFC,gN0XFE,gN07XF,gN03XF8,gN01XFC,gO0XFE,gO07XF,gO03XF8,gO01XFC,gP0XFE,gP07XF,gR01VF8"
",^FS ^XZ";
List<ZebraBluetoothDevice> _devices = List();
#override
void initState() {
super.initState();
__init();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> __init() async {
List<ZebraBluetoothDevice> devices = List();
try {
devices = await FlutterZsdk.discoverBluetoothDevices();
devices.forEach((d) {
print('Device: ${d.friendlyName} [${d.mac}]');
});
} catch (e) {
showDialog(context: context, child: Text(e));
//throw e;
print('Error' + e);
}
if (!mounted) return;
setState(() {
_devices = devices;
});
}
String levelText = "Querying...";
_level(ZebraBluetoothDevice d) {
d.batteryLevel().then((t) {
setState(() {
levelText = t;
});
});
}
Widget _listPrinters() {
List<Widget> items = List();
if (_devices.length < 1) {
items.add(ListTile(
title: Text("Not found any or still searching"),
));
} else {
items.addAll([
ListTile(
title: Text("Found ${_devices.length} device(s)"),
),
SizedBox(height: 50),
]);
_devices.forEach((d) {
_level(d);
items.add(
ListTile(
title: Text(d.friendlyName),
subtitle: Text(d.mac + "[%${levelText}]"),
leading: IconButton(icon: Icon(Icons.list), onPressed: () => d.properties()),
trailing: IconButton(
icon: Icon(Icons.print),
onPressed: () => d.sendZplOverBluetooth(FLUTTER_LOGO_ZPL),
),
),
);
});
}
return ListView(
padding: EdgeInsets.all(24),
children: items,
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Zebra Plugin Example App'),
),
body: _listPrinters(),
),
);
}
}
With autocomplete_textfield package of Flutter, I have made a search bar. When it returns the result as a container, I want to a button in it that'll push to the respected screen of the search result.
But how can I make the button dynamic so that it can go to the screen based on the search result?
For example, if the search result is Aishim, how can I get the button to go to AishimWidget() when pressed?
I have added the FlatButton to the result container. That goes to AishimWidget when pressed.
import 'package:autocomplete_textfield/autocomplete_textfield.dart';
import 'package:flutter/material.dart';
import 'package:smartdoctor/screens/aishim_widget.dart';
class SearchWidget extends StatefulWidget {
#override
State < StatefulWidget > createState() => _SearchWidgetState();
}
class _SearchWidgetState extends State < SearchWidget > {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: SecondPage(),
);
}
}
class ArbitrarySuggestionType {
String name;
ArbitrarySuggestionType(this.name);
}
class SecondPage extends StatefulWidget {
#override
State < StatefulWidget > createState() => _SecondPageState();
}
class _SecondPageState extends State < SecondPage > {
List < ArbitrarySuggestionType > suggestions = [
new ArbitrarySuggestionType("Minamishima"),
new ArbitrarySuggestionType("Aishim"),
];
GlobalKey key =
new GlobalKey < AutoCompleteTextFieldState < ArbitrarySuggestionType >> ();
AutoCompleteTextField < ArbitrarySuggestionType > textField;
ArbitrarySuggestionType selected;
_SecondPageState() {
textField = new AutoCompleteTextField < ArbitrarySuggestionType > (
decoration: new InputDecoration(
hintText: "Search:", suffixIcon: new Icon(Icons.search)),
itemSubmitted: (item) => setState(() => selected = item),
key: key,
suggestions: suggestions,
itemBuilder: (context, suggestion) => new Padding(
child: new ListTile(
title: new Text(suggestion.name)),
padding: EdgeInsets.all(8.0)),
itemSorter: (a, b) => a.stars == b.stars ? 0 : a.stars > b.stars ? -1 : 1,
itemFilter: (suggestion, input) =>
suggestion.name.toLowerCase().startsWith(input.toLowerCase()),
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Column(children: [
new Padding(
padding: EdgeInsets.fromLTRB(0.0, 64.0, 0.0, 0.0),
child: new Card(
child: selected != null ?
new Column(children: [
new Container(
child: FlatButton(
onPressed: () => this.onButtonPressed(context))),
new ListTile(
title: new Text(selected.name)),
]) :
new Icon(Icons.home))),
]),
);
}
void onButtonPressed(BuildContext context) => Navigator.push(context, MaterialPageRoute(builder: (context) => AishimWidget()));
}
But it's not dynamic. Can I use any if statement for deciding which screen to go to? Or is there any better way of doing this?
You can use named-routes https://flutter.dev/docs/cookbook/navigation/named-routes
Map each page with a string
In onButtonPressed, use string
Navigator.pushNamed(context, '/second');
or in your case might looks like the following, you can pass any string you want like selected.name or suggestion.name
Navigator.pushNamed(context, suggestion.name);
define your route, map each page with a string
void main() {
runApp(MaterialApp(
title: 'Named Routes Demo',
// Start the app with the "/" named route. In this case, the app starts
// on the FirstScreen widget.
initialRoute: '/',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => FirstScreen(),
// When navigating to the "/second" route, build the SecondScreen widget.
'/second': (context) => SecondScreen(),
},
));
}
full example code
import 'package:flutter/material.dart';
//void main() => runApp(MyApp());
void main() {
runApp(MaterialApp(
title: 'Named Routes Demo',
// Start the app with the "/" named route. In this case, the app starts
// on the FirstScreen widget.
initialRoute: '/',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => FirstScreen(),
// When navigating to the "/second" route, build the SecondScreen widget.
'/second': (context) => SecondScreen(),
},
));
}
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('Launch screen'),
onPressed: () {
// Navigate to the second screen using a named route.
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to the first screen by popping the current route
// off the stack.
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
I am looking for a way to send an API request after the user has stopped typing for X amount of seconds.
The way I am sending the request is through the onTextChanged callback, however, that sends a request on every key press
I have seen ways to do this with a timeout in React, however, I am relatively new to flutter so any help would be appreciated
you can use the below code to do this:
import 'package:flutter/material.dart';
import 'dart:async';
class Test extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _TestState();
}
}
class _TestState extends State<StatefulWidget> {
Timer searchOnStoppedTyping;
_onChangeHandler(value ) {
const duration = Duration(milliseconds:800); // set the duration that you want call search() after that.
if (searchOnStoppedTyping != null) {
setState(() => searchOnStoppedTyping.cancel()); // clear timer
}
setState(() => searchOnStoppedTyping = new Timer(duration, () => search(value)));
}
search(value) {
print('hello world from search . the value is $value');
}
#override
Widget build(BuildContext context) {
return TextField(
onChanged: _onChangeHandler,
decoration: InputDecoration(
hintText: 'Search ....'
),
);
}
}
The usual way to do this in Flutter is using RxDart and its debounce() method. It allows to wait a small period before launching a specific call.
In the following full example you see it in action with a time of 1 second. In the example, a message is shown where the call to the server should be dispatched.
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final subject = new PublishSubject<String>();
bool isLoading = false;
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey();
void _textChanged(String text) {
if (text.isEmpty) {
setState(() {
isLoading = false;
});
return;
}
setState(() {
isLoading = true;
});
scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text("Search for ${text}"),
));
}
#override
void initState() {
super.initState();
subject.stream.debounce(new Duration(milliseconds: 1000)).listen(_textChanged);
}
#override
void dispose() {
subject.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
key: scaffoldKey,
appBar: new AppBar(
title: new Text("Debounce demo"),
),
body: new Container(
padding: new EdgeInsets.all(8.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new TextField(
decoration: new InputDecoration(
hintText: 'Type text to search',
),
onChanged: (string) => (subject.add(string)),
),
isLoading
? Padding(
padding: const EdgeInsets.all(20.0),
child: new CircularProgressIndicator(),
)
: new Container(),
],
),
),
);
}
}
You can see this code in action in the following article and code by Norbert Kozsir