메시지 - 리스트, 쓰기, 상세 페이지 추가

This commit is contained in:
Yu Sung
2023-08-10 15:21:08 +09:00
parent 943e1d9f7f
commit 80ff04f825
36 changed files with 2969 additions and 2 deletions

View File

@@ -0,0 +1,195 @@
//
// TextMessageDetailView.swift
// SodaLive
//
// Created by klaus on 2023/08/10.
//
import SwiftUI
import Kingfisher
struct TextMessageDetailView: View {
@StateObject var viewModel = TextMessageDetailViewModel()
@StateObject var appState = AppState.shared
let messageItem: TextMessageItem
let messageBox: MessageFilterTab
let refresh: () -> Void
func back() {
refresh()
AppState.shared.back()
}
var body: some View {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
switch messageBox {
case .receive:
DetailNavigationBar(title: "받은 메시지 상세") { back() }
case .sent:
DetailNavigationBar(title: "보낸 메시지 상세") { back() }
case .keep:
DetailNavigationBar(title: "저장한 메시지 상세") { back() }
}
HStack(spacing: 13.3) {
KFImage(
URL(
string: messageBox == .sent ?
messageItem.recipientProfileImageUrl :
messageItem.senderProfileImageUrl
)
)
.resizable()
.scaledToFill()
.frame(width: 26.7, height: 26.7, alignment: .top)
.cornerRadius(13.3)
Text(
messageBox == .sent ?
messageItem.recipientNickname :
messageItem.senderNickname
)
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(Color(hex: "eeeeee"))
}
.padding(.vertical, 12.7)
.frame(width: screenSize().width - 26.7)
.background(Color(hex: "1b1b1b"))
.cornerRadius(10)
Text(messageItem.date.convertDateFormat(
from: "yyyy-MM-dd hh:mm:ss",
to: "yyyy년 MM월 dd일 E요일 HH:mm"
))
.font(.custom(Font.medium.rawValue, size: 15))
.foregroundColor(Color(hex: "bbbbbb"))
.padding(.top, 16.7)
ScrollView(.vertical, showsIndicators: false) {
Text(messageItem.textMessage)
.font(.custom(Font.medium.rawValue, size: 15))
.foregroundColor(Color(hex: "eeeeee"))
.multilineTextAlignment(.leading)
.padding(26.7)
.frame(width: screenSize().width - 26.7, alignment: .leading)
}
.frame(width: screenSize().width - 26.7)
.background(Color(hex: "222222"))
.cornerRadius(10)
.padding(.top, 10)
Spacer()
if messageBox == .receive {
HStack(spacing: 6.7) {
Text("답장")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color(hex: "eeeeee"))
.frame(
width: (screenSize().width - 40) / 3,
height: 48.7
)
.background(Color(hex: "9970ff"))
.cornerRadius(6.7)
.onTapGesture {
AppState.shared.setAppStep(step: .writeTextMessage(userId: messageItem.senderId, nickname: messageItem.senderNickname))
}
Text("보관")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color(hex: "9970ff"))
.frame(
width: (screenSize().width - 40) / 3,
height: 48.7
)
.background(Color(hex: "1f1734"))
.cornerRadius(6.7)
.onTapGesture {
if messageItem.isKept {
viewModel.errorMessage = "이미 보관된 메시지 입니다"
viewModel.isShowPopup = true
return
} else {
viewModel.keepTextMessage()
}
}
Text("삭제")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color(hex: "9970ff"))
.frame(
width: (screenSize().width - 40) / 3,
height: 48.7
)
.background(Color(hex: "1f1734"))
.cornerRadius(6.7)
.onTapGesture {
viewModel.deleteMessage { back() }
}
}
.frame(width: screenSize().width - 26.7)
.padding(.vertical, 26.7)
} else {
Text("삭제")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color(hex: "9970ff"))
.frame(
width: screenSize().width - 26.7,
height: 48.7
)
.background(Color(hex: "1f1734"))
.cornerRadius(6.7)
.onTapGesture {
viewModel.deleteMessage { back() }
}
.padding(.vertical, 26.7)
}
}
}
.popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) {
GeometryReader { geo in
HStack {
Spacer()
Text(viewModel.errorMessage)
.padding(.vertical, 13.3)
.padding(.horizontal, 6.7)
.frame(width: geo.size.width - 66.7, alignment: .center)
.font(.custom(Font.medium.rawValue, size: 12))
.background(Color(hex: "9970ff"))
.foregroundColor(Color.white)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
.cornerRadius(20)
.padding(.top, 66.7)
Spacer()
}
}
}
.onAppear {
viewModel.messageId = messageItem.messageId
}
}
}
struct TextMessageDetailView_Previews: PreviewProvider {
static var previews: some View {
TextMessageDetailView(
messageItem: TextMessageItem(
messageId: 10,
senderId: 1,
senderNickname: "누군가",
senderProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
recipientNickname: "테스터",
recipientProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
textMessage: "testtesttesttest",
date: "2022-07-08 10:20:30",
isKept: false),
messageBox: .receive,
refresh: {}
)
}
}

View File

@@ -0,0 +1,118 @@
//
// TextMessageDetailViewModel.swift
// SodaLive
//
// Created by klaus on 2023/08/10.
//
import Foundation
import Combine
final class TextMessageDetailViewModel: ObservableObject {
private let repository = MessageRepository()
private var subscription = Set<AnyCancellable>()
@Published var errorMessage = ""
@Published var isShowPopup = false
@Published var isLoading = false
@Published var saveMessagePrice = 0
@Published var isShowSavePopup = false
var messageId = 0
func deleteMessage(onSuccess: @escaping () -> Void) {
if messageId <= 0 {
errorMessage = "메시지를 삭제하지 못했습니다\n잠시 후 다시 시도해 주세요."
isShowPopup = true
return
}
isLoading = true
repository.deleteMessage(messageId: messageId)
.sink { result in
switch result {
case .finished:
DEBUG_LOG("finish")
case .failure(let error):
ERROR_LOG(error.localizedDescription)
}
} receiveValue: { [unowned self] response in
self.isLoading = false
let responseData = response.data
do {
let jsonDecoder = JSONDecoder()
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
if decoded.success {
self.errorMessage = "삭제되었습니다."
self.isShowPopup = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
onSuccess()
}
} else {
if let message = decoded.message {
self.errorMessage = message
self.isShowPopup = true
} else {
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
}
self.isShowPopup = true
}
} catch {
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
self.isShowPopup = true
}
}
.store(in: &subscription)
}
func keepTextMessage() {
if messageId <= 0 {
errorMessage = "메시지를 저장하지 못했습니다\n잠시 후 다시 시도해 주세요."
isShowPopup = true
return
}
isLoading = true
repository.keepTextMessage(messageId: messageId)
.sink { result in
switch result {
case .finished:
DEBUG_LOG("finish")
case .failure(let error):
ERROR_LOG(error.localizedDescription)
}
} receiveValue: { [unowned self] response in
self.isLoading = false
let responseData = response.data
do {
let jsonDecoder = JSONDecoder()
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
if decoded.success {
self.errorMessage = "보관되었습니다."
self.isShowPopup = true
} else {
if let message = decoded.message {
self.errorMessage = message
self.isShowPopup = true
} else {
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
}
self.isShowPopup = true
}
} catch {
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
self.isShowPopup = true
}
}
.store(in: &subscription)
}
}