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] #39 - Carousel 수정 #97

Merged
merged 8 commits into from
Feb 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 23 additions & 6 deletions Record.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
8715A798285531AB001AB4F5 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8715A797285531AB001AB4F5 /* SearchView.swift */; };
8715A79B2855479E001AB4F5 /* MusicAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8715A79A2855479E001AB4F5 /* MusicAPI.swift */; };
8715A79D2855B5AC001AB4F5 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8715A79C2855B5AC001AB4F5 /* Colors.xcassets */; };
8786B2F129AA547C000B46A1 /* CDPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8786B2F029AA547C000B46A1 /* CDPlayer.swift */; };
8786B2F329AA5726000B46A1 /* CDList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8786B2F229AA5726000B46A1 /* CDList.swift */; };
8786B2F529AA5CED000B46A1 /* MusicInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8786B2F429AA5CED000B46A1 /* MusicInformation.swift */; };
87A0D9B1285BAEF8006D0D3B /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87A0D9B0285BAEF8006D0D3B /* Persistence.swift */; };
87A0D9B4285BAF42006D0D3B /* Record.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 87A0D9B2285BAF42006D0D3B /* Record.xcdatamodeld */; };
87B6E3CD28EC9764002D579A /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B6E3CC28EC9764002D579A /* Color+Extensions.swift */; };
87B6E3CF28EC978D002D579A /* Font+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B6E3CE28EC978D002D579A /* Font+Extensions.swift */; };
87B6E3D128EC97B0002D579A /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B6E3D028EC97B0002D579A /* View+Extensions.swift */; };
87B6E3D328EC97CE002D579A /* UIScreen+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B6E3D228EC97CE002D579A /* UIScreen+Extensions.swift */; };
87C429EB28E37594009B6DA6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87C429EA28E37594009B6DA6 /* LaunchScreen.storyboard */; };
87D686F229A63B9F00E3707F /* EmptyCDListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D686F129A63B9F00E3707F /* EmptyCDListView.swift */; };
87D686F429A6768900E3707F /* FramePreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D686F329A6768900E3707F /* FramePreferenceKey.swift */; };
87E96F4928DF93C4007D167E /* FirstPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87E96F4828DF93C4007D167E /* FirstPage.swift */; };
87E96F4B28DF93CC007D167E /* SecondPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87E96F4A28DF93CC007D167E /* SecondPage.swift */; };
87E96F4D28DF940A007D167E /* ThirdPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87E96F4C28DF940A007D167E /* ThirdPage.swift */; };
Expand All @@ -38,6 +43,7 @@
B277EC172859A679001A97B1 /* CdListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B277EC162859A679001A97B1 /* CdListView.swift */; };
B29723B0285B192C0065FD36 /* SnapCarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B29723AF285B192C0065FD36 /* SnapCarouselView.swift */; };
F9BA11F329A499D500176807 /* MarqueeTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9BA11F229A499D500176807 /* MarqueeTextView.swift */; };

