refactor: auto refresh after submit feedback and app configuration

This commit is contained in:
Naresh Pratista 2024-11-06 13:28:28 +07:00
parent 6e91ce7898
commit 3f21a084bd
18 changed files with 125 additions and 143 deletions

View File

@ -3,7 +3,7 @@
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/>
<application <application
android:label="english_learning" android:label="SEALS"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -1 +1 @@
const String baseUrl = 'https://c62a-139-255-101-170.ngrok-free.app/'; const String baseUrl = 'https://7558-114-6-25-184.ngrok-free.app/';

View File

@ -51,9 +51,6 @@ class HistoryScreen extends StatelessWidget {
} }
Widget _buildContent(BuildContext context, HistoryProvider historyProvider) { Widget _buildContent(BuildContext context, HistoryProvider historyProvider) {
print("isLoading: ${historyProvider.isLoading}");
print("error: ${historyProvider.error}");
print("historyLength: ${historyProvider.learningHistory.length}");
if (historyProvider.isLoading) { if (historyProvider.isLoading) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }

View File

@ -12,12 +12,16 @@ class ExerciseScreen extends StatefulWidget {
final String? levelId; final String? levelId;
final String studentLearningId; final String studentLearningId;
final bool isReview; final bool isReview;
final String topicId; // Tambahkan ini
final String topicTitle; // Tambahkan ini
const ExerciseScreen({ const ExerciseScreen({
super.key, super.key,
required this.levelId, required this.levelId,
required this.studentLearningId, required this.studentLearningId,
this.isReview = false, this.isReview = false,
required this.topicId,
required this.topicTitle,
}); });
@override @override
@ -142,6 +146,8 @@ class _ExerciseScreenState extends State<ExerciseScreen> {
ExerciseNavigator( ExerciseNavigator(
onScrollToTop: _scrollToTop, onScrollToTop: _scrollToTop,
isReview: widget.isReview, isReview: widget.isReview,
topicId: widget.topicId,
topicTitle: widget.topicTitle,
), ),
const SizedBox(height: 32), const SizedBox(height: 32),
], ],

View File

@ -11,11 +11,15 @@ import 'package:provider/provider.dart';
class ExerciseNavigator extends StatelessWidget { class ExerciseNavigator extends StatelessWidget {
final VoidCallback? onScrollToTop; final VoidCallback? onScrollToTop;
final bool isReview; final bool isReview;
final String topicId;
final String topicTitle;
const ExerciseNavigator({ const ExerciseNavigator({
super.key, super.key,
required this.onScrollToTop, required this.onScrollToTop,
this.isReview = false, this.isReview = false,
required this.topicId,
required this.topicTitle,
}); });
@override @override
@ -43,6 +47,8 @@ class ExerciseNavigator extends StatelessWidget {
score: int.tryParse(result['SCORE'].toString()) ?? 0, score: int.tryParse(result['SCORE'].toString()) ?? 0,
isCompleted: result['IS_PASS'] == 1, isCompleted: result['IS_PASS'] == 1,
stdLearningId: result['STUDENT_LEARNING_ID']?.toString(), stdLearningId: result['STUDENT_LEARNING_ID']?.toString(),
topicId: topicId,
topicTitle: topicTitle,
), ),
), ),
); );

View File

