Reflect List Data Back Into UI [Flutter] - database

In short, users can choose their interests during onboarding, UI changes and the interests are added to a list.
When user navigates to another page ie settings, how can the chosen interests be selected alrdy (bool isChosen = true)?... and then users can update their interests from there again?
any guidance is appreciated, thanks!
Attached is my truncated code for a particular theme of interests, all the themes have the same code just different list.
Let's say my data has a list of [ "๐Ÿก Home-body", "๐Ÿƒโ€โ™€๏ธ Running", "๐Ÿง˜๐Ÿปโ€โ™€๏ธ Yoga", "๐ŸŽญ Theaters", "๐Ÿ˜ธ Anime & Manga",].
What can be done so that the bubble UI of this chosen list is shown as bool isChosen (so yellow color, compared to the other dark ones)? Following which users can select and unselect again?
final List<String> artsInterests = [
blah blah blah
];
class ArtsInterests extends StatelessWidget {
const ArtsInterests({
Key key,
#required this.artsInterests,
}) : super(key: key);
final List<String> artsInterests;
#override
Widget build(BuildContext context) {
final height = MediaQuery.size.height;
final width = MediaQuery.size.width;
return Column(children: [
Container(
margin: EdgeInsets.only(
left: width * 0.045,
top: height * 0.033),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
'๐ŸŽจ Arts',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 21),
)),
),
Column(
children: [
Padding(
padding: EdgeInsets.only(
left: width * 0.03,
top: height * 0.012),
child: Container(
width: width,
height: height * 0.045,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(1),
itemCount: 7,
itemBuilder: (context, int index) {
return Interests2(AvailableInterestChosen(
artsInterests[index],
isChosen: false,
));
}),
),
),
Padding(
padding: EdgeInsets.only(
left: width * 0.03,
top: height * 0.003),
child: Container(
width: width,
height: height * 0.045,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(1),
itemCount: artsInterests.length - 7,
itemBuilder: (context, int index) {
return Interests2(AvailableInterestChosen(
artsInterests[7 + index],
isChosen: false,
));
}),
),
),
],
),
]);
}
}
List<String> chosenInterests = [ "๐Ÿก Home-body", "๐Ÿƒโ€โ™€๏ธ Running", "๐Ÿง˜๐Ÿปโ€โ™€๏ธ Yoga", "๐ŸŽญ Theaters", "๐Ÿ˜ธ Anime & Manga",];
List<String> chosenArtsInterests = [];
class Interests2 extends StatefulWidget {
final AvailableInterestChosen viewInterest;
Interests2(this.viewInterest);
String id = 'Interests2';
#override
Interests2State createState() => Interests2State();
}
class Interests2State extends State<Interests2> {
#override
Widget build(BuildContext context) {
final height = MediaQuery.size.height;
final width = MediaQuery.size.width;
Container container = Container(
height: height * 0.03,
padding: EdgeInsets.symmetric(
horizontal: width * 0.027,
vertical:height * 0.003),
// padding: EdgeInsets.fromLTRB(12, 6, 12, 6),
margin: EdgeInsets.fromLTRB(
width * 0.012,
height * 0.003,
width * 0.012,
height * 0.003),
decoration: BoxDecoration(
color: widget.viewInterest.isChosen && chosenInterests.length < 9
? Color(0xff0B84FE)
: Colors.white.withOpacity(0.87),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.69),
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 1), // changes position of shadow
),
],
borderRadius: BorderRadius.circular(9),
),
child: Text(
'${widget.viewInterest.title}',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: widget.viewInterest.isChosen && chosenInterests.length < 9
? Colors.white
: Colors.black),
));
if (widget.viewInterest.isChosen && chosenInterests.length < 9) {
chosenArtsInterests.add('${widget.viewInterest.title}');
var chosenInterests = chosenSportsInterests +
chosenEntertainmentInterests +
chosenCharacterInterests +
chosenArtsInterests +
chosenWellnessInterests +
chosenLanguageInterests;
print(chosenInterests);
} else {
chosenArtsInterests.remove('${widget.viewInterest.title}');
var chosenInterests = chosenSportsInterests +
chosenEntertainmentInterests +
chosenCharacterInterests +
chosenArtsInterests +
chosenWellnessInterests +
chosenLanguageInterests;
print(chosenInterests);
}
return GestureDetector(
onTap: () {
setState(() {
widget.viewInterest.isChosen = !widget.viewInterest.isChosen;
});
},
child: container,
);
}
}
class AvailableInterestChosen {
bool isChosen;
String title;
AvailableInterestChosen(this.title, {this.isChosen = false});
}

You can pass the values to another widget as arguments but that is not possible in this case since there are so many values. You have to use a state management solution. For starter you can use provider

Related

The data from Firebase appears randomly, and it is not the last item I add that appears at the top

I need to show the data that I add at the top, but it does not happen, I thought that the data is arranged according to the date it was added to the Firebase Firestore,
I think the data is sorted by document ID
After I almost finished the application, I could not solve this problem, I am not very skilled in Firebase and I did not find the solution
class News extends StatefulWidget {
News({Key? key}) : super(key: key);
#override
State<News> createState() => _NewsState();
}
class _NewsState extends State<News> {
final Stream<QuerySnapshot> data =
FirebaseFirestore.instance.collection('news').snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromARGB(255, 102, 102, 102),
appBar: AppBar(
backgroundColor: Colors.blueAccent,
title: Center(
child: Text(
'ุฃุฎุจุงุฑ ุงู„ุฃู†ู…ูŠ',
style: TextStyle(fontSize: 30),
),
),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: StreamBuilder<QuerySnapshot>(
stream: data,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('ุญุฏุซ ุฎุทุฃ');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Column(
children: [
Center(child: Text('ุฌุงุฑูŠ ุงู„ุชุญู…ูŠู„')),
CircularProgressIndicator()
],
);
}
final anime = snapshot.requireData;
return ListView.builder(
physics: BouncingScrollPhysics(),
padding:
EdgeInsets.only(top: 3, left: 3, right: 3, bottom: 80),
itemCount: anime.size,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.blue, width: 3),
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 3.5,
spreadRadius: 1,
)
],
),
margin: EdgeInsets.all(5),
child: Row(
children: [
Expanded(
flex: 3,
child: Container(
alignment: Alignment.centerRight,
child: Text(
textDirection: TextDirection.rtl,
'${anime.docs[index]['title']}',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700),
),
)),
Expanded(
flex: 1,
child: Card(
child: Image.network(
'${anime.docs[index]['image']}',
fit: BoxFit.fill,
height: 120,
),
),
)
],
),
),
],
);
});
})),
);
}
}
Yes, firestore will return base on alphabetically sorting based on document ID.
Use the .orderBy("FieldToOrderBy") to return it in your desired order.
Order and limit data - Firestore

Flutter Images in a List (Flutter)

so I want to have a List/Array that contains images and where each image has his own title.
The image and the title should be shown in two different buttons and the title should change when I tap on the image.
I already could solve the first two points (to show in different places and that the title changes)
But I don't know how to add images to my List, could you help me?
In addition to that, the List should be randomized, but the title should always "stay" with his image.
I hope you understand what I want and thank you for your help.
class Sachen {
String title;
String image;
Sachen(this.title, this.image);
}
final List<Sachen> infoBank = [
Sachen("Chips", "images/snack1.png",),
Sachen("Erdnussflips", "images/snack2.png",),
];
int bankNumber = Random().nextInt(2) +1;
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
Card(
margin: EdgeInsets.fromLTRB(50, 35, 50, 0),
elevation: 8,
color: Color(0xFF4caf50),
child: SizedBox(
height: 80,
width: 150,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 18),
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Rezept('Rezept'),
),
);
},
child: SizedBox(
height: 125,
width: 150,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 18),
child: Text(
infoBank[bankNumber].title,
style: GoogleFonts.rubik(
fontSize: 20,
color: Colors.white,
),
),
),
),
),
),
),
),
),
),
Row(
children: [
Expanded(
child: TextButton(
onPressed: () {
setState(() {
bankNumber++;
});
changeDiceNumber();
print('LeftDiceNumber = $DiceNumber');
},
child: Container(
margin: EdgeInsets.fromLTRB(10, 20, 10, 20),
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: Colors.grey.shade700,
),
),
height: 350,
width: 350,
child: Image.asset('images/snack$DiceNumber.png',
fit: BoxFit.cover,
),
),
),
),
],
),
],
),
);
}
}
have you tried using Flutter's ListViewBuilder?
Like alread said ListView().builder will be a good usage.
Instead of building the widget you can just use ListTile or Card there you already have trailing, leading, and title for the positioning of your images.
Althou i would change the class Sachen with a final Icon or IconData to directly add it to your List. In The Constructor please use required for the parameters its for better reading and don't do mistakes
This is my first idea to use this
class Sachen {
final String title;
final String image;
Sachen({
required this.title,
required this.image,
});
}
final List<Sachen> liste = [
Sachen(title: "title", image: "name"),
Sachen(title: "title1", image: "name1"),
];
return ListView.builder(itemBuilder: (context, index) {
return ListTile(
leading: Image.asset(liste[index].image),
title: Text(liste[index].title),
onTap: (){
//Do On Tap
//remember to use SetState when you want to rebuild some changes
},
);
});
Other Idea maybe a little bit better:
class Sachen {
final String title;
final Image image;
Sachen({
required this.title,
required this.image,
});
}
final List<Sachen> liste = [
Sachen(title: "title", image: Image.asset("name")),
Sachen(title: "title1", image: Image.asset("name1")),
];
#override
Widget build(BuildContext context) {
return ListView.builder(itemBuilder: (context, index) {
return ListTile(
leading: liste[index].image,
title: Text(liste[index].title),
onTap: () {
//Do On Tap
//remember to use SetState when you want to rebuild some changes
},
);
});
}

How to get multiple urls from firebase storage as array in firestore document?

