updated text items (#278)
* updated text items * update version * fix JSON parsing in CIDirection, refactor data samples * show group member in received messages and chat preview * use profile displayName instead of localDisplayName, do not show fullName if it is the same as displayName
This commit is contained in:
parent
855881094b
commit
b3a4c21c4b
@ -1,6 +1,15 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "0.533",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
@ -115,15 +115,15 @@ struct User: Decodable {
|
||||
// self.profile = profile
|
||||
// self.activeUser = activeUser
|
||||
// }
|
||||
}
|
||||
|
||||
let sampleUser = User(
|
||||
userId: 1,
|
||||
userContactId: 1,
|
||||
localDisplayName: "alice",
|
||||
profile: sampleProfile,
|
||||
activeUser: true
|
||||
)
|
||||
static let sampleData = User(
|
||||
userId: 1,
|
||||
userContactId: 1,
|
||||
localDisplayName: "alice",
|
||||
profile: Profile.sampleData,
|
||||
activeUser: true
|
||||
)
|
||||
}
|
||||
|
||||
typealias ContactName = String
|
||||
|
||||
@ -132,12 +132,12 @@ typealias GroupName = String
|
||||
struct Profile: Codable {
|
||||
var displayName: String
|
||||
var fullName: String
|
||||
}
|
||||
|
||||
let sampleProfile = Profile(
|
||||
displayName: "alice",
|
||||
fullName: "Alice"
|
||||
)
|
||||
static let sampleData = Profile(
|
||||
displayName: "alice",
|
||||
fullName: "Alice"
|
||||
)
|
||||
}
|
||||
|
||||
enum ChatType: String {
|
||||
case direct = "@"
|
||||
@ -160,6 +160,16 @@ enum ChatInfo: Identifiable, Decodable {
|
||||
}
|
||||
}
|
||||
|
||||
var displayName: String {
|
||||
get {
|
||||
switch self {
|
||||
case let .direct(contact): return contact.profile.displayName
|
||||
case let .group(groupInfo): return groupInfo.groupProfile.displayName
|
||||
case let .contactRequest(contactRequest): return contactRequest.profile.displayName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fullName: String {
|
||||
get {
|
||||
switch self {
|
||||
@ -171,7 +181,7 @@ enum ChatInfo: Identifiable, Decodable {
|
||||
}
|
||||
|
||||
var chatViewName: String {
|
||||
get { localDisplayName + (fullName == "" || fullName == localDisplayName ? "" : " / \(fullName)") }
|
||||
get { displayName + (fullName == "" || fullName == displayName ? "" : " / \(fullName)") }
|
||||
}
|
||||
|
||||
var id: String {
|
||||
@ -211,14 +221,20 @@ enum ChatInfo: Identifiable, Decodable {
|
||||
case let .contactRequest(contactRequest): return contactRequest.createdAt
|
||||
}
|
||||
}
|
||||
|
||||
struct SampleData {
|
||||
var direct: ChatInfo
|
||||
var group: ChatInfo
|
||||
var contactRequest: ChatInfo
|
||||
}
|
||||
|
||||
static var sampleData: ChatInfo.SampleData = SampleData(
|
||||
direct: ChatInfo.direct(contact: Contact.sampleData),
|
||||
group: ChatInfo.group(groupInfo: GroupInfo.sampleData),
|
||||
contactRequest: ChatInfo.contactRequest(contactRequest: UserContactRequest.sampleData)
|
||||
)
|
||||
}
|
||||
|
||||
let sampleDirectChatInfo = ChatInfo.direct(contact: sampleContact)
|
||||
|
||||
let sampleGroupChatInfo = ChatInfo.group(groupInfo: sampleGroupInfo)
|
||||
|
||||
let sampleContactRequestChatInfo = ChatInfo.contactRequest(contactRequest: sampleContactRequest)
|
||||
|
||||
final class Chat: ObservableObject, Identifiable {
|
||||
@Published var chatInfo: ChatInfo
|
||||
@Published var chatItems: [ChatItem]
|
||||
@ -297,21 +313,21 @@ struct Contact: Identifiable, Decodable {
|
||||
var id: String { get { "@\(contactId)" } }
|
||||
var apiId: Int64 { get { contactId } }
|
||||
var ready: Bool { get { activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready" } }
|
||||
}
|
||||
|
||||
let sampleContact = Contact(
|
||||
contactId: 1,
|
||||
localDisplayName: "alice",
|
||||
profile: sampleProfile,
|
||||
activeConn: sampleConnection,
|
||||
createdAt: .now
|
||||
)
|
||||
static let sampleData = Contact(
|
||||
contactId: 1,
|
||||
localDisplayName: "alice",
|
||||
profile: Profile.sampleData,
|
||||
activeConn: Connection.sampleData,
|
||||
createdAt: .now
|
||||
)
|
||||
}
|
||||
|
||||
struct Connection: Decodable {
|
||||
var connStatus: String
|
||||
}
|
||||
|
||||
let sampleConnection = Connection(connStatus: "ready")
|
||||
static let sampleData = Connection(connStatus: "ready")
|
||||
}
|
||||
|
||||
struct UserContactRequest: Decodable {
|
||||
var contactRequestId: Int64
|
||||
@ -322,14 +338,14 @@ struct UserContactRequest: Decodable {
|
||||
var id: String { get { "<@\(contactRequestId)" } }
|
||||
|
||||
var apiId: Int64 { get { contactRequestId } }
|
||||
}
|
||||
|
||||
let sampleContactRequest = UserContactRequest(
|
||||
contactRequestId: 1,
|
||||
localDisplayName: "alice",
|
||||
profile: sampleProfile,
|
||||
createdAt: .now
|
||||
)
|
||||
static let sampleData = UserContactRequest(
|
||||
contactRequestId: 1,
|
||||
localDisplayName: "alice",
|
||||
profile: Profile.sampleData,
|
||||
createdAt: .now
|
||||
)
|
||||
}
|
||||
|
||||
struct GroupInfo: Identifiable, Decodable {
|
||||
var groupId: Int64
|
||||
@ -340,27 +356,44 @@ struct GroupInfo: Identifiable, Decodable {
|
||||
var id: String { get { "#\(groupId)" } }
|
||||
|
||||
var apiId: Int64 { get { groupId } }
|
||||
}
|
||||
|
||||
let sampleGroupInfo = GroupInfo(
|
||||
groupId: 1,
|
||||
localDisplayName: "team",
|
||||
groupProfile: sampleGroupProfile,
|
||||
createdAt: .now
|
||||
)
|
||||
static let sampleData = GroupInfo(
|
||||
groupId: 1,
|
||||
localDisplayName: "team",
|
||||
groupProfile: GroupProfile.sampleData,
|
||||
createdAt: .now
|
||||
)
|
||||
}
|
||||
|
||||
struct GroupProfile: Codable {
|
||||
var displayName: String
|
||||
var fullName: String
|
||||
|
||||
static let sampleData = GroupProfile(
|
||||
displayName: "team",
|
||||
fullName: "My Team"
|
||||
)
|
||||
}
|
||||
|
||||
let sampleGroupProfile = GroupProfile(
|
||||
displayName: "team",
|
||||
fullName: "My Team"
|
||||
)
|
||||
|
||||
struct GroupMember: Decodable {
|
||||
var groupMemberId: Int64
|
||||
var memberId: String
|
||||
// var memberRole: GroupMemberRole
|
||||
// var memberCategory: GroupMemberCategory
|
||||
// var memberStatus: GroupMemberStatus
|
||||
// var invitedBy: InvitedBy
|
||||
var localDisplayName: ContactName
|
||||
var memberProfile: Profile
|
||||
var memberContactId: Int64?
|
||||
// var activeConn: Connection?
|
||||
|
||||
static let sampleData = GroupMember(
|
||||
groupMemberId: 1,
|
||||
memberId: "abcd",
|
||||
localDisplayName: "alice",
|
||||
memberProfile: Profile.sampleData,
|
||||
memberContactId: 1
|
||||
)
|
||||
}
|
||||
|
||||
struct AChatItem: Decodable {
|
||||
@ -374,21 +407,21 @@ struct ChatItem: Identifiable, Decodable {
|
||||
var content: CIContent
|
||||
|
||||
var id: Int64 { get { meta.itemId } }
|
||||
}
|
||||
|
||||
func chatItemSample(_ id: Int64, _ dir: CIDirection, _ ts: Date, _ text: String) -> ChatItem {
|
||||
ChatItem(
|
||||
chatDir: dir,
|
||||
meta: ciMetaSample(id, ts, text),
|
||||
content: .sndMsgContent(msgContent: .text(text))
|
||||
)
|
||||
static func getSample (_ id: Int64, _ dir: CIDirection, _ ts: Date, _ text: String) -> ChatItem {
|
||||
ChatItem(
|
||||
chatDir: dir,
|
||||
meta: CIMeta.getSample(id, ts, text),
|
||||
content: .sndMsgContent(msgContent: .text(text))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum CIDirection: Decodable {
|
||||
case directSnd
|
||||
case directRcv
|
||||
case groupSnd
|
||||
case groupRcv(GroupMember)
|
||||
case groupRcv(groupMember: GroupMember)
|
||||
|
||||
var sent: Bool {
|
||||
get {
|
||||
@ -407,6 +440,15 @@ struct CIMeta: Decodable {
|
||||
var itemTs: Date
|
||||
var itemText: String
|
||||
var createdAt: Date
|
||||
|
||||
static func getSample(_ id: Int64, _ ts: Date, _ text: String) -> CIMeta {
|
||||
CIMeta(
|
||||
itemId: id,
|
||||
itemTs: ts,
|
||||
itemText: text,
|
||||
createdAt: ts
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum CIStatus: Decodable {
|
||||
@ -418,15 +460,6 @@ enum CIStatus: Decodable {
|
||||
case rcvRead
|
||||
}
|
||||
|
||||
func ciMetaSample(_ id: Int64, _ ts: Date, _ text: String) -> CIMeta {
|
||||
CIMeta(
|
||||
itemId: id,
|
||||
itemTs: ts,
|
||||
itemText: text,
|
||||
createdAt: ts
|
||||
)
|
||||
}
|
||||
|
||||
enum CIContent: Decodable {
|
||||
case sndMsgContent(msgContent: MsgContent)
|
||||
case rcvMsgContent(msgContent: MsgContent)
|
||||
|
@ -90,10 +90,8 @@ struct ChatInfoView: View {
|
||||
}
|
||||
|
||||
struct ChatInfoView_Previews: PreviewProvider {
|
||||
var chatInfo = sampleDirectChatInfo
|
||||
|
||||
static var previews: some View {
|
||||
@State var showChatInfo = true
|
||||
return ChatInfoView(chat: Chat(chatInfo: sampleDirectChatInfo, chatItems: []), showChatInfo: $showChatInfo)
|
||||
return ChatInfoView(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []), showChatInfo: $showChatInfo)
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ struct EmojiItemView: View {
|
||||
struct EmojiItemView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group{
|
||||
EmojiItemView(chatItem: chatItemSample(1, .directSnd, .now, "🙂"))
|
||||
EmojiItemView(chatItem: chatItemSample(2, .directRcv, .now, "👍"))
|
||||
EmojiItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂"))
|
||||
EmojiItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "👍"))
|
||||
}
|
||||
.previewLayout(.fixed(width: 360, height: 70))
|
||||
}
|
||||
|
@ -12,54 +12,73 @@ private let emailRegex = try! NSRegularExpression(pattern: "^[a-z0-9.!#$%&'*+/=?
|
||||
|
||||
private let phoneRegex = try! NSRegularExpression(pattern: "^\\+?[0-9\\.\\(\\)\\-]{7,20}$")
|
||||
|
||||
private let sentColorLigth = Color(.sRGB, red: 0.27, green: 0.72, blue: 1, opacity: 0.12)
|
||||
private let sentColorDark = Color(.sRGB, red: 0.27, green: 0.72, blue: 1, opacity: 0.17)
|
||||
private let linkColor = UIColor(red: 0, green: 0.533, blue: 1, alpha: 1)
|
||||
|
||||
struct TextItemView: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
var chatItem: ChatItem
|
||||
var width: CGFloat
|
||||
private let codeFont = Font.custom("Courier", size: UIFont.preferredFont(forTextStyle: .body).pointSize)
|
||||
|
||||
var body: some View {
|
||||
let sent = chatItem.chatDir.sent
|
||||
let minWidth = min(200, width)
|
||||
let maxWidth = min(300, width * 0.78)
|
||||
// let minWidth = min(200, width)
|
||||
let maxWidth = width * 0.78
|
||||
let meta = getDateFormatter().string(from: chatItem.meta.itemTs)
|
||||
|
||||
return ZStack(alignment: .bottomTrailing) {
|
||||
(messageText(chatItem.content.text, sent: sent) + reserveSpaceForMeta(meta))
|
||||
(messageText(chatItem) + reserveSpaceForMeta(meta))
|
||||
.padding(.top, 6)
|
||||
.padding(.bottom, 7)
|
||||
.padding(.horizontal, 12)
|
||||
.frame(minWidth: minWidth, maxWidth: maxWidth, alignment: .leading)
|
||||
.foregroundColor(sent ? .white : .primary)
|
||||
.frame(minWidth: 0, alignment: .leading)
|
||||
// .foregroundColor(sent ? .white : .primary)
|
||||
.textSelection(.enabled)
|
||||
|
||||
Text(meta)
|
||||
.font(.caption)
|
||||
.foregroundColor(sent ? Color(uiColor: .secondarySystemBackground) : .secondary)
|
||||
.foregroundColor(.secondary)
|
||||
// .foregroundColor(sent ? Color(uiColor: .secondarySystemBackground) : .secondary)
|
||||
.padding(.bottom, 4)
|
||||
.padding(.horizontal, 12)
|
||||
.frame(minWidth: minWidth, maxWidth: maxWidth, alignment: .bottomTrailing)
|
||||
}
|
||||
.background(sent ? .blue : Color(uiColor: .tertiarySystemGroupedBackground))
|
||||
// .background(sent ? .blue : Color(uiColor: .tertiarySystemGroupedBackground))
|
||||
.background(
|
||||
sent
|
||||
? (colorScheme == .light ? sentColorLigth : sentColorDark)
|
||||
: Color(uiColor: .tertiarySystemGroupedBackground)
|
||||
)
|
||||
.cornerRadius(18)
|
||||
.padding(.horizontal)
|
||||
.frame(
|
||||
minWidth: 200,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 0,
|
||||
maxWidth: maxWidth,
|
||||
maxHeight: .infinity,
|
||||
alignment: sent ? .trailing : .leading
|
||||
)
|
||||
}
|
||||
|
||||
private func messageText(_ s: String, sent: Bool) -> Text {
|
||||
if s == "" { return Text("") }
|
||||
let parts = s.split(separator: " ")
|
||||
var res = wordToText(parts[0], sent)
|
||||
var i = 1
|
||||
while i < parts.count {
|
||||
res = res + Text(" ") + wordToText(parts[i], sent)
|
||||
i = i + 1
|
||||
private func messageText(_ chatItem: ChatItem) -> Text {
|
||||
let s = chatItem.content.text
|
||||
var res: Text
|
||||
if s == "" {
|
||||
res = Text("")
|
||||
} else {
|
||||
let parts = s.split(separator: " ")
|
||||
res = wordToText(parts[0])
|
||||
var i = 1
|
||||
while i < parts.count {
|
||||
res = res + Text(" ") + wordToText(parts[i])
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
if case let .groupRcv(groupMember) = chatItem.chatDir {
|
||||
let member = Text(groupMember.memberProfile.displayName).font(.headline)
|
||||
return member + Text(": ") + res
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
private func reserveSpaceForMeta(_ meta: String) -> Text {
|
||||
@ -69,15 +88,15 @@ struct TextItemView: View {
|
||||
])))
|
||||
}
|
||||
|
||||
private func wordToText(_ s: String.SubSequence, _ sent: Bool) -> Text {
|
||||
private func wordToText(_ s: String.SubSequence) -> Text {
|
||||
let str = String(s)
|
||||
switch true {
|
||||
case s.starts(with: "http://") || s.starts(with: "https://"):
|
||||
return linkText(str, prefix: "", sent: sent)
|
||||
return linkText(str, prefix: "")
|
||||
case match(str, emailRegex):
|
||||
return linkText(str, prefix: "mailto:", sent: sent)
|
||||
return linkText(str, prefix: "mailto:")
|
||||
case match(str, phoneRegex):
|
||||
return linkText(str, prefix: "tel:", sent: sent)
|
||||
return linkText(str, prefix: "tel:")
|
||||
default:
|
||||
if (s.count > 1) {
|
||||
switch true {
|
||||
@ -97,10 +116,10 @@ struct TextItemView: View {
|
||||
regex.firstMatch(in: s, options: [], range: NSRange(location: 0, length: s.count)) != nil
|
||||
}
|
||||
|
||||
private func linkText(_ s: String, prefix: String, sent: Bool) -> Text {
|
||||
private func linkText(_ s: String, prefix: String) -> Text {
|
||||
Text(AttributedString(s, attributes: AttributeContainer([
|
||||
.link: NSURL(string: prefix + s) as Any,
|
||||
.foregroundColor: (sent ? UIColor.white : nil) as Any
|
||||
.foregroundColor: linkColor as Any
|
||||
]))).underline()
|
||||
}
|
||||
|
||||
@ -112,12 +131,13 @@ struct TextItemView: View {
|
||||
struct TextItemView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group{
|
||||
TextItemView(chatItem: chatItemSample(1, .directSnd, .now, "hello"), width: 360)
|
||||
TextItemView(chatItem: chatItemSample(2, .directSnd, .now, "https://simplex.chat"), width: 360)
|
||||
TextItemView(chatItem: chatItemSample(2, .directRcv, .now, "hello there too!!! this covers -"), width: 360)
|
||||
TextItemView(chatItem: chatItemSample(2, .directRcv, .now, "hello there too!!! this text has the time on the same line "), width: 360)
|
||||
TextItemView(chatItem: chatItemSample(2, .directRcv, .now, "https://simplex.chat"), width: 360)
|
||||
TextItemView(chatItem: chatItemSample(2, .directRcv, .now, "chaT@simplex.chat"), width: 360)
|
||||
TextItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "hello"), width: 360)
|
||||
TextItemView(chatItem: ChatItem.getSample(1, .groupRcv(groupMember: GroupMember.sampleData), .now, "hello"), width: 360)
|
||||
TextItemView(chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat"), width: 360)
|
||||
TextItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "hello there too!!! this covers -"), width: 360)
|
||||
TextItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "hello there too!!! this text has the time on the same line "), width: 360)
|
||||
TextItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "https://simplex.chat"), width: 360)
|
||||
TextItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "chaT@simplex.chat"), width: 360)
|
||||
}
|
||||
.previewLayout(.fixed(width: 360, height: 70))
|
||||
}
|
||||
|
@ -34,11 +34,11 @@ func getDateFormatter() -> DateFormatter {
|
||||
struct ChatItemView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group{
|
||||
ChatItemView(chatItem: chatItemSample(1, .directSnd, .now, "hello"), width: 360)
|
||||
ChatItemView(chatItem: chatItemSample(2, .directRcv, .now, "hello there too"), width: 360)
|
||||
ChatItemView(chatItem: chatItemSample(1, .directSnd, .now, "🙂"), width: 360)
|
||||
ChatItemView(chatItem: chatItemSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂"), width: 360)
|
||||
ChatItemView(chatItem: chatItemSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂🙂"), width: 360)
|
||||
ChatItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "hello"), width: 360)
|
||||
ChatItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "hello there too"), width: 360)
|
||||
ChatItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂"), width: 360)
|
||||
ChatItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂"), width: 360)
|
||||
ChatItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂🙂"), width: 360)
|
||||
}
|
||||
.previewLayout(.fixed(width: 360, height: 70))
|
||||
}
|
||||
|
@ -8,20 +8,27 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
private let chatImageColorLight = Color(red: 0.9, green: 0.9, blue: 0.9)
|
||||
private let chatImageColorDark = Color(red: 0.2, green: 0.2, blue: 0.2 )
|
||||
|
||||
struct ChatView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@ObservedObject var chat: Chat
|
||||
@State private var inProgress: Bool = false
|
||||
@State private var showChatInfo = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
let cInfo = chat.chatInfo
|
||||
|
||||
return VStack {
|
||||
GeometryReader { g in
|
||||
ScrollViewReader { proxy in
|
||||
ScrollView {
|
||||
VStack(spacing: 5) {
|
||||
ForEach(chatModel.chatItems, id: \.id) {
|
||||
ChatItemView(chatItem: $0, width: g.size.width)
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: $0.chatDir.sent ? .trailing : .leading)
|
||||
}
|
||||
.onAppear { scrollToBottom(proxy) }
|
||||
.onChange(of: chatModel.chatItems.count) { _ in scrollToBottom(proxy) }
|
||||
@ -37,7 +44,7 @@ struct ChatView: View {
|
||||
|
||||
SendMessageView(sendMessage: sendMessage, inProgress: inProgress)
|
||||
}
|
||||
.navigationTitle(chat.chatInfo.chatViewName)
|
||||
.navigationTitle(cInfo.chatViewName)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
@ -53,12 +60,19 @@ struct ChatView: View {
|
||||
showChatInfo = true
|
||||
} label: {
|
||||
HStack {
|
||||
ChatInfoImage(chat: chat)
|
||||
.frame(width: 32, height: 32)
|
||||
.padding(.trailing, 4)
|
||||
ChatInfoImage(
|
||||
chat: chat,
|
||||
color: colorScheme == .dark
|
||||
? chatImageColorDark
|
||||
: chatImageColorLight
|
||||
)
|
||||
.frame(width: 32, height: 32)
|
||||
.padding(.trailing, 4)
|
||||
VStack {
|
||||
Text(chat.chatInfo.localDisplayName).font(.headline)
|
||||
Text(chat.chatInfo.fullName).font(.subheadline)
|
||||
Text(cInfo.displayName).font(.headline)
|
||||
if cInfo.fullName != "" && cInfo.displayName != cInfo.fullName {
|
||||
Text(cInfo.fullName).font(.subheadline)
|
||||
}
|
||||
}
|
||||
}
|
||||
.foregroundColor(.primary)
|
||||
@ -94,16 +108,16 @@ struct ChatView_Previews: PreviewProvider {
|
||||
let chatModel = ChatModel()
|
||||
chatModel.chatId = "@1"
|
||||
chatModel.chatItems = [
|
||||
chatItemSample(1, .directSnd, .now, "hello"),
|
||||
chatItemSample(2, .directRcv, .now, "hi"),
|
||||
chatItemSample(3, .directRcv, .now, "hi there"),
|
||||
chatItemSample(4, .directRcv, .now, "hello again"),
|
||||
chatItemSample(5, .directSnd, .now, "hi there!!!"),
|
||||
chatItemSample(6, .directSnd, .now, "how are you?"),
|
||||
chatItemSample(7, .directSnd, .now, "👍👍👍👍"),
|
||||
chatItemSample(8, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
||||
ChatItem.getSample(1, .directSnd, .now, "hello"),
|
||||
ChatItem.getSample(2, .directRcv, .now, "hi"),
|
||||
ChatItem.getSample(3, .directRcv, .now, "hi there"),
|
||||
ChatItem.getSample(4, .directRcv, .now, "hello again"),
|
||||
ChatItem.getSample(5, .directSnd, .now, "hi there!!!"),
|
||||
ChatItem.getSample(6, .directSnd, .now, "how are you?"),
|
||||
ChatItem.getSample(7, .directSnd, .now, "👍👍👍👍"),
|
||||
ChatItem.getSample(8, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
||||
]
|
||||
return ChatView(chat: Chat(chatInfo: sampleDirectChatInfo, chatItems: []))
|
||||
return ChatView(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []))
|
||||
.environmentObject(chatModel)
|
||||
}
|
||||
}
|
||||
|
@ -175,15 +175,15 @@ struct ChatListNavLink_Previews: PreviewProvider {
|
||||
@State var chatId: String? = "@1"
|
||||
return Group {
|
||||
ChatListNavLink(chat: Chat(
|
||||
chatInfo: sampleDirectChatInfo,
|
||||
chatItems: [chatItemSample(1, .directSnd, .now, "hello")]
|
||||
chatInfo: ChatInfo.sampleData.direct,
|
||||
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello")]
|
||||
))
|
||||
ChatListNavLink(chat: Chat(
|
||||
chatInfo: sampleDirectChatInfo,
|
||||
chatItems: [chatItemSample(1, .directSnd, .now, "hello")]
|
||||
chatInfo: ChatInfo.sampleData.direct,
|
||||
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello")]
|
||||
))
|
||||
ChatListNavLink(chat: Chat(
|
||||
chatInfo: sampleContactRequestChatInfo,
|
||||
chatInfo: ChatInfo.sampleData.contactRequest,
|
||||
chatItems: []
|
||||
))
|
||||
}
|
||||
|
@ -91,20 +91,20 @@ struct ChatListView_Previews: PreviewProvider {
|
||||
let chatModel = ChatModel()
|
||||
chatModel.chats = [
|
||||
Chat(
|
||||
chatInfo: sampleDirectChatInfo,
|
||||
chatItems: [chatItemSample(1, .directSnd, .now, "hello")]
|
||||
chatInfo: ChatInfo.sampleData.direct,
|
||||
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello")]
|
||||
),
|
||||
Chat(
|
||||
chatInfo: sampleGroupChatInfo,
|
||||
chatItems: [chatItemSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")]
|
||||
chatInfo: ChatInfo.sampleData.group,
|
||||
chatItems: [ChatItem.getSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")]
|
||||
),
|
||||
Chat(
|
||||
chatInfo: sampleContactRequestChatInfo,
|
||||
chatInfo: ChatInfo.sampleData.contactRequest,
|
||||
chatItems: []
|
||||
)
|
||||
|
||||
]
|
||||
return ChatListView(user: sampleUser)
|
||||
return ChatListView(user: User.sampleData)
|
||||
.environmentObject(chatModel)
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ struct ChatPreviewView: View {
|
||||
.padding(.horizontal, 8)
|
||||
|
||||
if let cItem = cItem {
|
||||
Text(cItem.content.text)
|
||||
Text(chatItemText(cItem))
|
||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .topLeading)
|
||||
.padding([.leading, .trailing], 8)
|
||||
.padding(.bottom, 4)
|
||||
@ -60,22 +60,30 @@ struct ChatPreviewView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func chatItemText(_ cItem: ChatItem) -> String {
|
||||
let t = cItem.content.text
|
||||
if case let .groupRcv(groupMember) = cItem.chatDir {
|
||||
return groupMember.memberProfile.displayName + ": " + t
|
||||
}
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatPreviewView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group{
|
||||
ChatPreviewView(chat: Chat(
|
||||
chatInfo: sampleDirectChatInfo,
|
||||
chatInfo: ChatInfo.sampleData.direct,
|
||||
chatItems: []
|
||||
))
|
||||
ChatPreviewView(chat: Chat(
|
||||
chatInfo: sampleDirectChatInfo,
|
||||
chatItems: [chatItemSample(1, .directSnd, .now, "hello")]
|
||||
chatInfo: ChatInfo.sampleData.direct,
|
||||
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello")]
|
||||
))
|
||||
ChatPreviewView(chat: Chat(
|
||||
chatInfo: sampleGroupChatInfo,
|
||||
chatItems: [chatItemSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")]
|
||||
chatInfo: ChatInfo.sampleData.group,
|
||||
chatItems: [ChatItem.getSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")]
|
||||
))
|
||||
}
|
||||
.previewLayout(.fixed(width: 360, height: 78))
|
||||
|
@ -47,7 +47,7 @@ struct ContactRequestView: View {
|
||||
|
||||
struct ContactRequestView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContactRequestView(contactRequest: sampleContactRequest)
|
||||
ContactRequestView(contactRequest: UserContactRequest.sampleData)
|
||||
.previewLayout(.fixed(width: 360, height: 80))
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import SwiftUI
|
||||
|
||||
struct ChatInfoImage: View {
|
||||
@ObservedObject var chat: Chat
|
||||
var color = Color(uiColor: .tertiarySystemGroupedBackground)
|
||||
|
||||
var body: some View {
|
||||
var iconName: String
|
||||
@ -21,13 +22,16 @@ struct ChatInfoImage: View {
|
||||
|
||||
return Image(systemName: iconName)
|
||||
.resizable()
|
||||
.foregroundColor(Color(uiColor: .secondarySystemBackground))
|
||||
.foregroundColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatInfoImage_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ChatInfoImage(chat: Chat(chatInfo: sampleDirectChatInfo, chatItems: []))
|
||||
.previewLayout(.fixed(width: 63, height: 63))
|
||||
ChatInfoImage(
|
||||
chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: [])
|
||||
, color: Color(red: 0.9, green: 0.9, blue: 0.9)
|
||||
)
|
||||
.previewLayout(.fixed(width: 63, height: 63))
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ struct SettingsView: View {
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let chatModel = ChatModel()
|
||||
chatModel.currentUser = sampleUser
|
||||
chatModel.currentUser = User.sampleData
|
||||
return SettingsView()
|
||||
.environmentObject(chatModel)
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ struct UserProfile: View {
|
||||
struct UserProfile_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let chatModel = ChatModel()
|
||||
chatModel.currentUser = sampleUser
|
||||
chatModel.currentUser = User.sampleData
|
||||
return UserProfile()
|
||||
.environmentObject(chatModel)
|
||||
}
|
||||
|
@ -2,6 +2,10 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>chat.simplex.app.receive</string>
|
||||
</array>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
@ -15,5 +19,9 @@
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -763,7 +763,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@ -783,7 +783,7 @@
|
||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Libraries";
|
||||
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = "$(PROJECT_DIR)/Libraries/ios";
|
||||
"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(PROJECT_DIR)/Libraries/sim";
|
||||
MARKETING_VERSION = 0.2.1;
|
||||
MARKETING_VERSION = 0.2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
SDKROOT = iphoneos;
|
||||
@ -803,7 +803,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@ -823,7 +823,7 @@
|
||||
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Libraries";
|
||||
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = "$(PROJECT_DIR)/Libraries/ios";
|
||||
"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(PROJECT_DIR)/Libraries/sim";
|
||||
MARKETING_VERSION = 0.2.1;
|
||||
MARKETING_VERSION = 0.2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
SDKROOT = iphoneos;
|
||||
|
Loading…
Reference in New Issue
Block a user