feat: adding localization
This commit is contained in:
parent
b575f75f6d
commit
7dc0994162
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"greeting_time": "Good Afternoon",
|
||||
"greeting_user": "Hello {user}",
|
||||
"create_room": "Create Room",
|
||||
"join_room": "Join Room",
|
||||
"create_quiz": "Create Quiz",
|
||||
"ready_new_challenge": "Ready for a new challenge?",
|
||||
"search_or_select_category": "Search or select by category",
|
||||
"search_for_quizzes": "Search for quizzes...",
|
||||
"quiz_recommendation": "Recommended Quiz",
|
||||
"log_in": "Log In",
|
||||
"sign_in": "Sign In",
|
||||
"email": "Email",
|
||||
"enter_your_email": "Enter Your Email",
|
||||
"password": "Password",
|
||||
"enter_your_password": "Enter Your Password",
|
||||
"or": "OR",
|
||||
"register_title": "Register",
|
||||
"full_name": "Full Name",
|
||||
"birth_date": "Birth Date",
|
||||
"phone_optional": "Phone Number (Optional)",
|
||||
"verify_password": "Verify Password",
|
||||
"register_button": "Register",
|
||||
"nav_home": "Home",
|
||||
"nav_search": "Search",
|
||||
"nav_library": "Library",
|
||||
"nav_history": "History",
|
||||
"nav_profile": "Profile",
|
||||
"quiz_popular": "Popular Quiz",
|
||||
"see_all": "See All",
|
||||
|
||||
"library_title": "Quiz Library",
|
||||
"library_description": "A collection of quiz questions created for study.",
|
||||
"no_quiz_available": "No quizzes available yet.",
|
||||
"quiz_count_label": "Quizzes",
|
||||
"quiz_count_named": "{total} Quizzes",
|
||||
|
||||
"history_title": "Quiz History",
|
||||
"history_subtitle": "Review the quizzes you've taken",
|
||||
"no_history": "You don't have any quiz history yet",
|
||||
"score_label": "Score: {correct}/{total}",
|
||||
"duration_minutes": "{minute} minutes",
|
||||
|
||||
"edit_profile": "Edit Profile",
|
||||
"logout": "Logout",
|
||||
"total_quiz": "Total Quiz",
|
||||
"avg_score": "Average Score",
|
||||
|
||||
"history_detail_title": "Quiz Detail",
|
||||
"correct_answer": "Correct",
|
||||
"score": "Score",
|
||||
"time_taken": "Time",
|
||||
"duration_seconds": "{second}s",
|
||||
|
||||
"your_answer": "Your answer: {answer}",
|
||||
"question_type_option": "Multiple Choice",
|
||||
"question_type_fill": "Fill in the Blank",
|
||||
"question_type_true_false": "True / False",
|
||||
"question_type_unknown": "Unknown Type",
|
||||
|
||||
"enter_room_code": "Enter Room Code",
|
||||
"room_code_hint": "AB123C",
|
||||
"join_now": "Join Now",
|
||||
|
||||
"create_quiz_title": "Create Quiz",
|
||||
"save_all": "Save All",
|
||||
"mode_generate": "Generate",
|
||||
"mode_manual": "Manual",
|
||||
|
||||
"quiz_play_title": "Answer Quiz",
|
||||
"ready_in": "Ready in {second}",
|
||||
"question_indicator": "Question {current} of {total}",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"next": "Next",
|
||||
|
||||
"quiz_preview_title": "Preview Quiz",
|
||||
"quiz_title_label": "Title",
|
||||
"quiz_description_label": "Short Description",
|
||||
"quiz_subject_label": "Subject",
|
||||
"make_quiz_public": "Make Quiz Public",
|
||||
"save_quiz": "Save Quiz"
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"greeting_time": "Selamat Siang",
|
||||
"greeting_user": "Halo {user}",
|
||||
"create_room": "Buat Ruangan",
|
||||
"join_room": "Gabung Ruangan",
|
||||
"create_quiz": "Buat Kuis",
|
||||
"ready_new_challenge": "Siap untuk tantangan baru?",
|
||||
"search_or_select_category": "Cari atau pilih berdasarkan kategori",
|
||||
"search_for_quizzes": "Cari kuis...",
|
||||
"quiz_recommendation": "Rekomendasi Kuis",
|
||||
"log_in": "Masuk",
|
||||
"sign_in": "Masuk",
|
||||
"email": "Email",
|
||||
"enter_your_email": "Masukkan Email Anda",
|
||||
"password": "Kata Sandi",
|
||||
"enter_your_password": "Masukkan Kata Sandi Anda",
|
||||
"or": "ATAU",
|
||||
"register_title": "Daftar",
|
||||
"full_name": "Nama Lengkap",
|
||||
"birth_date": "Tanggal Lahir",
|
||||
"phone_optional": "Nomor Telepon (Opsional)",
|
||||
"verify_password": "Verifikasi Kata Sandi",
|
||||
"register_button": "Daftar",
|
||||
"nav_home": "Beranda",
|
||||
"nav_search": "Cari",
|
||||
"nav_library": "Pustaka",
|
||||
"nav_history": "Riwayat",
|
||||
"nav_profile": "Profil",
|
||||
"quiz_popular": "Kuis Populer",
|
||||
"see_all": "Lihat Semua",
|
||||
|
||||
"library_title": "Pustaka Kuis",
|
||||
"library_description": "Kumpulan pertanyaan kuis untuk belajar.",
|
||||
"no_quiz_available": "Belum ada kuis yang tersedia.",
|
||||
"quiz_count_label": "Kuis",
|
||||
"quiz_count_named": "{total} Kuis",
|
||||
|
||||
"history_title": "Riwayat Kuis",
|
||||
"history_subtitle": "Tinjau kuis yang telah kamu kerjakan",
|
||||
"no_history": "Kamu belum memiliki riwayat kuis",
|
||||
"score_label": "Skor: {correct}/{total}",
|
||||
"duration_minutes": "{minute} menit",
|
||||
|
||||
"edit_profile": "Edit Profil",
|
||||
"logout": "Keluar",
|
||||
"total_quiz": "Total Kuis",
|
||||
"avg_score": "Skor Rata-rata",
|
||||
|
||||
"history_detail_title": "Detail Kuis",
|
||||
"correct_answer": "Benar",
|
||||
"score": "Skor",
|
||||
"time_taken": "Waktu",
|
||||
"duration_seconds": "{second} detik",
|
||||
|
||||
"your_answer": "Jawaban kamu: {answer}",
|
||||
"question_type_option": "Pilihan Ganda",
|
||||
"question_type_fill": "Isian Kosong",
|
||||
"question_type_true_false": "Benar / Salah",
|
||||
"question_type_unknown": "Tipe Tidak Dikenal",
|
||||
|
||||
"enter_room_code": "Masukkan Kode Ruangan",
|
||||
"room_code_hint": "AB123C",
|
||||
"join_now": "Gabung Sekarang",
|
||||
|
||||
"create_quiz_title": "Buat Kuis",
|
||||
"save_all": "Simpan Semua",
|
||||
"mode_generate": "Otomatis",
|
||||
"mode_manual": "Manual",
|
||||
|
||||
"quiz_play_title": "Kerjakan Kuis",
|
||||
"ready_in": "Siap dalam {second}",
|
||||
"question_indicator": "Pertanyaan {current} dari {total}",
|
||||
"yes": "Ya",
|
||||
"no": "Tidak",
|
||||
"next": "Berikutnya",
|
||||
|
||||
"quiz_preview_title": "Pratinjau Kuis",
|
||||
"quiz_title_label": "Judul",
|
||||
"quiz_description_label": "Deskripsi Singkat",
|
||||
"quiz_subject_label": "Mata Pelajaran",
|
||||
"make_quiz_public": "Jadikan Kuis Publik",
|
||||
"save_quiz": "Simpan Kuis"
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"greeting_time": "Selamat Tengah Hari",
|
||||
"greeting_user": "Hai {user}",
|
||||
"create_room": "Cipta Bilik",
|
||||
"join_room": "Sertai Bilik",
|
||||
"create_quiz": "Cipta Kuiz",
|
||||
"ready_new_challenge": "Bersedia untuk cabaran baharu?",
|
||||
"search_or_select_category": "Cari atau pilih mengikut kategori",
|
||||
"search_for_quizzes": "Cari kuiz...",
|
||||
"quiz_recommendation": "Kuiz Disyorkan",
|
||||
"log_in": "Log Masuk",
|
||||
"sign_in": "Daftar Masuk",
|
||||
"email": "E-mel",
|
||||
"enter_your_email": "Masukkan E-mel Anda",
|
||||
"password": "Kata Laluan",
|
||||
"enter_your_password": "Masukkan Kata Laluan Anda",
|
||||
"or": "ATAU",
|
||||
"register_title": "Daftar",
|
||||
"full_name": "Nama Penuh",
|
||||
"birth_date": "Tarikh Lahir",
|
||||
"phone_optional": "Nombor Telefon (Pilihan)",
|
||||
"verify_password": "Sahkan Kata Laluan",
|
||||
"register_button": "Daftar",
|
||||
"nav_home": "Laman Utama",
|
||||
"nav_search": "Cari",
|
||||
"nav_library": "Perpustakaan",
|
||||
"nav_history": "Sejarah",
|
||||
"nav_profile": "Profil",
|
||||
"quiz_popular": "Kuiz Popular",
|
||||
"see_all": "Lihat Semua",
|
||||
|
||||
"library_title": "Perpustakaan Kuiz",
|
||||
"library_description": "Koleksi soalan kuiz untuk pembelajaran.",
|
||||
"no_quiz_available": "Tiada kuiz tersedia lagi.",
|
||||
"quiz_count_label": "Kuiz",
|
||||
"quiz_count_named": "{total} Kuiz",
|
||||
|
||||
"history_title": "Sejarah Kuiz",
|
||||
"history_subtitle": "Semak semula kuiz yang telah anda jawab",
|
||||
"no_history": "Anda belum mempunyai sejarah kuiz",
|
||||
"score_label": "Skor: {correct}/{total}",
|
||||
"duration_minutes": "{minute} minit",
|
||||
|
||||
"edit_profile": "Edit Profil",
|
||||
"logout": "Log Keluar",
|
||||
"total_quiz": "Jumlah Kuiz",
|
||||
"avg_score": "Skor Purata",
|
||||
|
||||
"history_detail_title": "Butiran Kuiz",
|
||||
"correct_answer": "Betul",
|
||||
"score": "Skor",
|
||||
"time_taken": "Masa",
|
||||
"duration_seconds": "{second} saat",
|
||||
|
||||
"your_answer": "Jawapan anda: {answer}",
|
||||
"question_type_option": "Pilihan Berganda",
|
||||
"question_type_fill": "Isi Tempat Kosong",
|
||||
"question_type_true_false": "Betul / Salah",
|
||||
"question_type_unknown": "Jenis Tidak Diketahui",
|
||||
|
||||
"enter_room_code": "Masukkan Kod Bilik",
|
||||
"room_code_hint": "AB123C",
|
||||
"join_now": "Sertai Sekarang",
|
||||
|
||||
"create_quiz_title": "Cipta Kuiz",
|
||||
"save_all": "Simpan Semua",
|
||||
"mode_generate": "Jana",
|
||||
"mode_manual": "Manual",
|
||||
|
||||
"quiz_play_title": "Jawab Kuiz",
|
||||
"ready_in": "Bersedia dalam {second}",
|
||||
"question_indicator": "Soalan {current} daripada {total}",
|
||||
"yes": "Ya",
|
||||
"no": "Tidak",
|
||||
"next": "Seterusnya",
|
||||
|
||||
"quiz_preview_title": "Pratonton Kuiz",
|
||||
"quiz_title_label": "Tajuk",
|
||||
"quiz_description_label": "Deskripsi Ringkas",
|
||||
"quiz_subject_label": "Subjek",
|
||||
"make_quiz_public": "Jadikan Kuiz Umum",
|
||||
"save_quiz": "Simpan Kuiz"
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get_navigation/src/root/get_material_app.dart';
|
||||
import 'package:quiz_app/app/bindings/initial_bindings.dart';
|
||||
|
@ -9,7 +10,10 @@ class MyApp extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetMaterialApp(
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
debugShowCheckedModeBanner: false,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: context.locale,
|
||||
title: 'Quiz App',
|
||||
initialBinding: InitialBindings(),
|
||||
initialRoute: AppRoutes.splashScreen,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
|
@ -54,7 +55,7 @@ class QuizItemWAComponent extends StatelessWidget {
|
|||
const SizedBox(height: 16),
|
||||
if (isOptionType && options != null) _buildOptions(),
|
||||
const SizedBox(height: 12),
|
||||
_buildAnswerIndicator(),
|
||||
_buildAnswerIndicator(context),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(height: 24, color: AppColors.shadowPrimary),
|
||||
_buildMetadata(),
|
||||
|
@ -109,7 +110,7 @@ class QuizItemWAComponent extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildAnswerIndicator() {
|
||||
Widget _buildAnswerIndicator(BuildContext context) {
|
||||
final icon = isCorrect ? LucideIcons.checkCircle2 : LucideIcons.xCircle;
|
||||
final color = isCorrect ? AppColors.primaryBlue : Colors.red;
|
||||
|
||||
|
@ -124,7 +125,7 @@ class QuizItemWAComponent extends StatelessWidget {
|
|||
Icon(icon, color: color, size: 18),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Jawabanmu: $userAnswerText',
|
||||
context.tr('your_answer', namedArgs: {'answer': userAnswerText}),
|
||||
style: AppTextStyles.statValue,
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:quiz_app/component/quiz_container_component.dart';
|
||||
import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
|
||||
|
@ -21,7 +22,7 @@ class RecomendationComponent extends StatelessWidget {
|
|||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildSectionTitle(title),
|
||||
_buildSectionTitle(context, title),
|
||||
const SizedBox(height: 10),
|
||||
datas.isNotEmpty
|
||||
// ? Text("yeay ${datas.length}")
|
||||
|
@ -53,7 +54,7 @@ class RecomendationComponent extends StatelessWidget {
|
|||
// );
|
||||
// }
|
||||
|
||||
Widget _buildSectionTitle(String title) {
|
||||
Widget _buildSectionTitle(BuildContext context, String title) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Row(
|
||||
|
@ -66,7 +67,7 @@ class RecomendationComponent extends StatelessWidget {
|
|||
GestureDetector(
|
||||
onTap: allOnTap,
|
||||
child: Text(
|
||||
"Lihat semua",
|
||||
context.tr('see_all'),
|
||||
style: TextStyle(fontSize: 14, color: Colors.blue.shade700),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class APIEndpoint {
|
||||
// static const String baseUrl = "http://192.168.1.9:5000";
|
||||
static const String baseUrl = "http://172.16.106.133:5000";
|
||||
static const String baseUrl = "http://192.168.1.9:5000";
|
||||
// static const String baseUrl = "http://172.16.106.133:5000";
|
||||
static const String api = "$baseUrl/api";
|
||||
|
||||
static const String login = "/login";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
|
@ -81,6 +82,7 @@ class DetailQuizView extends GetView<DetailQuizController> {
|
|||
const SizedBox(height: 20),
|
||||
const Divider(thickness: 1.2, color: AppColors.borderLight),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Soal Section
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
|
@ -169,13 +171,13 @@ class DetailQuizView extends GetView<DetailQuizController> {
|
|||
String _mapQuestionTypeToText(String? type) {
|
||||
switch (type) {
|
||||
case 'option':
|
||||
return 'Pilihan Ganda';
|
||||
return tr('question_type_option');
|
||||
case 'fill_the_blank':
|
||||
return 'Isian Kosong';
|
||||
return tr('question_type_fill');
|
||||
case 'true_false':
|
||||
return 'Benar / Salah';
|
||||
return tr('question_type_true_false');
|
||||
default:
|
||||
return 'Tipe Tidak Diketahui';
|
||||
return tr('question_type_unknown');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get_state_manager/get_state_manager.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
@ -18,7 +19,7 @@ class DetailHistoryView extends GetView<DetailHistoryController> {
|
|||
backgroundColor: AppColors.background,
|
||||
elevation: 0,
|
||||
title: Text(
|
||||
'Detail history',
|
||||
context.tr('history_detail_title'),
|
||||
style: AppTextStyles.title.copyWith(fontSize: 24),
|
||||
),
|
||||
centerTitle: true,
|
||||
|
@ -31,7 +32,7 @@ class DetailHistoryView extends GetView<DetailHistoryController> {
|
|||
}
|
||||
return ListView(
|
||||
children: [
|
||||
quizMetaInfo(),
|
||||
quizMetaInfo(context),
|
||||
...quizListings(),
|
||||
],
|
||||
);
|
||||
|
@ -55,7 +56,7 @@ class DetailHistoryView extends GetView<DetailHistoryController> {
|
|||
.toList();
|
||||
}
|
||||
|
||||
Widget quizMetaInfo() {
|
||||
Widget quizMetaInfo(BuildContext context) {
|
||||
final quiz = controller.quizAnswer;
|
||||
|
||||
return Container(
|
||||
|
@ -106,20 +107,20 @@ class DetailHistoryView extends GetView<DetailHistoryController> {
|
|||
children: [
|
||||
_buildStatItem(
|
||||
icon: LucideIcons.checkCircle2,
|
||||
label: 'Benar',
|
||||
label: context.tr('correct_answer'),
|
||||
value: "${quiz.totalCorrect}/${quiz.questionListings.length}",
|
||||
color: Colors.green,
|
||||
),
|
||||
_buildStatItem(
|
||||
icon: LucideIcons.award,
|
||||
label: 'Skor',
|
||||
label: context.tr('score'),
|
||||
value: quiz.totalScore.toString(),
|
||||
color: Colors.blueAccent,
|
||||
),
|
||||
_buildStatItem(
|
||||
icon: LucideIcons.clock3,
|
||||
label: 'Waktu',
|
||||
value: '${quiz.totalSolveTime}s',
|
||||
label: context.tr('time_taken'),
|
||||
value: tr('duration_seconds', namedArgs: {"second": quiz.totalSolveTime.toString()}),
|
||||
color: Colors.orange,
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
|
@ -19,10 +20,10 @@ class HistoryView extends GetView<HistoryController> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Riwayat Kuis", style: AppTextStyles.title.copyWith(fontSize: 24)),
|
||||
Text(context.tr("history_title"), style: AppTextStyles.title.copyWith(fontSize: 24)),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
"Lihat kembali hasil kuis yang telah kamu kerjakan",
|
||||
context.tr("history_subtitle"),
|
||||
style: AppTextStyles.subtitle,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
@ -38,7 +39,7 @@ class HistoryView extends GetView<HistoryController> {
|
|||
if (historyList.isEmpty) {
|
||||
return Expanded(
|
||||
child: Center(
|
||||
child: Text("You don't have any quiz history yet", style: AppTextStyles.body),
|
||||
child: Text(context.tr("no_history"), style: AppTextStyles.body),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -102,13 +103,13 @@ class HistoryView extends GetView<HistoryController> {
|
|||
const Icon(Icons.check_circle, size: 14, color: Colors.green),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
"Skor: ${item.totalCorrect}/${item.totalQuestion}",
|
||||
tr('score_label', namedArgs: {'correct': item.totalCorrect.toString(), 'total': item.totalQuestion.toString()}),
|
||||
style: AppTextStyles.caption,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const Icon(Icons.timer, size: 14, color: Colors.grey),
|
||||
const SizedBox(width: 4),
|
||||
Text("3 menit", style: AppTextStyles.caption),
|
||||
Text(tr("duration_minutes", namedArgs: {"minute": "3"}), style: AppTextStyles.caption),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ButtonOption extends StatelessWidget {
|
||||
|
@ -19,22 +20,22 @@ class ButtonOption extends StatelessWidget {
|
|||
margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: _buildCreateButton()),
|
||||
Expanded(child: _buildCreateButton(context)),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(child: _buildRoomButtons()),
|
||||
Expanded(child: _buildRoomButtons(context)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCreateButton() {
|
||||
Widget _buildCreateButton(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onCreate,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: SizedBox(
|
||||
height: double.infinity,
|
||||
child: _buildButtonContainer(
|
||||
label: 'Buat Quiz',
|
||||
label: context.tr("create_quiz"),
|
||||
gradientColors: [Color(0xFF0052CC), Color(0xFF0367D3)],
|
||||
icon: Icons.create,
|
||||
),
|
||||
|
@ -42,7 +43,7 @@ class ButtonOption extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildRoomButtons() {
|
||||
Widget _buildRoomButtons(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
|
@ -50,7 +51,7 @@ class ButtonOption extends StatelessWidget {
|
|||
onTap: onCreateRoom,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: _buildButtonContainer(
|
||||
label: 'Buat Room',
|
||||
label: context.tr("create_room"),
|
||||
gradientColors: [Color(0xFF36B37E), Color(0xFF22C39F)],
|
||||
icon: Icons.meeting_room,
|
||||
),
|
||||
|
@ -62,7 +63,7 @@ class ButtonOption extends StatelessWidget {
|
|||
onTap: onJoinRoom,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: _buildButtonContainer(
|
||||
label: 'Join Room',
|
||||
label: context.tr("join_room"),
|
||||
gradientColors: [Color(0xFFFFAB00), Color(0xFFFFC107)],
|
||||
icon: Icons.group,
|
||||
),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
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';
|
||||
|
@ -27,22 +28,22 @@ class SearchComponent extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTitleSection(),
|
||||
_buildTitleSection(context),
|
||||
const SizedBox(height: 12),
|
||||
_buildCategoryRow(),
|
||||
const SizedBox(height: 12),
|
||||
_buildSearchInput(),
|
||||
_buildSearchInput(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTitleSection() {
|
||||
Widget _buildTitleSection(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
children: [
|
||||
Text(
|
||||
"Ready for a new challenge?",
|
||||
context.tr("ready_new_challenge"),
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
@ -51,7 +52,7 @@ class SearchComponent extends StatelessWidget {
|
|||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
"Search or select by category",
|
||||
context.tr("search_or_select_category"),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF6B778C), // Soft gray text
|
||||
|
@ -98,7 +99,7 @@ class SearchComponent extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchInput() {
|
||||
Widget _buildSearchInput(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => onSearchTap(),
|
||||
child: Container(
|
||||
|
@ -115,11 +116,11 @@ class SearchComponent extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
child: Row(
|
||||
children: const [
|
||||
children: [
|
||||
Icon(Icons.search, color: Color(0xFF6B778C)),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
"Search for quizzes...",
|
||||
context.tr("search_for_quizzes"),
|
||||
style: TextStyle(
|
||||
color: Color(0xFF6B778C),
|
||||
fontSize: 16,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class UserGretingsComponent extends StatelessWidget {
|
||||
|
@ -34,11 +35,11 @@ class UserGretingsComponent extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Selamat Siang",
|
||||
context.tr("greeting_time"),
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
"Hello $userName",
|
||||
context.tr("greeting_user", namedArgs: {"user": userName}),
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
|
@ -50,7 +51,7 @@ class HomeView extends GetView<HomeController> {
|
|||
const SizedBox(height: 20),
|
||||
Obx(
|
||||
() => RecomendationComponent(
|
||||
title: "Quiz Rekomendasi",
|
||||
title: context.tr("quiz_recommendation"),
|
||||
datas: controller.data.toList(),
|
||||
itemOnTap: controller.onRecommendationTap,
|
||||
allOnTap: () => controller.goToListingsQuizPage(ListingType.recomendation),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
import 'package:quiz_app/component/global_button.dart';
|
||||
import 'package:quiz_app/component/global_text_field.dart';
|
||||
|
@ -41,9 +41,9 @@ class JoinRoomView extends GetView<JoinRoomController> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"Masukkan Kode Room",
|
||||
style: TextStyle(
|
||||
Text(
|
||||
context.tr("enter_room_code"),
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.black87,
|
||||
|
@ -52,18 +52,12 @@ class JoinRoomView extends GetView<JoinRoomController> {
|
|||
const SizedBox(height: 16),
|
||||
GlobalTextField(
|
||||
controller: controller.codeController,
|
||||
hintText: "AB123C",
|
||||
hintText: context.tr("room_code_hint"),
|
||||
textInputType: TextInputType.text,
|
||||
// Uncomment if needed:
|
||||
// maxLength: 6,
|
||||
// inputFormatters: [
|
||||
// FilteringTextInputFormatter.allow(RegExp(r'[A-Z0-9]')),
|
||||
// UpperCaseTextFormatter(),
|
||||
// ],
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
GlobalButton(
|
||||
text: "Gabung Sekarang",
|
||||
text: context.tr("join_now"),
|
||||
onPressed: controller.joinRoom,
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:quiz_app/component/widget/loading_widget.dart';
|
||||
import 'package:quiz_app/data/models/quiz/quiz_listing_model.dart';
|
||||
import 'package:quiz_app/feature/library/controller/library_controller.dart';
|
||||
|
@ -17,18 +18,18 @@ class LibraryView extends GetView<LibraryController> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Library Soal',
|
||||
style: TextStyle(
|
||||
Text(
|
||||
context.tr('library_title'),
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
"Kumpulan soal-soal kuis yang sudah dibuat untuk dipelajari.",
|
||||
style: TextStyle(
|
||||
Text(
|
||||
context.tr('library_description'),
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 14,
|
||||
),
|
||||
|
@ -41,10 +42,10 @@ class LibraryView extends GetView<LibraryController> {
|
|||
}
|
||||
|
||||
if (controller.quizs.isEmpty) {
|
||||
return const Center(
|
||||
return Center(
|
||||
child: Text(
|
||||
"Belum ada soal tersedia.",
|
||||
style: TextStyle(color: Colors.grey, fontSize: 14),
|
||||
context.tr('no_quiz_available'),
|
||||
style: const TextStyle(color: Colors.grey, fontSize: 14),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -53,7 +54,10 @@ class LibraryView extends GetView<LibraryController> {
|
|||
itemCount: controller.quizs.length,
|
||||
itemBuilder: (context, index) {
|
||||
final quiz = controller.quizs[index];
|
||||
return InkWell(onTap: () => controller.goToDetail(index), child: _buildQuizCard(quiz));
|
||||
return InkWell(
|
||||
onTap: () => controller.goToDetail(index),
|
||||
child: _buildQuizCard(context, quiz),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
|
@ -65,7 +69,7 @@ class LibraryView extends GetView<LibraryController> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildQuizCard(QuizListingModel quiz) {
|
||||
Widget _buildQuizCard(BuildContext context, QuizListingModel quiz) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
|
@ -74,7 +78,7 @@ class LibraryView extends GetView<LibraryController> {
|
|||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.05),
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 6,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
|
@ -129,7 +133,7 @@ class LibraryView extends GetView<LibraryController> {
|
|||
const Icon(Icons.list, size: 14, color: Colors.grey),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'${quiz.totalQuiz} Quizzes',
|
||||
context.tr('quiz_count_named', namedArgs: {'total': quiz.totalQuiz.toString()}),
|
||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
|
@ -27,7 +28,12 @@ class ListingsQuizView extends GetView<ListingQuizController> {
|
|||
}
|
||||
|
||||
if (controller.quizzes.isEmpty) {
|
||||
return const Center(child: Text('Tidak ada kuis tersedia.'));
|
||||
return Center(
|
||||
child: Text(
|
||||
context.tr('no_quiz_available'),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
|
@ -24,26 +25,26 @@ class LoginView extends GetView<LoginController> {
|
|||
const SizedBox(height: 40),
|
||||
const AppName(),
|
||||
const SizedBox(height: 40),
|
||||
const LabelTextField(
|
||||
label: "Log In",
|
||||
LabelTextField(
|
||||
label: context.tr("log_in"),
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF172B4D),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const LabelTextField(
|
||||
label: "Email",
|
||||
LabelTextField(
|
||||
label: context.tr("email"),
|
||||
color: Color(0xFF6B778C),
|
||||
fontSize: 14,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
GlobalTextField(
|
||||
controller: controller.emailController,
|
||||
hintText: "Masukkan email anda",
|
||||
hintText: context.tr("enter_your_email"),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const LabelTextField(
|
||||
label: "Password",
|
||||
LabelTextField(
|
||||
label: context.tr("password"),
|
||||
color: Color(0xFF6B778C),
|
||||
fontSize: 14,
|
||||
),
|
||||
|
@ -54,18 +55,18 @@ class LoginView extends GetView<LoginController> {
|
|||
isPassword: true,
|
||||
obscureText: controller.isPasswordHidden.value,
|
||||
onToggleVisibility: controller.togglePasswordVisibility,
|
||||
hintText: "Masukkan password anda",
|
||||
hintText: context.tr("enter_your_password"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Obx(() => GlobalButton(
|
||||
onPressed: controller.loginWithEmail,
|
||||
text: "Masuk",
|
||||
text: context.tr("sign_in"),
|
||||
type: controller.isButtonEnabled.value,
|
||||
)),
|
||||
const SizedBox(height: 24),
|
||||
const LabelTextField(
|
||||
label: "OR",
|
||||
LabelTextField(
|
||||
label: context.tr("or"),
|
||||
alignment: Alignment.center,
|
||||
color: Color(0xFF6B778C),
|
||||
),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/feature/history/view/history_view.dart';
|
||||
|
@ -31,29 +32,29 @@ class NavbarView extends GetView<NavigationController> {
|
|||
}),
|
||||
bottomNavigationBar: Obx(
|
||||
() => BottomNavigationBar(
|
||||
type: BottomNavigationBarType.fixed, // <=== ini tambahan penting!
|
||||
type: BottomNavigationBarType.fixed,
|
||||
currentIndex: controller.selectedIndex.value,
|
||||
onTap: controller.changePage,
|
||||
items: const [
|
||||
items: [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.home),
|
||||
label: 'Home',
|
||||
icon: const Icon(Icons.home),
|
||||
label: context.tr('nav_home'),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.search),
|
||||
label: 'Search',
|
||||
icon: const Icon(Icons.search),
|
||||
label: context.tr('nav_search'),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.menu_book),
|
||||
label: 'Library',
|
||||
icon: const Icon(Icons.menu_book),
|
||||
label: context.tr('nav_library'),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.history),
|
||||
label: 'History',
|
||||
icon: const Icon(Icons.history),
|
||||
label: context.tr('nav_history'),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.person),
|
||||
label: 'Profile',
|
||||
icon: const Icon(Icons.person),
|
||||
label: context.tr('nav_profile'),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -54,7 +54,6 @@ class PlayQuizMultiplayerView extends GetView<PlayQuizMultiplayerController> {
|
|||
if (question.type == 'option') _buildOptionQuestion(),
|
||||
if (question.type == 'fill_in_the_blank') _buildFillInBlankQuestion(),
|
||||
if (question.type == 'true_false') _buildTrueFalseQuestion(),
|
||||
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/feature/profile/controller/profile_controller.dart';
|
||||
|
@ -28,11 +29,20 @@ class ProfileView extends GetView<ProfileController> {
|
|||
style: const TextStyle(fontSize: 14, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
_buildStats(),
|
||||
_buildStats(context),
|
||||
const SizedBox(height: 32),
|
||||
_buildActionButton("Edit Profil", Icons.edit, controller.editProfile),
|
||||
_buildActionButton(
|
||||
context.tr("edit_profile"),
|
||||
Icons.edit,
|
||||
controller.editProfile,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildActionButton("Logout", Icons.logout, controller.logout, isDestructive: true),
|
||||
_buildActionButton(
|
||||
context.tr("logout"),
|
||||
Icons.logout,
|
||||
controller.logout,
|
||||
isDestructive: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
|
@ -57,7 +67,7 @@ class ProfileView extends GetView<ProfileController> {
|
|||
}
|
||||
}
|
||||
|
||||
Widget _buildStats() {
|
||||
Widget _buildStats(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
|
||||
decoration: BoxDecoration(
|
||||
|
@ -74,9 +84,15 @@ class ProfileView extends GetView<ProfileController> {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildStatItem("Total Quiz", controller.totalQuizzes.value.toString()),
|
||||
_buildStatItem(
|
||||
context.tr("total_quiz"),
|
||||
controller.totalQuizzes.value.toString(),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
_buildStatItem("Skor Rata-rata", "${controller.avgScore.value}%"),
|
||||
_buildStatItem(
|
||||
context.tr("avg_score"),
|
||||
"${controller.avgScore.value}%",
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
import 'package:quiz_app/component/global_button.dart';
|
||||
import 'package:quiz_app/feature/quiz_creation/controller/quiz_creation_controller.dart';
|
||||
|
@ -16,9 +17,9 @@ class QuizCreationView extends GetView<QuizCreationController> {
|
|||
appBar: AppBar(
|
||||
backgroundColor: AppColors.background,
|
||||
elevation: 0,
|
||||
title: const Text(
|
||||
'Create Quiz',
|
||||
style: TextStyle(
|
||||
title: Text(
|
||||
context.tr('create_quiz_title'),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.darkText,
|
||||
),
|
||||
|
@ -36,13 +37,14 @@ class QuizCreationView extends GetView<QuizCreationController> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildModeSelector(),
|
||||
_buildModeSelector(context),
|
||||
const SizedBox(height: 20),
|
||||
Obx(
|
||||
() => controller.isGenerate.value ? GenerateComponent() : CustomQuestionComponent(),
|
||||
),
|
||||
Obx(() => controller.isGenerate.value ? const GenerateComponent() : const CustomQuestionComponent()),
|
||||
const SizedBox(height: 30),
|
||||
GlobalButton(text: "simpan semua", onPressed: controller.onDone)
|
||||
GlobalButton(
|
||||
text: context.tr('save_all'),
|
||||
onPressed: controller.onDone,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -51,7 +53,7 @@ class QuizCreationView extends GetView<QuizCreationController> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildModeSelector() {
|
||||
Widget _buildModeSelector(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.background,
|
||||
|
@ -60,8 +62,8 @@ class QuizCreationView extends GetView<QuizCreationController> {
|
|||
),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildModeButton('Generate', controller.isGenerate, true),
|
||||
_buildModeButton('Manual', controller.isGenerate, false),
|
||||
_buildModeButton(context.tr('mode_generate'), controller.isGenerate, true),
|
||||
_buildModeButton(context.tr('mode_manual'), controller.isGenerate, false),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -71,17 +73,18 @@ class QuizCreationView extends GetView<QuizCreationController> {
|
|||
return Expanded(
|
||||
child: InkWell(
|
||||
onTap: () => controller.onCreationTypeChange(base),
|
||||
child: Obx(
|
||||
() => Container(
|
||||
child: Obx(() {
|
||||
final selected = isSelected.value == base;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected.value == base ? AppColors.primaryBlue : Colors.transparent,
|
||||
color: selected ? AppColors.primaryBlue : Colors.transparent,
|
||||
borderRadius: base
|
||||
? BorderRadius.only(
|
||||
? const BorderRadius.only(
|
||||
topLeft: Radius.circular(10),
|
||||
bottomLeft: Radius.circular(10),
|
||||
)
|
||||
: BorderRadius.only(
|
||||
: const BorderRadius.only(
|
||||
topRight: Radius.circular(10),
|
||||
bottomRight: Radius.circular(10),
|
||||
),
|
||||
|
@ -90,12 +93,12 @@ class QuizCreationView extends GetView<QuizCreationController> {
|
|||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: isSelected.value == base ? Colors.white : AppColors.softGrayText,
|
||||
color: selected ? Colors.white : AppColors.softGrayText,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
|
@ -18,27 +19,26 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
padding: const EdgeInsets.all(16),
|
||||
child: Obx(() {
|
||||
if (!controller.isStarting.value) {
|
||||
return Center(
|
||||
child: Text(
|
||||
"Ready in ${controller.prepareDuration}",
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
));
|
||||
return Text(
|
||||
context.tr('ready_in', namedArgs: {'second': controller.prepareDuration.toString()}),
|
||||
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildCustomAppBar(),
|
||||
_buildCustomAppBar(context),
|
||||
const SizedBox(height: 20),
|
||||
_buildProgressBar(),
|
||||
const SizedBox(height: 20),
|
||||
_buildQuestionIndicator(),
|
||||
_buildQuestionIndicator(context),
|
||||
const SizedBox(height: 12),
|
||||
_buildQuestionText(),
|
||||
const SizedBox(height: 30),
|
||||
_buildAnswerSection(),
|
||||
_buildAnswerSection(context),
|
||||
const Spacer(),
|
||||
_buildNextButton(),
|
||||
_buildNextButton(context),
|
||||
],
|
||||
);
|
||||
}),
|
||||
|
@ -47,7 +47,7 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildCustomAppBar() {
|
||||
Widget _buildCustomAppBar(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: const BoxDecoration(
|
||||
|
@ -55,9 +55,9 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
children: [
|
||||
Text(
|
||||
'Kerjakan Soal',
|
||||
context.tr('quiz_play_title'),
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
@ -79,9 +79,15 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildQuestionIndicator() {
|
||||
Widget _buildQuestionIndicator(BuildContext context) {
|
||||
return Text(
|
||||
'Soal ${controller.currentIndex.value + 1} dari ${controller.quizData.questionListings.length}',
|
||||
context.tr(
|
||||
'question_indicator',
|
||||
namedArgs: {
|
||||
'current': (controller.currentIndex.value + 1).toString(),
|
||||
'total': controller.quizData.questionListings.length.toString(),
|
||||
},
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
|
@ -101,7 +107,7 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildAnswerSection() {
|
||||
Widget _buildAnswerSection(BuildContext context) {
|
||||
final question = controller.currentQuestion;
|
||||
|
||||
if (question is OptionQuestion) {
|
||||
|
@ -131,8 +137,8 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildTrueFalseButton('Ya', true, controller.choosenAnswerTOF),
|
||||
_buildTrueFalseButton('Tidak', false, controller.choosenAnswerTOF),
|
||||
_buildTrueFalseButton(context.tr('yes'), true, controller.choosenAnswerTOF),
|
||||
_buildTrueFalseButton(context.tr('no'), false, controller.choosenAnswerTOF),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
|
@ -159,7 +165,7 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
});
|
||||
}
|
||||
|
||||
Widget _buildNextButton() {
|
||||
Widget _buildNextButton(BuildContext context) {
|
||||
return Obx(() {
|
||||
final isEnabled = controller.isAnswerSelected.value;
|
||||
|
||||
|
@ -171,8 +177,8 @@ class QuizPlayView extends GetView<QuizPlayController> {
|
|||
minimumSize: const Size(double.infinity, 50),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
child: const Text(
|
||||
'Next',
|
||||
child: Text(
|
||||
context.tr('next'),
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
import 'package:quiz_app/component/global_button.dart';
|
||||
import 'package:quiz_app/component/global_text_field.dart';
|
||||
|
@ -15,25 +16,25 @@ class QuizPreviewPage extends GetView<QuizPreviewController> {
|
|||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.background,
|
||||
appBar: _buildAppBar(),
|
||||
appBar: _buildAppBar(context),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: _buildContent(),
|
||||
child: _buildContent(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
PreferredSizeWidget _buildAppBar() {
|
||||
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: AppColors.background,
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
iconTheme: const IconThemeData(color: AppColors.darkText),
|
||||
title: const Text(
|
||||
'Preview Quiz',
|
||||
style: TextStyle(
|
||||
title: Text(
|
||||
context.tr('quiz_preview_title'),
|
||||
style: const TextStyle(
|
||||
color: AppColors.darkText,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
|
@ -41,25 +42,25 @@ class QuizPreviewPage extends GetView<QuizPreviewController> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildContent() {
|
||||
Widget _buildContent(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const LabelTextField(label: "Judul"),
|
||||
LabelTextField(label: context.tr("quiz_title_label")),
|
||||
GlobalTextField(controller: controller.titleController),
|
||||
const SizedBox(height: 20),
|
||||
const LabelTextField(label: "Deskripsi Singkat"),
|
||||
LabelTextField(label: context.tr("quiz_description_label")),
|
||||
GlobalTextField(controller: controller.descriptionController),
|
||||
const SizedBox(height: 20),
|
||||
const LabelTextField(label: "Mata Pelajaran"),
|
||||
LabelTextField(label: context.tr("quiz_subject_label")),
|
||||
Obx(() => SubjectDropdownComponent(
|
||||
data: controller.subjects.toList(),
|
||||
onItemTap: controller.onSubjectTap,
|
||||
selectedIndex: controller.subjectIndex.value,
|
||||
)),
|
||||
const SizedBox(height: 20),
|
||||
_buildPublicCheckbox(),
|
||||
_buildPublicCheckbox(context),
|
||||
const SizedBox(height: 30),
|
||||
const Divider(thickness: 1.2, color: AppColors.borderLight),
|
||||
const SizedBox(height: 20),
|
||||
|
@ -67,7 +68,7 @@ class QuizPreviewPage extends GetView<QuizPreviewController> {
|
|||
const SizedBox(height: 30),
|
||||
GlobalButton(
|
||||
onPressed: controller.onSaveQuiz,
|
||||
text: "Simpan Kuis",
|
||||
text: context.tr("save_quiz"),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -83,7 +84,7 @@ class QuizPreviewPage extends GetView<QuizPreviewController> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildPublicCheckbox() {
|
||||
Widget _buildPublicCheckbox(BuildContext context) {
|
||||
return Obx(() => GestureDetector(
|
||||
onTap: controller.isPublic.toggle,
|
||||
child: Row(
|
||||
|
@ -96,9 +97,9 @@ class QuizPreviewPage extends GetView<QuizPreviewController> {
|
|||
onChanged: (val) => controller.isPublic.value = val ?? false,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
"Buat Kuis Public",
|
||||
style: TextStyle(
|
||||
Text(
|
||||
context.tr("make_quiz_public"),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.darkText,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:quiz_app/app/const/colors/app_colors.dart';
|
||||
import 'package:quiz_app/component/app_name.dart';
|
||||
import 'package:quiz_app/component/global_button.dart';
|
||||
|
@ -9,6 +10,7 @@ import 'package:quiz_app/feature/register/controller/register_controller.dart';
|
|||
|
||||
class RegisterView extends GetView<RegisterController> {
|
||||
const RegisterView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -22,47 +24,52 @@ class RegisterView extends GetView<RegisterController> {
|
|||
padding: const EdgeInsets.symmetric(vertical: 40),
|
||||
child: AppName(),
|
||||
),
|
||||
LabelTextField(label: "Register", fontSize: 24),
|
||||
LabelTextField(
|
||||
label: context.tr('register_title'),
|
||||
fontSize: 24,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
LabelTextField(label: "Full Name"),
|
||||
LabelTextField(label: context.tr('full_name')),
|
||||
GlobalTextField(controller: controller.nameController),
|
||||
const SizedBox(height: 10),
|
||||
LabelTextField(label: "Email"),
|
||||
LabelTextField(label: context.tr('email')),
|
||||
GlobalTextField(controller: controller.emailController),
|
||||
const SizedBox(height: 10),
|
||||
LabelTextField(label: "Birth Date"),
|
||||
LabelTextField(label: context.tr('birth_date')),
|
||||
GlobalTextField(
|
||||
controller: controller.bDateController,
|
||||
hintText: "12-08-2001",
|
||||
),
|
||||
LabelTextField(label: "Nomer Telepon (Opsional)"),
|
||||
LabelTextField(label: context.tr('phone_optional')),
|
||||
GlobalTextField(
|
||||
controller: controller.phoneController,
|
||||
hintText: "085708570857",
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
LabelTextField(label: "Password"),
|
||||
LabelTextField(label: context.tr('password')),
|
||||
Obx(
|
||||
() => GlobalTextField(
|
||||
controller: controller.passwordController,
|
||||
isPassword: true,
|
||||
obscureText: controller.isPasswordHidden.value,
|
||||
onToggleVisibility: controller.togglePasswordVisibility),
|
||||
onToggleVisibility: controller.togglePasswordVisibility,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
LabelTextField(label: "Verify Password"),
|
||||
LabelTextField(label: context.tr('verify_password')),
|
||||
Obx(
|
||||
() => GlobalTextField(
|
||||
controller: controller.confirmPasswordController,
|
||||
isPassword: true,
|
||||
obscureText: controller.isConfirmPasswordHidden.value,
|
||||
onToggleVisibility: controller.toggleConfirmPasswordVisibility),
|
||||
onToggleVisibility: controller.toggleConfirmPasswordVisibility,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
GlobalButton(
|
||||
onPressed: controller.onRegister,
|
||||
text: "Register",
|
||||
)
|
||||
text: context.tr('register_button'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quiz_app/app/const/enums/listing_type.dart';
|
||||
|
@ -31,7 +32,7 @@ class SearchView extends GetView<SearchQuizController> {
|
|||
] else ...[
|
||||
Obx(
|
||||
() => RecomendationComponent(
|
||||
title: "Quiz Rekomendasi",
|
||||
title: context.tr('quiz_recommendation'),
|
||||
datas: controller.recommendationQData.toList(),
|
||||
itemOnTap: controller.goToDetailPage,
|
||||
allOnTap: () => controller.goToListingsQuizPage(ListingType.recomendation),
|
||||
|
@ -40,7 +41,7 @@ class SearchView extends GetView<SearchQuizController> {
|
|||
const SizedBox(height: 30),
|
||||
Obx(
|
||||
() => RecomendationComponent(
|
||||
title: "Quiz Populer",
|
||||
title: context.tr('quiz_popular'),
|
||||
datas: controller.recommendationQData.toList(),
|
||||
itemOnTap: controller.goToDetailPage,
|
||||
allOnTap: () => controller.goToListingsQuizPage(ListingType.populer),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:quiz_app/app/app.dart';
|
||||
|
@ -14,7 +15,21 @@ void main() {
|
|||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
|
||||
runApp(MyApp());
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
await EasyLocalization.ensureInitialized();
|
||||
|
||||
runApp(
|
||||
EasyLocalization(
|
||||
supportedLocales: [
|
||||
Locale('en', 'US'),
|
||||
Locale('id', 'ID'),
|
||||
],
|
||||
path: 'assets/translations',
|
||||
fallbackLocale: Locale('en', 'US'),
|
||||
child: MyApp(),
|
||||
),
|
||||
);
|
||||
}, (e, stackTrace) {
|
||||
logC.e("issue message $e || $stackTrace");
|
||||
});
|
||||
|
|
37
pubspec.lock
37
pubspec.lock
|
@ -1,6 +1,14 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -73,6 +81,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
easy_localization:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: easy_localization
|
||||
sha256: "0f5239c7b8ab06c66440cfb0e9aa4b4640429c6668d5a42fe389c5de42220b12"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.7+1"
|
||||
easy_logger:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: easy_logger
|
||||
sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -118,6 +142,11 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
flutter_localizations:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -208,6 +237,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -43,6 +43,7 @@ dependencies:
|
|||
lucide_icons: ^0.257.0
|
||||
google_fonts: ^6.1.0
|
||||
socket_io_client: ^3.1.2
|
||||
easy_localization: ^3.0.7+1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -69,6 +70,7 @@ flutter:
|
|||
assets:
|
||||
- assets/
|
||||
- assets/logo/
|
||||
- assets/translations/
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
|
||||
|
|
Loading…
Reference in New Issue