From a3fad411552e2acc188acd5a9eaba8780aa2aa28 Mon Sep 17 00:00:00 2001 From: Dawit Melka Date: Thu, 31 Aug 2023 09:04:22 +0300 Subject: [PATCH 1/5] fix(AAiT-mobile-3): Fix minor bugs --- .../article/presentation/screen/article_reading.dart | 5 +++++ .../lib/features/article/presentation/widgets/user_info.dart | 1 + 2 files changed, 6 insertions(+) diff --git a/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart b/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart index 9c3c52ee9..b38051794 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart @@ -1,3 +1,8 @@ +import 'package:blog_app/core/color/colors.dart'; +import 'package:blog_app/core/util/value_converter.dart'; +import 'package:blog_app/features/article/presentation/bloc/article_bloc.dart'; +import 'package:blog_app/features/article/presentation/widgets/loading_widget.dart'; +import 'package:blog_app/injection_container.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:top_snackbar_flutter/custom_snack_bar.dart'; diff --git a/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart b/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart index fcf52792e..a5c93626e 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart @@ -2,6 +2,7 @@ import 'package:blog_app/core/util/bookmark_preferences.dart'; import 'package:blog_app/features/article/domain/entity/article.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import '../../../../core/color/colors.dart'; From 57cb353459367f26f05a29736fbb20d54ed0ccda Mon Sep 17 00:00:00 2001 From: Dawit Melka Date: Sun, 3 Sep 2023 12:43:56 +0300 Subject: [PATCH 2/5] fix(AAiT-mobile-3): Fix bugs and refinining --- .../data_sources/article_remote_datasource.dart | 11 +++++++++++ .../article/presentation/bloc/article_bloc.dart | 3 +++ .../presentation/screen/article_reading.dart | 17 ++++++----------- .../article/presentation/widgets/user_info.dart | 1 - 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart b/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart index fe5fbc5db..4a5fadf4f 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart @@ -8,6 +8,9 @@ import 'package:shared_preferences/shared_preferences.dart'; import '../../../../core/util/convert_to_png.dart'; import '../../domain/entity/getArticlesEntity.dart'; +import '../../../../core/util/convert_to_png.dart'; +import '../../domain/entity/getArticlesEntity.dart'; + import '../../../../core/error/exception.dart'; import '../../../../core/util/constants.dart'; import '../models/article_model.dart'; @@ -39,6 +42,14 @@ class ArticleRemoteDataSourceImpl implements ArticleRemoteDataSource { @override Future createArticle(ArticleModel article) async { String token = await getStoredToken(); + try { + var photoFile = File(article.image); + var mimeType = lookupMimeType(photoFile.path)!; + if (mimeType != "image/png" || mimeType != "image/jpeg") { + final pngImage = convertToPng(photoFile); + photoFile = pngImage; + mimeType = lookupMimeType(photoFile.path)!; + } try { var photoFile = File(article.image); var mimeType = lookupMimeType(photoFile.path)!; diff --git a/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart b/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart index e3e44f00b..1692ef3b2 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart @@ -3,6 +3,8 @@ import 'dart:async'; import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../domain/entity/getArticlesEntity.dart'; +import '../../domain/use_case/get_tags.dart'; import '../../domain/entity/getArticlesEntity.dart'; import '../../domain/use_case/get_tags.dart'; import '../../../../core/use_case/usecase.dart'; @@ -62,6 +64,7 @@ class ArticleBloc extends Bloc { DeleteArticleEvent event, Emitter emit) async { emit(DeletingArticle()); final result = await _deleteArticle(event.id); + print(result); result.fold((failure) => emit(ArticleError(failure.errorMessage)), (_) => emit(ArticleDeleted())); diff --git a/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart b/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart index b38051794..9ccb270aa 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart @@ -1,11 +1,7 @@ -import 'package:blog_app/core/color/colors.dart'; -import 'package:blog_app/core/util/value_converter.dart'; -import 'package:blog_app/features/article/presentation/bloc/article_bloc.dart'; -import 'package:blog_app/features/article/presentation/widgets/loading_widget.dart'; -import 'package:blog_app/injection_container.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:top_snackbar_flutter/custom_snack_bar.dart'; +import 'package:top_snackbar_flutter/custom_snack_bar.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; import 'package:top_snackbar_flutter/top_snack_bar.dart'; @@ -42,7 +38,7 @@ class _ArticleReadingPageState extends State { Overlay.of(context), const CustomSnackBar.error( message: "Oops unable to load the article")); - context.go('/home'); + context.pop(); } else if (state is ArticleDeleted) { showTopSnackBar( Overlay.of(context), @@ -62,11 +58,10 @@ class _ArticleReadingPageState extends State { LoadingWidget(message: "Deleting article please wait")), ); case GettingArticle(): - return Scaffold(body: LoadingArticlePage()); - // return const Scaffold( - // body: LoadingWidget( - // message: "Fetching Article please wait", - // )); + return const Scaffold( + body: LoadingWidget( + message: "Fetching Article please wait", + )); case ArticleInitial(): BlocProvider.of(context) .add(GetArticleByIdEvent(id: this.widget.id)); diff --git a/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart b/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart index a5c93626e..fcf52792e 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/presentation/widgets/user_info.dart @@ -2,7 +2,6 @@ import 'package:blog_app/core/util/bookmark_preferences.dart'; import 'package:blog_app/features/article/domain/entity/article.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import '../../../../core/color/colors.dart'; From fa0fd8ee23e4c41da42d1915da818578ad2c993b Mon Sep 17 00:00:00 2001 From: Dawit Melka Date: Mon, 4 Sep 2023 00:15:13 +0300 Subject: [PATCH 3/5] feat(AAiT-mobile-1): Shimmer loading and bookmarks --- .../article/presentation/bloc/article_bloc.dart | 1 - .../article/presentation/screen/article_reading.dart | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart b/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart index 1692ef3b2..4bd6eca89 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/presentation/bloc/article_bloc.dart @@ -64,7 +64,6 @@ class ArticleBloc extends Bloc { DeleteArticleEvent event, Emitter emit) async { emit(DeletingArticle()); final result = await _deleteArticle(event.id); - print(result); result.fold((failure) => emit(ArticleError(failure.errorMessage)), (_) => emit(ArticleDeleted())); diff --git a/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart b/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart index 9ccb270aa..a5b1e829b 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/presentation/screen/article_reading.dart @@ -38,7 +38,7 @@ class _ArticleReadingPageState extends State { Overlay.of(context), const CustomSnackBar.error( message: "Oops unable to load the article")); - context.pop(); + context.go('/home'); } else if (state is ArticleDeleted) { showTopSnackBar( Overlay.of(context), @@ -58,10 +58,11 @@ class _ArticleReadingPageState extends State { LoadingWidget(message: "Deleting article please wait")), ); case GettingArticle(): - return const Scaffold( - body: LoadingWidget( - message: "Fetching Article please wait", - )); + return Scaffold(body: LoadingArticlePage()); + // return const Scaffold( + // body: LoadingWidget( + // message: "Fetching Article please wait", + // )); case ArticleInitial(): BlocProvider.of(context) .add(GetArticleByIdEvent(id: this.widget.id)); From 50673bd68892acdad9ec5c4d5d21f2957b64a6fd Mon Sep 17 00:00:00 2001 From: Dawit Melka Date: Tue, 5 Sep 2023 09:26:50 +0300 Subject: [PATCH 4/5] fet(AAiT-mobile-3): Add Bookmark feature --- .../lib/core/util/bookmark_preferences.dart | 54 ++++++++++++++++--- .../profile_local_data_source.dart | 16 ++++-- .../repository/profile_repository_impl.dart | 6 +-- .../repositories/profile_repository.dart | 2 +- .../use_case/update_profile_picture.dart | 18 +++++-- .../presentation/bloc/profile_bloc.dart | 2 +- 6 files changed, 80 insertions(+), 18 deletions(-) diff --git a/aait/mobile/group-3/blog_app/lib/core/util/bookmark_preferences.dart b/aait/mobile/group-3/blog_app/lib/core/util/bookmark_preferences.dart index 5048d5b3b..44d50f2a5 100644 --- a/aait/mobile/group-3/blog_app/lib/core/util/bookmark_preferences.dart +++ b/aait/mobile/group-3/blog_app/lib/core/util/bookmark_preferences.dart @@ -1,8 +1,46 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import '../../features/article/domain/entity/article.dart'; import '../../features/article/domain/use_case/get_article_by_id.dart'; +import '../error/exception.dart'; +import 'constants.dart'; + +Future getArticleById(String id) async { + String baseUrl = getBaseUrl(); + try { + String token = await getStoredToken(); + + var request = http.Request('GET', Uri.parse('$baseUrl/article/$id')); + request.headers['Authorization'] = 'Bearer $token'; + + http.StreamedResponse response = await request.send(); + + if (response.statusCode == 200) { + final http.Response result = await http.Response.fromStream(response); + + final jsonResponse = jsonDecode(result.body); + return jsonEncode(jsonResponse["data"]); + + } else { + final result = await http.Response.fromStream(response); + throw ServerException( + statusCode: result.statusCode, + message: "Failed to get the article"); + } + } catch (e) { + throw ServerException( + statusCode: 500, message: "Failed to get the article$e"); + } + } + + Future getStoredToken() async { + final SharedPreferences pref = await SharedPreferences.getInstance(); + final String token = pref.getString(cachedToken)!; + return token; + } class BookmarkPreferences { static SharedPreferences? _preferences; @@ -37,15 +75,19 @@ class BookmarkPreferences { return _preferences?.getStringList(userId) ?? []; } - static Future> getAllBookmarkedModels(String userId)async { + static Future getAllBookmarked(String userId)async { final articleIds = _preferences?.getStringList(userId) ?? []; - List
articles = []; + List articles = []; for (String id in articleIds) { - final article = await usecase!(id); - article.fold((l) => null, (value) => articles.add(value)); + final article = await getArticleById(id); + final articleMap = jsonDecode(article); + if (articleMap != null) + articles.add(article); } - - return articles; + final finalResult = jsonEncode(articles); + print("===============I accomplished my mission==============="); + print(finalResult); + return finalResult; } } diff --git a/aait/mobile/group-3/blog_app/lib/features/profile/data/data_sources/profile_local_data_source.dart b/aait/mobile/group-3/blog_app/lib/features/profile/data/data_sources/profile_local_data_source.dart index a1c2601bb..845e6744c 100644 --- a/aait/mobile/group-3/blog_app/lib/features/profile/data/data_sources/profile_local_data_source.dart +++ b/aait/mobile/group-3/blog_app/lib/features/profile/data/data_sources/profile_local_data_source.dart @@ -1,11 +1,12 @@ import 'dart:convert'; +import 'package:blog_app/core/util/bookmark_preferences.dart'; import 'package:blog_app/features/profile/data/models/article_model.dart'; import 'package:blog_app/features/profile/domain/entity/article.dart'; import 'package:shared_preferences/shared_preferences.dart'; abstract class ProfileLocalDataSource { - Future> getBookmarkArticles(); + Future> getBookmarkArticles(String userId); } const CACHED_ARTICLE_LIST = 'CACHED_ARTICLE_LIST'; @@ -16,16 +17,23 @@ class ProfileLocalDataSourceImpl implements ProfileLocalDataSource { ProfileLocalDataSourceImpl({required this.sharedPreferences}); @override - Future> getBookmarkArticles() async { + Future> getBookmarkArticles(String userId) async { //for testing purpose final dummy = _getDummyArticles(); final jsonVal = jsonEncode(dummy); sharedPreferences.setString(CACHED_ARTICLE_LIST, jsonVal); /////////////////////////////////////////////////////////////////// - final jsonValues = await sharedPreferences.getString(CACHED_ARTICLE_LIST); + final jsonValues = await BookmarkPreferences.getAllBookmarked(userId); if (jsonValues != null) { final List jsonList = jsonDecode(jsonValues); - final List
convertedList = jsonList.map
((e) => ArticleModel.fromJson(e)) + print("111$jsonList"); + final List
convertedList = jsonList.map
((e) { + print("222$e"); + final art = ArticleModel.fromJson(jsonDecode(e)); + print("333$art"); + return art; + + } ) .toList(); return Future.value(convertedList); } else { diff --git a/aait/mobile/group-3/blog_app/lib/features/profile/data/repository/profile_repository_impl.dart b/aait/mobile/group-3/blog_app/lib/features/profile/data/repository/profile_repository_impl.dart index 3ed3f41c1..de4995fd7 100644 --- a/aait/mobile/group-3/blog_app/lib/features/profile/data/repository/profile_repository_impl.dart +++ b/aait/mobile/group-3/blog_app/lib/features/profile/data/repository/profile_repository_impl.dart @@ -21,7 +21,7 @@ class ProfileRepositoryImpl implements ProfileRepository { Future> getProfile() async { try { final remoteProfile = await remoteDataSource.getProfile(); - final bookmarks = await localDataSource.getBookmarkArticles(); + final bookmarks = await localDataSource.getBookmarkArticles(remoteProfile.id); return Right(remoteProfile.copyWith(bookmarks: bookmarks)); } on ServerException { return Left(ServerFailure( @@ -30,10 +30,10 @@ class ProfileRepositoryImpl implements ProfileRepository { } @override - Future> updateProfilePicture(XFile image) async { + Future> updateProfilePicture({ required image, required String userId}) async { try { final remoteProfile = await remoteDataSource.updateProfilePicture(image); - final bookmarks = await localDataSource.getBookmarkArticles(); + final bookmarks = await localDataSource.getBookmarkArticles(userId); return Right(remoteProfile.copyWith(bookmarks: bookmarks)); } on ServerException { return Left(ServerFailure( diff --git a/aait/mobile/group-3/blog_app/lib/features/profile/domain/repositories/profile_repository.dart b/aait/mobile/group-3/blog_app/lib/features/profile/domain/repositories/profile_repository.dart index f0a571437..f47baa153 100644 --- a/aait/mobile/group-3/blog_app/lib/features/profile/domain/repositories/profile_repository.dart +++ b/aait/mobile/group-3/blog_app/lib/features/profile/domain/repositories/profile_repository.dart @@ -5,5 +5,5 @@ import 'package:image_picker/image_picker.dart'; abstract class ProfileRepository { Future> getProfile(); - Future> updateProfilePicture(XFile image); + Future> updateProfilePicture({required XFile image, required String userId}); } diff --git a/aait/mobile/group-3/blog_app/lib/features/profile/domain/use_case/update_profile_picture.dart b/aait/mobile/group-3/blog_app/lib/features/profile/domain/use_case/update_profile_picture.dart index 44b1fc479..d4bff503c 100644 --- a/aait/mobile/group-3/blog_app/lib/features/profile/domain/use_case/update_profile_picture.dart +++ b/aait/mobile/group-3/blog_app/lib/features/profile/domain/use_case/update_profile_picture.dart @@ -3,13 +3,25 @@ import 'package:blog_app/core/use_case/usecase.dart'; import 'package:blog_app/features/profile/domain/entity/profile.dart'; import 'package:blog_app/features/profile/domain/repositories/profile_repository.dart'; import 'package:dartz/dartz.dart'; +import 'package:equatable/equatable.dart'; +import 'package:image_picker/image_picker.dart'; -class UpdateProfilePicture extends UseCase { +class UpdateProfilePicture extends UseCase { final ProfileRepository repository; UpdateProfilePicture({required this.repository}); @override - Future> call(Params params) async { - return await repository.updateProfilePicture(params.data); + Future> call(UpdateProfileParams params) async { + return await repository.updateProfilePicture(image: params.image, userId: params.userId); } } + +class UpdateProfileParams extends Equatable { + final String userId; + final XFile image; + + UpdateProfileParams({required this.image, required this.userId}); + + @override + List get props => [userId, image]; +} \ No newline at end of file diff --git a/aait/mobile/group-3/blog_app/lib/features/profile/presentation/bloc/profile_bloc.dart b/aait/mobile/group-3/blog_app/lib/features/profile/presentation/bloc/profile_bloc.dart index d1e068607..5ebe97d0e 100644 --- a/aait/mobile/group-3/blog_app/lib/features/profile/presentation/bloc/profile_bloc.dart +++ b/aait/mobile/group-3/blog_app/lib/features/profile/presentation/bloc/profile_bloc.dart @@ -52,7 +52,7 @@ class ProfileBloc extends Bloc { final _state = state as ProfileLoaded; if (event.imageFile != null) { emit(ProfileLoading(message: "Updating Profile Picture...")); - final result = await updateProfilePicture(Params(event.imageFile)); + final result = await updateProfilePicture(UpdateProfileParams(image: event.imageFile!, userId: _state.profile.id)); result.fold( (failure) => emit(ProfileError()), (profile) => emit(ProfileLoaded( From 4174257dc3d4e42b83e29fed06551fb1328d9603 Mon Sep 17 00:00:00 2001 From: Dawit Melka Date: Tue, 5 Sep 2023 23:11:00 +0300 Subject: [PATCH 5/5] fix(AAiT-mobile-3): fix minor bug --- .../data_sources/article_remote_datasource.dart | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart b/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart index 4a5fadf4f..639387a88 100644 --- a/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart +++ b/aait/mobile/group-3/blog_app/lib/features/article/data/data_sources/article_remote_datasource.dart @@ -8,9 +8,6 @@ import 'package:shared_preferences/shared_preferences.dart'; import '../../../../core/util/convert_to_png.dart'; import '../../domain/entity/getArticlesEntity.dart'; -import '../../../../core/util/convert_to_png.dart'; -import '../../domain/entity/getArticlesEntity.dart'; - import '../../../../core/error/exception.dart'; import '../../../../core/util/constants.dart'; import '../models/article_model.dart'; @@ -50,15 +47,6 @@ class ArticleRemoteDataSourceImpl implements ArticleRemoteDataSource { photoFile = pngImage; mimeType = lookupMimeType(photoFile.path)!; } - try { - var photoFile = File(article.image); - var mimeType = lookupMimeType(photoFile.path)!; - if (mimeType != "image/png" || mimeType != "image/jpeg") { - final pngImage = convertToPng(photoFile); - photoFile = pngImage; - mimeType = lookupMimeType(photoFile.path)!; - } - var request = http.MultipartRequest('POST', Uri.parse('$baseUrl/article')); @@ -318,4 +306,4 @@ class ArticleRemoteDataSourceImpl implements ArticleRemoteDataSource { final String token = pref.getString(cachedToken)!; return token; } -} + }