Skip to content

Commit

Permalink
Merge pull request #103 from DSM-PICK/feature/#102-profile_image
Browse files Browse the repository at this point in the history
feat :: [#102] 프로필 수정 기능 추가
  • Loading branch information
cyj513 authored Oct 18, 2024
2 parents cfe0418 + bf8bc23 commit 1d367e3
Show file tree
Hide file tree
Showing 21 changed files with 257 additions and 70 deletions.
2 changes: 1 addition & 1 deletion Projects/Data/Sources/API/AuthAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extension AuthAPI: PiCKAPI {
public typealias ErrorType = PiCKError

public var urlType: PiCKURL {
.user
return .user
}

public var urlPath: String {
Expand Down
2 changes: 1 addition & 1 deletion Projects/Data/Sources/API/BugAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extension BugAPI: PiCKAPI {
public typealias ErrorType = PiCKError

public var urlType: PiCKURL {
.bug
return .bug
}

public var urlPath: String {
Expand Down
25 changes: 23 additions & 2 deletions Projects/Data/Sources/API/ProfileAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import AppNetwork
public enum ProfileAPI {
case fetchSimpleProfile
case fetchDetailProfile
case uploadProfileImage(image: Data)
}

extension ProfileAPI: PiCKAPI {
Expand All @@ -24,15 +25,35 @@ extension ProfileAPI: PiCKAPI {
return "/simple"
case .fetchDetailProfile:
return "/details"
case .uploadProfileImage:
return "/profile"
}
}

public var method: Moya.Method {
return .get
switch self {
case .uploadProfileImage:
return .patch
default:
return .get
}
}

public var task: Moya.Task {
return .requestPlain
switch self {
case .uploadProfileImage(let image):
var multiformData: [MultipartFormData] = []
multiformData.append(.init(
provider: .data(image),
name: "file",
fileName: "file.jpg",
mimeType: "file/jpg"
))

return .uploadMultipart(multiformData)
default:
return .requestPlain
}
}

public var pickHeader: TokenType {
Expand Down
3 changes: 3 additions & 0 deletions Projects/Data/Sources/DI/UseCaseAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ public final class UseCaseAssembly: Assembly {
container.register(FetchDetailProfileUseCase.self) { resolver in
FetchDetailProfileUseCase(repository: resolver.resolve(ProfileRepository.self)!)
}
container.register(UploadProfileImageUseCase.self) { resolver in
UploadProfileImageUseCase(repository: resolver.resolve(ProfileRepository.self)!)
}
// bug
container.register(BugImageUploadUseCase.self) { resolver in
BugImageUploadUseCase(repository: resolver.resolve(BugRepository.self)!)
Expand Down
7 changes: 7 additions & 0 deletions Projects/Data/Sources/DataSource/ProfileDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Domain
protocol ProfileDataSource {
func fetchSimpleProfile() -> Single<Response>
func fetchDetailProfile() -> Single<Response>
func uploadProfileImage(image: Data) -> Completable
}

class ProfileDataSourceImpl: BaseDataSource<ProfileAPI>, ProfileDataSource {
Expand All @@ -23,4 +24,10 @@ class ProfileDataSourceImpl: BaseDataSource<ProfileAPI>, ProfileDataSource {
.filterSuccessfulStatusCodes()
}

func uploadProfileImage(image: Data) -> Completable {
return request(.uploadProfileImage(image: image))
.filterSuccessfulStatusCodes()
.asCompletable()
}

}
4 changes: 4 additions & 0 deletions Projects/Data/Sources/Repository/ProfileRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ class ProfileRepositoryImpl: ProfileRepository {
.map { $0.toDomain() }
}

func uploadProfileImage(image: Data) -> Completable {
return remoteDataSource.uploadProfileImage(image: image)
}

}
1 change: 1 addition & 0 deletions Projects/Domain/Sources/Repository/ProfileRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ import RxSwift
public protocol ProfileRepository {
func fetchSimpleProfile() -> Single<SimpleProfileEntity>
func fetchDetailProfile() -> Single<DetailProfileEntity>
func uploadProfileImage(image: Data) -> Completable
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Foundation

import RxSwift

public class UploadProfileImageUseCase {
let repository: ProfileRepository

public init(repository: ProfileRepository) {
self.repository = repository
}

public func execute(image: Data) -> Completable {
return repository.uploadProfileImage(image: image)
}

}
2 changes: 1 addition & 1 deletion Projects/Flow/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ let project = Project.makeModule(
platform: .iOS,
product: .staticLibrary,
dependencies: [
.Projects.presentation,
.Projects.data,
.Projects.presentation,
.SPM.FCM
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,30 @@ import RxSwift
import RxCocoa
import RxGesture

import Kingfisher

import Core

public class PiCKProfileView: BaseView {
private let profileImageView = UIImageView(image: .profile)
private let profileImageView = UIImageView().then {
$0.contentMode = .scaleToFill
$0.layer.cornerRadius = 30
$0.clipsToBounds = true
}
private let userInfoLabel = PiCKLabel(
textColor: .modeBlack,
font: .label1,
numberOfLines: 0
)

public func setup(
image: UIImage,
image: String,
info: String
) {
self.profileImageView.image = image
self.profileImageView.kf.setImage(
with: URL(string: image),
placeholder: UIImage.profile
)
self.userInfoLabel.text = "대덕소프트웨어마이스터고\n\(info)"
}

Expand Down
7 changes: 5 additions & 2 deletions Projects/Presentation/Sources/DI/PresentationAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ public final class PresentationAssembly: Assembly {
}
container.register(AllTabViewModel.self) { resolver in
AllTabViewModel(
logoutUseCase: resolver.resolve(LogoutUseCase.self)!)
fetchProfileUsecase: resolver.resolve(FetchSimpleProfileUseCase.self)!,
logoutUseCase: resolver.resolve(LogoutUseCase.self)!
)
}
// Notice
container.register(NoticeListViewController.self) { resolver in
Expand Down Expand Up @@ -182,7 +184,8 @@ public final class PresentationAssembly: Assembly {
}
container.register(MyPageViewModel.self) { resolver in
MyPageViewModel(
profileUsecase: resolver.resolve(FetchDetailProfileUseCase.self)!
profileUsecase: resolver.resolve(FetchDetailProfileUseCase.self)!,
uploadProfileImageUseCase: resolver.resolve(UploadProfileImageUseCase.self)!
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class AllTabViewController: BaseViewController<AllTabViewModel> {
}
public override func bind() {
let input = AllTabViewModel.Input(
viewWillAppear: viewWillAppearRelay.asObservable(),
clickSelfStudyTab: helpSectionView.getSelectedItem(type: .selfStudy).asObservable(),
clickNoticeTab: helpSectionView.getSelectedItem(type: .notice).asObservable(),
clickBugReportTab: helpSectionView.getSelectedItem(type: .bugReport).asObservable(),
Expand All @@ -53,7 +54,18 @@ public class AllTabViewController: BaseViewController<AllTabViewModel> {
clickLogOutTab: logoutRelay.asObservable()
)

_ = viewModel.transform(input: input)
let output = viewModel.transform(input: input)

output.profileData.asObservable()
.withUnretained(self)
.bind { owner, profileData in
let userInfoData = UserDefaultStorage.shared.get(forKey: .userInfoData) as? String

owner.profileView.setup(
image: profileData.profile ?? "",
info: userInfoData ?? "정보가 없는 사용자"
)
}.disposed(by: disposeBag)

accountSectionView
.getSelectedItem(type: .logOut)
Expand Down Expand Up @@ -103,9 +115,4 @@ public class AllTabViewController: BaseViewController<AllTabViewModel> {
}
}

public override func setLayoutData() {
let userInfoData = UserDefaultStorage.shared.get(forKey: .userInfoData) as? String
self.profileView.setup(image: .profile, info: userInfoData ?? "정보가 없는 사용자")
}

}
28 changes: 25 additions & 3 deletions Projects/Presentation/Sources/Scene/AllTab/AllTabViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@ import Domain
public class AllTabViewModel: BaseViewModel, Stepper {
private let disposeBag = DisposeBag()
public var steps = PublishRelay<Step>()

private let fetchProfileUsecase: FetchSimpleProfileUseCase
private let logoutUseCase: LogoutUseCase

public init(logoutUseCase: LogoutUseCase) {
public init(
fetchProfileUsecase: FetchSimpleProfileUseCase,
logoutUseCase: LogoutUseCase
) {
self.fetchProfileUsecase = fetchProfileUsecase
self.logoutUseCase = logoutUseCase
}

public struct Input {
let viewWillAppear: Observable<Void>
let clickSelfStudyTab: Observable<IndexPath>
let clickNoticeTab: Observable<IndexPath>
let clickBugReportTab: Observable<IndexPath>
Expand All @@ -25,9 +32,24 @@ public class AllTabViewModel: BaseViewModel, Stepper {
let clickMyPageTab: Observable<IndexPath>
let clickLogOutTab: Observable<Void>
}
public struct Output {}
public struct Output {
let profileData: Signal<SimpleProfileEntity>
}

private let profileData = PublishRelay<SimpleProfileEntity>()

public func transform(input: Input) -> Output {
input.viewWillAppear
.flatMap {
self.fetchProfileUsecase.execute()
.catch {
print($0.localizedDescription)
return .never()
}
}
.bind(to: profileData)
.disposed(by: disposeBag)

input.clickSelfStudyTab
.map { _ in PiCKStep.selfStudyIsRequired }
.bind(to: steps)
Expand Down Expand Up @@ -66,7 +88,7 @@ public class AllTabViewModel: BaseViewModel, Stepper {
.bind(to: steps)
.disposed(by: disposeBag)

return Output()
return Output(profileData: profileData.asSignal())
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@ import UIKit

import SnapKit
import Then

import RxSwift
import RxCocoa

import Kingfisher

import Core
import DesignSystem

public class MyPageViewController: BaseViewController<MyPageViewModel> {
private let profileImageView = UIImageView(image: .profile)
private var profileImageData = PublishRelay<Data>()

private let profileImageView = UIImageView().then {
$0.layer.cornerRadius = 40
$0.clipsToBounds = true
$0.contentMode = .scaleAspectFill
}
private let changeButton = UIButton(type: .system).then {
// $0.setTitle("변경하기", for: .normal)
$0.setTitle("", for: .normal)
$0.setTitle("변경하기", for: .normal)
$0.setTitleColor(.gray500, for: .normal)
$0.titleLabel?.font = .body1
}
Expand Down Expand Up @@ -47,17 +55,33 @@ public class MyPageViewController: BaseViewController<MyPageViewModel> {
}
public override func bind() {
let input = MyPageViewModel.Input(
viewWillAppear: viewWillAppearRelay.asObservable()
viewWillAppear: viewWillAppearRelay.asObservable(),
profileImage: profileImageData.asObservable()
)
let output = viewModel.transform(input: input)

output.profileData.asObservable()
.bind(onNext: { [weak self] profileData in
self?.userNameLabel.text = profileData.name
self?.userBirthDayLabel.text = "\(profileData.birthDay.toDate(type: .fullDate).toString(type: .fullDateKorForCalendar))"
self?.userSchoolIDLabel.text = "\(profileData.grade)학년 \(profileData.classNum)\(profileData.num)"
self?.userIDLabel.text = profileData.accountID
}).disposed(by: disposeBag)
.withUnretained(self)
.bind { owner, profileData in
owner.profileImageView.kf.setImage(
with: URL(string: profileData.profile ?? ""),
placeholder: UIImage.profile
)
owner.userNameLabel.text = profileData.name
owner.userBirthDayLabel.text = "\(profileData.birthDay.toDate(type: .fullDate).toString(type: .fullDateKorForCalendar))"
owner.userSchoolIDLabel.text = "\(profileData.grade)학년 \(profileData.classNum)\(profileData.num)"
owner.userIDLabel.text = profileData.accountID
}.disposed(by: disposeBag)
}
public override func bindAction() {
changeButton.rx.tap
.bind { [weak self] in
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.allowsEditing = true
picker.delegate = self
self?.present(picker, animated: true)
}.disposed(by: disposeBag)
}

public override func addView() {
Expand All @@ -72,6 +96,7 @@ public class MyPageViewController: BaseViewController<MyPageViewModel> {
profileImageView.snp.makeConstraints {
$0.centerX.equalToSuperview()
$0.top.equalTo(view.safeAreaLayoutGuide).offset(40)
$0.size.equalTo(80)
}
changeButton.snp.makeConstraints {
$0.centerX.equalToSuperview()
Expand Down Expand Up @@ -99,3 +124,16 @@ public class MyPageViewController: BaseViewController<MyPageViewModel> {
}

}

extension MyPageViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
public func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
picker.dismiss(animated: true) { [weak self] in
let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
self?.profileImageView.image = image
self?.profileImageData.accept(image?.jpegData(compressionQuality: 0.1) ?? Data())
}
}
}
Loading

0 comments on commit 1d367e3

Please sign in to comment.