Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(AAiT-mobile-3): Add Bookmark feature #473

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<String> 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<String> getStoredToken() async {
final SharedPreferences pref = await SharedPreferences.getInstance();
final String token = pref.getString(cachedToken)!;
return token;
}

class BookmarkPreferences {
static SharedPreferences? _preferences;
Expand Down Expand Up @@ -37,15 +75,19 @@ class BookmarkPreferences {
return _preferences?.getStringList(userId) ?? [];
}

static Future<List<Article>> getAllBookmarkedModels(String userId)async {
static Future<String> getAllBookmarked(String userId)async {
final articleIds = _preferences?.getStringList(userId) ?? [];
List<Article> articles = [];
List<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ class ArticleRemoteDataSourceImpl implements ArticleRemoteDataSource {
photoFile = pngImage;
mimeType = lookupMimeType(photoFile.path)!;
}

var request =
http.MultipartRequest('POST', Uri.parse('$baseUrl/article'));

Expand Down Expand Up @@ -307,4 +306,4 @@ class ArticleRemoteDataSourceImpl implements ArticleRemoteDataSource {
final String token = pref.getString(cachedToken)!;
return token;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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';
Expand Down
Original file line number Diff line number Diff line change
@@ -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<List<Article>> getBookmarkArticles();
Future<List<Article>> getBookmarkArticles(String userId);
}

const CACHED_ARTICLE_LIST = 'CACHED_ARTICLE_LIST';
Expand All @@ -16,16 +17,23 @@ class ProfileLocalDataSourceImpl implements ProfileLocalDataSource {
ProfileLocalDataSourceImpl({required this.sharedPreferences});

@override
Future<List<Article>> getBookmarkArticles() async {
Future<List<Article>> 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<dynamic> jsonList = jsonDecode(jsonValues);
final List<Article> convertedList = jsonList.map<Article>((e) => ArticleModel.fromJson(e))
print("111$jsonList");
final List<Article> convertedList = jsonList.map<Article>((e) {
print("222$e");
final art = ArticleModel.fromJson(jsonDecode(e));
print("333$art");
return art;

} )
.toList();
return Future.value(convertedList);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ProfileRepositoryImpl implements ProfileRepository {
Future<Either<Failure, Profile>> 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(
Expand All @@ -30,10 +30,10 @@ class ProfileRepositoryImpl implements ProfileRepository {
}

@override
Future<Either<Failure, Profile>> updateProfilePicture(XFile image) async {
Future<Either<Failure, Profile>> 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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import 'package:image_picker/image_picker.dart';

abstract class ProfileRepository {
Future<Either<Failure, Profile>> getProfile();
Future<Either<Failure, Profile>> updateProfilePicture(XFile image);
Future<Either<Failure, Profile>> updateProfilePicture({required XFile image, required String userId});
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Profile, Params> {
class UpdateProfilePicture extends UseCase<Profile, UpdateProfileParams> {
final ProfileRepository repository;

UpdateProfilePicture({required this.repository});
@override
Future<Either<Failure, Profile>> call(Params params) async {
return await repository.updateProfilePicture(params.data);
Future<Either<Failure, Profile>> 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<Object> get props => [userId, image];
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
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(
Expand Down