-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CAT-176] Onboarding paging뷰 ui 및 기능구현 (#25)
- Loading branch information
Showing
11 changed files
with
309 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 0 additions & 33 deletions
33
Projects/Feature/OnboardingFeature/Interface/OnboardingCoreInterface.swift
This file was deleted.
Oops, something went wrong.
28 changes: 0 additions & 28 deletions
28
Projects/Feature/OnboardingFeature/Interface/OnboardingView.swift
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
Projects/Feature/OnboardingFeature/Sources/Onboarding/Helpers/OffsetReader.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// OffsetReader.swift | ||
// OnboardingFeature | ||
// | ||
// Created by 김지현 on 8/14/24. | ||
// Copyright © 2024 PomoNyang. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct OffsetKey: PreferenceKey { | ||
static var defaultValue: CGFloat = .zero | ||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { | ||
value = nextValue() | ||
} | ||
} | ||
|
||
extension View { | ||
@ViewBuilder | ||
func offsetX(_ addObserver: Bool, completion: @escaping (CGFloat) -> Void) -> some View { | ||
self | ||
.frame(maxWidth: .infinity) | ||
.overlay { | ||
if addObserver { | ||
GeometryReader { geometry in | ||
let minX = geometry.frame(in: .global).minX | ||
Color.clear | ||
.preference(key: OffsetKey.self, value: minX) | ||
.onPreferenceChange(OffsetKey.self, perform: completion) | ||
} | ||
} | ||
} | ||
} | ||
} |
129 changes: 129 additions & 0 deletions
129
Projects/Feature/OnboardingFeature/Sources/Onboarding/OnboardingCore.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// | ||
// OnboardingCore.swift | ||
// OnboardingFeature | ||
// | ||
// Created by devMinseok on 7/22/24. | ||
// Copyright © 2024 PomoNyang. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
import ComposableArchitecture | ||
|
||
@Reducer | ||
public struct OnboardingCore { | ||
@ObservableState | ||
public struct State: Equatable { | ||
public init() { } | ||
var data: [OnboardingItem] = OnboardingItemsData | ||
var fakedData: [OnboardingItem] = [] | ||
var width: CGFloat = .zero | ||
var currentIdx: Int = 0 | ||
var currentItemID: String = "" | ||
} | ||
|
||
public enum Action: BindableAction { | ||
case onApear | ||
case calculateOffset(CGFloat, OnboardingItem) | ||
case dragStart | ||
case _timerStart | ||
case _timerEnd | ||
case _timerTicked | ||
case _nextPage(Int) | ||
case _resetTofront | ||
case binding(BindingAction<State>) | ||
} | ||
|
||
public init() { } | ||
|
||
@Dependency(\.continuousClock) var clock | ||
@Dependency(\.mainQueue) var mainQueue | ||
|
||
public var body: some ReducerOf<Self> { | ||
BindingReducer() | ||
Reduce(self.core) | ||
} | ||
|
||
private func core(_ state: inout State, _ action: Action) -> EffectOf<Self> { | ||
enum CancelID { case timer, timerDebounce } | ||
|
||
switch action { | ||
case .onApear: | ||
state.currentItemID = state.data.first!.id.uuidString | ||
state.fakedData = state.data | ||
guard var first = state.data.first, | ||
var last = state.data.last else { return .none } | ||
first.id = .init() | ||
last.id = .init() | ||
state.fakedData.append(first) | ||
state.fakedData.insert(last, at: 0) | ||
return .run { send in | ||
await send(._timerStart) | ||
} | ||
|
||
case .calculateOffset(let minX, let item): | ||
let fakeIndex = state.fakedData.firstIndex(of: item) ?? 0 | ||
state.currentIdx = state.data.firstIndex { item in | ||
item.id.uuidString == state.currentItemID | ||
} ?? 0 | ||
let pageOffset = minX - state.width * CGFloat(fakeIndex) | ||
|
||
let pageProgress: CGFloat = pageOffset / state.width | ||
if -pageProgress < 1.0 { | ||
if state.fakedData.indices.contains(state.fakedData.count - 1) { | ||
state.currentItemID = state.fakedData[state.fakedData.count - 1].id.uuidString | ||
} | ||
} | ||
if -pageProgress > CGFloat(state.fakedData.count - 1) { | ||
if state.fakedData.indices.contains(1) { | ||
state.currentItemID = state.fakedData[1].id.uuidString | ||
} | ||
} | ||
return .none | ||
|
||
case .dragStart: | ||
let timerEndAction: Effect<Action> = .run { send in await send(._timerEnd) } | ||
let timerStartAction: Effect<Action> = .run { send in await send(._timerStart) } | ||
.debounce(id: CancelID.timerDebounce, for: .seconds(2), scheduler: self.mainQueue) | ||
return .merge( | ||
timerEndAction, | ||
timerStartAction | ||
) | ||
|
||
case ._timerStart: | ||
return .run { send in | ||
for await _ in self.clock.timer(interval: .seconds(3)) { | ||
await send(._timerTicked) | ||
} | ||
} | ||
.cancellable(id: CancelID.timer) | ||
|
||
case ._timerEnd: | ||
return .cancel(id: CancelID.timer) | ||
|
||
case ._timerTicked: | ||
let index = state.fakedData.firstIndex { item in | ||
item.id.uuidString == state.currentItemID | ||
} ?? 0 | ||
return .run { [index = index] send in | ||
if index == 4 { | ||
await send(._resetTofront) | ||
await send(._nextPage(2), animation: .easeInOut(duration: 0.3)) | ||
} else { | ||
await send(._nextPage(index + 1), animation: .easeInOut(duration: 0.3)) | ||
} | ||
} | ||
|
||
case ._nextPage(let index): | ||
state.currentItemID = state.fakedData[index].id.uuidString | ||
return .none | ||
|
||
case ._resetTofront: | ||
state.currentItemID = state.fakedData[1].id.uuidString | ||
return .none | ||
|
||
default: | ||
return .none | ||
} | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
Projects/Feature/OnboardingFeature/Sources/Onboarding/OnboardingItem.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// OnboardingItem.swift | ||
// OnboardingFeature | ||
// | ||
// Created by 김지현 on 8/9/24. | ||
// Copyright © 2024 PomoNyang. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
import DesignSystem | ||
|
||
public struct OnboardingItem: Equatable, Identifiable { | ||
public var id: UUID = .init() | ||
let image: Image | ||
var title: String | ||
let subTitle: String | ||
} | ||
|
||
let OnboardingItemsData: [OnboardingItem] = [ | ||
OnboardingItem( | ||
image: Image(systemName: "star"), | ||
title: "모하냥과 함께 집중시간을 늘려보세요", | ||
subTitle: "고양이 종에 따라 성격이 달라요.\n취향에 맞는 고양이를 선택해 몰입해 보세요."), | ||
OnboardingItem( | ||
image: Image(systemName: "star.fill"), | ||
title: "다른 앱을 실행하면 방해 알림을 보내요", | ||
subTitle: "뽀모도로를 실행한 후, 다른 앱을 사용하면\n설정한 주기로 방해 알림을 보내드려요."), | ||
OnboardingItem( | ||
image: Image(systemName: "house"), | ||
title: "집중과 휴식 반복을 통해 몰입을 관리해요", | ||
subTitle: "일정 시간 집중과 휴식을 반복해 번아웃을 방지하고\n짧은 시간의 몰입을 경험해보세요.") | ||
] | ||
|
Oops, something went wrong.