mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-16 18:46:04 +00:00
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>
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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: "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1648,6 +1648,11 @@ We will be adding server redundancy to prevent lost messages.</target>
|
||||
<target>Servers</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set contact name…" xml:space="preserve">
|
||||
<source>Set contact name…</source>
|
||||
<target>Set contact name…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set timeouts for proxy/VPN" xml:space="preserve">
|
||||
<source>Set timeouts for proxy/VPN</source>
|
||||
<target>Set timeouts for proxy/VPN</target>
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="Accent color" xml:space="preserve">
|
||||
<source>Accent color</source>
|
||||
<target>Цвет акцента</target>
|
||||
<target>Основной цвет</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Accept" xml:space="preserve">
|
||||
@@ -1648,6 +1648,11 @@ We will be adding server redundancy to prevent lost messages.</source>
|
||||
<target>Серверы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set contact name…" xml:space="preserve">
|
||||
<source>Set contact name…</source>
|
||||
<target>Имя контакта…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set timeouts for proxy/VPN" xml:space="preserve">
|
||||
<source>Set timeouts for proxy/VPN</source>
|
||||
<target>Установить таймауты для прокси/VPN</target>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user