Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feat [#150] 프로필 사진 변경 API 연동 및 모든 프로필 사진 부분 적용 #152

Merged
merged 29 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fb99995
[Feat] #150 - 앨범 접근 권한 허용 설정 추가
boogios Feb 23, 2024
c118109
[Fix] #150 - 한 줄 소개 없는 경우, 닉네임도 못불러오는 오류 해결
boogios Feb 23, 2024
4df823b
[Feat] #150 - 프로필 사진 추가 버튼 주석 해제
boogios Feb 23, 2024
668ebd3
[Feat] #150 - 사진 앨범 접근 권한 기능 구현, 설정으로 이동하는 Alert 추가
boogios Feb 23, 2024
3f6b99c
[Feat] #150 - 서버로 프로필 변경 데이터 전송 구현 완료, API 연결 완료
boogios Feb 23, 2024
f19b881
[Feat] #150 - 프로필 사진 변경 DTO 추가
boogios Feb 26, 2024
fa6d9c5
[Delete] #150 - 불필요한 코드 삭제
boogios Feb 26, 2024
65ee4db
[Feat] #150 - 프로필 사진 변경 이후 2초 후 새로고침 되도록 구현
boogios Feb 26, 2024
0aecf76
[Feat] #150 - viewWillAppear 될 때, 서버에서 프로필 이미지 사진 받아오도록 구현
boogios Feb 26, 2024
9f6c1d0
[Feat] #150 - 기본 프로필 이미지 설정
boogios Feb 26, 2024
83cda7b
[Delete] #150 - 프로필 이미지 기본값 삭제
boogios Feb 26, 2024
43e76de
[Feat] #150 - 셀 중복되는 이미지 값 기본값으로 수정
boogios Feb 26, 2024
9ed0e96
[Delete] #150 - 불필요한 코드 삭제
boogios Feb 26, 2024
e3a22f9
[Feat] #150 - 게시글 상세보기 뷰 프로필 이미지 적용
boogios Feb 26, 2024
dc28493
[Feat] #150 - UserInfo에 userProfileImage 값 추가
boogios Feb 27, 2024
e08a6a4
[Feat] #150 - 답글 뷰에서 프로필 이미지 추가
boogios Feb 27, 2024
e6f5673
[Fix] #150 - 알림 뷰에서 프로필 이미지 동그랗게 수정
boogios Feb 27, 2024
7ec00c4
[Feat] #150 - 답글 뷰에서 나의 프로필 이미지 추가
boogios Feb 27, 2024
8848708
[Feat] #150 - 글쓰기 뷰에서 나의 프로필 이미지 추가
boogios Feb 27, 2024
90d0ca4
[Fix] #150 - 이미지 동그랗게 수정
boogios Feb 27, 2024
099795f
[Feat] #150 - 회원가입 시, 이미지 변경 버튼 추가
boogios Feb 27, 2024
425ab4d
[Feat] #150 - 회원가입 뷰 사진 앨범 권한 추가
boogios Feb 27, 2024
0ec0453
[Feat] #150 - 회원가입 시, 이미지 정보 추가된 API 로 변경
boogios Feb 27, 2024
2ddfd71
[Feat] #150 - 온보딩 마지막 뷰에 프로필 이미지 서버에서 받아온 값으로 변경
boogios Feb 27, 2024
6761fd9
[Fix] #150 - 이미지 동그랗게 수정
boogios Feb 27, 2024
f25f94a
[Feat] #150 - 온보딩 마지막 뷰에서 서버에서 프로필 받아온 값 보여주도록 기능 구현
boogios Feb 27, 2024
5eb528e
Merge branch 'develop' into feat/#150-profileImageSetting
boogios Feb 27, 2024
4a97983
[Fix] #150 - 코드리뷰 반영, StringLiterals 추가
boogios Feb 28, 2024
9b6e631
Merge branch 'feat/#150-profileImageSetting' of https://github.com/Te…
boogios Feb 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1491,10 +1491,12 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "DontBe-iOS/Global/Resources/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "Don't Be";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "게시글이나 프로필을 변경할 때 사용합니다.";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_UIUserInterfaceStyle = Light;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -1526,10 +1528,12 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "DontBe-iOS/Global/Resources/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "Don't Be";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "게시글이나 프로필을 변경할 때 사용합니다.";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_UIUserInterfaceStyle = Light;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 리뷰:

  1. 코드 변경 내용이 중복되고 있습니다. 두 번의 변경 사항에서 동일한 "INFOPLIST_KEY_NSPhotoLibraryUsageDescription" 및 "INFOPLIST_KEY_UIUserInterfaceStyle" 키가 추가되었습니다.
  2. 코드 일정부분에서 확신이 없는 듯한 구석이 보입니다. 변경사항이 일상적인 것으로 보이며, 주변 변경 사항과 어울리지 않는 부분이 있습니다.
  3. 모든 조건에 대한 유효성 검사 및 테스트 케이스가 필요합니다.

개선 제안:

  1. 변경 내용을 하나로 합치거나 중복된 섹션을 정리하여 코드의 가독성을 향상시킬 수 있습니다.
  2. 변경 이유를 설명하는 주석을 추가하면 코드의 이해가 용이해집니다.
  3. 안전하게 테스트된 변경 내용을 포함하는 최상의 방법을 사용하여 변경사항이 앱에 원하지 않는 영향을 미치는 것을 방지할 수 있습니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석 없이 두 부분이 거의 동일하므로, 코드 리뷰 중 수정이 필요한 부분은 다음과 같습니다:

  1. INFOPLIST_KEY_NSPhotoLibraryUsageDescriptionINFOPLIST_KEY_UIUserInterfaceStyle가 중복 선언되었습니다. 중복 선언을 피하기 위해 이를 최상단에서 한 번만 정의하는 것이 좋습니다.

  2. 문자열 값 "Light"는 따옴표로 감싸져 있지 않으므로, 올바른 문자열로 인식될 수 있도록 따옴표로 묶어주는 것이 좋습니다.

  3. 주석이 없으므로 이 변경 사항이 왜 필요한지에 대한 설명이 없습니다. 변경의 이유와 의도를 나타내는 주석을 추가하는 것이 좋습니다.

Expand Down
3 changes: 2 additions & 1 deletion DontBe-iOS/DontBe-iOS/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
isJoinedApp: true,
isOnboardingFinished: true,
userNickname: loadUserData()?.userNickname ?? "",
memberId: loadUserData()?.memberId ?? 0))
memberId: loadUserData()?.memberId ?? 0,
userProfileImage: loadUserData()?.userProfileImage ?? StringLiterals.Network.baseImageURL))
// KeychainWrapper에 Access Token 저장하고 소셜로그인 화면으로
let accessToken = KeychainWrapper.loadToken(forKey: "accessToken") ?? ""
KeychainWrapper.saveToken(accessToken, forKey: "accessToken")
Expand Down
1 change: 1 addition & 0 deletions DontBe-iOS/DontBe-iOS/Global/Extension/UIImageView+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ extension UIImageView {
DispatchQueue.main.async {
self?.image = image
self?.layer.cornerRadius = (self?.frame.size.width ?? 0) / 2.adjusted
self?.contentMode = .scaleAspectFill
self?.clipsToBounds = true
}
}
Expand Down
4 changes: 4 additions & 0 deletions DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,8 @@ enum StringLiterals {
static let warnUserGoogleFormURL = "https://forms.gle/FTgZKkajwtzFvAk99"
static let errorMessage = "이런!\n현재 요청하신 페이지를 찾을 수 없어요!"
}