/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -55,13 +61,18 @@
8715A797285531AB001AB4F5 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = "<group>"; };
8715A79A2855479E001AB4F5 /* MusicAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicAPI.swift; sourceTree = "<group>"; };
8715A79C2855B5AC001AB4F5 /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = "<group>"; };
8786B2F029AA547C000B46A1 /* CDPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CDPlayer.swift; sourceTree = "<group>"; };
8786B2F229AA5726000B46A1 /* CDList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CDList.swift; sourceTree = "<group>"; };
8786B2F429AA5CED000B46A1 /* MusicInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicInformation.swift; sourceTree = "<group>"; };
87A0D9B0285BAEF8006D0D3B /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
87A0D9B3285BAF42006D0D3B /* Recored.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Recored.xcdatamodel; sourceTree = "<group>"; };
87B6E3CC28EC9764002D579A /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = "<group>"; };
87B6E3CE28EC978D002D579A /* Font+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Font+Extensions.swift"; sourceTree = "<group>"; };
87B6E3D028EC97B0002D579A /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
87B6E3D228EC97CE002D579A /* UIScreen+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScreen+Extensions.swift"; sourceTree = "<group>"; };
87C429EA28E37594009B6DA6 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
87D686F129A63B9F00E3707F /* EmptyCDListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyCDListView.swift; sourceTree = "<group>"; };
87D686F329A6768900E3707F /* FramePreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramePreferenceKey.swift; sourceTree = "<group>"; };
87E96F4828DF93C4007D167E /* FirstPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstPage.swift; sourceTree = "<group>"; };
87E96F4A28DF93CC007D167E /* SecondPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondPage.swift; sourceTree = "<group>"; };
87E96F4C28DF940A007D167E /* ThirdPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPage.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -170,9 +181,11 @@
87B6E3D928EC9C27002D579A /* CDListView */ = {
isa = PBXGroup;
children = (
B277EC162859A679001A97B1 /* CdListView.swift */,
B29723AF285B192C0065FD36 /* SnapCarouselView.swift */,
B277EC142859A671001A97B1 /* Carousel.swift */,
B277EC162859A679001A97B1 /* CDListView.swift */,
87D686F129A63B9F00E3707F /* EmptyCDListView.swift */,
8786B2F429AA5CED000B46A1 /* MusicInformation.swift */,
8786B2F229AA5726000B46A1 /* CDList.swift */,
8786B2F029AA547C000B46A1 /* CDPlayer.swift */,
F9BA11F229A499D500176807 /* MarqueeTextView.swift */,
);
path = CDListView;
Expand Down Expand Up @@ -218,6 +231,7 @@
isa = PBXGroup;
children = (
87F1956C295FED74004A1CAF /* URLImage.swift */,
87D686F329A6768900E3707F /* FramePreferenceKey.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -294,24 +308,27 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B277EC172859A679001A97B1 /* CDListView.swift in Sources */,
8786B2F129AA547C000B46A1 /* CDPlayer.swift in Sources */,
8786B2F529AA5CED000B46A1 /* MusicInformation.swift in Sources */,
F9BA11F329A499D500176807 /* MarqueeTextView.swift in Sources */,
B277EC172859A679001A97B1 /* CdListView.swift in Sources */,
87E96F4928DF93C4007D167E /* FirstPage.swift in Sources */,
87E96F4B28DF93CC007D167E /* SecondPage.swift in Sources */,
A01413222855F4E60000EA59 /* HomeView.swift in Sources */,
3D49B5B0285A41570054FDED /* PhotoModalView.swift in Sources */,
87D686F229A63B9F00E3707F /* EmptyCDListView.swift in Sources */,
8786B2F329AA5726000B46A1 /* CDList.swift in Sources */,
3D593E472858530B00E481C7 /* WritingModalView.swift in Sources */,
87B6E3CF28EC978D002D579A /* Font+Extensions.swift in Sources */,
B29723B0285B192C0065FD36 /* SnapCarouselView.swift in Sources */,
87E96F4D28DF940A007D167E /* ThirdPage.swift in Sources */,
87FB281D285A04680036A5BB /* Screenshot.swift in Sources */,
87F1956D295FED74004A1CAF /* URLImage.swift in Sources */,
87D686F429A6768900E3707F /* FramePreferenceKey.swift in Sources */,
8715A79B2855479E001AB4F5 /* MusicAPI.swift in Sources */,
87B6E3CD28EC9764002D579A /* Color+Extensions.swift in Sources */,
87A0D9B4285BAF42006D0D3B /* Record.xcdatamodeld in Sources */,
A0AA39BB285A4936009EE3EA /* OnboardingView.swift in Sources */,
A0AA39BF285AF643009EE3EA /* FourthPage.swift in Sources */,
B277EC152859A671001A97B1 /* Carousel.swift in Sources */,
A01413222855F4E60000EA59 /* HomeView.swift in Sources */,
87B6E3D328EC97CE002D579A /* UIScreen+Extensions.swift in Sources */,
3D49B5AE285A02B50054FDED /* StoryModalView.swift in Sources */,
Expand Down
16 changes: 16 additions & 0 deletions Record/Extensions/View+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,19 @@ extension View {
}
}
}


