Commit df266b93 authored by  Joel  Oksanen's avatar Joel Oksanen
Browse files

Finished messaging MVP on client

parent f151e1e5
......@@ -27,6 +27,8 @@
9449FE4924042D6500025F70 /* FeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4824042D6500025F70 /* FeatureView.swift */; };
9449FE4B24042E8800025F70 /* Argument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4A24042E8800025F70 /* Argument.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 */
/* Begin PBXFileReference section */
......@@ -52,6 +54,8 @@
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>"; };
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 */
/* Begin PBXFrameworksBuildPhase section */
......@@ -109,16 +113,18 @@
9449FE3E2403EDB400025F70 /* Chat */ = {
isa = PBXGroup;
children = (
9449FE5024053DA500025F70 /* ChatManager.swift */,
9449FE442403F0A600025F70 /* Sender.swift */,
9449FE382403E9A400025F70 /* Message.swift */,
9449FE3A2403EC3800025F70 /* ADAMessage.swift */,
9449FE4A24042E8800025F70 /* Argument.swift */,
9449FE4C2404561400025F70 /* ArgumentQuery.swift */,
9449FE3C2403ED0200025F70 /* UserMessage.swift */,
9449FE422403F02500025F70 /* MessageBubble.swift */,
9449FE302402C90800025F70 /* ChatView.swift */,
9449FE402403EF5A00025F70 /* MessageView.swift */,
9449FE422403F02500025F70 /* MessageBubble.swift */,
9449FE4824042D6500025F70 /* FeatureView.swift */,
9449FE4E240533FD00025F70 /* QueryOptionView.swift */,
);
name = Chat;
path = ADAbot/Chat;
......@@ -209,6 +215,7 @@
9449FE3B2403EC3800025F70 /* ADAMessage.swift in Sources */,
9449FE3D2403ED0200025F70 /* UserMessage.swift in Sources */,
9449FE2F2402C8C500025F70 /* ProductView.swift in Sources */,
9449FE4F240533FD00025F70 /* QueryOptionView.swift in Sources */,
9449FE4B24042E8800025F70 /* Argument.swift in Sources */,
9449FE372402D29E00025F70 /* Product.swift in Sources */,
9449FE432403F02500025F70 /* MessageBubble.swift in Sources */,
......@@ -218,6 +225,7 @@
9449FE4D2404561400025F70 /* ArgumentQuery.swift in Sources */,
9449FE4924042D6500025F70 /* FeatureView.swift in Sources */,
9449FE312402C90800025F70 /* ChatView.swift in Sources */,
9449FE5124053DA500025F70 /* ChatManager.swift in Sources */,
9449FE352402CCDA00025F70 /* ConnectionManager.swift in Sources */,
9449FE1D2402C84F00025F70 /* SceneDelegate.swift in Sources */,
9449FE1F2402C84F00025F70 /* ContentView.swift in Sources */,
......
......@@ -3,22 +3,4 @@
uuid = "91D35F8C-89D0-4137-A5A5-FAFC5B6FE3BA"
type = "1"
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>
......@@ -8,11 +8,15 @@
import UIKit
struct ADAMessage: Message, Decodable {
struct ADAMessage: Message, Decodable, Equatable {
let id = UUID()
let sender = Sender.ADA
let text: String
let arguments: [Argument]
static func == (lhs: ADAMessage, rhs: ADAMessage) -> Bool {
lhs.id == rhs.id
}
}
......@@ -8,10 +8,15 @@
import UIKit
struct Argument: Codable {
struct Argument: Codable, Equatable {
let id = UUID()
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
struct ArgumentQuery: Codable {
let id = UUID()
let argumentID: Int
let queryID: Int
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 @@
import SwiftUI
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 {
ZStack {
......@@ -19,11 +25,8 @@ struct ChatView: View {
ScrollView {
VStack(spacing: 0) {
ForEach(connectionManager.messages, id: \.id) { message in
MessageView(message: message)
.padding(EdgeInsets(top: 0, leading: 20, bottom: 15, trailing: 20))
MessageView(chatManager: self.chatManager, message: message)
}
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))
}
......
......@@ -9,44 +9,70 @@
import SwiftUI
struct FeatureView: View {
@ObservedObject var chatManager: ChatManager
static let bubbleColor = Color(red: 75/255, green: 90/255, blue: 116/255)
let arguments: [Argument]
let bubbleColor = Color(red: 75/255, green: 90/255, blue: 116/255)
@State var showingQueryOptionsForArgument: Argument?
var body: some View {
HStack(spacing: 0) {
Spacer()
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) {
VStack(spacing: 0) {
if (!chatManager.sent) {
HStack(spacing: 0) {
Spacer()
.frame(width: 10)
ForEach(self.arguments, id: \.id) { argument in
Text(argument.name)
.foregroundColor(Color.white)
.font(Font.custom("Helvetica Neue", size: 12))
.fixedSize(horizontal: true, vertical: true)
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.background(Capsule().foregroundColor(self.bubbleColor))
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 10))
Text("ASK ABOUT")
.foregroundColor(FeatureView.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(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(width: 10)
.frame(maxWidth: 280)
.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 @@
import SwiftUI
struct MessageView: View {
@ObservedObject var chatManager: ChatManager
let bubbleColors = [
Sender.ADA: Color(red: 242/255, green: 159/255, blue: 31/255),
Sender.USER: Color(red: 35/255, green: 45/255, blue: 62/255)
......@@ -16,23 +18,60 @@ struct MessageView: View {
let maxWidth: CGFloat = 300
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 {
HStack(spacing: 0) {
if message.sender == .USER {
Spacer()
VStack(spacing: 0) {
if !chatManager.sent || self.sent {
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)
.foregroundColor(Color.white)
.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()
if chatManager.showingOptionsFor(message) {
FeatureView(chatManager: chatManager, arguments: message.arguments)
}
}
.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 @@
import UIKit
struct UserMessage: Message {
struct UserMessage: Message, Equatable {
let id = UUID()
let sender = Sender.USER
let text: String
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 {
}
}
task.resume()
}
func addMessage(message: Message) {
messages.append(message)
}
}
......@@ -9,11 +9,13 @@
import SwiftUI
struct ContentView: View {
@ObservedObject var connectionManager = ConnectionManager()
var body: some View {
VStack(spacing: 0) {
ProductView()
ProductView(connectionManager: connectionManager)
.zIndex(10)
ChatView()
ChatView(connectionManager: connectionManager)
.zIndex(0)
}
.edgesIgnoringSafeArea(.all)
......
......@@ -9,7 +9,7 @@
import SwiftUI
struct ProductView: View {
@ObservedObject var connectionManager = ConnectionManager()
@ObservedObject var connectionManager: ConnectionManager
let height: CGFloat = 200
var body: some View {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment