Files
AudiOhm/frontend/lib/presentation/widgets/settings/profile_section.dart
T
root a89c7894cf Initial commit: AudiOhm - Alternative Spotify avec streaming YouTube
Backend:
- FastAPI avec PostgreSQL et Redis
- Authentification JWT complète
- API REST pour musique, playlists, recherche
- Streaming audio via yt-dlp
- SQLAlchemy 2.0 async

Frontend:
- Flutter avec thème néon cyberpunk
- State management Riverpod
- Layout adaptatif desktop/mobile
- Lecteur audio avec mini-player

Infrastructure:
- Docker Compose (PostgreSQL + Redis)
- Scripts d'installation automatisés
- Scripts de build pour exécutables

Fichiers ajoutés:
- BUILD_CLIENT_*.bat/sh: Scripts de compilation
- BUILD_CLIENT_README.md: Documentation compilation
- CHECK_FLUTTER.sh: Vérificateur d'environnement
- requirements.txt mis à jour pour Python 3.13
- Modèles SQLAlchemy corrigés (metadata -> extra_metadata)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-18 20:08:36 +00:00

193 lines
6.6 KiB
Dart

/// Profile Section Widget
library;
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/theme/colors.dart';
import '../../../core/theme/text_styles.dart';
import '../../../domain/entities/user.dart';
import '../../providers/settings_provider.dart';
import 'edit_profile_dialog.dart';
/// Profile section widget
class ProfileSection extends ConsumerWidget {
const ProfileSection({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final settingsState = ref.watch(settingsProvider);
final user = settingsState.user;
if (user == null) {
return const SizedBox.shrink();
}
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColors.surface,
AppColors.surfaceVariant,
],
),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppColors.cyan.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: AppColors.cyan.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
// Avatar and name
Row(
children: [
// Avatar
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: AppColors.primaryGradient,
boxShadow: AppColors.cyanGlow,
),
child: ClipOval(
child: user.avatarUrl != null
? Image.network(
user.avatarUrl!,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return _buildDefaultAvatar(user);
},
)
: _buildDefaultAvatar(user),
),
),
const SizedBox(width: 20),
// Name and email
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Flexible(
child: Text(
user.displayName ?? user.username,
style: AppTextStyles.h3.copyWith(
color: AppColors.onBackground,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis,
),
),
if (user.isPremium) ...[
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
gradient: AppColors.accentGradient,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: AppColors.violet.withOpacity(0.3),
blurRadius: 8,
),
],
),
child: Text(
'PREMIUM',
style: AppTextStyles.caption.copyWith(
color: Colors.white,
fontWeight: FontWeight.w700,
letterSpacing: 1,
),
),
),
],
],
),
const SizedBox(height: 6),
Text(
user.email,
style: AppTextStyles.body.copyWith(
color: AppColors.muted,
),
),
const SizedBox(height: 6),
Text(
'@${user.username}',
style: AppTextStyles.bodySmall.copyWith(
color: AppColors.onSurfaceVariant,
),
),
],
),
),
],
),
const SizedBox(height: 20),
// Edit Profile Button
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () => _showEditProfileDialog(context, ref, user),
icon: const Icon(Icons.edit_outlined, size: 18),
label: const Text('Edit Profile'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
backgroundColor: AppColors.cyan.withOpacity(0.15),
foregroundColor: AppColors.cyan,
elevation: 0,
side: BorderSide(
color: AppColors.cyan.withOpacity(0.3),
width: 1,
),
),
),
),
],
),
),
);
}
Widget _buildDefaultAvatar(User user) {
return Container(
color: AppColors.surfaceVariant,
child: Center(
child: Text(
(user.displayName ?? user.username)
.substring(0, 1)
.toUpperCase(),
style: AppTextStyles.h2.copyWith(
color: AppColors.cyan,
fontWeight: FontWeight.w700,
),
),
),
);
}
void _showEditProfileDialog(BuildContext context, WidgetRef ref, User user) {
showDialog(
context: context,
builder: (context) => EditProfileDialog(user: user),
);
}
}