How do I make mutiple icons go to different url's - flutter

I have my app which has some icons, the problem is that I set the icons as extensions/parents of one icon, so when I set an icon to go to a url all other icons go to that url too. But that is not what I want, I want each icon to go to a separate url.
The code for the extended icons is:
`
Row(
children: [
Expanded(
child: TaskCard(
label: "Teachers",
)),
Expanded(
child: TaskCard(
imageUrl: "assets/school-bag.png",
label: "EduPage",
pageUrl: "https://willowcosta.edupage.org",
)),
`
error displayed:
and the code for the parent icon is:
SizedBox(
height: 20.0,
),
Text(
"Sections",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
fontFamily: "SpaceGrotesk",
color: Colors.black),
),
//Here we set the "Shortcuts"
//If you click Teachers it will take you the page where you can see the Teachers -
//names a nd availabity alongs side the subject they teach
//If you click EduPage it takes you to edupage
//If you click Timetable it takes you to the Timetable generator
//If you click Messages it asks you to join a messenger Gc of Students of your class
Row(
children: [
Expanded(
child: TaskCard(
label: "Teachers",
)),
Expanded(
child: TaskCard(
imageUrl: "assets/school-bag.png",
label: "EduPage",
pageUrl: "https://willowcosta.edupage.org",
)),
Expanded(
child: TaskCard(
imageUrl: "assets/timetable.png",
label: "Timetable",
)),
Expanded(
child: TaskCard(
imageUrl: "assets/message.png",
label: "Messages",
)),
],
),
//Here we set the tasks that we have
const SizedBox(
height: 20.0,
),
const Text(
"You have 6 tasks for this week",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
fontFamily: "SpaceGrotesk",
color: Colors.black),
),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const SizedBox(
height: 100.0,
),
],
),
),
),
bottomSheet: const BottomSheetCard(),
);
}
}
//hier the first class ends
class TaskCard extends StatelessWidget {
final String? imageUrl;
final String? label;
const TaskCard({Key? key, this.imageUrl, this.label}) : super(key: key);
//Function to launch the selected url
Future<void> goToWebPage(String urlString) async {
final Uri _url = Uri.parse(urlString);
if (!await launchUrl(_url)) {
throw 'Could not launch $_url';
}
}
#override
Widget build(BuildContext context) {
return Padding(
//Here we set the properties of our Sections (Teachers etc)
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
height: 80.0,
width: 76.1,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.0),
boxShadow: [
BoxShadow(
color: Colors.grey, blurRadius: 2.0, spreadRadius: 0.5),
]),
child: IconButton(
onPressed: () async {
await goToWebPage(pageUrl);
},
icon: Image.asset(
imageUrl ?? "assets/teacher.png",
height: 75.0,
width: 70.0,
),
),
),
SizedBox(
height: 10.0,
),
Text(
label ?? "",
style: TextStyle(fontSize: 16.0),
)
],
),
);
}
}
error 2 displayed:
My app looks like this:
I want each icon to take me to a different website

In your parent icon you can define new string variable in constructor and name it pageUrl like two other variable imageUrl, label, now use it lie this:
onPressed: () async {
await goToWebPage(pageUrl);
},
then pass it like this:
Expanded(
child: TaskCard(
imageUrl: "assets/school-bag.png",
label: "EduPage",
pageUrl: "https://willowcosta.edupage.org",
),
),
Full Example of TaskCard calss:
class TaskCard extends StatelessWidget {
final String imageUrl;
final String label;
final String pageUrl;//<-- add this
const TaskCard(
{Key? key,
required this.imageUrl,
required this.label,
required this.pageUrl})//<-- add this
: super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
height: 80.0,
width: 76.1,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.0),
boxShadow: [
BoxShadow(
color: Colors.grey, blurRadius: 2.0, spreadRadius: 0.5),
]),
child: IconButton(
onPressed: () async {
await goToWebPage(pageUrl);//<-- add this
},
icon: Image.asset(
imageUrl ?? "assets/teacher.png",
height: 75.0,
width: 70.0,
),
),
),
SizedBox(
height: 10.0,
),
Text(
label ?? "",
style: TextStyle(fontSize: 16.0),
)
],
),
);
}
}

Related

How do I make it so that when I click an icon it opens another page file in flutter

How do I make it so that when I click an icon it opens another page file in flutter? I have this icons which when you click them it redirects you to a url, I want to make it so when you click one specific icon instead of opening a url it opens another page file, acting like a navigator.push...
But when I add an ontap to my taskcard I get an error, I had set the pageUrl = "", but it didn't return anything so I removed the this.required pageUrl and changed to this.pageUrl and now I have this error The parameter 'pageUrl' can't have a value of 'null' because of its type, but the implicit default value is 'null', my code is like this:
import 'dart:ui';
import 'package:url_launcher/url_launcher.dart';
import '';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:schoolmanagement/nav_bar.dart';
class DinningScreen extends StatefulWidget {
const DinningScreen({super.key});
#override
State<DinningScreen> createState() => _DinningState();
}
class _DinningState extends State<DinningScreen> {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavBar(),
key: scaffoldKey,
appBar: AppBar(...),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffF6FECE), Color(0xffB6C0C8)],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
tileMode: TileMode.clamp),
),
//Here we set the "Manage your ... box and it's properties"
padding: const EdgeInsets.all(12.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(...),
SizedBox(
height: 20.0,
),
Text(
"Sections",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
fontFamily: "SpaceGrotesk",
color: Colors.black),
),
//Here we set the "Shortcuts"
//If you click Teachers it will take you the page where you can see the Teachers -
//names a nd availabity alongs side the subject they teach
//If you click EduPage it takes you to edupage
//If you click Timetable it takes you to the Timetable generator
//If you click Messages it asks you to join a messenger Gc of Students of your class
Row(
children: [
Expanded(
child: TaskCard(
label: "Teachers",
pageUrl: "",
)),
Expanded(
child: TaskCard(
imageUrl: "assets/school-bag.png",
label: "EduPage",
pageUrl: "https://willowcosta.edupage.org",
)),
//This is what I want to change from going to url to another page
Expanded(
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
},
child: TaskCard(
imageUrl: "assets/timetable.png",
pageUrl: "",
label: "Timetable",
),
)),
Expanded(
child: TaskCard(
imageUrl: "assets/message.png",
pageUrl: "https://www.messenger.com",
label: "Messages",
)),
],
),
//Here we set the tasks that we have
const SizedBox(
height: 20.0,
),
const Text(
"You have 6 tasks for this week",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
fontFamily: "SpaceGrotesk",
color: Colors.black),
),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const TaskContainer(),
const SizedBox(
height: 100.0,
),
],
),
),
),
The TaskCard definition is here:
class TaskCard extends StatelessWidget {
final String? imageUrl;
final String? label;
final String pageUrl;
const TaskCard(
{Key? key, this.imageUrl, required this.label, required this.pageUrl})
: super(key: key);
//Function to launch the selected url
Future<void> goToWebPage(String urlString) async {
final Uri _url = Uri.parse(urlString);
if (!await launchUrl(_url)) {
throw 'Could not launch $_url';
}
}
#override
Widget build(BuildContext context) {
return Padding(
//Here we set the properties of our Sections (Teachers etc)
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
height: 80.0,
width: 76.1,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.0),
boxShadow: [
BoxShadow(
color: Colors.grey, blurRadius: 2.0, spreadRadius: 0.5),
]),
child: IconButton(
onPressed: () async {
if(pageUrl !=""){
await goToWebPage(pageUrl);
}
},
icon: Image.asset(
imageUrl ?? "assets/teacher.png",
height: 75.0,
width: 70.0,
),
),
),
SizedBox(
height: 10.0,
),
Text(
label ?? "",
style: TextStyle(fontSize: 16.0),
)
],
),
);
}
}
The parameter 'pageUrl' can't have a value of 'null' because of its
type, but the implicit default value is 'null'.
Check whether the pageUrl is an empty String. If it is an empty String, don't call goToWebPage.
onPressed: () async {
if(pageUrl !=""){
await goToWebPage(pageUrl);
}
},

Make a list tile button turn grey when clicked

How can I make individual buttons turn grey when I click on approve?
The screenshot is below
Below is the List Tile widget code
Widget pendingList({
required String title,
required String subtitle,
required String leading,
onTap,
}) {
return Row(
children: [
Expanded(
flex: 6,
child: Card(
child: ListTile(
leading: Container(
padding: const EdgeInsets.only(left: 15.0),
alignment: Alignment.center,
height: 50,
width: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.0),
image: DecorationImage(
image: NetworkImage(
'therul'),
fit: BoxFit.cover,
),
),
),
title: Text(
title,
style: TextStyle(
fontSize: BtnFnt2,
fontWeight: FontWeight.w600,
),
),
subtitle: Text(
subtitle,
style: TextStyle(
fontSize: littleTexts,
),
),
),
),
),
Expanded(
flex: 2,
child: Bounce(
duration: const Duration(milliseconds: 100),
onPressed: onTap,
child: Container(
padding: const EdgeInsets.all(15.0),
color: appOrange,
child: Text(
'Approve',
style: TextStyle(
color: white,
fontWeight: FontWeight.w500,
),
),
),
),
),
],
);
}
How can I make individual buttons turn grey when I click on approve?
Any idea will be appreciated. Kindly refer to the screenshot and assist if you can.
One way, is to make the card into a stateful widget, like (simplified)
class ColorCard extends StatefulWidget {
const ColorCard({
Key? key,
}) : super(key: key);
#override
State<ColorCard> createState() => _ColorCardState();
}
class _ColorCardState extends State<ColorCard> {
Color col = Colors.white;
#override
Widget build(BuildContext context) {
return Card(
color: col,
child: ListTile(
title: const Text('title'),
subtitle: const Text('subtitle'),
trailing: ElevatedButton(
onPressed: () {
setState(() => col = Colors.grey);
},
child: const Text('click'),
),
),
);
}
}
Alternatively the color could be based on a value stored in an object that extends or 'mixin'-s ChangeNotifier if you want more comprehensive integration.

Flutter- click is responding to every item in listview.builder

