why is Inkwell not assigned to the parameter Widget? - flutter

I am wondering why a wrapped Inkwell widget is not working on a simple flutter screen. The code is the following:
class SearchButtonState extends State<SearchButton> {
bool folded = true;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: Duration(milliseconds: 400),
width: folded ? 56 : 200,
height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
color: Color(0xFF88B4E0),
boxShadow: kElevationToShadow[6],
),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 16),
child: !folded
? TextField(
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(color: Colors.blue),
border: InputBorder.none),
)
: null,
),
),
Container(
//fixing splash
child: Material(
type: MaterialType.transparency,
child: Inkwell(
//Fixing the BorderRadius of the Splash
BorderRadius: BorderRadius.only(
topLeft: Radius.circular(folded ? 32 : 0),
topRight: Radius.circular(32),
bottomLeft: Radius.circular(folded ? 32 : 0),
bottomRight: Radius.circular(32),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(
folded ? Icons.search : Icons.close,
color: Color(0xFF88B4E0),
),
),
onTap: () {
setState(() {
folded = !folded;
});
},
)))
],
));
}
}
The error is the following: "The argument type 'dynamic' can't be assigned to the parameter type 'widget'". I would appreciate if someone know why do I get this error, since the Inkwell is wrapped.

Change this code Inkwell to InkWell and BorderRadius: to borderRadius:
child: Material(
type: MaterialType.transparency,
child: InkWell(
//Fixing the BorderRadius of the Splash
borderRadius: BorderRadius.only(
...

Related

Animated Listview-item to show more information

I want to add an animation to my ListView items. Therefor I wrapped them in an AnimatedController and made the height dynamic to show more information after the user taped on the item.
Here is my code:
Widget _buildCard(
String logo, Color logoColor, Color cardColor, Color prevColor) {
bool selected = false;
return SliverStickyHeader(
header: GestureDetector(
onTap: (() {
setState(() {
print("taped");
selected = !selected;
});
}),
child: Stack(
children: <Widget>[
Container(
height: 16,
color: prevColor,
),
AnimatedContainer(
duration: const Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
height: selected ? 130 : 60,
decoration: BoxDecoration(
color: selected ? Colors.amber : cardColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16))),
padding: const EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.bottomLeft,
child: Text(
logo,
style: TextStyle(color: logoColor, fontWeight: FontWeight.bold),
),
),
],
),
),
sliver: SliverToBoxAdapter(
child: Container(
height: 20,
color: cardColor,
),
),
);
}
Unfortunately the animation did not execute, does anybody know why? Did I forget anything while implementing the AnimationController to my List?
You don't need to reinvent the wheel. There already is a Widget for this. It's called ExpansionTile.

How to fix a text widget length to a specific length then should keep breaking to the next Line

i have a text widget that contain text, the text does not not overflow but i want to fix it to a specific length then multi line.
so if i fix the length to to 5, immediately it is more than 5 or get to 5 he should break to the next line
here is my code:
ListView.builder(
shrinkWrap: true,
itemCount: recentChats.length,
itemBuilder: (context, index) {
//final sender = recentChats[index].sender;
final auth = recentChats[index].sender.id;
final msg = recentChats[index].content;
//final timestamp = recentChats[index].time;
bool check = auth == 1 ? true : false;
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 15,
vertical: 10,
),
child: Column(
crossAxisAlignment: check
? CrossAxisAlignment.end
: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: check ? Colors.indigo : Colors.white,
borderRadius: check
? BorderRadius.only(
bottomLeft: Radius.circular(30),
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
)
: BorderRadius.only(
bottomRight: Radius.circular(30),
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
),
),
child: Text(
msg,
style: GoogleFonts.raleway(
textStyle: TextStyle(
color:
check ? Colors.white : Colors.black,
),
),
),
)
],
),
);
}),
what i am trying to achieve:
i have try using maxLine but is not achieving what i want....
this is what my code is getting
thanks
try wrapping your text in a ConstrainedBox:
//...
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 50), //<-- set the max width here
child: Text(
msg,
style: GoogleFonts.raleway(
textStyle: TextStyle(
color: check ? Colors.white : Colors.black,
),
),
),
),
//...

Display a widget if the user is an admin flutter

