From 3a077d927d1a108de2a351419529793e4e64ecc4 Mon Sep 17 00:00:00 2001
From: JRoberts <8711996+jr-simplex@users.noreply.github.com>
Date: Thu, 25 Aug 2022 17:36:26 +0400
Subject: [PATCH] ios: contact aliases (#970)
* ios: contact aliases
* wip
* wip
* wip
* move onTapGesture
* revert test
* improve search
* corrections
* font size
* remove parameter
* clear button
* button style
* remove clear button
* ternary
* refactor search
* rename
* ios: contact aliases translations (#972)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
---
apps/ios/Shared/Model/SimpleXAPI.swift | 10 +++-
apps/ios/Shared/Views/Chat/ChatInfoView.swift | 48 +++++++++++++++--
apps/ios/Shared/Views/Chat/ChatView.swift | 4 +-
.../Views/Chat/Group/GroupChatInfoView.swift | 6 +--
.../Chat/Group/GroupMemberInfoView.swift | 4 +-
.../Shared/Views/ChatList/ChatListView.swift | 13 +++--
.../Views/UserSettings/UserProfile.swift | 2 +-
.../en.xcloc/Localized Contents/en.xliff | 5 ++
.../ru.xcloc/Localized Contents/ru.xliff | 7 ++-
apps/ios/SimpleXChat/APITypes.swift | 10 +++-
apps/ios/SimpleXChat/ChatTypes.swift | 53 +++++++++++++++----
apps/ios/ru.lproj/Localizable.strings | 5 +-
12 files changed, 137 insertions(+), 30 deletions(-)
diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift
index 6651b577b2..ea5df407da 100644
--- a/apps/ios/Shared/Model/SimpleXAPI.swift
+++ b/apps/ios/Shared/Model/SimpleXAPI.swift
@@ -324,9 +324,9 @@ func apiContactInfo(contactId: Int64) async throws -> (ConnectionStats?, Profile
throw r
}
-func apiGroupMemberInfo(_ groupId: Int64, _ groupMemberId: Int64) async throws -> (ConnectionStats?, Profile?) {
+func apiGroupMemberInfo(_ groupId: Int64, _ groupMemberId: Int64) async throws -> (ConnectionStats?, LocalProfile?) {
let r = await chatSendCmd(.apiGroupMemberInfo(groupId: groupId, groupMemberId: groupMemberId))
- if case let .groupMemberInfo(_, _, connStats_, mainProfile) = r { return (connStats_, mainProfile) }
+ if case let .groupMemberInfo(_, _, connStats_, localMainProfile) = r { return (connStats_, localMainProfile) }
throw r
}
@@ -435,6 +435,12 @@ func apiUpdateProfile(profile: Profile) async throws -> Profile? {
}
}
+func apiSetContactAlias(contactId: Int64, localAlias: String) async throws -> Contact? {
+ let r = await chatSendCmd(.apiSetContactAlias(contactId: contactId, localAlias: localAlias))
+ if case let .contactAliasUpdated(toContact) = r { return toContact }
+ throw r
+}
+
func apiCreateUserAddress() async throws -> String {
let r = await chatSendCmd(.createMyAddress)
if case let .userContactLinkCreated(connReq) = r { return connReq }
diff --git a/apps/ios/Shared/Views/Chat/ChatInfoView.swift b/apps/ios/Shared/Views/Chat/ChatInfoView.swift
index 0450f79816..62449f90a0 100644
--- a/apps/ios/Shared/Views/Chat/ChatInfoView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatInfoView.swift
@@ -46,8 +46,11 @@ struct ChatInfoView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
@ObservedObject var chat: Chat
+ var contact: Contact
var connectionStats: ConnectionStats?
var customUserProfile: Profile?
+ @State var localAlias: String
+ @FocusState private var aliasTextFieldFocused: Bool
@State private var alert: ChatInfoViewAlert? = nil
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@@ -64,6 +67,14 @@ struct ChatInfoView: View {
List {
contactInfoHeader()
.listRowBackground(Color.clear)
+ .contentShape(Rectangle())
+ .onTapGesture {
+ aliasTextFieldFocused = false
+ }
+
+ localAliasTextEdit()
+ .listRowBackground(Color.clear)
+ .listRowSeparator(.hidden)
if let customUserProfile = customUserProfile {
Section("Incognito") {
@@ -113,11 +124,11 @@ struct ChatInfoView: View {
.frame(width: 192, height: 192)
.padding(.top, 12)
.padding()
- Text(cInfo.displayName)
+ Text(contact.profile.displayName)
.font(.largeTitle)
.lineLimit(1)
.padding(.bottom, 2)
- if cInfo.fullName != "" && cInfo.fullName != cInfo.displayName {
+ if cInfo.fullName != "" && cInfo.fullName != cInfo.displayName && cInfo.fullName != contact.profile.displayName {
Text(cInfo.fullName)
.font(.title2)
.lineLimit(2)
@@ -126,6 +137,37 @@ struct ChatInfoView: View {
.frame(maxWidth: .infinity, alignment: .center)
}
+ func localAliasTextEdit() -> some View {
+ TextField("Set contact name…", text: $localAlias)
+ .disableAutocorrection(true)
+ .focused($aliasTextFieldFocused)
+ .submitLabel(.done)
+ .onChange(of: aliasTextFieldFocused) { focused in
+ if !focused {
+ setContactAlias()
+ }
+ }
+ .onSubmit {
+ setContactAlias()
+ }
+ .multilineTextAlignment(.center)
+ .foregroundColor(.secondary)
+ }
+
+ private func setContactAlias() {
+ Task {
+ do {
+ if let contact = try await apiSetContactAlias(contactId: chat.chatInfo.apiId, localAlias: localAlias) {
+ await MainActor.run {
+ chatModel.updateContact(contact)
+ }
+ }
+ } catch {
+ logger.error("setContactAlias error: \(responseError(error))")
+ }
+ }
+ }
+
func networkStatusRow() -> some View {
HStack {
Text("Network status")
@@ -209,6 +251,6 @@ struct ChatInfoView: View {
struct ChatInfoView_Previews: PreviewProvider {
static var previews: some View {
- ChatInfoView(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []))
+ ChatInfoView(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []), contact: Contact.sampleData, localAlias: "")
}
}
diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift
index 049637f2d1..b5ea8afcc4 100644
--- a/apps/ios/Shared/Views/Chat/ChatView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatView.swift
@@ -101,8 +101,8 @@ struct ChatView: View {
}
.sheet(isPresented: $showChatInfoSheet) {
switch cInfo {
- case .direct:
- ChatInfoView(chat: chat, connectionStats: connectionStats, customUserProfile: customUserProfile)
+ case let .direct(contact):
+ ChatInfoView(chat: chat, contact: contact, connectionStats: connectionStats, customUserProfile: customUserProfile, localAlias: chat.chatInfo.localAlias)
case let .group(groupInfo):
GroupChatInfoView(chat: chat, groupInfo: groupInfo)
default:
diff --git a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift
index 68f402c0eb..90e721d431 100644
--- a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift
+++ b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift
@@ -20,7 +20,7 @@ struct GroupChatInfoView: View {
@State private var selectedMember: GroupMember? = nil
@State private var showGroupProfile: Bool = false
@State private var connectionStats: ConnectionStats?
- @State private var mainProfile: Profile?
+ @State private var memberMainProfile: LocalProfile?
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
enum GroupChatInfoViewAlert: Identifiable {
@@ -53,7 +53,7 @@ struct GroupChatInfoView: View {
let (stats, profile) = try await apiGroupMemberInfo(groupInfo.apiId, member.groupMemberId)
await MainActor.run {
connectionStats = stats
- mainProfile = profile
+ memberMainProfile = profile
}
} catch let error {
logger.error("apiGroupMemberInfo error: \(responseError(error))")
@@ -67,7 +67,7 @@ struct GroupChatInfoView: View {
AddGroupMembersView(chat: chat, groupInfo: groupInfo)
}
.sheet(item: $selectedMember, onDismiss: { connectionStats = nil }) { member in
- GroupMemberInfoView(groupInfo: groupInfo, member: member, connectionStats: connectionStats, mainProfile: mainProfile)
+ GroupMemberInfoView(groupInfo: groupInfo, member: member, connectionStats: connectionStats, mainProfile: memberMainProfile)
}
.sheet(isPresented: $showGroupProfile) {
GroupProfileView(groupId: groupInfo.apiId, groupProfile: groupInfo.groupProfile)
diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
index 3c0b257b21..96127affc6 100644
--- a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
+++ b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
@@ -15,7 +15,7 @@ struct GroupMemberInfoView: View {
var groupInfo: GroupInfo
var member: GroupMember
var connectionStats: ConnectionStats?
- var mainProfile: Profile?
+ var mainProfile: LocalProfile?
@State private var alert: GroupMemberInfoViewAlert?
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@@ -76,7 +76,7 @@ struct GroupMemberInfoView: View {
}
}
- private func mainProfileRow(_ mainProfile: Profile) -> some View {
+ private func mainProfileRow(_ mainProfile: LocalProfile) -> some View {
HStack {
Text("Known main profile")
Spacer()
diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift
index 71bdd682c4..4a4dd4d658 100644
--- a/apps/ios/Shared/Views/ChatList/ChatListView.swift
+++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift
@@ -77,9 +77,16 @@ struct ChatListView: View {
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
return s == ""
? chatModel.chats
- : chatModel.chats.filter {
- $0.chatInfo.chatType != .contactConnection &&
- $0.chatInfo.chatViewName.localizedLowercase.contains(s)
+ : chatModel.chats.filter { chat in
+ let contains = chat.chatInfo.chatViewName.localizedLowercase.contains(s)
+ switch chat.chatInfo {
+ case let .direct(contact):
+ return contains
+ || contact.profile.displayName.localizedLowercase.contains(s)
+ || contact.fullName.localizedLowercase.contains(s)
+ case .contactConnection: return false
+ default: return contains
+ }
}
}
}
diff --git a/apps/ios/Shared/Views/UserSettings/UserProfile.swift b/apps/ios/Shared/Views/UserSettings/UserProfile.swift
index a008b3d912..05951e5d31 100644
--- a/apps/ios/Shared/Views/UserSettings/UserProfile.swift
+++ b/apps/ios/Shared/Views/UserSettings/UserProfile.swift
@@ -142,7 +142,7 @@ struct UserProfile: View {
if let newProfile = try await apiUpdateProfile(profile: profile) {
DispatchQueue.main.async {
if let profileId = chatModel.currentUser?.profile.profileId {
- chatModel.currentUser?.profile = toLocalProfile(profileId, newProfile)
+ chatModel.currentUser?.profile = toLocalProfile(profileId, newProfile, "")
}
profile = newProfile
}
diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff
index 32ee0be336..54abdd9d69 100644
--- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff
+++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff
@@ -1648,6 +1648,11 @@ We will be adding server redundancy to prevent lost messages.
Servers
No comment provided by engineer.
+
+ Set contact name…
+ Set contact name…
+ No comment provided by engineer.
+
Set timeouts for proxy/VPN
Set timeouts for proxy/VPN
diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff
index 50ab0d6b07..7902c5b90c 100644
--- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff
+++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff
@@ -194,7 +194,7 @@
Accent color
- Цвет акцента
+ Основной цвет
No comment provided by engineer.
@@ -1648,6 +1648,11 @@ We will be adding server redundancy to prevent lost messages.
Серверы
No comment provided by engineer.
+
+ Set contact name…
+ Имя контакта…
+ No comment provided by engineer.
+
Set timeouts for proxy/VPN
Установить таймауты для прокси/VPN
diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift
index 5fb8cb19ed..060c55ccd0 100644
--- a/apps/ios/SimpleXChat/APITypes.swift
+++ b/apps/ios/SimpleXChat/APITypes.swift
@@ -55,6 +55,7 @@ public enum ChatCommand {
case apiClearChat(type: ChatType, id: Int64)
case listContacts
case apiUpdateProfile(profile: Profile)
+ case apiSetContactAlias(contactId: Int64, localAlias: String)
case createMyAddress
case deleteMyAddress
case showMyAddress
@@ -120,6 +121,7 @@ public enum ChatCommand {
case let .apiClearChat(type, id): return "/_clear chat \(ref(type, id))"
case .listContacts: return "/contacts"
case let .apiUpdateProfile(profile): return "/_profile \(encodeJSON(profile))"
+ case let .apiSetContactAlias(contactId, localAlias): return "/_set alias @\(contactId) \(localAlias.trimmingCharacters(in: .whitespaces))"
case .createMyAddress: return "/address"
case .deleteMyAddress: return "/delete_address"
case .showMyAddress: return "/show_address"
@@ -184,6 +186,7 @@ public enum ChatCommand {
case .apiClearChat: return "apiClearChat"
case .listContacts: return "listContacts"
case .apiUpdateProfile: return "apiUpdateProfile"
+ case .apiSetContactAlias: return "apiSetContactAlias"
case .createMyAddress: return "createMyAddress"
case .deleteMyAddress: return "deleteMyAddress"
case .showMyAddress: return "showMyAddress"
@@ -229,7 +232,7 @@ public enum ChatResponse: Decodable, Error {
case userSMPServers(smpServers: [String])
case networkConfig(networkConfig: NetCfg)
case contactInfo(contact: Contact, connectionStats: ConnectionStats, customUserProfile: Profile?)
- case groupMemberInfo(groupInfo: GroupInfo, member: GroupMember, connectionStats_: ConnectionStats?, mainProfile: Profile?)
+ case groupMemberInfo(groupInfo: GroupInfo, member: GroupMember, connectionStats_: ConnectionStats?, localMainProfile: LocalProfile?)
case invitation(connReqInvitation: String)
case sentConfirmation
case sentInvitation
@@ -238,6 +241,7 @@ public enum ChatResponse: Decodable, Error {
case chatCleared(chatInfo: ChatInfo)
case userProfileNoChange
case userProfileUpdated(fromProfile: Profile, toProfile: Profile)
+ case contactAliasUpdated(toContact: Contact)
case userContactLink(connReqContact: String)
case userContactLinkCreated(connReqContact: String)
case userContactLinkDeleted
@@ -329,6 +333,7 @@ public enum ChatResponse: Decodable, Error {
case .chatCleared: return "chatCleared"
case .userProfileNoChange: return "userProfileNoChange"
case .userProfileUpdated: return "userProfileUpdated"
+ case .contactAliasUpdated: return "contactAliasUpdated"
case .userContactLink: return "userContactLink"
case .userContactLinkCreated: return "userContactLinkCreated"
case .userContactLinkDeleted: return "userContactLinkDeleted"
@@ -411,7 +416,7 @@ public enum ChatResponse: Decodable, Error {
case let .userSMPServers(smpServers): return String(describing: smpServers)
case let .networkConfig(networkConfig): return String(describing: networkConfig)
case let .contactInfo(contact, connectionStats, customUserProfile): return "contact: \(String(describing: contact))\nconnectionStats: \(String(describing: connectionStats))\ncustomUserProfile: \(String(describing: customUserProfile))"
- case let .groupMemberInfo(groupInfo, member, connectionStats_, mainProfile): return "groupInfo: \(String(describing: groupInfo))\nmember: \(String(describing: member))\nconnectionStats_: \(String(describing: connectionStats_))\nmainProfile: \(String(describing: mainProfile))"
+ case let .groupMemberInfo(groupInfo, member, connectionStats_, localMainProfile): return "groupInfo: \(String(describing: groupInfo))\nmember: \(String(describing: member))\nconnectionStats_: \(String(describing: connectionStats_))\nlocalMainProfile: \(String(describing: localMainProfile))"
case let .invitation(connReqInvitation): return connReqInvitation
case .sentConfirmation: return noDetails
case .sentInvitation: return noDetails
@@ -420,6 +425,7 @@ public enum ChatResponse: Decodable, Error {
case let .chatCleared(chatInfo): return String(describing: chatInfo)
case .userProfileNoChange: return noDetails
case let .userProfileUpdated(_, toProfile): return String(describing: toProfile)
+ case let .contactAliasUpdated(toContact): return String(describing: toContact)
case let .userContactLink(connReq): return connReq
case let .userContactLinkCreated(connReq): return connReq
case .userContactLinkDeleted: return noDetails
diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift
index b5fea9e1bb..a15ac63df1 100644
--- a/apps/ios/SimpleXChat/ChatTypes.swift
+++ b/apps/ios/SimpleXChat/ChatTypes.swift
@@ -19,6 +19,7 @@ public struct User: Decodable, NamedChat {
public var displayName: String { get { profile.displayName } }
public var fullName: String { get { profile.fullName } }
public var image: String? { get { profile.image } }
+ public var localAlias: String { get { "" } }
public static let sampleData = User(
userId: 1,
@@ -43,6 +44,7 @@ public struct Profile: Codable, NamedChat {
public var displayName: String
public var fullName: String
public var image: String?
+ public var localAlias: String { get { "" } }
var profileViewName: String {
(fullName == "" || displayName == fullName) ? displayName : "\(displayName) (\(fullName))"
@@ -55,31 +57,36 @@ public struct Profile: Codable, NamedChat {
}
public struct LocalProfile: Codable, NamedChat {
- public init(profileId: Int64, displayName: String, fullName: String, image: String? = nil) {
+ public init(profileId: Int64, displayName: String, fullName: String, image: String? = nil, localAlias: String) {
self.profileId = profileId
self.displayName = displayName
self.fullName = fullName
self.image = image
+ self.localAlias = localAlias
}
public var profileId: Int64
public var displayName: String
public var fullName: String
public var image: String?
+ public var localAlias: String
var profileViewName: String {
- (fullName == "" || displayName == fullName) ? displayName : "\(displayName) (\(fullName))"
+ localAlias == ""
+ ? (fullName == "" || displayName == fullName) ? displayName : "\(displayName) (\(fullName))"
+ : localAlias
}
static let sampleData = LocalProfile(
profileId: 1,
displayName: "alice",
- fullName: "Alice"
+ fullName: "Alice",
+ localAlias: ""
)
}
-public func toLocalProfile (_ profileId: Int64, _ profile: Profile ) -> LocalProfile {
- LocalProfile(profileId: profileId, displayName: profile.displayName, fullName: profile.fullName, image: profile.image)
+public func toLocalProfile (_ profileId: Int64, _ profile: Profile, _ localAlias: String) -> LocalProfile {
+ LocalProfile(profileId: profileId, displayName: profile.displayName, fullName: profile.fullName, image: profile.image, localAlias: localAlias)
}
public func fromLocalProfile (_ profile: LocalProfile) -> Profile {
@@ -97,11 +104,14 @@ public protocol NamedChat {
var displayName: String { get }
var fullName: String { get }
var image: String? { get }
+ var localAlias: String { get }
}
extension NamedChat {
public var chatViewName: String {
- get { displayName + (fullName == "" || fullName == displayName ? "" : " / \(fullName)") }
+ localAlias == ""
+ ? displayName + (fullName == "" || fullName == displayName ? "" : " / \(fullName)")
+ : localAlias
}
}
@@ -157,6 +167,17 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat {
}
}
+ public var localAlias: String {
+ get {
+ switch self {
+ case let .direct(contact): return contact.localAlias
+ case let .group(groupInfo): return groupInfo.localAlias
+ case let .contactRequest(contactRequest): return contactRequest.localAlias
+ case let .contactConnection(contactConnection): return contactConnection.localAlias
+ }
+ }
+ }
+
public var id: ChatId {
get {
switch self {
@@ -303,9 +324,10 @@ public struct Contact: Identifiable, Decodable, NamedChat {
public var apiId: Int64 { get { contactId } }
public var ready: Bool { get { activeConn.connStatus == .ready } }
public var sendMsgEnabled: Bool { get { true } }
- public var displayName: String { get { profile.displayName } }
+ public var displayName: String { localAlias == "" ? profile.displayName : localAlias }
public var fullName: String { get { profile.fullName } }
public var image: String? { get { profile.image } }
+ public var localAlias: String { profile.localAlias }
public var isIndirectContact: Bool {
activeConn.connLevel > 0 || viaGroup != nil
@@ -384,6 +406,7 @@ public struct UserContactRequest: Decodable, NamedChat {
public var displayName: String { get { profile.displayName } }
public var fullName: String { get { profile.fullName } }
public var image: String? { get { profile.image } }
+ public var localAlias: String { "" }
public static let sampleData = UserContactRequest(
contactRequestId: 1,
@@ -425,6 +448,7 @@ public struct PendingContactConnection: Decodable, NamedChat {
}
public var fullName: String { get { "" } }
public var image: String? { get { nil } }
+ public var localAlias: String { "" }
public var initiated: Bool { get { (pccConnStatus.initiated ?? false) && !viaContactUri } }
public var incognito: Bool {
@@ -524,6 +548,7 @@ public struct GroupInfo: Identifiable, Decodable, NamedChat {
public var displayName: String { get { groupProfile.displayName } }
public var fullName: String { get { groupProfile.fullName } }
public var image: String? { get { groupProfile.image } }
+ public var localAlias: String { "" }
public var canEdit: Bool {
return membership.memberRole == .owner && membership.memberCurrent
@@ -559,6 +584,7 @@ public struct GroupProfile: Codable, NamedChat {
public var displayName: String
public var fullName: String
public var image: String?
+ public var localAlias: String { "" }
public static let sampleData = GroupProfile(
displayName: "team",
@@ -581,7 +607,12 @@ public struct GroupMember: Identifiable, Decodable {
public var activeConn: Connection?
public var id: String { "#\(groupId) @\(groupMemberId)" }
- public var displayName: String { get { memberProfile.displayName } }
+ public var displayName: String {
+ get {
+ let p = memberProfile
+ return p.localAlias == "" ? p.displayName : p.localAlias
+ }
+ }
public var fullName: String { get { memberProfile.fullName } }
public var image: String? { get { memberProfile.image } }
@@ -598,7 +629,9 @@ public struct GroupMember: Identifiable, Decodable {
public var chatViewName: String {
get {
let p = memberProfile
- return p.displayName + (p.fullName == "" || p.fullName == p.displayName ? "" : " / \(p.fullName)")
+ return p.localAlias == ""
+ ? p.displayName + (p.fullName == "" || p.fullName == p.displayName ? "" : " / \(p.fullName)")
+ : p.localAlias
}
}
@@ -860,7 +893,7 @@ public struct ChatItem: Identifiable, Decodable {
public var memberDisplayName: String? {
get {
if case let .groupRcv(groupMember) = chatDir {
- return groupMember.memberProfile.displayName
+ return groupMember.displayName
} else {
return nil
}
diff --git a/apps/ios/ru.lproj/Localizable.strings b/apps/ios/ru.lproj/Localizable.strings
index 2e84149b57..23da2d5727 100644
--- a/apps/ios/ru.lproj/Localizable.strings
+++ b/apps/ios/ru.lproj/Localizable.strings
@@ -125,7 +125,7 @@
"above, then choose:" = "наверху, затем выберите:";
/* No comment provided by engineer. */
-"Accent color" = "Цвет акцента";
+"Accent color" = "Основной цвет";
/* accept contact request via notification
accept incoming call via notification */
@@ -1175,6 +1175,9 @@
/* No comment provided by engineer. */
"Servers" = "Серверы";
+/* No comment provided by engineer. */
+"Set contact name…" = "Имя контакта…";
+
/* No comment provided by engineer. */
"Set timeouts for proxy/VPN" = "Установить таймауты для прокси/VPN";