Extended SkillOptions.

Added MyElevatedButton added to unify Save Buttons.
master
Rafael 2024-06-22 21:56:45 +02:00
parent a13ed0e74b
commit c5a788c67f
13 changed files with 395 additions and 357 deletions

View File

@ -4,6 +4,7 @@ import 'package:geolocator/geolocator.dart';
import 'package:osm_nominatim/osm_nominatim.dart';
import '../models/location.dart';
import '../utils/helper.dart';
import 'text_with_bold.dart';
class LocationSelector extends StatefulWidget {
final Function(MyLocation) onLocationChanged; // Callback function
@ -54,8 +55,8 @@ class LocationSelectorState extends State<LocationSelector> {
style: const TextStyle(color: Colors.red),
),
const SizedBox(height: 20),
Text('Country: $_country'),
Text('City: $_city'),
TextWithBold(leadingText: 'Country:', boldText: ' $_country'),
TextWithBold(leadingText: 'City:', boldText: ' $_city'),
Text('Postal Code: ${_postalCode ?? ''}'),
Text('Street: $_street'),
Text('State/Area: ${_administrativeArea ?? ''}'),

View File

@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
class MyElevatedButton extends StatelessWidget {
final void Function()? onPressed;
final Widget? child;
const MyElevatedButton({super.key, this.onPressed, required this.child});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
Theme.of(context).colorScheme.surfaceContainerHigh),
),
child: child,
);
}
}

View File

