diff --git a/.gitignore b/.gitignore index b3debac..5f73a51 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff +.idea/ .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml @@ -276,4 +277,7 @@ xcuserdata /*.gcno **/xcshareddata/WorkspaceSettings.xcsettings +.kiro/ +.junie/ + # End of https://www.toptal.com/developers/gitignore/api/macos,xcode,appcode,swift,swiftpackagemanager,swiftpm,fastlane,cocoapods diff --git a/SodaLive/Sources/Chat/Character/CharacterView.swift b/SodaLive/Sources/Chat/Character/CharacterView.swift new file mode 100644 index 0000000..83d3ed6 --- /dev/null +++ b/SodaLive/Sources/Chat/Character/CharacterView.swift @@ -0,0 +1,24 @@ +// +// CharacterView.swift +// SodaLive +// +// Created by klaus on 8/29/25. +// + +import SwiftUI + +struct CharacterView: View { + var body: some View { + VStack(spacing: 12) { + Spacer() + Text("캐릭터 페이지 (준비중)") + .font(.custom(Font.preMedium.rawValue, size: 16)) + .multilineTextAlignment(.center) + Spacer() + } + } +} + +#Preview { + CharacterView() +} diff --git a/SodaLive/Sources/Chat/ChatTabView.swift b/SodaLive/Sources/Chat/ChatTabView.swift new file mode 100644 index 0000000..39d4f0b --- /dev/null +++ b/SodaLive/Sources/Chat/ChatTabView.swift @@ -0,0 +1,119 @@ +// +// ChatTabView.swift +// SodaLive +// +// Created by klaus on 8/29/25. +// + +import SwiftUI + +struct ChatTabView: View { + @AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token) + + private enum InnerTab: Int, CaseIterable { + case character = 0 + case talk = 1 + + var title: String { + switch self { + case .character: return "캐릭터" + case .talk: return "톡" + } + } + } + + @State private var selectedTab: InnerTab = .character + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + // 앱 바 + HStack(spacing: 24) { + Image("img_text_logo") + + Spacer() + + if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + Image("ic_search_white") + .onTapGesture { + AppState + .shared + .setAppStep(step: .search) + } + + Image("ic_can_circle") + .onTapGesture { + AppState + .shared + .setAppStep(step: .canCharge(refresh: {})) + } + } + } + .padding(.horizontal, 24) + .padding(.vertical, 20) + + // 내부 탭 (캐릭터 / 톡) + HStack(spacing: 0) { + ChatInnerTab( + title: InnerTab.character.title, + isSelected: selectedTab == .character, + onTap: { if selectedTab != .character { selectedTab = .character } } + ) + + ChatInnerTab( + title: InnerTab.talk.title, + isSelected: selectedTab == .talk, + onTap: { if selectedTab != .talk { selectedTab = .talk } } + ) + } + .padding(.bottom, 12) + + Group { + switch selectedTab { + case .character: + CharacterView() + case .talk: + TalkView() + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + } + } +} + +struct ChatInnerTab: View { + let title: String + let isSelected: Bool + let onTap: () -> Void + + var body: some View { + Button(action: onTap) { + VStack(spacing: 0) { + Spacer() + + Text(title) + .font( + .custom( + isSelected ? Font.preBold.rawValue : Font.preRegular.rawValue, + size: 18 + ) + ) + .foregroundColor(Color(hex: "b0bec5")) + .frame(maxWidth: .infinity) + + Spacer() + + Rectangle() + .frame(maxWidth: .infinity) + .frame(height: 4) + .foregroundColor(Color(hex: "3bb9f1").opacity(isSelected ? 1 : 0)) + } + .frame(height: 50) + .contentShape(Rectangle()) + } + .buttonStyle(PlainButtonStyle()) + } +} + +#Preview { + ChatTabView() +} diff --git a/SodaLive/Sources/Chat/Talk/TalkView.swift b/SodaLive/Sources/Chat/Talk/TalkView.swift new file mode 100644 index 0000000..1fcc8a6 --- /dev/null +++ b/SodaLive/Sources/Chat/Talk/TalkView.swift @@ -0,0 +1,24 @@ +// +// TalkView.swift +// SodaLive +// +// Created by klaus on 8/29/25. +// + +import SwiftUI + +struct TalkView: View { + var body: some View { + VStack(spacing: 12) { + Spacer() + Text("톡 페이지 (준비중)") + .font(.custom(Font.preMedium.rawValue, size: 16)) + .multilineTextAlignment(.center) + Spacer() + } + } +} + +#Preview { + TalkView() +} diff --git a/SodaLive/Sources/Main/Home/BottomTabView.swift b/SodaLive/Sources/Main/Home/BottomTabView.swift index 1fc674b..2af95c1 100644 --- a/SodaLive/Sources/Main/Home/BottomTabView.swift +++ b/SodaLive/Sources/Main/Home/BottomTabView.swift @@ -13,7 +13,7 @@ struct BottomTabView: View { var body: some View { HStack(spacing: 0) { - let tabWidth = width / 3 + let tabWidth = width / 4 TabButton( title: "홈", @@ -40,6 +40,31 @@ struct BottomTabView: View { width: tabWidth ) + TabButton( + title: "채팅", + action: { + if currentTab != .chat { + currentTab = .chat + } + }, + image: { + currentTab == .chat ? + "ic_chat_selected" : + "ic_chat" + }, + fontName: { + currentTab == .chat ? + Font.bold.rawValue : + Font.medium.rawValue + }, + color: { + currentTab == .chat ? + Color.button : + Color.graybb + }, + width: tabWidth + ) + TabButton( title: "라이브", action: { diff --git a/SodaLive/Sources/Main/Home/HomeView.swift b/SodaLive/Sources/Main/Home/HomeView.swift index 5d0b2bc..502f58a 100644 --- a/SodaLive/Sources/Main/Home/HomeView.swift +++ b/SodaLive/Sources/Main/Home/HomeView.swift @@ -19,6 +19,7 @@ struct HomeView: View { private let liveView = LiveView() private let homeTabView = HomeTabView() + private let chatTabView = ChatTabView() @State private var isShowPlayer = false @AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token) @@ -32,6 +33,10 @@ struct HomeView: View { .frame(width: viewModel.currentTab == .home ? proxy.size.width : 0) .opacity(viewModel.currentTab == .home ? 1.0 : 0.01) + chatTabView + .frame(width: viewModel.currentTab == .chat ? proxy.size.width : 0) + .opacity(viewModel.currentTab == .chat ? 1.0 : 0.01) + liveView .frame(width: viewModel.currentTab == .live ? proxy.size.width : 0) .opacity(viewModel.currentTab == .live ? 1.0 : 0.01) diff --git a/SodaLive/Sources/Main/Home/HomeViewModel.swift b/SodaLive/Sources/Main/Home/HomeViewModel.swift index 8022fcf..e645952 100644 --- a/SodaLive/Sources/Main/Home/HomeViewModel.swift +++ b/SodaLive/Sources/Main/Home/HomeViewModel.swift @@ -18,7 +18,7 @@ final class HomeViewModel: ObservableObject { private let playbackTrackingRepository = PlaybackTrackingRepository() enum CurrentTab: String { - case home, live, mypage + case home, chat, live, mypage } @Published var currentTab: CurrentTab = AppState.shared.startTab