From 938d3de9d157ae3fb896e44d195827ce15695d92 Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Tue, 8 Jul 2025 23:17:16 +0530 Subject: [PATCH 01/10] fix: reset code bug --- .../lib/ui/views/learn/challenge/challenge_viewmodel.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart index 5bec29c55..c40ac05d1 100644 --- a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart +++ b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart @@ -593,6 +593,9 @@ class ChallengeViewModel extends BaseViewModel { await prefs.remove(challengeUrl); + closeWebViews(); + disposeOfListeners(); + _navigationService.replaceWith( Routes.challengeTemplateView, arguments: ChallengeTemplateViewArguments( From 3b0eb1ae9afa94a7858734adf549b5198f05423c Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Tue, 8 Jul 2025 23:21:58 +0530 Subject: [PATCH 02/10] fix: remove file editable region boundaries on code reset --- .../learn/challenge/challenge_viewmodel.dart | 15 +++++++++++---- mobile-app/lib/utils/helpers.dart | 6 +++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart index c40ac05d1..24e48b8d9 100644 --- a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart +++ b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart @@ -343,7 +343,7 @@ class ChallengeViewModel extends BaseViewModel { key: ValueKey(editorText), defaultLanguage: editorLanguage, defaultValue: editorText ?? '', - path: '/${challenge.id}/${getFullFileName(file)}', + path: getFullFilePath(challenge, file), options: options, ); @@ -480,7 +480,7 @@ class ChallengeViewModel extends BaseViewModel { .toList(); String text = prefs.getString( - '${currChallenge.id}.${currentFile[0].name}', + '${currChallenge.id}.${getFullFileName(currentFile[0])}', ) ?? currentFile[0].contents; @@ -545,6 +545,10 @@ class ChallengeViewModel extends BaseViewModel { return '${file.name}.${file.ext.value}'; } + String getFullFilePath(Challenge challenge, ChallengeFile file) { + return '/${challenge.id}/${getFullFileName(file)}'; + } + ChallengeFile currentFile(Challenge challenge) { if (currentSelectedFile.isNotEmpty) { ChallengeFile file = challenge.files.firstWhere( @@ -576,10 +580,13 @@ class ChallengeViewModel extends BaseViewModel { ); if (res?.confirmed == true) { - Challenge? currChallenge = challenge; + Challenge currChallenge = challenge!; - for (ChallengeFile file in currChallenge!.files) { + for (ChallengeFile file in currChallenge.files) { + // NOTE: Removes file content from cache await prefs.remove('${currChallenge.id}.${getFullFileName(file)}'); + // NOTE: Removes file editable region boundaries from cache + await prefs.remove(getFullFilePath(currChallenge, file)); } var challengeIndex = block!.challengeTiles.indexWhere( diff --git a/mobile-app/lib/utils/helpers.dart b/mobile-app/lib/utils/helpers.dart index 692f20389..a12b898f5 100644 --- a/mobile-app/lib/utils/helpers.dart +++ b/mobile-app/lib/utils/helpers.dart @@ -17,9 +17,9 @@ Future filesToMarkdown(Challenge challenge, String editorText) async { ? '/* file: ${challengeFile.name}.${challengeFile.ext} */\n' : ''; final fileType = challengeFile.ext.name; - final fileContent = - prefs.getString('${challenge.id}.${challengeFile.name}') ?? - challengeFile.contents; + final fileContent = prefs.getString( + '${challenge.id}.${challengeFile.name}${challengeFile.ext.value}') ?? + challengeFile.contents; markdownStr += '```$fileType\n$fileName$fileContent\n```\n\n'; } From ceead32f6528aa87219c7d533cdf67cecfe20fa2 Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Wed, 9 Jul 2025 06:27:20 +0530 Subject: [PATCH 03/10] chore: missing dot Co-authored-by: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com> --- mobile-app/lib/utils/helpers.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/lib/utils/helpers.dart b/mobile-app/lib/utils/helpers.dart index a12b898f5..a8f066679 100644 --- a/mobile-app/lib/utils/helpers.dart +++ b/mobile-app/lib/utils/helpers.dart @@ -18,7 +18,7 @@ Future filesToMarkdown(Challenge challenge, String editorText) async { : ''; final fileType = challengeFile.ext.name; final fileContent = prefs.getString( - '${challenge.id}.${challengeFile.name}${challengeFile.ext.value}') ?? + '${challenge.id}.${challengeFile.name}.${challengeFile.ext.value}') ?? challengeFile.contents; markdownStr += '```$fileType\n$fileName$fileContent\n```\n\n'; } From 1a1fb83ef9080b0b14698e6046c4f070d7b2468c Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Wed, 9 Jul 2025 06:44:08 +0530 Subject: [PATCH 04/10] fix: editor state not updated when changing away from editor view --- mobile-app/lib/ui/views/learn/challenge/challenge_view.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart b/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart index 9175a268c..fbf184bea 100644 --- a/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart @@ -295,7 +295,7 @@ class ChallengeView extends StatelessWidget { }, }, ); - log('TestRunner: \\$res'); + log('TestRunner: $res'); }, initialSettings: InAppWebViewSettings( isInspectable: true, @@ -459,6 +459,7 @@ class ChallengeView extends StatelessWidget { return TextButton.icon( onPressed: () { model.setShowTestsPanel = !model.showTestsPanel; + model.setMounted = false; }, label: Text( 'Tests', @@ -578,6 +579,7 @@ class ChallengeView extends StatelessWidget { ChallengeFile currFile = model.currentFile(challenge); model.setShowPreview = !model.showPreview; model.setShowConsole = false; + model.setMounted = false; model.initFile(challenge, currFile); }, ), @@ -587,6 +589,7 @@ class ChallengeView extends StatelessWidget { onPressed: () { model.setShowConsole = !model.showConsole; model.setShowPreview = false; + model.setMounted = false; }, ), ]; From 14f54b5e262a80659f1904f6edb2fec00453c9fe Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Wed, 9 Jul 2025 07:03:45 +0530 Subject: [PATCH 05/10] fix: close webview and listener before going to next challenge --- .../lib/ui/views/learn/widgets/pass/pass_widget_view.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart index c918e0e13..387d1e5d7 100644 --- a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart +++ b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart @@ -198,6 +198,9 @@ class PassButton extends StatelessWidget { width: MediaQuery.of(context).size.width, child: TextButton( onPressed: () async { + model.closeWebViews(); + model.disposeOfListeners(); + model.learnService.goToNextChallenge( maxChallenges, completed, From a62bf05af25818a637683ca06befe566cdd72a69 Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Wed, 9 Jul 2025 07:25:54 +0530 Subject: [PATCH 06/10] fix: challenge completion percentage --- .../learn/widgets/pass/pass_widget_view.dart | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart index 387d1e5d7..55ad79088 100644 --- a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart +++ b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart @@ -161,11 +161,26 @@ class PassWidgetView extends StatelessWidget { return Center(child: Container()); }, ), - PassButton( - model: challengeModel, - maxChallenges: maxChallenges, - completed: challengesCompleted, - ), + FutureBuilder( + future: model.numCompletedChallenges( + challengeModel, + challengesCompleted, + ), + builder: (context, completedSnapshot) { + if (completedSnapshot.hasData) { + int completed = completedSnapshot.data as int; + return PassButton( + model: challengeModel, + maxChallenges: maxChallenges, + completed: completed - 1, + ); + } + + return const Center( + child: CircularProgressIndicator(), + ); + }, + ) ], ), ), From ca6ecf6c09d4c6954dccbabeb50637d02ce00977 Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Wed, 9 Jul 2025 07:37:56 +0530 Subject: [PATCH 07/10] chore: remove dead code --- .../ui/views/learn/challenge/challenge_view.dart | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart b/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart index fbf184bea..d3a9fbf00 100644 --- a/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart @@ -306,7 +306,6 @@ class ChallengeView extends StatelessWidget { ..._panelIconButtons( model, challenge, - challengesCompleted, block, ), Expanded( @@ -337,18 +336,7 @@ class ChallengeView extends StatelessWidget { size: 30, ), onPressed: model.hasTypedInEditor - ? () async { - if (model.showPanel && - model.panelType == PanelType.pass) { - model.learnService.goToNextChallenge( - model.block!.challenges.length, - challengesCompleted, - challenge, - block, - ); - } - model.runTests(); - } + ? model.runTests : null, splashColor: Colors.transparent, highlightColor: Colors.transparent, @@ -556,7 +544,6 @@ class ChallengeView extends StatelessWidget { List _panelIconButtons( ChallengeViewModel model, Challenge challenge, - int challengesCompleted, Block block, ) { return [ From d149bb7b89bda8d08a874672f14da216eff78886 Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Sat, 12 Jul 2025 12:02:38 +0530 Subject: [PATCH 08/10] chore: remove comment --- mobile-app/integration_test/test_runner/curriculum_tests.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/integration_test/test_runner/curriculum_tests.dart b/mobile-app/integration_test/test_runner/curriculum_tests.dart index 8d1ec4a61..8bab0e6b0 100644 --- a/mobile-app/integration_test/test_runner/curriculum_tests.dart +++ b/mobile-app/integration_test/test_runner/curriculum_tests.dart @@ -87,7 +87,7 @@ void main() { // JavaScript Chapter 'workshop-greeting-bot', - 'lab-javascript-trivia-bot', // TODO: Re-verify after Oliver supports before all for JS challenges + 'lab-javascript-trivia-bot', 'lab-sentence-maker', 'workshop-teacher-chatbot', 'workshop-mathbot', From 5c3eb52f80c969f553c54522c1e298aaa5ed899e Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Sat, 12 Jul 2025 12:55:27 +0530 Subject: [PATCH 09/10] fix: challenge completion progress bar length on login --- .../learn/widgets/pass/pass_widget_model.dart | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_model.dart b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_model.dart index 092584e92..71352f7d4 100644 --- a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_model.dart +++ b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_model.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import 'package:freecodecamp/app/app.locator.dart'; import 'package:freecodecamp/models/learn/challenge_model.dart'; import 'package:freecodecamp/models/learn/completed_challenge_model.dart'; +import 'package:freecodecamp/models/learn/curriculum_model.dart'; import 'package:freecodecamp/models/learn/motivational_quote_model.dart'; import 'package:freecodecamp/models/main/user_model.dart'; import 'package:freecodecamp/service/authentication/authentication_service.dart'; @@ -14,23 +15,29 @@ import 'package:stacked/stacked.dart'; class PassWidgetModel extends BaseViewModel { final AuthenticationService auth = locator(); - Future numCompletedChallenges( - ChallengeViewModel challengeModel, - int challengesCompleted, - ) async { + Future numCompletedChallenges(ChallengeViewModel challengeModel) async { FccUserModel? user = await auth.userModel; if (user != null) { - List completedChallenges = user.completedChallenges; Challenge? currChallenge = challengeModel.challenge; - if (currChallenge != null) { - if (completedChallenges - .indexWhere((element) => element.id == currChallenge.id) != - -1) { - return challengesCompleted; - } else { - return challengesCompleted + 1; + List completedChallenges = user.completedChallenges; + Set completedChallengeIds = + completedChallenges.map((completed) => completed.id).toSet(); + int completedCount = 0; + List blockChallenges = + challengeModel.block?.challenges ?? []; + + for (ChallengeOrder challenge in blockChallenges) { + if (completedChallengeIds.contains(challenge.id)) { + completedCount += 1; } } + + if (currChallenge != null && + !completedChallengeIds.contains(currChallenge.id)) { + completedCount += 1; + } + + return completedCount; } return 0; } From 436a46f507c2aec6dc3e3f0f963418c1b1a10756 Mon Sep 17 00:00:00 2001 From: Niraj Nandish Date: Sun, 13 Jul 2025 05:59:05 +0530 Subject: [PATCH 10/10] chore: remove unused challengesCompleted property --- mobile-app/lib/app/app.router.dart | 30 ++++--------------- .../lib/service/learn/learn_service.dart | 2 -- .../learn/block/block_template_viewmodel.dart | 1 - .../views/learn/challenge/challenge_view.dart | 10 ++----- .../learn/challenge/challenge_viewmodel.dart | 13 -------- .../templates/english/english_view.dart | 8 ++--- .../multiple_choice/multiple_choice_view.dart | 3 -- .../python-project/python_project_view.dart | 3 -- .../templates/python/python_view.dart | 3 -- .../challenge/templates/quiz/quiz_view.dart | 3 -- .../templates/review/review_view.dart | 10 +++---- .../challenge/templates/template_view.dart | 8 ----- .../learn/landing/landing_viewmodel.dart | 20 ------------- .../learn/widgets/pass/pass_widget_view.dart | 12 ++------ 14 files changed, 20 insertions(+), 106 deletions(-) diff --git a/mobile-app/lib/app/app.router.dart b/mobile-app/lib/app/app.router.dart index f8b4b1f5e..8b266f604 100644 --- a/mobile-app/lib/app/app.router.dart +++ b/mobile-app/lib/app/app.router.dart @@ -260,10 +260,7 @@ class StackedRouter extends _i1.RouterBase { final args = data.getArgs(nullOk: false); return _i20.MaterialPageRoute( builder: (context) => _i11.ChallengeTemplateView( - key: args.key, - block: args.block, - challengeId: args.challengeId, - challengesCompleted: args.challengesCompleted), + key: args.key, block: args.block, challengeId: args.challengeId), settings: data, ); }, @@ -547,7 +544,6 @@ class ChallengeTemplateViewArguments { this.key, required this.block, required this.challengeId, - required this.challengesCompleted, }); final _i20.Key? key; @@ -556,11 +552,9 @@ class ChallengeTemplateViewArguments { final String challengeId; - final int challengesCompleted; - @override String toString() { - return '{"key": "$key", "block": "$block", "challengeId": "$challengeId", "challengesCompleted": "$challengesCompleted"}'; + return '{"key": "$key", "block": "$block", "challengeId": "$challengeId"}'; } @override @@ -568,16 +562,12 @@ class ChallengeTemplateViewArguments { if (identical(this, other)) return true; return other.key == key && other.block == block && - other.challengeId == challengeId && - other.challengesCompleted == challengesCompleted; + other.challengeId == challengeId; } @override int get hashCode { - return key.hashCode ^ - block.hashCode ^ - challengeId.hashCode ^ - challengesCompleted.hashCode; + return key.hashCode ^ block.hashCode ^ challengeId.hashCode; } } @@ -849,7 +839,6 @@ extension NavigatorStateExtension on _i25.NavigationService { _i20.Key? key, required _i24.Block block, required String challengeId, - required int challengesCompleted, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -858,10 +847,7 @@ extension NavigatorStateExtension on _i25.NavigationService { }) async { return navigateTo(Routes.challengeTemplateView, arguments: ChallengeTemplateViewArguments( - key: key, - block: block, - challengeId: challengeId, - challengesCompleted: challengesCompleted), + key: key, block: block, challengeId: challengeId), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1166,7 +1152,6 @@ extension NavigatorStateExtension on _i25.NavigationService { _i20.Key? key, required _i24.Block block, required String challengeId, - required int challengesCompleted, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1175,10 +1160,7 @@ extension NavigatorStateExtension on _i25.NavigationService { }) async { return replaceWith(Routes.challengeTemplateView, arguments: ChallengeTemplateViewArguments( - key: key, - block: block, - challengeId: challengeId, - challengesCompleted: challengesCompleted), + key: key, block: block, challengeId: challengeId), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, diff --git a/mobile-app/lib/service/learn/learn_service.dart b/mobile-app/lib/service/learn/learn_service.dart index e036deb3e..a369685b8 100644 --- a/mobile-app/lib/service/learn/learn_service.dart +++ b/mobile-app/lib/service/learn/learn_service.dart @@ -140,7 +140,6 @@ class LearnService { void goToNextChallenge( int maxChallenges, - int challengesCompleted, Challenge challenge, Block block, { String solutionLink = '', @@ -159,7 +158,6 @@ class LearnService { arguments: ChallengeTemplateViewArguments( challengeId: block.challengeTiles[challengeIndex + 1].id, block: block, - challengesCompleted: challengesCompleted + 1, ), ); } diff --git a/mobile-app/lib/ui/views/learn/block/block_template_viewmodel.dart b/mobile-app/lib/ui/views/learn/block/block_template_viewmodel.dart index 4e8218846..f82d78fda 100644 --- a/mobile-app/lib/ui/views/learn/block/block_template_viewmodel.dart +++ b/mobile-app/lib/ui/views/learn/block/block_template_viewmodel.dart @@ -44,7 +44,6 @@ class BlockTemplateViewModel extends BaseViewModel { arguments: ChallengeTemplateViewArguments( challengeId: challengeId, block: block, - challengesCompleted: _challengesCompleted, ), ); } diff --git a/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart b/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart index d3a9fbf00..f47dfc79e 100644 --- a/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/challenge_view.dart @@ -21,13 +21,11 @@ class ChallengeView extends StatelessWidget { super.key, required this.block, required this.challenge, - required this.challengesCompleted, required this.isProject, }); final Challenge challenge; final Block block; - final int challengesCompleted; final bool isProject; @override @@ -35,7 +33,7 @@ class ChallengeView extends StatelessWidget { return ViewModelBuilder.reactive( viewModelBuilder: () => ChallengeViewModel(), onViewModelReady: (model) { - model.init(block, challenge, challengesCompleted); + model.init(block, challenge); }, onDispose: (model) { model.closeWebViews(); @@ -139,7 +137,6 @@ class ChallengeView extends StatelessWidget { challenge: challenge, model: model, maxChallenges: maxChallenges, - challengesCompleted: challengesCompleted, ), ), ); @@ -335,9 +332,8 @@ class ChallengeView extends StatelessWidget { Icons.done_rounded, size: 30, ), - onPressed: model.hasTypedInEditor - ? model.runTests - : null, + onPressed: + model.hasTypedInEditor ? model.runTests : null, splashColor: Colors.transparent, highlightColor: Colors.transparent, ), diff --git a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart index 24e48b8d9..324e0c2b2 100644 --- a/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart +++ b/mobile-app/lib/ui/views/learn/challenge/challenge_viewmodel.dart @@ -124,9 +124,6 @@ class ChallengeViewModel extends BaseViewModel { Block? _block; Block? get block => _block; - int _challengesCompleted = 0; - int get challengesCompleted => _challengesCompleted; - EditorOptions defaultEditorOptions = EditorOptions(); TextFieldData? _textFieldData; @@ -224,11 +221,6 @@ class ChallengeViewModel extends BaseViewModel { notifyListeners(); } - set setChallengesCompleted(int value) { - _challengesCompleted = value; - notifyListeners(); - } - set setMounted(bool value) { _mounted = value; notifyListeners(); @@ -289,7 +281,6 @@ class ChallengeViewModel extends BaseViewModel { void init( Block block, Challenge challenge, - int challengesCompleted, ) async { await _babelWebView.run(); await _localhostServer.start(); @@ -298,7 +289,6 @@ class ChallengeViewModel extends BaseViewModel { setChallenge = challenge; setBlock = block; - setChallengesCompleted = challengesCompleted; listenToSymbolBarScrollController(); } @@ -608,7 +598,6 @@ class ChallengeViewModel extends BaseViewModel { arguments: ChallengeTemplateViewArguments( block: block!, challengeId: currChallenge.id, - challengesCompleted: challengesCompleted, ), ); } @@ -703,7 +692,6 @@ class ChallengeViewModel extends BaseViewModel { required Challenge challenge, required ChallengeViewModel model, required int maxChallenges, - required int challengesCompleted, }) { switch (panelType) { case PanelType.instruction: @@ -723,7 +711,6 @@ class ChallengeViewModel extends BaseViewModel { case PanelType.pass: return PassWidgetView( challengeModel: model, - challengesCompleted: challengesCompleted, maxChallenges: maxChallenges, ); default: diff --git a/mobile-app/lib/ui/views/learn/challenge/templates/english/english_view.dart b/mobile-app/lib/ui/views/learn/challenge/templates/english/english_view.dart index e779a2498..69418b87b 100644 --- a/mobile-app/lib/ui/views/learn/challenge/templates/english/english_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/templates/english/english_view.dart @@ -118,10 +118,10 @@ class EnglishView extends StatelessWidget { ), onPressed: model.allInputsCorrect ? () => model.learnService.goToNextChallenge( - block.challenges.length, - currentChallengeNum, - challenge, - block) + block.challenges.length, + challenge, + block, + ) : () => {model.checkAnswers(challenge)}, child: Text( model.allInputsCorrect || diff --git a/mobile-app/lib/ui/views/learn/challenge/templates/multiple_choice/multiple_choice_view.dart b/mobile-app/lib/ui/views/learn/challenge/templates/multiple_choice/multiple_choice_view.dart index 13ae885bc..285d0ff01 100644 --- a/mobile-app/lib/ui/views/learn/challenge/templates/multiple_choice/multiple_choice_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/templates/multiple_choice/multiple_choice_view.dart @@ -19,14 +19,12 @@ class MultipleChoiceView extends StatelessWidget { super.key, required this.challenge, required this.block, - required this.challengesCompleted, required this.currentChallengeNum, }); final Challenge challenge; final Block block; final int currentChallengeNum; - final int challengesCompleted; Widget buildDivider() { return const Divider( @@ -168,7 +166,6 @@ class MultipleChoiceView extends StatelessWidget { model.hasPassedAllQuestions) { model.learnService.goToNextChallenge( block.challenges.length, - challengesCompleted, challenge, block, ); diff --git a/mobile-app/lib/ui/views/learn/challenge/templates/python-project/python_project_view.dart b/mobile-app/lib/ui/views/learn/challenge/templates/python-project/python_project_view.dart index ba7adb7bf..dd2f8f9e2 100644 --- a/mobile-app/lib/ui/views/learn/challenge/templates/python-project/python_project_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/templates/python-project/python_project_view.dart @@ -12,12 +12,10 @@ class PythonProjectView extends StatelessWidget { super.key, required this.challenge, required this.block, - required this.challengesCompleted, }); final Challenge challenge; final Block block; - final int challengesCompleted; @override Widget build(BuildContext context) { @@ -117,7 +115,6 @@ class PythonProjectView extends StatelessWidget { model.validLink != null && model.validLink! ? model.learnService.goToNextChallenge( block.challenges.length, - challengesCompleted, challenge, block, ) diff --git a/mobile-app/lib/ui/views/learn/challenge/templates/python/python_view.dart b/mobile-app/lib/ui/views/learn/challenge/templates/python/python_view.dart index bdb6c0df8..0a2f63839 100644 --- a/mobile-app/lib/ui/views/learn/challenge/templates/python/python_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/templates/python/python_view.dart @@ -17,14 +17,12 @@ class PythonView extends StatelessWidget { super.key, required this.challenge, required this.block, - required this.challengesCompleted, required this.currentChallengeNum, }); final Challenge challenge; final Block block; final int currentChallengeNum; - final int challengesCompleted; @override Widget build(BuildContext context) { @@ -135,7 +133,6 @@ class PythonView extends StatelessWidget { model.hasPassedAllQuestions) { model.learnService.goToNextChallenge( block.challenges.length, - challengesCompleted, challenge, block, ); diff --git a/mobile-app/lib/ui/views/learn/challenge/templates/quiz/quiz_view.dart b/mobile-app/lib/ui/views/learn/challenge/templates/quiz/quiz_view.dart index 896f9cfa6..1c087b117 100644 --- a/mobile-app/lib/ui/views/learn/challenge/templates/quiz/quiz_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/templates/quiz/quiz_view.dart @@ -15,12 +15,10 @@ class QuizView extends StatelessWidget { super.key, required this.challenge, required this.block, - required this.challengesCompleted, }); final Challenge challenge; final Block block; - final int challengesCompleted; @override Widget build(BuildContext context) { @@ -164,7 +162,6 @@ class QuizView extends StatelessWidget { model.hasPassedAllQuestions) { model.learnService.goToNextChallenge( block.challenges.length, - challengesCompleted, challenge, block, ); diff --git a/mobile-app/lib/ui/views/learn/challenge/templates/review/review_view.dart b/mobile-app/lib/ui/views/learn/challenge/templates/review/review_view.dart index c2cb62022..5339e15fd 100644 --- a/mobile-app/lib/ui/views/learn/challenge/templates/review/review_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/templates/review/review_view.dart @@ -16,12 +16,10 @@ class ReviewView extends StatelessWidget { super.key, required this.challenge, required this.block, - required this.challengesCompleted, }); final Challenge challenge; final Block block; - final int challengesCompleted; @override Widget build(BuildContext context) { @@ -104,10 +102,10 @@ class ReviewView extends StatelessWidget { onPressed: model.assignmentsStatus .every((element) => element) ? () => model.learnService.goToNextChallenge( - block.challenges.length, - challengesCompleted, - challenge, - block) + block.challenges.length, + challenge, + block, + ) : null, child: Text( context.t.next, diff --git a/mobile-app/lib/ui/views/learn/challenge/templates/template_view.dart b/mobile-app/lib/ui/views/learn/challenge/templates/template_view.dart index b39fc1ea0..212e9c902 100644 --- a/mobile-app/lib/ui/views/learn/challenge/templates/template_view.dart +++ b/mobile-app/lib/ui/views/learn/challenge/templates/template_view.dart @@ -16,12 +16,10 @@ class ChallengeTemplateView extends StatelessWidget { super.key, required this.block, required this.challengeId, - required this.challengesCompleted, }); final Block block; final String challengeId; - final int challengesCompleted; @override Widget build(BuildContext context) { @@ -50,26 +48,22 @@ class ChallengeTemplateView extends StatelessWidget { return ChallengeView( challenge: challenge, block: block, - challengesCompleted: challengesCompleted, isProject: tiles.length > 1, ); case 8: return QuizView( challenge: challenge, block: block, - challengesCompleted: challengesCompleted, ); case 10: return PythonProjectView( challenge: challenge, block: block, - challengesCompleted: challengesCompleted, ); case 11: return PythonView( challenge: challenge, block: block, - challengesCompleted: challengesCompleted, currentChallengeNum: challNum, ); case 15: @@ -77,7 +71,6 @@ class ChallengeTemplateView extends StatelessWidget { return MultipleChoiceView( challenge: challenge, block: block, - challengesCompleted: challengesCompleted, currentChallengeNum: challNum, ); case 21: @@ -91,7 +84,6 @@ class ChallengeTemplateView extends StatelessWidget { return ReviewView( challenge: challenge, block: block, - challengesCompleted: challengesCompleted, ); default: return Center( diff --git a/mobile-app/lib/ui/views/learn/landing/landing_viewmodel.dart b/mobile-app/lib/ui/views/learn/landing/landing_viewmodel.dart index 14f870500..f21774892 100644 --- a/mobile-app/lib/ui/views/learn/landing/landing_viewmodel.dart +++ b/mobile-app/lib/ui/views/learn/landing/landing_viewmodel.dart @@ -11,7 +11,6 @@ import 'package:freecodecamp/app/app.router.dart'; import 'package:freecodecamp/models/learn/challenge_model.dart'; import 'package:freecodecamp/models/learn/curriculum_model.dart'; import 'package:freecodecamp/models/learn/motivational_quote_model.dart'; -import 'package:freecodecamp/models/main/user_model.dart'; import 'package:freecodecamp/service/authentication/authentication_service.dart'; import 'package:freecodecamp/service/dio_service.dart'; import 'package:freecodecamp/service/learn/learn_offline_service.dart'; @@ -59,10 +58,6 @@ class LearnLandingViewModel extends BaseViewModel { } void fastRouteToChallenge() async { - FccUserModel? user; - - int completedChallenges = 0; - SharedPreferences prefs = await SharedPreferences.getInstance(); List? lastVisitedChallenge = prefs.getStringList( 'lastVisitedChallenge', @@ -91,24 +86,10 @@ class LearnLandingViewModel extends BaseViewModel { lastVisitedChallenge[2], ).blocks as List; - if (AuthenticationService.staticIsloggedIn) { - user = await auth.userModel; - } - Block block = blocks.firstWhere( (element) => element.dashedName == lastVisitedChallenge[3], ); - Iterable completedChallengeIds = user!.completedChallenges.map( - (e) => e.id, - ); - - for (int i = 0; i < block.challenges.length; i++) { - if (completedChallengeIds.contains(block.challenges[i].id)) { - completedChallenges++; - } - } - _navigationService.navigateToSuperBlockView( superBlockDashedName: lastVisitedChallenge[1], superBlockName: lastVisitedChallenge[2], @@ -117,7 +98,6 @@ class LearnLandingViewModel extends BaseViewModel { _navigationService.navigateToChallengeTemplateView( block: block, - challengesCompleted: completedChallenges, challengeId: challenge.id, ); } diff --git a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart index 55ad79088..aa2a026ea 100644 --- a/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart +++ b/mobile-app/lib/ui/views/learn/widgets/pass/pass_widget_view.dart @@ -12,12 +12,10 @@ class PassWidgetView extends StatelessWidget { const PassWidgetView({ super.key, required this.challengeModel, - required this.challengesCompleted, required this.maxChallenges, }); final ChallengeViewModel challengeModel; - final int challengesCompleted; final int maxChallenges; @override @@ -79,7 +77,6 @@ class PassWidgetView extends StatelessWidget { return FutureBuilder( future: model.numCompletedChallenges( challengeModel, - challengesCompleted, ), builder: (context, completedSnapshot) { if (completedSnapshot.hasData) { @@ -104,8 +101,9 @@ class PassWidgetView extends StatelessWidget { Expanded( child: Text( context.t.completed_percent( - ((completed * 100) ~/ + ((completed * 100) / maxChallenges) + .round() .toString(), ), textAlign: TextAlign.right, @@ -162,10 +160,7 @@ class PassWidgetView extends StatelessWidget { }, ), FutureBuilder( - future: model.numCompletedChallenges( - challengeModel, - challengesCompleted, - ), + future: model.numCompletedChallenges(challengeModel), builder: (context, completedSnapshot) { if (completedSnapshot.hasData) { int completed = completedSnapshot.data as int; @@ -218,7 +213,6 @@ class PassButton extends StatelessWidget { model.learnService.goToNextChallenge( maxChallenges, - completed, model.challenge as Challenge, model.block as Block, );