@ -6,6 +6,9 @@ class Constants {
static const String appVersion = '1.0.1';
static const String appCompilationDate = '2024-06-20';
static const int maxSectors = 10;
static const int maxSkills = 5;
static const String dbCollectionFeedbacks = 'feedbacks';
static const String dbCollectionUsers = 'Users';
static const String dbCollectionLanguages = 'languages';

View File

@ -33,33 +33,42 @@ enum Gender {
}
enum SkillOption {
product,
finance,
engineering,
design,
marketing,
management,
data,
design,
engineering,
finance,
it,
legal,
marketing,
operations,
legal;
product,
software;
String get displayName {
switch (this) {
case SkillOption.product:
return 'Product Development';
case SkillOption.management:
return 'Business Development';
case SkillOption.data:
return 'Data Analysis and Analytics';
case SkillOption.design:
return 'Design';
case SkillOption.engineering:
return 'Engineering';
case SkillOption.marketing:
return 'Sales and Marketing';
case SkillOption.finance:
return 'Finance';
case SkillOption.management:
return 'Management';
case SkillOption.operations:
return 'Operations';
return 'Finance and Accounting';
case SkillOption.it:
return 'Information Technology';
case SkillOption.legal:
return 'Legal';
case SkillOption.marketing:
return 'Marketing and Sales';
case SkillOption.operations:
return 'Operations Management';
case SkillOption.product:
return 'Product Development';
case SkillOption.software:
return 'Software Development';
}
}
}

View File

@ -1,6 +1,7 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import '../components/my_elevated_button.dart';
import '../components/text_bold.dart';
import '../constants.dart';
import '../enumerations.dart';
@ -211,7 +212,7 @@ class CultureValuesFormPageState extends State<CultureValuesFormPage> {
);
}),
const SizedBox(height: 20),
ElevatedButton(
MyElevatedButton(
onPressed: handleSubmit,
child: Text(widget.isRegProcess ? 'Save and continue' : 'Save'),
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../components/my_elevated_button.dart';
import '../components/text_bold.dart';
import '../utils/helper.dart';
@ -91,7 +92,7 @@ class ProfileCategoryFormState<T> extends State<ProfileCategoryForm<T>> {
),
const SizedBox(height: 16.0),
if (!widget.hideSaveButton)
ElevatedButton(
MyElevatedButton(
onPressed: _saveButtonClicked,
child: Text(widget.saveButtonText ?? 'Save'),
),

View File

@ -1,6 +1,7 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../components/my_elevated_button.dart';
import '../constants.dart';
import '../enumerations.dart';
import '../pages/registration_complete_page.dart';
@ -180,7 +181,7 @@ class RisksFormPageState extends State<RisksFormPage> {
}),
const SizedBox(height: 20),
Center(
child: ElevatedButton(
child: MyElevatedButton(
onPressed: handleSubmit,
child:
Text(widget.isRegProcess ? 'Save and continue' : 'Save'),

View File

@ -31,15 +31,14 @@ class SectorsForm extends StatelessWidget {
return Text('Error: ${snapshot.error}');
} else {
List<SectorOption>? userSectors = snapshot.data;
int max = 10;
return ProfileCategoryForm(
title: 'Sectors of interest',
header: 'Sectors of interest',
description: 'Select up to $max sectors that match your interests.',
description: 'Select up to ${Constants.maxSectors} sectors that match your interests.',
saveButtonText: isRegProcess ? 'Save and continue' : 'Save',
options: SectorOption.values.toList(), // Convert enum to list
minSelections: 1,
maxSelections: max,
maxSelections: Constants.maxSectors,
preSelectedOptions: userSectors ?? [],
onSave: (selectedOptions) async {
// Handle saving selected options

View File

@ -41,12 +41,12 @@ class SkillsForm extends StatelessWidget {
? 'Skills you are searching for'
: 'Your own skills',
description: skillsSought
? 'Choose up to 3 areas you are looking for in a co-founder'
: 'Select up to 3 areas in which you are skilled',
? 'Choose up to ${Constants.maxSkills} areas you are looking for in a co-founder'
: 'Select up to ${Constants.maxSkills} areas in which you are skilled',
saveButtonText: isRegProcess ? 'Save and continue' : 'Save',
options: SkillOption.values.toList(), // Convert enum values to list
minSelections: 1,
maxSelections: 3,
maxSelections: Constants.maxSkills,
preSelectedOptions:
userSkills ?? [], // Pass pre-selected skills to the form
onSave: (selectedOptions) async {

View File

@ -1,11 +1,11 @@
import 'dart:convert';
import 'dart:convert' show json;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../components/location_dialog.dart';
import '../components/my_button.dart';
import '../components/my_elevated_button.dart';
import '../components/text_bold.dart';
import '../components/text_with_bold.dart';
import '../constants.dart';
@ -554,9 +554,11 @@ class _UserDataPageState extends State<UserDataPage> {
const Divider(),
Padding(
padding: const EdgeInsets.all(8.0),
child: MyButton(
text: widget.isRegProcess ? 'Save and continue' : 'Save',
onTap: () {
child: MyElevatedButton(
child: Text(
widget.isRegProcess ? 'Save and continue' : 'Save',
),
onPressed: () {
_saveButtonClicked(context);
},
),
@ -588,7 +590,7 @@ class _UserDataPageState extends State<UserDataPage> {
});
},
child: Text(
_isLanguageListExpanded ? 'Show less languages' : 'Show more languages',
_isLanguageListExpanded ? 'Show less' : 'Show full list',
),
);
}

View File

@ -499,14 +499,14 @@ class UserMatchingPageState extends State<UserMatchingPage> {
const TextBold(
text: 'You\'ve viewed all available profiles.',
textAlign: TextAlign.center,
fontSize: 24,
fontSize: 20,
),
const SizedBox(height: 60),
const SizedBox(height: 36),
const TextBold(
text: 'Would you like to do another run '
'and see the remaining profiles again?',
textAlign: TextAlign.center,
fontSize: 24,
fontSize: 20,
),
const SizedBox(height: 20),
ElevatedButton(
@ -518,6 +518,7 @@ class UserMatchingPageState extends State<UserMatchingPage> {
},
child: const Text('Another run'),
),
const SizedBox(height: 20), // additional space
],
),
),

View File

@ -260,12 +260,12 @@ class _UserProfilePageState extends State<UserProfilePage> {
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
if (isOwner) const SizedBox(height: 16),
_buildWorkCulture(context),
_buildRisks(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
if (isOwner) const SizedBox(height: 16),
_buildRisks(context),
_buildWorkCulture(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
@ -277,6 +277,324 @@ class _UserProfilePageState extends State<UserProfilePage> {
);
}
Widget _buildAvatar(BuildContext context) {
Widget genderIcon = const Icon(null);
if (myData.gender == Gender.male) {
genderIcon = const Padding(
padding: EdgeInsets.only(left: 4.0),
child: Icon(Icons.male, color: Colors.blue),
);
} else if (myData.gender == Gender.female) {
genderIcon = const Icon(Icons.female, color: Colors.pink);
}
return Column(
children: [
if (isOwner)
_editButton(context, editNameInfo, alignment: Alignment.bottomRight),
CircleAvatar(
radius: 80,
backgroundImage:
((profileImageUrl != null && profileImageUrl!.isNotEmpty))
? NetworkImage(profileImageUrl!)
: null,
child: (profileImageUrl == null || profileImageUrl!.isEmpty)
? const Icon(Icons.person, size: 80)
: null,
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: Text(
isOwner
? myData.name
: '${myData.name} ${ageInfo(myData.born)}'.trim(),
style: const TextStyle(fontSize: 24),
),
),
genderIcon,
],
),
if (isOwner) Text(myData.email, style: const TextStyle(fontSize: 16)),
const SizedBox(height: 32),
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isOwner ? 'Short description of yourself' : 'Short description',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
ExpandableText(
linkEllipsis: false,
collapseOnTextTap: true,
expandOnTextTap: true,
myData.bio ?? 'n/a',
expandText: '[Expand]',
collapseText: '[Collapse]',
maxLines: 3,
linkColor: Colors.blue,
style: const TextStyle(fontSize: 16),
),
],
),
),
],
);
}
Widget _buildLocation(BuildContext context) {
int age = calcAge(myData.born);
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
myData.locations.length > 1 ? 'Locations' : 'Location',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
if (myData.locations.isEmpty)
const Text('n/a', style: TextStyle(fontSize: 16)),
if (myData.locations
.containsKey(Constants.dbDocMainLocation))
Text(
myData.locations[Constants.dbDocMainLocation]
.toString(),
style: const TextStyle(fontSize: 16),
),
if (myData.locations
.containsKey(Constants.dbDocSecondLocation))
Text(
myData.locations[Constants.dbDocSecondLocation]
.toString(),
style: const TextStyle(fontSize: 16),
),
],
),
if (isOwner)
_editButton(context, editUserDataInfo,
alignment: Alignment.bottomRight),
],
),
if (isOwner) const SizedBox(height: 16),
if (isOwner)
Text(
'Age',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
if (isOwner)
Text(
(age > 0 ? '$age years old, born ${myData.born}' : 'n/a'),
style: const TextStyle(fontSize: 16),
),
if (isOwner) const SizedBox(height: 16),
if (isOwner)
Text(
'Gender',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
if (isOwner)
Text(getDisplayText(myData.gender),
style: const TextStyle(fontSize: 16)),
const SizedBox(height: 16),
Text(
'Spoken languages',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
MyLanguageList(
langList: myData.languages,
textSize: 16,
),
],
),
),
],
);
}
Widget _buildSkills(BuildContext context) {
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Skills offered',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(myData.skills.map((x) => x.displayName).join(', '),
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserSkillsInfo),
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Skills sought',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(
myData.skillsSought
.map((x) => x.displayName)
.join(', '),
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserSkillsSoughtInfo),
],
),
],
),
),
],
);
}
Widget _buildSectors(BuildContext context) {
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Sectors of Interest',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(
sortSectorsList(myData.sectors)
.map((x) => x.displayName)
.join('\n'),
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserSectorsInfo),
],
),
],
),
),
],
);
}
Widget _buildVision(BuildContext context) {
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Availability',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(myData.availability.displayName,
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserVisionInfo),
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Vision and Goals',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(
myData.visions
.map((x) => x.displayName)
.join(',\n'),
style: const TextStyle(fontSize: 16)),
],
),
),
],
),
],
),
),
],
);
}
Widget _buildRisks(BuildContext context) {
return Column(
children: [
@ -402,325 +720,6 @@ class _UserProfilePageState extends State<UserProfilePage> {
);
}
Widget _buildVision(BuildContext context) {
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Availability',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(myData.availability.displayName,
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserVisionInfo),
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Vision and Goals',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(
myData.visions
.map((x) => x.displayName)
.join(',\n'),
style: const TextStyle(fontSize: 16)),
],
),
),
],
),
],
),
),
],
);
}
Widget _buildSectors(BuildContext context) {
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Sectors of Interest',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(
sortSectorsList(myData.sectors)
.map((x) => x.displayName)
.join('\n'),
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserSectorsInfo),
],
),
const SizedBox(height: 16),
],
),
),
],
);
}
Widget _buildSkills(BuildContext context) {
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Skills offered',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(myData.skills.map((x) => x.displayName).join(', '),
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserSkillsInfo),
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Skills sought',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
Text(
myData.skillsSought
.map((x) => x.displayName)
.join(', '),
style: const TextStyle(fontSize: 16)),
],
),
),
if (isOwner) _editButton(context, editUserSkillsSoughtInfo),
],
),
],
),
),
],
);
}
Widget _buildLocation(BuildContext context) {
int age = calcAge(myData.born);
return Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
myData.locations.length > 1 ? 'Locations' : 'Location',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
if (myData.locations.isEmpty)
const Text('n/a', style: TextStyle(fontSize: 16)),
if (myData.locations
.containsKey(Constants.dbDocMainLocation))
Text(
myData.locations[Constants.dbDocMainLocation]
.toString(),
style: const TextStyle(fontSize: 16),
),
if (myData.locations
.containsKey(Constants.dbDocSecondLocation))
Text(
myData.locations[Constants.dbDocSecondLocation]
.toString(),
style: const TextStyle(fontSize: 16),
),
],
),
if (isOwner)
_editButton(context, editUserDataInfo,
alignment: Alignment.bottomRight),
],
),
if (isOwner) const SizedBox(height: 16),
if (isOwner)
Text(
'Age',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
if (isOwner)
Text(
(age > 0 ? '$age years old, born ${myData.born}' : 'n/a'),
style: const TextStyle(fontSize: 16),
),
if (isOwner) const SizedBox(height: 16),
if (isOwner)
Text(
'Gender',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
if (isOwner)
Text(getDisplayText(myData.gender),
style: const TextStyle(fontSize: 16)),
const SizedBox(height: 16),
Text(
'Spoken languages',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
MyLanguageList(
langList: myData.languages,
textSize: 16,
),
],
),
),
],
);
}
Widget _buildAvatar(BuildContext context) {
Widget genderIcon = const Icon(null);
if (myData.gender == Gender.male) {
genderIcon = const Padding(
padding: EdgeInsets.only(left: 4.0),
child: Icon(Icons.male, color: Colors.blue),
);
} else if (myData.gender == Gender.female) {
genderIcon = const Icon(Icons.female, color: Colors.pink);
}
return Column(
children: [
if (isOwner)
_editButton(context, editNameInfo, alignment: Alignment.bottomRight),
CircleAvatar(
radius: 80,
backgroundImage:
((profileImageUrl != null && profileImageUrl!.isNotEmpty))
? NetworkImage(profileImageUrl!)
: null,
child: (profileImageUrl == null || profileImageUrl!.isEmpty)
? const Icon(Icons.person, size: 80)
: null,
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: Text(
isOwner
? myData.name
: '${myData.name} ${ageInfo(myData.born)}'.trim(),
style: const TextStyle(fontSize: 24),
),
),
genderIcon,
],
),
if (isOwner) Text(myData.email, style: const TextStyle(fontSize: 16)),
const SizedBox(height: 32),
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isOwner ? 'Short description of yourself' : 'Short description',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
ExpandableText(
linkEllipsis: false,
collapseOnTextTap: true,
expandOnTextTap: true,
myData.bio ?? 'n/a',
expandText: '[Expand]',
collapseText: '[Collapse]',
maxLines: 3,
linkColor: Colors.blue,
style: const TextStyle(fontSize: 16),
),
],
),
),
],
);
}
Widget _editButton(BuildContext context, void Function()? onPressedFunction,
{Alignment alignment = Alignment.topRight}) {
return Align(

View File

@ -1,6 +1,7 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import '../components/my_elevated_button.dart';
import '../components/text_bold.dart';
import '../constants.dart';
import '../enumerations.dart';
@ -198,7 +199,7 @@ class UserVisionPageState extends State<UserVisionPage> {
}),
const SizedBox(height: 20),
Center(
child: ElevatedButton(
child: MyElevatedButton(
onPressed: handleSubmit,
child:
Text(widget.isRegProcess ? 'Save and continue' : 'Save'),