From 140b8f103c54fb60ba3bb6039f33f8019357f1b4 Mon Sep 17 00:00:00 2001 From: akhdanre Date: Sun, 4 May 2025 03:07:15 +0700 Subject: [PATCH] feat: adding global text style --- lib/app/const/text/text_style.dart | 55 ++++++++++++++++++ .../view/component/quiz_item_component.dart | 33 +++-------- .../history/view/detail_history_view.dart | 57 +++++-------------- lib/feature/history/view/history_view.dart | 49 ++++++---------- pubspec.lock | 40 +++++++++++++ pubspec.yaml | 1 + 6 files changed, 137 insertions(+), 98 deletions(-) create mode 100644 lib/app/const/text/text_style.dart diff --git a/lib/app/const/text/text_style.dart b/lib/app/const/text/text_style.dart new file mode 100644 index 0000000..f6697cc --- /dev/null +++ b/lib/app/const/text/text_style.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:quiz_app/app/const/colors/app_colors.dart'; + +class AppTextStyles { + /// Title: strong and modern using Roboto + static final TextStyle title = GoogleFonts.roboto( + fontSize: 20, + fontWeight: FontWeight.bold, + color: AppColors.darkText, + ); + + /// Subtitle: clean and readable using Inter + static final TextStyle subtitle = GoogleFonts.inter( + fontSize: 14, + fontWeight: FontWeight.w500, + color: AppColors.softGrayText, + ); + + /// Body: neutral and easy-to-read using Inter + static final TextStyle body = GoogleFonts.inter( + fontSize: 14, + fontWeight: FontWeight.w400, + color: AppColors.darkText, + ); + + /// Caption: friendly and soft using Nunito + static final TextStyle caption = GoogleFonts.nunito( + fontSize: 13, + fontWeight: FontWeight.w400, + color: AppColors.softGrayText, + ); + + /// Stat value: bold and standout using Poppins + static final TextStyle statValue = GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w600, + color: AppColors.darkText, + ); + + /// Option text: clean and consistent using Inter + static final TextStyle optionText = GoogleFonts.inter( + fontSize: 14, + fontWeight: FontWeight.w400, + color: AppColors.darkText, + ); + + /// DateTime: subtle and elegant using Nunito Italic + static final TextStyle dateTime = GoogleFonts.nunito( + fontSize: 13, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + color: AppColors.softGrayText, + ); +} diff --git a/lib/feature/history/view/component/quiz_item_component.dart b/lib/feature/history/view/component/quiz_item_component.dart index c4e107b..37e109a 100644 --- a/lib/feature/history/view/component/quiz_item_component.dart +++ b/lib/feature/history/view/component/quiz_item_component.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lucide_icons/lucide_icons.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/data/models/history/detail_quiz_history.dart'; class QuizItemComponent extends StatelessWidget { @@ -36,10 +37,7 @@ class QuizItemComponent extends StatelessWidget { const SizedBox(height: 12), _buildAnswerIndicator(), const SizedBox(height: 16), - const Divider( - height: 24, - color: AppColors.shadowPrimary, - ), + const Divider(height: 24, color: AppColors.shadowPrimary), _buildMetadata(), ], ), @@ -49,10 +47,7 @@ class QuizItemComponent extends StatelessWidget { Widget _buildQuestionText() { return Text( '${item.index}. ${item.question}', - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - ), + style: AppTextStyles.title.copyWith(fontSize: 16, fontWeight: FontWeight.w600), ); } @@ -90,17 +85,10 @@ class QuizItemComponent extends StatelessWidget { ), child: Row( children: [ - Icon( - icon, - size: 16, - color: iconColor, - ), + Icon(icon, size: 16, color: iconColor), const SizedBox(width: 8), Flexible( - child: Text( - text, - style: const TextStyle(fontSize: 14), - ), + child: Text(text, style: AppTextStyles.optionText), ), ], ), @@ -126,7 +114,7 @@ class QuizItemComponent extends StatelessWidget { const SizedBox(width: 8), Text( 'Jawabanmu: $userAnswerText', - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + style: AppTextStyles.statValue, ), ], ), @@ -134,10 +122,10 @@ class QuizItemComponent extends StatelessWidget { const SizedBox(height: 6), Row( children: [ - const SizedBox(width: 26), // offset icon size + spacing + const SizedBox(width: 26), // offset for icon + spacing Text( 'Jawaban benar: $correctAnswerText', - style: const TextStyle(fontSize: 14, color: Colors.black54), + style: AppTextStyles.caption, ), ], ), @@ -161,10 +149,7 @@ class QuizItemComponent extends StatelessWidget { children: [ Icon(icon, size: 16, color: AppColors.primaryBlue), const SizedBox(width: 6), - Text( - label, - style: const TextStyle(fontSize: 13, color: Colors.black54), - ), + Text(label, style: AppTextStyles.caption), ], ); } diff --git a/lib/feature/history/view/detail_history_view.dart b/lib/feature/history/view/detail_history_view.dart index 7e3f7db..eba49d4 100644 --- a/lib/feature/history/view/detail_history_view.dart +++ b/lib/feature/history/view/detail_history_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get_state_manager/get_state_manager.dart'; import 'package:lucide_icons/lucide_icons.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/widget/loading_widget.dart'; import 'package:quiz_app/feature/history/controller/detail_history_controller.dart'; import 'package:quiz_app/feature/history/view/component/quiz_item_component.dart'; @@ -16,12 +17,9 @@ class DetailHistoryView extends GetView { appBar: AppBar( backgroundColor: AppColors.background, elevation: 0, - title: const Text( + title: Text( 'Detail history', - style: TextStyle( - color: AppColors.darkText, - fontWeight: FontWeight.bold, - ), + style: AppTextStyles.title.copyWith(fontSize: 24), ), centerTitle: true, iconTheme: const IconThemeData(color: AppColors.darkText), @@ -29,11 +27,7 @@ class DetailHistoryView extends GetView { body: SafeArea( child: Obx(() { if (controller.isLoading.value) { - return Expanded( - child: Center( - child: LoadingWidget(), - ), - ); + return const Center(child: LoadingWidget()); } return ListView( children: [ @@ -62,7 +56,7 @@ class DetailHistoryView extends GetView { borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.05), + color: Colors.black.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, 4), ), @@ -71,43 +65,31 @@ class DetailHistoryView extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - quiz.title, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), + Text(quiz.title, style: AppTextStyles.title), const SizedBox(height: 8), Text( quiz.description, - style: const TextStyle(fontSize: 14, color: Colors.black54), + textAlign: TextAlign.justify, + style: AppTextStyles.caption, ), const SizedBox(height: 12), Row( children: [ - const Icon(LucideIcons.calendar, size: 16, color: Colors.black45), + const Icon(LucideIcons.calendar, size: 16, color: AppColors.softGrayText), const SizedBox(width: 6), - Text( - quiz.answeredAt, - style: const TextStyle(fontSize: 13, color: Colors.black54), - ), + Text(quiz.answeredAt, style: AppTextStyles.dateTime), ], ), const SizedBox(height: 6), Row( children: [ - const Icon(LucideIcons.clock, size: 16, color: Colors.black45), + const Icon(LucideIcons.clock, size: 16, color: AppColors.softGrayText), const SizedBox(width: 6), - Text( - '12:00', // tanggal dan jam dipisahkan titik tengah - style: const TextStyle(fontSize: 13, color: Colors.black54), - ), + Text('12:00', style: AppTextStyles.dateTime), // Replace with quiz.timeAnswered if available ], ), const SizedBox(height: 6), - const Divider( - height: 24, - thickness: 1, - color: AppColors.shadowPrimary, - ), + const Divider(height: 24, thickness: 1, color: AppColors.shadowPrimary), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -146,17 +128,8 @@ class DetailHistoryView extends GetView { children: [ Icon(icon, color: color, size: 28), const SizedBox(height: 4), - Text( - value, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - Text( - label, - style: const TextStyle(fontSize: 12, color: Colors.black54), - ), + Text(value, style: AppTextStyles.statValue), + Text(label, style: AppTextStyles.caption), ], ); } diff --git a/lib/feature/history/view/history_view.dart b/lib/feature/history/view/history_view.dart index c7b7f77..1582446 100644 --- a/lib/feature/history/view/history_view.dart +++ b/lib/feature/history/view/history_view.dart @@ -1,51 +1,45 @@ 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/widget/loading_widget.dart'; import 'package:quiz_app/data/models/history/quiz_history.dart'; import 'package:quiz_app/feature/history/controller/history_controller.dart'; class HistoryView extends GetView { const HistoryView({super.key}); + @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: const Color(0xFFF8F9FB), + backgroundColor: AppColors.background, body: SafeArea( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - "Riwayat Kuis", - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), + Text("Riwayat Kuis", style: AppTextStyles.title.copyWith(fontSize: 24)), const SizedBox(height: 8), - const Text( + Text( "Lihat kembali hasil kuis yang telah kamu kerjakan", - style: TextStyle( - fontSize: 14, - color: Colors.grey, - ), + style: AppTextStyles.subtitle, ), const SizedBox(height: 20), Obx(() { if (controller.isLoading.value) { - return Expanded( - child: Center( - child: LoadingWidget(), - ), + return const Expanded( + child: Center(child: LoadingWidget()), ); } final historyList = controller.historyList; if (historyList.isEmpty) { - return const Expanded( - child: Center(child: Text("you still doesnt have quiz history")), + return Expanded( + child: Center( + child: Text("You don't have any quiz history yet", style: AppTextStyles.body), + ), ); } @@ -99,15 +93,9 @@ class HistoryView extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - item.title, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), + Text(item.title, style: AppTextStyles.statValue), const SizedBox(height: 4), - Text( - item.date, - style: const TextStyle(fontSize: 12, color: Colors.grey), - ), + Text(item.date, style: AppTextStyles.caption), const SizedBox(height: 8), Row( children: [ @@ -115,15 +103,12 @@ class HistoryView extends GetView { const SizedBox(width: 4), Text( "Skor: ${item.totalCorrect}/${item.totalQuestion}", - style: const TextStyle(fontSize: 12), + style: AppTextStyles.caption, ), const SizedBox(width: 16), const Icon(Icons.timer, size: 14, color: Colors.grey), const SizedBox(width: 4), - Text( - "3 menit", - style: const TextStyle(fontSize: 12), - ), + Text("3 menit", style: AppTextStyles.caption), ], ), ], diff --git a/pubspec.lock b/pubspec.lock index 92b35f5..942d1fc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,6 +41,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" cupertino_icons: dependency: "direct main" description: @@ -128,6 +136,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.6.6" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" google_identity_services_web: dependency: transitive description: @@ -272,6 +288,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 + url: "https://pub.dev" + source: hosted + version: "2.2.17" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" + source: hosted + version: "2.4.1" path_provider_linux: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 757e6c0..cad9a05 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: dio: ^5.8.0+1 shared_preferences: ^2.5.3 lucide_icons: ^0.257.0 + google_fonts: ^6.1.0 dev_dependencies: flutter_test: