Skip to content

Commit

Permalink
refactor #95: 이미지 출력 모드 뷰 분리
Browse files Browse the repository at this point in the history
  • Loading branch information
enebin committed Sep 14, 2023
1 parent 88fd46a commit 2656f46
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class PinchZoomView: UIView {
isPinching = false
scale = scale.between(min: 0.5, max: 2.0)
lastScale = scale
anchor = .center
offset = .zero
// anchor = .center
// offset = .zero
default:
break
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ struct PinchToZoomViewModifier: ViewModifier {

func body(content: Content) -> some View {
content
.scaleEffect(scale, anchor: anchor)
// .scaleEffect(scale, anchor: anchor)
.scaleEffect(scale)
.offset(offset)
.overlay(
PinchZoomViewRepresentable(
Expand Down
38 changes: 30 additions & 8 deletions Projects/Features/Sources/MyPage/MyPageFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@ public struct MyPageFeature: Reducer {
@Dependency(\.keymeAPIManager) private var network

public struct State: Equatable {
var view: View

var similarCircleDataList: [CircleData] = []
var differentCircleDataList: [CircleData] = []
var view: View

@Box var scoreListState: ScoreListFeature.State
@PresentationState var settingViewState: SettingFeature.State?
var imageExportModeState: ImageExportOverlayFeature.State? {
didSet {
view.imageExportMode = imageExportModeState == nil ? false : true
}
}

struct View: Equatable {
let userId: Int
Expand All @@ -47,16 +54,18 @@ public struct MyPageFeature: Reducer {
case showCircle(MyPageSegment)
case requestCircle(MatchRate)
case view(View)

case scoreListAction(ScoreListFeature.Action)
case setting(PresentationAction<SettingFeature.Action>)
case imageExportModeAction(ImageExportOverlayFeature.Action)

public enum View: Equatable {
case markViewAsShown
case circleTapped
case circleDismissed
case prepareSettingView
case selectSegement(MyPageSegment)
case setExportPhotoMode(enabled: Bool)
case enableImageExportMode
}
}

Expand All @@ -70,10 +79,7 @@ public struct MyPageFeature: Reducer {

Reduce { state, action in
switch action {
case .view(.selectSegement(let segment)):
state.view.selectedSegment = segment
return .send(.showCircle(state.view.selectedSegment))

// MARK: - Internal actions
// 서버 부하가 있으므로 웬만하면 한 번만 콜 할 것
case .requestCircle(let rate):
let userId = state.view.userId
Expand Down Expand Up @@ -117,6 +123,11 @@ public struct MyPageFeature: Reducer {
}
return .none

// MARK: - View actions
case .view(.selectSegement(let segment)):
state.view.selectedSegment = segment
return .send(.showCircle(state.view.selectedSegment))

case .view(.markViewAsShown):
state.view.shownFirstTime = false
return .none
Expand All @@ -135,21 +146,32 @@ public struct MyPageFeature: Reducer {
state.settingViewState = SettingFeature.State()
return .none

case .view(.setExportPhotoMode(let isEnabled)):
state.view.imageExportMode = isEnabled
case .view(.enableImageExportMode):
state.imageExportModeState = ImageExportOverlayFeature.State(
title: state.view.selectedSegment.title,
nickname: state.view.nickname)

return .none

// MARK: - Child actions
case .scoreListAction:
print("score")
return .none

case .imageExportModeAction(.dismissImageExportMode):
state.imageExportModeState = nil
return .none

default:
return .none
}
}
.ifLet(\.$settingViewState, action: /Action.setting) {
SettingFeature()
}
.ifLet(\.imageExportModeState, action: /Action.imageExportModeAction) {
ImageExportOverlayFeature()
}
}
}

Expand Down
113 changes: 113 additions & 0 deletions Projects/Features/Sources/MyPage/MyPageView+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//
// MyPageView+.swift
// Features
//
// Created by 이영빈 on 2023/09/08.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import ComposableArchitecture
import DSKit
import SwiftUI

public struct ImageExportOverlayFeature: Reducer {
public struct State: Equatable {
let title: String
let nickname: String
}

public enum Action: Equatable {
case dismissImageExportMode
case captureImage
}

public var body: some ReducerOf<Self> {
Reduce { _, _ in
return .none
}
}
}

extension MyPageView {
struct ImageExportOverlayView: View {
private typealias Action = () -> Void
private let store: StoreOf<ImageExportOverlayFeature>

init(store: StoreOf<ImageExportOverlayFeature>) {
self.store = store
}

var body: some View {
WithViewStore(store, observe: { $0 }) { viewStore in
VStack(spacing: 0) {
HStack {
closeButton(action: { viewStore.send(.dismissImageExportMode) })

Spacer()

photoCaptureButton(action: { viewStore.send(.captureImage) })
}
.padding(.horizontal, 20)
.padding(.top, 28)
.background(DSKitAsset.Color.keymeBlack.swiftUIColor)

DSKitAsset.Color.keymeBlack.swiftUIColor
.reverseMask { maskingShape(isFilled: true) }
.overlay {
maskingShape(isFilled: false).overlay {
VStack(alignment: .leading, spacing: 8) {
Text.keyme(viewStore.title, font: .body5)
.foregroundColor(.white.opacity(0.3))

Text.keyme("친구들이 생각하는\n\(viewStore.nickname)님의 성격은?", font: .heading1)
.foregroundColor(.white)

Spacer()
horizontalSpacer
}
.padding(28)
}
.padding(32)
}
.allowsHitTesting(false)
}
}
}

private func maskingShape(isFilled: Bool) -> some View {
let shape = RoundedRectangle(cornerRadius: 24)

return Group {
if isFilled {
shape.fill(Color.black)
} else {
shape.stroke(.white.opacity(0.3))
}
}
.padding(.bottom, 40)
}

private var horizontalSpacer: some View {
HStack { Spacer() }
}

private func closeButton(action: @escaping Action) -> some View {
Button(action: action) {
Image(systemName: "xmark")
.foregroundColor(.white)
}
}

private func photoCaptureButton(action: @escaping Action) -> some View {
Button(action: action) {
HStack {
DSKitAsset.Image.photoExport.swiftUIImage
Text("이미지 저장")
}
}
.foregroundColor(.white)
.padding(3)
.overlay { Capsule().stroke(Color.white.opacity(0.3)) }
}
}
}
75 changes: 8 additions & 67 deletions Projects/Features/Sources/MyPage/MyPageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct MyPageView: View {

@State var graphRotationAngle: Angle = .degrees(45)
@State var lastRotationAngle: Angle = .degrees(45)
@State var isGestureStarted = false

private let store: StoreOf<MyPageFeature>

Expand Down Expand Up @@ -53,82 +54,22 @@ struct MyPageView: View {
viewStore.send(.circleDismissed)
}
}
.graphFrame(length: viewStore.imageExportMode ? 560 : 700)
.simultaneousGesture(
RotationGesture()
.onChanged { angle in
graphRotationAngle = lastRotationAngle + angle * 0.01
lastRotationAngle = graphRotationAngle
}
)
.ignoresSafeArea(.container, edges: .bottom)

if viewStore.imageExportMode {
VStack(spacing: 0) {
HStack {
Button(action: { viewStore.send(.setExportPhotoMode(enabled: false)) }) {
Image(systemName: "xmark")
.foregroundColor(.white)
}
Spacer()
Button(action: {}) {
HStack {
DSKitAsset.Image.photoExport.swiftUIImage
Text("이미지 저장")
}
}
.foregroundColor(.white)
.padding(3)
.overlay(
Capsule()
.stroke(Color.white.opacity(0.3))
)
}
.padding(.horizontal, 20)
.padding(.top, 28)
.background(DSKitAsset.Color.keymeBlack.swiftUIColor)

DSKitAsset.Color.keymeBlack.swiftUIColor
.allowsHitTesting(false)
.reverseMask {
RoundedRectangle(cornerRadius: 24)
.fill(Color.black)
.padding(32)
.padding(.bottom, 40)
}
.overlay {
RoundedRectangle(cornerRadius: 24)
.stroke(.white.opacity(0.3))
.padding(.bottom, 40)
.overlay {
VStack(alignment: .leading, spacing: 8) {
Text.keyme(
viewStore.selectedSegment.title,
font: .body5)
.foregroundColor(.white.opacity(0.3))
Text.keyme(
"친구들이 생각하는\n\(viewStore.nickname)님의 성격은?",
font: .heading1)
.foregroundColor(.white)

Spacer()

HStack { Spacer() }
}
.padding(28)
}
.padding(32)
}
}
.ignoresSafeArea(edges: .bottom)
// Export 모드에 진입합니다
IfLetStore(store.scope(
state: \.imageExportModeState,
action: MyPageFeature.Action.imageExportModeAction)
) {
ImageExportOverlayView(store: $0)
}

// 개별 원이 보이거나 사진 export 모드가 아닌 경우에만 보여주는 부분
// 탑 바, 탭 바, top5, bottom5 등
if !viewStore.circleShown && !viewStore.imageExportMode {
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 4) {
Button(action: { viewStore.send(.setExportPhotoMode(enabled: true)) }) {
Button(action: { viewStore.send(.enableImageExportMode) }) {
DSKitAsset.Image.photoExport.swiftUIImage
.resizable()
.frame(width: 35, height: 35)
Expand Down

0 comments on commit 2656f46

Please sign in to comment.