repository

μš©λ„

network μ—μ„œ λ§Œλ“€μ–΄μ€€ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό ν†΅ν•΄μ„œ μ„œλ²„μ™€ ν†΅μ‹ ν•΄μ„œ 데이터λ₯Ό 직접 κ°€μ Έμ˜€λŠ” μ±…μž„μ„ κ°€μ§„ 객체닀. 도메인 λ³„λ‘œ λ‚˜λˆ μ„œ 각 도메인에 λŒ€ν•΄μ„œ μ„œλ²„λ‘œλΆ€ν„° 데이터λ₯Ό 가져와 μ²˜λ¦¬ν•˜λŠ” λ“±μ˜ μ±…μž„μ„ μˆ˜ν–‰ν•œλ‹€.

κ΅¬ν˜„

클린 μ•„ν‚€ν…μ²˜ κ°•μ˜μ—μ„œ dartz λ₯Ό μ‚¬μš©ν–ˆλŠ”λ° μ²˜μŒμ—” μ’€ μ΄μƒν•˜λ‹€ μƒκ°ν–ˆλŠ”λ° 막상 ν”„λ‘œμ νŠΈμ— μ¨λ³΄λ‹ˆ μ—λŸ¬ λ‚¬μ„λ•Œμ™€ 정상 처리λ₯Ό 더 λΆ„λͺ…ν•˜κ²Œ ꡬ뢄할 수 μžˆμ–΄μ„œ μ’‹μ•˜λ‹€.

flutter pub add dartz
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart';

import '../../../../barrel.dart';

class UserRepositoryImpl extends UserRepository {
  final Dio apiClient;
  final ConnectionManager connectionManager;

  UserRepositoryImpl({
    required this.apiClient,
    required this.connectionManager,
  });

  @override
  Future<Either<AppException, bool>> replaceIsPushPermitted(
      bool isPushPermitted) async {
    final togglePushPermittedRequest =
        apiClient.put('/user/push-permitted', queryParameters: {
      'isPushPermitted': isPushPermitted,
    });
    try {
      Response response = await togglePushPermittedRequest;
      return Right(response.data['isPushPermitted'] as bool);
    } catch (error) {
      return Left(
          AppException(TextManager.notificationToggleFailedMessage.tr()));
    }
  }

  @override
  Future<Either<AppException, void>> replacePushToken(String pushToken) async {
    final replacePushTokenRequest = apiClient.put('/user/push-token');
    try {
      await replacePushTokenRequest;
      return const Right(null);
    } catch (error) {
      return Left(AppException.basicError());
    }
  }

  @override
  Future<Either<AppException, bool>> appVersionCheck() async {
    final appVersionCheck = apiClient.get('/app/version');

    try {
      final Response response = await appVersionCheck;
      return Right(response.data['isForceUpdate']);
    } catch (error) {
      return Left(AppException(TextManager.appVersionCheckFailedMessage.tr()));
    }
  }

  @override
  Future<Either<AppException, void>> updateProfile(
      UpdateProfileCommand command) async {
    bool isConnected = await connectionManager.isConnected;
    if (!isConnected) {
      return Left(AppException(TextManager.internetNotConnected.tr()));
    }

    final Map<String, dynamic> jsonData = command.toJson();
    final FormData formData;
    if (command.profileImage != null) {
      formData = FormData.fromMap({
        'profileImage':
            await MultipartFile.fromFile(command.profileImage!.path),
      });

      jsonData.forEach((key, value) {
        formData.fields.add(MapEntry(key, value.toString()));
      });
    } else {
      formData = FormData.fromMap(jsonData);
    }

    try {
      await apiClient.put(
        '/user/profile',
        data: formData,
        options: Options(
          contentType: 'multipart/form-data',
        ),
      );
      return const Right(null);
    } on DioException catch (error) {
      return Left(AppException(TextManager.updateProfileFailedMessage.tr()));
    }
  }

  @override
  Future<Either<AppException, void>> quitService() async {
    bool isConnected = await connectionManager.isConnected;
    if (!isConnected) {
      return Left(AppException(TextManager.internetNotConnected.tr()));
    }

    final minimumLatency = Future.delayed(const Duration(milliseconds: 700));
    final quitServiceRequest = apiClient.delete('/user/quit');
    try {
      await Future.wait([minimumLatency, quitServiceRequest]);
      return const Right(null);
    } catch (error) {
      return Left(AppException(TextManager.quitServiceFailedMessage.tr()));
    }
  }

  @override
  Future<Either<AppException, UserDetailModel>> getUserDetail() async {
    bool isConnected = await connectionManager.isConnected;
    if (!isConnected) {
      return Left(AppException(TextManager.internetNotConnected.tr()));
    }

    final minimumLatency = Future.delayed(const Duration(milliseconds: 700));
    final getUserDetailRequest = apiClient.get('/user/profile');
    try {
      await Future.wait([minimumLatency, getUserDetailRequest]);
      Response response = await getUserDetailRequest;
      UserDetailModel result = UserDetailModel.fromJson(response.data);

      return Right(result);
    } catch (error) {
      return Left(AppException(TextManager.userDetailFailedMessage.tr()));
    }
  }

  @override
  Future<Either<AppException, SignInResponse>> signIn() async {
    bool isConnected = await connectionManager.isConnected;
    if (!isConnected) {
      return Left(AppException(TextManager.internetNotConnected.tr()));
    }

    final minimumLatency = Future.delayed(const Duration(milliseconds: 700));
    final signInRequest = apiClient.post('/user/token');
    try {
      await Future.wait([minimumLatency, signInRequest]);
    } catch (error) {
      return Left(AppException(TextManager.signInFailed.tr()));
    }
    Response signInResponse = await signInRequest;

    return Right(SignInResponse.fromJson(signInResponse.data));
  }

  @override
  Future<Either<AppException, SignInResponse>> continueWithSocial(
      ContinueWithSocialQuery continueWithSocialQuery) async {
    bool isConnected = await connectionManager.isConnected;
    if (!isConnected) {
      return Left(AppException(TextManager.internetNotConnected.tr()));
    }

    final minimumLatency = Future.delayed(const Duration(milliseconds: 700));
    final continueWithSocialRequest =
        apiClient.post('/user', data: continueWithSocialQuery.toJson());

    try {
      await Future.wait([minimumLatency, continueWithSocialRequest]);
    } on DioException catch (error) {
      return Left(AppException(TextManager.continueWithSocialFailed.tr()));
    }
    final Response continueWithSocialResponse = await continueWithSocialRequest;

    return Right(SignInResponse.fromJson(continueWithSocialResponse.data));
  }

  @override
  Future<Either<AppException, void>> completeOnBoarding(
      CompleteOnBoardingCommand command) async {
    bool isConnected = await connectionManager.isConnected;
    if (!isConnected) {
      return Left(AppException(TextManager.internetNotConnected.tr()));
    }

    final Map<String, dynamic> jsonData = command.toJson();
    final FormData formData;
    if (command.profileImage != null) {
      formData = FormData.fromMap({
        'profileImage':
            await MultipartFile.fromFile(command.profileImage!.path),
      });

      jsonData.forEach((key, value) {
        formData.fields.add(MapEntry(key, value.toString()));
      });
    } else {
      formData = FormData.fromMap(jsonData);
    }

    try {
      await apiClient.post(
        '/user/profile',
        data: formData,
        options: Options(
          contentType: 'multipart/form-data',
        ),
      );
      return const Right(null);
    } on DioException catch (error) {
      return Left(
          AppException(TextManager.onboardingFailedExceptionContents.tr()));
    }
  }
}

λ‹€μ–‘ν•œ 데이터 톡신 μΌ€μ΄μŠ€κ°€ μžˆμ–΄μ„œ 일단 ν”„λ‘œμ νŠΈμ— μ‚¬μš©ν•œ μ½”λ“œλ₯Ό λ‹€ κ°€μ Έμ™”λ‹€. ν…œν”Œλ¦Ώ μ½”λ“œμ—μ„œλŠ” μΈν„°νŽ˜μ΄μŠ€, κ΅¬ν˜„μ²΄λ₯Ό λ‚˜λˆ„μ§€ μ•Šκ³  data λ ˆμ΄μ–΄μ— λ°”λ‘œ κ΅¬ν˜„μ²΄ ν•˜λ‚˜λ§Œ μ‚¬μš©ν•  μ˜ˆμ •μ΄λ‹€.

μ‚¬μš©

λ‹€λ₯Έ 것듀과 λ§ˆμ°¬κ°€μ§€λ‘œ Injector 에 μœ„μ™€ 같이 μ„ μ–Έν•œ ν›„ ν•„μš”ν•œ λ•Œ(= Bloc 에 μ£Όμž…) μ‚¬μš©ν•œλ‹€.

Last updated