enum Camera {
static let photoNoAuth = "Don't Be 앱에 사진 권한이 없습니다.\n설정으로 이동하여 권한 설정을 해주세요."
}
}
22 changes: 10 additions & 12 deletions DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>BASE_URL</key>
<string>$(BASE_URL)</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaolink</string>
<string>kakaokompassauth</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand All @@ -27,8 +15,18 @@
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaolink</string>
<string>kakaokompassauth</string>
</array>
<key>NATIVE_APP_KEY</key>
<string>$(NATIVE_APP_KEY)</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIAppFonts</key>
<array>
<string>Pretendard-Regular.otf</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import UIKit

// MARK: - UserProfileRequestDTO

Expand All @@ -15,3 +16,10 @@ struct UserProfileRequestDTO: Encodable {
let member_intro: String
let profile_url: String
}

struct EditUserProfileRequestDTO {
let nickname: String
let is_alarm_allowed: Bool
let member_intro: String
let profile_image: UIImage
Comment on lines +22 to +24
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3
카멜 케이스로 바꿔주면 더 좋을 것 같아요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3
서버 API 명세서에 맞춰놨던거 같아서 주주랑 한번 얘기해보고 수정하겠습니당!

}
1 change: 1 addition & 0 deletions DontBe-iOS/DontBe-iOS/Presentation/Helpers/UserInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct UserInfo: Codable {
let isOnboardingFinished: Bool
let userNickname: String
let memberId: Int
let userProfileImage: String
}

// 구조체를 UserDefault에 저장하는 함수
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import SnapKit