I have an form (writeUrltoFirestore) which is working except for an array of urls which has to be taken from storage and added to firestore document.
Currently for every file url added in form I have new document at firestore.
So if I select 5 documents and click on "Create" button it will create 5 exactly same documents with only difference their "url" in (writeUrltoFirestore).
As I mentioned it has to create single document in firestore with array of urls for each file stored in storage.
BTW Iam not a programmer - didn't read any book, just always wanted to learn how to make an working app (kinda a dream) so please explain like to a moron if you can and don't get mad if you see something stupid.
Thanks to anyone which is willing to help me.
I need result like this link
Here is code below with some explanations.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:file_picker/file_picker.dart';
import 'dart:io' show File;
class Fields extends StatefulWidget {
const Fields({Key? key}) : super(key: key);
#override
_FieldsState createState() =>
_FieldsState();
}
class _FieldsState extends State<Fields> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(child: _Body111()),
);
}
}
class _Body111 extends StatefulWidget {
#override
__Body111State createState() => __Body111State();
}
class __Body111State extends State<_Body111> {
final FirebaseStorage _firebaseStorage = FirebaseStorage.instance;
List<UploadTask> uploadedTasks = [];
List<File> selectedFiles = [];
//-----------------------------------------------------------------------------
// Select files to be uploaded to Storage
Future selectFileTo() async {
try {
FilePickerResult? result = await FilePicker.platform
.pickFiles(allowMultiple: true, type: FileType.any);
if (result != null) {
selectedFiles.clear();
for (var selectedFile in result.files) {
File file = File(selectedFile.path ?? '');
selectedFiles.add(file);
}
} else {
print("User has cancelled the selection");
}
} catch (e) {
print(e);
}
}
//---------------------------------------------------------------------------
// Upload selected files to Storage
uploadFileToStorage(File file) {
UploadTask task = _firebaseStorage
.ref()
.child("files/${DateTime.now().toString()}")
.putFile(file);
return task;
}
//----------------------------------------------------------------------------
// Save files to Storage and get files Urls
saveImageUrlToFirebase(UploadTask task) {
task.snapshotEvents.listen((snapShot) {
if (snapShot.state == TaskState.success) {
snapShot.ref.getDownloadURL().then((urls) =>
writeUrltoFirestore(urls));
}
});
}
//--------------------------------------------------------------------------
// Save files Urls to Firestore document
writeUrltoFirestore(urls) {
Map<String, dynamic> firestoredocData = {
"issue type": selectedValue,
"description": descriptionController.text,
"location": 'Building A',
"category": selectedCategory,
"subcategory": selectedSubcategory,
"uid": firebaseUser!.uid,
//----------------------------------------------------------------------
//----------------------------------------------------------------------
"url": urls, // HERE I HAVE TO STORE ARRAY OF URLS FROM STORAGE
//----------------------------------------------------------------------
//----------------------------------------------------------------------
};
CollectionReference collectionReference =
FirebaseFirestore.instance.collection('issues');
collectionReference.add(firestoredocData);
}
//--------------------------------------------------------------------------
// Button that triggers all
addData() async {
for (var file in selectedFiles) {
final UploadTask task = uploadFileToStorage(file);
saveImageUrlToFirebase(task);
setState(() {
uploadedTasks.add(task);
});
}
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('created successfully')));
Navigator.pop(context);
}
//----------------------------------------------------------------------------
// Other fields from Map above
List<String> categories = ['111', '222', '333'];
List<String> generalSubcategory = ['1111111', '2222222', '333333333'];
List<String> cleaningSubcategory = [
'1',
'2',
'3'
];
List<String> othersSubcategory = ['01', '02', '03'];
List<String> subcategory = [];
String? selectedCategory;
String? selectedSubcategory;
final TextEditingController descriptionController = TextEditingController();
var firebaseUser = FirebaseAuth.instance.currentUser;
String? selectedValue;
List<String> arrayList = [
'Individual ',
'Maintenance '
];
Widget _description() {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 35, 0, 0),
child: TextFormField(
controller: descriptionController,
decoration: InputDecoration(
hintText: 'Here you can describe ...',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(color: Colors.grey),
),
),
maxLines: 8,
),
);
}
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) =>
Stack(
children: [
GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: SingleChildScrollView(
child: Container(
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 20.0),
child: _description(),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0),
child: Container(
padding: const EdgeInsets.fromLTRB(13, 0, 25, 0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Colors.grey,
spreadRadius: 2,
blurRadius: 2,
offset:
Offset(5, 5), // changes position of shadow
),
],
border: Border.all(
color: Colors.grey, width: 1.0),
borderRadius:
const BorderRadius.all(Radius.circular(20)),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
dropdownColor: Colors.white,
borderRadius: BorderRadius.circular(20),
hint: const Padding(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Text(
'Categories',
style: TextStyle(),
)),
value: selectedCategory,
isExpanded: true,
items: categories.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Padding(
padding:
const EdgeInsets.fromLTRB(25, 0, 0, 0),
child: Text(
value,
textAlign: TextAlign.center,
style: const TextStyle(),
),
),
);
}).toList(),
onChanged: (category) {
if (category == '222') {
subcategory = cleaningSubcategory;
} else if (category == '111') {
subcategory = generalSubcategory;
} else if (category == '333') {
subcategory = othersSubcategory;
} else {
subcategory = [];
}
setState(() {
selectedSubcategory = null;
selectedCategory = category;
});
},
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0),
child: Container(
padding: const EdgeInsets.fromLTRB(20, 0, 25, 0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Colors.grey,
spreadRadius: 2,
blurRadius: 2,
offset:
Offset(5, 5), // changes position of shadow
),
],
border: Border.all(
color: Colors.grey, width: 1.0),
borderRadius:
const BorderRadius.all(Radius.circular(20)),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
dropdownColor: Colors.white,
borderRadius: BorderRadius.circular(20),
hint: const Padding(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Text(
'Subcategories',
style: TextStyle(),
)),
value: selectedSubcategory,
isExpanded: true,
items: subcategory.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Padding(
padding:
const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Text(value),
),
);
}).toList(),
onChanged: (subcategory) {
setState(() {
selectedSubcategory = subcategory;
});
},
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0),
child: Container(
padding: const EdgeInsets.fromLTRB(20, 0, 25, 0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Colors.grey,
spreadRadius: 2,
blurRadius: 2,
offset:
Offset(5, 5), // changes position of shadow
),
],
border: Border.all(
color: Colors.grey, width: 1.0),
borderRadius:
const BorderRadius.all(Radius.circular(20)),
),
child: DropdownButtonHideUnderline(
child: DropdownButtonFormField<String>(
dropdownColor: Colors.white,
decoration: const InputDecoration(
enabledBorder: InputBorder.none,
),
validator: (value) =>
selectedValue == null
? 'Please select type'
: null,
hint: const Padding(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Text(
'Type',
),
),
value: selectedValue,
isExpanded: true,
icon: const Icon(Icons.arrow_drop_down),
items: arrayList.map((String string) {
return DropdownMenuItem<String>(
value: string,
child: Padding(
padding:
const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Text(string),
),
);
}).toList(),
onChanged: (String? string) {
setState(() {
selectedValue = string;
});
},
),
),
),
),
const Padding(
padding: EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0)),
IconButton(
onPressed: selectFileTo,
icon: const Icon(
Icons.camera_alt_outlined,
size: 30,
color: Colors.grey,
)),
const Padding(
padding: EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0)),
Padding(
padding: const EdgeInsets.only(
left: 30.0, right: 30.0, top: 5.0),
child: ElevatedButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(0)),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
)),
backgroundColor: MaterialStateProperty.all<
Color>(
Colors.transparent),
shadowColor: MaterialStateProperty.all<Color>(
Colors.transparent)),
onPressed: addData,
child: Container(
decoration: const BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(20)),
),
constraints: const BoxConstraints(
minWidth: 120, minHeight: 40),
alignment: Alignment.center,
child: const Center(
child: Text(
"Create",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
),
),
),
],
),
),
),
),
],
),
);
}
}
// End of dart file
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Firebase API (separate dart file)
import 'dart:io';
import 'dart:typed_data';
import 'package:firebase_storage/firebase_storage.dart';
class FirebaseApi {
static UploadTask? uploadFile(String destination, File file) {
try {
final ref = FirebaseStorage.instance.ref(destination);
return ref.putFile(file);
} on FirebaseException catch (e) {
return null;
}
}
static UploadTask? uploadBytes(String destination, Uint8List data) {
try {
final ref = FirebaseStorage.instance.ref(destination);
return ref.putData(data);
} on FirebaseException catch (e) {
return null;
}
}
}
//-----------------------------------------------------------------------------
You should call writeUrltoFirestore at last of all upload. Maintain an List at top.
List<String> _urls = [];
in saveImageUrlToFirebase
saveImageUrlToFirebase(UploadTask task) {
task.snapshotEvents.listen((snapShot) {
if (snapShot.state == TaskState.success) {
snapShot.ref.getDownloadURL().then((url) =>
_urls.add(url.toString()));
}
});
}
In final upload task simply call
writeUrltoFirestore(_urls);

Flutter Chat Screen Textinputfield

I have create a Chat in my app. My problem is that when someone want to type in the Inputfield the Inputfield goes up because of the phone keyboard but my chat dont show the last message above the Inputfield. Does anyone know how to fix this? Chatscreen and Chatscreen with keyboard
class Chat extends StatefulWidget {
final String chatRoomId;
Chat({this.chatRoomId});
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
Stream<QuerySnapshot> chats;
TextEditingController messageEditingController = new TextEditingController();
Stream chatRooms;
Widget chatMessages(){
return StreamBuilder(
stream: chats,
builder: (context, snapshot){
return snapshot.hasData ?
ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index){
return MessageTile(
message: snapshot.data.docs[index].data()["message"],
sendByMe: Constants.myName == snapshot.data.docs[index].data()["sendBy"],
time: snapshot.data.docs[index].data()["time"],
);
},
) : SpinKitFadingCircle(color: Colors.white, size: 20.0);
},
);
}
addMessage() {
if (messageEditingController.text.isNotEmpty) {
Map<String, dynamic> chatMessageMap = {
"sendBy": Constants.myName,
"message": messageEditingController.text,
'time': DateTime
.now()
.millisecondsSinceEpoch,
};
DatabaseService().addMessage(widget.chatRoomId, chatMessageMap);
setState(() {
messageEditingController.text = "";
});
}
}
#override
void initState() {
DatabaseService().getChats(widget.chatRoomId).then((val) {
setState(() {
chats = val;
});
});
super.initState();
}
Future<DocumentSnapshot> getUserInfo() async {
var firebaseUser = await FirebaseAuth.instance.currentUser;
return await FirebaseFirestore.instance.collection("SerX")
.doc(firebaseUser.uid)
.get();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.black,
bottom: PreferredSize(
child: Container(
color: Colors.blue,
height: 4.0,
),
preferredSize: Size.fromHeight(0)),
title:Text("Conversation",
style: TextStyle(
color: Colors.white,
fontFamily: 'Orbitron',
fontSize: 20.0,
fontWeight: FontWeight.bold,
letterSpacing: 2.2
),),
leading: IconButton(icon: Icon(Icons.arrow_back ,color: Colors.blue,),onPressed: (){
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => Search()));
},),
),
body: Container(
child: Stack(
children: [
Container(child: chatMessages(), height: 595),
Container(
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 25, vertical: 3),
color: Colors.white,
child: Row(
children: [
Expanded(
child: TextField(
controller: messageEditingController,
style: TextStyle(
color: Colors.white,
fontFamily: 'Orbitron',
fontSize: 12.0,
fontWeight: FontWeight.bold,
),
decoration: InputDecoration(
contentPadding: new EdgeInsets.symmetric(vertical: 7, horizontal: 15),
filled: true,
fillColor: Colors.black,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(40),
borderSide: BorderSide(color: Colors.blue, width: 3)
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(40),
borderSide: BorderSide(color: Colors.blue, width: 3,)
),
border: InputBorder.none,
),
),
),
SizedBox(width: 20,),
GestureDetector(
onTap: () {
addMessage();
},
/*
child:Container(
height: 45,
width: 45,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color(0xFF000000),
const Color(0xFF000000),
]
),
borderRadius: BorderRadius.circular(40),
border: Border.all(
width: 2,
color: Colors.blue
)
),
*/
child:Icon(Icons.send, color: Colors /// <--- Um den grauen script zu aktivieren hinter Icon eine klammer zu setzen!
.black, size: 35,),
),
],
),
),
),
],
),
),
);
}
}
class MessageTile extends StatelessWidget {
final String message;
final bool sendByMe;
final int time;
MessageTile({#required this.message, #required this.sendByMe, #required this.time});
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: 3,
bottom: 3,
left: sendByMe ? 0 : 24,
right: sendByMe ? 24 : 0),
alignment: sendByMe ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
margin: sendByMe
? EdgeInsets.only(left: 30)
: EdgeInsets.only(right: 30),
padding: EdgeInsets.only(
top: 17, bottom: 17, left: 20, right: 20),
decoration: BoxDecoration(
borderRadius: sendByMe ? BorderRadius.only(
topLeft: Radius.circular(9),
topRight: Radius.circular(9),
bottomLeft: Radius.circular(9),
) :
BorderRadius.only(
topLeft: Radius.circular(9),
topRight: Radius.circular(9),
bottomRight: Radius.circular(9)),
color: sendByMe ? Colors.blue : Colors.white
),
child: Text(message,
textAlign: TextAlign.start,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontFamily: 'Orbitron',
fontSize: 9.0,),),
),
);
}
}
The cause of the error is that you set 595 pixels as a fixed height for the Container your chatMessages widget is in.
Container(child: chatMessages(), height: 595),
An easy solution would be to calculate the height of the keyboard (see this question):
Container(child: chatMessages(), height: MediaQuery.of(context).size.height - 134 - MediaQuery.of(context).viewInsets.bottom),
This takes the actual height of your device and subtracts the height of appBar, textinputfield and keyboard.
However, it would be more efficient to use a widget tree that does not depend on pixel calculations. Especially the part with the keyboard may lead to lagging on slower devices.

