feat: finish implement subject on the home and search

This commit is contained in:
akhdanre 2025-05-05 09:39:19 +07:00
parent 80e6704bec
commit cd38b79bef
8 changed files with 136 additions and 42 deletions

View File

@ -1,11 +1,18 @@
import 'package:get/get.dart';
import 'package:quiz_app/data/services/quiz_service.dart';
import 'package:quiz_app/data/services/subject_service.dart';
import 'package:quiz_app/feature/home/controller/home_controller.dart';
class HomeBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<QuizService>(() => QuizService());
Get.lazyPut<HomeController>(() => HomeController(Get.find<QuizService>()));
Get.lazyPut<SubjectService>(() => SubjectService());
Get.lazyPut<HomeController>(
() => HomeController(
Get.find<QuizService>(),
Get.find<SubjectService>(),
),
);
}
}

View File

@ -3,23 +3,40 @@ import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/data/controllers/user_controller.dart';
import 'package:quiz_app/data/models/base/base_model.dart';
import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
import 'package:quiz_app/data/models/subject/subject_model.dart';
import 'package:quiz_app/data/services/quiz_service.dart';
import 'package:quiz_app/data/services/subject_service.dart';
import 'package:quiz_app/feature/navigation/controllers/navigation_controller.dart';
class HomeController extends GetxController {
final UserController _userController = Get.find<UserController>();
final QuizService _quizService;
HomeController(this._quizService);
final SubjectService _subjectService;
HomeController(
this._quizService,
this._subjectService,
);
Rx<String> get userName => _userController.userName;
Rx<String?> get userImage => _userController.userImage;
RxList<QuizListingModel> data = <QuizListingModel>[].obs;
RxList<SubjectModel> subjects = <SubjectModel>[].obs;
void goToQuizCreation() => Get.toNamed(AppRoutes.quizCreatePage);
void goToSearch() {
final navController = Get.find<NavigationController>();
navController.changePage(1);
}
@override
void onInit() {
_getRecomendationQuiz();
loadSubjectData();
super.onInit();
}
@ -30,6 +47,13 @@ class HomeController extends GetxController {
}
}
void loadSubjectData() async {
BaseResponseModel<List<SubjectModel>>? respnse = await _subjectService.getSubject();
if (respnse != null) {
subjects.assignAll(respnse.data!);
}
}
void onRecommendationTap(String quizId) => Get.toNamed(AppRoutes.detailQuizPage, arguments: quizId);
void goToListingsQuizPage() => Get.toNamed(AppRoutes.listingQuizPage);

View File

@ -1,8 +1,16 @@
import 'package:flutter/material.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/data/models/subject/subject_model.dart';
class SearchComponent extends StatelessWidget {
const SearchComponent({super.key});
final Function() onSearchTap;
final List<SubjectModel> subject;
const SearchComponent({
super.key,
required this.onSearchTap,
required this.subject,
});
@override
Widget build(BuildContext context) {
@ -52,12 +60,18 @@ class SearchComponent extends StatelessWidget {
}
Widget _buildCategoryRow() {
return Row(
children: [
_buildCategoryComponent("History"),
const SizedBox(width: 8),
_buildCategoryComponent("Science"),
],
return SizedBox(
height: 30, // Set height for horizontal ListView
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: subject.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(right: index != subject.length - 1 ? 8.0 : 0),
child: _buildCategoryComponent(subject[index].alias),
);
},
),
);
}
@ -80,7 +94,10 @@ class SearchComponent extends StatelessWidget {
}
Widget _buildSearchInput() {
return Container(
return GestureDetector(
onTap: () => onSearchTap(),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
@ -88,16 +105,22 @@ class SearchComponent extends StatelessWidget {
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
blurRadius: 6,
offset: Offset(0, 2),
offset: const Offset(0, 2),
),
],
),
child: const TextField(
decoration: InputDecoration(
hintText: "Search for quizzes...",
hintStyle: TextStyle(color: Color(0xFF6B778C)),
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
children: const [
Icon(Icons.search, color: Color(0xFF6B778C)),
SizedBox(width: 8),
Text(
"Search for quizzes...",
style: TextStyle(
color: Color(0xFF6B778C),
fontSize: 16,
),
),
],
),
),
);

View File

