Added UserDataPage (first draft)
parent
952a8673f0
commit
25f456a193
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cofounderella/pages/user_data_page.dart';
|
||||||
import 'package:cofounderella/services/auth/auth_service.dart';
|
import 'package:cofounderella/services/auth/auth_service.dart';
|
||||||
import 'package:cofounderella/pages/settings_page.dart';
|
import 'package:cofounderella/pages/settings_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -85,6 +86,26 @@ class MyDrawer extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// TODO TESTING - user data tile
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 25),
|
||||||
|
child: ListTile(
|
||||||
|
title: const Text("User Data"),
|
||||||
|
leading: const Icon(Icons.supervised_user_circle),
|
||||||
|
onTap: () {
|
||||||
|
// pop the drawer
|
||||||
|
Navigator.pop(context);
|
||||||
|
|
||||||
|
//navigate to settings page
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const UserDataPage(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
// horizontal line
|
// horizontal line
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
class Language {
|
||||||
|
final String code;
|
||||||
|
final String name;
|
||||||
|
final String nativeName;
|
||||||
|
final String iconFile;
|
||||||
|
|
||||||
|
Language({
|
||||||
|
required this.code,
|
||||||
|
required this.name,
|
||||||
|
required this.nativeName,
|
||||||
|
required this.iconFile,
|
||||||
|
});
|
||||||
|
|
||||||
|
// convert to a map
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
'code': code,
|
||||||
|
'name': name,
|
||||||
|
'nativeName': nativeName,
|
||||||
|
'iconFile': iconFile,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import 'language.dart';
|
||||||
|
|
||||||
|
class LanguageSetting {
|
||||||
|
Language language;
|
||||||
|
bool isSelected;
|
||||||
|
|
||||||
|
LanguageSetting({
|
||||||
|
required this.language,
|
||||||
|
this.isSelected = false,
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
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<UserDataPage> createState() => _UserDataPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserDataPageState extends State<UserDataPage> {
|
||||||
|
final TextEditingController _locationController = TextEditingController();
|
||||||
|
final TextEditingController _birthdayController = TextEditingController();
|
||||||
|
final TextEditingController _genderController = TextEditingController();
|
||||||
|
|
||||||
|
List<LanguageSetting> languagesList = [];
|
||||||
|
final List<Language> _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<String> 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<void> deleteUnusedDocuments(
|
||||||
|
CollectionReference refCollection, List<String> 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<void> loadLanguagesFromJson() async {
|
||||||
|
// Load JSON data from assets
|
||||||
|
String jsonData = await rootBundle.loadString('lib/assets/languages.json');
|
||||||
|
// Parse JSON into a list of objects
|
||||||
|
List<dynamic> 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(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue