swift API for chat, started chat UI (#228)
* started swift API for chat * skeleton UI * show all chat responses in Terminal view * show chat list in UI * refactor swift API
This commit is contained in:
parent
55dde3531e
commit
7c36ee7955
@ -46,62 +46,59 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
|
||||
var controller: controller
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
|
||||
init(controller: controller) {
|
||||
self.controller = controller
|
||||
}
|
||||
// var chatStore: chat_store
|
||||
// private let controller: chat_controller
|
||||
|
||||
// init(chatStore: chat_store) {
|
||||
// self.chatStore = chatStore
|
||||
// }
|
||||
|
||||
|
||||
@State private var logbuffer = [String]()
|
||||
@State private var chatcmd: String = ""
|
||||
@State private var chatlog: String = ""
|
||||
@FocusState private var focused: Bool
|
||||
|
||||
func addLine(line: String) {
|
||||
print(line)
|
||||
logbuffer.append(line)
|
||||
if(logbuffer.count > 50) { _ = logbuffer.dropFirst() }
|
||||
chatlog = logbuffer.joined(separator: "\n")
|
||||
}
|
||||
// @State private var logbuffer = [String]()
|
||||
// @State private var chatcmd: String = ""
|
||||
// @State private var chatlog: String = ""
|
||||
// @FocusState private var focused: Bool
|
||||
//
|
||||
// func addLine(line: String) {
|
||||
// print(line)
|
||||
// logbuffer.append(line)
|
||||
// if(logbuffer.count > 50) { _ = logbuffer.dropFirst() }
|
||||
// chatlog = logbuffer.joined(separator: "\n")
|
||||
// }
|
||||
|
||||
var body: some View {
|
||||
|
||||
DispatchQueue.global().async {
|
||||
while(true) {
|
||||
let msg = String.init(cString: chat_recv_msg(controller))
|
||||
|
||||
DispatchQueue.main.async {
|
||||
addLine(line: msg)
|
||||
}
|
||||
}
|
||||
if let user = chatModel.currentUser {
|
||||
ChatListView(user: user)
|
||||
.onAppear { chatSendCmd(chatModel, .apiGetChats) }
|
||||
} else {
|
||||
WelcomeView()
|
||||
}
|
||||
|
||||
return VStack {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading) {
|
||||
HStack { Spacer() }
|
||||
Text(chatlog)
|
||||
.lineLimit(nil)
|
||||
.font(.system(.body, design: .monospaced))
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
TextField("Chat command", text: $chatcmd)
|
||||
.focused($focused)
|
||||
.onSubmit {
|
||||
print(chatcmd)
|
||||
var cCmd = chatcmd.cString(using: .utf8)!
|
||||
print(String.init(cString: chat_send_cmd(controller, &cCmd)))
|
||||
}
|
||||
.textInputAutocapitalization(.never)
|
||||
.disableAutocorrection(true)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
// return VStack {
|
||||
// ScrollView {
|
||||
// VStack(alignment: .leading) {
|
||||
// HStack { Spacer() }
|
||||
// Text(chatlog)
|
||||
// .lineLimit(nil)
|
||||
// .font(.system(.body, design: .monospaced))
|
||||
// }
|
||||
// .frame(maxWidth: .infinity)
|
||||
// }
|
||||
//
|
||||
// TextField("Chat command", text: $chatcmd)
|
||||
// .focused($focused)
|
||||
// .onSubmit {
|
||||
// print(chatcmd)
|
||||
// var cCmd = chatcmd.cString(using: .utf8)!
|
||||
// print(String.init(cString: chat_send_cmd(controller, &cCmd)))
|
||||
// }
|
||||
// .textInputAutocapitalization(.never)
|
||||
// .disableAutocorrection(true)
|
||||
// .padding()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,11 +8,13 @@
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
final class ChatModel: ObservableObject {
|
||||
@Published var currentUser: User?
|
||||
@Published var channels: [ChatChannel] = []
|
||||
@Published var chats: Dictionary<String, Chat> = [:]
|
||||
@Published var chatPreviews: [ChatPreview] = []
|
||||
@Published var chatItems: [ChatItem] = []
|
||||
@Published var apiResponses: [APIResponse] = []
|
||||
}
|
||||
|
||||
struct User: Codable {
|
||||
@ -32,22 +34,76 @@ struct Profile: Codable {
|
||||
var fullName: String
|
||||
}
|
||||
|
||||
enum ChatChannel {
|
||||
case contact(ContactInfo, [ChatMessage])
|
||||
case group(GroupInfo, [ChatMessage])
|
||||
struct ChatPreview: Identifiable, Codable {
|
||||
var chatInfo: ChatInfo
|
||||
var lastChatItem: ChatItem?
|
||||
|
||||
var id: String {
|
||||
get { chatInfo.id }
|
||||
}
|
||||
}
|
||||
|
||||
struct ContactInfo: Codable {
|
||||
enum ChatInfo: Identifiable, Codable {
|
||||
case direct(contact: Contact)
|
||||
// case group()
|
||||
|
||||
var displayName: String {
|
||||
get {
|
||||
switch self {
|
||||
case let .direct(contact): return "@\(contact.localDisplayName)"
|
||||
// case let .group(groupInfo, _): return "#\(groupInfo.localDisplayName)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var id: String {
|
||||
get {
|
||||
switch self {
|
||||
case let .direct(contact): return "@\(contact.contactId)"
|
||||
// case let .group(contact): return group.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var apiType: String {
|
||||
get {
|
||||
switch self {
|
||||
case .direct(_): return "direct"
|
||||
// case let .group(_): return "group"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var apiId: Int64 {
|
||||
get {
|
||||
switch self {
|
||||
case let .direct(contact): return contact.contactId
|
||||
// case let .group(contact): return group.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Chat: Codable {
|
||||
var chatInfo: ChatInfo
|
||||
var chatItems: [ChatItem]
|
||||
}
|
||||
|
||||
struct Contact: Identifiable, Codable {
|
||||
var contactId: Int64
|
||||
var localDisplayName: ContactName
|
||||
var profile: Profile
|
||||
var viaGroup: Int64?
|
||||
|
||||
var id: String { get { "@\(contactId)" } }
|
||||
}
|
||||
|
||||
struct GroupInfo: Codable {
|
||||
struct GroupInfo: Identifiable, Codable {
|
||||
var groupId: Int64
|
||||
var localDisplayName: GroupName
|
||||
var groupProfile: GroupProfile
|
||||
|
||||
var id: String { get { "#\(groupId)" } }
|
||||
}
|
||||
|
||||
struct GroupProfile: Codable {
|
||||
@ -55,13 +111,76 @@ struct GroupProfile: Codable {
|
||||
var fullName: String
|
||||
}
|
||||
|
||||
struct ChatMessage {
|
||||
var from: ContactInfo?
|
||||
var ts: Date
|
||||
var content: MsgContent
|
||||
struct GroupMember: Codable {
|
||||
|
||||
}
|
||||
|
||||
enum MsgContent {
|
||||
case text(String)
|
||||
case unknown
|
||||
struct ChatItem: Identifiable, Codable {
|
||||
var chatDir: CIDirection
|
||||
var meta: CIMeta
|
||||
var content: CIContent
|
||||
|
||||
var id: Int64 { get { meta.itemId } }
|
||||
}
|
||||
|
||||
enum CIDirection: Codable {
|
||||
case directSnd
|
||||
case directRcv
|
||||
case groupSnd
|
||||
case groupRcv(GroupMember)
|
||||
}
|
||||
|
||||
struct CIMeta: Codable {
|
||||
var itemId: Int64
|
||||
var itemTs: Date
|
||||
var itemText: String
|
||||
var createdAt: Date
|
||||
}
|
||||
|
||||
enum CIContent: Codable {
|
||||
case sndMsgContent(msgContent: MsgContent)
|
||||
case rcvMsgContent(msgContent: MsgContent)
|
||||
// files etc.
|
||||
|
||||
var text: String {
|
||||
get {
|
||||
switch self {
|
||||
case let .sndMsgContent(mc): return mc.string
|
||||
case let .rcvMsgContent(mc): return mc.string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum MsgContent: Codable {
|
||||
case text(String)
|
||||
case unknown(type: String, text: String, json: String)
|
||||
case invalid(json: 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 .invalid: return "invalid"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//func parseMsgContent(_ mc: SomeMsgContent) -> MsgContent {
|
||||
// if let type = mc["type"] as? String {
|
||||
// let text_ = mc["text"] as? String
|
||||
// switch type {
|
||||
// case "text":
|
||||
// if let text = text_ { return .text(text) }
|
||||
// case let t:
|
||||
// return .unknown(type: t, text: text_ ?? "unknown item", json: prettyJSON(mc) ?? "error")
|
||||
// }
|
||||
// }
|
||||
// return .invalid(json: prettyJSON(mc) ?? "error")
|
||||
//}
|
||||
|
220
apps/ios/Shared/Model/SimpleXAPI.swift
Normal file
220
apps/ios/Shared/Model/SimpleXAPI.swift
Normal file
@ -0,0 +1,220 @@
|
||||
//
|
||||
// ChatAPI.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by Evgeny Poberezkin on 27/01/2022.
|
||||
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
private var chatStore: chat_store?
|
||||
private var chatController: chat_ctrl?
|
||||
private let jsonDecoder = JSONDecoder()
|
||||
private let jsonEncoder = JSONEncoder()
|
||||
|
||||
enum ChatCommand {
|
||||
case apiGetChats
|
||||
case apiGetChatItems(type: String, id: Int64)
|
||||
case string(String)
|
||||
case help
|
||||
|
||||
var cmdString: String {
|
||||
get {
|
||||
switch self {
|
||||
case .apiGetChats:
|
||||
return "/api/v1/chats"
|
||||
case let .apiGetChatItems(type, id):
|
||||
return "/api/v1/chat/items/\(type)/\(id)"
|
||||
case let .string(str):
|
||||
return str
|
||||
case .help: return "/help"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct APIResponse: Identifiable {
|
||||
var resp: ChatResponse
|
||||
var id: Int64
|
||||
}
|
||||
|
||||
struct APIResponseJSON: Decodable {
|
||||
var resp: ChatResponse
|
||||
}
|
||||
|
||||
enum ChatResponse: Codable {
|
||||
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)
|
||||
|
||||
var responseType: String {
|
||||
get {
|
||||
switch self {
|
||||
case let .response(type, _): return "* \(type)"
|
||||
case .apiChats(_): return "apiChats"
|
||||
case .apiDirectChat(_): return "apiDirectChat"
|
||||
case .contactConnected(_): return "contactConnected"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var details: String {
|
||||
get {
|
||||
switch self {
|
||||
case let .response(_, json): return json
|
||||
case let .apiChats(chats): return String(describing: chats)
|
||||
case let .apiDirectChat(chat): return String(describing: chat)
|
||||
case let .contactConnected(contact): return String(describing: contact)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func chatGetUser() -> User? {
|
||||
let store = getStore()
|
||||
print("chatGetUser")
|
||||
let r: UserResponse? = decodeCJSON(chat_get_user(store))
|
||||
let user = r?.user
|
||||
if user != nil { initChatCtrl(store) }
|
||||
print("user", user as Any)
|
||||
return user
|
||||
}
|
||||
|
||||
func chatCreateUser(_ p: Profile) -> User? {
|
||||
let store = getStore()
|
||||
print("chatCreateUser")
|
||||
var str = encodeCJSON(p)
|
||||
chat_create_user(store, &str)
|
||||
let user = chatGetUser()
|
||||
if user != nil { initChatCtrl(store) }
|
||||
print("user", user as Any)
|
||||
return user
|
||||
}
|
||||
|
||||
func chatSendCmd(_ chatModel: ChatModel, _ cmd: ChatCommand) {
|
||||
var c = cmd.cmdString.cString(using: .utf8)!
|
||||
processAPIResponse(chatModel,
|
||||
apiResponse(
|
||||
chat_send_cmd(getChatCtrl(), &c)!))
|
||||
}
|
||||
|
||||
func chatRecvMsg(_ chatModel: ChatModel) {
|
||||
processAPIResponse(chatModel,
|
||||
apiResponse(
|
||||
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
|
||||
|
||||
// case let .response(type, _):
|
||||
// chatModel.chatItems.append(ChatItem(
|
||||
// ts: Date.now,
|
||||
// content: .text(type)
|
||||
// ))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct UserResponse: Decodable {
|
||||
var user: User?
|
||||
var error: String?
|
||||
}
|
||||
|
||||
private var respId: Int64 = 0
|
||||
|
||||
private func apiResponse(_ cjson: UnsafePointer<CChar>) -> APIResponse? {
|
||||
let s = String.init(cString: cjson)
|
||||
print("apiResponse", s)
|
||||
let d = s.data(using: .utf8)!
|
||||
// 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)
|
||||
|
||||
do {
|
||||
let r = try jsonDecoder.decode(APIResponseJSON.self, from: d)
|
||||
return APIResponse(resp: r.resp, id: respId)
|
||||
} catch {
|
||||
print (error)
|
||||
}
|
||||
|
||||
var type: String?
|
||||
var json: String?
|
||||
if let j = try? JSONSerialization.jsonObject(with: d) as? NSDictionary {
|
||||
if let j1 = j["resp"] as? NSDictionary, j1.count == 1 {
|
||||
type = j1.allKeys[0] as? String
|
||||
}
|
||||
json = prettyJSON(j)
|
||||
}
|
||||
respId += 1
|
||||
return APIResponse(
|
||||
resp: ChatResponse.response(type: type ?? "invalid", json: json ?? s),
|
||||
id: respId
|
||||
)
|
||||
}
|
||||
|
||||
func prettyJSON(_ obj: NSDictionary) -> String? {
|
||||
if let d = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) {
|
||||
return String(decoding: d, as: UTF8.self)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func getStore() -> chat_store {
|
||||
if let store = chatStore { return store }
|
||||
let dataDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.path + "/mobile_v1"
|
||||
var cstr = dataDir.cString(using: .utf8)!
|
||||
chatStore = chat_init_store(&cstr)
|
||||
return chatStore!
|
||||
}
|
||||
|
||||
private func initChatCtrl(_ store: chat_store) {
|
||||
if chatController == nil {
|
||||
chatController = chat_start(store)
|
||||
}
|
||||
}
|
||||
|
||||
private func getChatCtrl() -> chat_ctrl {
|
||||
if let controller = chatController { return controller }
|
||||
fatalError("Chat controller was not started!")
|
||||
}
|
||||
|
||||
private func decodeCJSON<T: Decodable>(_ cjson: UnsafePointer<CChar>) -> T? {
|
||||
let s = String.init(cString: cjson)
|
||||
print("decodeCJSON", s)
|
||||
let d = s.data(using: .utf8)!
|
||||
// let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson))
|
||||
// let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free)
|
||||
return try? jsonDecoder.decode(T.self, from: d)
|
||||
}
|
||||
|
||||
private func getJSONObject(_ cjson: UnsafePointer<CChar>) -> NSDictionary? {
|
||||
let s = String.init(cString: cjson)
|
||||
let d = s.data(using: .utf8)!
|
||||
return try? JSONSerialization.jsonObject(with: d) as? NSDictionary
|
||||
}
|
||||
|
||||
private func encodeCJSON<T: Encodable>(_ value: T) -> [CChar] {
|
||||
let data = try! jsonEncoder.encode(value)
|
||||
let str = String(decoding: data, as: UTF8.self)
|
||||
print("encodeCJSON", str)
|
||||
return str.cString(using: .utf8)!
|
||||
}
|
54
apps/ios/Shared/MyPlayground.playground/Contents.swift
Normal file
54
apps/ios/Shared/MyPlayground.playground/Contents.swift
Normal file
@ -0,0 +1,54 @@
|
||||
import Foundation
|
||||
|
||||
var greeting = "Hello, playground"
|
||||
|
||||
let jsonEncoder = JSONEncoder()
|
||||
|
||||
let ct = Contact(
|
||||
contactId: 123,
|
||||
localDisplayName: "ep",
|
||||
profile: Profile(displayName: "ep", fullName: "")
|
||||
)
|
||||
|
||||
//let data = try! jsonEncoder.encode(ChatResponse.contactConnected(contact: ct))
|
||||
|
||||
//print(String(decoding: data, as: UTF8.self))
|
||||
|
||||
//var str = """
|
||||
//{"resp":{"apiChats":{"chats":
|
||||
//[{"chatItem":null,"chatInfo":{"direct":{"contact":{"contactId":2,"profile":
|
||||
//{"displayName":"simplex","fullName":""},"activeConn":
|
||||
//{"connLevel":0,"entityId":2,"connType":"contact","connId":1
|
||||
//,"agentConnId":"QTRteFhTR1dWQnpQZHE3NQ==","createdAt":"2022-01-27T19:43:44.015562Z","connStatus":"ready"},"localDisplayName":"simplex"}}}},
|
||||
//{"chatItem":null,"chatInfo":{"direct":{"contact":{"contactId":3,"profile":
|
||||
//{"displayName":"ep","fullName":"Evgeny"},"activeConn":
|
||||
//{"connLevel":0,"entityId":3,"connType":"contact","connId":2
|
||||
//,"agentConnId":"cTdFNkprSHhZZmZhdWFQVg==","createdAt":"2022-01-27T19:47:08.891646Z","connStatus":"ready"},"localDisplayName":"ep"}}}}]}}}
|
||||
//"""
|
||||
|
||||
//var str = """
|
||||
//[{"chatItem":null,"chatInfo":{"direct":{"contact":{"contactId":2,"profile":
|
||||
//{"displayName":"simplex","fullName":""},"activeConn":
|
||||
//{"connLevel":0,"entityId":2,"connType":"contact","connId":1
|
||||
//,"agentConnId":"QTRteFhTR1dWQnpQZHE3NQ==","createdAt":"2022-01-27T19:43:44.015562Z","connStatus":"ready"},"localDisplayName":"simplex"}}}},
|
||||
//{"chatItem":null,"chatInfo":{"direct":{"contact":{"contactId":3,"profile":
|
||||
//{"displayName":"ep","fullName":"Evgeny"},"activeConn":
|
||||
//{"connLevel":0,"entityId":3,"connType":"contact","connId":2
|
||||
//,"agentConnId":"cTdFNkprSHhZZmZhdWFQVg==","createdAt":"2022-01-27T19:47:08.891646Z","connStatus":"ready"},"localDisplayName":"ep"}}}}]
|
||||
//"""
|
||||
//
|
||||
//let data = str.data(using: .utf8)!
|
||||
|
||||
let jsonDecoder = JSONDecoder()
|
||||
|
||||
//let r: [ChatPreview] = try! jsonDecoder.decode([ChatPreview].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)!)
|
||||
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='ios' buildActiveScheme='true' importAppTypes='true'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
11
apps/ios/Shared/MyPlayground.playground/timeline.xctimeline
Normal file
11
apps/ios/Shared/MyPlayground.playground/timeline.xctimeline
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Timeline
|
||||
version = "3.0">
|
||||
<TimelineItems>
|
||||
<LoggerValueHistoryTimelineItem
|
||||
documentLocation = "file:///Users/evgeny/opensource/simplex-chat/simplex-chat/apps/ios/Shared/MyPlayground.playground#CharacterRangeLen=88&CharacterRangeLoc=2005&EndingColumnNumber=0&EndingLineNumber=53&StartingColumnNumber=1&StartingLineNumber=52&Timestamp=665139674.041539"
|
||||
selectedRepresentationIndex = "0"
|
||||
shouldTrackSuperviewWidth = "NO">
|
||||
</LoggerValueHistoryTimelineItem>
|
||||
</TimelineItems>
|
||||
</Timeline>
|
@ -2,14 +2,14 @@
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
extern void hs_init(int argc, char ** argv[]);
|
||||
extern void hs_init(int argc, char **argv[]);
|
||||
|
||||
typedef void* chat_store;
|
||||
typedef void* controller;
|
||||
typedef void* chat_ctrl;
|
||||
|
||||
extern chat_store chat_init_store(char * path);
|
||||
extern chat_store chat_init_store(char *path);
|
||||
extern char *chat_get_user(chat_store store);
|
||||
extern char *chat_create_user(chat_store store, char *data);
|
||||
extern controller chat_start(chat_store store);
|
||||
extern char *chat_send_cmd(controller ctl, char *cmd);
|
||||
extern char *chat_recv_msg(controller ctl);
|
||||
extern chat_ctrl chat_start(chat_store store);
|
||||
extern char *chat_send_cmd(chat_ctrl ctl, char *cmd);
|
||||
extern char *chat_recv_msg(chat_ctrl ctl);
|
||||
|
@ -5,11 +5,11 @@
|
||||
extern void hs_init(int argc, char ** argv[]);
|
||||
|
||||
typedef void* chat_store;
|
||||
typedef void* controller;
|
||||
typedef void* chat_ctrl;
|
||||
|
||||
extern chat_store chat_init_store(char * path);
|
||||
extern char *chat_get_user(chat_store store);
|
||||
extern char *chat_create_user(chat_store store, char *data);
|
||||
extern controller chat_start(chat_store store);
|
||||
extern char *chat_send_cmd(controller ctl, char *cmd);
|
||||
extern char *chat_recv_msg(controller ctl);
|
||||
extern chat_ctrl chat_start(chat_store store);
|
||||
extern char *chat_send_cmd(chat_ctrl ctl, char *cmd);
|
||||
extern char *chat_recv_msg(chat_ctrl ctl);
|
||||
|
@ -9,26 +9,33 @@ import SwiftUI
|
||||
|
||||
@main
|
||||
struct SimpleXApp: App {
|
||||
private let controller: controller
|
||||
@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)!
|
||||
let store = chat_init_store(&cstr)
|
||||
let user = String.init(cString: chat_get_user(store))
|
||||
print(user)
|
||||
if 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)))
|
||||
// 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 {
|
||||
WindowGroup {
|
||||
ContentView(controller: controller)
|
||||
ContentView()
|
||||
.environmentObject(chatModel)
|
||||
.onAppear() {
|
||||
chatModel.currentUser = chatGetUser()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
56
apps/ios/Shared/Views/ChatListView.swift
Normal file
56
apps/ios/Shared/Views/ChatListView.swift
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// ChatListView.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by Evgeny Poberezkin on 27/01/2022.
|
||||
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ChatListView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
var user: User
|
||||
|
||||
var body: some View {
|
||||
DispatchQueue.global().async {
|
||||
while(true) { chatRecvMsg(chatModel) }
|
||||
}
|
||||
|
||||
return VStack {
|
||||
// if chatModel.chats.isEmpty {
|
||||
VStack {
|
||||
Text("Hello chat")
|
||||
Text("Active user: \(user.localDisplayName) (\(user.profile.fullName))")
|
||||
}
|
||||
// }
|
||||
NavigationView {
|
||||
List {
|
||||
NavigationLink {
|
||||
TerminalView()
|
||||
} label: {
|
||||
Text("Terminal")
|
||||
}
|
||||
|
||||
ForEach(chatModel.chatPreviews) { chatPreview in
|
||||
NavigationLink {
|
||||
ChatView(chatInfo: chatPreview.chatInfo)
|
||||
.onAppear {
|
||||
chatSendCmd(chatModel, .apiGetChatItems(type: "direct", id: chatPreview.chatInfo.apiId))
|
||||
}
|
||||
} label: {
|
||||
ChatPreviewView(chatPreview: chatPreview)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct ChatListView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// ChatListView()
|
||||
// }
|
||||
//}
|
33
apps/ios/Shared/Views/ChatPreviewView.swift
Normal file
33
apps/ios/Shared/Views/ChatPreviewView.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// ChatPreviewView.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by Evgeny Poberezkin on 28/01/2022.
|
||||
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ChatPreviewView: View {
|
||||
var chatPreview: ChatPreview
|
||||
|
||||
var body: some View {
|
||||
Text(chatPreview.chatInfo.displayName)
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatPreviewView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ChatPreviewView(chatPreview: ChatPreview(
|
||||
chatInfo: .direct(contact: Contact(
|
||||
contactId: 123,
|
||||
localDisplayName: "ep",
|
||||
profile: Profile(
|
||||
displayName: "ep",
|
||||
fullName: "Ep"
|
||||
),
|
||||
viaGroup: nil
|
||||
))
|
||||
))
|
||||
}
|
||||
}
|
37
apps/ios/Shared/Views/ChatView.swift
Normal file
37
apps/ios/Shared/Views/ChatView.swift
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// ChatView.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by Evgeny Poberezkin on 27/01/2022.
|
||||
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ChatView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
var chatInfo: ChatInfo
|
||||
var body: some View {
|
||||
VStack {
|
||||
if let chat: Chat = chatModel.chats[chatInfo.id] {
|
||||
VStack {
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
ForEach(chat.chatItems) { chatItem in
|
||||
Text(chatItem.content.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Text("unexpected: chat not found...")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct ChatView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// ChatView()
|
||||
// }
|
||||
//}
|
73
apps/ios/Shared/Views/TerminalView.swift
Normal file
73
apps/ios/Shared/Views/TerminalView.swift
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// TerminalView.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by Evgeny Poberezkin on 27/01/2022.
|
||||
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
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
|
||||
NavigationLink {
|
||||
ScrollView {
|
||||
Text(r.resp.details)
|
||||
}
|
||||
} label: {
|
||||
Text(r.resp.responseType)
|
||||
.frame(width: 360, height: 30, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack {
|
||||
TextField("Message...", text: $command)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.frame(minHeight: 30)
|
||||
Button(action: sendMessage) {
|
||||
Text("Send")
|
||||
}.disabled(command.isEmpty)
|
||||
}
|
||||
.frame(minHeight: 30)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
func sendMessage() {
|
||||
DispatchQueue.global().async {
|
||||
let cmd: String = self.$command.wrappedValue
|
||||
inProgress = true
|
||||
command = ""
|
||||
chatSendCmd(chatModel, ChatCommand.string(cmd))
|
||||
inProgress = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
]
|
||||
return NavigationView {
|
||||
TerminalView()
|
||||
.environmentObject(chatModel)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
83
apps/ios/Shared/Views/UserView.swift
Normal file
83
apps/ios/Shared/Views/UserView.swift
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// UserView.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by Evgeny Poberezkin on 27/01/2022.
|
||||
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct UserView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
var user: User
|
||||
|
||||
// private let controller: chat_ctrl
|
||||
//
|
||||
// var chatStore: chat_store
|
||||
|
||||
// @State private var logbuffer = [String]()
|
||||
// @State private var chatcmd: String = ""
|
||||
// @State private var chatlog: String = ""
|
||||
// @FocusState private var focused: Bool
|
||||
|
||||
// func addLine(line: String) {
|
||||
// print(line)
|
||||
// logbuffer.append(line)
|
||||
// if(logbuffer.count > 50) { _ = logbuffer.dropFirst() }
|
||||
// chatlog = logbuffer.joined(separator: "\n")
|
||||
// }
|
||||
|
||||
var body: some View {
|
||||
if chatModel.userChats.isEmpty {
|
||||
VStack {
|
||||
Text("Hello chat")
|
||||
Text("Active user: \(user.localDisplayName) (\(user.profile.fullName))")
|
||||
}
|
||||
} else {
|
||||
ChatList()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// DispatchQueue.global().async {
|
||||
// while(true) {
|
||||
// let msg = String.init(cString: chat_recv_msg(controller))
|
||||
//
|
||||
// DispatchQueue.main.async {
|
||||
// addLine(line: msg)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return VStack {
|
||||
// ScrollView {
|
||||
// VStack(alignment: .leading) {
|
||||
// HStack { Spacer() }
|
||||
// Text(chatlog)
|
||||
// .lineLimit(nil)
|
||||
// .font(.system(.body, design: .monospaced))
|
||||
// }
|
||||
// .frame(maxWidth: .infinity)
|
||||
// }
|
||||
//
|
||||
// TextField("Chat command", text: $chatcmd)
|
||||
// .focused($focused)
|
||||
// .onSubmit {
|
||||
// print(chatcmd)
|
||||
// var cCmd = chatcmd.cString(using: .utf8)!
|
||||
//// print(String.init(cString: chat_send_cmd(controller, &cCmd)))
|
||||
// }
|
||||
// .textInputAutocapitalization(.never)
|
||||
// .disableAutocorrection(true)
|
||||
// .padding()
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//struct UserView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// UserView()
|
||||
// }
|
||||
//}
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// ProfileView.swift
|
||||
// WelcomeView.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by Evgeny Poberezkin on 18/01/2022.
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ProfileView: View {
|
||||
struct WelcomeView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@State var displayName: String = ""
|
||||
@State var fullName: String = ""
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Create profile")
|
||||
@ -20,13 +22,23 @@ struct ProfileView: View {
|
||||
TextField("Display name", text: $displayName)
|
||||
.padding(.bottom)
|
||||
TextField("Full name (optional)", text: $fullName)
|
||||
.padding(.bottom)
|
||||
Button("Create") {
|
||||
let profile = Profile(
|
||||
displayName: displayName,
|
||||
fullName: fullName
|
||||
)
|
||||
if let user = chatCreateUser(profile) {
|
||||
chatModel.currentUser = user
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
struct ProfileView_Previews: PreviewProvider {
|
||||
struct WelcomeView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ProfileView()
|
||||
WelcomeView()
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* 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 */; };
|
||||
@ -17,6 +19,14 @@
|
||||
5C1AEB89279F4A6400247F08 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB80279F4A6400247F08 /* libgmp.a */; };
|
||||
5C1AEB8A279F4A6400247F08 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB81279F4A6400247F08 /* libgmpxx.a */; };
|
||||
5C1AEB8B279F4A6400247F08 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB81279F4A6400247F08 /* libgmpxx.a */; };
|
||||
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
|
||||
5C2E260827A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
|
||||
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
|
||||
5C2E260C27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
|
||||
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
|
||||
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 */; };
|
||||
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,8 +45,8 @@
|
||||
5CA059EE279559F40002BEB4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059C4279559F40002BEB4 /* ContentView.swift */; };
|
||||
5CA059EF279559F40002BEB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5CA059C5279559F40002BEB4 /* Assets.xcassets */; };
|
||||
5CA059F0279559F40002BEB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5CA059C5279559F40002BEB4 /* Assets.xcassets */; };
|
||||
5CA05A4C27974EB60002BEB4 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA05A4B27974EB60002BEB4 /* ProfileView.swift */; };
|
||||
5CA05A4D27974EB60002BEB4 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA05A4B27974EB60002BEB4 /* ProfileView.swift */; };
|
||||
5CA05A4C27974EB60002BEB4 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA05A4B27974EB60002BEB4 /* WelcomeView.swift */; };
|
||||
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 */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -59,11 +69,17 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* 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>"; };
|
||||
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = "<group>"; };
|
||||
5C2E260927A2C63500F70299 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -81,7 +97,7 @@
|
||||
5CA059E3279559F40002BEB4 /* Tests macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5CA059E7279559F40002BEB4 /* Tests_macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_macOS.swift; sourceTree = "<group>"; };
|
||||
5CA059E9279559F40002BEB4 /* Tests_macOSLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_macOSLaunchTests.swift; sourceTree = "<group>"; };
|
||||
5CA05A4B27974EB60002BEB4 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -131,6 +147,19 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
5C2E260D27A30E2400F70299 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CA05A4B27974EB60002BEB4 /* WelcomeView.swift */,
|
||||
5C2E260A27A30CFA00F70299 /* ChatListView.swift */,
|
||||
5CA05A4E279752D00002BEB4 /* MessageView.swift */,
|
||||
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */,
|
||||
5C2E260E27A30FDC00F70299 /* ChatView.swift */,
|
||||
5C2E261127A30FEA00F70299 /* TerminalView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -156,6 +185,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C764E88279CBCB3000C6508 /* ChatModel.swift */,
|
||||
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@ -178,10 +208,10 @@
|
||||
children = (
|
||||
5C764E87279CBC8E000C6508 /* Model */,
|
||||
5CA059C3279559F40002BEB4 /* SimpleXApp.swift */,
|
||||
5C2E260927A2C63500F70299 /* MyPlayground.playground */,
|
||||
5C764E7F279C7276000C6508 /* dummy.m */,
|
||||
5CA059C4279559F40002BEB4 /* ContentView.swift */,
|
||||
5CA05A4B27974EB60002BEB4 /* ProfileView.swift */,
|
||||
5CA05A4E279752D00002BEB4 /* MessageView.swift */,
|
||||
5C2E260D27A30E2400F70299 /* Views */,
|
||||
5CA059C5279559F40002BEB4 /* Assets.xcassets */,
|
||||
5C764E7D279C7275000C6508 /* SimpleX (iOS)-Bridging-Header.h */,
|
||||
5C764E7E279C7275000C6508 /* SimpleX (macOS)-Bridging-Header.h */,
|
||||
@ -387,11 +417,16 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C764E80279C7276000C6508 /* dummy.m in Sources */,
|
||||
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */,
|
||||
5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */,
|
||||
5CA05A4F279752D00002BEB4 /* MessageView.swift in Sources */,
|
||||
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */,
|
||||
5CA05A4C27974EB60002BEB4 /* ProfileView.swift in Sources */,
|
||||
5CA05A4C27974EB60002BEB4 /* WelcomeView.swift in Sources */,
|
||||
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */,
|
||||
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */,
|
||||
5CA059EB279559F40002BEB4 /* SimpleXApp.swift in Sources */,
|
||||
5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */,
|
||||
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -400,11 +435,16 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C764E81279C7276000C6508 /* dummy.m in Sources */,
|
||||
5C063D2827A4564100AEC577 /* ChatPreviewView.swift in Sources */,
|
||||
5C2E261327A30FEA00F70299 /* TerminalView.swift in Sources */,
|
||||
5CA05A50279752D00002BEB4 /* MessageView.swift in Sources */,
|
||||
5CA059EE279559F40002BEB4 /* ContentView.swift in Sources */,
|
||||
5CA05A4D27974EB60002BEB4 /* ProfileView.swift in Sources */,
|
||||
5CA05A4D27974EB60002BEB4 /* WelcomeView.swift in Sources */,
|
||||
5C2E261027A30FDC00F70299 /* ChatView.swift in Sources */,
|
||||
5C2E260C27A30CFA00F70299 /* ChatListView.swift in Sources */,
|
||||
5CA059EC279559F40002BEB4 /* SimpleXApp.swift in Sources */,
|
||||
5C764E8A279CBCB3000C6508 /* ChatModel.swift in Sources */,
|
||||
5C2E260827A2941F00F70299 /* SimpleXAPI.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user