how to infinite loop array on flutter

i want to asking about my problem, i want to make a stack of card with ifinite loop when stack card on last index on array, i want to make it loop to first index. i use satck widget and page builder for it, i have a list of data :
import 'package:flutter/material.dart';
List<String> images = [
'assets/images/trivia/bedroom.png',
'assets/images/trivia/digital-signature.png',
];
List<String> title = [
'โ€œ41 percent of job seekers search for jobs while in bedโ€',
'โ€œDigital signatures are legally recognized.โ€',
];
List<Color> colorList = [
Color(0xffa605ad),
Color(0xffe0991e),
];
and my flutter code :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'data.dart';
import 'dart:math';
void main() => runApp(MaterialApp(
home: Trivia(),
debugShowCheckedModeBanner: false,
));
class Trivia extends StatefulWidget {
#override
_TriviaState createState() => new _TriviaState();
}
var cardAspectRatio = 12.0 / 16.0;
var widgetAspectRatio = cardAspectRatio * 1.2;
class _TriviaState extends State<Trivia> {
var currentPage = images.length - 1.0;
#override
Widget build(BuildContext context) {
PageController controller = PageController(initialPage: images.length - 1);
controller.addListener(() {
setState(() {
currentPage = controller.page;
});
});
return Container(
decoration: BoxDecoration(
color: Colors.white,
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
children: <Widget>[
SizedBox(
height: 70,
),
Container(
alignment: Alignment.center,
child: Text(
'Please Wait',
textAlign: TextAlign.center,
),
),
SizedBox(
height: 60,
),
Stack(
children: <Widget>[
CardScrollWidget(currentPage),
Positioned.fill(
child: PageView.builder(
itemCount: images.length,
controller: controller,
reverse: true,
itemBuilder: (context, index) {
return Container();
},
),
),
],
),
],
),
),
);
}
}
class CardScrollWidget extends StatelessWidget {
double currentPage;
var padding = 20.0;
var verticalInset = 20.0;
CardScrollWidget(this.currentPage);
#override
Widget build(BuildContext context) {
return new AspectRatio(
aspectRatio: widgetAspectRatio,
child: LayoutBuilder(builder: (context, contraints) {
var width = contraints.maxWidth;
var height = contraints.maxHeight;
var safeWidth = width - 2 * padding;
var safeHeight = height - 2 * padding;
var heightOfPrimaryCard = safeHeight;
var widthOfPrimaryCard = heightOfPrimaryCard * cardAspectRatio;
var primaryCardLeft = safeWidth - widthOfPrimaryCard;
var horizontalInset = primaryCardLeft / 2;
List<Widget> cardList = new List();
for (var i = 0; i < images.length; i++) {
var delta = i - currentPage;
bool isOnRight = delta > 0;
var start = padding +
max(
primaryCardLeft -
horizontalInset * -delta * (isOnRight ? 15 : 1),
0.0);
var cardItem = Positioned.directional(
top: padding + verticalInset * max(-delta, 0.0),
bottom: padding + verticalInset * max(-delta, 0.0),
start: start,
textDirection: TextDirection.rtl,
child: ClipRRect(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.0),
border: Border.all(color: colorList[i], width: 2)),
child: AspectRatio(
aspectRatio: cardAspectRatio,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Text(
'Fun Fact',
textAlign: TextAlign.center,
style: TextStyle(
decorationColor: Colors.black,
fontSize: 22,
fontFamily: 'Poppins-ExtraBold'),
),
Image.asset(
images[i],
scale: 3,
),
Align(
alignment: Alignment.bottomLeft,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
child: Text(title[i],
textAlign: TextAlign.center,
style: TextStyle(
color: colorList[i],
fontSize: 18.0,
fontFamily: 'TTCommons')),
),
SizedBox(
height: 10.0,
),
],
),
)
],
),
),
),
),
);
cardList.add(cardItem);
}
return Stack(
children: cardList,
);
}),
);
}
}
i want to make the card loopable by array. thank you anyway
You can do this using an PageView, the default is loop, unless you provide an item count for PageView. Example
final controller = new PageController(initialPage: 999);
...
new PageView.builder(
controller: controller,
itemBuilder: (context, index) {
return new Center(
child: new Text('${index % 5}'),
);
},
)
I don't know if you need exactly the stack and can't do with PageView.. but if you can't do with PageView, i'll try searching an answer to you.
I Hope i have helped you!

Resources