small fix, don't worry about it

This commit is contained in:
Tomas Dvorak
2026-04-10 12:05:40 +02:00
parent 7b7ed0083f
commit 5ab2773f98
55 changed files with 3240 additions and 483 deletions
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:supabase_flutter/supabase_flutter.dart' as supabase;
import '../../../bootstrap/supabase_client.dart';
import '../../../core/widgets/app_scaffold.dart';
import '../../../core/widgets/loading_indicator.dart';
import '../../../core/widgets/empty_state.dart';
@@ -23,7 +23,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
@override
void initState() {
super.initState();
final userId = supabase.Supabase.instance.client.auth.currentUser?.id;
final userId = currentSupabaseUserId;
if (userId != null) {
ref.read(profileControllerProvider.notifier).loadProfile(userId);
}
@@ -33,10 +33,11 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
Widget build(BuildContext context) {
final profileState = ref.watch(profileControllerProvider);
final achievementsState = ref.watch(achievementsControllerProvider);
final userId = supabase.Supabase.instance.client.auth.currentUser?.id;
final userId = currentSupabaseUserId;
if (userId == null) {
return AppScaffold(
title: 'Profile',
body: Semantics(
label: 'Not signed in',
child: const EmptyState(
@@ -105,6 +106,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
SliverAppBar(
expandedHeight: 200,
pinned: true,
title: const Text('Profile'),
flexibleSpace: FlexibleSpaceBar(
background: Container(
decoration: BoxDecoration(
@@ -408,7 +410,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
);
if (confirmed == true && context.mounted) {
await supabase.Supabase.instance.client.auth.signOut();
await signOutCurrentSupabaseUser();
if (context.mounted) {
context.go('/');
}
@@ -8,6 +8,7 @@ import 'package:supabase_flutter/supabase_flutter.dart' as supabase;
import '../../../core/widgets/app_scaffold.dart';
import '../../../core/widgets/primary_button.dart';
import '../../../core/utils/validators.dart';
import '../../../core/utils/unit_conversion_utils.dart';
import '../application/profile_controller.dart';
class ProfileSetupScreen extends ConsumerStatefulWidget {
@@ -25,6 +26,8 @@ class _ProfileSetupScreenState extends ConsumerState<ProfileSetupScreen> {
final _instagramController = TextEditingController();
final _tiktokController = TextEditingController();
final _websiteController = TextEditingController();
final _heightController = TextEditingController();
final _weightController = TextEditingController();
dynamic _avatarFile;
String? _avatarUrl;
@@ -32,6 +35,11 @@ class _ProfileSetupScreenState extends ConsumerState<ProfileSetupScreen> {
bool _isCheckingUsername = false;
bool _isUsernameAvailable = true;
String? _usernameError;
Gender? _selectedGender;
DateTime? _selectedBirthDate;
HeightUnit _selectedHeightUnit = HeightUnit.metric;
WeightUnit _selectedWeightUnit = WeightUnit.metric;
final ImagePicker _imagePicker = ImagePicker();
@@ -152,6 +160,18 @@ class _ProfileSetupScreenState extends ConsumerState<ProfileSetupScreen> {
uploadedAvatarUrl = await _uploadAvatar();
}
// Parse height and weight values
double? heightCm;
double? weightKg;
if (_heightController.text.isNotEmpty) {
heightCm = UnitConversionUtils.parseHeight(_heightController.text, _selectedHeightUnit);
}
if (_weightController.text.isNotEmpty) {
weightKg = UnitConversionUtils.parseWeight(_weightController.text, _selectedWeightUnit);
}
await ref.read(profileControllerProvider.notifier).completeProfileSetup(
userId: userId,
username: _usernameController.text.trim(),
@@ -169,6 +189,12 @@ class _ProfileSetupScreenState extends ConsumerState<ProfileSetupScreen> {
websiteUrl: _websiteController.text.trim().isEmpty
? null
: _websiteController.text.trim(),
gender: _selectedGender,
birthDate: _selectedBirthDate,
heightCm: heightCm,
weightKg: weightKg,
heightUnit: _selectedHeightUnit,
weightUnit: _selectedWeightUnit,
);
if (mounted) {
@@ -195,6 +221,8 @@ class _ProfileSetupScreenState extends ConsumerState<ProfileSetupScreen> {
_instagramController.dispose();
_tiktokController.dispose();
_websiteController.dispose();
_heightController.dispose();
_weightController.dispose();
super.dispose();
}
@@ -341,6 +369,170 @@ class _ProfileSetupScreenState extends ConsumerState<ProfileSetupScreen> {
),
enabled: !_isLoading,
),
const SizedBox(height: 24),
const Divider(),
const SizedBox(height: 16),
Text(
'Biometric Information (Optional)',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary,
),
),
const SizedBox(height: 16),
// Gender Field
DropdownButtonFormField<Gender>(
initialValue: _selectedGender,
decoration: const InputDecoration(
labelText: 'Gender',
prefixIcon: Icon(Icons.person_outline),
border: OutlineInputBorder(),
),
items: Gender.values.map((gender) {
return DropdownMenuItem(
value: gender,
child: Row(
children: [
Text(gender.emoji),
const SizedBox(width: 8),
Text(gender.displayName),
],
),
);
}).toList(),
onChanged: !_isLoading ? (Gender? value) {
setState(() {
_selectedGender = value;
});
} : null,
),
const SizedBox(height: 16),
// Birth Date Field
InkWell(
onTap: !_isLoading ? () async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: _selectedBirthDate ?? DateTime.now().subtract(const Duration(days: 365 * 25)),
firstDate: DateTime.now().subtract(const Duration(days: 365 * 120)),
lastDate: DateTime.now().subtract(const Duration(days: 365 * 13)),
);
if (picked != null) {
setState(() {
_selectedBirthDate = picked;
});
}
} : null,
child: InputDecorator(
decoration: const InputDecoration(
labelText: 'Birth Date',
prefixIcon: Icon(Icons.cake_outlined),
border: OutlineInputBorder(),
),
child: Text(
_selectedBirthDate != null
? '${_selectedBirthDate!.day}/${_selectedBirthDate!.month}/${_selectedBirthDate!.year}'
: 'Select your birth date',
style: TextStyle(
color: _selectedBirthDate != null
? null
: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6),
),
),
),
),
const SizedBox(height: 16),
// Height and Weight Row
Row(
children: [
Expanded(
child: TextFormField(
controller: _heightController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Height (${_selectedHeightUnit == HeightUnit.metric ? 'cm' : 'ft/in'})',
prefixIcon: const Icon(Icons.height_outlined),
border: const OutlineInputBorder(),
suffixIcon: PopupMenuButton<HeightUnit>(
icon: const Icon(Icons.tune),
onSelected: (HeightUnit unit) {
setState(() {
_selectedHeightUnit = unit;
// Convert existing value if needed
if (_heightController.text.isNotEmpty) {
final currentValue = double.tryParse(_heightController.text);
if (currentValue != null) {
double convertedValue;
if (unit == HeightUnit.imperial && _selectedHeightUnit == HeightUnit.metric) {
convertedValue = UnitConversionUtils.cmToInches(currentValue);
_heightController.text = convertedValue.toStringAsFixed(1);
} else if (unit == HeightUnit.metric && _selectedHeightUnit == HeightUnit.imperial) {
convertedValue = UnitConversionUtils.inchesToCm(currentValue);
_heightController.text = convertedValue.toStringAsFixed(1);
}
}
}
});
},
itemBuilder: (context) => [
const PopupMenuItem(value: HeightUnit.metric, child: Text('Metric (cm)')),
const PopupMenuItem(value: HeightUnit.imperial, child: Text('Imperial (ft/in)')),
],
),
),
enabled: !_isLoading,
),
),
const SizedBox(width: 16),
Expanded(
child: TextFormField(
controller: _weightController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Weight (${_selectedWeightUnit == WeightUnit.metric ? 'kg' : 'lbs'})',
prefixIcon: const Icon(Icons.monitor_weight_outlined),
border: const OutlineInputBorder(),
suffixIcon: PopupMenuButton<WeightUnit>(
icon: const Icon(Icons.tune),
onSelected: (WeightUnit unit) {
setState(() {
_selectedWeightUnit = unit;
// Convert existing value if needed
if (_weightController.text.isNotEmpty) {
final currentValue = double.tryParse(_weightController.text);
if (currentValue != null) {
double convertedValue;
if (unit == WeightUnit.imperial && _selectedWeightUnit == WeightUnit.metric) {
convertedValue = UnitConversionUtils.kgToLbs(currentValue);
_weightController.text = convertedValue.toStringAsFixed(1);
} else if (unit == WeightUnit.metric && _selectedWeightUnit == WeightUnit.imperial) {
convertedValue = UnitConversionUtils.lbsToKg(currentValue);
_weightController.text = convertedValue.toStringAsFixed(1);
}
}
}
});
},
itemBuilder: (context) => [
const PopupMenuItem(value: WeightUnit.metric, child: Text('Metric (kg)')),
const PopupMenuItem(value: WeightUnit.imperial, child: Text('Imperial (lbs)')),
],
),
),
enabled: !_isLoading,
),
),
],
),
const SizedBox(height: 24),
const Divider(),
const SizedBox(height: 16),
Text(
'Social Links (Optional)',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary,
),
),
const SizedBox(height: 16),
TextFormField(
controller: _twitterController,