I'm trying to make an app that has basically the same mechanics as a simple todo-app. My problem is, when I try to open the screen where I can create a new project/todo(new_project_screen), there should be loaded some TextFields, but they don't. Instead, this error occurs. I tried several solutions from stackoverflow, but nothing worked and I have no idea why it's not working.(sorry for my bad english, I'm not a native xD)
Here is my code:
main.dart:
import 'package:flutter/material.dart';
import 'package:leisy/surface/main_screen.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Leisy',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainScreen(),
);
}
}
main_screen.dart:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:sqflite/sqflite.dart';
import 'package:leisy/db/database_helper.dart';
import 'package:leisy/model/project.dart';
import 'package:leisy/surface/settings_screen.dart';
import 'package:leisy/surface/new_project_screen.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Project> projectList = [];
int count = 0;
#override
Widget build(BuildContext context) {
if (projectList == null) {
projectList = <Project>[];
updateListView();
}
debugPrint("Building entire main screen scaffold");
return Scaffold(
appBar: AppBar(
title: Text("Leisy"),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Center(
child: Text(
"Menü",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => {Navigator.of(context).pop()},
),
ListTile(
leading: Icon(Icons.add),
title: Text('Neues Projekt'),
onTap: () => {
Navigator.of(context).push(new MaterialPageRoute(
builder: (context) => new NewProjectScreen()))
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Einstellungen'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()))
},
)
],
),
),
body: getProjectListView(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: navigateToNewProject,
),
);
}
ListView getProjectListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subtitle1;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
),
title: Text(
this.projectList[position].name,
style: titleStyle,
),
subtitle: Text(this.projectList[position].date),
onTap: () {
debugPrint('ListTile Tapped');
//navigateToDetail() einfügen
},
),
);
});
}
void _showSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(
content: Text(message),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
void navigateToNewProject() async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) => NewProjectScreen()));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initDB();
dbFuture.then((database) {
Future<List<Project>> projectListFuture = databaseHelper.getProjectList();
projectListFuture.then((projectList) {
setState(() {
this.projectList = projectList;
this.count = projectList.length;
});
});
});
}
}
new_project_screen.dart:
import 'package:flutter/material.dart';
import 'package:leisy/db/database_helper.dart';
import 'package:leisy/model/project.dart';
import 'package:leisy/surface/main_screen.dart';
import 'package:leisy/surface/settings_screen.dart';
class NewProjectScreen extends StatefulWidget {
#override
_NewProjectScreenState createState() => _NewProjectScreenState();
}
class _NewProjectScreenState extends State<NewProjectScreen> {
Project project;
DatabaseHelper helper = DatabaseHelper();
TextEditingController nameController = TextEditingController();
TextEditingController dateController = TextEditingController();
TextEditingController locationController = TextEditingController();
#override
Widget build(BuildContext context) {
nameController.text = project.name;
dateController.text = project.date;
locationController.text = project.location;
return Scaffold(
appBar: AppBar(
title: Text("Neues Projekt"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Center(
child: Text(
"Menü",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => MainScreen()))
},
),
ListTile(
leading: Icon(Icons.add),
title: Text('Neues Projekt'),
onTap: () => {Navigator.of(context).pop()},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Einstellungen'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()))
},
)
],
),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateName();
});
},
),
TextField(
decoration: InputDecoration(labelText: 'Datum'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateDate();
});
},
),
TextField(
decoration: InputDecoration(labelText: 'Ort'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateLocation();
});
},
),
Row(
children: <Widget>[
Expanded(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColorDark),
),
child: Text('Speichern'),
onPressed: () {
setState(() {
_save();
});
},
)),
Expanded(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColorDark),
),
child: Text('Abbrechen'),
onPressed: () {
setState(() {
_cancel();
});
},
)),
],
)
],
)
)
);
}
void _save() async {
Navigator.pop(context, true);
await helper.insertProject(project);
}
void _showSnackBar(String message) {
SnackBar snackBar = SnackBar(content: Text(message));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
void _cancel() async {
Navigator.pop(context, true);
_showSnackBar('Vorgang abgebrochen');
}
void updateName() {
project.name = nameController.text;
}
void updateDate() {
project.date = dateController.text;
}
void updateLocation() {
project.location = locationController.text;
}
}
project.dart:
class Project {
int _id;
String _name;
String _date;
String _location;
String _personaldb;
Project(this._name, this._date, this._location, this._personaldb);
Project.withId(
this._id, this._name, this._date, this._location, this._personaldb);
int get id => _id;
String get name => _name;
String get date => _date;
String get location => _location;
String get personalDB => _personaldb;
set name(String newName) {
if (newName.length <= 63) {
this._name = newName;
}
}
set date(String newDate) {
this._date = newDate;
}
set location(String newLocation) {
this._location = newLocation;
}
set personalDB(String newPersonalDB) {
this._personaldb = newPersonalDB;
}
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
if (id != null) {
map['id'] = _id;
}
map['name'] = _name;
map['date'] = _date;
map['location'] = _location;
map['personalDB'] = _personaldb;
return map;
}
Project.fromMapObject(Map<String, dynamic> map) {
this._id = map['id'];
this._name = map['name'];
this._date = map['date'];
this._location = map['location'];
this._personaldb = map['personalDB'];
}
}
database_helper.dart:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:leisy/model/project.dart';
class DatabaseHelper {
static DatabaseHelper _databaseHelper;
static Database _database;
String projectTable = 'project_table';
String colId = 'id';
String colName = 'name';
String colDate = 'date';
String colLocation = 'location';
String colPersonalDB = 'personalDB';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initDB();
}
return _database;
}
Future<Database> initDB() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'projects.db';
var projectsDB = await openDatabase(path, version: 1, onCreate: _createDB);
return projectsDB;
}
void _createDB(Database db, int newVersion) async {
await db.execute('CREATE TABLE $projectTable('
'$colId INTEGER PRIMARY KEY AUTOINCREMENT,'
'$colName TEXT,'
'$colDate TEXT,'
'$colLocation TEXT,'
'$colPersonalDB TEXT)');
}
Future<List<Map<String, dynamic>>> getProjectMapList() async {
Database db = await this.database;
var result = await db.query(projectTable);
return result;
}
Future<int> insertProject(Project project) async {
Database db = await this.database;
var result = await db.insert(projectTable, project.toMap());
return result;
}
Future<int> updateProject(Project project) async {
var db = await this.database;
var result = await db.update(projectTable, project.toMap(), where: '$colId = ?', whereArgs: [project.id]);
return result;
}
Future<int> deleteProject(int id) async {
var db = await this.database;
int result = await db.delete(projectTable, where: '$colId = $id');
return result;
}
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT (*) from $projectTable');
int result = Sqflite.firstIntValue(x);
return result;
}
Future<List<Project>> getProjectList() async {
var projectMapList = await getProjectMapList();
int count = projectMapList.length;
List<Project> projectList = <Project>[];
for (int i = 0; i < count; i++) {
projectList.add(Project.fromMapObject(projectMapList[i]));
}
return projectList;
}
}
Error:
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building NewProjectScreen(dirty, state: _NewProjectScreenState#670bc):
The getter 'name' was called on null.
Receiver: null
Tried calling: name
The relevant error-causing widget was:
NewProjectScreen file:///C:/Users/gabri/AndroidStudioProjects/leisy/lib/surface/main_screen.dart:116:89
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 _NewProjectScreenState.build (package:leisy/surface/new_project_screen.dart:24:35)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4612:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4495:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4667:11)
...
====================================================================================================
If anybody can help me, I would really appreciate it. And if anything in my code is inconvenient or badly implemented, please be kind with me I'm a beginner at this.
The file new_project_screen.dart has the problem
To be exact, the problem can be found in lines 24:35
And seems like that project variable is null project.name;
That is because you are creating Project project but isn't instancied yet. Is just a null variable
See the image below, will help you to understand a bit:
https://dartpad.dev/1ebc897cd3f547cc0b79e52290a63653
So to fix it, you need to create the instance previously
Related
Probably the contacts have duplicates, but I want the duplicates to be accepted. The basic idea is to access the contact list and populate the values to a dropdownMenu and let the user to select a contact from there and save to a file. I have already initialised the dropdownMenu with a string "Select a contact" through a variable.
Exception has occurred.
_AssertionError ('package:flutter/src/material/dropdown.dart': Failed assertion: line 890 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) {
return item.value == value;
}).length == 1': There should be exactly one item with [DropdownButton]'s value: Select a contact.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value)
Here is the complete code
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:io';
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';
import 'package:path_provider/path_provider.dart';
class Interface extends StatelessWidget {
const Interface({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('pAM'),
),
body: const ContactSelector(),
);
}
}
class ContactSelector extends StatefulWidget {
const ContactSelector({super.key});
#override
_ContactSelectorState createState() => _ContactSelectorState();
}
class _ContactSelectorState extends State<ContactSelector> {
Contact _selectedContact = Contact();
late bool _isTrue;
late Iterable<Contact> _contacts;
List<DropdownMenuItem<String>> _dropdownItems = [];
String _selectedName = "Select Contact";
//late List<DropdownMenuItem<String>> _dropdownItems;
#override
void initState() {
super.initState();
_getContacts();
_selectedName = _dropdownItems.isNotEmpty
? _dropdownItems[0].value!
: 'Select a contact';
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
if (_dropdownItems != null)
DropdownButton<String>(
value: _selectedName,
items: _dropdownItems,
onChanged: (newValue) {
_onContactChanged(newValue!);
},
)
else
const Text("Loading...")
],
);
}
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
void _sendMessage(String message) async {
String phoneNumber = _selectedContact.phones.toString();
Uri uri = Uri(
scheme: 'sms',
path: phoneNumber,
query: encodeQueryParameters(<String, String>{
'body': 'Welcome to pAM',
}),
);
if (await canLaunchUrl(uri)) {
await canLaunchUrl(uri);
} else {
throw 'Could not send SMS';
}
}
_getContacts() async {
_contacts = await ContactsService.getContacts(withThumbnails: false);
_dropdownItems = _contacts
.map((c) => DropdownMenuItem(
value: c.displayName,
child: Text(c.displayName.toString()),
))
.toList();
setState(() {});
}
_onContactChanged(String newValue) {
setState(() {
_selectedName = newValue;
_selectedContact =
_contacts.firstWhere((c) => c.displayName == _selectedName);
});
_saveContactToFile(_selectedContact);
_readJson();
}
_saveContactToFile(Contact contact) async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/selected_contact.txt');
if (!(await file.exists())) {
file.create();
}
file.writeAsString(jsonEncode(contact.toMap()));
}
void _readJson() async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/true.json');
if (await file.exists()) {
final content = jsonDecode(await file.readAsString());
if (content["isTrue"]) {
_promptMessage();
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Reminder'),
content: const Text(
"You can continue your work, remember your loved ones misses you"),
actions: <Widget>[
ElevatedButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
}
}
}
_promptMessage() {
if (_isTrue) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Select a message'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
InkWell(
child: const Text('How are you?'),
onTap: () {
_sendMessage('How are you?');
}),
InkWell(
child: const Text('What are you up to?'),
onTap: () {
_sendMessage('What are you up to?');
}),
InkWell(
child: const Text('What is for dinner?'),
onTap: () {
_sendMessage('What is for dinner?');
}),
],
),
),
actions: <Widget>[
ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
This is the key part of the error message:
There should be exactly one item with [DropdownButton]'s value: Select a contact.
You are setting the value of the DropdownButton to "Select a contact" (presumably because _dropdownItems.isNotEmpty == false), but none of the DropdownMenuItems that you have given to the DropdownButton via its items property has "Select a contact" as its value. You might want to look into the use of the hint property to show the "Select a contact", well, hint.
Something like the (untested) code below:
DropdownButton<String>(
hint: Text("Select a contact")
value: _dropdownItems.isNotEmpty ? _dropdownItems.first.value : null,
items: _dropdownItems,
onChanged: (newValue) {
_onContactChanged(newValue!);
},
)
Problem :
Im trying to delete data from Flutter DataTable, when i pressed the alertdialog and click yes the Data already deleted on the Database but the data still shown in the screen until i click the back navigation button and back to list of user.
Expected :
The Datatable should automatically refreshed with current data minus the data that i deleted earlier.
Datatable
// ignore_for_file: deprecated_member_use
import 'package:flutter/material.dart';
import 'package:flutter_auth/Models/nasabah.dart';
import 'package:flutter_auth/network/nasabah_service.dart';
import 'package:flutter_auth/screens/Menu/DataNasabah/detailnasabah.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
class DataNasabah extends StatefulWidget {
#override
_DataNasabahState createState() => _DataNasabahState();
}
class _DataNasabahState extends State<DataNasabah> {
String nama_debitur = '';
List<Nasabah> _nasabah = [];
#override
void initState() {
super.initState();
_loadUserData();
_getNasabah();
}
_loadUserData() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var user = jsonDecode(localStorage.getString('user'));
if (user != null) {
setState(() {
nama_debitur = user['nama_debitur'];
});
}
}
_getNasabah() {
NasabahService.getUser().then((nasabah) {
if (mounted) {
setState(() {
_nasabah = nasabah;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Data Nasabah'),
// backgroundColor: Color(0xff151515),
// automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
child: PaginatedDataTable(
rowsPerPage: 10,
header: Align(
alignment: Alignment.center,
child: Text(
'Data Nasabah',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
// Text("Data Nasabah"),
columns: [
DataColumn(
label: Expanded(
child: Text(
'ID Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Nama Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Aksi',
textAlign: TextAlign.center,
)),
),
],
source: NasabahDataTableSource(userData: _nasabah, context: context),
),
),
);
}
}
class NasabahDataTableSource extends DataTableSource {
BuildContext context;
NasabahDataTableSource({this.context, this.userData});
final List<Nasabah> userData;
#override
DataRow getRow(int index) {
return DataRow.byIndex(
index: index,
cells: [
DataCell(Align(
alignment: Alignment.center,
child: Text(
"${userData[index].id}",
))),
DataCell(Align(
alignment: Alignment.center,
child: Text("${userData[index].nama_debitur}"),
)),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(Icons.navigate_next),
color: Colors.blueAccent,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailNasabah(
nasabah: userData[index],
),
),
);
},
),
IconButton(
icon: Icon(Icons.delete),
color: Colors.red,
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Hapus Data Nasabah'),
content: Text(
'Apakah anda yakin ingin menghapus data nasabah ini?'),
actions: [
FlatButton(child: Text('Yes'), onPressed: () {
NasabahService.deleteUser(userData[index].id);
Navigator.pop(context);
})
],
),
);
},
)
],
),
),
// DataCell(
// FlatButton(
// child: Icon(
// Icons.chevron_right,
// color: Colors.red,
// ),
// onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => DetailNasabah(
// nasabah: userData[index],
// ),
// ),
// );
// },
// ),
// ),
],
);
}
#override
bool get isRowCountApproximate => false;
#override
int get rowCount => userData.length;
#override
int get selectedRowCount => 0;
void sort<T>(Comparable<T> getField(Nasabah d), bool ascending) {
userData.sort((Nasabah a, Nasabah b) {
if (!ascending) {
final Nasabah c = a;
a = b;
b = c;
}
final Comparable<T> aValue = getField(a);
final Comparable<T> bValue = getField(b);
return Comparable.compare(aValue, bValue);
});
notifyListeners();
}
}
Api
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
class Network {
final String _url = 'http://192.168.100.207:8080/api/';
// 192.168.1.2 is my IP, change with your IP address
var token;
_getToken() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
token = jsonDecode(localStorage.getString('token'));
}
auth(data, apiURL) async {
var fullUrl = _url + apiURL;
return await http.post(fullUrl,
body: jsonEncode(data), headers: _setHeaders());
}
getData(apiURL) async {
var fullUrl = _url + apiURL;
await _getToken();
return await http.get(
fullUrl,
headers: _setHeaders(),
);
}
deleteData(apiURL, id) async {
var fullUrl = _url + apiURL + '/' + id.toString();
await _getToken();
return await http.delete(
fullUrl,
headers: _setHeaders(),
);
}
_setHeaders() => {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
};
}
Service
import 'package:flutter_auth/Models/nasabah.dart';
import 'api.dart';
import 'dart:convert';
class NasabahService {
static String baseUrl = "mstdebitur";
static Future<List<Nasabah>> getUser() async {
final response = await Network().getData(baseUrl);
List<Nasabah> list = parseResponse(response.body);
return list;
}
static Future<List<Nasabah>> deleteUser(id) async {
final response = await Network().deleteData(baseUrl, id);
List<Nasabah> list = parseResponse(response.body);
return list;
}
static List<Nasabah> parseResponse(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Nasabah>((json) => Nasabah.fromJson(json)).toList();
}
}
I am using some code from an older version of File Picker, the null safety version will mess up my other code so I'm using 1.1.1.
the code isn't incorrect because it the same on the file picker package example. can anyone help plz?
the code goes as followed
void openFileExplorer() async {
try {
_path = null;
if (_multiPick) {
_paths = await FilePicker.getMultiFilePath(
type: _pickType, **fileExtension**: _extension);
} else {
_path = await FilePicker.getFilePath(
type: _pickType, **fileExtension**: _extension);
}
uploadToFirebase();
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
}
if (!mounted) return;
}
Try this one
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
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,
),
home: UploadMultipleImageDemo(),
);
}
}
class UploadMultipleImageDemo extends StatefulWidget {
UploadMultipleImageDemo() : super();
final String title = 'Firebase Storage';
#override
UploadMultipleImageDemoState createState() => UploadMultipleImageDemoState();
}
class UploadMultipleImageDemoState extends State<UploadMultipleImageDemo> {
//
String _path;
Map<String, String> _paths;
List<String> extensions;
FileType _pickType;
bool _multiPick = false;
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
List<StorageUploadTask> _tasks = <StorageUploadTask>[];
void openFileExplorer() async {
try {
_path = null;
if (_multiPick) {
_paths = await FilePicker.getMultiFilePath(
type: _pickType, allowedExtensions: extensions);
} else {
_path = await FilePicker.getFilePath(
type: _pickType, allowedExtensions: extensions);
}
//uploadToFirebase();
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
}
if (!mounted) return;
}
// uploadToFirebase() {
// if (_multiPick) {
// _paths.forEach((fileName, filePath) => {upload(fileName, filePath)});
// } else {
// if (_path != null) {
// String fileName = _path
// .split('/')
// .last;
// String filePath = _path;
// upload(fileName, filePath);
// }
// }
// }
// upload(fileName, filePath) {
// extensions = fileName.toString().split('.').last as List<String>;
// StorageReference storageRef =
// FirebaseStorage.instance.ref().child(fileName);
// final StorageUploadTask uploadTask = storageRef.putFile(
// File(filePath),
// StorageMetadata(
// contentType: '$_pickType/$extensions',
// ),
// );
// setState(() {
// _tasks.add(uploadTask);
// });
// extensions = null;
// }
dropDown() {
return DropdownButton(
hint: new Text('Select'),
value: _pickType,
items: <DropdownMenuItem>[
new DropdownMenuItem(
child: new Text('Audio'),
value: FileType.audio,
),
new DropdownMenuItem(
child: new Text('Image'),
value: FileType.image,
),
new DropdownMenuItem(
child: new Text('Video'),
value: FileType.video,
),
new DropdownMenuItem(
child: new Text('Any'),
value: FileType.any,
),
],
onChanged: (value) => setState(() {
_pickType = value;
}),
);
}
String _bytesTransferred(StorageTaskSnapshot snapshot) {
return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';
}
#override
Widget build(BuildContext context) {
final List<Widget> children = <Widget>[];
_tasks.forEach((StorageUploadTask task) {
final Widget tile = UploadTaskListTile(
task: task,
onDismissed: () => setState(() => _tasks.remove(task)),
onDownload: () => downloadFile(task.lastSnapshot.ref),
);
children.add(tile);
});
return new MaterialApp(
home: new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: Text(widget.title),
),
body: new Container(
padding: EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
dropDown(),
SwitchListTile.adaptive(
title: Text('Pick multiple files', textAlign: TextAlign.left),
onChanged: (bool value) => setState(() => _multiPick = value),
value: _multiPick,
),
OutlineButton(
onPressed: () => openFileExplorer(),
child: new Text("Open file picker"),
),
SizedBox(
height: 20.0,
),
Flexible(
child: ListView(
children: children,
),
),
],
),
),
),
);
}
Future<void> downloadFile(StorageReference ref) async {
final String url = await ref.getDownloadURL();
final http.Response downloadData = await http.get(url);
final Directory systemTempDir = Directory.systemTemp;
final File tempFile = File('${systemTempDir.path}/tmp.jpg');
if (tempFile.existsSync()) {
await tempFile.delete();
}
await tempFile.create();
final StorageFileDownloadTask task = ref.writeToFile(tempFile);
final int byteCount = (await task.future).totalByteCount;
var bodyBytes = downloadData.bodyBytes;
final String name = await ref.getName();
final String path = await ref.getPath();
print(
'Success!\nDownloaded $name \nUrl: $url'
'\npath: $path \nBytes Count :: $byteCount',
);
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.white,
content: Image.memory(
bodyBytes,
fit: BoxFit.fill,
),
),
);
}
}
class UploadTaskListTile extends StatelessWidget {
const UploadTaskListTile(
{Key key, this.task, this.onDismissed, this.onDownload})
: super(key: key);
final StorageUploadTask task;
final VoidCallback onDismissed;
final VoidCallback onDownload;
String get status {
String result;
if (task.isComplete) {
if (task.isSuccessful) {
result = 'Complete';
} else if (task.isCanceled) {
result = 'Canceled';
} else {
result = 'Failed ERROR: ${task.lastSnapshot.error}';
}
} else if (task.isInProgress) {
result = 'Uploading';
} else if (task.isPaused) {
result = 'Paused';
}
return result;
}
String _bytesTransferred(StorageTaskSnapshot snapshot) {
return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';
}
#override
Widget build(BuildContext context) {
return StreamBuilder<StorageTaskEvent>(
stream: task.events,
builder: (BuildContext context,
AsyncSnapshot<StorageTaskEvent> asyncSnapshot) {
Widget subtitle;
if (asyncSnapshot.hasData) {
final StorageTaskEvent event = asyncSnapshot.data;
final StorageTaskSnapshot snapshot = event.snapshot;
subtitle = Text('$status: ${_bytesTransferred(snapshot)} bytes sent');
} else {
subtitle = const Text('Starting...');
}
return Dismissible(
key: Key(task.hashCode.toString()),
onDismissed: (_) => onDismissed(),
child: ListTile(
title: Text('Upload Task #${task.hashCode}'),
subtitle: subtitle,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Offstage(
offstage: !task.isInProgress,
child: IconButton(
icon: const Icon(Icons.pause),
onPressed: () => task.pause(),
),
),
Offstage(
offstage: !task.isPaused,
child: IconButton(
icon: const Icon(Icons.file_upload),
onPressed: () => task.resume(),
),
),
Offstage(
offstage: task.isComplete,
child: IconButton(
icon: const Icon(Icons.cancel),
onPressed: () => task.cancel(),
),
),
Offstage(
offstage: !(task.isComplete && task.isSuccessful),
child: IconButton(
icon: const Icon(Icons.file_download),
onPressed: onDownload,
),
),
],
),
),
);
},
);
}
}
I'm learning Flutter and I'm trying to use the SQFLite package to persist data on the device. Everything works perfect but there's one problem, every time I add a new element or I upgrade it, I need to restart my app to see the changes and I don't know why, there are no errors or anything.
I uploaded it to github so you can try it, maybe is something in my emulator or something I dont know.
https://github.com/Rodrigogzmn6/sql_demo
or you can see part of the complete project here
Home Page
import 'package:flutter/material.dart';
import 'package:sql_demo/models/product.dart';
import 'package:sql_demo/pages/add_product_page.dart';
import 'package:sql_demo/pages/update_product_page.dart';
import 'package:sql_demo/pages/view_product_page.dart';
import 'package:sql_demo/services/dbhelper.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DbHelper helper;
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: FutureBuilder(
future: helper.getProducts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Product product = Product.fromMap(snapshot.data[index]);
return ListTile(
contentPadding: const EdgeInsets.all(16.0),
title: Text(
'${product.name} - \$${(product.price).toString()}'),
subtitle: Text(product.description),
trailing: Column(
children: [
Expanded(
child: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
setState(() {
helper.deleteProduct(product.id);
});
}),
),
SizedBox(
height: 20.0,
),
Expanded(
child: IconButton(
icon: Icon(
Icons.edit,
color: Colors.blue,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UpdateProductPage(
product: product,
)),
);
}),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailsPage(
product: product,
)));
},
);
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
color: Colors.white,
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AddProductPage()));
}),
);
}
}
Creating Item page
import 'package:flutter/material.dart';
import 'package:sql_demo/models/product.dart';
import 'package:sql_demo/services/dbhelper.dart';
class AddProductPage extends StatefulWidget {
#override
_AddProductPageState createState() => _AddProductPageState();
}
class _AddProductPageState extends State<AddProductPage> {
String name, description;
num price;
DbHelper helper;
//Instantiate Helper
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add new product"),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product name',
labelText: 'Product name',
),
onChanged: (value) {
setState(() {
name = value;
});
},
),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product description',
labelText: 'Product description',
),
onChanged: (value) {
setState(() {
description = value;
});
},
),
SizedBox(height: 16),
TextFormField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Enter product price',
labelText: 'Product price',
),
onChanged: (value) {
setState(() {
price = double.parse(value);
});
},
),
SizedBox(height: 16),
RaisedButton(
child: Text('Save'),
onPressed: () {
Product product = Product({
'name': name,
'description': description,
'price': price,
});
setState(() {
helper.createProduct(product);
Navigator.pop(context);
});
},
),
],
),
);
}
}
Database operations
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sql_demo/models/product.dart';
class DbHelper {
//Creates a singleton class (it only creates once)
static final DbHelper _singleton = DbHelper._internal();
factory DbHelper() => _singleton;
DbHelper._internal();
//Creating an object of type database
static Database _database;
//Initializing or creating the database named mydb.db
//Creating a products table with necessary fields
Future<Database> initDatabase() async {
//If this class was never instaciated, we will execute this method, otherwise return
if (_database != null) return _database;
String path = join(await getDatabasesPath(), 'mydb.db');
_database = await openDatabase(
path,
version: 1,
onCreate: (Database db, int v) async {
await db.execute(
'CREATE TABLE Products (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, price REAL)');
},
);
return _database;
}
//Select all products
Future<List> getProducts() async {
Database db = await initDatabase();
return await db.query('Products');
}
//Create new product
Future<int> createProduct(Product product) async {
Database db = await initDatabase();
print('Product added');
return await db.insert(
'Products',
product.toMap(),
);
}
//Update product
Future<int> updateProduct(Product product) async {
Database db = await initDatabase();
return await db.update(
'Products',
product.toMap(),
where: 'id=?',
whereArgs: [product.id],
);
}
//Delete a product
Future<int> deleteProduct(int productID) async {
Database db = await initDatabase();
return await db.delete('Products', where: 'id=?', whereArgs: [productID]);
}
}
You can copy paste run full code below
You can await Navigator.push to AddProductPage and then call setState(() {});
code snippet
onPressed: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => AddProductPage()));
setState(() {});
}),
working demo
full code
import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:convert';
class Product {
int _id;
String _name;
String _description;
double _price;
//Getters because the attributes are private
int get id => _id;
String get name => _name;
String get description => _description;
double get price => _price;
//Constructor
Product(dynamic obj) {
_id = obj['id'];
_name = obj['name'];
_description = obj['description'];
_price = obj['price'];
}
//Named objet (takes a Map as parameter)
Product.fromMap(Map<String, dynamic> data) {
_id = data['id'];
_name = data['name'];
_description = data['description'];
_price = data['price'];
}
//Method that converts the object into a map
Map<String, dynamic> toMap() {
return {
'id': _id,
'name': _name,
'description': _description,
'price': _price,
};
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DbHelper helper;
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: FutureBuilder(
future: helper.getProducts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Product product = Product.fromMap(snapshot.data[index]);
return ListTile(
contentPadding: const EdgeInsets.all(16.0),
title: Text(
'${product.name} - \$${(product.price).toString()}'),
subtitle: Text(product.description),
trailing: Column(
children: [
Expanded(
child: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
setState(() {
helper.deleteProduct(product.id);
});
}),
),
SizedBox(
height: 20.0,
),
Expanded(
child: IconButton(
icon: Icon(
Icons.edit,
color: Colors.blue,
),
onPressed: () {
/*Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UpdateProductPage(
product: product,
)),
);*/
}),
),
],
),
onTap: () {
/*Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailsPage(
product: product,
)));*/
},
);
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
color: Colors.white,
),
onPressed: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => AddProductPage()));
setState(() {});
}),
);
}
}
class AddProductPage extends StatefulWidget {
#override
_AddProductPageState createState() => _AddProductPageState();
}
class _AddProductPageState extends State<AddProductPage> {
String name, description;
num price;
DbHelper helper;
//Instantiate Helper
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add new product"),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product name',
labelText: 'Product name',
),
onChanged: (value) {
setState(() {
name = value;
});
},
),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product description',
labelText: 'Product description',
),
onChanged: (value) {
setState(() {
description = value;
});
},
),
SizedBox(height: 16),
TextFormField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Enter product price',
labelText: 'Product price',
),
onChanged: (value) {
setState(() {
price = double.parse(value);
});
},
),
SizedBox(height: 16),
RaisedButton(
child: Text('Save'),
onPressed: () {
Product product = Product({
'name': name,
'description': description,
'price': price,
});
setState(() {
helper.createProduct(product);
Navigator.pop(context);
});
},
),
],
),
);
}
}
class DbHelper {
//Creates a singleton class (it only creates once)
static final DbHelper _singleton = DbHelper._internal();
factory DbHelper() => _singleton;
DbHelper._internal();
//Creating an object of type database
static Database _database;
//Initializing or creating the database named mydb.db
//Creating a products table with necessary fields
Future<Database> initDatabase() async {
//If this class was never instaciated, we will execute this method, otherwise return
if (_database != null) return _database;
String path = join(await getDatabasesPath(), 'mydb.db');
_database = await openDatabase(
path,
version: 1,
onCreate: (Database db, int v) async {
await db.execute(
'CREATE TABLE Products (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, price REAL)');
},
);
return _database;
}
//Select all products
Future<List> getProducts() async {
Database db = await initDatabase();
return await db.query('Products');
}
//Create new product
Future<int> createProduct(Product product) async {
Database db = await initDatabase();
print('Product added');
return await db.insert(
'Products',
product.toMap(),
);
}
//Update product
Future<int> updateProduct(Product product) async {
Database db = await initDatabase();
return await db.update(
'Products',
product.toMap(),
where: 'id=?',
whereArgs: [product.id],
);
}
//Delete a product
Future<int> deleteProduct(int productID) async {
Database db = await initDatabase();
return await db.delete('Products', where: 'id=?', whereArgs: [productID]);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(),
);
}
}
Hot reload: Hot reload feature quickly compile the newly added code in our file and sent the code to Dart Virtual Machine. If you are using States in your application then Hot Reload preservers the States so they will not update on Hot Reload our set to their default values.
And, initState() does not rebuild after hot reload as its state is preserved. So, you have to perform hot restart to see database changes:
#override
void initState() {
super.initState();
helper = DbHelper();
}
When stateful widget is build, you have helper, but after you hot reload, the helper will be same as initState only called hot restart or you launch the widget. So, helper variable is preserved. Hence, you have to hot restart.
Links that might help you: Understanding Flutter hot reload and hot restart the simplest way | Refs
I need to shape myUrl inside Future related to username which I got from myfirstpage, I can get the name and use it in my homepage title but I couldn't figured out how can I use it in myUrl(instead of "$_name"),
Probably I made a mistake with point to data with "pushNamed(MyHomePage.routeName);" actually I don't need that value in MyHomePage, I just need it for shape myUrl line, also I tried to make "_name" value as a global value etc just not couldn't succeed..
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
Future<bool> saveNamedPreference(String name) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("name", name);
return prefs.commit();
}
Future<String> getNamePreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String name = prefs.getString("name");
return name;
}
Payload payloadFromJson(String str) {
return Payload.fromJson(json.decode(str));
}
String payloadToJson(Payload data) {
return json.encode(data.toJson());
}
Future<Payload> getData() async{
String myUrl = 'http://lunedor.pythonanywhere.com/query?username=$_name';
http.Response response = await http.get(myUrl);
print(myUrl);
return response == null ? getData() : payloadFromJson(response.body);
}
class Payload {
String moviecast;
String moviedirectors;
String moviegenre;
String movieposterurl;
String movierating;
String movieruntime;
String moviesummary;
String movietitle;
String moviewriters;
String movieyear;
Payload({
this.moviecast,
this.moviedirectors,
this.moviegenre,
this.movieposterurl,
this.movierating,
this.movieruntime,
this.moviesummary,
this.movietitle,
this.moviewriters,
this.movieyear,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
moviecast: json["Actors"],
moviedirectors: json["Director"],
moviegenre: json["Genre"],
movieposterurl: json["Poster"],
movierating: json["imdbRating"],
movieruntime: json["Runtime"],
moviesummary: json["Plot"],
movietitle: json["Title"],
moviewriters: json["Writer"],
movieyear: json["Year"],
);
Map<String, dynamic> toJson() => {
"moviecast": moviecast,
"moviedirectors": moviedirectors,
"moviegenre": moviegenre,
"movieposterurl": movieposterurl.replaceAll('300.jpg', '900.jpg'),
"movierating": movierating,
"movieruntime": movieruntime,
"moviesummary": moviesummary,
"movietitle": movietitle,
"moviewriters": moviewriters,
"movieyear": movieyear,
};
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Random Movie',
theme: new ThemeData(
primarySwatch: Colors.grey,
),
home: new MyFirstPage(),
routes: <String, WidgetBuilder>{
MyHomePage.routeName: (context) => new MyHomePage(),
},
);
}
}
class MyFirstPage extends StatefulWidget {
#override
_MyFirstPageState createState() => new _MyFirstPageState();
}
class _MyFirstPageState extends State<MyFirstPage>{
var _controller = new TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
backgroundColor: Colors.blueGrey,
centerTitle: true,
title: new Text("Please enter your Trakt username",
style: new TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
),
body: new ListView(
children: <Widget>[
new ListTile(
title: new TextField(
controller: _controller,
),
),
new ListTile(
title: new RaisedButton(
child: new Text("Submit"),
onPressed:(){setState(() {
saveName();
});
}),
)
],
),
);
}
void saveName() {
String name = _controller.text;
saveNamedPreference(name).then((bool committed) {
Navigator.of(context).pushNamed(MyHomePage.routeName);
});
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
static String routeName = "/myHomePage";
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
Payload payload;
class _MyHomePageState extends State<MyHomePage> {
Modal modal = Modal();
bool isLoading = true;
String _name = "";
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {loadData();
WidgetsBinding.instance.addPostFrameCallback((_) => _refreshIndicatorKey.currentState.show());
getNamePreferences().then(updateName);
});
}
void loadData() async {
payload = await getData();
isLoading = false;
setState(() {});
print('${payload.movieposterurl.replaceAll('300.jpg', '900.jpg')}');
}
void updateName(String name) {
setState(() {
this._name = name;
ValueKey(_name);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar:
AppBar(
backgroundColor: Colors.blueGrey,
title:
isLoading ? Center(child: CircularProgressIndicator()):Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Center(
child: Text('${payload.movietitle}', maxLines: 2, textAlign: TextAlign.center,
style: new TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
),
Text('${payload.movieyear}' + " - " + _name + " - " + '${payload.movierating}',
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
fontStyle: FontStyle.italic,),
),
]
),
),
),
body:
isLoading ? Center(child: CircularProgressIndicator()):
RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: () async{payload = await getData();
isLoading = false;
setState(() {});
},
child: Center(
child:ListView(
shrinkWrap: true,
children: [
FittedBox(
alignment: Alignment.center,
child:
Image.network('${payload.movieposterurl.replaceAll('300.jpg', '900.jpg')}'),
),
]
)
)
),
bottomNavigationBar: isLoading ? Center(child: CircularProgressIndicator()):
BottomAppBar(
child: Container(
color: Colors.grey,
child: SizedBox(
width: double.infinity,
child:
FlatButton(
color: Colors.grey,
textColor: Colors.black,
onPressed: () {
modal.mainBottomSheet(context);
},
child: Text("Details",
style: TextStyle(fontSize: 16.0),),
),
),
),
),
);
}
}
class Modal {
mainBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
_createTile(
context, "Genre: " + payload.moviegenre + "\n" + "Runtime: " + payload.movieruntime, Icons.local_movies,
_action),
_createTile(
context, "Director: " + payload.moviedirectors,
Icons.movie_creation,
_action),
_createTile(
context, "Writer: " + payload.moviewriters,
Icons.movie,
_action),
_createTile(
context, "Cast: " + payload.moviecast, Icons.chrome_reader_mode,
_action),
_createTile(
context, "Summary: " + payload.moviesummary, Icons.recent_actors, _action),
],
),
);
}
);
}
ListTile _createTile(BuildContext context, String name, IconData icon,
Function action) {
return ListTile(
leading: Icon(icon),
title: Text(name),
onTap: () {
Navigator.pop(context);
action();
},
);
}
_action() {
print('action');
}
}
Not completely sure I got your question, but it should be enough to modify your getData() method to accept a String in parameters, at the moment getData() is a top-level function that doesn't know the _name value because is a private instance variable of _MyHomePageState
Future<Payload> getData(String name) async{
String myUrl = 'http://lunedor.pythonanywhere.com/query?username=$name';
http.Response response = await http.get(myUrl);
print(myUrl);
return response == null ? getData() : payloadFromJson(response.body);
}
And then in your loadData() method pass the correct value
void loadData() async {
payload = await getData(_name);
isLoading = false;
setState(() {});
print('${payload.movieposterurl.replaceAll('300.jpg', '900.jpg')}');
}
One last thing, you should add the "reload" logic when you change the name
void updateName(String name) {
setState(() {
isLoading = true;
this._name = name;
ValueKey(_name);
loadData();
});
}
Personally I think that the Payload variable should stay inside your _MyHomePageState class