diff --git a/AsyncSwift.xcodeproj/project.pbxproj b/AsyncSwift.xcodeproj/project.pbxproj index 8c47b4c..9b079d9 100644 --- a/AsyncSwift.xcodeproj/project.pbxproj +++ b/AsyncSwift.xcodeproj/project.pbxproj @@ -515,12 +515,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = AsyncSwift/AsyncSwift.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AsyncSwift/Preview Content\""; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 76AJ433CP5; + DEVELOPMENT_TEAM = 76AJ433CP5; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AsyncSwift/Info.plist; @@ -543,7 +541,6 @@ PRODUCT_BUNDLE_IDENTIFIER = com.kim.AsyncSwift; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = AsyncSwiftProvisioning; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; @@ -560,12 +557,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = AsyncSwift/AsyncSwift.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AsyncSwift/Preview Content\""; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 76AJ433CP5; + DEVELOPMENT_TEAM = 76AJ433CP5; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AsyncSwift/Info.plist; @@ -588,7 +583,6 @@ PRODUCT_BUNDLE_IDENTIFIER = com.kim.AsyncSwift; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = AsyncSwiftProvisioning; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; diff --git a/AsyncSwift/Models/Stamp.swift b/AsyncSwift/Models/Stamp.swift index 4e6873c..d04ab22 100644 --- a/AsyncSwift/Models/Stamp.swift +++ b/AsyncSwift/Models/Stamp.swift @@ -12,7 +12,8 @@ struct Stamp: Decodable { } struct Card { + var originalPosition: CGFloat - var isSelected = false var image: Image + var event: String } diff --git a/AsyncSwift/Observed/StampView+Observed.swift b/AsyncSwift/Observed/StampView+Observed.swift index 1ffc1bd..aa7229a 100644 --- a/AsyncSwift/Observed/StampView+Observed.swift +++ b/AsyncSwift/Observed/StampView+Observed.swift @@ -9,9 +9,10 @@ import SwiftUI extension StampView { @MainActor final class Observed: ObservableObject { - @Published var cards = [String: Card]() + @Published var cards: [Card] = [] @Published var events = [String]() @Published var currentIndex = 0 + @Published var isLoading = true private let keyChainManager = KeyChainManager() private let cardInterval: CGFloat = (UIScreen.main.bounds.width - 32) * 56 / 358 private let cardSize: CGFloat = UIScreen.main.bounds.width - 32 @@ -22,8 +23,7 @@ extension StampView { private func getEvents() -> [String] { let pwRaw = keyChainManager.getItem(key: keyChainManager.stampKey) as? String - guard var convertedStringArray = pwRaw?.convertToStringArray() else { return [] } - convertedStringArray.insert("Next", at: 0) // MARK: Test 실제에서는 Next storage 둘다 설정해야함 + guard let convertedStringArray = pwRaw?.convertToStringArray() else { return [] } self.events = convertedStringArray.reversed() return events } @@ -33,27 +33,33 @@ extension StampView { private func fetchStampsImages(){ let events = getEvents() + guard !events.isEmpty else { + isLoading = false + return + } + events.enumerated().forEach { [weak self] in - guard let self = self else { return } + guard let self else { return } let event = $0.element let index = $0.offset Task { @MainActor () -> Void in guard let cardImageURL = URL(string: "https://raw.githubusercontent.com/Async-Swift/jsonstorage/main/Images/Stamp/" + event + "/stamp.png") else { return } - + let cardImageRequest = URLRequest(url: cardImageURL) let (cardImageData, cardImageResponse) = try await URLSession.shared.data(for: cardImageRequest) guard let httpsResponse = cardImageResponse as? HTTPURLResponse, httpsResponse.statusCode == 200 else { return } - + guard let cardUIImage = UIImage(data: cardImageData) else { return } - - self.cards[event] = Card(originalPosition: cardInterval * CGFloat(index), - image: Image(uiImage: cardUIImage)) - // 가장 최근의 EventCard가 선택된 상태로 지정하기 - if index == 0 { - self.cards[event]?.isSelected = true - } else { - self.cards[event]?.isSelected = false + + let card = Card( + originalPosition: self.cardInterval * CGFloat(index), + image: Image(uiImage: cardUIImage), + event: event + ) + self.cards.append(card) + if index == events.count - 1 { + self.isLoading = false } } } @@ -105,40 +111,5 @@ extension StampView { return stamp } - - /// 가장 맨 위에 올라온 카드라면 아무것도 작동안하도록, 아니라면 가장 맨위로 올도록 하는 함수입니다. - func didCardTapped(index: Int, scrollReader: ScrollViewProxy) { - if index != currentIndex { - scrollReader.scrollTo(0, anchor: .init(x: 0, y: 94)) - withAnimation(.spring()) { - cards[events[index]]?.isSelected = true - cards[events[currentIndex]]?.isSelected = false - currentIndex = index - } - } - } - - /// 카드의 개수에 따라서 카드의 위치를 지정해주는 함수입니다. - func getCardOffsetY(index: Int, size: CGSize) -> CGFloat { - withAnimation(.spring()) { - guard let card = cards[events[index]] else { return .zero} - if card.isSelected { - return .zero - } else if size.height - CGFloat(94) < cardSize + CGFloat(16) + cardInterval * CGFloat(cards.count - 1) { - return cardSize + CGFloat(16) + card.originalPosition - } else { - return size.height - CGFloat(94) - cardInterval * CGFloat(cards.count - index) - CGFloat(8) - } - } - } - - /// 스크롤을 원할하게 하기 위해서 Offset 으로 원래 크기 보다 밀려난 만큼 Spacer로 확보해줍니다. - func getSpacerMinLength(size: CGSize) -> CGFloat { - if size.height - CGFloat(94) < cardSize + CGFloat(16) + cardInterval * CGFloat(cards.count - 1) { - return cardSize + CGFloat(16) + cardInterval * CGFloat(cards.count - 1) + cardSize - } else { - return size.height - CGFloat(94) - cardInterval - } - } } } diff --git a/AsyncSwift/Views/StampView.swift b/AsyncSwift/Views/StampView.swift index 232c2e8..6777dd8 100644 --- a/AsyncSwift/Views/StampView.swift +++ b/AsyncSwift/Views/StampView.swift @@ -10,41 +10,36 @@ import SwiftUI struct StampView: View { @StateObject var observed = Observed() @EnvironmentObject var envObserved: MainTabViewObserved + let columns = [ + GridItem(.flexible(), spacing: 10), + GridItem(.flexible()) + ] var body: some View { - GeometryReader { geometry in - if observed.cards.isEmpty { - emptyCardView - .padding(36) - } else { + + GeometryReader { proxy in + NavigationView { ScrollView(showsIndicators: false) { ScrollViewReader { reader in - HStack(alignment: .bottom) { - Text("Stamp") - .font(.system(size: 34)) - .fontWeight(.bold) - .padding(.leading, 16) - .padding(.bottom, 7) - .padding(.top, 48) - Spacer() - } - .frame(height: 94) - ZStack { - ForEach(0.. some View { - observed.cards[observed.events[index]]?.image + @ViewBuilder func cardView(card: Card, size: CGSize) -> some View { + card.image .resizable() - .aspectRatio(contentMode: .fit) + .aspectRatio(contentMode: .fill) .shadow(color: Color.black.opacity(0.1), radius: 10, y: 4) - .offset(y: observed.getCardOffsetY(index: index, size: size)) - .onTapGesture { - observed.didCardTapped(index: index, scrollReader: scrollReader) - } } }