extension View {

func frame(perform: @escaping (CGRect) -> Void) -> some View {
background(
GeometryReader {
Color.clear
.preference(key: FramePreferenceKey.self, value: $0.frame(in: .global))
}
)
.onPreferenceChange(FramePreferenceKey.self) { value in
DispatchQueue.main.async { perform(value) }
}
}
}
142 changes: 142 additions & 0 deletions Record/Views/CDListView/CDList.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//
// CDList.swift
// Record
//
// Created by 이지원 on 2023/02/25.
//

import SwiftUI

/**
사용자가 저장한 모든 CD(이야기)를 캐러셀 형태로 보여주는 뷰 입니다.

- Parameters:
- items: Content 리스트 (core data에 저장된 데이터)
- currentIndex: 사용자가 선택한 CD index 번호
*/

struct CDList: View {

@Binding var items: [Content]
@Binding var currentIndex: Int

// MARK: Carousel Animaion
@State private var pointX: CGFloat = 0
@State private var size: CGSize = .zero
@State private var isDragging = false

@GestureState private var offsetState: CGSize = .zero

private let spacing: CGFloat = -UIScreen.getWidth(90)
private let cdSize: CGFloat = UIScreen.getWidth(200)

private var firstItemPositionX: CGFloat {
(cdSize * CGFloat(max(0, items.count - 1)) + spacing * CGFloat(max(0, items.count - 1))) / 2 + size.width / 2
}

var body: some View {

ZStack {

GeometryReader { proxy in

HStack(spacing: spacing) {

ForEach (items.indices, id: \.self) { i in

// MARK: - CD
ZStack {

URLImage(urlString: items[i].albumArt ?? "")
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
.shadow(color: Color(.gray), radius: 4, x: 0, y: 4)

Circle()
.frame(width: UIScreen.getWidth(40), height: UIScreen.getHeight(40))
.foregroundColor(.background)
.overlay(
Circle()
.stroke(.background, lineWidth: 0.1)
.shadow(color: .titleDarkgray, radius: 2, x: 3, y: 3)
)
}
.frame(width: cdSize, height: cdSize)
.scaleEffect(max(1.0 - abs(distance(i)) * 0.25, 0.0001))
.zIndex(1.0 - abs(distance(i) * 0.1))
.opacity(1.0 - abs(distance(i) * 0.3))
.frame { value in
let range = cdSize + spacing

if isDragging {
var ratio: CGFloat {
switch value.origin.x {
case (proxy.size.width / 2 - cdSize / 2)...(proxy.size.width + cdSize / 2 + spacing):
let offset = (proxy.size.width + cdSize / 2 + spacing) - (proxy.size.width / 2) - value.origin.x
return offset / range

case (spacing / 2)..<(proxy.size.width / 2 - cdSize / 2):
let offset = ((proxy.size.width - cdSize) / 2) - value.origin.x
return 1 - offset / range

default:
return 0
}
}

withAnimation {
if 0.5 < ratio {
currentIndex = i
}
}
}
}
.onTapGesture {
withAnimation {
self.currentIndex = i
pointX = -(CGFloat(currentIndex) * cdSize + (CGFloat(currentIndex) * spacing))
}
}
}
}
.position(x: firstItemPositionX + pointX + offsetState.width, y: proxy.size.height / 2)
.task {
size = proxy.size
}
}
}
.onAppear {
withAnimation {
pointX = -(CGFloat(currentIndex) * cdSize + (CGFloat(currentIndex) * spacing))
}
}
.gesture(
DragGesture()
.updating($offsetState) { currentState, gestureState, transaction in
gestureState = currentState.translation
}
.onChanged { value in
isDragging = true
}

.onEnded { value in

isDragging = false
pointX += value.translation.width

withAnimation(.spring(response: 0.5, dampingFraction: 0.9, blendDuration: 0)) {
pointX = -(CGFloat(currentIndex) * cdSize + (CGFloat(currentIndex) * spacing))
}

let haptic = UIImpactFeedbackGenerator(style: .soft)
haptic.impactOccurred()
}
)
.frame(height: cdSize)

}

private func distance(_ index: Int) -> Double {
return Double(currentIndex - index)
}
}
47 changes: 47 additions & 0 deletions Record/Views/CDListView/CDListView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// CdListView.swift
// Recorder
//
// Created by 조은비 on 2022/06/13.
//

