Json from file not loading the first time - json

I'm trying to get a online JSON, save it locally for offline use. The issue is that when I try to get the data from the saved JSON file, the first time I open the new "window" no data is loading, because my "goggo1" variable does not receive the new value from reading the JSON file. The funny thing is if I go back and the open it again, then "goggo1" is getting the value required to show the JSON contents.
class HomePagerstare extends StatefulWidget {
Contact contact = new Contact();
String title, content;
#override
_HomePageState createState() => _HomePageState();
}
Future<String> get getFilePath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get getFile async {
final path = await getFilePath;
return File('$path/myfile.json');
}
Future<File> saveToFile(String datar) async {
final file = await getFile;
return file.writeAsString(datar);
}
Future<String> readFromFile() async {
try {
final file = await getFile;
final String fileContents = await file.readAsString();
return fileContents;
} catch (e) {
return "aici e eroare";
}
}
class _HomePageState extends State<HomePagerstare> implements HomeContract {
List<Note> data1 = List<Note>();
List<Note> data2 = List<Note>();
var goggo1 = "";
Future<List<Note>> loadJsonData() async {
var data = List<Note>();
this.setState(() {
print(goggo1);
var datas = jsonDecode(goggo1);
for (var noteJson in datas) {
data.add(Note.fromJson(noteJson));
Note note =
Note(noteJson["id"], noteJson["title"], noteJson["content"]);
}
});
return data;
}
#override
void initState() {
print("1Nu Suntem Online");
super.initState();
readFromFile().then((fileContents) {
setState(() {
goggo1 = fileContents;
});
});
print("1Nu Suntem Online");
this.loadJsonData().then((value) {
setState(() {
data1.addAll(value);
data2 = data1;
print("2Nu Suntem Online");
});
});
}
class Note {
String title;
String content;
int id;
the note.dart
Note(this.id, this.title, this.content);
Note.fromJson(Map<String, dynamic> json) {
id = json['id'];
title = json['title'];
content = json['content'];
}
}
Please help!

I think I could give you an idea. Try something like this,
readFromFile().then((fileContents) {
setState(() {
goggo1 = fileContents;
});
this.loadJsonData().then((value) {
setState(() {
data1.addAll(value);
data2 = data1;
print("2Nu Suntem Online");
});
});
});
Hope that works!

Related

How to work with large images on Blazor/ Web

my question is how to manage really large images on the web. Im using blazor, I need to send and recive Images of 100mb or more, And im using webshockets to send btwin the web and the server that send images. Im using base64 but its also slow.
this is how i send and i recive an image
public class WebshocketConections
{
public Uri _Uri = new Uri("ws://xxx.xxx.xxx.xxx:YYYY");
ClientWebSocket _cliente;
CancellationTokenSource cts = new();
public delegate void CheckNewMessage(string a);
public event CheckNewMessage? onMessage;
public WebshocketConections(ClientWebSocket client, Uri uri)
{
_cliente = client;
_Uri = uri;
}
public async Task Connect()
{
cts.CancelAfter(TimeSpan.FromSeconds(100));
await _cliente.ConnectAsync(_Uri, cts.Token);
await Echo(_cliente);
}
public async Task SendString(string message)
{
ArraySegment<byte> byteToSend = await Task.Run(() => { return new ArraySegment<byte>(Encoding.UTF8.GetBytes(message)); });
await _cliente.SendAsync(byteToSend, WebSocketMessageType.Text, true, cts.Token);
}
public async Task SendImage(byte[] Base64)
{
ArraySegment<byte> byteToSend = await Task.Run(() => { return new ArraySegment<byte>(Encoding.UTF8.GetBytes("img" + Convert.ToBase64String(Base64))); });
await _cliente.SendAsync(byteToSend, WebSocketMessageType.Binary, true, cts.Token);
}
public async Task<ClientWebSocket> GetClient()
{
return _cliente;
}
private async Task Echo(ClientWebSocket client)
{
var buffer = new byte[1024 * 1000000];
var receiveResult = await client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue)
{
onMessage(Encoding.UTF8.GetString(buffer, 0, receiveResult.Count));
await client.SendAsync(
new ArraySegment<byte>(buffer, 0, receiveResult.Count),
receiveResult.MessageType,
receiveResult.EndOfMessage,
CancellationToken.None);
receiveResult = await client.ReceiveAsync(
new ArraySegment<byte>(buffer),
CancellationToken.None);
}
await client.CloseAsync(
receiveResult.CloseStatus.Value,
receiveResult.CloseStatusDescription,
CancellationToken.None);
}
}

Pass Map data from API to multiple screens in flutter?

How can i pass the Map data from that list to others screens being StatefulWidget or StatelessWidget, and why it donĀ“t work like the one screen example?
The Api Part here:
Future pokeinfo(int position) async {
var dio = Dio();
Response response;
response =
await dio.get('https://pokeapi.co/api/v2/pokemon/${position.toString()}');
Map json = jsonDecode(response.toString());
return json;
}
The function part here:
bool widgetVisible = false;
List<PokeList> elements = [];
void showWidget() {
createList();
setState(() {
widgetVisible = !widgetVisible;
});
}
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
void createList() async {
List<PokeList> _elements = [];
for (int i = 1; i < 50; i++) {
Map currentData = await pokeinfo(i);
_elements.add(PokeList(currentData));
}
setState(() {
elements = _elements;
});
How it works in one screen:
Map data;
PokeList(Map this.data);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PokemonPage()),
);
you need to use one of state management packages, However google recommend provider package.
with provider you can make request in provider class
class PokeProvider extends ChangeNotifier {
Map json;
Future pokeinfo(int position) async {
var dio = Dio();
Response response;
response = await dio
.get('https://pokeapi.co/api/v2/pokemon/${position.toString()}');
Map json = jsonDecode(response.toString());
return json;
}
}
then store it's data inside a variable that every screen will listen on change of it, like json
then expose that provider to whole app
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => PokeProvider(),
child: const MyApp(),
),
);
}
then read it from anywhere inside application with
PokeProvider pokeProvider = Provider.of<PokeProvider>(context, listen: false);
pokeProvider.json; // now you got your map
be carful of listen: false if your data will change ui directly so make listen: true
for more information about provider package check the link blew contain everything you need
ChangeNotifierProvider example
Thank you all who tried to help me, I got the problem and how to solve it. I will put the solution here to someone who has the same problem. A simple thing to change actually:
Remove the specific screen from List.
bool widgetVisible = false;
List elements = [];
void showWidget() {
createList();
setState(() {
widgetVisible = !widgetVisible;
});
}
Inside the function you just need to change List, repeating what was shown previously.
void createList() async {
List _elements = [];
for (int i = 1; i < 50; i++) {
Map currentData = await pokeinfo(i);
_elements.add(PokeList(currentData));
}
And finally, you only have to put inside the screen class. Like that:
Class ScreenNameHere extends StatelessWidget{
Map data;
ScreenNameHere(Map this.data);
/*
#override
Widget build(BuildContext context) {
return ScreenBody();
}
*/
}

sqflite + Flutter : map((e) => .... returns [Instance of Class]

I am currently using Sqflite with Flutter for a small app being developed.
My model Class for User is as follows:
class User {
static const tblUser = 'users';
static const colUserId = 'id';
static const colUserName = 'name';
static const colUserMail = 'mail';
static const colUserPhone = 'phone';
User({this.id, this.name, this.mail, this.phone});
int id;
String name;
String mail;
String phone;
User.fromMap(Map<String, dynamic> map) {
this.id = map[colUserId];
this.name = map[colUserName];
this.mail = map[colUserMail];
this.phone = map[colUserPhone];
}
Map<String, dynamic> toMap() {
var map = <String, dynamic>{
colUserName: name,
colUserMail: mail,
colUserPhone: phone
};
if (id != null) {
map[colUserId] = id;
}
return map;
}
}
In the database_helper class, I create the database and the tables, which work correctly:
class DatabaseHelper {
static const _databaseName = 'FinmanDatabase.db';
static const _databaseVersion = 1;
DatabaseHelper._();
static final DatabaseHelper instance = DatabaseHelper._();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
Directory dbDirectory = await getApplicationDocumentsDirectory();
String dbpath = join(dbDirectory.path, _databaseName);
return await openDatabase(dbpath,
version: _databaseVersion, onCreate: _onCreateDB);
}
Future _onCreateDB(Database db, int version) async {
await db.execute('''
CREATE TABLE ${User.tblUser} (
${User.colUserId} INTEGER PRIMARY KEY AUTOINCREMENT,
${User.colUserName} TEXT NOT NULL,
${User.colUserMail} TEXT NOT NULL,
${User.colUserPhone} TEXT NOT NULL
)
''');
}}
However, when I try to fetch the Users to flutter, the program returns 'Instance of User' instead of the contents. The function to fetch the Users is as follows:
Future<List<User>> fetchAllUser() async {
Database db = await database;
List<Map> userslist = await db.query(User.tblUser);
int count = userslist.length;
print('Printing $userslist from DBHelper + Length: $count');
return userslist.length == 0 ? [] : userslist.map((e) => User.fromMap(e)).toList();
}
And here is how I am calling this in Flutter:
class _HomeState extends State<Home> {
User user = User();
List<User> _users;
String _dbExists;
DatabaseHelper _dbhelper;
int count = 0;
#override
void initState() {
super.initState();
setState(() {
_dbhelper = DatabaseHelper.instance;
});
_refreshUserList();
}
_refreshUserList() async {
List<User> x = await _dbhelper.fetchAllUser();
setState(() {
_users = x;
print(_users);
count = _users.length;
print(count);
if (count > 0) {
_dbExists = 'Database exists';
} else {
_dbExists = 'Create a new Database';
}
});
}}
While the print(count) returns 1 (which is the number of records in the User Table), print(_users) returns [Instance of User]??
Any help is appreciated.
when I try to fetch the Users to flutter, the program returns
'Instance of User' instead of the contents
Because x is List<User>.
To get the content, you can use for-loop
for(var i in x){
print(i.name); // it will print out the name
}

Flutter/Dart - How to pass variables between classes?

I am very new to programming and I am trying to pass a variable (jsonData) from a future to another future in a different class, so the data from the variable can be stored in a database. Dont be confused, I am using an API for getting the neccessary data, this works perfectly fine. Any tips how I can access the variable jsonData to insert the data?
//first class gets the json data
class getJSONData {
Future<void> makeRequest() async {
var url = "some url";
Map inputData = {
"Password": example,
"SQL": sql query,
"db_server": "server",
"db_table": "table",
};
var body = json.encode(inputData);
var putRequest = await http.put(
Uri.encodeFull(url), headers: {"Content-Type": "application/json"},
body: body);
//this variable has to be stored
var jsonData = json.decode(putRequest.body);
}
}
//data needs to be inserted here
class Database {
Future<void> insertJSON() async {
db = await openDatabase(
join(await getDatabasesPath(), tableName),
onCreate: (db, version) {
return db.execute('''
INSERT INTO $tableName(column1, column2, etc) VALUES (${jsonData["Records].data1}, ${jsonData["Records].data2}, etc)
''');
}
);
}
}
below i am showing you how to pass data between two screens :
Screen 1 :
class HomeScreenTopContainer extends StatefulWidget {
#override
_HomeScreenTopContainerState createState() => _HomeScreenTopContainerState();
}
class _HomeScreenTopContainerState extends State<HomeScreenTopContainer> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Inkwell(onTap:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ParentLanding(parameter:"pass your value here")),
);
},child:Text("Tap Here and pass data")),
],
);
}
}
Screen 2 :
class ParentLanding extends StatefulWidget {
String parameter;
ParentLanding({Key key,String parameter}) : super(key: key,parameter:parameter);
#override
_ParentLandingState createState() => _ParentLandingState();
}
class _ParentLandingState extends State<ParentLanding> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Inkwell(onTap:(){
// you can use this parameter like this.
},child:Text(**Widget.parameter**)),
],
);
}
}
You have many options.
I'll suggest you one.
Change the signatures of both methods.
Example
Your HttpClient class
Future<Map<String, dynamic>> makeRequest() async {
// ... your code
var jsonData = json.decode(putRequest.body);
return jsonData;
}
Your DB Class
Future<void> insertJSON(Map<String, dynamic> jsonData) async {
db = await openDatabase(
join(await getDatabasesPath(), tableName),
onCreate: (db, version) {
return db.execute('''
INSERT INTO $tableName(column1, column2, etc) VALUES
(${jsonData["Records].data1}, ${jsonData["Records].data2}, etc)
''');
}
);
}
Use a third Class/object/method that make the call to the api, take the result and pass it to the db class:
main() async {
HttClient http = HttpClient();
Database db = Database();
final json = await http.makeRequest();
await db.insertJSON(json);
}
Easiest way to pass any value is using an argument.
Value can be send as:
Keys.navKey.currentState.pushNamed(
Routes.gameViewScreen, arguments: jsonData );
In another class it can be retrieved as :
var jsonData = ModalRoute.of(context).settings.arguments;

Flutter : Showing nested data received from serve : Edited #3

I have an app receive nested data from server in the page i print the data's and it is printed successfully :
class page :
final DateTime mDate;
final List<Games> games;
class DatedMatchs {
DatedMatchs(
this.mDate,
this.games,
);
}
class Games {
Games(
this.id,this.sId,this.wId,this.leagueName,this.homeTeam,this.awayTeam,this.homeGoals,this.awayGoals,this.mHour,this.homeEx,this.awayEx,
);
final String id;
final String sId;
final String wId;
final String leagueName;
final String homeTeam;
final String awayTeam;
final String homeGoals;
final String awayGoals;
final String mHour;
final String homeEx;
final String awayEx;
}
page i want to show data:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import '../models/dated_matchs.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
List matchs = [];
Future<List> getmatchs() async {
var url =
'xxx/api/controller/matchs/dated_matchs.php?s_id=1';
var response = await http.get(url);
var data = jsonDecode(response.body);
print(data);
}
return FutureBuilder(
future: getmatchs(),
builder: (ctx, snapshot) {
return Container();
});
}
}
Now i don't know how to add received data to a list then show it on list-view
I used this way inside future function but there is something wrong :
Future<List> getmatchs() async {
var url =
'xxx/api/controller/matchs/dated_matchs.php?s_id=1';
var response = await http.get(url);
var data = jsonDecode(response.body);
for (var x in data) {
for (var y in x['games']) {
cont1.add(TextEditingController());
cont2.add(TextEditingController());
Games newmatch = Games(
y['id'],
y['s_id'],
y['w_id'],
y['league_name'],
y['home_team'],
y['away_team'],
y['home_goals'],
y['away_goals'],
y['m_hour'],
y['home_ex'],
y['away_ex']);
matchs.add(newmatch);
}
DatedMatchs newdated = DatedMatchs(x['m_date'], x['matchs']);
datedmatchs.add(newdated);
}
return datedmatchs;
}
no thing print
Some of your data is coming back as a Map, rather than a List. You'll need to debug and see which data is a Map, then you can print it from the Map.
Also, I wouldn't call an api in your UI. It's best to use a state management library, such as Bloc, Provider, or RxDart.
I solved it and below the future method which get me list of data correctly :
List<Games> games = []; // I added type of List
List<DatedMatchs> datedmatchs = []; // I added type of List
Future<List> getmatchs() async {
var url =
'xxx/api/controller/matchs/dated_matchs.php?s_id=1';
var response = await http.get(url);
var data = await jsonDecode(response.body);
for (var x in data) {
for (var y in x['games']) {
cont1.add(TextEditingController());
cont2.add(TextEditingController());
Games newmatch = Games(
y['id'],
y['s_id'],
y['w_id'],
y['league_name'],
y['home_team'],
y['away_team'],
y['home_goals'],
y['away_goals'],
y['m_hour'],
y['home_ex'],
x['away_ex']);
games.add(newmatch);
}
DatedMatchs newdated = DatedMatchs(x['m_date'], games); // add name of list
datedmatchs.add(newdated);
}
return datedmatchs;
}