Hey guys I am new to flutter, I have been trying to build a mock app that shows a feed it works fine using the mock data, but when I try to add new input data it gets added but doesn't get updated, please help me, I totally understand that my mistake can be super trivial and foolish but I have been stuck for weeks, here is the code. This is the screen where everything is displayed
import 'package:deep_pocket/models/data_feed.dart';
import 'package:deep_pocket/models/mock_data.dart';
import 'package:deep_pocket/widgets/menu_buttons.dart';
import 'package:deep_pocket/widgets/post_widget.dart';
import 'package:deep_pocket/screens/user_input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
class feedScreen extends StatefulWidget {
@override
State<feedScreen> createState() => _feedScreenState();
}
class _feedScreenState extends State<feedScreen> {
int filter = 0;
void updateFilter(tx, context) {
setState(() {
filter = tx;
});
Navigator.of(context).pop();
}
void filterSheet(ctx) {
showModalBottomSheet(
context: ctx,
builder: (ctx) => Container(
height: 300,
child: SingleChildScrollView(
child: Container(
height: 280,
child: ListView.builder(
itemCount: Tag.length,
itemBuilder: (ctx, i) => TextButton(
onPressed: () {
return updateFilter(i, context);
},
child: Text(Tag[i]),
)),
)),
));
}
@override
Widget build(BuildContext context) {
var posts = Provider.of<mockData>(context).items;
print(posts.length);
if (filter != 0) {
posts = posts.where((i) => i.tag == filter).toList();
}
return Scaffold(
// drawer: Drawer(
// // Populate the Drawer in the next step.
// ),
appBar: AppBar(
title: const Text("Home"),
actions: [
TextButton(
onPressed: () => {filterSheet(context)},
child: const Text(
"Filters",
style: TextStyle(color: Colors.white),
))
],
),
body: SingleChildScrollView(
child: Column(
children: [
menuButtons(),
Container(
padding: const EdgeInsets.all(8),
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: posts.length,
itemBuilder: (ctx, i) => postWidget(post: posts[i])),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, userInput.route);
},
child: const Icon(Icons.add)),
);
}
}
This is where I am handling Input
import 'package:deep_pocket/models/data_feed.dart';
import 'package:deep_pocket/models/mock_data.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class userInput extends StatefulWidget {
static const route = '/user-input';
@override
_userInputState createState() => _userInputState();
}
class _userInputState extends State<userInput> {
var _chosenValue = 'all';
final titleController = TextEditingController();
final bodyController = TextEditingController();
void submitted() {
String titleCheck = titleController.text;
String bodyCheck = bodyController.text;
int tag = Tag.indexOf(_chosenValue);
if (titleCheck.isEmpty || bodyCheck.length < 10) {
return;
}
final newPost = dataFeed(
imgsrc: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
name: "Priyam ",
title: titleCheck,
text: bodyCheck,
tag: tag,
);
titleController.dispose();
bodyController.dispose();
Provider.of<mockData>(context, listen: false).addPost(newPost);
Navigator.of(context).pop();
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: submitted,
label: const Text("SUBMIT"),
),
appBar: AppBar(
title: Text("New Post"),
),
body: Container(
child: Column(
children: [
TextField(
controller: titleController,
decoration: const InputDecoration(
label: Text("Title"),
enabledBorder: OutlineInputBorder(),
),
),
TextField(
controller: bodyController,
decoration: const InputDecoration(
label: Text("Body"),
enabledBorder: OutlineInputBorder(),
),
),
DropdownButton<String>(
focusColor: Colors.white,
value: _chosenValue,
//elevation: 5,
style: TextStyle(color: Colors.white),
iconEnabledColor: Colors.black,
items: Tag.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: TextStyle(color: Colors.black),
),
);
}).toList(),
hint: const Text(
"select a tag",
style: TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w500),
),
onChanged: (String? value) {
setState(() {
_chosenValue = value.toString();
});
},
),
],
),
),
);
}
}
This is the mock data class
import 'package:deep_pocket/models/data_feed.dart';
import 'package:flutter/material.dart';
class mockData with ChangeNotifier {
final List<dataFeed> _data = [
dataFeed(
imgsrc: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
name: "Priyam Srivastava",
title: "How to change room ?",
tag: 1,
text:
"I would like to know the process of changing my room cause I have not been able to study, and my roomate always plays music and drinks too much then shouts all night, please tell me how",
),
dataFeed(
imgsrc: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
title: "Anyone intresed in playing BGMI?",
name: "Part Agarwal",
tag: 2,
text:
"So I have been looing for a squad for a long time and now i have finally decided that I am gonna buckle up and ask you all to join me",
),
dataFeed(
imgsrc: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
title: "How to solve this question in O(n) complexity",
name: "Preet Singh",
tag: 3,
text:
"So I have been looing for a squad for a long time and now i have finally decided that I am gonna buckle up and ask you all to join me",
),
];
List<dataFeed> get items {
return [..._data];
}
void addPost(dataFeed newpost) {
final newPost = dataFeed(
imgsrc: newpost.imgsrc,
name: newpost.name,
title: newpost.title,
text: newpost.text,
tag: newpost.tag,
);
_data.insert(0, newPost);
print(_data.length);
notifyListeners();
}
}
Datafield class
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
List<String> Tag = [
'all',
'Query',
'Games',
'Doubt',
'Selling',
'CabShare',
'Announcement',
'OpenDiscussion',
];
class dataFeed with ChangeNotifier {
final String id = DateTime.now().toString();
final String name;
final String title;
final String text;
final String imgsrc;
final DateTime date = DateTime.now();
final int tag;
dataFeed({
required this.imgsrc,
required this.name,
required this.title,
this.tag = 0,
required this.text,
});
CodePudding user response:
Firstly, wrap Scaffold with ChangeNotifierProvider<T>
and change your floating action button onPressed
function like this:
ChangeNotifierProvider<mockData>(
create: (context) => mockData(),
builder: (context, child){
var posts = context.select((mockData m) => m.items);
return Scaffold(
body: SingleChildScrollView(
....
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
//Waiting for result
var newData = await Navigator.pushNamed(context, userInput.route);
if(newData != null){
context.read<mockData>().addPost(newData);
}
},
child: const Icon(Icons.add)),
);
}
);
Secondly, change your submitted
function in userInput
class like this:
void submitted(){
///....
final newPost = dataFeed(
imgsrc: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
name: "Priyam ",
title: titleCheck,
text: bodyCheck,
tag: tag,
);
titleController.dispose();
bodyController.dispose();
//Sending newPost to previous page via Navigator.
Navigator.of(context).pop(newPost); //<- Attention
}
And change the below line in _feedScreenState
for listening the list.
Instead
var posts = Provider.of<mockData>(context).items;
This:
var posts = context.watch<mockData>().items;
//or
var posts = context.select((mockData m) => m.items);
Or add a Selector
widget for listening the list
Selector<mockData, List<dataFeed>>(
selector: (_, m) => m.items,
builder: (_, items, __) => ListView.builder(
//...
itemBuilder: (ctx, i) => postWidget(post: items[i])),
)
)