🎉 Initial commit: AudiOhm - Alternative à Spotify avec streaming YouTube

Features:
- Frontend Flutter avec thème néon cyberpunk
- Backend FastAPI avec streaming YouTube
- Base de données PostgreSQL + Redis
- Authentification JWT complète
- Recherche multi-source (DB + YouTube)
- Playlists CRUD avec drag & drop
- Queue management
- Settings avec audio quality
- Interface adaptative (Desktop + Mobile)

Tech Stack:
- Frontend: Flutter 3.2+, Riverpod
- Backend: Python 3.11+, FastAPI
- Database: PostgreSQL 15+
- Cache: Redis 7+
- Streaming: yt-dlp + FFmpeg

🚀 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
feldenr
2026-01-18 17:08:59 +01:00
commit 9c504d2c3d
128 changed files with 22638 additions and 0 deletions
@@ -0,0 +1,192 @@
/// 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),
);
}
}