import 'dart:convert'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cofounderella/components/my_button.dart'; import 'package:cofounderella/components/my_textfield.dart'; import 'package:cofounderella/models/language.dart'; import 'package:cofounderella/models/language_setting.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:cofounderella/services/auth/auth_service.dart'; class UserDataPage extends StatefulWidget { const UserDataPage({super.key}); @override State createState() => _UserDataPageState(); } class _UserDataPageState extends State { final TextEditingController _locationController = TextEditingController(); final TextEditingController _birthdayController = TextEditingController(); final TextEditingController _genderController = TextEditingController(); List languagesList = []; final List _selectedLanguages = []; // get instance of firestore and auth final FirebaseFirestore _firestore = FirebaseFirestore.instance; final AuthService _authService = AuthService(); @override void initState() { super.initState(); // Load data from JSON file when the widget initializes loadLanguagesFromJson(); } void saveUserData(BuildContext context) async { // get userID from auth service String currentUserID = _authService.getCurrentUser()!.uid; // Get reference to the Firebase collection CollectionReference languagesRef = _firestore .collection('Users') .doc(currentUserID) .collection('languages'); // Loop through each Language object and save it to the collection for (int i = 0; i < _selectedLanguages.length; i++) { // Convert Language object to a map and add the map to the collection, // using .doc(myID).set() instead of .add() to avoid duplicates. await languagesRef .doc(_selectedLanguages[i].code) .set(_selectedLanguages[i].toMap()); } // List to store language codes from the provided list List languageCodes = _selectedLanguages.map((language) => language.code).toList(); // Clean up languages that were not part of the provided list await deleteUnusedDocuments(languagesRef, languageCodes); } /// Deletes documents from collection that are not part of the provided list Future deleteUnusedDocuments( CollectionReference refCollection, List idsToKeep) async { // Fetch the existing documents from the database QuerySnapshot snapshot = await refCollection.get(); // Loop through each document in the collection for (QueryDocumentSnapshot doc in snapshot.docs) { String documentId = doc.id; // If the language code is not in the provided list, delete the document if (!idsToKeep.contains(documentId)) { await doc.reference.delete(); } } } Future loadLanguagesFromJson() async { // Load JSON data from assets String jsonData = await rootBundle.loadString('lib/assets/languages.json'); // Parse JSON into a list of objects List jsonList = await json.decode(jsonData); // Create LanguageSetting objects from JSON data languagesList = jsonList.map((item) { Language language = Language( code: item['code'], name: item['name'], nativeName: item['nativeName'], iconFile: item['iconFile'], ); // TODO Werte aus DB laden return LanguageSetting(language: language); }).toList(); // Update the UI after loading data setState(() { // TODO ? }); } @override Widget build(BuildContext context) { if (languagesList.isEmpty) { return const Center(child: CircularProgressIndicator()); } else { return Scaffold( appBar: AppBar( title: const Text("User Data"), centerTitle: true, ), body: ListView( children: [ const Text( 'Location', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), MyTextField( hintText: "Location", obscureText: false, controller: _locationController, ), const Text( 'Birthday', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), MyTextField( hintText: "Birthday", obscureText: false, controller: _birthdayController, ), const Text( 'Gender', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), MyTextField( hintText: "Gender", obscureText: false, controller: _genderController, ), const Divider(), Text( 'Language: (${_selectedLanguages.length} selected)', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ...languagesList.map(buildSingleCheckbox), // ... spread operator const Divider(), Padding( padding: const EdgeInsets.all(8.0), child: MyButton(text: "Save", onTap: () => saveUserData(context)), ) ], ), ); } } Widget buildSingleCheckbox(LanguageSetting languageSetting) => buildCheckbox( languageSetting: languageSetting, onClicked: () { setState(() { final newValue = !languageSetting.isSelected; languageSetting.isSelected = newValue; if (languageSetting.isSelected && !_selectedLanguages.contains(languageSetting.language)) { _selectedLanguages.add(languageSetting.language); } else if (languageSetting.isSelected == false) { _selectedLanguages.removeWhere( (element) => element.code == languageSetting.language.code); } }); }, ); Widget buildCheckbox({ required LanguageSetting languageSetting, required VoidCallback onClicked, }) => ListTile( tileColor: Colors.greenAccent, onTap: onClicked, leading: SizedBox( width: 48, height: 32, child: SvgPicture.asset( languageSetting.language.iconFile, ), ), title: Text( languageSetting.language.nativeName, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), subtitle: Text(languageSetting.language.name), trailing: Checkbox( value: languageSetting.isSelected, onChanged: (value) => onClicked(), ), ); }