final class HomeCollectionViewCell: UICollectionViewCell, UICollectionViewRegisterable {

override func prepareForReuse() {
super.prepareForReuse()

profileImageView.image = ImageLiterals.Common.imgProfile
}

// MARK: - Properties

var KebabButtonAction: (() -> Void) = {}
Expand Down Expand Up @@ -45,7 +51,6 @@ final class HomeCollectionViewCell: UICollectionViewCell, UICollectionViewRegist
image.clipsToBounds = true
image.layer.borderWidth = 1.adjusted
image.layer.borderColor = UIColor.clear.cgColor
image.image = ImageLiterals.Common.imgProfile
image.layer.cornerRadius = 22.adjusted
image.isUserInteractionEnabled = true
return image
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ final class HomeViewController: UIViewController {
setLayout()
setDelegate()
setAddTarget()
bindViewModel()
setRefreshControl()
}

Expand Down Expand Up @@ -215,7 +214,6 @@ extension HomeViewController {
DispatchQueue.main.async {
self.bindViewModel()
}
self.homeCollectionView.reloadData()
self.perform(#selector(self.finishedRefreshing), with: nil, afterDelay: 0.1)
}

Expand Down Expand Up @@ -440,14 +438,13 @@ extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelega
self.present(self.transparentPopupVC, animated: false, completion: nil)
}

cell.profileImageView.load(url: homeViewModel.postData[indexPath.row].memberProfileUrl)
cell.nicknameLabel.text = homeViewModel.postData[indexPath.row].memberNickname
cell.transparentLabel.text = "투명도 \(homeViewModel.postData[indexPath.row].memberGhost)%"
cell.contentTextLabel.text = homeViewModel.postData[indexPath.row].contentText
cell.likeNumLabel.text = "\(homeViewModel.postData[indexPath.row].likedNumber)"
cell.commentNumLabel.text = "\(homeViewModel.postData[indexPath.row].commentNumber)"
cell.timeLabel.text = "\(homeViewModel.postData[indexPath.row].time.formattedTime())"
cell.profileImageView.load(url: "\(homeViewModel.postData[indexPath.row].memberProfileUrl)")
cell.profileImageView.load(url: "\(self.homeViewModel.postData[indexPath.row].memberProfileUrl)")
cell.likeButton.setImage(homeViewModel.postData[indexPath.row].isLiked ? ImageLiterals.Posting.btnFavoriteActive : ImageLiterals.Posting.btnFavoriteInActive, for: .normal)
cell.isLiked = self.homeViewModel.postData[indexPath.row].isLiked
cell.likeButton.setImage(cell.isLiked ? ImageLiterals.Posting.btnFavoriteActive : ImageLiterals.Posting.btnFavoriteInActive, for: .normal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//

import UIKit
import Photos
import PhotosUI

import SnapKit

Expand All @@ -21,9 +23,13 @@ final class JoinProfileViewController: UIViewController {
return self.originView.nickNameTextField.text ?? ""
}.eraseToAnyPublisher()
private lazy var finishButtonTapped = self.originView.finishActiveButton.publisher(for: .touchUpInside).map { _ in
return self.originView.nickNameTextField.text ?? ""
return EditUserProfileRequestDTO(nickname: self.originView.nickNameTextField.text ?? "",
is_alarm_allowed: true,
member_intro: "",
profile_image: self.originView.profileImage.image ?? ImageLiterals.Common.imgProfile)
}.eraseToAnyPublisher()


// MARK: - UI Components

private let navigationBackButton = BackButton()
Expand Down Expand Up @@ -56,6 +62,7 @@ final class JoinProfileViewController: UIViewController {
setUI()
setHierarchy()
setLayout()
setAddTarget()
bindViewModel()
}

Expand Down Expand Up @@ -93,6 +100,10 @@ extension JoinProfileViewController {
}
}

private func setAddTarget() {
self.originView.plusButton.addTarget(self, action: #selector(plusButtonTapped), for: .touchUpInside)
}

private func setDelegate() {
NotificationCenter.default.addObserver(self, selector: #selector(textFieldTisEmpty), name: UITextField.textDidChangeNotification, object: nil)
}
Expand Down Expand Up @@ -138,4 +149,74 @@ extension JoinProfileViewController {
self.originView.duplicationCheckDescription.text = StringLiterals.Join.duplicationCheckDescription
self.originView.duplicationCheckDescription.textColor = .donGray8
}

@objc
private func plusButtonTapped() {
let status = PHPhotoLibrary.authorizationStatus(for: .addOnly)

switch status {
case .authorized, .limited:
presentPicker()
case .notDetermined:
PHPhotoLibrary.requestAuthorization(for: .addOnly) { [weak self] status in
DispatchQueue.main.async {
if status == .authorized {
self?.presentPicker()
}
}
}
case .denied, .restricted:
authSettingOpen()
default:
break
}
}

private func presentPicker() {
var configuration = PHPickerConfiguration()
configuration.filter = .images // 이미지만 필터링
configuration.selectionLimit = 1 // 선택 제한

let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)
}

func authSettingOpen() {
let message = StringLiterals.Camera.photoNoAuth

let alert = UIAlertController(title: "설정", message: message, preferredStyle: .alert)

let cancle = UIAlertAction(title: "닫기", style: .default)

let confirm = UIAlertAction(title: "권한설정하기", style: .default) { (UIAlertAction) in
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
}

alert.addAction(cancle)
alert.addAction(confirm)

self.present(alert, animated: true, completion: nil)
}
}

extension JoinProfileViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true)

guard let selectedImage = results.first else { return }

selectedImage.itemProvider.loadObject(ofClass: UIImage.self) { (image, error) in
DispatchQueue.main.async {
if let image = image as? UIImage {
self.originView.profileImage.image = image
self.originView.profileImage.contentMode = .scaleAspectFill
self.originView.profileImage.layer.cornerRadius = self.originView.profileImage.frame.size.width / 2
self.originView.profileImage.clipsToBounds = true
} else if let error = error {
print(error)
}
}
}
}
}
Loading