I am trying to create a list of items in flutter with listView.builder, i am also using using elevatedButton in my itemBuilder.
i applied setState in button
i want to change value of single item only
but that is applying to every value in list
here is my code
import 'dart:developer';
import 'package:counter_button/counter_button.dart';
import 'package:flutter/material.dart';
import 'package:fooddeliveryapp/apis.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'models/restrauntmenu.dart';
class RestrauntPage extends StatefulWidget {
final String restrauntId;
final String restrauntName;
final String restrauntType;
final String restrauntApproxBill;
final String restrauntTagline;
const RestrauntPage(
{Key? key,
required this.restrauntId,
required this.restrauntType,
required this.restrauntApproxBill,
required this.restrauntTagline,
required this.restrauntName})
: super(key: key);
#override
State<RestrauntPage> createState() => _RestrauntPageState();
}
class _RestrauntPageState extends State<RestrauntPage> {
int _counterValue = 1;
bool itemAdded = false;
late Future<List<RestrauntMenu>> futureRestrauntMenu;
Future<List<RestrauntMenu>> fetchRestrauntMenu() async {
String restrauntId = widget.restrauntId;
final response = await http.get(Uri.parse(menuApi(restrauntId)));
if (response.statusCode == 200) {
final parsed = json.decode(response.body).cast<Map<String, dynamic>>();
return parsed
.map<RestrauntMenu>((json) => RestrauntMenu.fromMap(json))
.toList();
} else {
throw Exception('Failed to load album');
}
}
addToCartButton(
{required String? itemname,
required String? itemprice,
required int? itemCount,
required String? usermob,
required String? restrauntName}) {
return ElevatedButton(
clipBehavior: Clip.antiAliasWithSaveLayer,
style: ButtonStyle(
elevation: MaterialStateProperty.all(
6,
),
backgroundColor: MaterialStateProperty.all(Colors.white),
),
onPressed: () {
addToCart(
itemname: itemname,
itemprice: itemprice,
restrauntName: restrauntName,
usermob: usermob,
itemCount: itemCount);
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'ADD TO CART',
style: TextStyle(
color: Colors.green,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
);
}
counterButton() {
return Container(
decoration: const BoxDecoration(color: Colors.white),
child: CounterButton(
loading: false,
onChange: (int val) {
setState(() {
_counterValue = val;
});
},
count: _counterValue,
countColor: Colors.green,
buttonColor: Colors.black,
progressColor: Colors.black,
),
);
}
Future addToCart(
{required String? itemname,
required String? itemprice,
required int? itemCount,
required String? usermob,
required String? restrauntName}) async {
itemCount = _counterValue;
var url = addToCartApi(
itemname: itemname,
itemprice: itemprice,
itemCount: itemCount,
usermob: usermob,
restrauntName: restrauntName);
var response = await http.get(
Uri.parse(url),
);
if (response.statusCode == 200) {
setState(() {
itemAdded = true;
});
} else {
return false;
}
}
#override
void initState() {
futureRestrauntMenu = fetchRestrauntMenu();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
foregroundColor: Colors.black,
elevation: 0,
backgroundColor: Colors.white,
title: const Text('Restraunt Name'),
),
body: SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.03,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.restrauntName,
style: const TextStyle(
color: Colors.black,
fontSize: 24,
fontWeight: FontWeight.w900,
),
),
// const SizedBox(height: 4),
Text(
widget.restrauntType,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.normal,
),
),
Text(
widget.restrauntTagline,
style: const TextStyle(
color: Colors.black87,
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
const SizedBox(
height: 6,
),
Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: RichText(
text: TextSpan(
children: [
const WidgetSpan(
child: Icon(
Icons.currency_rupee,
size: 16,
color: Color.fromARGB(255, 45, 174, 49),
),
),
TextSpan(
text: widget.restrauntApproxBill,
style: const TextStyle(
color: Colors.black,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
],
),
const Spacer(),
Container(
decoration: BoxDecoration(
color: const Color.fromARGB(255, 49, 171, 53),
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: RichText(
text: const TextSpan(
children: [
TextSpan(
text: '3.6',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
WidgetSpan(
child: Icon(
Icons.star,
color: Colors.white,
size: 18,
),
),
],
),
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.03,
),
],
),
const SizedBox(
height: 12,
),
Expanded(
child: FutureBuilder<List<RestrauntMenu>>(
future: futureRestrauntMenu,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ExpansionTile(
initiallyExpanded: true,
childrenPadding: const EdgeInsets.all(8),
title: Text(
snapshot.data![index].catname!,
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
children: [
Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
snapshot.data![index].itemname!,
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 4,
),
Text(
snapshot.data![index].itemPrice!,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
const SizedBox(
height: 4,
),
Text(
snapshot.data![index].itemDescription!,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
],
),
const Spacer(),
Stack(
alignment: Alignment.bottomCenter,
children: [
Padding(
padding:
const EdgeInsets.only(bottom: 16),
child: ClipRRect(
borderRadius:
BorderRadius.circular(10),
child: FittedBox(
child: Container(
height: MediaQuery.of(context)
.size
.height *
0.22,
width: MediaQuery.of(context)
.size
.width *
0.4,
decoration: BoxDecoration(
color: Colors.red,
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
'http://www.jfamoslogistics.com/images/${snapshot.data![index].itemimage!}',
),
),
),
),
),
),
),
Align(
alignment: Alignment.topRight,
child: itemAdded
? counterButton()
: addToCartButton(
itemprice: snapshot
.data![index].itemPrice,
itemname: snapshot
.data![index].itemname,
itemCount: _counterValue,
restrauntName:
widget.restrauntName,
usermob: '9354954343',
))
],
)
],
),
],
);
},
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
),
],
),
),
),
);
}
}
please check and help me
please let me know if i am missing something or making some mistake in code
i have tried google everywhere but nothing works
thanks in advance
As Giseppe Colucci described, you are using a single counter variable for a list . You can follow the simple approach of using list. On State
int _counterValue = 1; will be replaced with List<int> _counterValue = []
After getting data initialize the list with default value.
if (snapshot.hasData) {
_counterValue =List.generate(snapshot.data!.length, (index) => 1); // you might prefer default value as 0 instead of 1
As for the counter button method we need to update specific index, therefore we will pass index here
counterButton(int index) {
return Container(
decoration: const BoxDecoration(color: Colors.white),
child: CounterButton(
loading: false,
onChange: (int val) {
setState(() {
_counterValue[index] = val;
});
},
count: _counterValue[index],
Now whenever we use this counterButton method we need to pass index and here we get index from listview.
child: itemAdded
? counterButton(index)
: addToCartButton(
That is because your itemAdded bool is only one, for every item in the list, you should make a map, like this:
{'id':true}
where id is the restaurant menu item, and true is whenever the item is selected or not.
If this is too hard for you, just use a simple list.

Move Textfield up when Keyboard apperears inside Bottom Sheet in Flutter

I am currently trying to create some kind of TikTok like comment section in flutter. For this I'm using a ModalBottomSheet and a Expanded Listview with the comments inside. However, I'm failing to archive that my TextField moves up when its selected and the Keyboard appears, meaning I always cant see the Textfield anymore after it's selection. I already tried using a focusnode and animation controller, however it didnt work out because of the Flex container which contains the comments... I know it's much code but please help I really cant figure it out.
The BottomSheet Widget:
void onCommentButtonPressed() {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => Container(
height: MediaQuery.of(context).size.height * 0.75,
decoration: new BoxDecoration(
color: Colors.grey[900],
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0),
),
),
child: Column(
children: <Widget>[
Comments(
postId: targetId,
postOwnerId: ownerId,
),
],
),
),
);
}
and the comment section inside of it:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/Widgets/Images/profile_picture_small.dart';
import 'package:flutter_app/Widgets/header.dart';
import 'package:flutter_app/Widgets/progress.dart';
import 'package:flutter_app/constants.dart';
import 'package:provider/provider.dart';
import '../../Screens/Authenticate/authservice.dart';
import '../../Screens/Authenticate/database.dart';
import '../../models/user.dart';
import 'package:timeago/timeago.dart' as timeago;
class Comments extends StatefulWidget {
final String postId;
final String postOwnerId;
Comments({
required this.postId,
required this.postOwnerId,
});
#override
CommentsState createState() => CommentsState(
postId: postId,
postOwnerId: postOwnerId,
);
}
class CommentsState extends State<Comments> {
TextEditingController commentController = TextEditingController();
final String postId;
final String postOwnerId;
CommentsState({
required this.postId,
required this.postOwnerId,
});
#override
Widget build(BuildContext context) {
return Flexible(
child: Column(
children: [
Expanded(
child: buildComments(),
),
buildTextField(),
],
),
);
}
addComment(){
final currentUser = Provider.of<MyUser>(context, listen: false);
bool isNotPostOwner = postOwnerId != currentUser.id;
commentsRef.doc(postId).collection('comments').add({
'username': currentUser.username,
'comment': commentController.text,
'timestamp': DateTime.now(),
'avatarUrl': currentUser.photoUrl,
'userId': currentUser.id,
});
if(isNotPostOwner) {
activityFeedRef.doc(postOwnerId).collection('feedItems').add({
'type': 'comment',
'commentData': commentController.text,
'username': currentUser.username,
'userId': currentUser.id,
'userProfileImg': currentUser.photoUrl,
'postId': postId,
'timestamp': timestamp,
});
}
commentController.clear();
}
buildComments() {
return StreamBuilder<QuerySnapshot>(
stream: commentsRef.
doc(postId).
collection('comments').
orderBy('timestamp', descending: true).
snapshots(),
builder: (context, snapshot){
if (!snapshot.hasData){
return circularProgress();
}
else {
List<Comment> comments = [];
snapshot.data!.docs.forEach((doc){
comments.add(Comment.fromDocument(doc));
});
return ListView(children: comments,);
}
},
);
}
Widget buildTextField() {
return Container(
padding: EdgeInsets.symmetric(
vertical: kDefaultPadding / 2,
horizontal: kDefaultPadding / 2,
),
decoration: BoxDecoration(
color: Colors.transparent,
boxShadow: [
BoxShadow(
offset: Offset(0, 4),
blurRadius: 32,
color: Colors.blueGrey.withOpacity(0.1),
),
],
),
child: SafeArea(
child: Row(
children: [
ProfilePictureSmall(),
Padding(padding: EdgeInsets.symmetric(horizontal: 5)),
Expanded(
child: Container(
padding: EdgeInsets.symmetric(
horizontal: kDefaultPadding * 0.75,
),
decoration: BoxDecoration(
color: Colors.grey[800],
borderRadius: BorderRadius.circular(40),
),
child: Row(
children: [
SizedBox(width: kDefaultPadding / 4),
Expanded(
child: TextField(
controller: commentController,
decoration: InputDecoration(
hintText: "Write a comment...",
border: InputBorder.none,
),
),
),
InkWell(
onTap: () => addComment(),
child: Container(
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(40.0),
),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Icon(
Icons.arrow_upward_rounded,
color: Theme.of(context)
.textTheme
.bodyText1!
.color!
.withOpacity(0.64),
),
),
),
),
],
),
),
),
],
),
),
);
}
}
class Comment extends StatelessWidget {
final String username;
final String userId;
final String avatarUrl;
final String comment;
final Timestamp timestamp;
Comment({
required this.username,
required this.userId,
required this.avatarUrl,
required this.comment,
required this.timestamp,
});
factory Comment.fromDocument(DocumentSnapshot doc){
return Comment(
username: doc['username'],
userId: doc['userId'],
comment: doc['comment'],
timestamp: doc['timestamp'],
avatarUrl: doc['avatarUrl'],
);
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListTile(
title: RichText(
text: TextSpan(text: '#...$username ',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
children: <TextSpan> [
TextSpan(text: '$comment',
style: Theme.of(context).textTheme.bodyText2),
]
),
),
leading: ProfilePictureSmall(),
subtitle: RichText(
text: TextSpan(
style: TextStyle(
fontSize: 12,
color: Colors.white,
fontWeight: FontWeight.bold,
),
children: <TextSpan> [
TextSpan(text: '${timeago.format(timestamp.toDate(), locale: 'en_short')} ',
style: TextStyle(
color: Colors.grey[400],
fontWeight: FontWeight.w400,
),),
TextSpan(text: '193 Rockets ',
style: TextStyle(
color: Colors.grey[400]
),),
TextSpan(text: 'Reply',
style: TextStyle(
color: Colors.grey[400]
),
),
]
),
),
trailing: buildCommentFooter(context),
),
// Divider(color: Colors.white,),
],
);
}
buildCommentFooter(BuildContext context){
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: ()=> print('pressed'),
child: Icon(
Icons.monetization_on_rounded,
size: 20,
color: Colors.grey,
),
),
],
);
}
}

image_picker only showing images after hot reload. Flutter

I'm using the image_picker package to read images and take them using the camera.
I'm also using the provider package to manage the changes in results.
The app is about ads for selling stuff, when adding a new ad it is added successfully.
the problem is that the ad main image is not showing until I make a hot reload, and before reloading it shows an error.
Unable to load asset: /storage/emulated/0/Android/data/com.bkh.ads/files/Pictures/d2abeed9-3dfa-44b4-a032-ddefff58762e2465964411313585659.jpg
once I make a hot reload the ad image gets shown correctly and the error vanishes.
This is how I'm using image_picker:
Future _setAdMainImage() async {
String _method;
await showModalBottomSheet(
context: context,
builder: (context) => Container(
height: 105,
child: Column(
children: [
Container(
height: 50,
child: RaisedButton(
color: ColorPalette.PRIMARY_COLOR,
onPressed: () {
_method = 'Camera';
Navigator.of(context).pop();
},
child: Center(
child: Text(
'Image From Camera',
textDirection: TextDirection.rtl,
style: TextStyle(
fontSize: 18,
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
),
SizedBox(
height: 5,
),
Container(
height: 50,
child: RaisedButton(
color: ColorPalette.PRIMARY_COLOR,
onPressed: () {
_method = 'Gallery';
Navigator.of(context).pop();
},
child: Center(
child: Text(
'Image From Gallery',
textDirection: TextDirection.rtl,
style: TextStyle(
fontSize: 18,
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
),
],
),
),
);
if (_method != null) {
final _pickedFile = await _imagePicker.getImage(
source: _method == 'Camera' ? ImageSource.camera : ImageSource.gallery,
);
setState(() {
_image = File(_pickedFile.path);
});
_method = null;
}
}
This is how I'm adding the new ad object using the provider:
void addVehicleAd(VehicleAd vehicleAd) {
_vehicleAds.add(vehicleAd);
notifyListeners();
}
This is how I'm showing the results:
#override
Widget build(BuildContext context) {
_data = ModalRoute.of(context).settings.arguments as Map<String, dynamic>;
_ads = Provider.of<VehicleAds>(context).carAds;
return Scaffold(
body: ListView.builder(
itemCount: _ads.length,
itemBuilder: (context, index) => AdCard(
id: _ads[index].id,
image: _ads[index].image,
price: _ads[index].price,
label: _ads[index].label,
date: _ads[index].date,
),
),
);
}
And this is the AdCard widget:
class AdCard extends StatelessWidget {
final int id;
final String label, image;
final int price;
final DateTime date;
AdCard({
#required this.id,
#required this.label,
#required this.price,
#required this.image,
#required this.date,
});
#override
Widget build(BuildContext context) {
var _height = MediaQuery.of(context).size.height;
return InkWell(
child: Card(
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(
width: 2,
color: ColorPalette.ACCENT_COLOR,
),
),
child: Stack(
children: <Widget>[
Container(
height: 250,
width: double.infinity,
child: Hero(
tag: id,
child: Image(
image: AssetImage(image),
fit: BoxFit.cover,
),
),
),
Positioned(
right: 10,
bottom: 10,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black.withOpacity(.5),
),
child: Text(
label,
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
style: TextStyle(
height: 1,
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
Positioned(
left: 10,
bottom: 10,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black.withOpacity(.5),
),
child: Text(
'$price',
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
style: TextStyle(
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: Align(
alignment: Alignment.topCenter,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black.withOpacity(.5),
),
child: Text(
'${date.day}/${date.month}/${date.year}',
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
style: TextStyle(
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
),
],
),
),
);
}
}
I have no idea where the wrong code is...
Any help would be appreciated
AssetImage widget gets from your asset resource.
For images taken by imagepicker, use Image.file.
Image.file(/* your file */, fit: BoxFit.cover,)