@ -2,15 +2,20 @@ import 'package:english_learning/core/widgets/global_button.dart';
import 'package:english_learning/core/utils/styles/theme.dart'; import 'package:english_learning/core/utils/styles/theme.dart';
import 'package:english_learning/features/learning/modules/exercises/providers/exercise_provider.dart'; import 'package:english_learning/features/learning/modules/exercises/providers/exercise_provider.dart';
import 'package:english_learning/features/learning/modules/feedback/widgets/feedback_dialog.dart'; import 'package:english_learning/features/learning/modules/feedback/widgets/feedback_dialog.dart';
import 'package:english_learning/features/learning/modules/level/screens/level_list_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class FeedbackScreen extends StatefulWidget { class FeedbackScreen extends StatefulWidget {
final String stdLearningId; final String stdLearningId;
final String topicId;
final String topicTitle;
const FeedbackScreen({ const FeedbackScreen({
super.key, super.key,
required this.stdLearningId, required this.stdLearningId,
required this.topicId,
required this.topicTitle,
}); });
@override @override
@ -75,7 +80,16 @@ class _FeedbackScreenState extends State<FeedbackScreen> {
return FeedbackDialog( return FeedbackDialog(
onSubmit: () { onSubmit: () {
Navigator.of(dialogContext).pop(); // Close the dialog Navigator.of(dialogContext).pop(); // Close the dialog
Navigator.of(context).pop(); // Return to the previous screen Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => LevelListScreen(
topicId: widget.topicId,
topicTitle: widget.topicTitle,
),
),
(route) => false, // This removes all previous routes
);
}, },
); );
}, },
@ -189,16 +203,15 @@ class _FeedbackScreenState extends State<FeedbackScreen> {
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
borderColor: AppColors.blueColor, borderColor: AppColors.blueColor,
onPressed: () { onPressed: () {
// Navigator.push( Navigator.pushReplacement(
// context, context,
// MaterialPageRoute( MaterialPageRoute(
// builder: (context) => LevelListScreen( builder: (context) => LevelListScreen(
// topicId: widget.topicId!, topicId: widget.topicId,
// topicTitle: widget.topicTitle!, topicTitle: widget.topicTitle,
// ), ),
// ), ),
// ); );
Navigator.of(context).pop(true);
}, },
) )
], ],

View File

@ -46,31 +46,6 @@ class LevelProvider with ChangeNotifier {
orElse: () => throw Exception('Pretest not found')); orElse: () => throw Exception('Pretest not found'));
} }
// int getLevelScore(String levelId) {
// final level = _levels.firstWhere((level) => level.idLevel == levelId,
// orElse: () => const Level(
// idLevel: '',
// idTopic: '',
// idSection: '',
// nameSection: '',
// nameTopic: '',
// nameLevel: '',
// content: '',
// isPretest: 0,
// timeLevel: '',
// ));
// return level.score ?? 0;
// }
// bool isLevelAllowed(String levelName) {
// return _unlockedLevels.contains(levelName);
// }
// bool isLevelCompleted(String levelId) {
// return _lastCompletedLevel != null &&
// _lastCompletedLevel!['ID_LEVEL'] == levelId;
// }
bool isPretestFinished(String levelId) { bool isPretestFinished(String levelId) {
return _levels.any( return _levels.any(
(level) => level.idLevel == levelId && level.idStudentLearning != null); (level) => level.idLevel == levelId && level.idStudentLearning != null);
@ -98,38 +73,4 @@ class LevelProvider with ChangeNotifier {
return _levels.any( return _levels.any(
(level) => level.idLevel == levelId && level.idStudentLearning != null); (level) => level.idLevel == levelId && level.idStudentLearning != null);
} }
// bool isLevelAllowed(String levelId) {
// if (_lastCompletedLevel == null) {
// // Jika tidak ada level yang selesai, hanya pretest yang diizinkan
// return levelId == _levels.first.idLevel;
// }
// String lastCompletedLevelId = _lastCompletedLevel!['ID_LEVEL'];
// int lastCompletedIndex =
// _levels.indexWhere((level) => level.idLevel == lastCompletedLevelId);
// int currentIndex = _levels.indexWhere((level) => level.idLevel == levelId);
// // Level diizinkan jika indeksnya kurang dari atau sama dengan indeks terakhir yang selesai + 1
// return currentIndex <= lastCompletedIndex + 1;
// }
// bool isLevelAllowed(int levelIndex) {
// if (levelIndex == 0) return true; // Pretest is always allowed
// if (_lastCompletedLevel == null)
// return levelIndex ==
// 1; // If no level completed, only first level is allowed
// String lastCompletedLevelId = _lastCompletedLevel!['ID_LEVEL'];
// int lastCompletedIndex =
// _levels.indexWhere((level) => level.idLevel == lastCompletedLevelId);
// return levelIndex <= lastCompletedIndex + 2;
// }
// bool isLevelFinished(int levelIndex) {
// return _levels[levelIndex].idStudentLearning != null;
// }
// int getLevelScore(int levelIndex) {
// return _levels[levelIndex].score ?? 0;
// }
} }

View File

@ -78,7 +78,9 @@ class _LevelListScreenState extends State<LevelListScreen> {
.where((level) => level.isPretest == 0) .where((level) => level.isPretest == 0)
.toList(); .toList();
return Padding( return RefreshIndicator(
onRefresh: _fetchLevels,
child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
children: [ children: [
@ -116,6 +118,7 @@ class _LevelListScreenState extends State<LevelListScreen> {
), ),
], ],
), ),
),
); );
} }
}, },

View File

@ -141,6 +141,8 @@ class LevelCard extends StatelessWidget {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => MaterialScreen( builder: (context) => MaterialScreen(
levelId: level.idLevel, levelId: level.idLevel,
topicId: level.idTopic,
topicTitle: level.nameTopic,
), ),
), ),
); );

View File

@ -37,6 +37,8 @@ class PretestCard extends StatelessWidget {
levelId: pretest.idLevel, levelId: pretest.idLevel,
isReview: true, isReview: true,
studentLearningId: pretest.idStudentLearning, studentLearningId: pretest.idStudentLearning,
topicId: pretest.idTopic,
topicTitle: pretest.nameTopic,
), ),
), ),
); );
@ -48,6 +50,8 @@ class PretestCard extends StatelessWidget {
builder: (context) => MaterialScreen( builder: (context) => MaterialScreen(
levelId: pretest.idLevel, levelId: pretest.idLevel,
isReview: false, isReview: false,
topicId: pretest.idTopic,
topicTitle: pretest.nameTopic,
), ),
), ),
); );
@ -141,31 +145,6 @@ class PretestCard extends StatelessWidget {
width: double.infinity, width: double.infinity,
height: 36, height: 36,
color: isFinished ? Colors.green : AppColors.yellowButtonColor, color: isFinished ? Colors.green : AppColors.yellowButtonColor,
// onPressed: () {
// if (!isCompleted) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => MaterialScreen(
// levelId: pretest.idLevel,
// ),
// ),
// );
// }
// // Jika isCompleted true, tidak melakukan apa-apa
// },
// onPressed: isAllowed
// ? () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => MaterialScreen(
// levelId: pretest.idLevel,
// ),
// ),
// );
// }
// : () {},
onPressed: navigateToMaterial, onPressed: navigateToMaterial,
), ),
], ],

View File

@ -16,12 +16,16 @@ class MaterialScreen extends StatefulWidget {
final String levelId; final String levelId;
final bool isReview; final bool isReview;
final String? studentLearningId; final String? studentLearningId;
final String topicId;
final String topicTitle;
const MaterialScreen({ const MaterialScreen({
super.key, super.key,
required this.levelId, required this.levelId,
this.isReview = false, this.isReview = false,
this.studentLearningId, this.studentLearningId,
required this.topicId,
required this.topicTitle,
}); });
@override @override
@ -100,6 +104,8 @@ class _MaterialScreenState extends State<MaterialScreen>
levelId: widget.levelId, levelId: widget.levelId,
studentLearningId: studentLearningId, studentLearningId: studentLearningId,
isReview: widget.isReview, isReview: widget.isReview,
topicId: widget.topicId,
topicTitle: widget.topicTitle,
), ),
), ),
); );

View File

@ -10,6 +10,8 @@ class ResultScreen extends StatelessWidget {
final int score; final int score;
final bool isCompleted; final bool isCompleted;
final String? stdLearningId; final String? stdLearningId;
final String topicId;
final String topicTitle;
const ResultScreen({ const ResultScreen({
super.key, super.key,
@ -18,6 +20,8 @@ class ResultScreen extends StatelessWidget {
required this.score, required this.score,
required this.isCompleted, required this.isCompleted,
this.stdLearningId, this.stdLearningId,
required this.topicId,
required this.topicTitle,
}); });
@override @override
@ -37,18 +41,24 @@ class ResultScreen extends StatelessWidget {
currentLevel: currentLevel, currentLevel: currentLevel,
score: score, score: score,
stdLearningId: stdLearningId ?? '', stdLearningId: stdLearningId ?? '',
topicId: topicId, // Tambahkan ini
topicTitle: topicTitle, // Tambahkan ini
) )
else if (nextLevel != currentLevel) else if (nextLevel != currentLevel)
JumpResultWidget( JumpResultWidget(
nextLevel: nextLevel, nextLevel: nextLevel,
score: score, score: score,
stdLearningId: stdLearningId ?? '', stdLearningId: stdLearningId ?? '',
topicId: topicId, // Tambahkan ini
topicTitle: topicTitle, // Tambahkan ini
) )
else else
DownResultWidget( DownResultWidget(
nextLevel: nextLevel, nextLevel: nextLevel,
score: score, score: score,
stdLearningId: stdLearningId ?? '', stdLearningId: stdLearningId ?? '',
topicId: topicId, // Tambahkan ini
topicTitle: topicTitle, // Tambahkan ini
), ),
], ],
), ),

