Skip to content

Commit

Permalink
UC classes page redesign (#1438)
Browse files Browse the repository at this point in the history
  • Loading branch information
HenriqueSFernandes authored Feb 6, 2025
2 parents 0d86b4e + e253604 commit 213f317
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 99 deletions.
8 changes: 8 additions & 0 deletions packages/uni_app/lib/utils/student_number_getter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:uni/model/providers/startup/session_provider.dart';

int getStudentNumber(SessionProvider sessionProvider) {
return int.tryParse(
sessionProvider.state!.username.replaceAll(RegExp(r'\D'), ''),
) ??
0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,175 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:uni/model/entities/course_units/course_unit_class.dart';
import 'package:uni/model/providers/startup/session_provider.dart';
import 'package:uni/view/course_unit_info/widgets/course_unit_info_card.dart';
import 'package:uni/view/course_unit_info/widgets/course_unit_student_row.dart';
import 'package:uni/utils/student_number_getter.dart';
import 'package:uni/view/course_unit_info/widgets/course_unit_student_tile.dart';
import 'package:uni_ui/theme.dart';

class CourseUnitClassesView extends StatelessWidget {
class CourseUnitClassesView extends StatefulWidget {
const CourseUnitClassesView(this.classes, {super.key});

final List<CourseUnitClass> classes;

@override
_CourseUnitClassesViewState createState() => _CourseUnitClassesViewState();
}

class _CourseUnitClassesViewState extends State<CourseUnitClassesView> {
static const double _itemWidth = 140;
static const Duration _scrollDuration = Duration(milliseconds: 300);

final ScrollController _scrollController = ScrollController();

late int selectedIndex;
late int studentNumber;
late SessionProvider sessionProvider;

@override
void initState() {
super.initState();
sessionProvider = context.read<SessionProvider>();
studentNumber = getStudentNumber(sessionProvider);

selectedIndex = widget.classes.indexWhere(
(courseClass) => courseClass.students.any(
(student) => student.number == studentNumber,
),
);

if (selectedIndex == -1) {
selectedIndex = 0;
}

WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToSelectedClass();
});
}

void _scrollToSelectedClass() {
final screenWidth = MediaQuery.of(context).size.width;
final offset =
(_itemWidth * selectedIndex) - (screenWidth - _itemWidth) / 2;

_scrollController.animateTo(
offset < 0 ? 0 : offset,
duration: _scrollDuration,
curve: Curves.easeInOut,
);
}

void _handleClassTap(int index) {
setState(() => selectedIndex = index);
_scrollToSelectedClass();
}

@override
void dispose() {
_scrollController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final session = context.read<SessionProvider>().state!;
final cards = <CourseUnitInfoCard>[];
for (final courseUnitClass in classes) {
final isMyClass = courseUnitClass.students
.where(
(student) =>
student.number ==
(int.tryParse(
session.username.replaceAll(RegExp(r'\D'), ''),
) ??
0),
)
.isNotEmpty;
cards.add(
CourseUnitInfoCard(
isMyClass
? '${courseUnitClass.className} *'
: courseUnitClass.className,
Column(
children: courseUnitClass.students
.map((student) => CourseUnitStudentRow(student, session))
.toList(),
),
return SingleChildScrollView(
child: Column(
children: [
_buildClassSelector(studentNumber),
_buildStudentList(sessionProvider),
],
),
);
}

Widget _buildClassSelector(int studentNumber) {
return Padding(
padding: const EdgeInsets.only(bottom: 20),
child: SizedBox(
height: 55,
child: ListView.builder(
controller: _scrollController,
scrollDirection: Axis.horizontal,
itemCount: widget.classes.length,
itemBuilder: (context, index) {
final courseUnitClass = widget.classes[index];
final isMyClass = courseUnitClass.students
.any((student) => student.number == studentNumber);
final isSelected = index == selectedIndex;

return ConstrainedBox(
constraints: const BoxConstraints(
minWidth: _itemWidth,
maxWidth: _itemWidth,
),
child: GestureDetector(
onTap: () => _handleClassTap(index),
child: Container(
margin:
const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
decoration: BoxDecoration(
color: isSelected
? lightTheme.colorScheme.primary
: lightTheme.colorScheme.secondary,
borderRadius: BorderRadius.circular(25),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 2),
),
],
),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 10,
),
alignment: Alignment.center,
child: Text(
isMyClass
? '${courseUnitClass.className} *'
: courseUnitClass.className,
style: isSelected
? lightTheme.textTheme.labelMedium?.copyWith(
color: lightTheme.colorScheme.onPrimary,
)
: lightTheme.textTheme.labelMedium,
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
);
},
),
);
}
),
);
}

return Container(
padding: const EdgeInsets.only(left: 10, right: 10),
child: ListView(children: cards),
Widget _buildStudentList(SessionProvider session) {
final currentClass = widget.classes[selectedIndex];
return Padding(
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 8),
child: GridView.builder(
key: ValueKey(currentClass.className),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 20,
mainAxisSpacing: 5,
childAspectRatio: 0.60,
),
itemCount: currentClass.students.length,
itemBuilder: (context, index) {
final student = currentClass.students[index];
return CourseUnitStudentTile(
student,
session.state!,
key: ValueKey('${currentClass.className}_${student.number}'),
);
},
),
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import 'package:figma_squircle/figma_squircle.dart';
import 'package:flutter/material.dart';
import 'package:uni/model/entities/course_units/course_unit_class.dart';
import 'package:uni/model/providers/startup/profile_provider.dart';
import 'package:uni/session/flows/base/session.dart';
import 'package:uni_ui/theme.dart';

class CourseUnitStudentTile extends StatelessWidget {
const CourseUnitStudentTile(this.student, this.session, {super.key});

final CourseUnitStudent student;
final Session session;

@override
Widget build(BuildContext context) {
final userImage = ProfileProvider.fetchOrGetCachedProfilePicture(
session,
studentNumber: student.number,
);
return FutureBuilder(
builder: (context, snapshot) {
final names = student.name.split(RegExp(r'\s+'));
final firstName = names.first;
final lastName = names.last;

return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
decoration: ShapeDecoration(
shape: SmoothRectangleBorder(
borderRadius: SmoothBorderRadius(
cornerRadius: 25,
cornerSmoothing: 1,
),
),
image: DecorationImage(
fit: BoxFit.cover,
image: snapshot.hasData && snapshot.data!.lengthSync() > 0
? FileImage(snapshot.data!) as ImageProvider
: const AssetImage(
'assets/images/profile_placeholder.png',
),
),
),
child: AspectRatio(
aspectRatio: 1,
child: Container(),
),
),
const SizedBox(height: 8),
LayoutBuilder(
builder: (context, constraints) {
return Container(
width: constraints.maxWidth,
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Column(
children: [
Text(
firstName,
overflow: TextOverflow.fade,
style: lightTheme.textTheme.titleLarge?.copyWith(
color: grayText,
),
textAlign: TextAlign.center,
),
Text(
lastName,
overflow: TextOverflow.ellipsis,
style: lightTheme.textTheme.titleLarge?.copyWith(
color: grayText,
),
textAlign: TextAlign.center,
),
],
),
);
},
),
],
);
},
future: userImage,
);
}
}
2 changes: 1 addition & 1 deletion packages/uni_app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ packages:
source: hosted
version: "2.1.3"
figma_squircle:
dependency: transitive
dependency: "direct main"
description:
name: figma_squircle
sha256: "790b91a9505e90d246f6efe2fa065ff7fffe658c7b44fe9b5b20c7b0ad3818c0"
Expand Down
1 change: 1 addition & 0 deletions packages/uni_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies:
email_validator: ^2.0.1
expandable: ^5.0.1
expansion_tile_card: ^3.0.0
figma_squircle: ^0.5.3
flutter:
sdk: flutter
flutter_cache_manager: ^3.3.1
Expand Down

0 comments on commit 213f317

Please sign in to comment.