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'));
I'm facing issue to fetch json data from Flutter mobile app.
Code as follow:
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/main_page.dart';
class App extends StatelessWidget
{
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Flutter NodeJS",
home: MainPage(),
);
}
}
void main(){
runApp(App());
}
main_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/modules/http.dart';
import 'package:flutter_app/pages/add_user_page.dart';
class MainPage extends StatefulWidget
{
#override
State<StatefulWidget> createState() {
return MainPageState();
}
}
class User
{
String id;
String first_name,email;
User(this.id, this.first_name,this.email);
}
class MainPageState extends State<MainPage>
{
List<User> users = [];
Future<void> refreshUsers()async{
var result = await http_get('users');
if(result.ok)
{
setState(() {
users.clear();
var in_users = result.data as List<dynamic>;
in_users.forEach((in_user){
users.add(User(
in_user['id'].toString(),
in_user['first_name'],
in_user['email']
));
});
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Users"),
//email: Text("Email"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(
builder: (context){
return AddUserPage();
}
));
},
)
],
),
body: RefreshIndicator(
onRefresh: refreshUsers,
child: ListView.separated(
itemCount: users.length,
itemBuilder: (context, i) => ListTile(
leading: Icon(Icons.person),
title: Text(users[i].first_name+"\n" + users[i].email),
//email: Text(users[i].email),
),
separatorBuilder: (context, i) => Divider(),
),
),
);
}
}
http.dart
import 'dart:convert';
import "package:http/http.dart" as http;
class RequestResult
{
bool ok;
dynamic data;
RequestResult(this.ok, this.data);
}
//'https://jsonplaceholder.typicode.com/users/1
//http://192.168.183.179:8081/api/users/
const PROTOCOL = "http";
const DOMAIN = "https://jsonplaceholder.typicode.com/users/1";
Future<RequestResult> http_get(String route, [dynamic data]) async
{
var dataStr = jsonEncode(data);
var url = "$PROTOCOL://$DOMAIN/$route?data=$dataStr";
var result = await http.get(url);
return RequestResult(true, jsonDecode(result.body));
}
Future<RequestResult> http_post(String route, [dynamic data]) async
{
var url = "$PROTOCOL://$DOMAIN/$route";
var dataStr = jsonEncode(data);
var result = await http.post(url, body: dataStr, headers:{"Content-Type":"application/json"});
return RequestResult(true, jsonDecode(result.body));
}
When I'm fetch json data from "https://jsonplaceholder.typicode.com/users/1". Its working fine.
enter image description here
When I try to fetch json data from "https://192.168.183.179:8081/api/users". Its give error:
at Object.createErrorWithStack (http://localhost:15340/dart_sdk.js:4348:12)
at Object._rethrow (http://localhost:15340/dart_sdk.js:37892:16)
at async._AsyncCallbackEntry.new.callback (http://localhost:15340/dart_sdk.js:37886:13)
at Object._microtaskLoop (http://localhost:15340/dart_sdk.js:37718:13)
at _startMicrotaskLoop (http://localhost:15340/dart_sdk.js:37724:13)
at http://localhost:15340/dart_sdk.js:33243:9
What I'm doing wrong
Regards,
SAO
Check in Postman whether the ip address is returning data.
Another case would be the data obtained, could not be transffered correctly to the app. Check the variables and types where the data is stored.
I need widget with bpmn.js view: https://github.com/bpmn-io/bpmn-js
Used HtmlElementView:
// ignore: undefined_prefixed_name
ui.platformViewRegistry
.registerViewFactory('bpmn_view', (int viewId) => element);
return Column(
children: <Widget>[
Expanded(
child: HtmlElementView(key: UniqueKey(), viewType: "bpmn_view")),
],
);
With js:
const html = '''
<div id="canvas">canvas</div>
<script>
(function () {
window.addEventListener('view_bpmn', function (e) {
var bpmnJS = new BpmnJS({
container: "#canvas"
});
bpmnJS.importXML(e.details);
}, false);
}());
</script>
''';
element.setInnerHtml(html,
validator: NodeValidatorBuilder.common()..allowElement('script'));
But I get error when it execute:
VM4761 bpmn-viewer.development.js:18864 Uncaught TypeError: Cannot read property 'appendChild' of null
at Viewer.BaseViewer.attachTo (VM4761 bpmn-viewer.development.js:18864)
at Viewer.BaseViewer._init (VM4761 bpmn-viewer.development.js:18911)
at Viewer.BaseViewer (VM4761 bpmn-viewer.development.js:18454)
at new Viewer (VM4761 bpmn-viewer.development.js:19082)
at <anonymous>:3:25
at main.dart:185
at future.dart:316
at internalCallback (isolate_helper.dart:50)
And I can't set selector for BpmnJS like:
var bpmnJS = new BpmnJS({
container: "document.querySelector('flt-platform-view').shadowRoot.querySelector('#canvas')";
});
How can I make it work?
Since BpmnJS container parameter accepts DOMElement type value, we can pass querySelector's result directly:
_element = html.DivElement()
..id = 'canvas'
..append(html.ScriptElement()
..text = """
const canvas = document.querySelector("flt-platform-view").shadowRoot.querySelector("#canvas");
const viewer = new BpmnJS({ container: canvas });
""");
// ignore: undefined_prefixed_name
ui.platformViewRegistry
.registerViewFactory('bpmn-view', (int viewId) => _element);
BpmnJS module should be attached to index.html file (in your project's top-level web folder):
<!DOCTYPE html>
<head>
<title>BpmnJS Demo</title>
<script defer src="main.dart.js" type="application/javascript"></script>
<script src="https://unpkg.com/bpmn-js#6.4.2/dist/bpmn-navigated-viewer.development.js"></script>
</head>
...
Here is full code:
import 'dart:ui' as ui;
import 'package:universal_html/html.dart' as html;
import 'package:flutter/material.dart';
class BpmnDemo extends StatefulWidget {
#override
_BpmnDemoState createState() => _BpmnDemoState();
}
class _BpmnDemoState extends State<BpmnDemo> {
html.DivElement _element;
#override
void initState() {
super.initState();
_element = html.DivElement()
..id = 'canvas'
..append(html.ScriptElement()
..text = """
const canvas = document.querySelector("flt-platform-view").shadowRoot.querySelector("#canvas");
const viewer = new BpmnJS({ container: canvas });
const uri = "https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/dfceecba/url-viewer/resources/pizza-collaboration.bpmn";
fetch(uri).then(res => res.text().then(xml => viewer.importXML(xml)));
""");
// ignore: undefined_prefixed_name
ui.platformViewRegistry
.registerViewFactory('bpmn-view', (int viewId) => _element);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: HtmlElementView(key: UniqueKey(), viewType: "bpmn-view")),
);
}
}
UPDATE:
This example shows how to load a diagram from dart code and uses dart:js library:
import 'dart:ui' as ui;
import 'dart:js' as js;
import 'package:universal_html/html.dart' as html;
import 'package:flutter/material.dart';
class BpmnDemo extends StatefulWidget {
#override
_BpmnDemoState createState() => _BpmnDemoState();
}
class _BpmnDemoState extends State<BpmnDemo> {
html.DivElement _element;
js.JsObject _viewer;
#override
void initState() {
super.initState();
_element = html.DivElement();
_viewer = js.JsObject(
js.context['BpmnJS'],
[
js.JsObject.jsify({'container': _element})
],
);
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory('bpmn-view', (int viewId) => _element);
loadDiagram('assets/pizza-collaboration.bpmn');
}
loadDiagram(String src) async {
final bundle = DefaultAssetBundle.of(context);
final xml = await bundle.loadString(src);
_viewer.callMethod('importXML', [xml]);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(child: HtmlElementView(key: UniqueKey(), viewType: "bpmn-view")),
);
}
}
UPDATE 2:
Certain complications with calling methods from js library can arise when HtmlElementView uses IFrame element. In this case we can try two options:
Store IFrame context on dart side and then use callMethod with saved context.
Use postMessage method to communicate with IFrame
import 'dart:ui' as ui;
import 'dart:js' as js;
import 'dart:html' as html;
import 'package:flutter/material.dart';
class IFrameDemoPage extends StatefulWidget {
#override
_IFrameDemoPageState createState() => _IFrameDemoPageState();
}
class _IFrameDemoPageState extends State<IFrameDemoPage> {
html.IFrameElement _element;
js.JsObject _connector;
#override
void initState() {
super.initState();
js.context["connect_content_to_flutter"] = (content) {
_connector = content;
};
_element = html.IFrameElement()
..style.border = 'none'
..srcdoc = """
<!DOCTYPE html>
<head>
<script>
// variant 1
parent.connect_content_to_flutter && parent.connect_content_to_flutter(window)
function hello(msg) {
alert(msg)
}
// variant 2
window.addEventListener("message", (message) => {
if (message.data.id === "test") {
alert(message.data.msg)
}
})
</script>
</head>
<body>
<h2>I'm IFrame</h2>
</body>
</html>
""";
// ignore:undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'example',
(int viewId) => _element,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.filter_1),
tooltip: 'Test with connector',
onPressed: () {
_connector.callMethod('hello', ['Hello from first variant']);
},
),
IconButton(
icon: Icon(Icons.filter_2),
tooltip: 'Test with postMessage',
onPressed: () {
_element.contentWindow.postMessage({
'id': 'test',
'msg': 'Hello from second variant',
}, "*");
},
)
],
),
body: Container(
child: HtmlElementView(viewType: 'example'),
),
);
}
}
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(),
),
);
}
}
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