View File

@ -8,12 +8,16 @@ class CompleteResultWidget extends StatelessWidget {
final String? currentLevel; final String? currentLevel;
final int? score; final int? score;
final String stdLearningId; final String stdLearningId;
final String topicId;
final String topicTitle;
const CompleteResultWidget({ const CompleteResultWidget({
super.key, super.key,
required this.currentLevel, required this.currentLevel,
required this.score, required this.score,
required this.stdLearningId, required this.stdLearningId,
required this.topicId,
required this.topicTitle,
}); });
@override @override
@ -57,6 +61,8 @@ class CompleteResultWidget extends StatelessWidget {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => FeedbackScreen( builder: (context) => FeedbackScreen(
stdLearningId: stdLearningId, stdLearningId: stdLearningId,
topicId: topicId, // Tambahkan ini
topicTitle: topicTitle, // Tambahkan ini
), ),
), ),
); );

View File

@ -8,12 +8,16 @@ class DownResultWidget extends StatelessWidget {
final String? nextLevel; final String? nextLevel;
final int? score; final int? score;
final String stdLearningId; final String stdLearningId;
final String topicId;
final String topicTitle;
const DownResultWidget({ const DownResultWidget({
super.key, super.key,
required this.nextLevel, required this.nextLevel,
required this.score, required this.score,
required this.stdLearningId, required this.stdLearningId,
required this.topicId,
required this.topicTitle,
}); });
@override @override
@ -67,6 +71,8 @@ class DownResultWidget extends StatelessWidget {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => FeedbackScreen( builder: (context) => FeedbackScreen(
stdLearningId: stdLearningId, stdLearningId: stdLearningId,
topicId: topicId, // Tambahkan ini
topicTitle: topicTitle, // Tambahkan ini
), ),
), ),
); );

View File

@ -8,12 +8,17 @@ class JumpResultWidget extends StatelessWidget {
final String? nextLevel; final String? nextLevel;
final int? score; final int? score;
final String stdLearningId; final String stdLearningId;
final String topicId;
final String topicTitle;
const JumpResultWidget( const JumpResultWidget({
{super.key, super.key,
required this.nextLevel, required this.nextLevel,
required this.score, required this.score,
required this.stdLearningId}); required this.stdLearningId,
required this.topicId,
required this.topicTitle,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -66,6 +71,8 @@ class JumpResultWidget extends StatelessWidget {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => FeedbackScreen( builder: (context) => FeedbackScreen(
stdLearningId: stdLearningId, stdLearningId: stdLearningId,
topicId: topicId, // Tambahkan ini
topicTitle: topicTitle, // Tambahkan ini
), ),
), ),
); );

View File

@ -137,7 +137,7 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
child: Consumer<TopicProvider>( child: Consumer<TopicProvider>(
builder: (context, topicProvider, _) { builder: (context, topicProvider, _) {
if (topicProvider.topics.isEmpty) { if (topicProvider.topics.isEmpty) {
return Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (topicProvider.error != null) { } else if (topicProvider.error != null) {
return const Center(child: Text('No topics available')); return const Center(child: Text('No topics available'));
} else { } else {
@ -150,7 +150,7 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
description: topic.description, description: topic.description,
isCompleted: topic.isCompleted, isCompleted: topic.isCompleted,
onTap: () { onTap: () {
Navigator.push( Navigator.pushReplacement(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => LevelListScreen( builder: (context) => LevelListScreen(