Add trusted and untrusted avatar circle

This commit is contained in:
Benoit Martins 2026-02-19 11:38:59 +01:00
parent d5d1600b4e
commit 09863890ea
6 changed files with 134 additions and 72 deletions

View file

@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "not_trusted.svg",
"filename" : "not-trusted.svg",
"idiom" : "universal",
"scale" : "1x"
},

View file

@ -0,0 +1,59 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
id="vector">
<defs>
<clipPath id="clip_path_1">
<path d="M 0 0 L 10 0 L 10 10 L 0 10 Z"/>
</clipPath>
<clipPath id="clip_path_2">
<path
d="M 0 0 L 10 0 L 10 10 L 0 10 Z"
clip-path="url(#clip_path_2_1)"/>
</clipPath>
<clipPath id="clip_path_2_1">
<path d="M 0 0 L 10 0 L 10 10 L 0 10 Z"/>
</clipPath>
<clipPath id="clip_path_3">
<path
d="M 0 0 L 10 0 L 10 10 L 0 10 Z"
clip-path="url(#clip_path_3_1)"/>
</clipPath>
<clipPath id="clip_path_3_1">
<path
d="M 0 0 L 10 0 L 10 10 L 0 10 Z"
clip-path="url(#clip_path_3_2)"/>
</clipPath>
<clipPath id="clip_path_3_2">
<path d="M 0 0 L 10 0 L 10 10 L 0 10 Z"/>
</clipPath>
</defs>
<g
id="wrapper"
transform="scale(2.4 2.4)">
<path
id="path"
d="M 0.769 5 C 0.769 6.122 1.215 7.199 2.008 7.992 C 2.801 8.785 3.878 9.231 5 9.231 C 6.122 9.231 7.199 8.785 7.992 7.992 C 8.785 7.199 9.231 6.122 9.231 5 C 9.231 4.107 8.948 3.236 8.423 2.513 C 7.898 1.79 7.157 1.252 6.307 0.976 C 5.458 0.7 4.542 0.7 3.693 0.976 C 2.843 1.252 2.102 1.79 1.577 2.513 C 1.052 3.236 0.769 4.107 0.769 5 Z"
fill="#dd5f5f"
stroke-width="1"/>
<path
id="path_1"
clip-path="url(#clip_path_1)"
d="M 5 2.917 C 5.23 2.917 5.417 3.103 5.417 3.333 L 5.417 5 C 5.417 5.23 5.23 5.417 5 5.417 C 4.77 5.417 4.583 5.23 4.583 5 L 4.583 3.333 C 4.583 3.103 4.77 2.917 5 2.917 Z"
fill="#364860"
stroke-width="1"/>
<path
id="path_2"
clip-path="url(#clip_path_2)"
d="M 5 6.25 C 4.77 6.25 4.583 6.437 4.583 6.667 C 4.583 6.897 4.77 7.083 5 7.083 L 5.004 7.083 C 5.234 7.083 5.421 6.897 5.421 6.667 C 5.421 6.437 5.234 6.25 5.004 6.25 L 5 6.25 Z"
fill="#364860"
stroke-width="1"/>
<path
id="path_3"
clip-path="url(#clip_path_3)"
d="M 2.98 0.539 C 3.058 0.461 3.164 0.417 3.275 0.417 L 6.725 0.417 C 6.835 0.417 6.941 0.461 7.02 0.539 L 9.461 2.98 C 9.539 3.059 9.583 3.164 9.583 3.275 L 9.583 6.725 C 9.583 6.835 9.539 6.941 9.461 7.02 L 7.02 9.461 C 6.941 9.539 6.835 9.583 6.725 9.583 L 3.275 9.583 C 3.164 9.583 3.058 9.539 2.98 9.461 L 0.539 7.02 C 0.461 6.941 0.417 6.835 0.417 6.725 L 0.417 3.275 C 0.417 3.164 0.461 3.059 0.539 2.98 L 2.98 0.539 Z M 3.448 1.25 L 1.25 3.448 L 1.25 6.552 L 3.448 8.75 L 6.552 8.75 L 8.75 6.552 L 8.75 3.448 L 6.552 1.25 L 3.448 1.25 Z"
fill="#364860"
stroke-width="1"
fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -1,13 +0,0 @@
<svg width="11" height="10" viewBox="0 0 11 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="5.24993" cy="5.00006" rx="4.23077" ry="4.23077" fill="#DD5F5F"/>
<g clip-path="url(#clip0_2386_24363)">
<path d="M5.24996 2.91666C5.48008 2.91666 5.66663 3.1032 5.66663 3.33332V4.99999C5.66663 5.23011 5.48008 5.41666 5.24996 5.41666C5.01984 5.41666 4.83329 5.23011 4.83329 4.99999V3.33332C4.83329 3.1032 5.01984 2.91666 5.24996 2.91666Z" fill="#364860"/>
<path d="M5.24996 6.24999C5.01984 6.24999 4.83329 6.43654 4.83329 6.66666C4.83329 6.89677 5.01984 7.08332 5.24996 7.08332H5.25413C5.48424 7.08332 5.67079 6.89677 5.67079 6.66666C5.67079 6.43654 5.48424 6.24999 5.25413 6.24999H5.24996Z" fill="#364860"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.23033 0.538695C3.30847 0.460555 3.41445 0.416656 3.52496 0.416656H6.97496C7.08547 0.416656 7.19145 0.460555 7.26959 0.538695L9.71125 2.98036C9.78939 3.0585 9.83329 3.16448 9.83329 3.27499V6.72499C9.83329 6.8355 9.78939 6.94148 9.71125 7.01962L7.26959 9.46128C7.19145 9.53942 7.08547 9.58332 6.97496 9.58332H3.52496C3.41445 9.58332 3.30847 9.53942 3.23033 9.46128L0.788665 7.01962C0.710525 6.94148 0.666626 6.8355 0.666626 6.72499V3.27499C0.666626 3.16448 0.710525 3.0585 0.788665 2.98036L3.23033 0.538695ZM3.69755 1.24999L1.49996 3.44758V6.5524L3.69755 8.74999H6.80237L8.99996 6.5524V3.44758L6.80237 1.24999H3.69755Z" fill="#364860"/>
</g>
<defs>
<clipPath id="clip0_2386_24363">
<rect width="10" height="10" fill="white" transform="translate(0.25)"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -1,7 +1,7 @@
import Foundation
public enum AppGitInfo {
public static let branch = "feature/trust_list"
public static let commit = "692a308d7"
public static let branch = "master"
public static let commit = "d5d1600b4"
public static let tag = "6.1.0-alpha"
}

View file

@ -45,6 +45,8 @@ class ContactAvatarModel: ObservableObject, Identifiable {
@Published var photo: String = ""
@Published var lastPresenceInfo: String = ""
@Published var presenceStatus: ConsolidatedPresence = .Offline
@Published var unsafeFriend: Bool = false
@Published var trustedFriend: Bool = false
private var friendDelegate: FriendDelegate?
@ -89,6 +91,9 @@ class ContactAvatarModel: ObservableObject, Identifiable {
var lastPresenceInfoTmp = ""
var presenceStatusTmp: ConsolidatedPresence = .Offline
let unsafeFriendTmp = (friend?.securityLevel ?? .None) == .Unsafe
let trustedFriendTmp = (friend?.securityLevel ?? .None) == .EndToEndEncryptedAndVerified
if let friend = friend, withPresence == true {
lastPresenceInfoTmp = ""
@ -128,6 +133,8 @@ class ContactAvatarModel: ObservableObject, Identifiable {
self.photo = photoTmp
self.lastPresenceInfo = lastPresenceInfoTmp
self.presenceStatus = presenceStatusTmp
self.unsafeFriend = unsafeFriendTmp
self.trustedFriend = trustedFriendTmp
}
}
}

View file

@ -27,65 +27,79 @@ struct Avatar: View {
@ObservedObject var contactAvatarModel: ContactAvatarModel
let avatarSize: CGFloat
let hidePresence: Bool
init(contactAvatarModel: ContactAvatarModel, avatarSize: CGFloat, hidePresence: Bool = false) {
self.contactAvatarModel = contactAvatarModel
self.avatarSize = avatarSize
self.hidePresence = hidePresence
}
let hidePresence: Bool
init(contactAvatarModel: ContactAvatarModel, avatarSize: CGFloat, hidePresence: Bool = false) {
self.contactAvatarModel = contactAvatarModel
self.avatarSize = avatarSize
self.hidePresence = hidePresence
}
var body: some View {
if !contactAvatarModel.photo.isEmpty {
let uniqueUrl = ContactsManager.shared.getImagePath(friendPhotoPath: contactAvatarModel.photo)
//let finalUrl = uniqueUrl.appendingQueryItem("v", value: UUID().uuidString)
AsyncImage(url: uniqueUrl) { image in
switch image {
case .empty:
ProgressView()
.frame(width: avatarSize, height: avatarSize)
case .success(let image):
ZStack {
image
ZStack {
if !contactAvatarModel.photo.isEmpty {
let uniqueUrl = ContactsManager.shared.getImagePath(friendPhotoPath: contactAvatarModel.photo)
//let finalUrl = uniqueUrl.appendingQueryItem("v", value: UUID().uuidString)
AsyncImage(url: uniqueUrl) { image in
switch image {
case .empty:
ProgressView()
.frame(width: avatarSize, height: avatarSize)
case .success(let image):
ZStack {
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
}
case .failure:
Image("profil-picture-default")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
HStack {
Spacer()
VStack {
Spacer()
if !hidePresence && (contactAvatarModel.presenceStatus == .Online || contactAvatarModel.presenceStatus == .Busy) {
Image(contactAvatarModel.presenceStatus == .Online ? "presence-online" : "presence-busy")
.resizable()
.frame(width: avatarSize/4, height: avatarSize/4)
.padding(.trailing, avatarSize == 50 || avatarSize == 35 ? 1 : 3)
.padding(.bottom, avatarSize == 50 || avatarSize == 35 ? 1 : 3)
}
}
}
.frame(width: avatarSize, height: avatarSize)
@unknown default:
EmptyView()
}
case .failure:
Image("profil-picture-default")
.resizable()
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
@unknown default:
EmptyView()
}
} else if !contactAvatarModel.name.isEmpty {
ZStack {
Image(uiImage: contactsManager.textToImage(
firstName: contactAvatarModel.name,
lastName: contactAvatarModel.name.components(separatedBy: " ").count > 1
? contactAvatarModel.name.components(separatedBy: " ")[1]
: ""))
.resizable()
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
}
} else {
Image("profil-picture-default")
.resizable()
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
}
} else if !contactAvatarModel.name.isEmpty {
ZStack {
Image(uiImage: contactsManager.textToImage(
firstName: contactAvatarModel.name,
lastName: contactAvatarModel.name.components(separatedBy: " ").count > 1
? contactAvatarModel.name.components(separatedBy: " ")[1]
: ""))
.resizable()
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
if contactAvatarModel.friend != nil && !hidePresence {
if contactAvatarModel.unsafeFriend || contactAvatarModel.trustedFriend {
Circle()
.stroke(contactAvatarModel.trustedFriend ? Color.blueInfo500 : Color.redDanger500, lineWidth: 2)
.frame(width: avatarSize, height: avatarSize)
HStack {
VStack {
Spacer()
Image(contactAvatarModel.trustedFriend ? "trusted" : "not-trusted")
.resizable()
.frame(width: avatarSize/4, height: avatarSize/4)
.padding(.trailing, avatarSize == 50 || avatarSize == 35 ? 1 : 3)
.padding(.bottom, avatarSize == 50 || avatarSize == 35 ? 1 : 3)
}
Spacer()
}
.frame(width: avatarSize, height: avatarSize)
}
HStack {
Spacer()
@ -102,11 +116,6 @@ struct Avatar: View {
}
.frame(width: avatarSize, height: avatarSize)
}
} else {
Image("profil-picture-default")
.resizable()
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
}
}
}