diff --git a/lib/core/api/auth/datasources/auth_remote_datasource.dart b/lib/core/api/auth/datasources/auth_remote_datasource.dart index 4c1bfd9..bd054e0 100644 --- a/lib/core/api/auth/datasources/auth_remote_datasource.dart +++ b/lib/core/api/auth/datasources/auth_remote_datasource.dart @@ -5,13 +5,15 @@ import 'package:waterbus_sdk/constants/api_enpoints.dart'; import 'package:waterbus_sdk/constants/http_status_code.dart'; import 'package:waterbus_sdk/core/api/auth/datasources/auth_local_datasource.dart'; import 'package:waterbus_sdk/core/api/base/base_remote_data.dart'; +import 'package:waterbus_sdk/types/error/failures.dart'; import 'package:waterbus_sdk/types/models/auth_payload_model.dart'; import 'package:waterbus_sdk/types/models/user_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class AuthRemoteDataSource { Future<(String?, String?)> refreshToken(); - Future signInWithSocial(AuthPayloadModel authPayload); - Future logOut(); + Future> signInWithSocial(AuthPayloadModel authPayload); + Future> logOut(); } @LazySingleton(as: AuthRemoteDataSource) @@ -22,7 +24,7 @@ class AuthRemoteDataSourceImpl extends AuthRemoteDataSource { AuthRemoteDataSourceImpl(this._baseRemoteData, this._localDataSource); @override - Future signInWithSocial(AuthPayloadModel authPayload) async { + Future> signInWithSocial(AuthPayloadModel authPayload) async { final Map body = authPayload.toMap(); final Response response = await _baseRemoteData.postRoute( @@ -39,10 +41,10 @@ class AuthRemoteDataSourceImpl extends AuthRemoteDataSource { refreshToken: refreshToken, ); - return User.fromMap(response.data['user']); + return Result.success(User.fromMap(response.data['user'])); } - return null; + return Result.failure(ServerFailure()); } @override @@ -61,11 +63,15 @@ class AuthRemoteDataSourceImpl extends AuthRemoteDataSource { } @override - Future logOut() async { + Future> logOut() async { final Response response = await _baseRemoteData.deleteRoute( ApiEndpoints.auth, ); - return response.statusCode == StatusCode.noContent; + if (response.statusCode == StatusCode.noContent) { + return Result.success(true); + } + + return Result.failure(ServerFailure()); } } diff --git a/lib/core/api/auth/repositories/auth_repository.dart b/lib/core/api/auth/repositories/auth_repository.dart index 21269d3..46e9249 100644 --- a/lib/core/api/auth/repositories/auth_repository.dart +++ b/lib/core/api/auth/repositories/auth_repository.dart @@ -2,13 +2,15 @@ import 'package:injectable/injectable.dart'; import 'package:waterbus_sdk/core/api/auth/datasources/auth_local_datasource.dart'; import 'package:waterbus_sdk/core/api/auth/datasources/auth_remote_datasource.dart'; +import 'package:waterbus_sdk/types/error/failures.dart'; import 'package:waterbus_sdk/types/models/auth_payload_model.dart'; import 'package:waterbus_sdk/types/models/user_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class AuthRepository { - Future refreshToken(); - Future loginWithSocial(AuthPayloadModel params); - Future logOut(); + Future> refreshToken(); + Future> loginWithSocial(AuthPayloadModel params); + Future> logOut(); } @LazySingleton(as: AuthRepository) @@ -19,33 +21,36 @@ class AuthRepositoryImpl extends AuthRepository { AuthRepositoryImpl(this._localDataSource, this._remoteDataSource); @override - Future loginWithSocial(AuthPayloadModel params) async { - final User? response = await _remoteDataSource.signInWithSocial(params); + Future> loginWithSocial(AuthPayloadModel params) async { + final Result result = + await _remoteDataSource.signInWithSocial(params); - return response; + return result; } @override - Future refreshToken() async { + Future> refreshToken() async { final (String? accessToken, String? refreshToken) = await _remoteDataSource.refreshToken(); - if (accessToken == null || refreshToken == null) return false; + if (accessToken == null || refreshToken == null) { + return Result.failure(ServerFailure()); + } _localDataSource.saveTokens( accessToken: accessToken, refreshToken: refreshToken, ); - return true; + return Result.success(true); } @override - Future logOut() async { - final bool isSignedOut = await _remoteDataSource.logOut(); + Future> logOut() async { + final Result result = await _remoteDataSource.logOut(); _localDataSource.clearToken(); - return isSignedOut; + return result; } } diff --git a/lib/core/api/chat/datasources/chat_remote_datasource.dart b/lib/core/api/chat/datasources/chat_remote_datasource.dart index e1f9e69..d85671a 100644 --- a/lib/core/api/chat/datasources/chat_remote_datasource.dart +++ b/lib/core/api/chat/datasources/chat_remote_datasource.dart @@ -7,25 +7,30 @@ import 'package:waterbus_sdk/constants/api_enpoints.dart'; import 'package:waterbus_sdk/constants/http_status_code.dart'; import 'package:waterbus_sdk/core/api/base/base_remote_data.dart'; import 'package:waterbus_sdk/flutter_waterbus_sdk.dart'; +import 'package:waterbus_sdk/types/models/exceptions/exceptions.dart'; +import 'package:waterbus_sdk/types/result.dart'; import 'package:waterbus_sdk/utils/encrypt/encrypt.dart'; abstract class ChatRemoteDataSource { - Future> getConversations({ + Future>> getConversations({ required int skip, required int limit, required int status, }); - Future> getArchivedConversations({ + Future>> getArchivedConversations({ required int skip, required int limit, }); - Future deleteConversation({required int meetingId}); - Future archivedConversation({required int code}); - Future leaveConversation({required int code}); - Future addMember({required int code, required int userId}); - Future deleteMember({required int code, required int userId}); - Future acceptInvite({required int meetingId}); - Future updateConversation({ + Future> deleteConversation({required int meetingId}); + Future> archivedConversation({required int code}); + Future> leaveConversation({required int code}); + Future> addMember({required int code, required int userId}); + Future> deleteMember({ + required int code, + required int userId, + }); + Future> acceptInvite({required int meetingId}); + Future> updateConversation({ required Meeting meeting, String? password, }); @@ -39,7 +44,7 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { ); @override - Future> getConversations({ + Future>> getConversations({ required int skip, required int limit, required int status, @@ -57,14 +62,14 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { "key": WaterbusSdk.privateMessageKey, }; - return await compute(_handleDecryptLastMessage, message); + return Result.success(await compute(_handleDecryptLastMessage, message)); } - return []; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future> getArchivedConversations({ + Future>> getArchivedConversations({ required int skip, required int limit, }) async { @@ -81,10 +86,10 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { "key": WaterbusSdk.privateMessageKey, }; - return await compute(_handleDecryptLastMessage, message); + return Result.success(await compute(_handleDecryptLastMessage, message)); } - return []; + return Result.failure(response.data['message'].toString().meetingException); } static Future> _handleDecryptLastMessage( @@ -115,7 +120,7 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { } @override - Future updateConversation({ + Future> updateConversation({ required Meeting meeting, String? password, }) async { @@ -124,20 +129,28 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { meeting.toMapCreate(password: password), ); - return response.statusCode == StatusCode.ok; + if (response.statusCode == StatusCode.ok) { + return Result.success(true); + } + + return Result.failure(response.data['message'].toString().meetingException); } @override - Future deleteConversation({required int meetingId}) async { + Future> deleteConversation({required int meetingId}) async { final response = await _remoteData.deleteRoute( "${ApiEndpoints.chatsConversations}/$meetingId", ); - return [StatusCode.ok, StatusCode.created].contains(response.statusCode); + if ([StatusCode.ok, StatusCode.created].contains(response.statusCode)) { + return Result.success(true); + } + + return Result.failure(response.data['message'].toString().meetingException); } @override - Future leaveConversation({required int code}) async { + Future> leaveConversation({required int code}) async { final Response response = await _remoteData.deleteRoute( '${ApiEndpoints.meetings}/$code', ); @@ -148,14 +161,16 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { "key": WaterbusSdk.privateMessageKey, }; - return (await compute(_handleDecryptLastMessage, message)).first; + return Result.success( + (await compute(_handleDecryptLastMessage, message)).first, + ); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future acceptInvite({required int meetingId}) async { + Future> acceptInvite({required int meetingId}) async { final Response response = await _remoteData.postRoute( '${ApiEndpoints.acceptInvite}/$meetingId', ); @@ -166,14 +181,19 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { "key": WaterbusSdk.privateMessageKey, }; - return (await compute(_handleDecryptLastMessage, message)).first; + return Result.success( + (await compute(_handleDecryptLastMessage, message)).first, + ); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future addMember({required int code, required int userId}) async { + Future> addMember({ + required int code, + required int userId, + }) async { final Response response = await _remoteData.postRoute( '${ApiEndpoints.meetingMembers}/$code', body: {"userId": userId}, @@ -185,14 +205,16 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { "key": WaterbusSdk.privateMessageKey, }; - return (await compute(_handleDecryptLastMessage, message)).first; + return Result.success( + (await compute(_handleDecryptLastMessage, message)).first, + ); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future deleteMember({ + Future> deleteMember({ required int code, required int userId, }) async { @@ -207,14 +229,16 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { "key": WaterbusSdk.privateMessageKey, }; - return (await compute(_handleDecryptLastMessage, message)).first; + return Result.success( + (await compute(_handleDecryptLastMessage, message)).first, + ); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future archivedConversation({required int code}) async { + Future> archivedConversation({required int code}) async { final Response response = await _remoteData.postRoute( '${ApiEndpoints.archivedMeeeting}/$code', ); @@ -225,9 +249,11 @@ class ChatRemoteDataSourceImpl extends ChatRemoteDataSource { "key": WaterbusSdk.privateMessageKey, }; - return (await compute(_handleDecryptLastMessage, message)).first; + return Result.success( + (await compute(_handleDecryptLastMessage, message)).first, + ); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } } diff --git a/lib/core/api/chat/repositories/chat_repository.dart b/lib/core/api/chat/repositories/chat_repository.dart index 38c4ee4..854803d 100644 --- a/lib/core/api/chat/repositories/chat_repository.dart +++ b/lib/core/api/chat/repositories/chat_repository.dart @@ -2,27 +2,31 @@ import 'package:injectable/injectable.dart'; import 'package:waterbus_sdk/core/api/chat/datasources/chat_remote_datasource.dart'; import 'package:waterbus_sdk/flutter_waterbus_sdk.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class ChatRepository { - Future> getConversations({ + Future>> getConversations({ required int status, required int limit, required int skip, }); - Future> getArchivedConversations({ + Future>> getArchivedConversations({ required int skip, required int limit, }); - Future updateConversation({ + Future> updateConversation({ required Meeting meeting, String? password, }); - Future deleteConversation(int meetingId); - Future leaveConversation({required int code}); - Future addMember({required int code, required int userId}); - Future deleteMember({required int code, required int userId}); - Future acceptInvite({required int meetingId}); - Future archivedConversation({required int code}); + Future> deleteConversation(int meetingId); + Future> leaveConversation({required int code}); + Future> addMember({required int code, required int userId}); + Future> deleteMember({ + required int code, + required int userId, + }); + Future> acceptInvite({required int meetingId}); + Future> archivedConversation({required int code}); } @LazySingleton(as: ChatRepository) @@ -34,12 +38,12 @@ class ChatRepositoryImpl extends ChatRepository { ); @override - Future> getConversations({ + Future>> getConversations({ required int status, required limit, required skip, }) async { - final List conversations = + final Result> conversations = await _remoteDataSource.getConversations( skip: skip, limit: limit, @@ -50,11 +54,11 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future> getArchivedConversations({ + Future>> getArchivedConversations({ required limit, required skip, }) async { - final List archivedConversations = + final Result> archivedConversations = await _remoteDataSource.getArchivedConversations( skip: skip, limit: limit, @@ -64,8 +68,8 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future deleteConversation(int meetingId) async { - final bool isSucceed = await _remoteDataSource.deleteConversation( + Future> deleteConversation(int meetingId) async { + final Result isSucceed = await _remoteDataSource.deleteConversation( meetingId: meetingId, ); @@ -73,8 +77,8 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future leaveConversation({required int code}) async { - final Meeting? meeting = await _remoteDataSource.leaveConversation( + Future> leaveConversation({required int code}) async { + final Result meeting = await _remoteDataSource.leaveConversation( code: code, ); @@ -82,8 +86,8 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future acceptInvite({required int meetingId}) async { - final Meeting? meeting = await _remoteDataSource.acceptInvite( + Future> acceptInvite({required int meetingId}) async { + final Result meeting = await _remoteDataSource.acceptInvite( meetingId: meetingId, ); @@ -91,8 +95,11 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future addMember({required int code, required int userId}) async { - final Meeting? member = await _remoteDataSource.addMember( + Future> addMember({ + required int code, + required int userId, + }) async { + final Result member = await _remoteDataSource.addMember( code: code, userId: userId, ); @@ -101,11 +108,11 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future deleteMember({ + Future> deleteMember({ required int code, required int userId, }) async { - final Meeting? meeting = await _remoteDataSource.deleteMember( + final Result meeting = await _remoteDataSource.deleteMember( code: code, userId: userId, ); @@ -114,11 +121,11 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future updateConversation({ + Future> updateConversation({ required Meeting meeting, String? password, }) async { - final bool isSucceed = await _remoteDataSource.updateConversation( + final Result isSucceed = await _remoteDataSource.updateConversation( meeting: meeting, password: password, ); @@ -127,8 +134,9 @@ class ChatRepositoryImpl extends ChatRepository { } @override - Future archivedConversation({required int code}) async { - final Meeting? meeting = await _remoteDataSource.archivedConversation( + Future> archivedConversation({required int code}) async { + final Result meeting = + await _remoteDataSource.archivedConversation( code: code, ); diff --git a/lib/core/api/meetings/datasources/meeting_remote_datesource.dart b/lib/core/api/meetings/datasources/meeting_remote_datesource.dart index 286e157..01598f6 100644 --- a/lib/core/api/meetings/datasources/meeting_remote_datesource.dart +++ b/lib/core/api/meetings/datasources/meeting_remote_datesource.dart @@ -4,29 +4,34 @@ import 'package:injectable/injectable.dart'; import 'package:waterbus_sdk/constants/api_enpoints.dart'; import 'package:waterbus_sdk/constants/http_status_code.dart'; import 'package:waterbus_sdk/core/api/base/base_remote_data.dart'; +import 'package:waterbus_sdk/types/models/exceptions/exceptions.dart'; import 'package:waterbus_sdk/types/models/meeting_model.dart'; import 'package:waterbus_sdk/types/models/record_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class MeetingRemoteDataSource { - Future createMeeting({ + Future> createMeeting({ required Meeting meeting, required String password, }); - Future updateMeeting({ + Future> updateMeeting({ required Meeting meeting, required String password, }); - Future joinMeetingWithPassword({ + Future> joinMeetingWithPassword({ required Meeting meeting, required String password, }); - Future joinMeetingWithoutPassword({ + Future> joinMeetingWithoutPassword({ required Meeting meeting, }); - Future getInfoMeeting(int code); - Future> getRecords({required int skip, required int limit}); - Future startRecord(int roomId); - Future stopRecord(int roomId); + Future> getInfoMeeting(int code); + Future>> getRecords({ + required int skip, + required int limit, + }); + Future> startRecord(int roomId); + Future> stopRecord(int roomId); } @LazySingleton(as: MeetingRemoteDataSource) @@ -37,7 +42,7 @@ class MeetingRemoteDataSourceImpl extends MeetingRemoteDataSource { ); @override - Future createMeeting({ + Future> createMeeting({ required Meeting meeting, required String password, }) async { @@ -48,14 +53,14 @@ class MeetingRemoteDataSourceImpl extends MeetingRemoteDataSource { if (response.statusCode == StatusCode.created) { final Map rawData = response.data; - return Meeting.fromMap(rawData); + return Result.success(Meeting.fromMap(rawData)); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future getInfoMeeting(int code) async { + Future> getInfoMeeting(int code) async { final Response response = await _remoteData.getRoute( '${ApiEndpoints.meetings}/$code', ); @@ -63,14 +68,14 @@ class MeetingRemoteDataSourceImpl extends MeetingRemoteDataSource { if (response.statusCode == StatusCode.ok && response.data.toString().isNotEmpty) { final Map rawData = response.data; - return Meeting.fromMap(rawData); + return Result.success(Meeting.fromMap(rawData)); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future joinMeetingWithPassword({ + Future> joinMeetingWithPassword({ required Meeting meeting, required String password, }) async { @@ -81,16 +86,18 @@ class MeetingRemoteDataSourceImpl extends MeetingRemoteDataSource { if (response.statusCode == StatusCode.created) { final Map rawData = response.data; - return Meeting.fromMap(rawData).copyWith( - latestJoinedAt: DateTime.now(), + return Result.success( + Meeting.fromMap(rawData).copyWith( + latestJoinedAt: DateTime.now(), + ), ); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future joinMeetingWithoutPassword({ + Future> joinMeetingWithoutPassword({ required Meeting meeting, }) async { final Response response = await _remoteData.postRoute( @@ -99,16 +106,18 @@ class MeetingRemoteDataSourceImpl extends MeetingRemoteDataSource { if (response.statusCode == StatusCode.created) { final Map rawData = response.data; - return Meeting.fromMap(rawData).copyWith( - latestJoinedAt: DateTime.now(), + return Result.success( + Meeting.fromMap(rawData).copyWith( + latestJoinedAt: DateTime.now(), + ), ); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future updateMeeting({ + Future> updateMeeting({ required Meeting meeting, required String password, }) async { @@ -117,11 +126,15 @@ class MeetingRemoteDataSourceImpl extends MeetingRemoteDataSource { meeting.toMapCreate(password: password), ); - return response.statusCode == StatusCode.ok; + if (response.statusCode == StatusCode.ok) { + return Result.success(true); + } + + return Result.failure(response.data['message'].toString().meetingException); } @override - Future> getRecords({ + Future>> getRecords({ required int skip, required int limit, }) async { @@ -129,33 +142,39 @@ class MeetingRemoteDataSourceImpl extends MeetingRemoteDataSource { if (response.statusCode == StatusCode.ok) { final List rawData = response.data; - return rawData.map((data) => RecordModel.fromMap(data)).toList(); + return Result.success( + rawData.map((data) => RecordModel.fromMap(data)).toList(), + ); } - return []; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future startRecord(int roomId) async { + Future> startRecord(int roomId) async { final Response response = await _remoteData.postRoute( ApiEndpoints.startRecord, queryParameters: {"code": roomId}, ); if (response.statusCode == StatusCode.created) { - return response.data['id']; + return Result.success(response.data['id']); } - return null; + return Result.failure(response.data['message'].toString().meetingException); } @override - Future stopRecord(int roomId) async { + Future> stopRecord(int roomId) async { final Response response = await _remoteData.postRoute( ApiEndpoints.stopRecord, queryParameters: {"code": roomId}, ); - return response.statusCode == StatusCode.created; + if (response.statusCode == StatusCode.created) { + return Result.success(true); + } + + return Result.failure(response.data['message'].toString().meetingException); } } diff --git a/lib/core/api/meetings/repositories/meeting_repository.dart b/lib/core/api/meetings/repositories/meeting_repository.dart index 61197da..11dbf13 100644 --- a/lib/core/api/meetings/repositories/meeting_repository.dart +++ b/lib/core/api/meetings/repositories/meeting_repository.dart @@ -4,20 +4,24 @@ import 'package:waterbus_sdk/core/api/meetings/datasources/meeting_remote_dateso import 'package:waterbus_sdk/types/index.dart'; import 'package:waterbus_sdk/types/models/create_meeting_params.dart'; import 'package:waterbus_sdk/types/models/record_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class MeetingRepository { - Future createMeeting(CreateMeetingParams params); - Future updateMeeting(CreateMeetingParams params); - Future joinMeetingWithPassword( + Future> createMeeting(CreateMeetingParams params); + Future> updateMeeting(CreateMeetingParams params); + Future> joinMeetingWithPassword( CreateMeetingParams params, ); - Future joinMeetingWithoutPassword( + Future> joinMeetingWithoutPassword( CreateMeetingParams params, ); - Future getInfoMeeting(int code); - Future> getRecords({required int skip, required int limit}); - Future startRecord(int roomId); - Future stopRecord(int roomId); + Future> getInfoMeeting(int code); + Future>> getRecords({ + required int skip, + required int limit, + }); + Future> startRecord(int roomId); + Future> stopRecord(int roomId); } @LazySingleton(as: MeetingRepository) @@ -27,76 +31,79 @@ class MeetingRepositoryImpl extends MeetingRepository { MeetingRepositoryImpl(this._remoteDataSource); @override - Future createMeeting( + Future> createMeeting( CreateMeetingParams params, ) async { - Meeting? meeting = await _remoteDataSource.createMeeting( + Result result = await _remoteDataSource.createMeeting( meeting: params.meeting, password: params.password, ); - if (meeting == null) return null; + if (result.isFailure) return result; - meeting = findMyParticipantObject(meeting, userId: params.userId); + result = Result.success( + findMyParticipantObject(result.value!, userId: params.userId), + ); - return meeting; + return result; } @override - Future getInfoMeeting(int code) async { - final Meeting? meeting = await _remoteDataSource.getInfoMeeting(code); - - if (meeting == null) return null; + Future> getInfoMeeting(int code) async { + final Result meeting = + await _remoteDataSource.getInfoMeeting(code); return meeting; } @override - Future joinMeetingWithPassword( + Future> joinMeetingWithPassword( CreateMeetingParams params, ) async { - Meeting? meeting = await _remoteDataSource.joinMeetingWithPassword( + Result result = await _remoteDataSource.joinMeetingWithPassword( meeting: params.meeting, password: params.password, ); - if (meeting == null) return null; + if (result.isFailure) return result; - meeting = findMyParticipantObject(meeting, userId: params.userId); + result = Result.success( + findMyParticipantObject(result.value!, userId: params.userId), + ); - return meeting; + return result; } @override - Future joinMeetingWithoutPassword( + Future> joinMeetingWithoutPassword( CreateMeetingParams params, ) async { - Meeting? meeting = await _remoteDataSource.joinMeetingWithoutPassword( + Result result = await _remoteDataSource.joinMeetingWithoutPassword( meeting: params.meeting, ); - if (meeting == null) return null; + if (result.isFailure) return result; - meeting = findMyParticipantObject( - meeting, - userId: params.userId, + result = Result.success( + findMyParticipantObject( + result.value!, + userId: params.userId, + ), ); - return meeting; + return result; } @override - Future updateMeeting( + Future> updateMeeting( CreateMeetingParams params, ) async { - final bool isUpdateSucceed = await _remoteDataSource.updateMeeting( + final Result isUpdateSucceed = await _remoteDataSource.updateMeeting( meeting: params.meeting, password: params.password, ); - if (!isUpdateSucceed) return null; - - return params.meeting; + return isUpdateSucceed; } // MARK: private @@ -123,7 +130,7 @@ class MeetingRepositoryImpl extends MeetingRepository { } @override - Future> getRecords({ + Future>> getRecords({ required int skip, required int limit, }) async { @@ -131,12 +138,12 @@ class MeetingRepositoryImpl extends MeetingRepository { } @override - Future startRecord(int roomId) async { + Future> startRecord(int roomId) async { return await _remoteDataSource.startRecord(roomId); } @override - Future stopRecord(int roomId) async { + Future> stopRecord(int roomId) async { return await _remoteDataSource.stopRecord(roomId); } } diff --git a/lib/core/api/messages/datasources/message_remote_datasource.dart b/lib/core/api/messages/datasources/message_remote_datasource.dart index 03f9efc..222bf01 100644 --- a/lib/core/api/messages/datasources/message_remote_datasource.dart +++ b/lib/core/api/messages/datasources/message_remote_datasource.dart @@ -7,24 +7,26 @@ import 'package:waterbus_sdk/constants/api_enpoints.dart'; import 'package:waterbus_sdk/constants/http_status_code.dart'; import 'package:waterbus_sdk/core/api/base/base_remote_data.dart'; import 'package:waterbus_sdk/flutter_waterbus_sdk.dart'; +import 'package:waterbus_sdk/types/models/exceptions/exceptions.dart'; +import 'package:waterbus_sdk/types/result.dart'; import 'package:waterbus_sdk/utils/encrypt/encrypt.dart'; abstract class MessageRemoteDataSource { - Future> getMessageByRoom({ + Future>> getMessageByRoom({ required int meetingId, required int limit, required int skip, }); - Future sendMessage({ + Future> sendMessage({ required int meetingId, required String data, }); - Future editMessage({ + Future> editMessage({ required int messageId, required String data, }); - Future deleteMessage({required int messageId}); + Future> deleteMessage({required int messageId}); } @LazySingleton(as: MessageRemoteDataSource) @@ -36,7 +38,7 @@ class MessageRemoteDataSourceImpl extends MessageRemoteDataSource { ); @override - Future> getMessageByRoom({ + Future>> getMessageByRoom({ required int meetingId, required int limit, required int skip, @@ -51,13 +53,17 @@ class MessageRemoteDataSourceImpl extends MessageRemoteDataSource { .map((message) => MessageModel.fromMap(message)) .toList(); - return await compute(_handleDecryptMessages, { - "messages": messages, - "key": WaterbusSdk.privateMessageKey, - }); + return Result.success( + await compute(_handleDecryptMessages, { + "messages": messages, + "key": WaterbusSdk.privateMessageKey, + }), + ); } - return []; + return Result.failure( + (response.data['message'] as String).messageException, + ); } static Future> _handleDecryptMessages( @@ -78,7 +84,7 @@ class MessageRemoteDataSourceImpl extends MessageRemoteDataSource { } @override - Future sendMessage({ + Future> sendMessage({ required int meetingId, required String data, }) async { @@ -91,14 +97,18 @@ class MessageRemoteDataSourceImpl extends MessageRemoteDataSource { ); if ([StatusCode.ok, StatusCode.created].contains(response.statusCode)) { - return MessageModel.fromMap(response.data).copyWith(data: data); + return Result.success( + MessageModel.fromMap(response.data).copyWith(data: data), + ); } - return null; + return Result.failure( + (response.data['message'] as String).messageException, + ); } @override - Future editMessage({ + Future> editMessage({ required int messageId, required String data, }) async { @@ -110,22 +120,30 @@ class MessageRemoteDataSourceImpl extends MessageRemoteDataSource { ); if ([StatusCode.ok, StatusCode.created].contains(response.statusCode)) { - return MessageModel.fromMap(response.data).copyWith(data: data); + return Result.success( + MessageModel.fromMap(response.data).copyWith(data: data), + ); } - return null; + return Result.failure( + (response.data['message'] as String).messageException, + ); } @override - Future deleteMessage({required int messageId}) async { + Future> deleteMessage({ + required int messageId, + }) async { final Response response = await _remoteData.deleteRoute( "${ApiEndpoints.chats}/$messageId", ); if ([StatusCode.ok, StatusCode.created].contains(response.statusCode)) { - return MessageModel.fromMap(response.data); + return Result.success(MessageModel.fromMap(response.data)); } - return null; + return Result.failure( + (response.data['message'] as String).messageException, + ); } } diff --git a/lib/core/api/messages/repositories/message_repository.dart b/lib/core/api/messages/repositories/message_repository.dart index 4ddbdbb..eb826c1 100644 --- a/lib/core/api/messages/repositories/message_repository.dart +++ b/lib/core/api/messages/repositories/message_repository.dart @@ -2,23 +2,24 @@ import 'package:injectable/injectable.dart'; import 'package:waterbus_sdk/core/api/messages/datasources/message_remote_datasource.dart'; import 'package:waterbus_sdk/types/models/message_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class MessageRepository { - Future> getMessageByRoom({ + Future>> getMessageByRoom({ required int meetingId, required int limit, required int skip, }); - Future sendMessage({ + Future> sendMessage({ required int meetingId, required String data, }); - Future editMessage({ + Future> editMessage({ required int messageId, required String data, }); - Future deleteMessage({required int messageId}); + Future> deleteMessage({required int messageId}); } @LazySingleton(as: MessageRepository) @@ -30,46 +31,46 @@ class MessageRepositoryImpl extends MessageRepository { ); @override - Future deleteMessage({required int messageId}) async { - final MessageModel? messageModel = + Future> deleteMessage({required int messageId}) async { + final Result messageModel = await _remoteDataSource.deleteMessage(messageId: messageId); return messageModel; } @override - Future editMessage({ + Future> editMessage({ required int messageId, required String data, }) async { - final MessageModel? messageModel = + final Result messageModel = await _remoteDataSource.editMessage(messageId: messageId, data: data); return messageModel; } @override - Future> getMessageByRoom({ + Future>> getMessageByRoom({ required int meetingId, required int limit, required int skip, }) async { - final List messages = + final Result> result = await _remoteDataSource.getMessageByRoom( meetingId: meetingId, skip: skip, limit: limit, ); - return messages; + return result; } @override - Future sendMessage({ + Future> sendMessage({ required int meetingId, required String data, }) async { - final MessageModel? message = + final Result message = await _remoteDataSource.sendMessage(meetingId: meetingId, data: data); return message; diff --git a/lib/core/api/user/datasources/user_remote_datasource.dart b/lib/core/api/user/datasources/user_remote_datasource.dart index b59a9a9..806cb1e 100644 --- a/lib/core/api/user/datasources/user_remote_datasource.dart +++ b/lib/core/api/user/datasources/user_remote_datasource.dart @@ -10,20 +10,23 @@ import 'package:injectable/injectable.dart'; import 'package:waterbus_sdk/constants/api_enpoints.dart'; import 'package:waterbus_sdk/constants/http_status_code.dart'; import 'package:waterbus_sdk/core/api/base/base_remote_data.dart'; +import 'package:waterbus_sdk/types/error/failures.dart'; +import 'package:waterbus_sdk/types/models/exceptions/exceptions.dart'; import 'package:waterbus_sdk/types/models/user_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class UserRemoteDataSource { - Future getUserProfile(); - Future updateUserProfile(User user); - Future updateUsername(String username); - Future checkUsername(String username); - Future> searchUsers({ + Future> getUserProfile(); + Future> updateUserProfile(User user); + Future> updateUsername(String username); + Future> checkUsername(String username); + Future>> searchUsers({ required String keyword, required int skip, required int limit, }); - Future getPresignedUrl(); - Future uploadImageToS3({ + Future> getPresignedUrl(); + Future> uploadImageToS3({ required String uploadUrl, required Uint8List image, }); @@ -35,21 +38,21 @@ class UserRemoteDataSourceImpl extends UserRemoteDataSource { UserRemoteDataSourceImpl(this._remoteData); @override - Future getPresignedUrl() async { + Future> getPresignedUrl() async { final Response response = await _remoteData.postRoute( ApiEndpoints.presignedUrlS3, ); if (response.statusCode == StatusCode.created) { final Map rawData = response.data; - return rawData['presignedUrl']; + return Result.success(rawData['presignedUrl']); } - return null; + return Result.failure(ServerFailure()); } @override - Future uploadImageToS3({ + Future> uploadImageToS3({ required String uploadUrl, required Uint8List image, }) async { @@ -63,62 +66,70 @@ class UserRemoteDataSourceImpl extends UserRemoteDataSource { ); if (response.statusCode == StatusCode.ok) { - return uploadUrl.split('?').first; + return Result.success(uploadUrl.split('?').first); } - return null; + return Result.failure(ServerFailure()); } catch (error) { - return null; + return Result.failure(ServerFailure()); } } @override - Future getUserProfile() async { + Future> getUserProfile() async { final Response response = await _remoteData.getRoute(ApiEndpoints.users); if (response.statusCode == StatusCode.ok) { final Map rawData = response.data; - return User.fromMap(rawData); + return Result.success(User.fromMap(rawData)); } - return null; + return Result.failure(response.data['message'].toString().userException); } @override - Future updateUserProfile(User user) async { + Future> updateUserProfile(User user) async { final Response response = await _remoteData.putRoute( ApiEndpoints.users, user.toMap(), ); - return response.statusCode == StatusCode.ok; + if (response.statusCode == StatusCode.ok) { + return Result.success(true); + } + + return Result.failure(response.data['message'].toString().userException); } @override - Future updateUsername(String username) async { + Future> updateUsername(String username) async { final Response response = await _remoteData.putRoute( "${ApiEndpoints.username}/$username", {}, ); - return response.statusCode == StatusCode.ok; + if (response.statusCode == StatusCode.ok) { + return Result.success(true); + } + + return Result.failure(response.data['message'].toString().userException); } @override - Future checkUsername(String username) async { + Future> checkUsername(String username) async { final Response response = await _remoteData.getRoute( "${ApiEndpoints.username}/$username", ); if (response.statusCode == StatusCode.ok) { - return response.data['isRegistered'] ?? false; + return Result.success(response.data['isRegistered'] ?? false); } - return false; + return Result.failure(response.data['message'].toString().userException); } @override - Future> searchUsers({ + Future>> searchUsers({ required String keyword, required int skip, required int limit, @@ -131,9 +142,11 @@ class UserRemoteDataSourceImpl extends UserRemoteDataSource { if (response.statusCode == StatusCode.ok) { final List data = response.data['hits']; - return data.map((user) => User.fromMap(user['document'])).toList(); + return Result.success( + data.map((user) => User.fromMap(user['document'])).toList(), + ); } - return []; + return Result.failure(response.data['message'].toString().userException); } } diff --git a/lib/core/api/user/repositories/user_repository.dart b/lib/core/api/user/repositories/user_repository.dart index ed83040..be819d9 100644 --- a/lib/core/api/user/repositories/user_repository.dart +++ b/lib/core/api/user/repositories/user_repository.dart @@ -4,18 +4,19 @@ import 'package:injectable/injectable.dart'; import 'package:waterbus_sdk/core/api/user/datasources/user_remote_datasource.dart'; import 'package:waterbus_sdk/types/models/user_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class UserRepository { - Future getUserProfile(); - Future updateUserProfile(User user); - Future updateUsername(String username); - Future checkUsername(String username); - Future getPresignedUrl(); - Future uploadImageToS3({ + Future> getUserProfile(); + Future> updateUserProfile(User user); + Future> updateUsername(String username); + Future> checkUsername(String username); + Future> getPresignedUrl(); + Future> uploadImageToS3({ required String uploadUrl, required Uint8List image, }); - Future> searchUsers({ + Future>> searchUsers({ required String keyword, required int skip, required int limit, @@ -29,70 +30,68 @@ class UserRepositoryImpl extends UserRepository { UserRepositoryImpl(this._remoteDataSource); @override - Future getUserProfile() async { - final User? user = await _remoteDataSource.getUserProfile(); + Future> getUserProfile() async { + final Result user = await _remoteDataSource.getUserProfile(); return user; } @override - Future updateUserProfile(User user) async { - final bool isUpdateSucceed = await _remoteDataSource.updateUserProfile( + Future> updateUserProfile(User user) async { + final Result result = await _remoteDataSource.updateUserProfile( user, ); - if (!isUpdateSucceed) return null; - - return user; + return result; } @override - Future getPresignedUrl() async { - final String? presignedUrl = await _remoteDataSource.getPresignedUrl(); + Future> getPresignedUrl() async { + final Result result = await _remoteDataSource.getPresignedUrl(); - return presignedUrl; + return result; } @override - Future uploadImageToS3({ + Future> uploadImageToS3({ required String uploadUrl, required Uint8List image, }) async { - final String? urlToImage = await _remoteDataSource.uploadImageToS3( + final Result result = await _remoteDataSource.uploadImageToS3( uploadUrl: uploadUrl, image: image, ); - return urlToImage; + return result; } @override - Future updateUsername(String username) async { - final bool isUpdateSucceed = + Future> updateUsername(String username) async { + final Result result = await _remoteDataSource.updateUsername(username); - return isUpdateSucceed; + return result; } @override - Future checkUsername(String username) async { - final bool? isRegistered = await _remoteDataSource.checkUsername(username); + Future> checkUsername(String username) async { + final Result result = await _remoteDataSource.checkUsername(username); - return isRegistered ?? false; + return result; } @override - Future> searchUsers({ + Future>> searchUsers({ required String keyword, required int skip, required int limit, }) async { - final List users = await _remoteDataSource.searchUsers( + final Result> result = await _remoteDataSource.searchUsers( keyword: keyword, limit: limit, skip: skip, ); - return users; + return result; } } diff --git a/lib/flutter_waterbus_sdk.dart b/lib/flutter_waterbus_sdk.dart index 790f7d2..d3d8683 100644 --- a/lib/flutter_waterbus_sdk.dart +++ b/lib/flutter_waterbus_sdk.dart @@ -1,4 +1,4 @@ -library waterbus_sdk; +library; import 'package:flutter/foundation.dart'; @@ -12,6 +12,7 @@ import 'package:waterbus_sdk/types/index.dart'; import 'package:waterbus_sdk/types/models/conversation_socket_event.dart'; import 'package:waterbus_sdk/types/models/draw_model.dart'; import 'package:waterbus_sdk/types/models/record_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; import 'package:waterbus_sdk/utils/callkit/callkit_listener.dart'; import 'package:waterbus_sdk/waterbus_sdk_interface.dart'; @@ -85,7 +86,7 @@ class WaterbusSdk { } // Meeting - Future createRoom({ + Future> createRoom({ required Meeting meeting, required String password, required int? userId, @@ -97,7 +98,7 @@ class WaterbusSdk { ); } - Future joinRoom({ + Future> joinRoom({ required Meeting meeting, required String password, required int? userId, @@ -109,7 +110,7 @@ class WaterbusSdk { ); } - Future updateRoom({ + Future> updateRoom({ required Meeting meeting, required String password, required int? userId, @@ -121,19 +122,22 @@ class WaterbusSdk { ); } - Future getRoomInfo({required int code}) async { + Future> getRoomInfo({required int code}) async { return await _sdk.getRoomInfo(code); } - Future> getRecords({int skip = 0, int limit = 10}) async { + Future>> getRecords({ + int skip = 0, + int limit = 10, + }) async { return await _sdk.getRecords(skip: skip, limit: limit); } - Future startRecord() async { + Future> startRecord() async { return await _sdk.startRecord(); } - Future stopRecord() async { + Future> stopRecord() async { return await _sdk.stopRecord(); } @@ -242,38 +246,38 @@ class WaterbusSdk { } // User - Future getProfile() async { + Future> getProfile() async { return await _sdk.getProfile(); } - Future updateProfile({required User user}) async { + Future> updateProfile({required User user}) async { return await _sdk.updateProfile(user: user); } - Future updateUsername({ + Future> updateUsername({ required String username, }) async { return await _sdk.updateUsername(username: username); } - Future checkUsername({ + Future> checkUsername({ required String username, }) async { return await _sdk.checkUsername(username: username); } - Future getPresignedUrl() async { + Future> getPresignedUrl() async { return await _sdk.getPresignedUrl(); } - Future uploadAvatar({ + Future> uploadAvatar({ required Uint8List image, required String uploadUrl, }) async { return await _sdk.uploadAvatar(image: image, uploadUrl: uploadUrl); } - Future> searchUsers({ + Future>> searchUsers({ required String keyword, required int skip, int limit = 10, @@ -282,31 +286,31 @@ class WaterbusSdk { } // Chat - Future addMember(int code, int userId) async { + Future> addMember(int code, int userId) async { return await _sdk.addMember(code: code, userId: userId); } - Future deleteMember(int code, int userId) async { + Future> deleteMember(int code, int userId) async { return await _sdk.deleteMember(code: code, userId: userId); } - Future acceptInvite(int meetingId) async { + Future> acceptInvite(int meetingId) async { return await _sdk.acceptInvite(meetingId: meetingId); } - Future leaveConversation(int code) async { + Future> leaveConversation(int code) async { return await _sdk.leaveConversation(code: code); } - Future archivedConversation(int code) async { + Future> archivedConversation(int code) async { return await _sdk.archivedConversation(code: code); } - Future deleteConversation(int conversationId) async { + Future> deleteConversation(int conversationId) async { return await _sdk.deleteConversation(conversationId); } - Future> getConversations({ + Future>> getConversations({ required int skip, int limit = 10, int status = 2, @@ -318,7 +322,7 @@ class WaterbusSdk { ); } - Future> getArchivedConversations({ + Future>> getArchivedConversations({ required int skip, int limit = 10, }) async { @@ -328,7 +332,7 @@ class WaterbusSdk { ); } - Future updateConversation({ + Future> updateConversation({ required Meeting meeting, String? password, }) async { @@ -339,7 +343,7 @@ class WaterbusSdk { } // Messages - Future> getMessageByRoom({ + Future>> getMessageByRoom({ required int meetingId, required int skip, int limit = 10, @@ -351,34 +355,34 @@ class WaterbusSdk { ); } - Future sendMessage({ + Future> sendMessage({ required int meetingId, required String data, }) async { return await _sdk.sendMessage(meetingId: meetingId, data: data); } - Future editMessage({ + Future> editMessage({ required int messageId, required String data, }) async { return await _sdk.editMessage(messageId: messageId, data: data); } - Future deleteMessage({required int messageId}) async { + Future> deleteMessage({required int messageId}) async { return await _sdk.deleteMessage(messageId: messageId); } // Auth - Future createToken(AuthPayloadModel payload) async { + Future> createToken(AuthPayloadModel payload) async { return await _sdk.createToken(payload: payload); } - Future deleteToken() async { + Future> deleteToken() async { return await _sdk.deleteToken(); } - Future renewToken() async { + Future> renewToken() async { return await _sdk.refreshToken(); } diff --git a/lib/native/picture-in-picture/pip_web.dart b/lib/native/picture-in-picture/pip_web.dart index b557921..13d2eac 100644 --- a/lib/native/picture-in-picture/pip_web.dart +++ b/lib/native/picture-in-picture/pip_web.dart @@ -1,5 +1,5 @@ @JS() -library t; +library; import 'dart:js_interop'; diff --git a/lib/native/virtual_background/virtual_background_web.dart b/lib/native/virtual_background/virtual_background_web.dart index dcc19d1..970ebbd 100644 --- a/lib/native/virtual_background/virtual_background_web.dart +++ b/lib/native/virtual_background/virtual_background_web.dart @@ -1,5 +1,5 @@ @JS() -library t; +library; import 'dart:convert'; import 'dart:js_interop'; diff --git a/lib/types/error/failures.dart b/lib/types/error/failures.dart index 79b6373..17892da 100644 --- a/lib/types/error/failures.dart +++ b/lib/types/error/failures.dart @@ -1,5 +1,9 @@ import 'package:equatable/equatable.dart'; +part "meeting_failure.dart"; +part "message_failure.dart"; +part "user_failure.dart"; + abstract class Failure extends Equatable { final String? message; diff --git a/lib/types/error/meeting_failure.dart b/lib/types/error/meeting_failure.dart new file mode 100644 index 0000000..b845138 --- /dev/null +++ b/lib/types/error/meeting_failure.dart @@ -0,0 +1,33 @@ +part of 'failures.dart'; + +class RoomNotFound extends Failure {} + +class NotAllowedToUpdateRoom extends Failure {} + +class WrongPassword extends Failure {} + +class NotAllowToJoinDirectly extends Failure {} + +class NotExistsParticipant extends Failure {} + +class NotExistsCCU extends Failure {} + +class IsAlreadyInRoom extends Failure {} + +class HostNotFound extends Failure {} + +class NotAllowToAddUser extends Failure {} + +class HasNotJoinedMeeting extends Failure {} + +class MemberNotFound extends Failure {} + +class ParticipantNotFound extends Failure {} + +class OnlyAllowHostStartRecord extends Failure {} + +class OnlyAllowHostStopRecord extends Failure {} + +class NotAllowedToLeaveTheRoom extends Failure {} + +class OnlyHostPermitedToArchivedTheRoom extends Failure {} diff --git a/lib/types/error/message_failure.dart b/lib/types/error/message_failure.dart new file mode 100644 index 0000000..5d9f551 --- /dev/null +++ b/lib/types/error/message_failure.dart @@ -0,0 +1,9 @@ +part of 'failures.dart'; + +class NotAllowedGetMessages extends Failure {} + +class NotAllowedModifyMessage extends Failure {} + +class MessageNotFound extends Failure {} + +class MessageHasBeenDelete extends Failure {} diff --git a/lib/types/error/user_failure.dart b/lib/types/error/user_failure.dart new file mode 100644 index 0000000..ee8821e --- /dev/null +++ b/lib/types/error/user_failure.dart @@ -0,0 +1,5 @@ +part of 'failures.dart'; + +class UserNotFound extends Failure {} + +class UserIsAlreadyUsed extends Failure {} diff --git a/lib/types/models/exceptions/exceptions.dart b/lib/types/models/exceptions/exceptions.dart new file mode 100644 index 0000000..5de8e66 --- /dev/null +++ b/lib/types/models/exceptions/exceptions.dart @@ -0,0 +1,5 @@ +import 'package:waterbus_sdk/types/error/failures.dart'; + +part "meeting_exceptions.dart"; +part "message_exceptions.dart"; +part "user_exceptions.dart"; diff --git a/lib/types/models/exceptions/meeting_exceptions.dart b/lib/types/models/exceptions/meeting_exceptions.dart new file mode 100644 index 0000000..050461e --- /dev/null +++ b/lib/types/models/exceptions/meeting_exceptions.dart @@ -0,0 +1,60 @@ +part of 'exceptions.dart'; + +enum MeetingException { + roomNotFound("Room Not Found"), + userNotFound('User not found'), + notAllowedToUpdateRoom('User not allowed to update rooom'), + wrongPassword('Wrong password!'), + notAllowToJoinDirectly('User not allow to join directly'), + notExistsParticipant('Not exists participant'), + notExistsCCU('Not exists CCU'), + isAlreadyInRoom('User already in room'), + hostNotFound('Host not found'), + notAllowToAddUser('You not allow to add user'), + hasNotJoinedMeeting('User not joined meeting'), + memberNotFound('Member Not Found'), + participantNotFound('Participant Not Found'), + onlyAllowHostStartRecord('Only allow host start record'), + onlyAllowHostStopRecord('Only allow host stop record'), + notAllowedToLeaveTheRoom( + 'Host not allowed to leave the room. You can archive chats if the room no longer active.', + ), + onlyHostPermitedToArchivedTheRoom('Only Host permited to archived the room.'), + ; + + const MeetingException(this.message); + + final String message; + + Failure get meetingFailure => switch (this) { + MeetingException.roomNotFound => RoomNotFound(), + MeetingException.userNotFound => UserNotFound(), + MeetingException.notAllowedToUpdateRoom => NotAllowedToUpdateRoom(), + MeetingException.wrongPassword => WrongPassword(), + MeetingException.notAllowToJoinDirectly => NotAllowToJoinDirectly(), + MeetingException.notExistsParticipant => NotExistsParticipant(), + MeetingException.notExistsCCU => NotExistsCCU(), + MeetingException.isAlreadyInRoom => IsAlreadyInRoom(), + MeetingException.hostNotFound => HostNotFound(), + MeetingException.notAllowToAddUser => NotAllowToAddUser(), + MeetingException.hasNotJoinedMeeting => HasNotJoinedMeeting(), + MeetingException.memberNotFound => MemberNotFound(), + MeetingException.participantNotFound => ParticipantNotFound(), + MeetingException.onlyAllowHostStartRecord => OnlyAllowHostStartRecord(), + MeetingException.onlyAllowHostStopRecord => OnlyAllowHostStopRecord(), + MeetingException.notAllowedToLeaveTheRoom => NotAllowedToLeaveTheRoom(), + MeetingException.onlyHostPermitedToArchivedTheRoom => + OnlyHostPermitedToArchivedTheRoom(), + }; +} + +extension MeetingExceptionX on String { + Failure get meetingException { + final int index = MeetingException.values + .indexWhere((exception) => exception.message == this); + + if (index == -1) return ServerFailure(); + + return MeetingException.values[index].meetingFailure; + } +} diff --git a/lib/types/models/exceptions/message_exceptions.dart b/lib/types/models/exceptions/message_exceptions.dart new file mode 100644 index 0000000..ef1445c --- /dev/null +++ b/lib/types/models/exceptions/message_exceptions.dart @@ -0,0 +1,37 @@ +part of 'exceptions.dart'; + +enum MessageException { + roomNotFound("Room Not Found"), + notAllowedGetMessages( + "You not allowed get messages from room that you not stay in there", + ), + notAllowedModifyMessage("You not allowed modify message of other users"), + userNotFound('User not found'), + messageHasBeenDelete('Message has been deleted'), + messageNotFound("Message not found"), + ; + + const MessageException(this.message); + + final String message; + + Failure get messageFailure => switch (this) { + MessageException.roomNotFound => RoomNotFound(), + MessageException.userNotFound => UserNotFound(), + MessageException.messageNotFound => MessageNotFound(), + MessageException.messageHasBeenDelete => MessageHasBeenDelete(), + MessageException.notAllowedGetMessages => NotAllowedGetMessages(), + MessageException.notAllowedModifyMessage => NotAllowedModifyMessage(), + }; +} + +extension MessageExceptionX on String { + Failure get messageException { + final int index = MessageException.values + .indexWhere((exception) => exception.message == this); + + if (index == -1) return ServerFailure(); + + return MessageException.values[index].messageFailure; + } +} diff --git a/lib/types/models/exceptions/user_exceptions.dart b/lib/types/models/exceptions/user_exceptions.dart new file mode 100644 index 0000000..ac9ae08 --- /dev/null +++ b/lib/types/models/exceptions/user_exceptions.dart @@ -0,0 +1,27 @@ +part of 'exceptions.dart'; + +enum UserException { + userNotFound("User not found"), + usernameIsAlreadyUsed("Username is already used"), + ; + + const UserException(this.message); + + final String message; + + Failure get userFailure => switch (this) { + UserException.userNotFound => UserNotFound(), + UserException.usernameIsAlreadyUsed => UserIsAlreadyUsed(), + }; +} + +extension UserExceptionX on String { + Failure get userException { + final int index = UserException.values + .indexWhere((exception) => exception.message == this); + + if (index == -1) return ServerFailure(); + + return UserException.values[index].userFailure; + } +} diff --git a/lib/utils/http/dio_transformer.dart b/lib/utils/http/dio_transformer.dart index 53cd629..8dc0e9d 100644 --- a/lib/utils/http/dio_transformer.dart +++ b/lib/utils/http/dio_transformer.dart @@ -1,4 +1,4 @@ -library dio_flutter_transformer; +library; import 'dart:convert'; diff --git a/lib/waterbus_sdk_impl.dart b/lib/waterbus_sdk_impl.dart index 26aa3b1..ad3a26c 100644 --- a/lib/waterbus_sdk_impl.dart +++ b/lib/waterbus_sdk_impl.dart @@ -17,9 +17,11 @@ import 'package:waterbus_sdk/flutter_waterbus_sdk.dart'; import 'package:waterbus_sdk/native/picture-in-picture/index.dart'; import 'package:waterbus_sdk/native/replaykit.dart'; import 'package:waterbus_sdk/types/enums/draw_action.dart'; +import 'package:waterbus_sdk/types/error/failures.dart'; import 'package:waterbus_sdk/types/models/create_meeting_params.dart'; import 'package:waterbus_sdk/types/models/draw_model.dart'; import 'package:waterbus_sdk/types/models/record_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; import 'package:waterbus_sdk/utils/logger/logger.dart'; import 'package:waterbus_sdk/utils/replaykit/replaykit_helper.dart'; import 'package:waterbus_sdk/waterbus_sdk_interface.dart'; @@ -73,7 +75,7 @@ class SdkCore extends WaterbusSdkInterface { // Meeting @override - Future createRoom({ + Future> createRoom({ required Meeting meeting, required String password, required int? userId, @@ -88,14 +90,14 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future joinRoom({ + Future> joinRoom({ required Meeting meeting, required String password, required int? userId, }) async { - if (!_webSocket.isConnected) return null; + if (!_webSocket.isConnected) return Result.failure(ServerFailure()); - late final Meeting? room; + late final Result room; if (password.isEmpty) { room = await _meetingRepository.joinMeetingWithoutPassword( @@ -115,19 +117,21 @@ class SdkCore extends WaterbusSdkInterface { ); } - if (room != null) { - final int mParticipantIndex = room.participants.lastIndexWhere( + if (room.value != null) { + final Meeting meeting = room.value!; + + final int mParticipantIndex = meeting.participants.lastIndexWhere( (participant) => participant.isMe, ); - if (mParticipantIndex < 0) return null; + if (mParticipantIndex < 0) return Result.failure(ServerFailure()); await _joinRoom( - roomId: room.code.toString(), - participantId: room.participants[mParticipantIndex].id, + roomId: meeting.code.toString(), + participantId: meeting.participants[mParticipantIndex].id, ); - final List targetIds = room.participants + final List targetIds = meeting.participants .where((participant) => !participant.isMe) .map((participant) => participant.id.toString()) .toList(); @@ -135,11 +139,11 @@ class SdkCore extends WaterbusSdkInterface { _subscribe(targetIds); } - return room; + return Result.success(meeting); } @override - Future updateRoom({ + Future> updateRoom({ required Meeting meeting, required String password, required int? userId, @@ -154,12 +158,12 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future getRoomInfo(int code) async { + Future> getRoomInfo(int code) async { return await _meetingRepository.getInfoMeeting(code); } @override - Future> getRecords({ + Future>> getRecords({ required int skip, required int limit, }) async { @@ -167,19 +171,19 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future startRecord() async { + Future> startRecord() async { final String? meetingId = _rtcManager.roomId; - if (meetingId == null) return null; + if (meetingId == null) return Result.failure(ServerFailure()); return await _meetingRepository.startRecord(int.parse(meetingId)); } @override - Future stopRecord() async { + Future> stopRecord() async { final String? meetingId = _rtcManager.roomId; - if (meetingId == null) return false; + if (meetingId == null) return Result.failure(ServerFailure()); return await _meetingRepository.stopRecord(int.parse(meetingId)); } @@ -322,12 +326,12 @@ class SdkCore extends WaterbusSdkInterface { // Chat @override - Future deleteConversation(int conversationId) async { + Future> deleteConversation(int conversationId) async { return await _chatRepository.deleteConversation(conversationId); } @override - Future> getConversations({ + Future>> getConversations({ required int skip, int limit = 10, int status = 2, @@ -340,7 +344,7 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future> getArchivedConversations({ + Future>> getArchivedConversations({ int limit = 10, required int skip, }) async { @@ -351,7 +355,7 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future updateConversation({ + Future> updateConversation({ required Meeting meeting, String? password, }) async { @@ -362,27 +366,30 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future acceptInvite({required int meetingId}) async { + Future> acceptInvite({required int meetingId}) async { return await _chatRepository.acceptInvite(meetingId: meetingId); } @override - Future addMember({required int code, required int userId}) async { + Future> addMember({ + required int code, + required int userId, + }) async { return await _chatRepository.addMember(code: code, userId: userId); } @override - Future leaveConversation({required int code}) async { + Future> leaveConversation({required int code}) async { return await _chatRepository.leaveConversation(code: code); } @override - Future archivedConversation({required int code}) async { + Future> archivedConversation({required int code}) async { return await _chatRepository.archivedConversation(code: code); } @override - Future deleteMember({ + Future> deleteMember({ required int code, required int userId, }) async { @@ -391,7 +398,7 @@ class SdkCore extends WaterbusSdkInterface { // Messages @override - Future> getMessageByRoom({ + Future>> getMessageByRoom({ required int meetingId, required int skip, int limit = 10, @@ -404,7 +411,7 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future sendMessage({ + Future> sendMessage({ required int meetingId, required String data, }) async { @@ -415,7 +422,7 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future editMessage({ + Future> editMessage({ required int messageId, required String data, }) async { @@ -426,42 +433,42 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future deleteMessage({required int messageId}) async { + Future> deleteMessage({required int messageId}) async { return await _messageRepository.deleteMessage(messageId: messageId); } // User @override - Future getProfile() async { + Future> getProfile() async { return await _userRepository.getUserProfile(); } @override - Future updateProfile({required User user}) async { + Future> updateProfile({required User user}) async { return await _userRepository.updateUserProfile(user); } @override - Future updateUsername({ + Future> updateUsername({ required String username, }) async { return await _userRepository.updateUsername(username); } @override - Future checkUsername({ + Future> checkUsername({ required String username, }) async { return await _userRepository.checkUsername(username); } @override - Future getPresignedUrl() async { + Future> getPresignedUrl() async { return await _userRepository.getPresignedUrl(); } @override - Future uploadAvatar({ + Future> uploadAvatar({ required Uint8List image, required String uploadUrl, }) async { @@ -472,7 +479,7 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future> searchUsers({ + Future>> searchUsers({ required String keyword, required int skip, required int limit, @@ -486,10 +493,10 @@ class SdkCore extends WaterbusSdkInterface { // Auth @override - Future createToken({required AuthPayloadModel payload}) async { - final User? user = await _authRepository.loginWithSocial(payload); + Future> createToken({required AuthPayloadModel payload}) async { + final Result user = await _authRepository.loginWithSocial(payload); - if (user != null) { + if (user.isSuccess) { _webSocket.establishConnection(forceConnection: true); } @@ -497,14 +504,14 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future deleteToken() async { + Future> deleteToken() async { _webSocket.disconnection(); return await _authRepository.logOut(); } @override - Future refreshToken() async { + Future> refreshToken() async { return await _authRepository.refreshToken(); } diff --git a/lib/waterbus_sdk_interface.dart b/lib/waterbus_sdk_interface.dart index 234e12b..cda0c23 100644 --- a/lib/waterbus_sdk_interface.dart +++ b/lib/waterbus_sdk_interface.dart @@ -4,89 +4,95 @@ import 'package:waterbus_sdk/flutter_waterbus_sdk.dart'; import 'package:waterbus_sdk/types/enums/draw_action.dart'; import 'package:waterbus_sdk/types/models/draw_model.dart'; import 'package:waterbus_sdk/types/models/record_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; abstract class WaterbusSdkInterface { Future initializeApp(); // Auth - Future createToken({required AuthPayloadModel payload}); - Future deleteToken(); - Future refreshToken(); + Future> createToken({required AuthPayloadModel payload}); + Future> deleteToken(); + Future> refreshToken(); // User - Future getProfile(); - Future updateProfile({required User user}); - Future updateUsername({required String username}); - Future checkUsername({required String username}); - Future getPresignedUrl(); - Future uploadAvatar({ + Future> getProfile(); + Future> updateProfile({required User user}); + Future> updateUsername({required String username}); + Future> checkUsername({required String username}); + Future> getPresignedUrl(); + Future> uploadAvatar({ required Uint8List image, required String uploadUrl, }); - Future> searchUsers({ + Future>> searchUsers({ required String keyword, required int skip, required int limit, }); // Chat - Future> getConversations({ + Future>> getConversations({ int status = 2, int limit = 10, required int skip, }); - Future> getArchivedConversations({ + Future>> getArchivedConversations({ int limit = 10, required int skip, }); - Future updateConversation({ + Future> updateConversation({ required Meeting meeting, String? password, }); - Future deleteConversation(int conversationId); - Future leaveConversation({required int code}); - Future addMember({required int code, required int userId}); - Future deleteMember({required int code, required int userId}); - Future acceptInvite({required int meetingId}); - Future archivedConversation({required int code}); + Future> deleteConversation(int conversationId); + Future> leaveConversation({required int code}); + Future> addMember({required int code, required int userId}); + Future> deleteMember({ + required int code, + required int userId, + }); + Future> acceptInvite({required int meetingId}); + Future> archivedConversation({required int code}); // Messages - Future> getMessageByRoom({ + Future>> getMessageByRoom({ required int skip, required int meetingId, int limit = 10, }); - - Future sendMessage({ + Future> sendMessage({ required int meetingId, required String data, }); - Future editMessage({ + Future> editMessage({ required int messageId, required String data, }); - Future deleteMessage({required int messageId}); + Future> deleteMessage({required int messageId}); // Meeting - Future createRoom({ + Future> createRoom({ required Meeting meeting, required String password, required int? userId, }); - Future updateRoom({ + Future> updateRoom({ required Meeting meeting, required String password, required int? userId, }); - Future joinRoom({ + Future> joinRoom({ required Meeting meeting, required String password, required int? userId, }); - Future getRoomInfo(int code); - Future> getRecords({required int skip, required int limit}); - Future startRecord(); - Future stopRecord(); + Future> getRoomInfo(int code); + Future>> getRecords({ + required int skip, + required int limit, + }); + Future> startRecord(); + Future> stopRecord(); Future leaveRoom(); void toggleRaiseHand(); diff --git a/pubspec.yaml b/pubspec.yaml index 4b8e219..3b63174 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,14 +14,14 @@ dependencies: sdk: flutter # Network - connectivity_plus: ^6.0.5 + connectivity_plus: ^6.1.1 rhttp: ^0.9.8 http: ^1.2.2 dio: ^5.6.0 dio_smart_retry: ^6.0.0 - dio_cache_interceptor: ^3.5.0 + dio_cache_interceptor: ^3.5.1 dio_compatibility_layer: ^0.1.0 - socket_io_client: ^2.0.3+1 + socket_io_client: ^3.0.2 # Storage hive: ^2.2.3 @@ -30,7 +30,7 @@ dependencies: collection: '^1.16.0' universal_io: ^2.2.2 equatable: ^2.0.5 - logger: ^2.4.0 + logger: ^2.5.0 path_provider: ^2.1.4 wakelock_plus: ^1.2.8 replay_kit_launcher: ^1.0.0 @@ -47,19 +47,19 @@ dependencies: # path: /Users/lambiengcode/Documents/waterbus/flutter-webrtc-plus # Dependency Injection - get_it: ^7.6.8 + get_it: ^8.0.3 injectable: ^2.4.4 dev_dependencies: flutter_test: sdk: flutter # Lints - flutter_lints: ^4.0.0 + flutter_lints: ^5.0.0 import_sorter: ^4.6.0 # Code Generator injectable_generator: ^2.6.2 - build_runner: ^2.4.12 + build_runner: ^2.4.13 mockito: ^5.4.4 # For information on the generic Dart part of this file, see the @@ -82,4 +82,5 @@ topics: - webrtc - sfu - video - - conferencing \ No newline at end of file + - conferencing + - waterbus \ No newline at end of file diff --git a/test/features/auth/data/repositories/auth_repository_imp_test.dart b/test/features/auth/data/repositories/auth_repository_imp_test.dart index e2e2e05..49780c5 100644 --- a/test/features/auth/data/repositories/auth_repository_imp_test.dart +++ b/test/features/auth/data/repositories/auth_repository_imp_test.dart @@ -8,6 +8,7 @@ import 'package:waterbus_sdk/core/api/auth/datasources/auth_local_datasource.dar import 'package:waterbus_sdk/core/api/auth/datasources/auth_remote_datasource.dart'; import 'package:waterbus_sdk/core/api/auth/repositories/auth_repository.dart'; import 'package:waterbus_sdk/types/index.dart'; +import 'package:waterbus_sdk/types/result.dart'; import '../../../../constants/sample_file_path.dart'; import '../../../../fixtures/fixture_reader.dart'; import 'auth_repository_imp_test.mocks.dart'; @@ -42,16 +43,16 @@ void main() { final User user = User.fromMap(userJson); when(mockAuthRemoteDataSource.signInWithSocial(authParams)).thenAnswer( - (realInvocation) => Future.value(user), + (realInvocation) => Future.value(Result.success(user)), ); // act - final User? result = await repository.loginWithSocial( + final Result result = await repository.loginWithSocial( authParams, ); // assert - expect(result, user); + expect(result.value, user); verify(repository.loginWithSocial(authParams)); verifyNever( @@ -64,14 +65,14 @@ void main() { test('log out success', () async { // arrange when(mockAuthRemoteDataSource.logOut()).thenAnswer( - (realInvocation) => Future.value(true), + (realInvocation) => Future.value(Result.success(true)), ); // act - final bool result = await repository.logOut(); + final Result result = await repository.logOut(); // assert - expect(result, true); + expect(result.value, true); verify(mockAuthRemoteDataSource.logOut()); verify(mockAuthLocalDataSource.clearToken()); diff --git a/test/features/auth/data/repositories/auth_repository_imp_test.mocks.dart b/test/features/auth/data/repositories/auth_repository_imp_test.mocks.dart index 977b707..b8c2d89 100644 --- a/test/features/auth/data/repositories/auth_repository_imp_test.mocks.dart +++ b/test/features/auth/data/repositories/auth_repository_imp_test.mocks.dart @@ -4,18 +4,19 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i5; +import 'dart:async' as _i6; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i3; +import 'package:mockito/src/dummies.dart' as _i4; -import 'package:waterbus_sdk/types/models/auth_payload_model.dart' as _i7; -import 'package:waterbus_sdk/types/models/user_model.dart' as _i6; +import 'package:waterbus_sdk/types/models/auth_payload_model.dart' as _i8; +import 'package:waterbus_sdk/types/models/user_model.dart' as _i7; +import 'package:waterbus_sdk/types/result.dart' as _i2; import 'package:waterbus_sdk/core/api/auth/datasources/auth_local_datasource.dart' - as _i2; + as _i3; import 'package:waterbus_sdk/core/api/auth/datasources/auth_remote_datasource.dart' - as _i4; + as _i5; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -30,19 +31,29 @@ import 'package:waterbus_sdk/core/api/auth/datasources/auth_remote_datasource.da // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +class _FakeResult_0 extends _i1.SmartFake implements _i2.Result { + _FakeResult_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + /// A class which mocks [AuthLocalDataSource]. /// /// See the documentation for Mockito's code generation for more information. class MockAuthLocalDataSource extends _i1.Mock - implements _i2.AuthLocalDataSource { + implements _i3.AuthLocalDataSource { @override String get accessToken => (super.noSuchMethod( Invocation.getter(#accessToken), - returnValue: _i3.dummyValue( + returnValue: _i4.dummyValue( this, Invocation.getter(#accessToken), ), - returnValueForMissingStub: _i3.dummyValue( + returnValueForMissingStub: _i4.dummyValue( this, Invocation.getter(#accessToken), ), @@ -51,11 +62,11 @@ class MockAuthLocalDataSource extends _i1.Mock @override String get refreshToken => (super.noSuchMethod( Invocation.getter(#refreshToken), - returnValue: _i3.dummyValue( + returnValue: _i4.dummyValue( this, Invocation.getter(#refreshToken), ), - returnValueForMissingStub: _i3.dummyValue( + returnValueForMissingStub: _i4.dummyValue( this, Invocation.getter(#refreshToken), ), @@ -92,36 +103,64 @@ class MockAuthLocalDataSource extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockAuthRemoteDataSource extends _i1.Mock - implements _i4.AuthRemoteDataSource { + implements _i5.AuthRemoteDataSource { @override - _i5.Future<(String?, String?)> refreshToken() => (super.noSuchMethod( + _i6.Future<(String?, String?)> refreshToken() => (super.noSuchMethod( Invocation.method( #refreshToken, [], ), - returnValue: _i5.Future<(String?, String?)>.value((null, null)), + returnValue: _i6.Future<(String?, String?)>.value((null, null)), returnValueForMissingStub: - _i5.Future<(String?, String?)>.value((null, null)), - ) as _i5.Future<(String?, String?)>); + _i6.Future<(String?, String?)>.value((null, null)), + ) as _i6.Future<(String?, String?)>); @override - _i5.Future<_i6.User?> signInWithSocial(_i7.AuthPayloadModel? authPayload) => + _i6.Future<_i2.Result<_i7.User>> signInWithSocial( + _i8.AuthPayloadModel? authPayload) => (super.noSuchMethod( Invocation.method( #signInWithSocial, [authPayload], ), - returnValue: _i5.Future<_i6.User?>.value(), - returnValueForMissingStub: _i5.Future<_i6.User?>.value(), - ) as _i5.Future<_i6.User?>); + returnValue: + _i6.Future<_i2.Result<_i7.User>>.value(_FakeResult_0<_i7.User>( + this, + Invocation.method( + #signInWithSocial, + [authPayload], + ), + )), + returnValueForMissingStub: + _i6.Future<_i2.Result<_i7.User>>.value(_FakeResult_0<_i7.User>( + this, + Invocation.method( + #signInWithSocial, + [authPayload], + ), + )), + ) as _i6.Future<_i2.Result<_i7.User>>); @override - _i5.Future logOut() => (super.noSuchMethod( + _i6.Future<_i2.Result> logOut() => (super.noSuchMethod( Invocation.method( #logOut, [], ), - returnValue: _i5.Future.value(false), - returnValueForMissingStub: _i5.Future.value(false), - ) as _i5.Future); + returnValue: _i6.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #logOut, + [], + ), + )), + returnValueForMissingStub: + _i6.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #logOut, + [], + ), + )), + ) as _i6.Future<_i2.Result>); } diff --git a/test/features/profile/data/repositories/user_repository_impl_test.dart b/test/features/profile/data/repositories/user_repository_impl_test.dart index de0ac9f..f10b08c 100644 --- a/test/features/profile/data/repositories/user_repository_impl_test.dart +++ b/test/features/profile/data/repositories/user_repository_impl_test.dart @@ -6,7 +6,9 @@ import 'package:mockito/mockito.dart'; import 'package:waterbus_sdk/core/api/user/datasources/user_remote_datasource.dart'; import 'package:waterbus_sdk/core/api/user/repositories/user_repository.dart'; +import 'package:waterbus_sdk/types/error/failures.dart'; import 'package:waterbus_sdk/types/models/user_model.dart'; +import 'package:waterbus_sdk/types/result.dart'; import 'user_repository_impl_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -24,27 +26,29 @@ void main() { group('getUserProfile', () { test('should return user from remote data source', () async { // Arrange - when(mockDataSource.getUserProfile()).thenAnswer((_) async => testUser); + when(mockDataSource.getUserProfile()) + .thenAnswer((_) async => Result.success(testUser)); // Act final result = await repository.getUserProfile(); // Assert - expect(result, testUser); + expect(result.value, testUser); verify(mockDataSource.getUserProfile()); verifyNoMoreInteractions(mockDataSource); }); test('should return a failure from remote data source', () async { // Arrange - when(mockDataSource.getUserProfile()) - .thenAnswer((realInvocation) async => null); + when(mockDataSource.getUserProfile()).thenAnswer( + (realInvocation) async => Result.failure(ServerFailure()), + ); // Act final result = await repository.getUserProfile(); // Assert - expect(result, null); + expect(result.error, ServerFailure()); verify(mockDataSource.getUserProfile()); verifyNoMoreInteractions(mockDataSource); }); @@ -54,13 +58,13 @@ void main() { test('should return updated user from remote data source', () async { // Arrange when(mockDataSource.updateUserProfile(testUser)) - .thenAnswer((_) async => true); + .thenAnswer((_) async => Result.success(true)); // Act final result = await repository.updateUserProfile(testUser); // Assert - expect(result, testUser); + expect(result.value, true); verify(mockDataSource.updateUserProfile(testUser)); verifyNoMoreInteractions(mockDataSource); }); @@ -68,13 +72,13 @@ void main() { test('should return a failure from remote data source', () async { // Arrange when(mockDataSource.updateUserProfile(testUser)) - .thenAnswer((_) async => false); + .thenAnswer((_) async => Result.failure(ServerFailure())); // Act final result = await repository.updateUserProfile(testUser); // Assert - expect(result, null); + expect(result.error, ServerFailure()); verify(mockDataSource.updateUserProfile(testUser)); verifyNoMoreInteractions(mockDataSource); }); @@ -84,13 +88,13 @@ void main() { test('should return true from remote data source', () async { // Arrange when(mockDataSource.updateUsername(testUser.userName)) - .thenAnswer((_) async => true); + .thenAnswer((_) async => Result.success(true)); // Act final result = await repository.updateUsername(testUser.userName); // Assert - expect(result, true); + expect(result.value, true); verify(mockDataSource.updateUsername(testUser.userName)); verifyNoMoreInteractions(mockDataSource); }); @@ -98,13 +102,13 @@ void main() { test('should return a failure from remote data source', () async { // Arrange when(mockDataSource.updateUsername(testUser.userName)) - .thenAnswer((_) async => false); + .thenAnswer((_) async => Result.failure(ServerFailure())); // Act final result = await repository.updateUsername(testUser.userName); // Assert - expect(result, false); + expect(result.error, ServerFailure()); verify(mockDataSource.updateUsername(testUser.userName)); verifyNoMoreInteractions(mockDataSource); }); @@ -114,13 +118,13 @@ void main() { test('should return true from remote data source', () async { // Arrange when(mockDataSource.checkUsername(testUser.userName)) - .thenAnswer((_) async => true); + .thenAnswer((_) async => Result.success(true)); // Act final result = await repository.checkUsername(testUser.userName); // Assert - expect(result, true); + expect(result.value, true); verify(mockDataSource.checkUsername(testUser.userName)); verifyNoMoreInteractions(mockDataSource); }); @@ -128,13 +132,13 @@ void main() { test('should return false from remote data source', () async { // Arrange when(mockDataSource.checkUsername(testUser.userName)) - .thenAnswer((_) async => false); + .thenAnswer((_) async => Result.failure(ServerFailure())); // Act final result = await repository.checkUsername(testUser.userName); // Assert - expect(result, false); + expect(result.error, ServerFailure()); verify(mockDataSource.checkUsername(testUser.userName)); verifyNoMoreInteractions(mockDataSource); }); @@ -142,13 +146,13 @@ void main() { test('should return null from remote data source', () async { // Arrange when(mockDataSource.checkUsername(testUser.userName)) - .thenAnswer((_) async => null); + .thenAnswer((_) async => Result.failure(ServerFailure())); // Act final result = await repository.checkUsername(testUser.userName); // Assert - expect(result, false); + expect(result.error, ServerFailure()); verify(mockDataSource.checkUsername(testUser.userName)); verifyNoMoreInteractions(mockDataSource); }); @@ -158,13 +162,14 @@ void main() { test('should return presigned URL from remote data source', () async { // Arrange const testUrl = 'https://example.com/presigned-url'; - when(mockDataSource.getPresignedUrl()).thenAnswer((_) async => testUrl); + when(mockDataSource.getPresignedUrl()) + .thenAnswer((_) async => Result.success(testUrl)); // Act final result = await repository.getPresignedUrl(); // Assert - expect(result, testUrl); + expect(result.value, testUrl); verify(mockDataSource.getPresignedUrl()); verifyNoMoreInteractions(mockDataSource); }); @@ -172,14 +177,14 @@ void main() { test('should return a failure from remote data source', () async { // Arrange when(mockDataSource.getPresignedUrl()).thenAnswer( - (realInvocation) async => null, + (realInvocation) async => Result.failure(ServerFailure()), ); // Act final result = await repository.getPresignedUrl(); // Assert - expect(result, null); + expect(result.error, ServerFailure()); verify(mockDataSource.getPresignedUrl()); verifyNoMoreInteractions(mockDataSource); }); @@ -197,7 +202,7 @@ void main() { uploadUrl: anyNamed('uploadUrl'), image: anyNamed('image'), ), - ).thenAnswer((_) async => testImageUrl); + ).thenAnswer((_) async => Result.success(testImageUrl)); // Act final result = await repository.uploadImageToS3( @@ -206,7 +211,7 @@ void main() { ); // Assert - expect(result, testImageUrl); + expect(result.value, testImageUrl); verify( mockDataSource.uploadImageToS3( uploadUrl: testUploadUrl, @@ -223,7 +228,7 @@ void main() { uploadUrl: anyNamed('uploadUrl'), image: anyNamed('image'), ), - ).thenAnswer((_) async => null); + ).thenAnswer((_) async => Result.failure(ServerFailure())); // Act final result = await repository.uploadImageToS3( @@ -232,7 +237,7 @@ void main() { ); // Assert - expect(result, null); + expect(result.error, ServerFailure()); verify( mockDataSource.uploadImageToS3( uploadUrl: testUploadUrl, diff --git a/test/features/profile/data/repositories/user_repository_impl_test.mocks.dart b/test/features/profile/data/repositories/user_repository_impl_test.mocks.dart index 0fa0db5..cfb0acf 100644 --- a/test/features/profile/data/repositories/user_repository_impl_test.mocks.dart +++ b/test/features/profile/data/repositories/user_repository_impl_test.mocks.dart @@ -4,15 +4,16 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i3; -import 'dart:typed_data' as _i5; +import 'dart:async' as _i4; +import 'dart:typed_data' as _i6; import 'package:mockito/mockito.dart' as _i1; -import 'package:waterbus_sdk/types/models/user_model.dart' as _i4; +import 'package:waterbus_sdk/types/models/user_model.dart' as _i5; +import 'package:waterbus_sdk/types/result.dart' as _i2; import 'package:waterbus_sdk/core/api/user/datasources/user_remote_datasource.dart' - as _i2; + as _i3; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -27,53 +28,119 @@ import 'package:waterbus_sdk/core/api/user/datasources/user_remote_datasource.da // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +class _FakeResult_0 extends _i1.SmartFake implements _i2.Result { + _FakeResult_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + /// A class which mocks [UserRemoteDataSource]. /// /// See the documentation for Mockito's code generation for more information. class MockUserRemoteDataSource extends _i1.Mock - implements _i2.UserRemoteDataSource { + implements _i3.UserRemoteDataSource { @override - _i3.Future<_i4.User?> getUserProfile() => (super.noSuchMethod( + _i4.Future<_i2.Result<_i5.User>> getUserProfile() => (super.noSuchMethod( Invocation.method( #getUserProfile, [], ), - returnValue: _i3.Future<_i4.User?>.value(), - returnValueForMissingStub: _i3.Future<_i4.User?>.value(), - ) as _i3.Future<_i4.User?>); + returnValue: + _i4.Future<_i2.Result<_i5.User>>.value(_FakeResult_0<_i5.User>( + this, + Invocation.method( + #getUserProfile, + [], + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Result<_i5.User>>.value(_FakeResult_0<_i5.User>( + this, + Invocation.method( + #getUserProfile, + [], + ), + )), + ) as _i4.Future<_i2.Result<_i5.User>>); @override - _i3.Future updateUserProfile(_i4.User? user) => (super.noSuchMethod( + _i4.Future<_i2.Result> updateUserProfile(_i5.User? user) => + (super.noSuchMethod( Invocation.method( #updateUserProfile, [user], ), - returnValue: _i3.Future.value(false), - returnValueForMissingStub: _i3.Future.value(false), - ) as _i3.Future); + returnValue: _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #updateUserProfile, + [user], + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #updateUserProfile, + [user], + ), + )), + ) as _i4.Future<_i2.Result>); @override - _i3.Future updateUsername(String? username) => (super.noSuchMethod( + _i4.Future<_i2.Result> updateUsername(String? username) => + (super.noSuchMethod( Invocation.method( #updateUsername, [username], ), - returnValue: _i3.Future.value(false), - returnValueForMissingStub: _i3.Future.value(false), - ) as _i3.Future); + returnValue: _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #updateUsername, + [username], + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #updateUsername, + [username], + ), + )), + ) as _i4.Future<_i2.Result>); @override - _i3.Future checkUsername(String? username) => (super.noSuchMethod( + _i4.Future<_i2.Result> checkUsername(String? username) => + (super.noSuchMethod( Invocation.method( #checkUsername, [username], ), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) as _i3.Future); + returnValue: _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #checkUsername, + [username], + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #checkUsername, + [username], + ), + )), + ) as _i4.Future<_i2.Result>); @override - _i3.Future> searchUsers({ + _i4.Future<_i2.Result>> searchUsers({ required String? keyword, required int? skip, required int? limit, @@ -88,25 +155,61 @@ class MockUserRemoteDataSource extends _i1.Mock #limit: limit, }, ), - returnValue: _i3.Future>.value(<_i4.User>[]), - returnValueForMissingStub: - _i3.Future>.value(<_i4.User>[]), - ) as _i3.Future>); + returnValue: _i4.Future<_i2.Result>>.value( + _FakeResult_0>( + this, + Invocation.method( + #searchUsers, + [], + { + #keyword: keyword, + #skip: skip, + #limit: limit, + }, + ), + )), + returnValueForMissingStub: _i4.Future<_i2.Result>>.value( + _FakeResult_0>( + this, + Invocation.method( + #searchUsers, + [], + { + #keyword: keyword, + #skip: skip, + #limit: limit, + }, + ), + )), + ) as _i4.Future<_i2.Result>>); @override - _i3.Future getPresignedUrl() => (super.noSuchMethod( + _i4.Future<_i2.Result> getPresignedUrl() => (super.noSuchMethod( Invocation.method( #getPresignedUrl, [], ), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) as _i3.Future); + returnValue: _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #getPresignedUrl, + [], + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #getPresignedUrl, + [], + ), + )), + ) as _i4.Future<_i2.Result>); @override - _i3.Future uploadImageToS3({ + _i4.Future<_i2.Result> uploadImageToS3({ required String? uploadUrl, - required _i5.Uint8List? image, + required _i6.Uint8List? image, }) => (super.noSuchMethod( Invocation.method( @@ -117,7 +220,28 @@ class MockUserRemoteDataSource extends _i1.Mock #image: image, }, ), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) as _i3.Future); + returnValue: _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #uploadImageToS3, + [], + { + #uploadUrl: uploadUrl, + #image: image, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Result>.value(_FakeResult_0( + this, + Invocation.method( + #uploadImageToS3, + [], + { + #uploadUrl: uploadUrl, + #image: image, + }, + ), + )), + ) as _i4.Future<_i2.Result>); }