diff --git a/mobile-app/lib/app/app.dart b/mobile-app/lib/app/app.dart index 57202a953..d6abe0dda 100644 --- a/mobile-app/lib/app/app.dart +++ b/mobile-app/lib/app/app.dart @@ -21,8 +21,7 @@ import 'package:freecodecamp/ui/views/podcast/episode-view/episode_view.dart'; import 'package:freecodecamp/ui/views/news/news-article/news_article_view.dart'; import 'package:freecodecamp/ui/views/news/news-bookmark/news_bookmark_view.dart'; import 'package:freecodecamp/ui/views/news/news-feed/news_feed_view.dart'; -import 'package:freecodecamp/ui/views/settings/forumSettings/forum_settings_view.dart'; -import 'package:freecodecamp/ui/views/settings/podcastSettings/podcast_settings_view.dart'; +import 'package:freecodecamp/ui/views/learn/settings/settings_view.dart'; import 'package:freecodecamp/ui/views/learn/learn-builders/superblock_builder.dart'; import 'package:freecodecamp/ui/views/learn/challenge_editor/challenge_view.dart'; import 'package:freecodecamp/ui/views/web_view/web_view_view.dart'; @@ -38,7 +37,6 @@ import 'package:sqflite_migration_service/sqflite_migration_service.dart'; routes: [ MaterialRoute(page: HomeView, initial: true), MaterialRoute(page: PodcastListView), - MaterialRoute(page: PodcastSettingsView), MaterialRoute(page: EpisodeView), MaterialRoute(page: NewsArticleView), MaterialRoute(page: NewsBookmarkPostView), @@ -50,13 +48,13 @@ import 'package:sqflite_migration_service/sqflite_migration_service.dart'; MaterialRoute(page: ForumPostView), MaterialRoute(page: ForumLoginView), MaterialRoute(page: ForumUserView), - MaterialRoute(page: ForumSettingsView), MaterialRoute(page: ForumUserProfileView), MaterialRoute(page: CodeRadioView), MaterialRoute(page: SuperBlockView), MaterialRoute(page: ChallengeView), MaterialRoute(page: ProfileView), - MaterialRoute(page: WebViewView) + MaterialRoute(page: WebViewView), + MaterialRoute(page: SettingsView) ], dependencies: [ LazySingleton(classType: NavigationService), diff --git a/mobile-app/lib/app/app.router.dart b/mobile-app/lib/app/app.router.dart index 2d6eea20a..a8de93e1d 100644 --- a/mobile-app/lib/app/app.router.dart +++ b/mobile-app/lib/app/app.router.dart @@ -5,60 +5,56 @@ // ************************************************************************** // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:flutter/material.dart' as _i23; +import 'package:flutter/material.dart' as _i22; import 'package:flutter/material.dart'; -import 'package:freecodecamp/models/learn/curriculum_model.dart' as _i27; -import 'package:freecodecamp/models/news/bookmarked_article_model.dart' as _i26; -import 'package:freecodecamp/models/podcasts/episodes_model.dart' as _i24; -import 'package:freecodecamp/models/podcasts/podcasts_model.dart' as _i25; -import 'package:freecodecamp/ui/views/code_radio/code_radio_view.dart' as _i18; +import 'package:freecodecamp/models/learn/curriculum_model.dart' as _i26; +import 'package:freecodecamp/models/news/bookmarked_article_model.dart' as _i25; +import 'package:freecodecamp/models/podcasts/episodes_model.dart' as _i23; +import 'package:freecodecamp/models/podcasts/podcasts_model.dart' as _i24; +import 'package:freecodecamp/ui/views/code_radio/code_radio_view.dart' as _i16; import 'package:freecodecamp/ui/views/forum/forum-categories/forum_category_view.dart' - as _i11; + as _i10; import 'package:freecodecamp/ui/views/forum/forum-login/forum_login_view.dart' - as _i14; + as _i13; import 'package:freecodecamp/ui/views/forum/forum-post-feed/forum_post_feed_view.dart' - as _i12; + as _i11; import 'package:freecodecamp/ui/views/forum/forum-post/forum_post_view.dart' - as _i13; + as _i12; import 'package:freecodecamp/ui/views/forum/forum-user-profile/forum_user_profile_view.dart' - as _i17; -import 'package:freecodecamp/ui/views/forum/forum-user/forum_user_view.dart' as _i15; +import 'package:freecodecamp/ui/views/forum/forum-user/forum_user_view.dart' + as _i14; import 'package:freecodecamp/ui/views/home/home_view.dart' as _i2; import 'package:freecodecamp/ui/views/learn/challenge_editor/challenge_view.dart' - as _i20; + as _i18; import 'package:freecodecamp/ui/views/learn/learn-builders/superblock_builder.dart' - as _i19; + as _i17; +import 'package:freecodecamp/ui/views/learn/settings/settings_view.dart' + as _i21; import 'package:freecodecamp/ui/views/news/news-article/news_article_view.dart' - as _i6; + as _i5; import 'package:freecodecamp/ui/views/news/news-author/news_author_view.dart' - as _i9; + as _i8; import 'package:freecodecamp/ui/views/news/news-bookmark/news_bookmark_view.dart' - as _i7; + as _i6; import 'package:freecodecamp/ui/views/news/news-feed/news_feed_view.dart' - as _i8; + as _i7; import 'package:freecodecamp/ui/views/news/news-image-viewer/news_image_viewer.dart' - as _i10; + as _i9; import 'package:freecodecamp/ui/views/podcast/episode-view/episode_view.dart' - as _i5; + as _i4; import 'package:freecodecamp/ui/views/podcast/podcast-list/podcast_list_view.dart' as _i3; -import 'package:freecodecamp/ui/views/profile/profile_view.dart' as _i21; -import 'package:freecodecamp/ui/views/settings/forumSettings/forum_settings_view.dart' - as _i16; -import 'package:freecodecamp/ui/views/settings/podcastSettings/podcast_settings_view.dart' - as _i4; -import 'package:freecodecamp/ui/views/web_view/web_view_view.dart' as _i22; +import 'package:freecodecamp/ui/views/profile/profile_view.dart' as _i19; +import 'package:freecodecamp/ui/views/web_view/web_view_view.dart' as _i20; import 'package:stacked/stacked.dart' as _i1; -import 'package:stacked_services/stacked_services.dart' as _i28; +import 'package:stacked_services/stacked_services.dart' as _i27; class Routes { static const homeView = '/'; static const podcastListView = '/podcast-list-view'; - static const podcastSettingsView = '/podcast-settings-view'; - static const episodeView = '/episode-view'; static const newsArticleView = '/news-article-view'; @@ -81,8 +77,6 @@ class Routes { static const forumUserView = '/forum-user-view'; - static const forumSettingsView = '/forum-settings-view'; - static const forumUserProfileView = '/forum-user-profile-view'; static const codeRadioView = '/code-radio-view'; @@ -95,10 +89,11 @@ class Routes { static const webViewView = '/web-view-view'; + static const settingsView = '/settings-view'; + static const all = { homeView, podcastListView, - podcastSettingsView, episodeView, newsArticleView, newsBookmarkPostView, @@ -110,13 +105,13 @@ class Routes { forumPostView, forumLoginView, forumUserView, - forumSettingsView, forumUserProfileView, codeRadioView, superBlockView, challengeView, profileView, webViewView, + settingsView, }; } @@ -130,81 +125,77 @@ class StackedRouter extends _i1.RouterBase { Routes.podcastListView, page: _i3.PodcastListView, ), - _i1.RouteDef( - Routes.podcastSettingsView, - page: _i4.PodcastSettingsView, - ), _i1.RouteDef( Routes.episodeView, - page: _i5.EpisodeView, + page: _i4.EpisodeView, ), _i1.RouteDef( Routes.newsArticleView, - page: _i6.NewsArticleView, + page: _i5.NewsArticleView, ), _i1.RouteDef( Routes.newsBookmarkPostView, - page: _i7.NewsBookmarkPostView, + page: _i6.NewsBookmarkPostView, ), _i1.RouteDef( Routes.newsFeedView, - page: _i8.NewsFeedView, + page: _i7.NewsFeedView, ), _i1.RouteDef( Routes.newsAuthorView, - page: _i9.NewsAuthorView, + page: _i8.NewsAuthorView, ), _i1.RouteDef( Routes.newsImageView, - page: _i10.NewsImageView, + page: _i9.NewsImageView, ), _i1.RouteDef( Routes.forumCategoryView, - page: _i11.ForumCategoryView, + page: _i10.ForumCategoryView, ), _i1.RouteDef( Routes.forumPostFeedView, - page: _i12.ForumPostFeedView, + page: _i11.ForumPostFeedView, ), _i1.RouteDef( Routes.forumPostView, - page: _i13.ForumPostView, + page: _i12.ForumPostView, ), _i1.RouteDef( Routes.forumLoginView, - page: _i14.ForumLoginView, + page: _i13.ForumLoginView, ), _i1.RouteDef( Routes.forumUserView, - page: _i15.ForumUserView, - ), - _i1.RouteDef( - Routes.forumSettingsView, - page: _i16.ForumSettingsView, + page: _i14.ForumUserView, ), _i1.RouteDef( Routes.forumUserProfileView, - page: _i17.ForumUserProfileView, + page: _i15.ForumUserProfileView, ), _i1.RouteDef( Routes.codeRadioView, - page: _i18.CodeRadioView, + page: _i16.CodeRadioView, ), _i1.RouteDef( Routes.superBlockView, - page: _i19.SuperBlockView, + page: _i17.SuperBlockView, ), _i1.RouteDef( Routes.challengeView, - page: _i20.ChallengeView, + page: _i18.ChallengeView, ), _i1.RouteDef( Routes.profileView, - page: _i21.ProfileView, + page: _i19.ProfileView, ), _i1.RouteDef( Routes.webViewView, - page: _i22.WebViewView, + page: _i20.WebViewView, + ), + _i1.RouteDef( + Routes.settingsView, + page: _i21.SettingsView, ), ]; @@ -221,42 +212,36 @@ class StackedRouter extends _i1.RouterBase { settings: data, ); }, - _i4.PodcastSettingsView: (data) { - return MaterialPageRoute( - builder: (context) => const _i4.PodcastSettingsView(), - settings: data, - ); - }, - _i5.EpisodeView: (data) { + _i4.EpisodeView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( - builder: (context) => _i5.EpisodeView( + builder: (context) => _i4.EpisodeView( key: args.key, episode: args.episode, podcast: args.podcast), settings: data, ); }, - _i6.NewsArticleView: (data) { + _i5.NewsArticleView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( builder: (context) => - _i6.NewsArticleView(key: args.key, refId: args.refId), + _i5.NewsArticleView(key: args.key, refId: args.refId), settings: data, ); }, - _i7.NewsBookmarkPostView: (data) { + _i6.NewsBookmarkPostView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( builder: (context) => - _i7.NewsBookmarkPostView(key: args.key, article: args.article), + _i6.NewsBookmarkPostView(key: args.key, article: args.article), settings: data, ); }, - _i8.NewsFeedView: (data) { + _i7.NewsFeedView: (data) { final args = data.getArgs( orElse: () => const NewsFeedViewArguments(), ); return MaterialPageRoute( - builder: (context) => _i8.NewsFeedView( + builder: (context) => _i7.NewsFeedView( key: args.key, slug: args.slug, author: args.author, @@ -266,97 +251,91 @@ class StackedRouter extends _i1.RouterBase { settings: data, ); }, - _i9.NewsAuthorView: (data) { + _i8.NewsAuthorView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( builder: (context) => - _i9.NewsAuthorView(key: args.key, authorSlug: args.authorSlug), + _i8.NewsAuthorView(key: args.key, authorSlug: args.authorSlug), settings: data, ); }, - _i10.NewsImageView: (data) { + _i9.NewsImageView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( builder: (context) => - _i10.NewsImageView(key: args.key, imgUrl: args.imgUrl), + _i9.NewsImageView(key: args.key, imgUrl: args.imgUrl), settings: data, ); }, - _i11.ForumCategoryView: (data) { + _i10.ForumCategoryView: (data) { final args = data.getArgs( orElse: () => const ForumCategoryViewArguments(), ); return MaterialPageRoute( - builder: (context) => _i11.ForumCategoryView(key: args.key), + builder: (context) => _i10.ForumCategoryView(key: args.key), settings: data, ); }, - _i12.ForumPostFeedView: (data) { + _i11.ForumPostFeedView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( - builder: (context) => _i12.ForumPostFeedView( + builder: (context) => _i11.ForumPostFeedView( key: args.key, slug: args.slug, id: args.id, name: args.name), settings: data, ); }, - _i13.ForumPostView: (data) { + _i12.ForumPostView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( builder: (context) => - _i13.ForumPostView(key: args.key, id: args.id, slug: args.slug), + _i12.ForumPostView(key: args.key, id: args.id, slug: args.slug), settings: data, ); }, - _i14.ForumLoginView: (data) { + _i13.ForumLoginView: (data) { final args = data.getArgs( orElse: () => const ForumLoginViewArguments(), ); return MaterialPageRoute( - builder: (context) => _i14.ForumLoginView( + builder: (context) => _i13.ForumLoginView( key: args.key, fromCreatePost: args.fromCreatePost), settings: data, ); }, - _i15.ForumUserView: (data) { + _i14.ForumUserView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( builder: (context) => - _i15.ForumUserView(key: args.key, username: args.username), + _i14.ForumUserView(key: args.key, username: args.username), settings: data, ); }, - _i16.ForumSettingsView: (data) { + _i15.ForumUserProfileView: (data) { return MaterialPageRoute( - builder: (context) => const _i16.ForumSettingsView(), + builder: (context) => const _i15.ForumUserProfileView(), settings: data, ); }, - _i17.ForumUserProfileView: (data) { + _i16.CodeRadioView: (data) { return MaterialPageRoute( - builder: (context) => const _i17.ForumUserProfileView(), + builder: (context) => const _i16.CodeRadioView(), settings: data, ); }, - _i18.CodeRadioView: (data) { - return MaterialPageRoute( - builder: (context) => const _i18.CodeRadioView(), - settings: data, - ); - }, - _i19.SuperBlockView: (data) { + _i17.SuperBlockView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( - builder: (context) => _i19.SuperBlockView( + builder: (context) => _i17.SuperBlockView( key: args.key, superBlockDashedName: args.superBlockDashedName, superblockName: args.superblockName), settings: data, ); }, - _i20.ChallengeView: (data) { + _i18.ChallengeView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( - builder: (context) => _i20.ChallengeView( + builder: (context) => _i18.ChallengeView( key: args.key, url: args.url, block: args.block, @@ -364,16 +343,22 @@ class StackedRouter extends _i1.RouterBase { settings: data, ); }, - _i21.ProfileView: (data) { + _i19.ProfileView: (data) { return MaterialPageRoute( - builder: (context) => const _i21.ProfileView(), + builder: (context) => const _i19.ProfileView(), settings: data, ); }, - _i22.WebViewView: (data) { + _i20.WebViewView: (data) { final args = data.getArgs(nullOk: false); return MaterialPageRoute( - builder: (context) => _i22.WebViewView(key: args.key, url: args.url), + builder: (context) => _i20.WebViewView(key: args.key, url: args.url), + settings: data, + ); + }, + _i21.SettingsView: (data) { + return MaterialPageRoute( + builder: (context) => const _i21.SettingsView(), settings: data, ); }, @@ -392,11 +377,11 @@ class EpisodeViewArguments { required this.podcast, }); - final _i23.Key? key; + final _i22.Key? key; - final _i24.Episodes episode; + final _i23.Episodes episode; - final _i25.Podcasts podcast; + final _i24.Podcasts podcast; } class NewsArticleViewArguments { @@ -405,7 +390,7 @@ class NewsArticleViewArguments { required this.refId, }); - final _i23.Key? key; + final _i22.Key? key; final String refId; } @@ -416,9 +401,9 @@ class NewsBookmarkPostViewArguments { required this.article, }); - final _i23.Key? key; + final _i22.Key? key; - final _i26.BookmarkedArticle article; + final _i25.BookmarkedArticle article; } class NewsFeedViewArguments { @@ -431,7 +416,7 @@ class NewsFeedViewArguments { this.subject = '', }); - final _i23.Key? key; + final _i22.Key? key; final String slug; @@ -450,7 +435,7 @@ class NewsAuthorViewArguments { required this.authorSlug, }); - final _i23.Key? key; + final _i22.Key? key; final String authorSlug; } @@ -461,7 +446,7 @@ class NewsImageViewArguments { required this.imgUrl, }); - final _i23.Key? key; + final _i22.Key? key; final String imgUrl; } @@ -469,7 +454,7 @@ class NewsImageViewArguments { class ForumCategoryViewArguments { const ForumCategoryViewArguments({this.key}); - final _i23.Key? key; + final _i22.Key? key; } class ForumPostFeedViewArguments { @@ -480,7 +465,7 @@ class ForumPostFeedViewArguments { required this.name, }); - final _i23.Key? key; + final _i22.Key? key; final String slug; @@ -496,7 +481,7 @@ class ForumPostViewArguments { required this.slug, }); - final _i23.Key? key; + final _i22.Key? key; final String id; @@ -509,7 +494,7 @@ class ForumLoginViewArguments { this.fromCreatePost = false, }); - final _i23.Key? key; + final _i22.Key? key; final bool fromCreatePost; } @@ -520,7 +505,7 @@ class ForumUserViewArguments { required this.username, }); - final _i23.Key? key; + final _i22.Key? key; final String username; } @@ -532,7 +517,7 @@ class SuperBlockViewArguments { required this.superblockName, }); - final _i23.Key? key; + final _i22.Key? key; final String superBlockDashedName; @@ -547,11 +532,11 @@ class ChallengeViewArguments { required this.challengesCompleted, }); - final _i23.Key? key; + final _i22.Key? key; final String url; - final _i27.Block block; + final _i26.Block block; final int challengesCompleted; } @@ -562,12 +547,12 @@ class WebViewViewArguments { required this.url, }); - final _i23.Key? key; + final _i22.Key? key; final String url; } -extension NavigatorStateExtension on _i28.NavigationService { +extension NavigatorStateExtension on _i27.NavigationService { Future navigateToHomeView([ int? routerId, bool preventDuplicates = true, @@ -596,24 +581,10 @@ extension NavigatorStateExtension on _i28.NavigationService { transition: transition); } - Future navigateToPodcastSettingsView([ - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - ]) async { - return navigateTo(Routes.podcastSettingsView, - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - Future navigateToEpisodeView({ - _i23.Key? key, - required _i24.Episodes episode, - required _i25.Podcasts podcast, + _i22.Key? key, + required _i23.Episodes episode, + required _i24.Podcasts podcast, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -630,7 +601,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToNewsArticleView({ - _i23.Key? key, + _i22.Key? key, required String refId, int? routerId, bool preventDuplicates = true, @@ -647,8 +618,8 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToNewsBookmarkPostView({ - _i23.Key? key, - required _i26.BookmarkedArticle article, + _i22.Key? key, + required _i25.BookmarkedArticle article, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -664,7 +635,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToNewsFeedView({ - _i23.Key? key, + _i22.Key? key, String slug = '', String author = '', bool fromAuthor = false, @@ -691,7 +662,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToNewsAuthorView({ - _i23.Key? key, + _i22.Key? key, required String authorSlug, int? routerId, bool preventDuplicates = true, @@ -708,7 +679,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToNewsImageView({ - _i23.Key? key, + _i22.Key? key, required String imgUrl, int? routerId, bool preventDuplicates = true, @@ -725,7 +696,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToForumCategoryView({ - _i23.Key? key, + _i22.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -741,7 +712,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToForumPostFeedView({ - _i23.Key? key, + _i22.Key? key, required String slug, required String id, required String name, @@ -761,7 +732,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToForumPostView({ - _i23.Key? key, + _i22.Key? key, required String id, required String slug, int? routerId, @@ -779,7 +750,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToForumLoginView({ - _i23.Key? key, + _i22.Key? key, bool fromCreatePost = false, int? routerId, bool preventDuplicates = true, @@ -797,7 +768,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToForumUserView({ - _i23.Key? key, + _i22.Key? key, required String username, int? routerId, bool preventDuplicates = true, @@ -813,20 +784,6 @@ extension NavigatorStateExtension on _i28.NavigationService { transition: transition); } - Future navigateToForumSettingsView([ - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - ]) async { - return navigateTo(Routes.forumSettingsView, - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - Future navigateToForumUserProfileView([ int? routerId, bool preventDuplicates = true, @@ -856,7 +813,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToSuperBlockView({ - _i23.Key? key, + _i22.Key? key, required String superBlockDashedName, required String superblockName, int? routerId, @@ -877,9 +834,9 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToChallengeView({ - _i23.Key? key, + _i22.Key? key, required String url, - required _i27.Block block, + required _i26.Block block, required int challengesCompleted, int? routerId, bool preventDuplicates = true, @@ -914,7 +871,7 @@ extension NavigatorStateExtension on _i28.NavigationService { } Future navigateToWebViewView({ - _i23.Key? key, + _i22.Key? key, required String url, int? routerId, bool preventDuplicates = true, @@ -929,4 +886,18 @@ extension NavigatorStateExtension on _i28.NavigationService { parameters: parameters, transition: transition); } + + Future navigateToSettingsView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return navigateTo(Routes.settingsView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } } diff --git a/mobile-app/lib/models/main/profile_ui_model.dart b/mobile-app/lib/models/main/profile_ui_model.dart index 1c6fe42ce..f205022ad 100644 --- a/mobile-app/lib/models/main/profile_ui_model.dart +++ b/mobile-app/lib/models/main/profile_ui_model.dart @@ -35,4 +35,19 @@ class ProfileUI { showPortfolio: data['showPortfolio'], showTimeLine: data['showTimeLine']); } + + static Map toMap(ProfileUI data) { + return { + 'isLocked': data.isLocked, + 'showAbout': data.showAbout, + 'showCerts': data.showCerts, + 'showDonation': data.showDonation, + 'showHeatMap': data.showHeatMap, + 'showLocation': data.showLocation, + 'showName': data.showName, + 'showPoints': data.showPoints, + 'showPortfolio': data.showPortfolio, + 'showTimeLine': data.showTimeLine, + }; + } } diff --git a/mobile-app/lib/service/authentication_service.dart b/mobile-app/lib/service/authentication_service.dart index e00469af5..88ed7106c 100644 --- a/mobile-app/lib/service/authentication_service.dart +++ b/mobile-app/lib/service/authentication_service.dart @@ -149,6 +149,8 @@ class AuthenticationService { } Future fetchUser() async { + log('fetching user'); + Response res = await _dio.get( '/user/get-session-user', options: Options( diff --git a/mobile-app/lib/service/learn_service.dart b/mobile-app/lib/service/learn_service.dart index 046ac0942..388342f73 100644 --- a/mobile-app/lib/service/learn_service.dart +++ b/mobile-app/lib/service/learn_service.dart @@ -10,8 +10,6 @@ import 'package:pretty_dio_logger/pretty_dio_logger.dart'; class LearnService { static final LearnService _learnService = LearnService._internal(); final _authenticationService = locator(); - - // TODO: make a Dio service instead of initialising it everywhere final Dio _dio = Dio(); factory LearnService() { @@ -23,6 +21,89 @@ class LearnService { _dio.interceptors.add(CurlLoggerDioInterceptor()); } + Future updateMyAbout(Map data) async { + Response res = await _dio.put( + '${AuthenticationService.baseApiURL}/update-my-about', + data: data, + options: Options( + headers: { + 'CSRF-Token': _authenticationService.csrfToken, + 'Cookie': + 'jwt_access_token=${_authenticationService.jwtAccessToken}; _csrf=${_authenticationService.csrf};', + }, + ), + ); + + if (res.statusCode == 200) { + return true; + } + + return false; + } + + Future updateMyProfileUI(Map data) async { + Response res = await _dio.put( + '${AuthenticationService.baseApiURL}/update-my-profileui', + data: data, + options: Options( + headers: { + 'CSRF-Token': _authenticationService.csrfToken, + 'Cookie': + 'jwt_access_token=${_authenticationService.jwtAccessToken}; _csrf=${_authenticationService.csrf};', + }, + ), + ); + + if (res.statusCode == 200) { + return true; + } + + return false; + } + + Future updateUsername(String name) async { + Response res = await _dio.put( + '${AuthenticationService.baseApiURL}/update-my-username', + data: {'username': name}, + options: Options( + headers: { + 'CSRF-Token': _authenticationService.csrfToken, + 'Cookie': + 'jwt_access_token=${_authenticationService.jwtAccessToken}; _csrf=${_authenticationService.csrf};', + }, + ), + ); + + if (res.statusCode == 200) { + if (res.data['type'] == 'info') { + return false; + } + + return true; + } else { + return false; + } + } + + Future checkIfUsernameIsTaken(String name) async { + Response res = await _dio.get( + '${AuthenticationService.baseApiURL}/api/users/exists?username=$name', + options: Options( + headers: { + 'CSRF-Token': _authenticationService.csrfToken, + 'Cookie': + 'jwt_access_token=${_authenticationService.jwtAccessToken}; _csrf=${_authenticationService.csrf};', + }, + ), + ); + + if (res.statusCode == 200) { + return res.data['exists']; + } + + return true; + } + Future postChallengeCompleted( Challenge challenge, List challengeFiles) async { // NOTE: Assuming for now it's just HTML and JS challenges are being submitted diff --git a/mobile-app/lib/ui/views/learn/settings/settings_model.dart b/mobile-app/lib/ui/views/learn/settings/settings_model.dart new file mode 100644 index 000000000..1e74a90b5 --- /dev/null +++ b/mobile-app/lib/ui/views/learn/settings/settings_model.dart @@ -0,0 +1,216 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:freecodecamp/app/app.locator.dart'; +import 'package:freecodecamp/models/main/profile_ui_model.dart'; +import 'package:freecodecamp/models/main/user_model.dart'; +import 'package:freecodecamp/service/authentication_service.dart'; +import 'package:freecodecamp/service/learn_service.dart'; +import 'package:stacked/stacked.dart'; +import 'package:stacked_services/stacked_services.dart'; + +class SettingsModel extends BaseViewModel { + late Map? profile; + + final AuthenticationService auth = locator(); + final LearnService _learnService = locator(); + final SnackbarService _snackbarService = locator(); + + Future? userFuture; + + String? username; + + Timer? requestCooldonwTimer; + + String? helperText; + String? errorText; + + Map? userInfo; + + set setProfile(Map ui) { + profile = ui; + notifyListeners(); + } + + set setUserInfo(Map data) { + userInfo = data; + notifyListeners(); + } + + set setUserFuture(Future userLoaded) { + userFuture = userLoaded; + notifyListeners(); + } + + set setUsername(String name) { + username = name; + notifyListeners(); + } + + set setHelperText(String? text) { + helperText = text; + notifyListeners(); + } + + set setErrorText(String? text) { + errorText = text; + notifyListeners(); + } + + void init() async { + await auth.init(); + + setUserFuture = auth.userModel!; + + FccUserModel? user = await userFuture!; + + setProfile = ProfileUI.toMap(user.profileUI); + + setUserInfo = { + 'name': user.name, + 'location': user.location, + 'picture': user.picture, + 'about': user.about, + }; + } + + String? getDescriptions(String flag) { + switch (flag) { + case 'isLocked': + return '''Your certifications will be disabled, if set to private.'''; + case 'showName': + return '''Your name will not appear on your certifications, if this is set to private.'''; + case 'showCerts': + return '''Your certifications will be disabled, if set to private.'''; + } + + return null; + } + + void setNewValue(String flag, bool value) { + List profileKeys = profile!.keys.toList(); + + Map scopedProfile = profile!; + + if (profileKeys.contains(flag)) { + flag != 'isLocked' + ? scopedProfile[flag] = value + : scopedProfile[flag] = !value; + + setProfile = scopedProfile; + } + } + + save() async { + bool updated = + await _learnService.updateMyProfileUI({'profileUI': profile!}); + + if (updated) { + _snackbarService.showSnackbar( + title: 'updated settings successfully', message: ''); + auth.init(); + } else { + _snackbarService.showSnackbar(title: 'something went wrong', message: ''); + } + } + + void updateUsername(String username) async { + if (await _learnService.updateUsername(username)) { + _snackbarService.showSnackbar( + title: 'username updated successfully', message: ''); + init(); + auth.init(); + } else { + _snackbarService.showSnackbar(title: 'something went wrong', message: ''); + } + } + + Future validateUsername(String username, String currName) async { + log(username); + RegExp validChars = + RegExp(r'^[a-zA-Z0-9\-_+]*$', multiLine: true, unicode: true); + + int? intUsername = int.tryParse(username); + + if (username.length <= 2 || username.isEmpty) { + setErrorText = 'name is too short'; + return false; + } + + if (currName == username) { + setErrorText = 'this already is your username'; + return false; + } + + if (!validChars.hasMatch(username)) { + setErrorText = 'contains invalid characters'; + return false; + } + + if (intUsername != null) { + if (intUsername >= 100 && intUsername <= 599) { + setErrorText = '$username is a reserved error code'; + return false; + } + } + + return true; + } + + void searchUsername(String username, String currentName) { + void search() async { + bool usernameIsValid = await validateUsername(username, currentName); + + if (usernameIsValid) { + if (await _learnService.checkIfUsernameIsTaken(username)) { + setErrorText = 'username is already taken'; + return; + } else { + setHelperText = 'username is available'; + setErrorText = null; + } + } + } + + if (requestCooldonwTimer == null) { + log('timer was not set to begin with'); + requestCooldonwTimer = Timer(const Duration(seconds: 1), search); + } else if (!requestCooldonwTimer!.isActive) { + requestCooldonwTimer = Timer(const Duration(seconds: 1), search); + } else { + requestCooldonwTimer!.cancel(); + requestCooldonwTimer = Timer(const Duration(seconds: 1), search); + } + + setHelperText = 'searching..'; + setErrorText = null; + } + + saveAbout() async { + if (userInfo != null) { + bool complete = await _learnService.updateMyAbout(userInfo!); + + if (complete) { + _snackbarService.showSnackbar( + title: 'info updated successfully', message: ''); + auth.init(); + } else { + _snackbarService.showSnackbar( + title: 'something went wrong', message: ''); + } + } + } + + upateMyAbout(String flag, String value) { + if (userInfo != null) { + Map localUserInfo = userInfo!; + + List possibleFlags = ['location', 'about', 'picture', 'name']; + + if (possibleFlags.contains(flag)) { + localUserInfo[flag] = value; + setUserInfo = localUserInfo; + } + } + } +} diff --git a/mobile-app/lib/ui/views/learn/settings/settings_view.dart b/mobile-app/lib/ui/views/learn/settings/settings_view.dart new file mode 100644 index 000000000..ae1d2f1a5 --- /dev/null +++ b/mobile-app/lib/ui/views/learn/settings/settings_view.dart @@ -0,0 +1,292 @@ +import 'package:flutter/material.dart'; +import 'package:freecodecamp/models/main/user_model.dart'; + +import 'package:freecodecamp/ui/views/learn/settings/settings_model.dart'; +import 'package:stacked/stacked.dart'; + +class SettingsView extends StatelessWidget { + const SettingsView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder.reactive( + viewModelBuilder: () => SettingsModel(), + onModelReady: (model) => model.init(), + builder: ((context, model, child) { + return Scaffold( + backgroundColor: const Color.fromRGBO(0x1b, 0x1b, 0x32, 1), + appBar: AppBar( + title: const Text('LEARN SETTINGS'), + centerTitle: true, + ), + body: SingleChildScrollView( + child: FutureBuilder( + future: model.userFuture, + builder: ((context, snapshot) { + if (snapshot.hasData) { + FccUserModel user = snapshot.data as FccUserModel; + + return Row( + children: [ + Expanded( + child: Column( + children: [ + textfieldUsername('Username', user.username, model), + textfield('Name', model, user.name), + textfield('Location', model, user.location), + textfield('Picture', model, user.picture), + textfield('About', model, user.about, 5), + saveAboutButton(model), + switchButton('isLocked', 'My profile', model), + switchButton('showName', 'My name', model), + switchButton('showLocation', 'My location', model), + switchButton('showAbout', 'My about', model), + switchButton('showPoints', 'My points', model), + switchButton('showHeatMap', 'My heatmap', model), + switchButton( + 'showCerts', 'My certifications', model), + switchButton( + 'showPortfolio', 'My portfolio', model), + switchButton('showTimeLine', 'My timeline', model), + switchButton('showDonation', 'My donations', model), + saveProfileButton(model), + ], + ), + ) + ], + ); + } + + return const Center( + child: CircularProgressIndicator(), + ); + }), + )), + ); + })); + } + + Container textfield( + String label, + SettingsModel model, + String? initValue, [ + int? maxLines, + ]) { + return Container( + padding: const EdgeInsets.all(16), + width: 340, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Text( + label, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + ), + TextFormField( + initialValue: initValue, + maxLines: maxLines ?? 1, + decoration: const InputDecoration( + border: OutlineInputBorder(), + filled: true, + fillColor: Color(0xFF0a0a23)), + onChanged: (change) { + model.upateMyAbout(label.toLowerCase(), change); + }, + ), + ], + ), + ); + } + + Widget textfieldUsername( + String label, String? initValue, SettingsModel model) { + return Column( + children: [ + Container( + padding: const EdgeInsets.all(16), + width: 340, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Text( + label, + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + ), + ), + TextFormField( + initialValue: initValue, + onChanged: (String changedName) { + model.searchUsername(changedName, initValue ?? ''); + model.setUsername = changedName; + }, + decoration: InputDecoration( + helperText: model.helperText, + errorText: model.errorText, + helperStyle: model.helperText == 'username is available' + ? const TextStyle(color: Colors.green) + : null, + border: const OutlineInputBorder(), + filled: true, + fillColor: const Color(0xFF0a0a23)), + ), + ], + ), + ), + SizedBox( + width: 310, + child: TextButton( + style: TextButton.styleFrom( + side: const BorderSide(width: 2, color: Colors.white), + padding: const EdgeInsets.all(0), + backgroundColor: const Color.fromRGBO(0x3b, 0x3b, 0x4f, 1), + ), + onPressed: () async { + if (model.errorText == null) { + model.updateUsername(model.username!); + } + }, + child: const Text('Save'))) + ], + ); + } + + Widget saveAboutButton(SettingsModel model) { + return SizedBox( + width: 300, + child: TextButton( + style: TextButton.styleFrom( + side: const BorderSide(width: 2, color: Colors.white), + padding: const EdgeInsets.all(0), + backgroundColor: const Color.fromRGBO(0x3b, 0x3b, 0x4f, 1), + ), + onPressed: () { + model.saveAbout(); + }, + child: const Text('Save'))); + } + + Widget saveProfileButton(SettingsModel model) { + return SizedBox( + width: 300, + child: TextButton( + style: TextButton.styleFrom( + side: const BorderSide(width: 2, color: Colors.white), + padding: const EdgeInsets.all(0), + backgroundColor: const Color.fromRGBO(0x3b, 0x3b, 0x4f, 1), + ), + onPressed: () { + model.save(); + }, + child: const Text('Save'))); + } + + Widget switchButton(String flag, String title, SettingsModel model) { + bool isPublic = + flag != 'isLocked' ? model.profile![flag] : !model.profile![flag]; + + String? description = model.getDescriptions(flag); + + return Column( + children: [ + Container( + width: 300, + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.only(bottom: 8, top: 16), + child: Text( + title, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + ), + ), + if (description != null) + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: SizedBox( + width: 300, + child: Text( + description, + style: const TextStyle( + fontStyle: FontStyle.italic, + fontWeight: FontWeight.bold, + color: Color.fromRGBO(0xd0, 0xd0, 0xd5, 1)), + )), + ), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + InkWell( + onTap: () { + model.setNewValue(flag, false); + }, + child: Container( + decoration: BoxDecoration( + color: !isPublic + ? Colors.white + : const Color.fromRGBO(0x3b, 0x3b, 0x4f, 1), + border: Border.all( + width: 2, color: const Color.fromARGB(255, 230, 230, 230)), + ), + width: 150, + height: 40, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (!isPublic) + const Icon( + Icons.check, + color: Colors.black, + size: 15, + ), + Text( + 'Private', + style: TextStyle( + color: !isPublic ? Colors.black : Colors.white, + fontSize: 16, + fontWeight: FontWeight.w200, + fontFamily: 'RobotoMono'), + ), + ], + ), + ), + ), + InkWell( + onTap: () { + model.setNewValue(flag, true); + }, + child: Container( + decoration: BoxDecoration( + border: Border.all(width: 2, color: Colors.white), + color: isPublic + ? const Color.fromARGB(255, 230, 230, 230) + : const Color.fromRGBO(0x3b, 0x3b, 0x4f, 1)), + width: 150, + height: 40, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Public', + style: TextStyle( + color: isPublic ? Colors.black : Colors.white, + fontSize: 16, + fontWeight: FontWeight.w200, + fontFamily: 'RobotoMono')), + if (isPublic) + const Icon( + Icons.check, + color: Colors.black, + size: 15, + ), + ], + ), + ), + ) + ]), + ], + ); + } +} diff --git a/mobile-app/lib/ui/views/profile/profile_viemodel.dart b/mobile-app/lib/ui/views/profile/profile_viemodel.dart index 4d7101320..5f669b03e 100644 --- a/mobile-app/lib/ui/views/profile/profile_viemodel.dart +++ b/mobile-app/lib/ui/views/profile/profile_viemodel.dart @@ -1,8 +1,10 @@ import 'package:freecodecamp/app/app.locator.dart'; import 'package:freecodecamp/service/authentication_service.dart'; import 'package:stacked/stacked.dart'; +import 'package:stacked_services/stacked_services.dart'; // import 'dart:developer'; class ProfileViewModel extends BaseViewModel { final AuthenticationService auth = locator(); + final NavigationService navigationService = locator(); } diff --git a/mobile-app/lib/ui/views/settings/forumSettings/forum_settings_view.dart b/mobile-app/lib/ui/views/settings/forumSettings/forum_settings_view.dart deleted file mode 100644 index fb588cecd..000000000 --- a/mobile-app/lib/ui/views/settings/forumSettings/forum_settings_view.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:freecodecamp/ui/views/settings/forumSettings/forum_settings_viewmodel.dart'; -import 'package:stacked/stacked.dart'; - -class ForumSettingsView extends StatelessWidget { - const ForumSettingsView({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - return ViewModelBuilder.reactive( - onModelReady: (model) => model.init(), - viewModelBuilder: () => ForumSettingsViewModel(), - builder: (context, model, child) => Scaffold( - appBar: AppBar( - title: const Text('FORUM SETTINGS'), - ), - body: ListView( - children: [ - model.isLoggedIn ? loginButton(model) : Container(), - Container( - decoration: const BoxDecoration( - border: - Border(bottom: BorderSide(color: Colors.white))), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ListTile( - title: const Text( - 'REGISTER', - ), - subtitle: const Text( - 'register on the forum', - ), - onTap: () { - model.gotoForum(); - }, - ), - ), - ), - Container( - decoration: const BoxDecoration( - border: - Border(bottom: BorderSide(color: Colors.white))), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ListTile( - title: const Text( - 'RESET PASSWORD', - ), - subtitle: const Text( - 'reset your password on the forum', - ), - onTap: () { - model.gotoForum(); - }, - ), - ), - ), - ], - ), - )); - } - - Container loginButton(ForumSettingsViewModel model) { - return Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.white))), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ListTile( - title: const Text( - 'LOGOUT', - ), - subtitle: const Text( - 'logout from the forum', - ), - onTap: () { - model.forumLogout(); - }, - ), - ), - ); - } -} diff --git a/mobile-app/lib/ui/views/settings/forumSettings/forum_settings_viewmodel.dart b/mobile-app/lib/ui/views/settings/forumSettings/forum_settings_viewmodel.dart deleted file mode 100644 index e60b67aa9..000000000 --- a/mobile-app/lib/ui/views/settings/forumSettings/forum_settings_viewmodel.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:stacked/stacked.dart'; -import 'package:url_launcher/url_launcher_string.dart'; - -class ForumSettingsViewModel extends BaseViewModel { - bool _isLoggedIn = false; - bool get isLoggedIn => _isLoggedIn; - - void init() async { - _isLoggedIn = await checkLoggedIn(); - notifyListeners(); - } - - void forumLogout() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - - prefs.setBool('loggedIn', false); - prefs.remove('username'); - _isLoggedIn = false; - notifyListeners(); - } - - void gotoForum() { - launchUrlString('https://forum.freecodecamp.org/'); - } - - Future checkLoggedIn() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - return prefs.getBool('loggedIn') ?? false; - } -} diff --git a/mobile-app/lib/ui/views/settings/podcastSettings/podcast_settings_view.dart b/mobile-app/lib/ui/views/settings/podcastSettings/podcast_settings_view.dart deleted file mode 100644 index 8e6e955b2..000000000 --- a/mobile-app/lib/ui/views/settings/podcastSettings/podcast_settings_view.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:freecodecamp/ui/views/settings/podcastSettings/podcast_settings_viewmodel.dart'; -import 'package:stacked/stacked.dart'; - -class PodcastSettingsView extends StatelessWidget { - const PodcastSettingsView({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - return ViewModelBuilder.reactive( - viewModelBuilder: () => PodcastSettingsViewModel(), - builder: (context, model, child) => Scaffold( - backgroundColor: const Color.fromRGBO(0x2A, 0x2A, 0x40, 1), - appBar: AppBar( - backgroundColor: const Color(0xFF0a0a23), - title: const Text('PODCAST SETTINGS'), - centerTitle: true, - ), - )); - } -} diff --git a/mobile-app/lib/ui/views/settings/podcastSettings/podcast_settings_viewmodel.dart b/mobile-app/lib/ui/views/settings/podcastSettings/podcast_settings_viewmodel.dart deleted file mode 100644 index e2b1de119..000000000 --- a/mobile-app/lib/ui/views/settings/podcastSettings/podcast_settings_viewmodel.dart +++ /dev/null @@ -1,3 +0,0 @@ -import 'package:stacked/stacked.dart'; - -class PodcastSettingsViewModel extends BaseViewModel {} diff --git a/mobile-app/lib/ui/views/settings/settings_view.dart b/mobile-app/lib/ui/views/settings/settings_view.dart deleted file mode 100644 index c0c733cbd..000000000 --- a/mobile-app/lib/ui/views/settings/settings_view.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:freecodecamp/ui/views/settings/settings_viewmodel.dart'; -import 'package:freecodecamp/ui/widgets/drawer_widget/drawer_widget_view.dart'; -import 'package:stacked/stacked.dart'; - -class SettingsView extends StatelessWidget { - const SettingsView({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return ViewModelBuilder.reactive( - viewModelBuilder: () => SettingsViewModel(), - builder: (context, model, child) => Scaffold( - backgroundColor: const Color.fromRGBO(0x2A, 0x2A, 0x40, 1), - appBar: AppBar( - backgroundColor: const Color(0xFF0a0a23), - title: const Text('SETTINGS'), - centerTitle: true, - ), - drawer: const DrawerWidgetView(), - body: ListView( - children: [ - Container( - decoration: const BoxDecoration( - border: - Border(bottom: BorderSide(color: Colors.white))), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ListTile( - onTap: () { - model.goToForumSettings(); - }, - title: const Text( - 'FORUM', - style: TextStyle(color: Colors.white), - ), - subtitle: const Text( - 'You can find the forum settings here', - style: TextStyle(color: Colors.white, fontSize: 18.0), - ), - trailing: const Icon( - Icons.arrow_forward_ios_sharp, - color: Colors.white, - ), - ), - ), - ), - Container( - decoration: const BoxDecoration( - border: - Border(bottom: BorderSide(color: Colors.white))), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ListTile( - onTap: () { - model.goToPodastSettings(); - }, - title: const Text( - 'PODCAST', - style: TextStyle(color: Colors.white), - ), - subtitle: const Text( - 'You can find the podcast settings here', - style: TextStyle(color: Colors.white, fontSize: 18.0), - ), - trailing: const Icon( - Icons.arrow_forward_ios_sharp, - color: Colors.white, - ), - ), - ), - ) - ], - ), - )); - } -} diff --git a/mobile-app/lib/ui/views/settings/settings_viewmodel.dart b/mobile-app/lib/ui/views/settings/settings_viewmodel.dart deleted file mode 100644 index 3304bc704..000000000 --- a/mobile-app/lib/ui/views/settings/settings_viewmodel.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:freecodecamp/app/app.locator.dart'; -import 'package:freecodecamp/app/app.router.dart'; -import 'package:stacked/stacked.dart'; -import 'package:stacked_services/stacked_services.dart'; - -class SettingsViewModel extends BaseViewModel { - final _navigationService = locator(); - - void goToForumSettings() { - _navigationService.navigateTo(Routes.forumSettingsView); - } - - void goToPodastSettings() { - _navigationService.navigateTo(Routes.podcastSettingsView); - } -} diff --git a/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_view.dart b/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_view.dart index dc04f1ba0..c9afb4b11 100644 --- a/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_view.dart +++ b/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_view.dart @@ -92,11 +92,13 @@ class DrawerWidgetView extends StatelessWidget { icon: Icons.info_outline, url: 'https://www.freecodecamp.org/news/privacy-policy/', ), - const WebButton( - component: 'DONATE', - url: 'https://www.freecodecamp.org/donate/', - icon: Icons.favorite, - ), + if (model.loggedIn) + DrawerButton( + component: 'SETTINGS', + icon: Icons.settings, + route: () { + model.routeComponent('SETTINGS', context); + }), buildDivider(), DrawerButton( component: model.loggedIn ? 'LOG OUT' : 'LOGIN', diff --git a/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_viewmodel.dart b/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_viewmodel.dart index 00ef201bd..82485d3cc 100644 --- a/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_viewmodel.dart +++ b/mobile-app/lib/ui/widgets/drawer_widget/drawer_widget_viewmodel.dart @@ -3,13 +3,13 @@ import 'package:freecodecamp/service/authentication_service.dart'; import 'package:freecodecamp/app/app.locator.dart'; import 'package:freecodecamp/service/test_service.dart'; import 'package:freecodecamp/ui/views/code_radio/code_radio_view.dart'; -//import 'package:freecodecamp/ui/views/learn/learn_view.dart'; import 'package:freecodecamp/ui/views/forum/forum-categories/forum_category_view.dart'; import 'package:freecodecamp/ui/views/home/home_view.dart'; import 'package:freecodecamp/ui/views/learn/learn/learn_view.dart'; +import 'package:freecodecamp/ui/views/learn/settings/settings_view.dart'; import 'package:freecodecamp/ui/views/podcast/podcast-list/podcast_list_view.dart'; import 'package:freecodecamp/ui/views/profile/profile_view.dart'; -import 'package:freecodecamp/ui/views/settings/settings_view.dart'; + import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; @@ -89,7 +89,7 @@ class DrawerWidgtetViewModel extends BaseViewModel { const PodcastListView())); break; case 'SETTINGS': - Navigator.pushReplacement( + Navigator.push( context, PageRouteBuilder( transitionDuration: Duration.zero,