Files
AudiOhm/frontend/lib/presentation/pages/mobile/mobile_home_page.dart
T
root 85dad89d5b feat: Modernisation UI/UX et configuration Flutter multi-plateforme
Phase 1 - Corrections Critiques:
- Fixed memory leaks dans music_provider.dart (stream subscriptions)
- Fixed race conditions dans search_provider.dart (stale results)
- Fixed token refresh errors dans api_service.dart
- Improved error handling avec messages utilisateur
- Changed API URL to HTTPS by default

Phase 2 - Améliorations UX Desktop:
- Ajouté cursor pointers sur tous les éléments cliquables
- Implémenté hover states avec effets néon glow (200ms transitions)
- Créé skeleton loading states avec shimmer animation
- Ajouté widgets: ClickableWrapper, ErrorDisplay, SkeletonLoading
- Enhanced visual feedback pour desktop users

Phase 3 - Configuration Flutter:
- Configuré Android (Gradle 8.1.0, Kotlin 1.9.0, minSdk 21, targetSdk 34)
- Créé launcher icons cyberpunk néon (5 densités)
- Configuré Windows desktop (structure complète)
- Activé Linux desktop support
- Ajouté package équatable pour entités de domaine
- Corrigé imports (colors.dart, auth_provider.dart)
- Fixed Dio API compatibility (RequestOptions)

Documentation:
- STYLE_GUIDE.md: Guide complet (100+ pages)
- DESIGN_IMPLEMENTATION_GUIDE.md: Implémentation Flutter
- BUILD_STATUS.md: Status builds + troubleshooting
- QUICKSTART_BUILDS.md: Guide rapide
- BUILD_INDEX.md: Index documentation
- PHASE_1_CORRECTIONS.md: Corrections Phase 1
- PHASE_2_UX_IMPROVEMENTS.md: Améliorations Phase 2
- PR_REVIEW_SUMMARY.md: Revue code complète
- CODE_ANALYSIS_AND_PRIORITIES.md: Analyse code

Scripts & Builds:
- BUILD_ALL.sh: Script automatisé builds multi-plateforme
- builds/: Structure avec README par plateforme
- design-system/: Système de design complet

Backend:
- Ajouté streaming HTTP Range pour audio progressif
- Enhanced YouTube service avec métadonnées complètes
- Improved error handling et validation

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-01-19 07:44:40 +00:00

308 lines
8.6 KiB
Dart

import 'package:flutter/material.dart';
import '../../../core/theme/colors.dart';
import '../../widgets/common/skeleton_loading.dart';
/// Mobile Home Page with loading states
class MobileHomePage extends StatelessWidget {
const MobileHomePage({super.key});
@override
Widget build(BuildContext context) {
// TODO: Integrate with actual data provider
// For now, showing skeleton loading as example
final isLoading = false; // Change to true to see skeleton
return CustomScrollView(
slivers: [
// Header
SliverAppBar(
expandedHeight: 180,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: const Text(
'Good Evening',
style: TextStyle(
color: AppColors.onBackground,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColors.surface,
AppColors.surfaceVariant,
],
),
),
),
),
),
// Content sections or skeleton
SliverToBoxAdapter(
child: isLoading
? const PageSkeleton(
showHero: false,
sectionCount: 3,
)
: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Quick picks grid
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.5,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: 6,
itemBuilder: (context, index) {
return const _QuickPickCard();
},
),
const SizedBox(height: 24),
// Recently played
const _SectionTitle(title: 'Recently Played'),
const SizedBox(height: 12),
SizedBox(
height: 160,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return const _AlbumCard();
},
),
),
const SizedBox(height: 24),
// Made for you
const _SectionTitle(title: 'Made For You'),
const SizedBox(height: 12),
SizedBox(
height: 160,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 8,
itemBuilder: (context, index) {
return const _PlaylistCard();
},
),
),
],
),
),
),
],
);
}
}
class _SectionTitle extends StatelessWidget {
final String title;
const _SectionTitle({required this.title});
@override
Widget build(BuildContext context) {
return Text(
title,
style: Theme.of(context).textTheme.displaySmall?.copyWith(
color: AppColors.cyan,
fontSize: 20,
),
);
}
}
class _QuickPickCard extends StatelessWidget {
const _QuickPickCard();
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.surface,
AppColors.surfaceVariant,
],
),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: AppColors.cyan.withOpacity(0.2),
width: 1,
),
),
child: Row(
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
gradient: AppColors.primaryGradient,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(7),
bottomLeft: Radius.circular(7),
),
),
child: const Icon(
Icons.music_note,
color: AppColors.onBackground,
size: 20,
),
),
const Expanded(
child: Padding(
padding: EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Playlist',
style: TextStyle(
fontWeight: FontWeight.w500,
color: AppColors.onSurface,
fontSize: 13,
),
),
Text(
'Description',
style: TextStyle(
fontSize: 10,
color: AppColors.muted,
),
),
],
),
),
),
],
),
);
}
}
class _AlbumCard extends StatelessWidget {
const _AlbumCard();
@override
Widget build(BuildContext context) {
return Container(
width: 120,
margin: const EdgeInsets.only(right: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Album art
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
gradient: AppColors.accentGradient,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.album,
size: 48,
color: AppColors.onBackground,
),
),
const SizedBox(height: 6),
// Album info
const Text(
'Album Name',
style: TextStyle(
fontWeight: FontWeight.w500,
color: AppColors.onSurface,
fontSize: 13,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const Text(
'Artist',
style: TextStyle(
fontSize: 11,
color: AppColors.muted,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
);
}
}
class _PlaylistCard extends StatelessWidget {
const _PlaylistCard();
@override
Widget build(BuildContext context) {
return Container(
width: 120,
margin: const EdgeInsets.only(right: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Playlist art
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
gradient: AppColors.fullGradient,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.playlist_play,
size: 48,
color: AppColors.onBackground,
),
),
const SizedBox(height: 6),
// Playlist info
const Text(
'Playlist',
style: TextStyle(
fontWeight: FontWeight.w500,
color: AppColors.onSurface,
fontSize: 13,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const Text(
'Description',
style: TextStyle(
fontSize: 11,
color: AppColors.muted,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
);
}
}