feat: slicing profile page
This commit is contained in:
parent
26ed9797b8
commit
dbb3bd8c90
|
@ -7,6 +7,7 @@ import 'package:quiz_app/feature/login/bindings/login_binding.dart';
|
||||||
import 'package:quiz_app/feature/login/view/login_page.dart';
|
import 'package:quiz_app/feature/login/view/login_page.dart';
|
||||||
import 'package:quiz_app/feature/navigation/bindings/navigation_binding.dart';
|
import 'package:quiz_app/feature/navigation/bindings/navigation_binding.dart';
|
||||||
import 'package:quiz_app/feature/navigation/views/navbar_view.dart';
|
import 'package:quiz_app/feature/navigation/views/navbar_view.dart';
|
||||||
|
import 'package:quiz_app/feature/profile/binding/profile_binding.dart';
|
||||||
import 'package:quiz_app/feature/register/binding/register_binding.dart';
|
import 'package:quiz_app/feature/register/binding/register_binding.dart';
|
||||||
import 'package:quiz_app/feature/register/view/register_page.dart';
|
import 'package:quiz_app/feature/register/view/register_page.dart';
|
||||||
import 'package:quiz_app/feature/search/binding/search_binding.dart';
|
import 'package:quiz_app/feature/search/binding/search_binding.dart';
|
||||||
|
@ -44,6 +45,7 @@ class AppPages {
|
||||||
HomeBinding(),
|
HomeBinding(),
|
||||||
SearchBinding(),
|
SearchBinding(),
|
||||||
HistoryBinding(),
|
HistoryBinding(),
|
||||||
|
ProfileBinding(),
|
||||||
],
|
],
|
||||||
middlewares: [AuthMiddleware()],
|
middlewares: [AuthMiddleware()],
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:quiz_app/feature/profile/controller/profile_controller.dart';
|
||||||
|
|
||||||
|
class ProfileBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
Get.lazyPut(() => ProfileController());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class ProfileController extends GetxController {
|
||||||
|
final userName = 'Alhidan Robbani'.obs;
|
||||||
|
final email = 'alhidan@example.com'.obs;
|
||||||
|
|
||||||
|
final totalQuizzes = 12.obs;
|
||||||
|
final avgScore = 85.obs;
|
||||||
|
|
||||||
|
void logout() {
|
||||||
|
print("Logout pressed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void editProfile() {
|
||||||
|
print("Edit profile pressed");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,106 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:quiz_app/feature/profile/controller/profile_controller.dart';
|
||||||
|
|
||||||
class ProfileView extends StatelessWidget {
|
class ProfileView extends GetView<ProfileController> {
|
||||||
const ProfileView({super.key});
|
const ProfileView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold();
|
return Scaffold(
|
||||||
|
backgroundColor: const Color(0xFFF8F9FB),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: Obx(() {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildAvatar(),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
controller.userName.value,
|
||||||
|
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
controller.email.value,
|
||||||
|
style: const TextStyle(fontSize: 14, color: Colors.grey),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
_buildStats(),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
_buildActionButton("Edit Profil", Icons.edit, controller.editProfile),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildActionButton("Logout", Icons.logout, controller.logout, isDestructive: true),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAvatar() {
|
||||||
|
return const CircleAvatar(
|
||||||
|
radius: 45,
|
||||||
|
backgroundColor: Colors.blueAccent,
|
||||||
|
child: Icon(Icons.person, size: 50, color: Colors.white),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStats() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black12,
|
||||||
|
blurRadius: 6,
|
||||||
|
offset: Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
_buildStatItem("Total Quiz", controller.totalQuizzes.value.toString()),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
_buildStatItem("Skor Rata-rata", "${controller.avgScore.value}%"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStatItem(String label, String value) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Text(value, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(label, style: const TextStyle(fontSize: 13, color: Colors.grey)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildActionButton(String title, IconData icon, VoidCallback onPressed, {bool isDestructive = false}) {
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
icon: Icon(icon, color: isDestructive ? Colors.red : Colors.white),
|
||||||
|
label: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(color: isDestructive ? Colors.red : Colors.white),
|
||||||
|
),
|
||||||
|
onPressed: onPressed,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: isDestructive ? Colors.red.shade50 : Colors.blueAccent,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
side: isDestructive ? const BorderSide(color: Colors.red) : BorderSide.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue