feat(chat): 채팅 탭 추가 및 캐릭터/톡 내부 탭 구현
- ChatTabView 신설: 앱 바 + 내부 탭(캐릭터/톡) 전환 구성 - 커스텀 탭 적용 - indicatorHeight: 4, indicatorColor: #3bb9f1 - tabText color: #b0bec5 - 폰트: 선택 전 Pretendard-Regular, 선택 후 Pretendard-Bold - HomeView/BottomTabView에 ChatTabView 연동 - CharacterView/TalkView 플레이스홀더 추가
This commit is contained in:
		
							
								
								
									
										24
									
								
								SodaLive/Sources/Chat/Character/CharacterView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								SodaLive/Sources/Chat/Character/CharacterView.swift
									
									
									
									
									
										Normal 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()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								SodaLive/Sources/Chat/ChatTabView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								SodaLive/Sources/Chat/ChatTabView.swift
									
									
									
									
									
										Normal 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()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								SodaLive/Sources/Chat/Talk/TalkView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								SodaLive/Sources/Chat/Talk/TalkView.swift
									
									
									
									
									
										Normal 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()
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user