@ -41,7 +41,10 @@ class HomeView extends GetView<HomeController> {
padding: const EdgeInsets.all(20),
child: Column(
children: [
SearchComponent(),
Obx(() => SearchComponent(
onSearchTap: controller.goToSearch,
subject: controller.subjects.toList(),
)),
const SizedBox(height: 20),
Obx(
() => RecomendationComponent(

View File

@ -154,7 +154,6 @@ class QuizPlayController extends GetxController {
await Future.delayed(Duration(seconds: 2));
print(quizData);
Get.offAllNamed(
AppRoutes.resultQuizPage,

View File

@ -1,5 +1,6 @@
import 'package:get/get.dart';
import 'package:quiz_app/data/services/quiz_service.dart';
import 'package:quiz_app/data/services/subject_service.dart';
import 'package:quiz_app/feature/search/controller/search_controller.dart';
class SearchBinding extends Bindings {
@ -8,6 +9,12 @@ class SearchBinding extends Bindings {
if (!Get.isRegistered<QuizService>()) {
Get.lazyPut<QuizService>(() => QuizService());
}
Get.lazyPut<SearchQuizController>(() => SearchQuizController(Get.find<QuizService>()));
if (!Get.isRegistered()) Get.lazyPut<SubjectService>(() => SubjectService());
Get.lazyPut<SearchQuizController>(() => SearchQuizController(
Get.find<QuizService>(),
Get.find<SubjectService>(),
));
}
}

View File

@ -3,12 +3,18 @@ import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/data/models/base/base_model.dart';
import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
import 'package:quiz_app/data/models/subject/subject_model.dart';
import 'package:quiz_app/data/services/quiz_service.dart';
import 'package:quiz_app/data/services/subject_service.dart';
class SearchQuizController extends GetxController {
final QuizService _quizService;
final SubjectService _subjectService;
SearchQuizController(this._quizService);
SearchQuizController(
this._quizService,
this._subjectService,
);
final searchController = TextEditingController();
final searchText = ''.obs;
@ -16,9 +22,12 @@ class SearchQuizController extends GetxController {
RxList<QuizListingModel> recommendationQData = <QuizListingModel>[].obs;
RxList<QuizListingModel> searchQData = <QuizListingModel>[].obs;
RxList<SubjectModel> subjects = <SubjectModel>[].obs;
@override
void onInit() {
getRecomendation();
loadSubjectData();
super.onInit();
searchController.addListener(() {
searchText.value = searchController.text;
@ -49,6 +58,15 @@ class SearchQuizController extends GetxController {
void goToListingsQuizPage() => Get.toNamed(AppRoutes.listingQuizPage);
void loadSubjectData() async {
BaseResponseModel<List<SubjectModel>>? respnse = await _subjectService.getSubject();
if (respnse != null) {
subjects.assignAll(respnse.data!);
}
}
void goToDetailQuizListing() {}
@override
void onClose() {
searchController.dispose();

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/component/quiz_container_component.dart';
import 'package:quiz_app/component/widget/recomendation_component.dart';
import 'package:quiz_app/data/models/subject/subject_model.dart';
import 'package:quiz_app/feature/search/controller/search_controller.dart';
class SearchView extends GetView<SearchQuizController> {
@ -21,7 +22,7 @@ class SearchView extends GetView<SearchQuizController> {
_buildSearchBar(),
const SizedBox(height: 20),
if (isSearching) ...[
_buildCategoryFilter(),
Obx(() => _buildCategoryFilter(controller.subjects.toList())),
const SizedBox(height: 20),
...controller.searchQData.map(
(e) => QuizContainerComponent(data: e, onTap: controller.goToDetailPage),
@ -78,17 +79,29 @@ class SearchView extends GetView<SearchQuizController> {
);
}
Widget _buildCategoryFilter() {
final categories = ['Fisika', 'Matematika', 'Agama', 'English', 'Sejarah', 'Biologi'];
Widget _buildCategoryFilter(List<SubjectModel> data) {
return Wrap(
spacing: 8,
runSpacing: 8,
children: categories.map((cat) {
return Chip(
label: Text(cat),
padding: const EdgeInsets.symmetric(horizontal: 12),
backgroundColor: Colors.white,
side: const BorderSide(color: Colors.black12),
spacing: 6,
runSpacing: 1,
children: data.map((cat) {
return InkWell(
onTap: () => controller.goToDetailQuizListing,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
margin: const EdgeInsets.symmetric(vertical: 2),
decoration: BoxDecoration(
color: Color(0xFFD6E4FF),
borderRadius: BorderRadius.circular(15),
),
child: Text(
cat.alias,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF0052CC),
),
),
),
);
}).toList(),
);