show received messages in chat, send command on Enter, fix Date parsing (#237)

* refactor UI and API, send command on Enter, fix Date parsing

* UI sheets to create connection and groups

* show received messages

* readme
This commit is contained in:
Evgeny Poberezkin
2022-01-29 23:37:02 +00:00
committed by GitHub
parent 7e2f365c1c
commit cb602dd377
20 changed files with 546 additions and 176 deletions

View File

@@ -2,11 +2,7 @@
## Prerequisites
- `mac2ios` executable and in PATH:
https://github.com/zw3rk/mobile-core-tools
- Folders:
- Prepare folders:
```sh
mkdir -p ./apps/ios/Libraries/mac ./apps/ios/Libraries/ios ./apps/ios/Libraries/sim
@@ -14,11 +10,9 @@
## Update binaries
1. Download binary distribution from `aarch64-darwin:lib:simplex-chat.aarch64-darwin` job at
https://ci.zw3rk.com/jobset/zw3rk/simplex-chat
and extract binaries to `./apps/ios/Libraries/mac`.
1. Extract binaries to `./apps/ios/Libraries/mac`.
2. Prepare binaries for iOS and for Xcode simulator:
2. Prepare binaries:
```sh
chmod +w ./apps/ios/Libraries/mac/*
@@ -30,13 +24,11 @@ and extract binaries to `./apps/ios/Libraries/mac`.
3. Put binaries into `./apps/ios/Libraries`.
For simulator:
```sh
cp ./apps/ios/Libraries/sim/* ./apps/ios/Libraries
```
For iOS:
or:
```sh
cp ./apps/ios/Libraries/ios/* ./apps/ios/Libraries

View File

@@ -71,7 +71,14 @@ struct ContentView: View {
var body: some View {
if let user = chatModel.currentUser {
ChatListView(user: user)
.onAppear { chatSendCmd(chatModel, .apiGetChats) }
.onAppear {
do {
let chats = try apiGetChats()
chatModel.chatPreviews = chats
} catch {
print(error)
}
}
} else {
WelcomeView()
}

View File

@@ -14,7 +14,7 @@ final class ChatModel: ObservableObject {
@Published var chats: Dictionary<String, Chat> = [:]
@Published var chatPreviews: [ChatPreview] = []
@Published var chatItems: [ChatItem] = []
@Published var apiResponses: [APIResponse] = []
@Published var terminalItems: [TerminalItem] = []
}
struct User: Codable {
@@ -25,6 +25,14 @@ struct User: Codable {
var activeUser: Bool
}
let sampleUser = User(
userId: 1,
userContactId: 1,
localDisplayName: "alice",
profile: sampleProfile,
activeUser: true
)
typealias ContactName = String
typealias GroupName = String
@@ -34,7 +42,12 @@ struct Profile: Codable {
var fullName: String
}
struct ChatPreview: Identifiable, Codable {
let sampleProfile = Profile(
displayName: "alice",
fullName: "Alice"
)
struct ChatPreview: Identifiable, Decodable {
var chatInfo: ChatInfo
var lastChatItem: ChatItem?
@@ -43,6 +56,11 @@ struct ChatPreview: Identifiable, Codable {
}
}
enum ChatType: String {
case direct
case group
}
enum ChatInfo: Identifiable, Codable {
case direct(contact: Contact)
case group(groupInfo: GroupInfo)
@@ -65,11 +83,11 @@ enum ChatInfo: Identifiable, Codable {
}
}
var apiType: String {
var chatType: ChatType {
get {
switch self {
case .direct(_): return "direct"
case .group(_): return "group"
case .direct: return .direct
case .group: return .group
}
}
}
@@ -84,9 +102,18 @@ enum ChatInfo: Identifiable, Codable {
}
}
class Chat: Codable {
let sampleDirectChatInfo = ChatInfo.direct(contact: sampleContact)
let sampleGroupChatInfo = ChatInfo.group(groupInfo: sampleGroupInfo)
class Chat: Decodable {
var chatInfo: ChatInfo
var chatItems: [ChatItem]
init(chatInfo: ChatInfo, chatItems: [ChatItem]) {
self.chatInfo = chatInfo
self.chatItems = chatItems
}
}
struct Contact: Identifiable, Codable {
@@ -98,6 +125,12 @@ struct Contact: Identifiable, Codable {
var id: String { get { "@\(contactId)" } }
}
let sampleContact = Contact(
contactId: 1,
localDisplayName: "alice",
profile: sampleProfile
)
struct GroupInfo: Identifiable, Codable {
var groupId: Int64
var localDisplayName: GroupName
@@ -106,16 +139,32 @@ struct GroupInfo: Identifiable, Codable {
var id: String { get { "#\(groupId)" } }
}
let sampleGroupInfo = GroupInfo(
groupId: 1,
localDisplayName: "team",
groupProfile: sampleGroupProfile
)
struct GroupProfile: Codable {
var displayName: String
var fullName: String
}
let sampleGroupProfile = GroupProfile(
displayName: "team",
fullName: "My Team"
)
struct GroupMember: Codable {
}
struct ChatItem: Identifiable, Codable {
struct AChatItem: Decodable {
var chatInfo: ChatInfo
var chatItem: ChatItem
}
struct ChatItem: Identifiable, Decodable {
var chatDir: CIDirection
var meta: CIMeta
var content: CIContent
@@ -123,21 +172,21 @@ struct ChatItem: Identifiable, Codable {
var id: Int64 { get { meta.itemId } }
}
enum CIDirection: Codable {
enum CIDirection: Decodable {
case directSnd
case directRcv
case groupSnd
case groupRcv(GroupMember)
}
struct CIMeta: Codable {
struct CIMeta: Decodable {
var itemId: Int64
var itemTs: Date
var itemText: String
var createdAt: Date
}
enum CIContent: Codable {
enum CIContent: Decodable {
case sndMsgContent(msgContent: MsgContent)
case rcvMsgContent(msgContent: MsgContent)
// files etc.
@@ -152,24 +201,44 @@ enum CIContent: Codable {
}
}
enum MsgContent: Codable {
enum MsgContent {
case text(String)
case unknown(type: String, text: String, json: String)
case invalid(json: String)
case unknown(type: String, text: String)
case invalid(error: String)
init(from: Decoder) throws {
self = .invalid(json: "")
}
var string: String {
get {
switch self {
case let .text(str): return str
case .unknown: return "unknown"
case let .text(text): return text
case let .unknown(_, text): return text
case .invalid: return "invalid"
}
}
}
enum CodingKeys: String, CodingKey {
case type
case text
}
}
extension MsgContent: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
let type = try container.decode(String.self, forKey: CodingKeys.type)
switch type {
case "text":
let text = try container.decode(String.self, forKey: CodingKeys.text)
self = .text(text)
default:
let text = try? container.decode(String.self, forKey: CodingKeys.text)
self = .unknown(type: type, text: text ?? "unknown message format")
}
} catch {
self = .invalid(error: String(describing: error))
}
}
}
//func parseMsgContent(_ mc: SomeMsgContent) -> MsgContent {

View File

@@ -0,0 +1,38 @@
//
// JSON.swift
// SimpleX
//
// Created by Evgeny Poberezkin on 29/01/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import Foundation
func getJSONDecoder() -> JSONDecoder {
let jd = JSONDecoder()
let fracSeconds = getDateFormatter("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ")
let noFracSeconds = getDateFormatter("yyyy-MM-dd'T'HH:mm:ssZZZZZ")
jd.dateDecodingStrategy = .custom { decoder in
let container = try decoder.singleValueContainer()
let string = try container.decode(String.self)
if let date = fracSeconds.date(from: string) ?? noFracSeconds.date(from: string) {
return date
}
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)")
}
return jd
}
func getJSONEncoder() -> JSONEncoder {
let je = JSONEncoder()
je.dateEncodingStrategy = .iso8601
return je
}
private func getDateFormatter(_ format: String) -> DateFormatter {
let df = DateFormatter()
df.locale = Locale(identifier: "en_US_POSIX")
df.dateFormat = format
df.timeZone = TimeZone(secondsFromGMT: 0)
return df
}

View File

@@ -7,15 +7,16 @@
//
import Foundation
import UIKit
private var chatStore: chat_store?
private var chatController: chat_ctrl?
private let jsonDecoder = JSONDecoder()
private let jsonEncoder = JSONEncoder()
private let jsonDecoder = getJSONDecoder()
private let jsonEncoder = getJSONEncoder()
enum ChatCommand {
case apiGetChats
case apiGetChatItems(type: String, id: Int64)
case apiGetChatItems(type: ChatType, id: Int64)
case string(String)
case help
@@ -25,7 +26,7 @@ enum ChatCommand {
case .apiGetChats:
return "/api/v1/chats"
case let .apiGetChatItems(type, id):
return "/api/v1/chat/items/\(type)/\(id)"
return "/api/v1/chat/\(type)/\(id)"
case let .string(str):
return str
case .help: return "/help"
@@ -34,30 +35,26 @@ enum ChatCommand {
}
}
struct APIResponse: Identifiable {
var resp: ChatResponse
var id: Int64
}
struct APIResponseJSON: Decodable {
struct APIResponse: Decodable {
var resp: ChatResponse
}
enum ChatResponse: Codable {
enum ChatResponse: Decodable, Error {
case response(type: String, json: String)
case apiChats(chats: [ChatPreview])
case apiDirectChat(chat: Chat) // direct/<id> or group/<id>, same as ChatPreview.id
// case chatHelp(String)
// case newSentInvitation
case contactConnected(contact: Contact)
case newChatItem(chatItem: AChatItem)
var responseType: String {
get {
switch self {
case let .response(type, _): return "* \(type)"
case .apiChats(_): return "apiChats"
case .apiDirectChat(_): return "apiDirectChat"
case .contactConnected(_): return "contactConnected"
case .apiChats: return "apiChats"
case .apiDirectChat: return "apiDirectChat"
case .contactConnected: return "contactConnected"
case .newChatItem: return "newChatItem"
}
}
}
@@ -69,6 +66,39 @@ enum ChatResponse: Codable {
case let .apiChats(chats): return String(describing: chats)
case let .apiDirectChat(chat): return String(describing: chat)
case let .contactConnected(contact): return String(describing: contact)
case let .newChatItem(chatItem): return String(describing: chatItem)
}
}
}
}
enum TerminalItem: Identifiable {
case cmd(Date, ChatCommand)
case resp(Date, ChatResponse)
var id: Date {
get {
switch self {
case let .cmd(id, _): return id
case let .resp(id, _): return id
}
}
}
var label: String {
get {
switch self {
case let .cmd(_, cmd): return "> \(cmd.cmdString.prefix(30))"
case let .resp(_, resp): return "< \(resp.responseType)"
}
}
}
var details: String {
get {
switch self {
case let .cmd(_, cmd): return cmd.cmdString
case let .resp(_, resp): return resp.details
}
}
}
@@ -95,41 +125,52 @@ func chatCreateUser(_ p: Profile) -> User? {
return user
}
func chatSendCmd(_ chatModel: ChatModel, _ cmd: ChatCommand) {
func chatSendCmd(_ cmd: ChatCommand) throws -> ChatResponse {
var c = cmd.cmdString.cString(using: .utf8)!
processAPIResponse(chatModel,
apiResponse(
chat_send_cmd(getChatCtrl(), &c)!))
// TODO some mechanism to update model without passing it - maybe Publisher / Subscriber?
// DispatchQueue.main.async {
// termId += 1
// chatModel.terminalItems.append(.cmd(termId, cmd))
// }
return chatResponse(chat_send_cmd(getChatCtrl(), &c)!)
}
func chatRecvMsg(_ chatModel: ChatModel) {
processAPIResponse(chatModel,
apiResponse(
chat_recv_msg(getChatCtrl())!))
func chatRecvMsg() throws -> ChatResponse {
chatResponse(chat_recv_msg(getChatCtrl())!)
}
private func processAPIResponse(_ chatModel: ChatModel, _ res: APIResponse?) {
if let r = res {
DispatchQueue.main.async {
chatModel.apiResponses.append(r)
switch r.resp {
case let .apiChats(chats):
chatModel.chatPreviews = chats
case let .apiDirectChat(chat):
chatModel.chats[chat.chatInfo.id] = chat
case let .contactConnected(contact):
chatModel.chatPreviews.insert(
ChatPreview(chatInfo: .direct(contact: contact)),
at: 0
)
default: return
func apiGetChats() throws -> [ChatPreview] {
let r = try chatSendCmd(.apiGetChats)
switch r {
case let .apiChats(chats): return chats
default: throw r
}
}
// case let .response(type, _):
// chatModel.chatItems.append(ChatItem(
// ts: Date.now,
// content: .text(type)
// ))
}
func apiGetChatItems(type: ChatType, id: Int64) throws -> Chat {
let r = try chatSendCmd(.apiGetChatItems(type: type, id: id))
switch r {
case let .apiDirectChat(chat): return chat
default: throw r
}
}
func processReceivedMsg(_ chatModel: ChatModel, _ res: ChatResponse) {
DispatchQueue.main.async {
chatModel.terminalItems.append(.resp(Date.now, res))
switch res {
case let .contactConnected(contact):
chatModel.chatPreviews.insert(
ChatPreview(chatInfo: .direct(contact: contact)),
at: 0
)
case let .newChatItem(aChatItem):
let ci = aChatItem.chatInfo
let chat = chatModel.chats[ci.id] ?? Chat(chatInfo: ci, chatItems: [])
chatModel.chats[ci.id] = chat
chat.chatItems.append(aChatItem.chatItem)
default:
print("unsupported response: ", res)
}
}
}
@@ -139,19 +180,19 @@ private struct UserResponse: Decodable {
var error: String?
}
private var respId: Int64 = 0
private func apiResponse(_ cjson: UnsafePointer<CChar>) -> APIResponse? {
private func chatResponse(_ cjson: UnsafePointer<CChar>) -> ChatResponse {
let s = String.init(cString: cjson)
print("apiResponse", s)
print("chatResponse", s)
let d = s.data(using: .utf8)!
// TODO is there a way to do it without copying the data? e.g:
// TODO is there a way to do it without copying the data? e.g:
// let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson))
// let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free)
// TODO some mechanism to update model without passing it - maybe Publisher / Subscriber?
do {
let r = try jsonDecoder.decode(APIResponseJSON.self, from: d)
return APIResponse(resp: r.resp, id: respId)
let r = try jsonDecoder.decode(APIResponse.self, from: d)
return r.resp
} catch {
print (error)
}
@@ -164,11 +205,7 @@ private func apiResponse(_ cjson: UnsafePointer<CChar>) -> APIResponse? {
}
json = prettyJSON(j)
}
respId += 1
return APIResponse(
resp: ChatResponse.response(type: type ?? "invalid", json: json ?? s),
id: respId
)
return ChatResponse.response(type: type ?? "invalid", json: json ?? s)
}
func prettyJSON(_ obj: NSDictionary) -> String? {

View File

@@ -37,18 +37,45 @@ let ct = Contact(
//,"agentConnId":"cTdFNkprSHhZZmZhdWFQVg==","createdAt":"2022-01-27T19:47:08.891646Z","connStatus":"ready"},"localDisplayName":"ep"}}}}]
//"""
//
//let data = str.data(using: .utf8)!
//let str = """
//{"resp":{"apiDirectChat":{"chat":{"chatInfo":{"direct":{"contact":{"contactId":2,"localDisplayName":"ep","profile":{"displayName":"ep","fullName":"Evgeny"},"activeConn":{"connId":1,"agentConnId":"bUk2OXZlN3lfNXFaVWRWMQ==","connLevel":0,"connType":"contact","connStatus":"ready","entityId":2,"createdAt":"2022-01-29T11:21:18.669786Z"}}}},"chatItems":[{"chatDir":{"directSnd":{}},"meta":{"itemId":1,"itemTs":"2022-01-29T11:21:47.947865Z","itemText":"hello","localItemTs":"2022-01-29T11:21:47.947865Z","createdAt":"2022-01-29T11:21:47.947865Z"},"content":{"sndMsgContent":{"msgContent":{"type":"text","text":"hello"}}}},{"chatDir":{"directRcv":{}},"meta":{"itemId":2,"itemTs":"2022-01-29T11:22:08Z","itemText":"hi","localItemTs":"2022-01-29T11:22:08Z","createdAt":"2022-01-29T11:22:08.563959Z"},"content":{"rcvMsgContent":{"msgContent":{"type":"text","text":"hi"}}}}]}}}}
//"""
let str = "\"2022-01-29T11:21:47Z\""
let data = str.data(using: .utf8)!
let jsonDecoder = JSONDecoder()
//let r: [ChatPreview] = try! jsonDecoder.decode([ChatPreview].self, from: data)
//
//print(r)
let df1 = DateFormatter()
df1.locale = Locale(identifier: "en_US_POSIX")
df1.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
df1.timeZone = TimeZone(secondsFromGMT: 0)
let df2 = DateFormatter()
df2.locale = Locale(identifier: "en_US_POSIX")
df2.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
df2.timeZone = TimeZone(secondsFromGMT: 0)
jsonDecoder.dateDecodingStrategy = .iso8601 // .custom { decoder in
// let container = try decoder.singleValueContainer()
// let string = try container.decode(String.self)
// if let date = df1.date(from: string) ?? df2.date(from: string) {
// return date
// }
// throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)")
//}
let r: Date = try! jsonDecoder.decode(Date.self, from: data)
print(r)
struct Test: Decodable {
var name: String
var id: Int64 = 0
}
jsonDecoder.decode(Test.self, from: "{\"name\":\"hello\",\"id\":1}".data(using: .utf8)!)
//jsonDecoder.decode(Test.self, from: "{\"name\":\"hello\",\"id\":1}".data(using: .utf8)!)

View File

@@ -3,7 +3,7 @@
version = "3.0">
<TimelineItems>
<LoggerValueHistoryTimelineItem
documentLocation = "file:///Users/evgeny/opensource/simplex-chat/simplex-chat/apps/ios/Shared/MyPlayground.playground#CharacterRangeLen=88&amp;CharacterRangeLoc=2005&amp;EndingColumnNumber=0&amp;EndingLineNumber=53&amp;StartingColumnNumber=1&amp;StartingLineNumber=52&amp;Timestamp=665139674.041539"
documentLocation = "file:///Users/evgeny/opensource/simplex-chat/simplex-chat/apps/ios/Shared/MyPlayground.playground#CharacterRangeLen=88&amp;CharacterRangeLoc=3634&amp;EndingColumnNumber=0&amp;EndingLineNumber=80&amp;StartingColumnNumber=3&amp;StartingLineNumber=79&amp;Timestamp=665153525.657431"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>

View File

@@ -10,23 +10,9 @@ import SwiftUI
@main
struct SimpleXApp: App {
@StateObject private var chatModel = ChatModel()
// let store: chat_store
init() {
hs_init(0, nil)
// let dataDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.path + "/mobile_v1"
// var cstr = dataDir.cString(using: .utf8)!
// store = chat_init_store(&cstr)
// let user = String.init(cString: chat_get_user(store))
// print(user)
// if user != "{}" {
// chatModel.currentUser = parseJSON(user)
// var data = "{ \"displayName\": \"test\", \"fullName\": \"ios test\" }".cString(using: .utf8)!
// chat_create_user(store, &data)
// }
// controller = chat_start(store)
// var cmd = "/help".cString(using: .utf8)!
// print(String.init(cString: chat_send_cmd(controller, &cmd)))
}
var body: some Scene {

View File

@@ -14,16 +14,25 @@ struct ChatListView: View {
var body: some View {
DispatchQueue.global().async {
while(true) { chatRecvMsg(chatModel) }
while(true) {
do {
try processReceivedMsg(chatModel, chatRecvMsg())
} catch {
print("error receiving message: ", error)
}
}
}
return VStack {
// if chatModel.chats.isEmpty {
VStack {
Text("Hello chat")
Text("Active user: \(user.localDisplayName) (\(user.profile.fullName))")
}
// VStack {
// Text("Hello chat")
// Text("Active user: \(user.localDisplayName) (\(user.profile.fullName))")
// }
// }
ChatHeaderView()
NavigationView {
List {
NavigationLink {
@@ -36,7 +45,12 @@ struct ChatListView: View {
NavigationLink {
ChatView(chatInfo: chatPreview.chatInfo)
.onAppear {
chatSendCmd(chatModel, .apiGetChatItems(type: "direct", id: chatPreview.chatInfo.apiId))
do {
let chat = try apiGetChatItems(type: .direct, id: chatPreview.chatInfo.apiId)
chatModel.chats[chat.chatInfo.id] = chat
} catch {
print("apiGetChatItems", error)
}
}
} label: {
ChatPreviewView(chatPreview: chatPreview)
@@ -51,6 +65,9 @@ struct ChatListView: View {
//struct ChatListView_Previews: PreviewProvider {
// static var previews: some View {
// ChatListView()
// let chatModel = ChatModel()
// chatModel.chatPreviews = []
// return ChatListView(user: sampleUser)
// .environmentObject(chatModel)
// }
//}

View File

@@ -19,28 +19,8 @@ struct ChatPreviewView: View {
struct ChatPreviewView_Previews: PreviewProvider {
static var previews: some View {
Group{
ChatPreviewView(chatPreview: ChatPreview(
chatInfo: .direct(contact: Contact(
contactId: 123,
localDisplayName: "ep",
profile: Profile(
displayName: "ep",
fullName: "Ep"
),
viaGroup: nil
))
))
ChatPreviewView(chatPreview: ChatPreview(
chatInfo: .group(groupInfo: GroupInfo(
groupId: 123,
localDisplayName: "team",
groupProfile: GroupProfile(
displayName: "team",
fullName: "My Team"
)
))
))
ChatPreviewView(chatPreview: ChatPreview(chatInfo: sampleDirectChatInfo))
ChatPreviewView(chatPreview: ChatPreview(chatInfo: sampleGroupChatInfo))
}
.previewLayout(.fixed(width: 300, height: 70))
}

View File

@@ -10,6 +10,8 @@ import SwiftUI
struct ChatView: View {
@EnvironmentObject var chatModel: ChatModel
@State var inProgress: Bool = false
var chatInfo: ChatInfo
var body: some View {
VStack {
@@ -26,12 +28,28 @@ struct ChatView: View {
} else {
Text("unexpected: chat not found...")
}
Spacer()
SendMessageView(sendMessage: sendMessage, inProgress: inProgress)
}
}
func sendMessage(_ msg: String) {
}
}
//struct ChatView_Previews: PreviewProvider {
// static var previews: some View {
// ChatView()
// }
//}
struct ChatView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.chats = [
"@1": Chat(
chatInfo: sampleDirectChatInfo,
chatItems: []
)
]
return ChatView(chatInfo: sampleDirectChatInfo)
.environmentObject(chatModel)
}
}

View File

@@ -0,0 +1,43 @@
//
// ChatHeaderView.swift
// SimpleX
//
// Created by Evgeny Poberezkin on 29/01/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct ChatHeaderView: View {
@State private var showAddChat = false
@State private var inviteContact = false
@State private var scanQRCode = false
@State private var createGroup = false
var body: some View {
HStack {
Button("Edit", action: {})
Spacer()
Text("Your chats")
Spacer()
Button { showAddChat = true } label: {
Image(systemName: "square.and.pencil")
}
.confirmationDialog("Start new chat", isPresented: $showAddChat, titleVisibility: .visible) {
Button("Invite contact") { inviteContact = true }
Button("Scan QR code") { scanQRCode = true }
Button("Create group") { createGroup = true }
}
.sheet(isPresented: $inviteContact, content: { InviteContactView() })
.sheet(isPresented: $scanQRCode, content: { ScanQRCodeView() })
.sheet(isPresented: $createGroup, content: { CreateGroupView() })
}
.padding(.horizontal)
}
}
struct ChatHeaderView_Previews: PreviewProvider {
static var previews: some View {
ChatHeaderView()
}
}

View File

@@ -0,0 +1,21 @@
//
// CreateGroupView.swift
// SimpleX
//
// Created by Evgeny Poberezkin on 29/01/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct CreateGroupView: View {
var body: some View {
Text("CreateGroupView")
}
}
struct CreateGroupView_Previews: PreviewProvider {
static var previews: some View {
CreateGroupView()
}
}

View File

@@ -0,0 +1,21 @@
//
// InviteContactView.swift
// SimpleX
//
// Created by Evgeny Poberezkin on 29/01/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct InviteContactView: View {
var body: some View {
Text("InviteContactView")
}
}
struct InviteContactView_Previews: PreviewProvider {
static var previews: some View {
InviteContactView()
}
}

View File

@@ -0,0 +1,21 @@
//
// ScanQRCodeView.swift
// SimpleX
//
// Created by Evgeny Poberezkin on 29/01/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct ScanQRCodeView: View {
var body: some View {
Text("ScanQRCodeView")
}
}
struct ScanQRCodeView_Previews: PreviewProvider {
static var previews: some View {
ScanQRCodeView()
}
}

View File

@@ -0,0 +1,47 @@
//
// SendMessageView.swift
// SimpleX
//
// Created by Evgeny Poberezkin on 29/01/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct SendMessageView: View {
var sendMessage: (String) -> Void
var inProgress: Bool = false
@State var command: String = ""
var body: some View {
HStack {
TextField("Message...", text: $command)
.textFieldStyle(RoundedBorderTextFieldStyle())
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.frame(minHeight: 30)
.onSubmit(submit)
if (inProgress) {
ProgressView()
.frame(width: 40, height: 20, alignment: .center)
} else {
Button("Send", action :submit)
.disabled(command.isEmpty)
}
}
.frame(minHeight: 30)
.padding()
}
func submit() {
sendMessage(command)
command = ""
}
}
struct SendMessageView_Previews: PreviewProvider {
static var previews: some View {
SendMessageView(sendMessage: { print ($0) })
}
}

View File

@@ -10,20 +10,19 @@ import SwiftUI
struct TerminalView: View {
@EnvironmentObject var chatModel: ChatModel
@State var command: String = ""
@State var inProgress: Bool = false
var body: some View {
VStack {
ScrollView {
LazyVStack {
ForEach(chatModel.apiResponses) { r in
ForEach(chatModel.terminalItems) { item in
NavigationLink {
ScrollView {
Text(r.resp.details)
Text(item.details)
}
} label: {
Text(r.resp.responseType)
Text(item.label)
.frame(width: 360, height: 30, alignment: .leading)
}
}
@@ -33,25 +32,24 @@ struct TerminalView: View {
Spacer()
HStack {
TextField("Message...", text: $command)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(minHeight: 30)
Button(action: sendMessage) {
Text("Send")
}.disabled(command.isEmpty)
}
.frame(minHeight: 30)
.padding()
SendMessageView(sendMessage: sendMessage, inProgress: inProgress)
}
}
func sendMessage() {
func sendMessage(_ cmdStr: String) {
let cmd = ChatCommand.string(cmdStr)
chatModel.terminalItems.append(.cmd(Date.now, cmd))
DispatchQueue.global().async {
let cmd: String = self.$command.wrappedValue
inProgress = true
command = ""
chatSendCmd(chatModel, ChatCommand.string(cmd))
do {
let r = try chatSendCmd(cmd)
DispatchQueue.main.async {
chatModel.terminalItems.append(.resp(Date.now, r))
}
} catch {
print(error)
}
inProgress = false
}
}
@@ -60,9 +58,9 @@ struct TerminalView: View {
struct TerminalView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.apiResponses = [
APIResponse(resp: ChatResponse.response(type: "contactSubscribed", json: "{}"), id: 1),
APIResponse(resp: ChatResponse.response(type: "newChatItem", json: "{}"), id: 2)
chatModel.terminalItems = [
.resp(Date.now, ChatResponse.response(type: "contactSubscribed", json: "{}")),
.resp(Date.now, ChatResponse.response(type: "newChatItem", json: "{}"))
]
return NavigationView {
TerminalView()

View File

@@ -20,8 +20,12 @@ struct WelcomeView: View {
Text("Your profile is stored on your device and shared only with your contacts.\nSimpleX servers cannot see your profile.")
.padding(.bottom)
TextField("Display name", text: $displayName)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.padding(.bottom)
TextField("Full name (optional)", text: $fullName)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.padding(.bottom)
Button("Create") {
let profile = Profile(

View File

@@ -9,10 +9,6 @@
/* Begin PBXBuildFile section */
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
5C063D2827A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
5C1AEB82279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */; };
5C1AEB83279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */; };
5C1AEB84279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */; };
5C1AEB85279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */; };
5C1AEB86279F4A6400247F08 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7F279F4A6400247F08 /* libffi.a */; };
5C1AEB87279F4A6400247F08 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7F279F4A6400247F08 /* libffi.a */; };
5C1AEB88279F4A6400247F08 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB80279F4A6400247F08 /* libgmp.a */; };
@@ -27,6 +23,10 @@
5C2E261027A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E261127A30FEA00F70299 /* TerminalView.swift */; };
5C2E261327A30FEA00F70299 /* TerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E261127A30FEA00F70299 /* TerminalView.swift */; };
5C44B6A027A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */; };
5C44B6A127A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */; };
5C44B6A227A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */; };
5C44B6A327A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */; };
5C764E80279C7276000C6508 /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E7F279C7276000C6508 /* dummy.m */; };
5C764E81279C7276000C6508 /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E7F279C7276000C6508 /* dummy.m */; };
5C764E82279C748B000C6508 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E7B279C71D4000C6508 /* libiconv.tbd */; };
@@ -35,6 +35,10 @@
5C764E85279C748C000C6508 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E7C279C71DB000C6508 /* libz.tbd */; };
5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E88279CBCB3000C6508 /* ChatModel.swift */; };
5C764E8A279CBCB3000C6508 /* ChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E88279CBCB3000C6508 /* ChatModel.swift */; };
5C9FD96B27A56D4D0075386C /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96A27A56D4D0075386C /* JSON.swift */; };
5C9FD96C27A56D4D0075386C /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96A27A56D4D0075386C /* JSON.swift */; };
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */; };
5C9FD96F27A5D6ED0075386C /* SendMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */; };
5CA059DC279559F40002BEB4 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DB279559F40002BEB4 /* Tests_iOS.swift */; };
5CA059DE279559F40002BEB4 /* Tests_iOSLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DD279559F40002BEB4 /* Tests_iOSLaunchTests.swift */; };
5CA059E8279559F40002BEB4 /* Tests_macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059E7279559F40002BEB4 /* Tests_macOS.swift */; };
@@ -49,6 +53,14 @@
5CA05A4D27974EB60002BEB4 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA05A4B27974EB60002BEB4 /* WelcomeView.swift */; };
5CA05A4F279752D00002BEB4 /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA05A4E279752D00002BEB4 /* MessageView.swift */; };
5CA05A50279752D00002BEB4 /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA05A4E279752D00002BEB4 /* MessageView.swift */; };
5CCD403127A5F1C600368C90 /* ChatHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403027A5F1C600368C90 /* ChatHeaderView.swift */; };
5CCD403227A5F1C600368C90 /* ChatHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403027A5F1C600368C90 /* ChatHeaderView.swift */; };
5CCD403427A5F6DF00368C90 /* InviteContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* InviteContactView.swift */; };
5CCD403527A5F6DF00368C90 /* InviteContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* InviteContactView.swift */; };
5CCD403727A5F9A200368C90 /* ScanQRCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanQRCodeView.swift */; };
5CCD403827A5F9A200368C90 /* ScanQRCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanQRCodeView.swift */; };
5CCD403A27A5F9BE00368C90 /* CreateGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403927A5F9BE00368C90 /* CreateGroupView.swift */; };
5CCD403B27A5F9BE00368C90 /* CreateGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403927A5F9BE00368C90 /* CreateGroupView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -70,8 +82,6 @@
/* Begin PBXFileReference section */
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = "<group>"; };
5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a"; sourceTree = "<group>"; };
5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a"; sourceTree = "<group>"; };
5C1AEB7F279F4A6400247F08 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C1AEB80279F4A6400247F08 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C1AEB81279F4A6400247F08 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
@@ -80,12 +90,16 @@
5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = "<group>"; };
5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
5C2E261127A30FEA00F70299 /* TerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalView.swift; sourceTree = "<group>"; };
5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a"; sourceTree = "<group>"; };
5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a"; sourceTree = "<group>"; };
5C764E7B279C71D4000C6508 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/lib/libiconv.tbd; sourceTree = DEVELOPER_DIR; };
5C764E7C279C71DB000C6508 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; };
5C764E7D279C7275000C6508 /* SimpleX (iOS)-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleX (iOS)-Bridging-Header.h"; sourceTree = "<group>"; };
5C764E7E279C7275000C6508 /* SimpleX (macOS)-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleX (macOS)-Bridging-Header.h"; sourceTree = "<group>"; };
5C764E7F279C7276000C6508 /* dummy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = dummy.m; sourceTree = "<group>"; };
5C764E88279CBCB3000C6508 /* ChatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatModel.swift; sourceTree = "<group>"; };
5C9FD96A27A56D4D0075386C /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMessageView.swift; sourceTree = "<group>"; };
5CA059C3279559F40002BEB4 /* SimpleXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXApp.swift; sourceTree = "<group>"; };
5CA059C4279559F40002BEB4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
5CA059C5279559F40002BEB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -99,6 +113,10 @@
5CA059E9279559F40002BEB4 /* Tests_macOSLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_macOSLaunchTests.swift; sourceTree = "<group>"; };
5CA05A4B27974EB60002BEB4 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
5CA05A4E279752D00002BEB4 /* MessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageView.swift; sourceTree = "<group>"; };
5CCD403027A5F1C600368C90 /* ChatHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHeaderView.swift; sourceTree = "<group>"; };
5CCD403327A5F6DF00368C90 /* InviteContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteContactView.swift; sourceTree = "<group>"; };
5CCD403627A5F9A200368C90 /* ScanQRCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeView.swift; sourceTree = "<group>"; };
5CCD403927A5F9BE00368C90 /* CreateGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -107,11 +125,11 @@
buildActionMask = 2147483647;
files = (
5C764E83279C748B000C6508 /* libz.tbd in Frameworks */,
5C1AEB84279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */,
5C764E82279C748B000C6508 /* libiconv.tbd in Frameworks */,
5C1AEB86279F4A6400247F08 /* libffi.a in Frameworks */,
5C44B6A227A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */,
5C1AEB88279F4A6400247F08 /* libgmp.a in Frameworks */,
5C1AEB82279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */,
5C44B6A027A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */,
5C1AEB8A279F4A6400247F08 /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -121,11 +139,11 @@
buildActionMask = 2147483647;
files = (
5C764E85279C748C000C6508 /* libz.tbd in Frameworks */,
5C1AEB85279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */,
5C764E84279C748C000C6508 /* libiconv.tbd in Frameworks */,
5C1AEB87279F4A6400247F08 /* libffi.a in Frameworks */,
5C44B6A327A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */,
5C1AEB89279F4A6400247F08 /* libgmp.a in Frameworks */,
5C1AEB83279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */,
5C44B6A127A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */,
5C1AEB8B279F4A6400247F08 /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -150,9 +168,9 @@
5C2E260D27A30E2400F70299 /* Views */ = {
isa = PBXGroup;
children = (
5C5F4AC227A5E9AF00B51EF1 /* Helpers */,
5CA05A4B27974EB60002BEB4 /* WelcomeView.swift */,
5C2E260A27A30CFA00F70299 /* ChatListView.swift */,
5CA05A4E279752D00002BEB4 /* MessageView.swift */,
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */,
5C2E260E27A30FDC00F70299 /* ChatView.swift */,
5C2E261127A30FEA00F70299 /* TerminalView.swift */,
@@ -160,14 +178,27 @@
path = Views;
sourceTree = "<group>";
};
5C5F4AC227A5E9AF00B51EF1 /* Helpers */ = {
isa = PBXGroup;
children = (
5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */,
5CA05A4E279752D00002BEB4 /* MessageView.swift */,
5CCD403027A5F1C600368C90 /* ChatHeaderView.swift */,
5CCD403927A5F9BE00368C90 /* CreateGroupView.swift */,
5CCD403627A5F9A200368C90 /* ScanQRCodeView.swift */,
5CCD403327A5F6DF00368C90 /* InviteContactView.swift */,
);
path = Helpers;
sourceTree = "<group>";
};
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5C1AEB7F279F4A6400247F08 /* libffi.a */,
5C1AEB80279F4A6400247F08 /* libgmp.a */,
5C1AEB81279F4A6400247F08 /* libgmpxx.a */,
5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */,
5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */,
5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */,
5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -186,6 +217,7 @@
children = (
5C764E88279CBCB3000C6508 /* ChatModel.swift */,
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */,
5C9FD96A27A56D4D0075386C /* JSON.swift */,
);
path = Model;
sourceTree = "<group>";
@@ -419,12 +451,18 @@
5C764E80279C7276000C6508 /* dummy.m in Sources */,
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */,
5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */,
5C9FD96B27A56D4D0075386C /* JSON.swift in Sources */,
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */,
5CCD403127A5F1C600368C90 /* ChatHeaderView.swift in Sources */,
5CA05A4F279752D00002BEB4 /* MessageView.swift in Sources */,
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */,
5CCD403427A5F6DF00368C90 /* InviteContactView.swift in Sources */,
5CA05A4C27974EB60002BEB4 /* WelcomeView.swift in Sources */,
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */,
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */,
5CA059EB279559F40002BEB4 /* SimpleXApp.swift in Sources */,
5CCD403727A5F9A200368C90 /* ScanQRCodeView.swift in Sources */,
5CCD403A27A5F9BE00368C90 /* CreateGroupView.swift in Sources */,
5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */,
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */,
);
@@ -437,12 +475,18 @@
5C764E81279C7276000C6508 /* dummy.m in Sources */,
5C063D2827A4564100AEC577 /* ChatPreviewView.swift in Sources */,
5C2E261327A30FEA00F70299 /* TerminalView.swift in Sources */,
5C9FD96C27A56D4D0075386C /* JSON.swift in Sources */,
5C9FD96F27A5D6ED0075386C /* SendMessageView.swift in Sources */,
5CCD403227A5F1C600368C90 /* ChatHeaderView.swift in Sources */,
5CA05A50279752D00002BEB4 /* MessageView.swift in Sources */,
5CA059EE279559F40002BEB4 /* ContentView.swift in Sources */,
5CCD403527A5F6DF00368C90 /* InviteContactView.swift in Sources */,
5CA05A4D27974EB60002BEB4 /* WelcomeView.swift in Sources */,
5C2E261027A30FDC00F70299 /* ChatView.swift in Sources */,
5C2E260C27A30CFA00F70299 /* ChatListView.swift in Sources */,
5CA059EC279559F40002BEB4 /* SimpleXApp.swift in Sources */,
5CCD403827A5F9A200368C90 /* ScanQRCodeView.swift in Sources */,
5CCD403B27A5F9BE00368C90 /* CreateGroupView.swift in Sources */,
5C764E8A279CBCB3000C6508 /* ChatModel.swift in Sources */,
5C2E260827A2941F00F70299 /* SimpleXAPI.swift in Sources */,
);