Skip to content

Commit 62114b5

Browse files
authored
Merge pull request #370 from depromeet/feat/#367-camera-zoom-buttom-add
fix: camera zoom in zoom out Button Action 추가 및 ReactionMemberViewController Emoji Type추가
2 parents ac2a899 + e85983f commit 62114b5

File tree

14 files changed

+150
-68
lines changed

14 files changed

+150
-68
lines changed

14th-team5-iOS/App/Sources/Presentation/Camera/CameraViewController.swift

+59-30
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public final class CameraViewController: BaseViewController<CameraViewReactor> {
3636
private let toggleButton: UIButton = UIButton.createCircleButton(radius: 24)
3737
private let cameraIndicatorView: BibbiLoadingView = BibbiLoadingView()
3838
private let filterView: UIImageView = UIImageView()
39-
private let zoomView: UIImageView = UIImageView()
39+
private let zoomView: UIButton = UIButton()
4040
private let realEmojiDescriptionLabel = BibbiLabel(.body1Regular, textColor: .mainYellow)
4141
private let realEmojiFaceView = UIView()
4242
private let realEmojiFaceImageView = UIImageView()
@@ -71,7 +71,7 @@ public final class CameraViewController: BaseViewController<CameraViewReactor> {
7171
public override func setupUI() {
7272
super.setupUI()
7373
realEmojiFaceView.addSubview(realEmojiFaceImageView)
74-
view.addSubviews(cameraView, shutterButton, flashButton, toggleButton, realEmojiFaceView, realEmojiHorizontalStakView, realEmojiCollectionView, cameraIndicatorView , cameraNavigationBar)
74+
view.addSubviews(cameraView, shutterButton, flashButton, toggleButton, realEmojiFaceView, realEmojiHorizontalStakView, realEmojiCollectionView ,cameraIndicatorView , cameraNavigationBar)
7575
}
7676

7777
public override func setupAttributes() {
@@ -87,8 +87,8 @@ public final class CameraViewController: BaseViewController<CameraViewReactor> {
8787
}
8888

8989
zoomView.do {
90-
$0.image = DesignSystemAsset.zoom.image
91-
$0.contentMode = .scaleAspectFill
90+
$0.setBackgroundImage(DesignSystemAsset.zoomin.image, for: .normal)
91+
$0.setTitle("", for: .normal)
9292
}
9393

9494
realEmojiFlowLayout.do {
@@ -109,7 +109,6 @@ public final class CameraViewController: BaseViewController<CameraViewReactor> {
109109
$0.clipsToBounds = true
110110
$0.layer.cornerRadius = 35 / 2
111111
$0.backgroundColor = DesignSystemAsset.gray600.color
112-
$0.clipsToBounds = true
113112
}
114113

115114
realEmojiFaceImageView.do {
@@ -277,6 +276,41 @@ public final class CameraViewController: BaseViewController<CameraViewReactor> {
277276
NotificationCenter.default.post(name: .DidFinishProfileImageUpdate, object: nil, userInfo: userInfo)
278277
}.disposed(by: disposeBag)
279278

279+
zoomView
280+
.rx.tap
281+
.map { _ in CGFloat(1.0)}
282+
.map { Reactor.Action.didTapZoomButton($0)}
283+
.bind(to: reactor.action)
284+
.disposed(by: disposeBag)
285+
286+
reactor.pulse(\.$zoomScale)
287+
.withUnretained(self)
288+
.observe(on: MainScheduler.instance)
289+
.bind(onNext: {
290+
guard let currentCamera = $0.0.isToggle ? $0.0.frontCamera : $0.0.backCamera else { return }
291+
$0.0.transitionZoomImageScale(owner: $0.0, scale: $0.1, camera: currentCamera)
292+
}).disposed(by: disposeBag)
293+
294+
reactor.pulse(\.$pinchZoomScale)
295+
.withUnretained(self)
296+
.bind(onNext: {
297+
guard let currentCamera = $0.0.isToggle ? $0.0.frontCamera : $0.0.backCamera else { return }
298+
$0.0.transitionPinchImageScale(owner: $0.0, scale: $0.1, camera: currentCamera)
299+
}).disposed(by: disposeBag)
300+
301+
reactor.pulse(\.$zoomScale)
302+
.map { $0 == 2.0 ? DesignSystemAsset.zoomout.image : DesignSystemAsset.zoomin.image }
303+
.observe(on: MainScheduler.instance)
304+
.withUnretained(self)
305+
.bind(onNext: { $0.0.zoomView.setBackgroundImage($0.1, for: .normal) })
306+
.disposed(by: disposeBag)
307+
308+
reactor.pulse(\.$pinchZoomScale)
309+
.map { $0 == 10.0 ? DesignSystemAsset.zoomout.image : DesignSystemAsset.zoomin.image }
310+
.observe(on: MainScheduler.instance)
311+
.withUnretained(self)
312+
.bind(onNext: { $0.0.zoomView.setBackgroundImage($0.1, for: .normal) })
313+
.disposed(by: disposeBag)
280314

281315
reactor.state
282316
.map { ($0.accountImage, $0.profileImageURLEntity, $0.memberId)}
@@ -323,12 +357,10 @@ public final class CameraViewController: BaseViewController<CameraViewReactor> {
323357

324358
cameraView.rx
325359
.pinchGesture
326-
.withUnretained(self)
327-
.observe(on: MainScheduler.instance)
328-
.bind(onNext: {
329-
guard let currentCamera = $0.0.isToggle ? $0.0.frontCamera : $0.0.backCamera else { return }
330-
$0.0.transitionImageScale(owner: $0.0, gesture: $0.1, camera: currentCamera)
331-
}).disposed(by: disposeBag)
360+
.map { $0.scale }
361+
.map { Reactor.Action.dragPreviewLayer($0)}
362+
.bind(to: reactor.action)
363+
.disposed(by: disposeBag)
332364

333365

334366
toggleButton
@@ -530,25 +562,22 @@ extension CameraViewController: AVCapturePhotoCaptureDelegate {
530562
self.navigationController?.popViewController(animated: true)
531563
}
532564

533-
private func transitionImageScale(owner: CameraViewController, gesture: UIPinchGestureRecognizer, camera: AVCaptureDevice) {
534-
535-
switch gesture.state {
536-
537-
case .began:
538-
owner.initialScale = camera.videoZoomFactor
539-
540-
case .changed:
541-
let minAvailableZoomScale = camera.minAvailableVideoZoomFactor
542-
let maxAvailableZoomScale = camera.maxAvailableVideoZoomFactor
543-
let availableZoomScaleRange = minAvailableZoomScale...maxAvailableZoomScale
544-
let resolvedZoomScaleRange = zoomScaleRange.clamped(to: availableZoomScaleRange)
545-
546-
let resolvedScale = max(resolvedZoomScaleRange.lowerBound, min(gesture.scale * initialScale, resolvedZoomScaleRange.upperBound))
547-
setupImageScale(owner: owner, scale: resolvedScale, camera: camera)
548-
default:
549-
return
550-
551-
}
565+
private func transitionZoomImageScale(owner: CameraViewController, scale: CGFloat, camera: AVCaptureDevice) {
566+
let minAvailableZoomScale: CGFloat = 1.0
567+
let maxAvailableZoomScale: CGFloat = 2.0
568+
let availableZoomScaleRange = minAvailableZoomScale...maxAvailableZoomScale
569+
let resolvedZoomScaleRange = zoomScaleRange.clamped(to: availableZoomScaleRange)
570+
let resolvedScale = max(resolvedZoomScaleRange.lowerBound, min(scale, resolvedZoomScaleRange.upperBound))
571+
setupImageScale(owner: owner, scale: resolvedScale, camera: camera)
572+
}
573+
574+
private func transitionPinchImageScale(owner: CameraViewController, scale: CGFloat, camera: AVCaptureDevice) {
575+
let minAvailableZoomScale: CGFloat = 1.0
576+
let maxAvailableZoomScale: CGFloat = 10.0
577+
let availableZoomScaleRange = minAvailableZoomScale...maxAvailableZoomScale
578+
let resolvedZoomScaleRange = zoomScaleRange.clamped(to: availableZoomScaleRange)
579+
let resolvedScale = max(resolvedZoomScaleRange.lowerBound, min(scale, resolvedZoomScaleRange.upperBound))
580+
setupImageScale(owner: owner, scale: resolvedScale, camera: camera)
552581
}
553582

554583
private func showPermissionAlertController() {

14th-team5-iOS/App/Sources/Presentation/Camera/Reactor/CameraViewReactor.swift

+26
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ public final class CameraViewReactor: Reactor {
2727
case didTapFlashButton
2828
case didTapToggleButton
2929
case didTapShutterButton(Data)
30+
case didTapZoomButton(CGFloat)
3031
case didTapRealEmojiPad(IndexPath)
32+
case dragPreviewLayer(CGFloat)
3133
}
3234

3335
public enum Mutation {
@@ -36,6 +38,8 @@ public final class CameraViewReactor: Reactor {
3638
case setFlashMode(Bool)
3739
case uploadImageToS3(Bool)
3840
case setAccountProfileData(Data)
41+
case setPinchZoomScale(CGFloat)
42+
case setZoomScale(CGFloat)
3943
case setProfileImageURLResponse(CameraDisplayImageResponse?)
4044
case setProfileMemberResponse(ProfileMemberResponse?)
4145
case setRealEmojiImageURLResponse(CameraRealEmojiPreSignedResponse?)
@@ -62,6 +66,8 @@ public final class CameraViewReactor: Reactor {
6266
@Pulse var realEmojiSection: [EmojiSectionModel]
6367
@Pulse var reloadRealEmojiImage: [String: URL?]
6468
@Pulse var reloadRealEmojiId: [String: String]
69+
@Pulse var zoomScale: CGFloat
70+
@Pulse var pinchZoomScale: CGFloat
6571
var updateEmojiImage: URL?
6672
var emojiType: String
6773
var selectedEmojiPadItem: String
@@ -94,6 +100,8 @@ public final class CameraViewReactor: Reactor {
94100
realEmojiSection: [.realEmoji([])],
95101
reloadRealEmojiImage: [:],
96102
reloadRealEmojiId: [:],
103+
zoomScale: 1.0,
104+
pinchZoomScale: 1.0,
97105
updateEmojiImage: nil,
98106
emojiType: "EMOJI_1",
99107
selectedEmojiPadItem: "",
@@ -116,6 +124,12 @@ public final class CameraViewReactor: Reactor {
116124
return cameraUseCase.executeToggleCameraPosition(self.currentState.isSwitchPosition).map { .setPosition($0) }
117125
case .didTapFlashButton:
118126
return cameraUseCase.executeToggleCameraFlash(self.currentState.isFlashMode).map { .setFlashMode($0) }
127+
case let .didTapZoomButton(scale):
128+
if self.currentState.zoomScale == 2.0 {
129+
return .just(.setZoomScale(self.currentState.zoomScale - scale))
130+
} else {
131+
return .just(.setZoomScale(self.currentState.zoomScale + scale))
132+
}
119133

120134
case let .didTapShutterButton(fileData):
121135
return didTapShutterButtonMutation(imageData: fileData)
@@ -127,6 +141,14 @@ public final class CameraViewReactor: Reactor {
127141
.just(.setRealEmojiPadItem(CameraRealEmojiItems.allCases[indexPath.row].rawValue)),
128142
.just(.setRealEmojiType(CameraRealEmojiItems.allCases[indexPath.row].emojiType))
129143
)
144+
case let .dragPreviewLayer(scale):
145+
let minAvailableZoomScale: CGFloat = 1.0
146+
let maxAvailableZoomScale: CGFloat = 10.0
147+
let availableZoomScaleRange = minAvailableZoomScale...maxAvailableZoomScale
148+
let zoomScaleRange: ClosedRange<CGFloat> = 1...10
149+
let resolvedZoomScaleRange = zoomScaleRange.clamped(to: availableZoomScaleRange)
150+
151+
return .just(.setPinchZoomScale(max(resolvedZoomScaleRange.lowerBound, min(scale * self.currentState.pinchZoomScale, resolvedZoomScaleRange.upperBound))))
130152
}
131153

132154
}
@@ -171,6 +193,10 @@ public final class CameraViewReactor: Reactor {
171193
newState.reloadRealEmojiImage = reloadRealEmojiImage
172194
case let .setRealEmojiId(reloadRealEmojiId):
173195
newState.reloadRealEmojiId = reloadRealEmojiId
196+
case let .setZoomScale(zoomScale):
197+
newState.zoomScale = zoomScale
198+
case let .setPinchZoomScale(pinchZoomScale):
199+
newState.pinchZoomScale = pinchZoomScale
174200
}
175201

176202
return newState

14th-team5-iOS/App/Sources/Presentation/PostDetail/Dependency/ReactionDIContainer.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Domain
1212

1313
final class ReactionDIContainer {
1414
private func makeReactor(postId: String) -> TempReactor {
15-
return TempReactor(initialState: .init(postId: postId), emojiRepository: makeEmojiUseCase(), realEmojiRepository: makeRealEmojiUseCase())
15+
return TempReactor(initialState: .init(postId: postId, isShowingReactionMemberSheetType: .emoji1), emojiRepository: makeEmojiUseCase(), realEmojiRepository: makeRealEmojiUseCase())
1616
}
1717

1818
func makeViewController(postId: String) -> ReactionViewController {

14th-team5-iOS/App/Sources/Presentation/PostDetail/Dependency/ReactionMemberDIContainer.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ final class ReactionMemberDIContainer {
3030
return SearchFamilyUseCase(searchFamilyRepository: makeFamilyRepository())
3131
}
3232

33-
func makeReactionMemberReactor(memberIds: [String]) -> ReactionMemberReactor {
34-
return ReactionMemberReactor(initialState: .init(reactionMemberIds: memberIds), familyRepository: makeFamilyUseCase())
33+
func makeReactionMemberReactor(memberIds: [String], type: Emojis) -> ReactionMemberReactor {
34+
return ReactionMemberReactor(initialState: .init(reactionMemberIds: memberIds, reactionMemberType: type), familyRepository: makeFamilyUseCase())
3535
}
3636

37-
func makeViewController(memberIds: [String]) -> ReactionMembersViewController {
38-
return ReactionMembersViewController(reactor: makeReactionMemberReactor(memberIds: memberIds))
37+
func makeViewController(memberIds: [String], type: Emojis) -> ReactionMembersViewController {
38+
return ReactionMembersViewController(reactor: makeReactionMemberReactor(memberIds: memberIds, type: type))
3939
}
4040

4141
func makeEmojiRepository() -> EmojiRepository {

14th-team5-iOS/App/Sources/Presentation/PostDetail/Reactor/PostReactor.swift

-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ final class PostReactor: Reactor {
2121
enum Mutation {
2222
case setPop
2323
case setSelectedPostIndex(Int)
24-
case showReactionSheet([String])
2524
}
2625

2726
struct State {
@@ -68,8 +67,6 @@ extension PostReactor {
6867
}
6968
case .setPop:
7069
newState.isPop = true
71-
case let .showReactionSheet(memberIds):
72-
newState.reactionMemberIds = memberIds
7370
}
7471
return newState
7572
}

14th-team5-iOS/App/Sources/Presentation/PostDetail/Reactor/ReactionMemberReactor.swift

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ final class ReactionMemberReactor: Reactor {
2323

2424
struct State {
2525
let reactionMemberIds: [String]
26+
let reactionMemberType: Emojis
2627
var memberDataSource: [FamilyMemberProfileSectionModel] = []
2728
}
2829

14th-team5-iOS/App/Sources/Presentation/PostDetail/Reactor/TempReactor.swift

+8-1
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ final class TempReactor: Reactor {
2929
case setCommentSheet
3030
case setEmojiSheet
3131
case setReactionMemberSheet([String])
32+
case setReactionMemberType(Emojis)
3233
case updateDataSource([ReactionSection.Item])
3334
case setPostId(String)
3435
case setInitialDataSource
3536
}
3637

3738
struct State {
3839
var postId: String
40+
@Pulse var isShowingReactionMemberSheetType: Emojis
3941
var deSelectedReactionIndicies: [Int] = []
4042
var selectedReactionIndicies: [Int] = []
4143
var reactionSections: ReactionSection.Model = ReactionSection.Model(model: 0, items: [
@@ -84,7 +86,10 @@ extension TempReactor {
8486
case .longPressEmoji(let indexPath):
8587
switch currentState.reactionSections.items[indexPath.row] {
8688
case .main(let fetchedEmojiData):
87-
return Observable.just(Mutation.setReactionMemberSheet(fetchedEmojiData.memberIds))
89+
return Observable.concat(
90+
Observable.just(Mutation.setReactionMemberSheet(fetchedEmojiData.memberIds)),
91+
Observable.just(Mutation.setReactionMemberType(fetchedEmojiData.emojiType))
92+
)
8893
default:
8994
return Observable.empty()
9095
}
@@ -130,6 +135,8 @@ extension TempReactor {
130135
.addComment,
131136
.addReaction,
132137
])
138+
case .setReactionMemberType(let emojiType):
139+
newState.isShowingReactionMemberSheetType = emojiType
133140
}
134141
return newState
135142
}

14th-team5-iOS/App/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift

-18
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ final class PostViewController: BaseViewController<PostReactor> {
2929

3030
override func viewDidLoad() {
3131
super.viewDidLoad()
32-
3332
self.navigationController?.navigationBar.isHidden = true
3433
}
3534

@@ -65,12 +64,6 @@ final class PostViewController: BaseViewController<PostReactor> {
6564
})
6665
.disposed(by: disposeBag)
6766

68-
reactor.pulse(\.$reactionMemberIds)
69-
.withUnretained(self)
70-
.observe(on: MainScheduler.instance)
71-
.subscribe(onNext: { $0.0.showReactionSheet($0.1) })
72-
.disposed(by: disposeBag)
73-
7467
reactor.state
7568
.map { $0.isPop }
7669
.asObservable()
@@ -181,17 +174,6 @@ extension PostViewController {
181174
self.backgroundImageView.kf.setImage(with: url)
182175
}
183176

184-
private func showReactionSheet(_ memberIds: [String]) {
185-
if memberIds.isEmpty { return }
186-
187-
let reactionMembersViewController = ReactionMemberDIContainer().makeViewController(memberIds: memberIds)
188-
if let sheet = reactionMembersViewController.sheetPresentationController {
189-
sheet.detents = [.medium()]
190-
sheet.prefersGrabberVisible = true
191-
}
192-
193-
present(reactionMembersViewController, animated: true)
194-
}
195177

196178
private func calculateCurrentPage(offset: CGPoint) -> Int {
197179
guard collectionView.frame.width > 0 else {

0 commit comments

Comments
 (0)