feat(chat): 채팅 탭 추가 및 캐릭터/톡 내부 탭 구현

- ChatTabView 신설: 앱 바 + 내부 탭(캐릭터/톡) 전환 구성
- 커스텀 탭 적용
  - indicatorHeight: 4, indicatorColor: #3bb9f1
  - tabText color: #b0bec5
  - 폰트: 선택 전 Pretendard-Regular, 선택 후 Pretendard-Bold
- HomeView/BottomTabView에 ChatTabView 연동
- CharacterView/TalkView 플레이스홀더 추가
This commit is contained in:
Yu Sung
2025-08-29 14:32:45 +09:00
parent 97a0798995
commit 1488ed5b89
7 changed files with 203 additions and 2 deletions

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}