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:
committed by
GitHub
parent
7e2f365c1c
commit
cb602dd377
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
38
apps/ios/Shared/Model/JSON.swift
Normal file
38
apps/ios/Shared/Model/JSON.swift
Normal 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
|
||||
}
|
||||
@@ -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? {
|
||||
|
||||
@@ -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)!)
|
||||
|
||||
|
||||
@@ -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&CharacterRangeLoc=2005&EndingColumnNumber=0&EndingLineNumber=53&StartingColumnNumber=1&StartingLineNumber=52&Timestamp=665139674.041539"
|
||||
documentLocation = "file:///Users/evgeny/opensource/simplex-chat/simplex-chat/apps/ios/Shared/MyPlayground.playground#CharacterRangeLen=88&CharacterRangeLoc=3634&EndingColumnNumber=0&EndingLineNumber=80&StartingColumnNumber=3&StartingLineNumber=79&Timestamp=665153525.657431"
|
||||
selectedRepresentationIndex = "0"
|
||||
shouldTrackSuperviewWidth = "NO">
|
||||
</LoggerValueHistoryTimelineItem>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
43
apps/ios/Shared/Views/Helpers/ChatHeaderView.swift
Normal file
43
apps/ios/Shared/Views/Helpers/ChatHeaderView.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
21
apps/ios/Shared/Views/Helpers/CreateGroupView.swift
Normal file
21
apps/ios/Shared/Views/Helpers/CreateGroupView.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
21
apps/ios/Shared/Views/Helpers/InviteContactView.swift
Normal file
21
apps/ios/Shared/Views/Helpers/InviteContactView.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
21
apps/ios/Shared/Views/Helpers/ScanQRCodeView.swift
Normal file
21
apps/ios/Shared/Views/Helpers/ScanQRCodeView.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
47
apps/ios/Shared/Views/Helpers/SendMessageView.swift
Normal file
47
apps/ios/Shared/Views/Helpers/SendMessageView.swift
Normal 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) })
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 */,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user