Merge branch 'review-mode-fix' into 'master'
feat: HistoryCard navigation to direct users to ReviewScreen, and refactor... See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!19
This commit is contained in:
commit
09d264ed59
|
|
@ -1 +1 @@
|
|||
const String baseUrl = 'http://54.173.167.62/';
|
||||
const String baseUrl = 'https://1252-114-6-25-184.ngrok-free.app/';
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ class HistoryRepository {
|
|||
|
||||
HistoryRepository(this._dioClient);
|
||||
|
||||
Future<List<LearningHistory>> getLearningHistory(
|
||||
Future<List<HistoryModel>> getLearningHistory(
|
||||
String sectionId,
|
||||
String token,
|
||||
) async {
|
||||
|
|
@ -23,9 +23,7 @@ class HistoryRepository {
|
|||
if (historyData.isEmpty) {
|
||||
return []; // Mengembalikan list kosong jika tidak ada data
|
||||
}
|
||||
return historyData
|
||||
.map((json) => LearningHistory.fromJson(json))
|
||||
.toList();
|
||||
return historyData.map((json) => HistoryModel.fromJson(json)).toList();
|
||||
} else {
|
||||
throw Exception(
|
||||
'Failed to load learning history: ${response.statusMessage}');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:intl/intl.dart';
|
||||
|
||||
class LearningHistory {
|
||||
class HistoryModel {
|
||||
final String idStudentLearning;
|
||||
final int? score;
|
||||
final String currentLevel;
|
||||
final String? nextLevel;
|
||||
|
|
@ -9,7 +10,8 @@ class LearningHistory {
|
|||
final String sectionName;
|
||||
final bool isPass;
|
||||
|
||||
LearningHistory({
|
||||
HistoryModel({
|
||||
required this.idStudentLearning,
|
||||
required this.score,
|
||||
required this.currentLevel,
|
||||
required this.nextLevel,
|
||||
|
|
@ -19,8 +21,9 @@ class LearningHistory {
|
|||
required this.isPass,
|
||||
});
|
||||
|
||||
factory LearningHistory.fromJson(Map<String, dynamic> json) {
|
||||
return LearningHistory(
|
||||
factory HistoryModel.fromJson(Map<String, dynamic> json) {
|
||||
return HistoryModel(
|
||||
idStudentLearning: json['ID_STUDENT_LEARNING'],
|
||||
score: json['SCORE'] ?? 0,
|
||||
currentLevel: json['CURRENT_LEVEL'] ?? 'Unknown',
|
||||
nextLevel: json['NEXT_LEVEL'],
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import 'package:english_learning/features/history/models/history_model.dart';
|
|||
class HistoryProvider with ChangeNotifier {
|
||||
final HistoryRepository _repository;
|
||||
final SectionProvider _sectionProvider;
|
||||
List<LearningHistory> _learningHistory = [];
|
||||
List<HistoryModel> _historyModel = [];
|
||||
int _selectedPageIndex = 0;
|
||||
bool _isLoading = false;
|
||||
String? _error;
|
||||
|
|
@ -18,7 +18,7 @@ class HistoryProvider with ChangeNotifier {
|
|||
this._sectionProvider,
|
||||
);
|
||||
|
||||
List<LearningHistory> get learningHistory => _learningHistory;
|
||||
List<HistoryModel> get historyModel => _historyModel;
|
||||
int get selectedPageIndex => _selectedPageIndex;
|
||||
bool get isLoading => _isLoading;
|
||||
String? get error => _error;
|
||||
|
|
@ -46,13 +46,13 @@ class HistoryProvider with ChangeNotifier {
|
|||
String firstSectionId = _sectionProvider.sections.first.id;
|
||||
|
||||
// Fetch history for the first section
|
||||
_learningHistory =
|
||||
_historyModel =
|
||||
await _repository.getLearningHistory(firstSectionId, token);
|
||||
_error = null;
|
||||
_isInitialized = true; // Mark as initialized
|
||||
} catch (e) {
|
||||
_error = 'Error loading data: ${e.toString()}';
|
||||
_learningHistory = [];
|
||||
_historyModel = [];
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
|
|
@ -78,11 +78,11 @@ class HistoryProvider with ChangeNotifier {
|
|||
|
||||
try {
|
||||
final history = await _repository.getLearningHistory(sectionId, token);
|
||||
_learningHistory = history;
|
||||
_historyModel = history;
|
||||
_error = null;
|
||||
} catch (e) {
|
||||
_error = 'Error fetching learning history: ${e.toString()}';
|
||||
_learningHistory = [];
|
||||
_historyModel = [];
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
|
|
@ -151,14 +151,14 @@ class HistoryProvider with ChangeNotifier {
|
|||
await _sectionProvider.fetchSections(token);
|
||||
if (_sectionProvider.sections.isNotEmpty) {
|
||||
String firstSectionId = _sectionProvider.sections.first.id;
|
||||
_learningHistory =
|
||||
_historyModel =
|
||||
await _repository.getLearningHistory(firstSectionId, token);
|
||||
} else {
|
||||
_error = 'No sections available';
|
||||
}
|
||||
} catch (e) {
|
||||
_error = 'Error loading data: ${e.toString()}';
|
||||
_learningHistory = []; // Clear the list in case of error
|
||||
_historyModel = []; // Clear the list in case of error
|
||||
} finally {
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||
}
|
||||
|
||||
// Tampilkan empty state jika tidak ada history
|
||||
if (historyProvider.learningHistory.isEmpty) {
|
||||
if (historyProvider.historyModel.isEmpty) {
|
||||
return _buildEmptyState(context);
|
||||
}
|
||||
|
||||
|
|
@ -154,8 +154,8 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: ListView.builder(
|
||||
key: ValueKey(historyProvider.learningHistory.length),
|
||||
itemCount: historyProvider.learningHistory.length,
|
||||
key: ValueKey(historyProvider.historyModel.length),
|
||||
itemCount: historyProvider.historyModel.length,
|
||||
itemBuilder: (context, index) {
|
||||
return AnimatedOpacity(
|
||||
opacity: 1.0,
|
||||
|
|
@ -163,7 +163,7 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||
child: Column(
|
||||
children: [
|
||||
ExerciseHistoryCard(
|
||||
exercise: historyProvider.learningHistory[index],
|
||||
exercise: historyProvider.historyModel[index],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,104 +1,124 @@
|
|||
import 'package:english_learning/features/history/models/history_model.dart';
|
||||
import 'package:english_learning/features/history/provider/history_provider.dart';
|
||||
import 'package:english_learning/core/utils/styles/theme.dart';
|
||||
import 'package:english_learning/features/learning/modules/exercises/screens/review_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ExerciseHistoryCard extends StatelessWidget {
|
||||
final LearningHistory exercise;
|
||||
class ExerciseHistoryCard extends StatefulWidget {
|
||||
final HistoryModel exercise;
|
||||
|
||||
const ExerciseHistoryCard({
|
||||
super.key,
|
||||
required this.exercise,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ExerciseHistoryCard> createState() => _ExerciseHistoryCardState();
|
||||
}
|
||||
|
||||
class _ExerciseHistoryCardState extends State<ExerciseHistoryCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final historyProvider =
|
||||
Provider.of<HistoryProvider>(context, listen: false);
|
||||
final color = historyProvider.getColorForLevels(
|
||||
exercise.currentLevel,
|
||||
exercise.nextLevel,
|
||||
exercise.isPass,
|
||||
widget.exercise.currentLevel,
|
||||
widget.exercise.nextLevel,
|
||||
widget.exercise.isPass,
|
||||
);
|
||||
|
||||
return Card(
|
||||
color: AppColors.whiteColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
elevation: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 18.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
exercise.topicName,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: AppTextStyles.tetriaryTextStyle.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ReviewScreen(
|
||||
idStudentLearning: widget.exercise.idStudentLearning,
|
||||
topicTitle: widget.exercise.topicName,
|
||||
topicId: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Card(
|
||||
color: AppColors.whiteColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
elevation: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 18.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.exercise.topicName,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: AppTextStyles.tetriaryTextStyle.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: AppTextStyles.greyTextStyle.copyWith(
|
||||
fontSize: 14,
|
||||
const SizedBox(height: 8),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: AppTextStyles.greyTextStyle.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${widget.exercise.currentLevel} → ',
|
||||
style: AppTextStyles.blackTextStyle.copyWith(),
|
||||
),
|
||||
TextSpan(
|
||||
text: widget.exercise.isPass
|
||||
? 'Topic Finished'
|
||||
: '${widget.exercise.nextLevel}',
|
||||
style: AppTextStyles.blackTextStyle.copyWith(
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Submission: ${widget.exercise.formattedDate}',
|
||||
style: AppTextStyles.disableTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${exercise.currentLevel} → ',
|
||||
style: AppTextStyles.blackTextStyle.copyWith(),
|
||||
),
|
||||
TextSpan(
|
||||
text: exercise.isPass
|
||||
? 'Topic Finished'
|
||||
: '${exercise.nextLevel}',
|
||||
style: AppTextStyles.blackTextStyle.copyWith(
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Submission: ${exercise.formattedDate}',
|
||||
style: AppTextStyles.disableTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 26.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: color,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: Text(
|
||||
'${exercise.score}/100',
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontWeight: FontWeight.bold,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 10),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 26.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: color,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: Text(
|
||||
'${widget.exercise.score}/100',
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class ReviewExerciseModel {
|
|||
}
|
||||
|
||||
class ReviewExerciseDetail {
|
||||
final String idStudentExercise;
|
||||
final String? idStudentExercise;
|
||||
final String idAdminExercise;
|
||||
final String title;
|
||||
final String question;
|
||||
|
|
@ -46,14 +46,14 @@ class ReviewExerciseDetail {
|
|||
final String? video;
|
||||
final String? audio;
|
||||
|
||||
final String answerStudent;
|
||||
final int isCorrect;
|
||||
String answerStudent;
|
||||
int isCorrect;
|
||||
final double resultScoreStudent;
|
||||
final List<ReviewMultipleChoice>? multipleChoices;
|
||||
final List<ReviewMatchingPair>? matchingPairs;
|
||||
|
||||
ReviewExerciseDetail({
|
||||
required this.idStudentExercise,
|
||||
this.idStudentExercise,
|
||||
required this.idAdminExercise,
|
||||
required this.title,
|
||||
required this.question,
|
||||
|
|
|
|||
|
|
@ -374,6 +374,14 @@ class ExerciseProvider extends ChangeNotifier {
|
|||
|
||||
// Reset current index
|
||||
_currentExerciseIndex = 0;
|
||||
|
||||
// Ensure all exercises are displayed with empty answers for unanswered questions
|
||||
for (var exercise in _reviewExercises) {
|
||||
if (exercise.answerStudent.isEmpty) {
|
||||
exercise.answerStudent = ''; // Set empty answer
|
||||
exercise.isCorrect = 0; // Mark as incorrect
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error fetching review exercises: $e');
|
||||
rethrow;
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@ class ExerciseScreen extends StatefulWidget {
|
|||
final String? levelId;
|
||||
final String studentLearningId;
|
||||
final bool isReview;
|
||||
final String topicId; // Tambahkan ini
|
||||
final String topicTitle; // Tambahkan ini
|
||||
final String topicId;
|
||||
final String topicTitle;
|
||||
|
||||
const ExerciseScreen({
|
||||
super.key,
|
||||
required this.levelId,
|
||||
required this.studentLearningId,
|
||||
this.isReview = false,
|
||||
required this.topicId,
|
||||
required this.isReview,
|
||||
required this.topicTitle,
|
||||
});
|
||||
|
||||
|
|
@ -36,12 +36,7 @@ class _ExerciseScreenState extends State<ExerciseScreen> {
|
|||
_scrollController = ScrollController();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final provider = context.read<ExerciseProvider>();
|
||||
|
||||
if (widget.isReview) {
|
||||
provider.fetchReviewExercises(widget.studentLearningId);
|
||||
} else {
|
||||
provider.fetchExercises(widget.levelId!);
|
||||
}
|
||||
provider.fetchExercises(widget.levelId!);
|
||||
provider.setStudentLearningId(widget.studentLearningId);
|
||||
});
|
||||
}
|
||||
|
|
@ -70,9 +65,7 @@ class _ExerciseScreenState extends State<ExerciseScreen> {
|
|||
}
|
||||
|
||||
final currentExercise = provider.currentExercise;
|
||||
final hasExercises = widget.isReview
|
||||
? provider.reviewExercises.isNotEmpty
|
||||
: provider.exercises.isNotEmpty;
|
||||
final hasExercises = provider.exercises.isNotEmpty;
|
||||
|
||||
if (!hasExercises || currentExercise == null) {
|
||||
return const Scaffold(
|
||||
|
|
@ -85,15 +78,6 @@ class _ExerciseScreenState extends State<ExerciseScreen> {
|
|||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
automaticallyImplyLeading: false,
|
||||
leading: widget.isReview
|
||||
? IconButton(
|
||||
icon: const Icon(
|
||||
BootstrapIcons.arrow_left,
|
||||
color: AppColors.whiteColor,
|
||||
),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
)
|
||||
: null, // Show back button only in review mode
|
||||
iconTheme: const IconThemeData(color: AppColors.whiteColor),
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
|
|
@ -108,27 +92,24 @@ class _ExerciseScreenState extends State<ExerciseScreen> {
|
|||
gradient: AppColors.gradientTheme,
|
||||
),
|
||||
),
|
||||
actions: !widget.isReview
|
||||
? [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
BootstrapIcons.info_circle,
|
||||
color: AppColors.whiteColor,
|
||||
size: 22,
|
||||
),
|
||||
onPressed: () => _showInstructions(context),
|
||||
),
|
||||
]
|
||||
: null,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
BootstrapIcons.info_circle,
|
||||
color: AppColors.whiteColor,
|
||||
size: 22,
|
||||
),
|
||||
onPressed: () => _showInstructions(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
if (!widget.isReview)
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: ExerciseProgress(),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: ExerciseProgress(),
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
|
|
@ -140,12 +121,12 @@ class _ExerciseScreenState extends State<ExerciseScreen> {
|
|||
ExerciseContent(
|
||||
key: ValueKey(provider.currentExerciseIndex),
|
||||
exercise: currentExercise,
|
||||
isReview: widget.isReview,
|
||||
isReview: false,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ExerciseNavigator(
|
||||
onScrollToTop: _scrollToTop,
|
||||
isReview: widget.isReview,
|
||||
isReview: false,
|
||||
topicId: widget.topicId,
|
||||
topicTitle: widget.topicTitle,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,122 @@
|
|||
import 'package:bootstrap_icons/bootstrap_icons.dart';
|
||||
import 'package:english_learning/features/learning/modules/exercises/providers/exercise_provider.dart';
|
||||
import 'package:english_learning/features/learning/modules/exercises/widgets/content/exercise_content.dart';
|
||||
import 'package:english_learning/features/learning/modules/exercises/widgets/exercise_navigator.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:english_learning/core/utils/styles/theme.dart';
|
||||
|
||||
class ReviewScreen extends StatefulWidget {
|
||||
final String idStudentLearning;
|
||||
final String? topicId;
|
||||
final String topicTitle;
|
||||
|
||||
const ReviewScreen({
|
||||
super.key,
|
||||
required this.idStudentLearning,
|
||||
this.topicId,
|
||||
required this.topicTitle,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ReviewScreen> createState() => _ReviewScreenState();
|
||||
}
|
||||
|
||||
class _ReviewScreenState extends State<ReviewScreen> {
|
||||
late ScrollController _scrollController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController = ScrollController();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final provider = context.read<ExerciseProvider>();
|
||||
provider.fetchReviewExercises(widget.idStudentLearning);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _scrollToTop() {
|
||||
_scrollController.animateTo(
|
||||
0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<ExerciseProvider>(builder: (context, provider, child) {
|
||||
if (provider.isLoading) {
|
||||
return const Scaffold(
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
|
||||
final currentExercise = provider.currentExercise;
|
||||
final hasExercises = provider.reviewExercises.isNotEmpty;
|
||||
|
||||
if (!hasExercises || currentExercise == null) {
|
||||
return const Scaffold(
|
||||
body: Center(child: Text('No review exercises available')),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bgSoftColor,
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
'${provider.nameTopic} - ${provider.nameLevel}',
|
||||
style: AppTextStyles.whiteTextStyle.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
flexibleSpace: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: AppColors.gradientTheme,
|
||||
),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: const Icon(
|
||||
BootstrapIcons.arrow_left,
|
||||
color: AppColors.whiteColor,
|
||||
),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
ExerciseContent(
|
||||
key: ValueKey(provider.currentExerciseIndex),
|
||||
exercise: currentExercise,
|
||||
isReview: true,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ExerciseNavigator(
|
||||
onScrollToTop: _scrollToTop,
|
||||
isReview: true,
|
||||
topicId: widget.topicId ?? '',
|
||||
topicTitle: widget.topicTitle,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -12,14 +12,14 @@ import 'package:provider/provider.dart';
|
|||
class ExerciseNavigator extends StatelessWidget {
|
||||
final VoidCallback? onScrollToTop;
|
||||
final bool isReview;
|
||||
final String topicId;
|
||||
final String? topicId;
|
||||
final String topicTitle;
|
||||
|
||||
const ExerciseNavigator({
|
||||
super.key,
|
||||
required this.onScrollToTop,
|
||||
this.isReview = false,
|
||||
required this.topicId,
|
||||
this.topicId,
|
||||
required this.topicTitle,
|
||||
});
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ class ExerciseNavigator extends StatelessWidget {
|
|||
score: int.tryParse(result['SCORE'].toString()) ?? 0,
|
||||
isCompleted: result['IS_PASS'] == 1,
|
||||
stdLearningId: result['STUDENT_LEARNING_ID']?.toString(),
|
||||
topicId: topicId,
|
||||
topicId: topicId!,
|
||||
topicTitle: topicTitle,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:bootstrap_icons/bootstrap_icons.dart';
|
||||
import 'package:english_learning/core/utils/styles/theme.dart';
|
||||
import 'package:english_learning/core/widgets/custom_button.dart';
|
||||
import 'package:english_learning/features/learning/modules/exercises/screens/review_screen.dart';
|
||||
import 'package:english_learning/features/learning/modules/level/models/level_model.dart';
|
||||
import 'package:english_learning/features/learning/modules/level/providers/level_provider.dart';
|
||||
import 'package:english_learning/features/learning/modules/material/screens/material_screen.dart';
|
||||
|
|
@ -33,11 +34,9 @@ class PretestCard extends StatelessWidget {
|
|||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MaterialScreen(
|
||||
levelId: pretest.idLevel,
|
||||
isReview: true,
|
||||
studentLearningId: pretest.idStudentLearning,
|
||||
topicId: pretest.idTopic,
|
||||
builder: (context) => ReviewScreen(
|
||||
idStudentLearning: pretest.idStudentLearning!,
|
||||
topicId: null,
|
||||
topicTitle: pretest.nameTopic,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:english_learning/core/widgets/custom_snackbar.dart';
|
|||
import 'package:english_learning/core/widgets/global_button.dart';
|
||||
import 'package:english_learning/features/auth/provider/user_provider.dart';
|
||||
import 'package:english_learning/features/learning/modules/exercises/screens/exercise_screen.dart';
|
||||
import 'package:english_learning/features/learning/modules/exercises/screens/review_screen.dart';
|
||||
import 'package:english_learning/features/learning/modules/level/providers/level_provider.dart';
|
||||
import 'package:english_learning/features/learning/modules/material/widgets/audio_player_widget.dart';
|
||||
import 'package:english_learning/features/learning/modules/material/widgets/image_widget.dart';
|
||||
|
|
@ -67,8 +68,8 @@ class _MaterialScreenState extends State<MaterialScreen>
|
|||
|
||||
Future<void> _createStudentLearning() async {
|
||||
if (widget.isReview && widget.studentLearningId != null) {
|
||||
// Jika mode review dan studentLearningId tersedia, langsung navigasi ke ExerciseScreen
|
||||
_navigateToExercise(widget.studentLearningId!);
|
||||
// Jika mode review dan studentLearningId tersedia, langsung navigasi ke ReviewScreen
|
||||
_navigateToReview(widget.studentLearningId!);
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
|
|
@ -102,7 +103,20 @@ class _MaterialScreenState extends State<MaterialScreen>
|
|||
builder: (context) => ExerciseScreen(
|
||||
levelId: widget.levelId,
|
||||
studentLearningId: studentLearningId,
|
||||
isReview: widget.isReview,
|
||||
isReview: false,
|
||||
topicId: widget.topicId,
|
||||
topicTitle: widget.topicTitle,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToReview(String studentLearningId) {
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ReviewScreen(
|
||||
idStudentLearning: studentLearningId,
|
||||
topicId: widget.topicId,
|
||||
topicTitle: widget.topicTitle,
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user