feat: interface on the quiz creation

This commit is contained in:
akhdanre 2025-04-27 00:30:25 +07:00
parent 39ab35b2a8
commit 05a22f3360
21 changed files with 591 additions and 19 deletions

View File

@ -0,0 +1,14 @@
import 'dart:ui';
class AppColors {
static const Color primaryBlue = Color(0xFF0052CC);
static const Color darkText = Color(0xFF172B4D);
static const Color softGrayText = Color(0xFF6B778C);
static const Color background = Color(0xFFFAFBFC);
static const Color borderLight = Color(0xFFE1E4E8);
static const Color accentBlue = Color(0xFFD6E4FF);
static const Color shadowPrimary = Color(0x330052CC);
static const Color disabledBackground = Color(0xFFE0E0E0);
static const Color disabledText = Color(0xFF9E9E9E);
}

View File

@ -8,6 +8,8 @@ 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/profile/binding/profile_binding.dart';
import 'package:quiz_app/feature/quiz_creation/binding/quiz_creation_binding.dart';
import 'package:quiz_app/feature/quiz_creation/view/quiz_creation_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/search/binding/search_binding.dart'; import 'package:quiz_app/feature/search/binding/search_binding.dart';
@ -48,6 +50,11 @@ class AppPages {
ProfileBinding(), ProfileBinding(),
], ],
middlewares: [AuthMiddleware()], middlewares: [AuthMiddleware()],
) ),
GetPage(
name: AppRoutes.quizCreatePage,
page: () => QuizCreationView(),
binding: QuizCreationBinding(),
),
]; ];
} }

View File

@ -7,4 +7,6 @@ abstract class AppRoutes {
static const homePage = '/home'; static const homePage = '/home';
static const mainPage = '/main'; static const mainPage = '/main';
static const quizCreatePage = "/quiz/creation";
} }

View File

@ -4,6 +4,7 @@ class GlobalTextField extends StatelessWidget {
final TextEditingController controller; final TextEditingController controller;
final String? hintText; final String? hintText;
final String? labelText; final String? labelText;
final int limitTextLine;
final bool isPassword; final bool isPassword;
final bool obscureText; final bool obscureText;
final VoidCallback? onToggleVisibility; final VoidCallback? onToggleVisibility;
@ -13,6 +14,7 @@ class GlobalTextField extends StatelessWidget {
required this.controller, required this.controller,
this.hintText, this.hintText,
this.labelText, this.labelText,
this.limitTextLine = 1,
this.isPassword = false, this.isPassword = false,
this.obscureText = false, this.obscureText = false,
this.onToggleVisibility, this.onToggleVisibility,
@ -23,31 +25,44 @@ class GlobalTextField extends StatelessWidget {
return TextField( return TextField(
controller: controller, controller: controller,
obscureText: isPassword ? obscureText : false, obscureText: isPassword ? obscureText : false,
maxLines: limitTextLine, // <-- ini tambahan dari limitTextLine
decoration: InputDecoration( decoration: InputDecoration(
labelText: labelText, labelText: labelText,
labelStyle: const TextStyle(color: Color(0xFF6B778C), fontSize: 14), labelStyle: const TextStyle(
color: Color(0xFF6B778C),
fontSize: 14,
),
hintText: hintText, hintText: hintText,
hintStyle: const TextStyle(color: Color(0xFF6B778C), fontSize: 14), hintStyle: const TextStyle(
color: Color(0xFF6B778C),
fontSize: 14,
),
filled: true, filled: true,
fillColor: const Color.fromARGB(255, 234, 234, 235), // Background soft white fillColor: Color.fromARGB(255, 234, 234, 235),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(color: Colors.transparent), borderSide: BorderSide.none,
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(color: Colors.transparent), borderSide: BorderSide.none,
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
borderSide: const BorderSide(color: Color(0xFF0052CC), width: 2), borderSide: const BorderSide(
color: Color(0xFF0052CC),
width: 2,
),
), ),
suffixIcon: isPassword suffixIcon: isPassword
? IconButton( ? IconButton(
icon: Icon( icon: Icon(
obscureText ? Icons.visibility_off : Icons.visibility, obscureText ? Icons.visibility_off : Icons.visibility,
color: const Color(0xFF6B778C), color: Color(0xFF6B778C),
), ),
onPressed: onToggleVisibility, onPressed: onToggleVisibility,
) )

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
class QuizContainerComponent extends StatelessWidget { class QuizContainerComponent extends StatelessWidget {
const QuizContainerComponent({super.key}); const QuizContainerComponent({super.key});
@ -8,7 +9,7 @@ class QuizContainerComponent extends StatelessWidget {
return Container( return Container(
padding: const EdgeInsets.all(14), padding: const EdgeInsets.all(14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(0xFFFAFBFC), color: AppColors.background,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all( border: Border.all(
color: Color(0xFFE1E4E8), color: Color(0xFFE1E4E8),

View File

@ -1,5 +1,4 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/data/services/user_storage_service.dart';
import 'package:quiz_app/feature/home/controller/home_controller.dart'; import 'package:quiz_app/feature/home/controller/home_controller.dart';
class HomeBinding extends Bindings { class HomeBinding extends Bindings {

View File

@ -1,4 +1,5 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/data/controllers/user_controller.dart'; import 'package:quiz_app/data/controllers/user_controller.dart';
class HomeController extends GetxController { class HomeController extends GetxController {
@ -6,4 +7,6 @@ class HomeController extends GetxController {
Rx<String> get userName => _userController.userName; Rx<String> get userName => _userController.userName;
Rx<String?> get userImage => _userController.userImage; Rx<String?> get userImage => _userController.userImage;
void goToQuizCreation() => Get.toNamed(AppRoutes.quizCreatePage);
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
class SearchComponent extends StatelessWidget { class SearchComponent extends StatelessWidget {
const SearchComponent({super.key}); const SearchComponent({super.key});
@ -9,7 +10,7 @@ class SearchComponent extends StatelessWidget {
margin: const EdgeInsets.symmetric(vertical: 10), margin: const EdgeInsets.symmetric(vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFFAFBFC), // Soft background color: AppColors.background, // Soft background
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
border: Border.all(color: Color(0xFFE1E4E8)), // Light border border: Border.all(color: Color(0xFFE1E4E8)), // Light border
), ),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/feature/home/controller/home_controller.dart'; import 'package:quiz_app/feature/home/controller/home_controller.dart';
import 'package:quiz_app/feature/home/view/component/button_option.dart'; import 'package:quiz_app/feature/home/view/component/button_option.dart';
import 'package:quiz_app/feature/home/view/component/recomendation_component.dart'; import 'package:quiz_app/feature/home/view/component/recomendation_component.dart';
@ -12,7 +13,7 @@ class HomeView extends GetView<HomeController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFFAFBFC), backgroundColor: AppColors.background,
body: SafeArea( body: SafeArea(
child: ListView( child: ListView(
children: [ children: [
@ -32,7 +33,7 @@ class HomeView extends GetView<HomeController> {
), ),
// ButtonOption di luar Padding // ButtonOption di luar Padding
ButtonOption( ButtonOption(
onCreate: () {}, onCreate: controller.goToQuizCreation,
onCreateRoom: () {}, onCreateRoom: () {},
onJoinRoom: () {}, onJoinRoom: () {},
), ),

View File

@ -73,7 +73,7 @@ class LoginController extends GetxController {
_userStorageService.isLogged = true; _userStorageService.isLogged = true;
Get.toNamed(AppRoutes.homePage); Get.toNamed(AppRoutes.mainPage);
} catch (e, stackTrace) { } catch (e, stackTrace) {
logC.e(e, stackTrace: stackTrace); logC.e(e, stackTrace: stackTrace);
Get.snackbar("Error", "Failed to connect to server"); Get.snackbar("Error", "Failed to connect to server");
@ -104,7 +104,7 @@ class LoginController extends GetxController {
_userStorageService.isLogged = true; _userStorageService.isLogged = true;
Get.toNamed(AppRoutes.homePage); Get.toNamed(AppRoutes.mainPage);
} catch (e, stackTrace) { } catch (e, stackTrace) {
logC.e("Google Sign-In Error: $e", stackTrace: stackTrace); logC.e("Google Sign-In Error: $e", stackTrace: stackTrace);
Get.snackbar("Error", "Google sign-in error"); Get.snackbar("Error", "Google sign-in error");

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/component/app_name.dart'; import 'package:quiz_app/component/app_name.dart';
import 'package:quiz_app/component/global_button.dart'; import 'package:quiz_app/component/global_button.dart';
import 'package:quiz_app/component/global_text_field.dart'; import 'package:quiz_app/component/global_text_field.dart';
@ -14,7 +15,7 @@ class LoginView extends GetView<LoginController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFFAFBFC), // background soft clean backgroundColor: AppColors.background, // background soft clean
body: SafeArea( body: SafeArea(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),

View File

@ -0,0 +1,9 @@
import "package:get/get.dart";
import "package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart";
class QuizCreationBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<QuizCreationController>(() => QuizCreationController());
}
}

View File

@ -0,0 +1,17 @@
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
class QuizCreationController extends GetxController {
TextEditingController questionTC = TextEditingController();
TextEditingController answerTC = TextEditingController();
RxBool isGenerate = true.obs;
Rx<QuestionType> currentQuestionType = QuestionType.fillTheBlank.obs;
onCreationTypeChange(bool value) => isGenerate.value = value;
onQuestionTypeChange(QuestionType type) => currentQuestionType.value = type;
}
enum QuestionType { fillTheBlank, option, trueOrFalse }

View File

@ -0,0 +1,156 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart';
import 'package:quiz_app/feature/quiz_creation/view/component/fill_the_blank_component.dart';
import 'package:quiz_app/feature/quiz_creation/view/component/option_question_component.dart';
import 'package:quiz_app/feature/quiz_creation/view/component/true_or_false_component.dart';
class CustomQuestionComponent extends GetView<QuizCreationController> {
const CustomQuestionComponent({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
_buildNumberPicker(),
const SizedBox(height: 20),
_buildQuizTypeSelector(),
const SizedBox(height: 20),
_questionTypeValue(),
const SizedBox(height: 20),
_buildDurationDropdown(),
],
);
}
Widget _questionTypeValue() {
return Obx(() {
switch (controller.currentQuestionType.value) {
case QuestionType.fillTheBlank:
return FillTheBlankComponent(
questionTC: controller.questionTC,
answerTC: controller.answerTC,
);
case QuestionType.option:
return OptionQuestionComponent(
questionTC: TextEditingController(),
optionTCList: List.generate(4, (index) => TextEditingController()),
);
case QuestionType.trueOrFalse:
return TrueFalseQuestionComponent(questionTC: controller.questionTC);
}
});
}
Widget _buildNumberPicker() {
return Wrap(
spacing: 8,
runSpacing: 8,
children: List.generate(14, (index) {
return Container(
width: 42,
height: 42,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColors.borderLight),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 4,
offset: const Offset(2, 2),
),
],
),
child: Text(
'${index + 1}',
style: const TextStyle(
fontWeight: FontWeight.w600,
color: AppColors.darkText,
),
),
);
}),
);
}
Widget _buildQuizTypeSelector() {
return Container(
decoration: BoxDecoration(
color: AppColors.background,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.borderLight),
),
child: Row(
children: [
_buildQuizTypeButton(
'Fill the Blanks',
type: QuestionType.fillTheBlank,
),
_buildQuizTypeButton(
'Option',
type: QuestionType.option,
),
_buildQuizTypeButton(
'True / False',
type: QuestionType.trueOrFalse,
),
],
),
);
}
Widget _buildQuizTypeButton(String label, {required QuestionType type}) {
return Expanded(
child: Obx(() {
final bool isSelected = controller.currentQuestionType.value == type;
return GestureDetector(
onTap: () => controller.onQuestionTypeChange(type),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 14),
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryBlue : Colors.transparent,
borderRadius: BorderRadius.circular(12),
),
alignment: Alignment.center,
child: Text(
label,
style: TextStyle(
color: isSelected ? Colors.white : AppColors.softGrayText,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
),
);
}),
);
}
Widget _buildDurationDropdown() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.borderLight),
),
child: DropdownButtonFormField<String>(
value: '1 minute',
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 14),
),
style: const TextStyle(color: AppColors.darkText, fontWeight: FontWeight.w500),
items: const [
DropdownMenuItem(value: '30 seconds', child: Text('30 seconds')),
DropdownMenuItem(value: '1 minute', child: Text('1 minute')),
DropdownMenuItem(value: '2 minutes', child: Text('2 minutes')),
],
onChanged: (value) {},
),
);
}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/widgets.dart';
import 'package:quiz_app/component/global_text_field.dart';
import 'package:quiz_app/component/label_text_field.dart';
class FillTheBlankComponent extends StatelessWidget {
final TextEditingController questionTC;
final TextEditingController answerTC;
const FillTheBlankComponent({super.key, required this.questionTC, required this.answerTC});
@override
Widget build(BuildContext context) {
return Column(
children: [
LabelTextField(label: "Pertanyaan"),
GlobalTextField(
controller: questionTC,
limitTextLine: 3,
hintText: "Tulis Pertanyaan",
),
const SizedBox(height: 15),
LabelTextField(label: "Jawaban"),
GlobalTextField(
controller: answerTC,
hintText: "Tulis Jawaban",
),
const SizedBox(height: 20),
],
);
}
}

View File

@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart';
class GenerateComponent extends GetView<QuizCreationController> {
const GenerateComponent({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Unggah file materi kamu (PDF atau Word) untuk membuat soal otomatis.",
style: TextStyle(
fontSize: 14,
color: Color(0xFF6B778C),
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 16),
GestureDetector(
onTap: () {},
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 30),
decoration: BoxDecoration(
color: const Color(0xFFF0F2F5),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.grey.shade300),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(Icons.insert_drive_file, size: 50, color: Color(0xFF6B778C)),
SizedBox(height: 10),
Text(
"Upload PDF atau Word",
style: TextStyle(
fontSize: 16,
color: Color(0xFF6B778C),
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 8),
Text(
"Max 10 MB",
style: TextStyle(
fontSize: 12,
color: Color(0xFF9FA8B2),
),
),
],
),
),
),
],
);
}
}

View File

@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:quiz_app/component/global_text_field.dart';
import 'package:quiz_app/component/label_text_field.dart';
class OptionQuestionComponent extends StatefulWidget {
final TextEditingController questionTC;
final List<TextEditingController> optionTCList;
const OptionQuestionComponent({
super.key,
required this.questionTC,
required this.optionTCList,
});
@override
State<OptionQuestionComponent> createState() => _OptionQuestionComponentState();
}
class _OptionQuestionComponentState extends State<OptionQuestionComponent> {
String? selectedCorrectAnswer; // A, B, C, D
@override
Widget build(BuildContext context) {
return Column(
children: [
// Pertanyaan
LabelTextField(label: "Pertanyaan"),
GlobalTextField(
controller: widget.questionTC,
limitTextLine: 3,
hintText: "Tulis Pertanyaan",
),
const SizedBox(height: 15),
// Pilihan A, B, C, D
...List.generate(widget.optionTCList.length, (index) {
return Column(
children: [
LabelTextField(label: "Pilihan ${String.fromCharCode(65 + index)}"),
GlobalTextField(
controller: widget.optionTCList[index],
hintText: "Tulis Pilihan ${String.fromCharCode(65 + index)}",
),
const SizedBox(height: 10),
],
);
}),
// Jawaban Benar Dropdown
const SizedBox(height: 10),
LabelTextField(label: "Jawaban Benar"),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: selectedCorrectAnswer,
hint: const Text('Pilih Jawaban Benar'),
isExpanded: true,
items: List.generate(widget.optionTCList.length, (index) {
final optionLabel = String.fromCharCode(65 + index); // 'A', 'B', 'C', etc.
return DropdownMenuItem<String>(
value: optionLabel,
child: Text(optionLabel),
);
}),
onChanged: (value) {
setState(() {
selectedCorrectAnswer = value;
});
},
),
),
),
const SizedBox(height: 20),
],
);
}
}

View File

@ -0,0 +1,70 @@
import 'package:flutter/material.dart';
import 'package:quiz_app/component/global_text_field.dart';
import 'package:quiz_app/component/label_text_field.dart';
class TrueFalseQuestionComponent extends StatefulWidget {
final TextEditingController questionTC;
const TrueFalseQuestionComponent({
super.key,
required this.questionTC,
});
@override
State<TrueFalseQuestionComponent> createState() => _TrueFalseQuestionComponentState();
}
class _TrueFalseQuestionComponentState extends State<TrueFalseQuestionComponent> {
bool? selectedAnswer; // true or false
@override
Widget build(BuildContext context) {
return Column(
children: [
// Pertanyaan
LabelTextField(label: "Pertanyaan"),
GlobalTextField(
controller: widget.questionTC,
limitTextLine: 3,
hintText: "Tulis Pertanyaan",
),
const SizedBox(height: 15),
// Jawaban Dropdown
LabelTextField(label: "Jawaban Benar"),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<bool>(
value: selectedAnswer,
hint: const Text('Pilih Jawaban Benar'),
isExpanded: true,
items: const [
DropdownMenuItem(
value: true,
child: Text('True'),
),
DropdownMenuItem(
value: false,
child: Text('False'),
),
],
onChanged: (value) {
setState(() {
selectedAnswer = value;
});
},
),
),
),
const SizedBox(height: 20),
],
);
}
}

View File

@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart';
import 'package:quiz_app/feature/quiz_creation/view/component/custom_question_component.dart';
import 'package:quiz_app/feature/quiz_creation/view/component/generate_component.dart';
class QuizCreationView extends GetView<QuizCreationController> {
const QuizCreationView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.background,
appBar: AppBar(
backgroundColor: AppColors.background,
elevation: 0,
title: const Text(
'Create Quiz',
style: TextStyle(
fontWeight: FontWeight.bold,
color: AppColors.darkText,
),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new_rounded, color: AppColors.darkText),
onPressed: () => Navigator.pop(context),
),
centerTitle: true,
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildModeSelector(),
const SizedBox(height: 20),
Obx(
() => controller.isGenerate.value ? GenerateComponent() : CustomQuestionComponent(),
),
],
),
),
),
),
);
}
Widget _buildModeSelector() {
return Container(
decoration: BoxDecoration(
color: AppColors.background,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.borderLight),
),
child: Row(
children: [
_buildModeButton('Generate', controller.isGenerate, true),
_buildModeButton('Manual', controller.isGenerate, false),
],
),
);
}
Widget _buildModeButton(String label, RxBool isSelected, bool base) {
return Expanded(
child: InkWell(
onTap: () => controller.onCreationTypeChange(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,
),
),
),
),
),
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/component/app_name.dart'; import 'package:quiz_app/component/app_name.dart';
import 'package:quiz_app/component/global_button.dart'; import 'package:quiz_app/component/global_button.dart';
import 'package:quiz_app/component/global_text_field.dart'; import 'package:quiz_app/component/global_text_field.dart';
@ -11,7 +12,7 @@ class RegisterView extends GetView<RegisterController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFFAFBFC), backgroundColor: AppColors.background,
body: SafeArea( body: SafeArea(
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:quiz_app/app/const/colors/app_colors.dart';
import 'package:quiz_app/app/routes/app_pages.dart'; import 'package:quiz_app/app/routes/app_pages.dart';
import 'package:quiz_app/component/app_name.dart'; import 'package:quiz_app/component/app_name.dart';
import 'package:quiz_app/data/services/user_storage_service.dart'; import 'package:quiz_app/data/services/user_storage_service.dart';
@ -29,7 +30,7 @@ class SplashScreenView extends StatelessWidget {
}); });
return const Scaffold( return const Scaffold(
backgroundColor: Color(0xFFFAFBFC), backgroundColor: AppColors.background,
body: Center( body: Center(
child: AppName(), child: AppName(),
), ),