I have a "settings" screen where the user can click on "Admin mode" and then is asked for a password. If this password corresponds to a defined password that I'll give to the admins of the app, he has the app displaying all the admin widgets on the other screens.
I want to set a default admin password, when the user click on the "validate" button, the program check is the password is correct. I have a button on a screen that is like the "admin panel" and I want this button to be displayed only if the user is an admin.
Here is the Dialog I created and where I suppose I'll have to create something to check if the password is correct in the onPressed function.
class DialogModeAdmin extends StatelessWidget {
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
String _passAdmin;
dialogContent(BuildContext context) {
return Container(
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 10.0,
offset: const Offset(0.0, 10.0),
),
],
),
child: SizedBox(
height: 120,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text("Mot de passe"),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: new BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.black,
width: 1,
),
boxShadow: [BoxShadow(
color: Color.fromRGBO(10, 10, 10, 0.25),
blurRadius: 5.0,
spreadRadius: -2.0,
offset: Offset(3.0, 5.0),
)],
borderRadius: BorderRadius.all(Radius.circular(5.0)),
),
child: SizedBox(
height: 30,
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5.0, top: 1.0, bottom: 4.0),
child: FormBuilderTextField(
// validator: FormBuilderValidators.required(context),
decoration: InputDecoration(
border: InputBorder.none,
),
name: 'passadmin',
onChanged: (String value) {
_passAdmin = value;
},
),
)
)
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: SizedBox(
height: 30,
width: 90,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Color.fromRGBO(255, 64, 0, 1.0),
onPrimary: Colors.white,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0))),
),
onPressed: () async{
if(_fbKey.currentState.validate()){
// check if the password is correct and then set a local variable to true to set the privileges of an admin
}
},
child: Text('Valider'),
),
),
),
],
)
)
);
}
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0.0,
backgroundColor: Colors.transparent,
child: dialogContent(context),
);
}
}
You can store a isAdmin boolean in a static way or with ChangeNotifier (similar to observable).
https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple
https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html
Then use this value to show/hide your widgets with the Visibility Widget
https://api.flutter.dev/flutter/widgets/Visibility-class.html
Visibility(
visible: // isAdmin variable,
child: ...
),
EDIT : For your problem to check the password :
class DialogModeAdmin extends StatelessWidget {
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
String _passAdmin;
// This is your password
final String _password = "MyPassword";
dialogContent(BuildContext context) {
...
name: 'passadmin',
// Here you store correctly what the user typed
onChanged: (String value) {
_passAdmin = value;
},
),
...
child: ElevatedButton(
...
onPressed: () async{
if(_fbKey.currentState.validate()){
// check if the password is correct and then set a local variable to true to set the privileges of an admin
// As the comment says :
if(_passAdmin == _password){
// set the static/valueNotifier to true
} else {
// display an error 'wrong password'
}
}
},
child: Text('Valider'),
),
...
}

How to make Container widget take only the required space in flutter?

I am working on a chat application using flutter. In that, I have to create a chat screen containing messages. I want each message container to take only the required space. For example: Short message, short container width & Long message, long container. Currently, it's taking full space of the Column container no matter what's the length of the message.
As a side note, I have tried wrapping the message container inside flexible but it didn't work at all.
Here's my code:
import 'package:flutter/material.dart';
import 'package:memomessenger/Services/Chats.dart';
import 'package:memomessenger/Services/Constants.dart';
import 'package:memomessenger/Services/Types/Chat.dart';
import 'package:memomessenger/Services/Types/ChatsActivity.dart';
import 'package:memomessenger/Services/User.dart';
Widget buildMessageWidget(
BuildContext context, Message message, String currentUserId) {
final bool isFromCurrentUser = message.senderId == currentUserId;
return LimitedBox(
maxWidth: MediaQuery.of(context).size.width * .75,
child: Container(
margin: EdgeInsets.symmetric(vertical: 2),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(
isFromCurrentUser ? 0 : messageBorderRadius,
),
topLeft: Radius.circular(
isFromCurrentUser ? messageBorderRadius : 0,
),
bottomLeft: Radius.circular(messageBorderRadius),
bottomRight: Radius.circular(messageBorderRadius),
),
color: isFromCurrentUser ? themeAccentColor[500] : Colors.cyan,
),
child: Align(
alignment:
isFromCurrentUser ? Alignment.centerRight : Alignment.centerLeft,
child: Text(
message.text,
style: TextStyle(
color: isFromCurrentUser ? Colors.white : Colors.black,
),
),
),
),
);
}
Widget buildChatMessagesUI(BuildContext context, List<Message> messages) {
final String currentUserId = currentUser.value.id;
return SingleChildScrollView(
child: Column(
verticalDirection: VerticalDirection.up,
children: messages.reversed.map((Message message) {
return buildMessageWidget(context, message, currentUserId);
}).toList(),
),
);
}
Widget buildMessageInputUI({#required String chatId}) {
final String currentUserId = currentUser.value.id;
return TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your email',
),
onChanged: (String message) {
sendMessage(chatId, Message(text: message, senderId: currentUserId));
},
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
autofocus: true,
autocorrect: true,
keyboardType: TextInputType.multiline,
);
}
class ChatActivity extends StatelessWidget {
final String chatId;
ChatActivity({#required this.chatId});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: StreamBuilder<Map<String, Chat>>(
stream: chatActivityChatList,
initialData: {},
builder: (BuildContext context,
AsyncSnapshot<Map<String, Chat>> data) {
if (data.hasData && data.data[chatId] != null) {
return buildChatMessagesUI(
context, data.data[chatId].messages);
} else {
return Text("No Data");
}
},
),
),
buildMessageInputUI(chatId: chatId),
],
),
),
),
),
);
}
}
The Align widget sizes itself to its incoming constraints if bounded, and your Container with a decoration is placed around it. This means the decoration will cover the entire width of the column. To fix this, the DecoratedBox (produced by Container) needs to be a descendant of Align instead.
Another problem you may have noticed is that LimitedBox does nothing if the incoming constraint is already bounded. In order to tighten the existing bound, you will need to provide constraints in your Container (or equivalently, a ConstrainedBox widget). FractionallySizedBox might also be worth considering.
Widget buildMessageWidget(
BuildContext context, Message message, String currentUserId) {
final bool isFromCurrentUser = message.senderId == currentUserId;
return Align(
alignment:
isFromCurrentUser ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
margin: EdgeInsets.symmetric(vertical: 2),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .75
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(
isFromCurrentUser ? 0 : messageBorderRadius,
),
topLeft: Radius.circular(
isFromCurrentUser ? messageBorderRadius : 0,
),
bottomLeft: Radius.circular(messageBorderRadius),
bottomRight: Radius.circular(messageBorderRadius),
),
color: isFromCurrentUser ? themeAccentColor[500] : Colors.cyan,
),
child: Text(
message.text,
style: TextStyle(
color: isFromCurrentUser ? Colors.white : Colors.black,
),
),
),
);
}

showModalBottomSheet triggers Futurebuilder

I'm really frustrated on this one.
I have 3 functions that calls showModalBottomSheet in each function.
2 Modals that are Stateful and 1 Stateless.
I'm having problem with the other Stateful Modal.
They are both called using InkWell's onTap function. and both are also not occupying the whole screen therefore shows the main page.
MY STATEFUL MODAL THAT DOESN'T TRIGGER THE FUTURE/ DOESN'T REFRESH THE PAGE:
void showCommentsModal(int id) {
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
backgroundColor: Color(colorBackground),
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Color(colorBackground),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20))),
height: MediaQuery.of(context).size.height / 1.5,
width: MediaQuery.of(context).size.width,
child: ViewCommentModal(
postID: id,
userList: userList,
),
);
},
);
}
THE OTHER STATEFUL MODAL THAT TRIGGERS THE FUTURE/ REFRESHES THE LIST:
addCommentModal(int i) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: AddCommentModal(
onPost: (String text) {
APIServices.commentPost(context, i.toString(), text);
Navigator.pop(context);
},
),
);
},
);
}
what makes the addCommentModal trigger the future? please help.
EDIT:
I've caught the suspect!
here is my AddCommentModal code:
class AddCommentModal extends StatefulWidget {
final ValueChanged<String> onPost;
AddCommentModal({#required this.onPost});
#override
_AddCommentModalState createState() => _AddCommentModalState();
}
class _AddCommentModalState extends State<AddCommentModal> {
final commentController = TextEditingController();
String defaultProfilePhoto = "";
#override
void initState() {
defaultProfilePhoto = Constants.userFirstName[0].toUpperCase();
super.initState();
}
#override
void dispose() {
commentController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Row(
children: <Widget>[
Container(
width: 50,
height: 50,
child: ClipRRect(
borderRadius: new BorderRadius.circular(50),
child: Constants.userProfilePhoto == null
? Container(
color: Color(colorPrimary),
alignment: Alignment.center,
child: Text(
defaultProfilePhoto,
style: TextStyle(
color: Color(colorText), fontSize: 20),
),
)
: Image.network(
APIServices.httpDomain + Constants.userProfilePhoto,
fit: BoxFit.cover,
)),
),
Expanded(
child: Container(
margin: EdgeInsets.only(
left: 10,
),
child: TextFormField(
controller: commentController,
decoration: new InputDecoration(
suffixIcon: IconButton(
onPressed: () => widget.onPost(commentController.text),
icon: Icon(
FontAwesomeIcons.paperPlane,
size: 15,
color: Theme.of(context).primaryColor,
)),
contentPadding: EdgeInsets.all(10),
hintText: "Add a comment ...",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(20.0),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
borderSide:
BorderSide(width: 1, color: Color(0xFFff8b50)))),
keyboardType: TextInputType.text,
style: new TextStyle(fontFamily: "Poppins", fontSize: 15),
),
))
],
));
}
}
The issue that causes the page to refresh is because of the SoftKeyboard that pops up whenever the TextFormField is focused.
When I show the the modal, it runs smoothly. but when I start to tap the field, the page refreshes as if the future is once again called.