228 lines
8.1 KiB
Dart
228 lines
8.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../../core/theme/app_theme.dart';
|
|
import '../../models/student.dart';
|
|
import '../../providers/dashboard_provider.dart';
|
|
|
|
class ProfileScreen extends ConsumerWidget {
|
|
const ProfileScreen({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final profileAsync = ref.watch(studentProfileProvider);
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: const Text('Student Profile'),
|
|
),
|
|
body: RefreshIndicator(
|
|
onRefresh: () async {
|
|
ref.invalidate(studentProfileProvider);
|
|
await ref.read(studentProfileProvider.future);
|
|
},
|
|
child: profileAsync.when(
|
|
loading: () => const Center(child: CircularProgressIndicator()),
|
|
error: (err, _) => Center(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
const Icon(Icons.error_outline_rounded, size: 48, color: AppTheme.errorColor),
|
|
const SizedBox(height: 12),
|
|
const Text(
|
|
'Failed to load profile details',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
err.toString(),
|
|
textAlign: TextAlign.center,
|
|
style: const TextStyle(color: AppTheme.textSecondary, fontSize: 13),
|
|
),
|
|
const SizedBox(height: 16),
|
|
ElevatedButton(
|
|
onPressed: () => ref.refresh(studentProfileProvider),
|
|
child: const Text('Retry'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
data: (profile) => _buildProfileBody(context, profile),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildProfileBody(BuildContext context, StudentProfile profile) {
|
|
return ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
// Profile Header Card
|
|
Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Column(
|
|
children: [
|
|
CircleAvatar(
|
|
radius: 36,
|
|
backgroundColor: AppTheme.primaryColor,
|
|
child: Text(
|
|
profile.fullName.isNotEmpty ? profile.fullName[0].toUpperCase() : 'S',
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 28,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Text(
|
|
profile.fullName,
|
|
style: const TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppTheme.textPrimary,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
|
decoration: BoxDecoration(
|
|
color: AppTheme.primaryLight.withOpacity(0.12),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Text(
|
|
'ID: ${profile.studentId}',
|
|
style: const TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
color: AppTheme.primaryDark,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Academic Information Card
|
|
Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Row(
|
|
children: [
|
|
Icon(Icons.school_outlined, size: 20, color: AppTheme.primaryColor),
|
|
SizedBox(width: 8),
|
|
Text(
|
|
'Academic Details',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppTheme.textPrimary,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Divider(),
|
|
_buildInfoTile('Admission Number', profile.admissionNumber),
|
|
if (profile.rollNumber != null) _buildInfoTile('Roll Number', profile.rollNumber!),
|
|
if (profile.program?.name != null) _buildInfoTile('Program', profile.program!.name),
|
|
if (profile.department?.name != null)
|
|
_buildInfoTile('Department', profile.department!.name),
|
|
if (profile.level?.name != null) _buildInfoTile('Level', profile.level!.name),
|
|
if (profile.academicYear?.name != null)
|
|
_buildInfoTile('Academic Year', profile.academicYear!.name),
|
|
if (profile.academicTerm?.name != null)
|
|
_buildInfoTile('Academic Term', profile.academicTerm!.name),
|
|
if (profile.batch?.name != null) _buildInfoTile('Batch', profile.batch!.name),
|
|
if (profile.semester?.name != null)
|
|
_buildInfoTile('Semester', profile.semester!.name),
|
|
if (profile.section?.name != null) _buildInfoTile('Section', profile.section!.name),
|
|
if (profile.campus?.name != null) _buildInfoTile('Campus', profile.campus!.name),
|
|
_buildInfoTile('Status', profile.status.toUpperCase()),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Personal Information Card
|
|
if (profile.email != null ||
|
|
profile.mobile != null ||
|
|
profile.gender != null ||
|
|
profile.dateOfBirth != null)
|
|
Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Row(
|
|
children: [
|
|
Icon(Icons.badge_outlined, size: 20, color: AppTheme.primaryColor),
|
|
SizedBox(width: 8),
|
|
Text(
|
|
'Personal Information',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppTheme.textPrimary,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Divider(),
|
|
if (profile.email != null) _buildInfoTile('Email', profile.email!),
|
|
if (profile.mobile != null) _buildInfoTile('Mobile', profile.mobile!),
|
|
if (profile.gender != null)
|
|
_buildInfoTile('Gender', profile.gender!.toUpperCase()),
|
|
if (profile.dateOfBirth != null)
|
|
_buildInfoTile('Date of Birth', profile.dateOfBirth!),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildInfoTile(String label, String value) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
SizedBox(
|
|
width: 140,
|
|
child: Text(
|
|
label,
|
|
style: const TextStyle(
|
|
fontSize: 13,
|
|
color: AppTheme.textSecondary,
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Text(
|
|
value,
|
|
style: const TextStyle(
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.w600,
|
|
color: AppTheme.textPrimary,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|