import SwiftUI

struct CDListView: View {

@State private var items = PersistenceController.shared.fetchContent()
@State private var currentIndex = 0

var body: some View {

ZStack {
Color("background")

VStack {
if items.isEmpty {

EmptyCDListView()

} else {

VStack(spacing: 0) {

ForEach (items.indices, id: \.self) { i in
if i == currentIndex {
MusicInformation(item: $items[i])
}
}
CDList(items: $items, currentIndex: $currentIndex)
CDPlayer(item: $items[currentIndex])
}
}
}
}
.navigationBarTitle("리스트", displayMode: .inline)
.ignoresSafeArea()
.onAppear {
items = PersistenceController.shared.fetchContent()
currentIndex = min(currentIndex, items.count - 1)
}
}
}
80 changes: 80 additions & 0 deletions Record/Views/CDListView/CDPlayer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//
// CdPlayer.swift
// Record
//
// Created by 이지원 on 2023/02/25.
//

import SwiftUI

/**
화면 하단 Detail view로 이동할 수 있는 CD Player 및 CD를 보여주는 뷰입니다.

- parameters:
- item: 사용자가 선택한 Content형 데이터를 넣어주세요.
*/


struct CDPlayer: View {

@Binding var item: Content

@State private var angle = 0.0
@State private var showDetailView = false

var body: some View {

VStack {

Text("CD를 선택하고 플레이어를 재생해보세요")
.foregroundColor(.titleGray)
.font(.customBody2())
.frame(width: UIScreen.getWidth(300))
.padding(.bottom, UIScreen.getHeight(-20))
.padding(.top, UIScreen.getHeight(45))

// MARK: - CD Player, 네비게이션 링크
ZStack {

Image("ListViewCdPlayer")
.offset(y: 30)

NavigationLink(destination: RecordDetailView(item: $item), isActive: $showDetailView) {
URLImage(urlString: item.albumArt ?? "")
.clipShape(Circle())
.frame(width: UIScreen.getWidth(110), height: UIScreen.getHeight(110))
.rotationEffect(.degrees(self.angle))
.animation(.timingCurve(0, 0.8, 0.2, 1, duration: 10), value: angle)
.onTapGesture {
self.angle += Double.random(in: 1000..<1980)
timeCount()
}
.animation(.timingCurve(0, 0.8, 0.2, 1, duration: 10), value: angle)
.padding(.bottom, 120)
.padding(.leading, 2) // CdPlayer를 그림자 포함해서 뽑아서 전체 CdPlayer와 정렬 맞추기 위함
}

ZStack {
Circle()
.foregroundColor(.titleLightgray)
.frame(width: UIScreen.getWidth(30) , height: UIScreen.getHeight(30))
Circle()
.foregroundColor(.titleDarkgray)
.frame(width: UIScreen.getWidth(15) , height: UIScreen.getHeight(15))
.shadow(color: Color(.gray), radius: 4, x: 0, y: 4)
Circle()
.foregroundColor(.background)
.frame(width: UIScreen.getWidth(3) , height: UIScreen.getHeight(3))
}
.padding(.bottom, 120)
.padding(.leading, 4)
}
}
}

private func timeCount() {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { timer in
self.showDetailView = true
}
}
}
Loading