feat: done working on the room maker
This commit is contained in:
parent
ca9e9cde7d
commit
481bfbe228
|
@ -25,6 +25,8 @@ import 'package:quiz_app/feature/quiz_result/binding/quiz_result_binding.dart';
|
||||||
import 'package:quiz_app/feature/quiz_result/view/quiz_result_view.dart';
|
import 'package:quiz_app/feature/quiz_result/view/quiz_result_view.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/room_maker/binding/room_maker_binding.dart';
|
||||||
|
import 'package:quiz_app/feature/room_maker/view/room_maker_view.dart';
|
||||||
import 'package:quiz_app/feature/search/binding/search_binding.dart';
|
import 'package:quiz_app/feature/search/binding/search_binding.dart';
|
||||||
import 'package:quiz_app/feature/splash_screen/presentation/splash_screen_page.dart';
|
import 'package:quiz_app/feature/splash_screen/presentation/splash_screen_page.dart';
|
||||||
|
|
||||||
|
@ -99,6 +101,11 @@ class AppPages {
|
||||||
name: AppRoutes.detailHistoryPage,
|
name: AppRoutes.detailHistoryPage,
|
||||||
page: () => DetailHistoryView(),
|
page: () => DetailHistoryView(),
|
||||||
binding: DetailHistoryBinding(),
|
binding: DetailHistoryBinding(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: AppRoutes.roomPage,
|
||||||
|
page: () => RoomMakerView(),
|
||||||
|
binding: RoomMakerBinding(),
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,4 +17,6 @@ abstract class AppRoutes {
|
||||||
static const resultQuizPage = "/quiz/result";
|
static const resultQuizPage = "/quiz/result";
|
||||||
|
|
||||||
static const detailHistoryPage = "/history/detail";
|
static const detailHistoryPage = "/history/detail";
|
||||||
|
|
||||||
|
static const roomPage = "/room/quiz";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class GlobalTextField extends StatelessWidget {
|
class GlobalTextField extends StatelessWidget {
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
@ -8,9 +9,10 @@ class GlobalTextField extends StatelessWidget {
|
||||||
final bool isPassword;
|
final bool isPassword;
|
||||||
final bool obscureText;
|
final bool obscureText;
|
||||||
final VoidCallback? onToggleVisibility;
|
final VoidCallback? onToggleVisibility;
|
||||||
|
final TextInputType textInputType;
|
||||||
|
|
||||||
const GlobalTextField({
|
const GlobalTextField(
|
||||||
super.key,
|
{super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
this.hintText,
|
this.hintText,
|
||||||
this.labelText,
|
this.labelText,
|
||||||
|
@ -18,12 +20,13 @@ class GlobalTextField extends StatelessWidget {
|
||||||
this.isPassword = false,
|
this.isPassword = false,
|
||||||
this.obscureText = false,
|
this.obscureText = false,
|
||||||
this.onToggleVisibility,
|
this.onToggleVisibility,
|
||||||
});
|
this.textInputType = TextInputType.text});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
keyboardType: textInputType,
|
||||||
obscureText: isPassword ? obscureText : false,
|
obscureText: isPassword ? obscureText : false,
|
||||||
maxLines: limitTextLine, // <-- ini tambahan dari limitTextLine
|
maxLines: limitTextLine, // <-- ini tambahan dari limitTextLine
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
|
|
@ -27,13 +27,6 @@ class HomeController extends GetxController {
|
||||||
|
|
||||||
RxList<SubjectModel> subjects = <SubjectModel>[].obs;
|
RxList<SubjectModel> subjects = <SubjectModel>[].obs;
|
||||||
|
|
||||||
void goToQuizCreation() => Get.toNamed(AppRoutes.quizCreatePage);
|
|
||||||
|
|
||||||
void goToSearch() {
|
|
||||||
final navController = Get.find<NavigationController>();
|
|
||||||
navController.changePage(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
_getRecomendationQuiz();
|
_getRecomendationQuiz();
|
||||||
|
@ -55,6 +48,15 @@ class HomeController extends GetxController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void goToQuizCreation() => Get.toNamed(AppRoutes.quizCreatePage);
|
||||||
|
|
||||||
|
void goToRoomMaker() => Get.toNamed(AppRoutes.roomPage);
|
||||||
|
|
||||||
|
void goToSearch() {
|
||||||
|
final navController = Get.find<NavigationController>();
|
||||||
|
navController.changePage(1);
|
||||||
|
}
|
||||||
|
|
||||||
void onRecommendationTap(String quizId) => Get.toNamed(AppRoutes.detailQuizPage, arguments: quizId);
|
void onRecommendationTap(String quizId) => Get.toNamed(AppRoutes.detailQuizPage, arguments: quizId);
|
||||||
|
|
||||||
void goToListingsQuizPage(ListingType page, {String? subjectId, String? subjecName}) => Get.toNamed(
|
void goToListingsQuizPage(ListingType page, {String? subjectId, String? subjecName}) => Get.toNamed(
|
||||||
|
|
|
@ -35,7 +35,7 @@ class HomeView extends GetView<HomeController> {
|
||||||
// ButtonOption di luar Padding
|
// ButtonOption di luar Padding
|
||||||
ButtonOption(
|
ButtonOption(
|
||||||
onCreate: controller.goToQuizCreation,
|
onCreate: controller.goToQuizCreation,
|
||||||
onCreateRoom: () {},
|
onCreateRoom: controller.goToRoomMaker,
|
||||||
onJoinRoom: () {},
|
onJoinRoom: () {},
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:quiz_app/feature/room_maker/controller/room_maker_controller.dart';
|
||||||
|
|
||||||
|
class RoomMakerBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
Get.lazyPut(() => RoomMakerController());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
|
||||||
|
|
||||||
|
class RoomMakerController extends GetxController {
|
||||||
|
final roomName = ''.obs;
|
||||||
|
final selectedQuiz = Rxn<QuizListingModel>();
|
||||||
|
|
||||||
|
RxBool isOnwQuiz = true.obs;
|
||||||
|
|
||||||
|
final TextEditingController nameTC = TextEditingController();
|
||||||
|
final TextEditingController maxPlayerTC = TextEditingController();
|
||||||
|
|
||||||
|
final availableQuizzes = <QuizListingModel>[
|
||||||
|
QuizListingModel(
|
||||||
|
quizId: '1',
|
||||||
|
authorId: 'u1',
|
||||||
|
authorName: 'Admin',
|
||||||
|
title: 'Sejarah Indonesia',
|
||||||
|
description: 'Kuis tentang kerajaan dan sejarah nusantara.',
|
||||||
|
date: '2025-05-01',
|
||||||
|
totalQuiz: 10,
|
||||||
|
duration: 600,
|
||||||
|
),
|
||||||
|
QuizListingModel(
|
||||||
|
quizId: '2',
|
||||||
|
authorId: 'u2',
|
||||||
|
authorName: 'Guru IPA',
|
||||||
|
title: 'Ilmu Pengetahuan Alam',
|
||||||
|
description: 'Kuis IPA untuk kelas 8.',
|
||||||
|
date: '2025-04-28',
|
||||||
|
totalQuiz: 15,
|
||||||
|
duration: 900,
|
||||||
|
),
|
||||||
|
].obs;
|
||||||
|
|
||||||
|
void createRoom() {
|
||||||
|
if (roomName.value.trim().isEmpty || selectedQuiz.value == null) {
|
||||||
|
Get.snackbar("Gagal", "Nama room dan kuis harus dipilih.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final quiz = selectedQuiz.value!;
|
||||||
|
print("Membuat room:");
|
||||||
|
print("- Nama: ${roomName.value}");
|
||||||
|
print("- Quiz: ${quiz.title}");
|
||||||
|
print("- Durasi: ${quiz.duration} detik");
|
||||||
|
print("- Jumlah Soal: ${quiz.totalQuiz}");
|
||||||
|
}
|
||||||
|
|
||||||
|
void onQuizSourceChange(bool base) {
|
||||||
|
isOnwQuiz.value = base;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onQuizChoosen(String quizId) {
|
||||||
|
final selected = availableQuizzes.firstWhere((e) => e.quizId == quizId);
|
||||||
|
selectedQuiz.value = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onCreateRoom() {}
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||||
|
import 'package:quiz_app/app/const/text/text_style.dart';
|
||||||
|
import 'package:quiz_app/component/global_button.dart';
|
||||||
|
import 'package:quiz_app/component/global_text_field.dart';
|
||||||
|
import 'package:quiz_app/component/label_text_field.dart';
|
||||||
|
import 'package:quiz_app/component/quiz_container_component.dart';
|
||||||
|
import 'package:quiz_app/feature/room_maker/controller/room_maker_controller.dart';
|
||||||
|
|
||||||
|
class RoomMakerView extends GetView<RoomMakerController> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.background,
|
||||||
|
appBar: AppBar(title: Text("Buat Room Quiz")),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
LabelTextField(
|
||||||
|
label: "Room Name",
|
||||||
|
),
|
||||||
|
GlobalTextField(
|
||||||
|
controller: controller.nameTC,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
LabelTextField(label: "Jumlah Maksimal Pemain"),
|
||||||
|
GlobalTextField(
|
||||||
|
controller: controller.maxPlayerTC,
|
||||||
|
textInputType: TextInputType.number,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
quizMeta(),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
_buildModeSelector(),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
child: Obx(() => ListView.builder(
|
||||||
|
itemCount: controller.availableQuizzes.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return QuizContainerComponent(
|
||||||
|
data: controller.availableQuizzes[index],
|
||||||
|
onTap: controller.onQuizChoosen,
|
||||||
|
);
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
GlobalButton(text: "Buat Room", onPressed: controller.onCreateRoom)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget quizMeta() {
|
||||||
|
return Obx(() {
|
||||||
|
final quiz = controller.selectedQuiz.value;
|
||||||
|
if (quiz == null) return SizedBox.shrink();
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
margin: const EdgeInsets.only(top: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.05),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Kuis yang Dipilih",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildMetaRow("Judul", quiz.title),
|
||||||
|
_buildMetaRow("Deskripsi", quiz.description),
|
||||||
|
_buildMetaRow("Jumlah Soal", quiz.totalQuiz.toString()),
|
||||||
|
_buildMetaRow("Durasi", "${quiz.duration ~/ 60} menit"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMetaRow(String label, String value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("$label: ", style: AppTextStyles.subtitle),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: AppTextStyles.subtitle,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildModeSelector() {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.background,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(color: AppColors.borderLight),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
_buildModeButton('kuismu', controller.isOnwQuiz, true),
|
||||||
|
_buildModeButton('Rekomendasi', controller.isOnwQuiz, false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildModeButton(String label, RxBool isSelected, bool base) {
|
||||||
|
return Expanded(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => controller.onQuizSourceChange(base),
|
||||||
|
child: Obx(
|
||||||
|
() => Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isSelected.value == base ? AppColors.primaryBlue : Colors.transparent,
|
||||||
|
borderRadius: base
|
||||||
|
? BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(10),
|
||||||
|
bottomLeft: Radius.circular(10),
|
||||||
|
)
|
||||||
|
: BorderRadius.only(
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
color: isSelected.value == base ? Colors.white : AppColors.softGrayText,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue