updateing one field in a table at a time in flutter - database

i have made a user table in firebase firestore with multiple fields. and I am saving the data Onchange in text field when the user does any change. But when I change one field it changes all the field in the table and the other data gets altered. but I want to update single field when user updates it.
below is the code that i wrote to update in database -:
FirebaseFirestore firestore = FirebaseFirestore.instance;
void userinfo() async{
firestore.collection("users").doc('122345').update(
{
"name" : '${username.text}',
"Describe" : '${describe.text}',
"SchoolName" : '${school.text}',
"dob" : '${dob.text}',
"address" : '${address.text}',
},
). then((_){
print("success!");
});
}
TextFormField(
controller: username,
textInputAction: TextInputAction.next,
focusNode: fnOne,
autofocus: false,
maxLines: 1,
textAlign: TextAlign.center,
keyboardType: TextInputType.text,
decoration: InputDecoration(
enabled: true,
suffixIcon: Padding(
padding: EdgeInsets.only(top: 15, bottom: 15),
child: Icon(
Icons.edit,
color: Colors.pinkAccent,
),
),
labelText: Uname,
),
onChanged: (value) async{
value = username.text;
userinfo();
},
onSaved: (value){
value = username.text;
},
),
I am new to firebase can anyone help me with this please?

If you want to update only a subset of the document fields, the Map you pass to the update() method needs to contain only the corresponding elements.
For example, the following will update the SchoolName field and let the other fields unchanged:
FirebaseFirestore firestore = FirebaseFirestore.instance;
void userinfo() async{
firestore.collection("users").doc('122345').update(
{
"SchoolName" : '${school.text}',
},
). then((_){
print("success!");
});
}
It's up to you to define the Map according to the fields that are modified in the front-end.
Update following your comment:
You can do as follows to update only the desired field:
FirebaseFirestore firestore = FirebaseFirestore.instance;
void userinfo(fieldToUpdate, value) async{
var updateMap = new Map();
updateMap[fieldToUpdate] = value;
await firestore.collection("users").doc('122345').update(updateMap);
print("success!");
}
TextFormField(
controller: username,
// ...
onChanged: (value) async{
value = username.text;
userinfo('username', value);
}

Related

converting a single image stored in a List<String> and display it as an image

I'd like to ask on how do I display a single image that is stored in a List.
I am using the same arrayList for multi-image picker and single image picker.
I do get this error when I am trying to display the image as File(imagePath)
The argument type 'List<String>' can't be assigned to the parameter type 'String'.
However it does change when I am adding File(imagePath.toString()).
════════ Exception caught by image resource service ════════════════════════════ Cannot open file, path = '[/data/user/0/package_name/cache/image_cropper_1675327578829.jpg]' (OS Error: No such file or directory, errno = 2)
This is my code.
// where I store my Image
List<String> imagePath = []
Future selectFile() async {
try {
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image != null) {
final croppedImage = await ImageCropper().cropImage(
sourcePath: image.path,
aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1),
compressQuality: 100,
maxWidth: 450,
maxHeight: 450,
compressFormat: ImageCompressFormat.jpg,
aspectRatioPresets: [CropAspectRatioPreset.square],
);
setState(() {
// I have stored the cropeedImage in imagePath
imagePath.add(croppedImage!.path);
});
}
} on PlatformException catch (e) {
print(e.message);
}
}
I am trying to display the image here in the column..
Column(
// constraints: BoxConstraints.expand(),
// color: Colors.blue[100],
children: [
Center(
child: Image.file(
// I do get an error here, altho it shows the whole path in my emulator device.
File(imagePath.toString()),
width: double.infinity,
height: 300,
fit: BoxFit.cover,
)),
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
selectFile();
},
child: const Text("Select a Photo")),
])
If you like to show the first image of the list, you can do
File(imagePath.first)
Or pass the index you like to show.

how to get the name Column from an ID foreign Key SQLITE?

I want to display the name of the home and away team in a listTile, I have a table that has two foreign keys, each one of them points to the ID of the team used on this game.
How can I display their name and not their ID in my tile please?
ListView(
children: snapshot.data!.map((match){
return Center(
child: Card(
child: Material(
elevation: 10.0,
child: ListTile(
tileColor: Colors.lightBlue,
title: Row(
children: [
Text(
(match.xidTeam).toString()
),
Text("-----"),
Text(match.scoreT),
Text("/"),
Text(match.scoreR),
Text("-----"),
Text(match.xidRival.toString()),
],
),
onTap: (){},
),
this is the query I am using:
Future<List<Matchs>> getMatches(teamId) async {
var dbCoach = await db;
var games = await dbCoach!.query('matchs',
orderBy: 'idMatch', where: 'xidTeam = ?', whereArgs: [teamId]);
List<Matchs> matches =
games.isNotEmpty ? games.map((e) => Matchs.fromMap(e)).toList() : [];
return matches;
}
and this is my controller:
Future<List<Matchs>> listMatchs() async{
final statAccess = DatabaseModel();
SharedPreferences sp = await _pref;
var teamId = sp.getInt('idTeam');
List<Matchs> matchs = await statAccess.getMatches(teamId);
return matchs;
}

Build Data Back to ListView Builder [Flutter]

The existing code shows a list of buttons of varying interests. Users can tap to select which interests they prefer.
However, if the user has already selected their interests beforehand and comes back to this page, it's illogical to get the users to choose from a fresh state again.
I want to repopulate what the users have previously chosen and reflect back on the screen as chosen (which = widget.viewInterest.isChosen). The color of container will be Color(0xff0B84FE), & color of text is Colors.yellow, as seen in the code below.
Let's say user has chosen this list
List UserInterests = [
"☕ Coffee",
"🎭 Theaters",
];
QUESTION: How to make containers that contain these strings bool true (which is widget.viewInterest.isChosen), similar to when users have tapped on the respective buttons?
Attached is truncated code:
final List<String> artsInterests = [
"📸 Photography",
"🎭 Theaters",
"🖼️ Exhibitions",
"📐 Architecture",
"🍳‍ Cooking",
"☕ Coffee",
"🖍️ Design",
"👗 Fashion",
"📚 Reading",
"💃🏽 Dance",
"🏺 Pottery",
"🎨 Drawing",
"💋 Beauty",
"📖 Journalling",
];
StatelessWidget shortened
final List<String> artsInterests;
shortened
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(1),
itemCount: artsInterests.length
itemBuilder: (context, int index) {
return Interests2(AvailableInterestChosen(
artsInterests[index],
isChosen: false,
));
brackets...
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: userChosenInterests
.contains(artsInterests[7 + index]),
));
closing brackets...
List<String> chosenArtsInterests = [];
List<String> UserInterests = [
"☕ Coffee",
"🎭 Theaters",
];
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.of(context).size.height;
final width = MediaQuery.of(context).size.width;
Container container = Container(
decoration shortened
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}');
print(chosenArtsInterests);
} else {
chosenArtsInterests.remove('${widget.viewInterest.title}');
print(chosenArtsInterests);
}
return GestureDetector(
onTap: () {
setState(() {
widget.viewInterest.isChosen = !widget.viewInterest.isChosen;
});
},
child: container,
);
}
}
class AvailableInterestChosen {
bool isChosen;
String title;
AvailableInterestChosen(this.title, {this.isChosen = false});
}
For the buttons to depict UI that shows they are chosen, my guess is something like
for (string i in UserInterests) setState ((){widget.viewInterest.isChosen})
But in regards to where to put it or the exact code, I'm lost. If anyone has some experience or similar resources to share so I can read on it, that will be great!
How about checking the element is in the UserInterests list?
Something like this may work,
AvailableInterestChosen(
artsInterests[index],
isChosen: UserInterests.contains(artsInterests[index]),
)

passing API data from page 1 to another dart page on flutter

page that already has data from the API, then I want to send the API data to the next page.
example: when we click the food list, a description of the food that is clicked will appear or when we click the data on another page, it is more detailed than the data on the list
The following is the code from the start page :
var notifikasiSiswa = [];
//====================== Fungsi ListView ================================
class _NotifikasiSiswaState extends State<NotifikasiSiswa> {
Future<SharedPreferences> _sprefs = SharedPreferences.getInstance();
int id;
#override
Future<Null> getData() async {
final SharedPreferences prefs = await _sprefs;
int data = prefs.getInt('id');
this.setState(() {
id = data ;
});
// counter = data;
// api coba dsni
NotifikasiSiswaMo.getPengumuman(id.toString()).then((value) {
notifikasiSiswa = value;
this.setState(() {
notifikasiSiswa = value;
});
print("muncul");
});
// print(token);
}
#override
void initState() {
super.initState();
setState(() {
getData();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Materi Siswa"),),
body: ListView.builder( // Auto Scroll Jika Data yang dimunculkan banyak
reverse: true,
itemCount: notifikasiSiswa.length,
itemBuilder: (context, index){
return Center(
child: Padding(
padding: EdgeInsets.only(left: 20.0, right: 20.0, top: 15.0 ),
child: Stack(
children: <Widget>[
Container(
height: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_borderRadius),
gradient: LinearGradient(
colors: [Colors.white, Colors.white],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
)
),
Positioned.fill(child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return NotifikasiSiswaDetail(
s_date : notifikasiSiswa[index].date,
s_title : notifikasiSiswa[index].title,
s_message :notifikasiSiswa[index].message
);
},
));
},
child: Row(
children: <Widget>[
Expanded(
child:
Center(
child: Icon(Icons.notifications_active))
),
Expanded(
flex: 4,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, //Vertical dengan posisi aligmn start
children: <Widget>[
Text(notifikasiSiswa[index].date ?? "00/00/00",
style: TextStyle(
color: Colors.black45,
fontWeight: FontWeight.w500),),
SizedBox(
height: 6.0,
),
how on the next page ?
final List args = ModalRoute.of(context).settings.arguments;Provided that I understood your question correctly, you can pass data to a new page using the arguments parameter in your Navigator.pushNamed().
Navigator.pushNamed(context, '/newPage', arguments: /* data you want to pass */);
To access this data from the new page you can use this line inside its build method.
final args = ModalRoute.of(context).settings.arguments;
You can learn more about this here: https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments
You have (at least) two options here:
Save the data in the state. If the data is not so big and complex, you can carry it around via state.
Make a new request. If you need a lot more details than just title and description such as comments, like, shares, etc. then you better make a new request. Yes, it costs you more in terms of bandwidth and also money, but it gives you more room to work with.

Firebase messages not saved in order flutter draft

I am building basically a message app where the user can add a message (task), which will be saved in firebase. It should then be shown on the screen as "messagebubbles" in order (the newest one at the bottom of the screen). The messages don't show up in order though. Looking into my firebase database collection, it seems as if the messages are not saved in order of the time they arrived. Is that a normal behaviour and does that mean that I have to sort my snapshot instead? I thought the snapshot would show me the messages exactly in the same order as they were sent.
TextField(
controller: messageTextController,
autofocus: true,
textAlign: TextAlign.center,
cursorColor: Colors.white,
style: TextStyle(color: Colors.white, fontSize: 20.0),
onChanged: (newText) {
newTaskTitle = newText;
},
),
FlatButton(
child: Text(
'Add',
style: TextStyle(
color: kSlate,
),
),
color: kSlateBorder,
onPressed: () {
messageTextController.clear();
firestore.collection('Slate1').add({
'Task': newTaskTitle,
'User': loggedInUser.email,
});
Navigator.pop(context);
},
),
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: firestore.collection('Test').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final messages = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data['Task'];
final messageSender = message.data['User'];
final currentUser = loggedInUser.email;
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
);
messageBubbles.add(messageBubble);
}
Document in Firestore are not naturally ordered by time. In the console, they appear ordered by the document ID.
If you want to impose an ordering on documents within a collection, you should use a document field for that. Consider adding a timestamp field to each message, then order your query using that timestamp.
in case anyone else was looking for an answer / implementation:
here is how I added the firebase server timestamp
firestore.collection('Test1').add({
'Task': newTaskTitle,
'User': loggedInUser.email,
'Timestamp': FieldValue.serverTimestamp(),
});
and ordered it then here based on the timestamp:
return StreamBuilder<QuerySnapshot>(
stream: firestore.collection('Test1').orderBy('Timestamp').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {

Resources