Skip to content
Snippets Groups Projects
Commit df266b93 authored by Joel  Oksanen's avatar Joel Oksanen
Browse files

Finished messaging MVP on client

parent f151e1e5
No related branches found
No related tags found
No related merge requests found
Showing
with 228 additions and 73 deletions
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
9449FE4924042D6500025F70 /* FeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4824042D6500025F70 /* FeatureView.swift */; }; 9449FE4924042D6500025F70 /* FeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4824042D6500025F70 /* FeatureView.swift */; };
9449FE4B24042E8800025F70 /* Argument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4A24042E8800025F70 /* Argument.swift */; }; 9449FE4B24042E8800025F70 /* Argument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4A24042E8800025F70 /* Argument.swift */; };
9449FE4D2404561400025F70 /* ArgumentQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4C2404561400025F70 /* ArgumentQuery.swift */; }; 9449FE4D2404561400025F70 /* ArgumentQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4C2404561400025F70 /* ArgumentQuery.swift */; };
9449FE4F240533FD00025F70 /* QueryOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4E240533FD00025F70 /* QueryOptionView.swift */; };
9449FE5124053DA500025F70 /* ChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE5024053DA500025F70 /* ChatManager.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
...@@ -52,6 +54,8 @@ ...@@ -52,6 +54,8 @@
9449FE4824042D6500025F70 /* FeatureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureView.swift; sourceTree = "<group>"; }; 9449FE4824042D6500025F70 /* FeatureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureView.swift; sourceTree = "<group>"; };
9449FE4A24042E8800025F70 /* Argument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Argument.swift; sourceTree = "<group>"; }; 9449FE4A24042E8800025F70 /* Argument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Argument.swift; sourceTree = "<group>"; };
9449FE4C2404561400025F70 /* ArgumentQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentQuery.swift; sourceTree = "<group>"; }; 9449FE4C2404561400025F70 /* ArgumentQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentQuery.swift; sourceTree = "<group>"; };
9449FE4E240533FD00025F70 /* QueryOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryOptionView.swift; sourceTree = "<group>"; };
9449FE5024053DA500025F70 /* ChatManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatManager.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
...@@ -109,16 +113,18 @@ ...@@ -109,16 +113,18 @@
9449FE3E2403EDB400025F70 /* Chat */ = { 9449FE3E2403EDB400025F70 /* Chat */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
9449FE5024053DA500025F70 /* ChatManager.swift */,
9449FE442403F0A600025F70 /* Sender.swift */, 9449FE442403F0A600025F70 /* Sender.swift */,
9449FE382403E9A400025F70 /* Message.swift */, 9449FE382403E9A400025F70 /* Message.swift */,
9449FE3A2403EC3800025F70 /* ADAMessage.swift */, 9449FE3A2403EC3800025F70 /* ADAMessage.swift */,
9449FE4A24042E8800025F70 /* Argument.swift */, 9449FE4A24042E8800025F70 /* Argument.swift */,
9449FE4C2404561400025F70 /* ArgumentQuery.swift */, 9449FE4C2404561400025F70 /* ArgumentQuery.swift */,
9449FE3C2403ED0200025F70 /* UserMessage.swift */, 9449FE3C2403ED0200025F70 /* UserMessage.swift */,
9449FE422403F02500025F70 /* MessageBubble.swift */,
9449FE302402C90800025F70 /* ChatView.swift */, 9449FE302402C90800025F70 /* ChatView.swift */,
9449FE402403EF5A00025F70 /* MessageView.swift */, 9449FE402403EF5A00025F70 /* MessageView.swift */,
9449FE422403F02500025F70 /* MessageBubble.swift */,
9449FE4824042D6500025F70 /* FeatureView.swift */, 9449FE4824042D6500025F70 /* FeatureView.swift */,
9449FE4E240533FD00025F70 /* QueryOptionView.swift */,
); );
name = Chat; name = Chat;
path = ADAbot/Chat; path = ADAbot/Chat;
...@@ -209,6 +215,7 @@ ...@@ -209,6 +215,7 @@
9449FE3B2403EC3800025F70 /* ADAMessage.swift in Sources */, 9449FE3B2403EC3800025F70 /* ADAMessage.swift in Sources */,
9449FE3D2403ED0200025F70 /* UserMessage.swift in Sources */, 9449FE3D2403ED0200025F70 /* UserMessage.swift in Sources */,
9449FE2F2402C8C500025F70 /* ProductView.swift in Sources */, 9449FE2F2402C8C500025F70 /* ProductView.swift in Sources */,
9449FE4F240533FD00025F70 /* QueryOptionView.swift in Sources */,
9449FE4B24042E8800025F70 /* Argument.swift in Sources */, 9449FE4B24042E8800025F70 /* Argument.swift in Sources */,
9449FE372402D29E00025F70 /* Product.swift in Sources */, 9449FE372402D29E00025F70 /* Product.swift in Sources */,
9449FE432403F02500025F70 /* MessageBubble.swift in Sources */, 9449FE432403F02500025F70 /* MessageBubble.swift in Sources */,
...@@ -218,6 +225,7 @@ ...@@ -218,6 +225,7 @@
9449FE4D2404561400025F70 /* ArgumentQuery.swift in Sources */, 9449FE4D2404561400025F70 /* ArgumentQuery.swift in Sources */,
9449FE4924042D6500025F70 /* FeatureView.swift in Sources */, 9449FE4924042D6500025F70 /* FeatureView.swift in Sources */,
9449FE312402C90800025F70 /* ChatView.swift in Sources */, 9449FE312402C90800025F70 /* ChatView.swift in Sources */,
9449FE5124053DA500025F70 /* ChatManager.swift in Sources */,
9449FE352402CCDA00025F70 /* ConnectionManager.swift in Sources */, 9449FE352402CCDA00025F70 /* ConnectionManager.swift in Sources */,
9449FE1D2402C84F00025F70 /* SceneDelegate.swift in Sources */, 9449FE1D2402C84F00025F70 /* SceneDelegate.swift in Sources */,
9449FE1F2402C84F00025F70 /* ContentView.swift in Sources */, 9449FE1F2402C84F00025F70 /* ContentView.swift in Sources */,
......
...@@ -3,22 +3,4 @@ ...@@ -3,22 +3,4 @@
uuid = "91D35F8C-89D0-4137-A5A5-FAFC5B6FE3BA" uuid = "91D35F8C-89D0-4137-A5A5-FAFC5B6FE3BA"
type = "1" type = "1"
version = "2.0"> version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "01922009-364B-4C8F-87E5-58886FB47FAA"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "ADAbot/Chat/MessageView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "34"
endingLineNumber = "34"
landmarkName = "body"
landmarkType = "24">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket> </Bucket>
...@@ -8,11 +8,15 @@ ...@@ -8,11 +8,15 @@
import UIKit import UIKit
struct ADAMessage: Message, Decodable { struct ADAMessage: Message, Decodable, Equatable {
let id = UUID() let id = UUID()
let sender = Sender.ADA let sender = Sender.ADA
let text: String let text: String
let arguments: [Argument] let arguments: [Argument]
static func == (lhs: ADAMessage, rhs: ADAMessage) -> Bool {
lhs.id == rhs.id
}
} }
...@@ -8,10 +8,15 @@ ...@@ -8,10 +8,15 @@
import UIKit import UIKit
struct Argument: Codable { struct Argument: Codable, Equatable {
let id = UUID() let id = UUID()
let name: String let name: String
let queries = [ArgumentQuery]() let queries = [ArgumentQuery(argumentID: 1, queryID: 1, text: "Why was the lens considered to be good?"),
ArgumentQuery(argumentID: 1, queryID: 2, text: "What did users say about the lens being good?")]
static func == (lhs: Argument, rhs: Argument) -> Bool {
lhs.id == rhs.id
}
} }
...@@ -10,8 +10,14 @@ import UIKit ...@@ -10,8 +10,14 @@ import UIKit
struct ArgumentQuery: Codable { struct ArgumentQuery: Codable {
let id = UUID()
let argumentID: Int let argumentID: Int
let queryID: Int let queryID: Int
let text: String let text: String
var message: UserMessage {
get {
return UserMessage(query: self)
}
}
} }
//
// ChatManager.swift
// ADAbot
//
// Created by Joel Oksanen on 25.2.2020.
// Copyright © 2020 Joel Oksanen. All rights reserved.
//
import SwiftUI
class ChatManager: ObservableObject {
@Published var sent = false
@Published var showingOptionsForMessage: ADAMessage?
let connectionManager: ConnectionManager
init(connectionManager: ConnectionManager) {
self.connectionManager = connectionManager
}
func sendQuery(query: ArgumentQuery) {
sent = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.sent = false
self.connectionManager.addMessage(message: query.message)
self.showingOptionsForMessage = nil
}
}
func showOptionsFor(_ message: ADAMessage) {
showingOptionsForMessage = message
}
func showingOptionsFor(_ message: Message) -> Bool {
return message is ADAMessage && (message as! ADAMessage) == showingOptionsForMessage
}
}
...@@ -9,7 +9,13 @@ ...@@ -9,7 +9,13 @@
import SwiftUI import SwiftUI
struct ChatView: View { struct ChatView: View {
@ObservedObject var connectionManager = ConnectionManager() @ObservedObject var connectionManager: ConnectionManager
@ObservedObject var chatManager: ChatManager
init(connectionManager: ConnectionManager) {
self.connectionManager = connectionManager
self.chatManager = ChatManager(connectionManager: connectionManager)
}
var body: some View { var body: some View {
ZStack { ZStack {
...@@ -19,11 +25,8 @@ struct ChatView: View { ...@@ -19,11 +25,8 @@ struct ChatView: View {
ScrollView { ScrollView {
VStack(spacing: 0) { VStack(spacing: 0) {
ForEach(connectionManager.messages, id: \.id) { message in ForEach(connectionManager.messages, id: \.id) { message in
MessageView(message: message) MessageView(chatManager: self.chatManager, message: message)
.padding(EdgeInsets(top: 0, leading: 20, bottom: 15, trailing: 20))
} }
FeatureView(arguments: connectionManager.messages.last!.arguments)
.padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0))
} }
.padding(EdgeInsets(top: 30, leading: 0, bottom: 30, trailing: 0)) .padding(EdgeInsets(top: 30, leading: 0, bottom: 30, trailing: 0))
} }
......
...@@ -9,44 +9,70 @@ ...@@ -9,44 +9,70 @@
import SwiftUI import SwiftUI
struct FeatureView: View { struct FeatureView: View {
@ObservedObject var chatManager: ChatManager
static let bubbleColor = Color(red: 75/255, green: 90/255, blue: 116/255)
let arguments: [Argument] let arguments: [Argument]
let bubbleColor = Color(red: 75/255, green: 90/255, blue: 116/255) @State var showingQueryOptionsForArgument: Argument?
var body: some View { var body: some View {
HStack(spacing: 0) { VStack(spacing: 0) {
Spacer() if (!chatManager.sent) {
Text("ASK ABOUT")
.foregroundColor(self.bubbleColor)
.font(Font.custom("Gill Sans", size: 11))
.fixedSize(horizontal: true, vertical: false)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 10))
Capsule()
.foregroundColor(self.bubbleColor)
.frame(width: 1, height: 38)
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 0) { HStack(spacing: 0) {
Spacer() Spacer()
.frame(width: 10)
ForEach(self.arguments, id: \.id) { argument in Text("ASK ABOUT")
Text(argument.name) .foregroundColor(FeatureView.bubbleColor)
.foregroundColor(Color.white) .font(Font.custom("Gill Sans", size: 11))
.font(Font.custom("Helvetica Neue", size: 12)) .fixedSize(horizontal: true, vertical: false)
.fixedSize(horizontal: true, vertical: true) .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 10))
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.background(Capsule().foregroundColor(self.bubbleColor)) Capsule()
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 10)) .foregroundColor(FeatureView.bubbleColor)
.frame(width: 1, height: 38)
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 0) {
Spacer()
.frame(width: 10)
ForEach(self.arguments, id: \.id) { argument in
FeatureBubble(argument: argument,
showingQueryOptionsForArgument: self.$showingQueryOptionsForArgument)
.onTapGesture { self.showingQueryOptionsForArgument = argument }
}
Spacer()
.frame(width: 10)
}
} }
Spacer() .frame(maxWidth: 280)
.frame(width: 10) .fixedSize(horizontal: true, vertical: false)
.zIndex(-1)
} }
.padding(EdgeInsets(top: 0, leading: 0, bottom: 15, trailing: 0))
}
if showingQueryOptionsForArgument != nil {
QueryOptionView(chatManager: chatManager, queries: showingQueryOptionsForArgument!.queries)
} }
.frame(maxWidth: 280)
.fixedSize(horizontal: true, vertical: false)
.zIndex(-1)
} }
.frame(width: UIScreen.main.bounds.width)
}
}
struct FeatureBubble: View {
let argument: Argument
@Binding var showingQueryOptionsForArgument: Argument?
var body: some View {
Text(argument.name)
.foregroundColor(self.showingQueryOptionsForArgument == argument ? Color.white : FeatureView.bubbleColor)
.font(Font.custom("Helvetica Neue", size: 12))
.fixedSize(horizontal: true, vertical: true)
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.background(self.showingQueryOptionsForArgument == argument ?
AnyView(Capsule().foregroundColor(FeatureView.bubbleColor)) :
AnyView(Capsule().strokeBorder(FeatureView.bubbleColor))
)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 10))
} }
} }
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
import SwiftUI import SwiftUI
struct MessageView: View { struct MessageView: View {
@ObservedObject var chatManager: ChatManager
let bubbleColors = [ let bubbleColors = [
Sender.ADA: Color(red: 242/255, green: 159/255, blue: 31/255), Sender.ADA: Color(red: 242/255, green: 159/255, blue: 31/255),
Sender.USER: Color(red: 35/255, green: 45/255, blue: 62/255) Sender.USER: Color(red: 35/255, green: 45/255, blue: 62/255)
...@@ -16,23 +18,60 @@ struct MessageView: View { ...@@ -16,23 +18,60 @@ struct MessageView: View {
let maxWidth: CGFloat = 300 let maxWidth: CGFloat = 300
let message: Message let message: Message
let query: ArgumentQuery?
@State var sent: Bool
init(chatManager: ChatManager, message: Message) {
self.chatManager = chatManager
self.message = message
self.query = nil
_sent = State(initialValue: true)
}
init(chatManager: ChatManager, query: ArgumentQuery) {
self.chatManager = chatManager
self.message = query.message
self.query = query
_sent = State(initialValue: false)
}
var body: some View { var body: some View {
HStack(spacing: 0) { VStack(spacing: 0) {
if message.sender == .USER { if !chatManager.sent || self.sent {
Spacer() HStack(spacing: 0) {
if message.sender == .USER {
Spacer()
}
Text(message.text)
.foregroundColor(Color.white)
.font(Font.custom("Helvetica Neue", size: 14))
.fixedSize(horizontal: false, vertical: true)
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.background(MessageBubble(sender: message.sender).foregroundColor(sent ? bubbleColors[message.sender] : FeatureView.bubbleColor))
.frame(minWidth: 0, maxWidth: maxWidth, alignment: message.sender == .ADA ? .leading : .trailing)
.onTapGesture {
if self.message.sender == .ADA {
self.chatManager.showOptionsFor(self.message as! ADAMessage)
} else if !self.sent {
withAnimation(Animation.easeInOut(duration: 0.3)) {
self.chatManager.sendQuery(query: self.query!)
self.sent = true
}
}
}
if message.sender == .ADA {
Spacer()
}
}
.padding(EdgeInsets(top: 0, leading: 20, bottom: 15, trailing: 20))
} }
Text(message.text) if chatManager.showingOptionsFor(message) {
.foregroundColor(Color.white) FeatureView(chatManager: chatManager, arguments: message.arguments)
.font(Font.custom("Helvetica Neue", size: 14))
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.background(MessageBubble(sender: message.sender).foregroundColor(bubbleColors[message.sender]))
.frame(minWidth: 0, maxWidth: maxWidth, alignment: message.sender == .ADA ? .leading : .trailing)
if message.sender == .ADA {
Spacer()
} }
} }
.frame(width: UIScreen.main.bounds.width)
} }
} }
//
// QueryOptionView.swift
// ADAbot
//
// Created by Joel Oksanen on 25.2.2020.
// Copyright © 2020 Joel Oksanen. All rights reserved.
//
import SwiftUI
struct QueryOptionView: View {
@ObservedObject var chatManager: ChatManager
let queries: [ArgumentQuery]
var body: some View {
VStack(spacing: 0) {
ForEach(queries, id: \.id) { query in
MessageView(chatManager: self.chatManager, query: query)
}
}
}
}
...@@ -8,11 +8,26 @@ ...@@ -8,11 +8,26 @@
import UIKit import UIKit
struct UserMessage: Message { struct UserMessage: Message, Equatable {
let id = UUID() let id = UUID()
let sender = Sender.USER let sender = Sender.USER
let text: String let text: String
let arguments = [Argument]() let arguments = [Argument]()
let sent: Bool
init(text: String) {
self.text = text
self.sent = true
}
init(query: ArgumentQuery) {
self.text = query.text
self.sent = false
}
static func == (lhs: UserMessage, rhs: UserMessage) -> Bool {
lhs.id == rhs.id
}
} }
...@@ -51,7 +51,10 @@ class ConnectionManager: ObservableObject { ...@@ -51,7 +51,10 @@ class ConnectionManager: ObservableObject {
} }
} }
task.resume() task.resume()
}
func addMessage(message: Message) {
messages.append(message)
} }
} }
...@@ -9,11 +9,13 @@ ...@@ -9,11 +9,13 @@
import SwiftUI import SwiftUI
struct ContentView: View { struct ContentView: View {
@ObservedObject var connectionManager = ConnectionManager()
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
ProductView() ProductView(connectionManager: connectionManager)
.zIndex(10) .zIndex(10)
ChatView() ChatView(connectionManager: connectionManager)
.zIndex(0) .zIndex(0)
} }
.edgesIgnoringSafeArea(.all) .edgesIgnoringSafeArea(.all)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
import SwiftUI import SwiftUI
struct ProductView: View { struct ProductView: View {
@ObservedObject var connectionManager = ConnectionManager() @ObservedObject var connectionManager: ConnectionManager
let height: CGFloat = 200 let height: CGFloat = 200
var body: some View { var body: some View {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment