guidesoutenance
This commit is contained in:
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../services/intra_api_exception.dart';
|
||||
import '../services/intra_profile_service.dart';
|
||||
import '../theme/swifty_ui.dart';
|
||||
|
||||
/// Vue 2 — profil complet (étape 4).
|
||||
class ProfileScreen extends StatefulWidget {
|
||||
@@ -79,18 +80,18 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
final imageUrl = _imageUrl(user);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(login),
|
||||
backgroundColor: const Color(0xFF00BABC),
|
||||
foregroundColor: Colors.black,
|
||||
),
|
||||
appBar: SwiftyUi.appBar(title: login, showBack: true),
|
||||
body: _loading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _error != null
|
||||
? _ErrorBody(message: _error!, onRetry: _load)
|
||||
? ResponsiveScrollBody(
|
||||
maxWidth: SwiftyUi.searchMaxWidth,
|
||||
child: _ErrorBody(message: _error!, onRetry: _load),
|
||||
)
|
||||
: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final wide = constraints.maxWidth >= 720;
|
||||
final wide =
|
||||
constraints.maxWidth >= SwiftyUi.wideBreakpoint;
|
||||
final profile = _profile!;
|
||||
final header = _ProfileHeader(
|
||||
login: login,
|
||||
@@ -104,51 +105,65 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
final skills = _SkillsCard(skills: profile.skills);
|
||||
final projects = _ProjectsCard(projects: profile.projects);
|
||||
|
||||
final column = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
header,
|
||||
const SizedBox(height: 16),
|
||||
details,
|
||||
const SizedBox(height: 16),
|
||||
skills,
|
||||
const SizedBox(height: 16),
|
||||
projects,
|
||||
],
|
||||
);
|
||||
|
||||
if (wide) {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
children: [
|
||||
header,
|
||||
const SizedBox(height: 16),
|
||||
details,
|
||||
],
|
||||
),
|
||||
padding: SwiftyUi.pagePadding(constraints),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: SwiftyUi.contentMaxWidth,
|
||||
),
|
||||
const SizedBox(width: 24),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
children: [
|
||||
skills,
|
||||
const SizedBox(height: 16),
|
||||
projects,
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
children: [header, const SizedBox(height: 16), details],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 24),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
children: [
|
||||
skills,
|
||||
const SizedBox(height: 16),
|
||||
projects,
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
header,
|
||||
const SizedBox(height: 16),
|
||||
details,
|
||||
const SizedBox(height: 16),
|
||||
skills,
|
||||
const SizedBox(height: 16),
|
||||
projects,
|
||||
],
|
||||
padding: SwiftyUi.pagePadding(constraints),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: SwiftyUi.contentMaxWidth,
|
||||
),
|
||||
child: column,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -165,20 +180,18 @@ class _ErrorBody extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
message,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.error),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(onPressed: onRetry, child: const Text('Réessayer')),
|
||||
],
|
||||
),
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 48),
|
||||
ErrorMessage(message: message),
|
||||
const SizedBox(height: 20),
|
||||
LoadingFilledButton(
|
||||
label: 'Réessayer',
|
||||
loading: false,
|
||||
onPressed: onRetry,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -269,21 +282,39 @@ class _DetailRow extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 120,
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final stacked = constraints.maxWidth < 400;
|
||||
if (stacked) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 2),
|
||||
Text(value),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 120,
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
Expanded(child: Text(value)),
|
||||
],
|
||||
),
|
||||
Expanded(child: Text(value)),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -318,7 +349,7 @@ class _SkillsCard extends StatelessWidget {
|
||||
value: (s.level + s.percentage / 100).clamp(0, 15) / 15,
|
||||
minHeight: 6,
|
||||
backgroundColor: Colors.grey.shade300,
|
||||
color: const Color(0xFF00BABC),
|
||||
color: SwiftyUi.brand,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -356,18 +387,25 @@ class _ProjectsCard extends StatelessWidget {
|
||||
final statusLabel =
|
||||
p.status == 'failed' ? 'Échec' : 'Validé';
|
||||
final mark = p.finalMark != null ? ' · ${p.finalMark}' : '';
|
||||
return ListTile(
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(p.name),
|
||||
trailing: Text(
|
||||
'$statusLabel$mark',
|
||||
style: TextStyle(
|
||||
color: p.status == 'failed'
|
||||
? Theme.of(context).colorScheme.error
|
||||
: Colors.green.shade700,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(p.name),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'$statusLabel$mark',
|
||||
style: TextStyle(
|
||||
color: p.status == 'failed'
|
||||
? Theme.of(context).colorScheme.error
|
||||
: Colors.green.shade700,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user