2024-06-19 15:15:27 +00:00
import Combine
import Foundation
import Martin
import SwiftUI
2024-06-21 10:42:50 +00:00
struct ConversationScreen : View {
@ EnvironmentObject var store : AppStore
2024-06-19 15:15:27 +00:00
var body : some View {
2024-06-24 13:28:26 +00:00
ZStack {
// B a c k g r o u n d c o l o r
Color . Main . backgroundLight
. ignoresSafeArea ( )
2024-06-19 15:15:27 +00:00
2024-06-24 13:28:26 +00:00
// C o n t e n t
VStack ( spacing : 0 ) {
// H e a d e r
ConversationScreenHeader ( )
// M s g l i s t
let messages = store . state . conversationsState . currentMessages
if ! messages . isEmpty {
List {
ForEach ( messages ) { message in
ConversationMessageRow ( message : message )
}
}
. listStyle ( . plain )
. background ( Color . Main . backgroundLight )
2024-06-26 07:27:23 +00:00
. scrollDismissesKeyboard ( . immediately )
2024-06-24 13:28:26 +00:00
} else {
Spacer ( )
}
}
2024-06-26 07:27:23 +00:00
. onTapGesture {
UIApplication . shared . sendAction ( #selector ( UIResponder . resignFirstResponder ) , to : nil , from : nil , for : nil )
}
2024-06-19 15:15:27 +00:00
}
2024-06-25 11:13:59 +00:00
. safeAreaInset ( edge : . bottom , spacing : 0 ) {
ConversationScreenTextInput ( )
}
}
}
struct ConversationScreenTextInput : View {
@ EnvironmentObject var store : AppStore
@ State private var messageStr = " "
var body : some View {
HStack {
Image ( systemName : " paperclip " )
. font ( . title2 )
. foregroundColor ( . Tango . blueLight )
. padding ( . leading , 8 )
. tappablePadding ( . symmetric ( 8 ) ) {
print ( " Attach file " )
}
TextField ( L10n . Chat . textfieldPrompt , text : $ messageStr )
. font ( . body1 )
. padding ( . horizontal , 8 )
. padding ( . vertical , 4 )
. background ( Color . Main . white )
. clipShape ( RoundedRectangle ( cornerRadius : 8 ) )
. padding ( . vertical , 4 )
let img = messageStr . isEmpty ? " paperplane " : " paperplane.fill "
Image ( systemName : img )
. font ( . title2 )
. foregroundColor ( messageStr . isEmpty ? . Main . separator : . Tango . blueLight )
. padding ( . trailing , 8 )
. tappablePadding ( . symmetric ( 8 ) ) {
if ! messageStr . isEmpty {
2024-06-26 08:00:59 +00:00
guard let acc = store . state . conversationsState . currentChat ? . account else { return }
guard let contact = store . state . conversationsState . currentChat ? . participant else { return }
store . dispatch ( . conversationAction ( . sendMessage (
from : acc ,
to : contact ,
body : messageStr
) ) )
2024-06-25 11:13:59 +00:00
messageStr = " "
UIApplication . shared . sendAction ( #selector ( UIResponder . resignFirstResponder ) , to : nil , from : nil , for : nil )
}
}
}
. padding ( . vertical , 8 )
. background ( Color . Main . backgroundDark )
2024-06-19 15:15:27 +00:00
}
}
2024-06-21 10:42:50 +00:00
private struct ConversationScreenHeader : View {
2024-06-26 06:51:56 +00:00
@ EnvironmentObject var store : AppStore
2024-06-19 15:15:27 +00:00
var body : some View {
ZStack {
// b g
Color . Main . backgroundDark
. ignoresSafeArea ( )
// t i t l e
2024-06-26 06:51:56 +00:00
let name = (
store . state . conversationsState . currentRoster ? . name ? ?
store . state . conversationsState . currentRoster ? . contactBareJid
) ? ? L10n . Chat . title
Text ( name )
2024-06-19 15:15:27 +00:00
. font ( . head2 )
. foregroundColor ( Color . Main . black )
HStack {
Image ( systemName : " chevron.left " )
. foregroundColor ( Color . Tango . orangeMedium )
. tappablePadding ( . symmetric ( 12 ) ) {
2024-06-21 10:42:50 +00:00
store . dispatch ( . changeFlow ( store . state . previousFlow ) )
2024-06-19 15:15:27 +00:00
}
Spacer ( )
}
. padding ( . horizontal , 16 )
}
. frame ( height : 44 )
}
}
2024-06-24 13:28:26 +00:00
private struct ConversationMessageRow : View {
@ EnvironmentObject var store : AppStore
2024-06-19 15:15:27 +00:00
let message : Message
var body : some View {
2024-06-25 11:13:59 +00:00
VStack ( spacing : 0 ) {
HStack ( spacing : 0 ) {
if isOutgoing ( ) {
2024-06-24 13:28:26 +00:00
Spacer ( )
2024-06-25 11:13:59 +00:00
VStack ( spacing : 0 ) {
MessageTime ( message : message )
Spacer ( )
}
. padding ( . trailing , 4 )
2024-06-24 13:28:26 +00:00
}
2024-06-25 11:13:59 +00:00
MessageContainer ( message : message , isOutgoing : isOutgoing ( ) )
. background ( isOutgoing ( ) ? Color . Material . greenDark100 : Color . Main . white )
. clipShape ( MessageBubble ( isOutgoing : isOutgoing ( ) ) )
if ! isOutgoing ( ) {
VStack ( spacing : 0 ) {
MessageTime ( message : message )
Spacer ( )
}
. padding ( . leading , 4 )
2024-06-24 13:28:26 +00:00
Spacer ( )
}
}
2024-06-25 11:13:59 +00:00
. padding ( . vertical , 10 )
. padding ( . horizontal , 16 )
2024-06-19 15:15:27 +00:00
}
2024-06-24 13:28:26 +00:00
. sharedListRow ( )
2024-06-19 15:15:27 +00:00
}
2024-06-25 11:13:59 +00:00
private func isOutgoing ( ) -> Bool {
message . from = = store . state . conversationsState . currentChat ? . account
}
}
struct MessageContainer : View {
let message : Message
let isOutgoing : Bool
var body : some View {
Text ( message . body ? ? " ... " )
. font ( . body2 )
. foregroundColor ( Color . Main . black )
. multilineTextAlignment ( . leading )
. padding ( 10 )
}
}
struct MessageBubble : Shape {
let isOutgoing : Bool
func path ( in rect : CGRect ) -> Path {
let path = UIBezierPath (
roundedRect : rect ,
byRoundingCorners : isOutgoing ? [ . topLeft , . bottomLeft , . bottomRight ] : [ . topRight , . bottomLeft , . bottomRight ] ,
cornerRadii : CGSize ( width : 8 , height : 10 )
)
return Path ( path . cgPath )
2024-06-24 13:28:26 +00:00
}
2024-06-19 15:15:27 +00:00
}
2024-06-25 11:13:59 +00:00
struct MessageTime : View {
let message : Message
var body : some View {
Text ( message . date , style : . time )
. font ( . sub2 )
. foregroundColor ( Color . Main . gray )
}
}
// P r e v i e w
#if DEBUG
struct ConversationScreen_Previews : PreviewProvider {
static var previews : some View {
ConversationScreen ( )
. environmentObject ( pStore )
}
static var pStore : AppStore {
let state = pState
return AppStore ( initialState : state , reducer : AppState . reducer , middlewares : [ ] )
}
static var pState : AppState {
var state = AppState ( )
let acc = " user@test.com "
let contact = " some@test.com "
state . conversationsState . currentChat = Chat ( id : " 1 " , account : acc , participant : contact , type : . chat )
state . conversationsState . currentMessages = [
Message (
id : " 1 " ,
type : . chat ,
contentType : . text ,
from : contact ,
to : acc ,
body : " this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf " ,
subject : nil ,
thread : nil ,
oobUrl : nil ,
2024-06-26 07:27:23 +00:00
date : Date ( ) ,
pending : false
2024-06-25 11:13:59 +00:00
) ,
2024-06-26 07:27:23 +00:00
Message ( id : " 2 " , type : . chat , contentType : . text , from : contact , to : acc , body : " this is for testsdfsdf sdfsdf sdfs sdf sdffsdf sdf sdf sdf sdf sdf sdff sdfffwwe " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
Message ( id : " 3 " , type : . chat , contentType : . text , from : contact , to : acc , body : " this is for test " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
Message ( id : " 4 " , type : . chat , contentType : . text , from : acc , to : contact , body : " this is for test sdfkjwek jwkjfh jwerf jdfhskjdhf jsdhfjhwefh sjdhfh fsdjhfh sd " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
Message ( id : " 5 " , type : . chat , contentType : . text , from : contact , to : acc , body : " this is for test sdfjkkeke kekkddjw;; w;edkdjfj l kjwekrjfk wef " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
Message ( id : " 6 " , type : . chat , contentType : . text , from : acc , to : contact , body : " this is for testsdf dsdkkekkddn wejkjfj " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
2024-06-25 11:13:59 +00:00
Message (
id : " 7 " ,
type : . chat ,
contentType : . text ,
from : acc ,
to : contact ,
body : " this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf " ,
subject : nil ,
thread : nil ,
oobUrl : nil ,
2024-06-26 07:27:23 +00:00
date : Date ( ) , pending : false
2024-06-25 11:13:59 +00:00
) ,
2024-06-26 07:27:23 +00:00
Message ( id : " 8 " , type : . chat , contentType : . text , from : acc , to : contact , body : " so test " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
Message ( id : " 9 " , type : . chat , contentType : . text , from : contact , to : acc , body : " so test " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
Message ( id : " 10 " , type : . chat , contentType : . text , from : acc , to : contact , body : " so test so test so test " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false ) ,
Message ( id : " 11 " , type : . chat , contentType : . text , from : contact , to : acc , body : " xD " , subject : nil , thread : nil , oobUrl : nil , date : Date ( ) , pending : false )
2024-06-25 11:13:59 +00:00
]
return state
}
}
#endif