This commit is contained in:
spaced4ndy
2026-07-10 12:37:57 +04:00
parent b03c4bbfc7
commit 40ce22cae6
13 changed files with 97 additions and 16 deletions
@@ -16,6 +16,7 @@ struct CIFileView: View {
@EnvironmentObject var theme: AppTheme
let file: CIFile?
let edited: Bool
let msgVerified: MsgVerified
let senderProfile: LocalProfile?
var smallViewSize: CGFloat?
@@ -24,9 +25,9 @@ struct CIFileView: View {
fileIndicator()
.simultaneousGesture(TapGesture().onEnded(fileAction))
} else {
let metaReserve = edited
? " "
: " "
// the signature/"signature missing" icon in the overlaid meta needs reserved space too (matches CIMetaView)
let signedReserve = (msgVerified.verified && (file?.loaded ?? true)) || msgVerified == .sigMissing ? " " : ""
let metaReserve = (edited ? " " : " ") + signedReserve
HStack(alignment: .bottom, spacing: 6) {
fileIndicator()
.padding(.top, 5)
@@ -151,9 +151,11 @@ func ciMetaText(
space = textSpace
}
if meta.msgVerified.verified && signedFileVerified {
appendSpace()
r = r + colored(Text(Image("signature.plain")), resolved)
space = textSpace
} else if meta.msgVerified == .sigMissing {
appendSpace()
r = r + colored(Text(Image(systemName: "exclamationmark.triangle")), colorMode.resolve(.red))
space = textSpace
}
@@ -349,7 +349,7 @@ struct FramedItemView: View {
}
@ViewBuilder private func ciFileView(_ ci: ChatItem, _ text: String) -> some View {
CIFileView(file: chatItem.file, edited: chatItem.meta.itemEdited, senderProfile: ciSenderProfile(chatItem, chat.chatInfo))
CIFileView(file: chatItem.file, edited: chatItem.meta.itemEdited, msgVerified: chatItem.meta.msgVerified, senderProfile: ciSenderProfile(chatItem, chat.chatInfo))
.overlay(DetermineWidth())
if text != "" || ci.meta.isLive {
ciMsgContentView (chatItem)
@@ -120,7 +120,7 @@ struct GroupPreferencesView: View {
get: { enableFeature.wrappedValue == .on },
set: { on, _ in enableFeature.wrappedValue = on ? .on : .off }
)
settingsRow(icon, color: color) {
settingsRow(icon, color: color, customImage: feature.customImage) {
Toggle(feature.text(isChannel: groupInfo.isChannel), isOn: enable)
}
.disabled(disabled)
@@ -143,7 +143,7 @@ struct GroupPreferencesView: View {
.frame(height: 36)
}
} else {
settingsRow(icon, color: color) {
settingsRow(icon, color: color, customImage: feature.customImage) {
infoRow(Text(feature.text(isChannel: groupInfo.isChannel)), enableFeature.wrappedValue.text)
}
if timedOn {
@@ -438,7 +438,7 @@ struct ChatPreviewView: View {
}
case .file:
smallContentPreviewFile(size: dynamicMediaSize) {
CIFileView(file: ci.file, edited: ci.meta.itemEdited, senderProfile: ciSenderProfile(ci, chat.chatInfo), smallViewSize: dynamicMediaSize)
CIFileView(file: ci.file, edited: ci.meta.itemEdited, msgVerified: ci.meta.msgVerified, senderProfile: ciSenderProfile(ci, chat.chatInfo), smallViewSize: dynamicMediaSize)
}
case let .chat(_, chatLink, ownerSig):
smallContentPreview(size: dynamicMediaSize, borderColor: chatLink.image != nil ? .secondary : .clear) {
@@ -530,9 +530,11 @@ struct SettingsView: View {
}
}
func settingsRow<Content : View>(_ icon: String, color: Color/* = .secondary*/, content: @escaping () -> Content) -> some View {
func settingsRow<Content : View>(_ icon: String, color: Color/* = .secondary*/, customImage: Bool = false, content: @escaping () -> Content) -> some View {
ZStack(alignment: .leading) {
Image(systemName: icon).frame(maxWidth: 24, maxHeight: 24, alignment: .center)
// custom symbol sets (e.g. "signature.plain") are asset images, SF Symbols are system images
(customImage ? Image(icon) : Image(systemName: icon))
.frame(maxWidth: 24, maxHeight: 24, alignment: .center)
.symbolRenderingMode(.monochrome)
.foregroundColor(color)
content().padding(.leading, indent)
+9 -2
View File
@@ -1005,7 +1005,7 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .reports: return "flag"
case .history: return "clock"
case .support: return "questionmark.circle"
case .signMessages: return "signature"
case .signMessages: return "signature.plain"
}
}
@@ -1021,7 +1021,7 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .reports: return "flag.fill"
case .history: return "clock.fill"
case .support: return "questionmark.circle.fill"
case .signMessages: return "signature"
case .signMessages: return "signature.plain"
}
}
@@ -1032,6 +1032,13 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
}
}
public var customImage: Bool {
switch self {
case .signMessages: return true
default: return false
}
}
public func enableDescription(_ enabled: GroupFeatureEnabled, _ canEdit: Bool, isChannel: Bool = false) -> LocalizedStringKey {
if canEdit {
switch self {
@@ -110,8 +110,10 @@ private fun CIMetaText(
StatusIconText(painterResource(if (encrypted) MR.images.ic_lock else MR.images.ic_lock_open_right), color)
}
if (meta.msgVerified.verified && signedFileVerified) {
Spacer(Modifier.width(4.dp))
StatusIconText(painterResource(MR.images.ic_signature), color)
} else if (meta.msgVerified is MsgVerified.SigMissing) {
Spacer(Modifier.width(4.dp))
StatusIconText(painterResource(MR.images.ic_warning), Color.Red)
}
@@ -176,6 +178,7 @@ fun reserveSpaceForMeta(
space = whiteSpace
}
if ((meta.msgVerified.verified && signedFileVerified) || meta.msgVerified is MsgVerified.SigMissing) {
appendSpace()
res += iconSpace
space = whiteSpace
}
+22 -1
View File
@@ -139,6 +139,7 @@ This file is generated automatically.
- [MsgReaction](#msgreaction)
- [MsgReceiptStatus](#msgreceiptstatus)
- [MsgSigStatus](#msgsigstatus)
- [MsgVerified](#msgverified)
- [NameErrorType](#nameerrortype)
- [NetworkError](#networkerror)
- [NewUser](#newuser)
@@ -872,7 +873,7 @@ Group:
- editable: bool
- forwardedByMember: int64?
- showGroupAsSender: bool
- msgSigned: [MsgSigStatus](#msgsigstatus)?
- msgVerified: [MsgVerified](#msgverified)
- createdAt: UTCTime
- updatedAt: UTCTime
@@ -2218,6 +2219,7 @@ Phone:
- support: [SupportGroupPreference](#supportgrouppreference)
- sessions: [RoleGroupPreference](#rolegrouppreference)
- comments: [CommentsGroupPreference](#commentsgrouppreference)
- signMessages: [GroupPreference](#grouppreference)
- commands: [[ChatBotCommand](#chatbotcommand)]
@@ -2310,6 +2312,7 @@ MemberSupport:
- "support"
- "sessions"
- "comments"
- "signMessages"
---
@@ -2551,6 +2554,7 @@ UpdateRequired:
- support: [SupportGroupPreference](#supportgrouppreference)?
- sessions: [RoleGroupPreference](#rolegrouppreference)?
- comments: [CommentsGroupPreference](#commentsgrouppreference)?
- signMessages: [GroupPreference](#grouppreference)?
- commands: [[ChatBotCommand](#chatbotcommand)]?
@@ -2951,6 +2955,23 @@ Unknown:
- "signedNoKey"
---
## MsgVerified
**Discriminated union type**:
Signed:
- type: "signed"
- sigStatus: [MsgSigStatus](#msgsigstatus)
SigMissing:
- type: "sigMissing"
Unsigned:
- type: "unsigned"
---
## NameErrorType
+2
View File
@@ -322,6 +322,7 @@ chatTypesDocsData =
(sti @MsgReaction, STUnion, "MR", [], "", ""),
(sti @MsgReceiptStatus, STEnum, "MR", [], "", ""),
(sti @MsgSigStatus, STEnum, "MSS", [], "", ""),
(sti @MsgVerified, STUnion, "MV", [], "", ""),
(sti @NameErrorType, STUnion, "", [], "", ""),
(sti @NetworkError, STUnion, "NE", [], "", ""),
(sti @NewUser, STRecord, "", [], "", ""),
@@ -554,6 +555,7 @@ deriving instance Generic MsgFilter
deriving instance Generic MsgReaction
deriving instance Generic MsgReceiptStatus
deriving instance Generic MsgSigStatus
deriving instance Generic MsgVerified
deriving instance Generic NameErrorType
deriving instance Generic NetworkError
deriving instance Generic NewUser
+2 -1
View File
@@ -240,7 +240,8 @@ toTypeInfo tr =
[ "FullDeleteGroupPreference",
"ReactionsGroupPreference",
"ReportsGroupPreference",
"HistoryGroupPreference"
"HistoryGroupPreference",
"SignMessagesGroupPreference"
]
roleGroupPrefTypes =
[ "DirectMessagesGroupPreference",
@@ -841,7 +841,7 @@ export interface CIMeta {
editable: boolean
forwardedByMember?: number // int64
showGroupAsSender: boolean
msgSigned?: MsgSigStatus
msgVerified: MsgVerified
createdAt: string // ISO-8601 timestamp
updatedAt: string // ISO-8601 timestamp
}
@@ -2529,6 +2529,7 @@ export interface FullGroupPreferences {
support: SupportGroupPreference
sessions: RoleGroupPreference
comments: CommentsGroupPreference
signMessages: GroupPreference
commands: ChatBotCommand[]
}
@@ -2603,6 +2604,7 @@ export enum GroupFeature {
Support = "support",
Sessions = "sessions",
Comments = "comments",
SignMessages = "signMessages",
}
export enum GroupFeatureEnabled {
@@ -2812,6 +2814,7 @@ export interface GroupPreferences {
support?: SupportGroupPreference
sessions?: RoleGroupPreference
comments?: CommentsGroupPreference
signMessages?: GroupPreference
commands?: ChatBotCommand[]
}
@@ -3207,6 +3210,29 @@ export enum MsgSigStatus {
SignedNoKey = "signedNoKey",
}
export type MsgVerified = MsgVerified.Signed | MsgVerified.SigMissing | MsgVerified.Unsigned
export namespace MsgVerified {
export type Tag = "signed" | "sigMissing" | "unsigned"
interface Interface {
type: Tag
}
export interface Signed extends Interface {
type: "signed"
sigStatus: MsgSigStatus
}
export interface SigMissing extends Interface {
type: "sigMissing"
}
export interface Unsigned extends Interface {
type: "unsigned"
}
}
export type NameErrorType = NameErrorType.NO_RESOLVER | NameErrorType.NOT_FOUND | NameErrorType.RESOLVER
export namespace NameErrorType {
@@ -587,7 +587,7 @@ class CIMeta(TypedDict):
editable: bool
forwardedByMember: NotRequired[int] # int64
showGroupAsSender: bool
msgSigned: NotRequired["MsgSigStatus"]
msgVerified: "MsgVerified"
createdAt: str # ISO-8601 timestamp
updatedAt: str # ISO-8601 timestamp
@@ -1775,6 +1775,7 @@ class FullGroupPreferences(TypedDict):
support: "SupportGroupPreference"
sessions: "RoleGroupPreference"
comments: "CommentsGroupPreference"
signMessages: "GroupPreference"
commands: list["ChatBotCommand"]
class FullPreferences(TypedDict):
@@ -1818,7 +1819,7 @@ class GroupDirectInvitation(TypedDict):
fromGroupMemberConnId_: NotRequired[int] # int64
groupDirectInvStartedConnection: bool
GroupFeature = Literal["timedMessages", "directMessages", "fullDelete", "reactions", "voice", "files", "simplexLinks", "reports", "history", "support", "sessions", "comments"]
GroupFeature = Literal["timedMessages", "directMessages", "fullDelete", "reactions", "voice", "files", "simplexLinks", "reports", "history", "support", "sessions", "comments", "signMessages"]
GroupFeatureEnabled = Literal["on", "off"]
@@ -1966,6 +1967,7 @@ class GroupPreferences(TypedDict):
support: NotRequired["SupportGroupPreference"]
sessions: NotRequired["RoleGroupPreference"]
comments: NotRequired["CommentsGroupPreference"]
signMessages: NotRequired["GroupPreference"]
commands: NotRequired[list["ChatBotCommand"]]
class GroupProfile(TypedDict):
@@ -2243,6 +2245,20 @@ MsgReceiptStatus = Literal["ok", "badMsgHash"]
MsgSigStatus = Literal["verified", "signedNoKey"]
class MsgVerified_signed(TypedDict):
type: Literal["signed"]
sigStatus: "MsgSigStatus"
class MsgVerified_sigMissing(TypedDict):
type: Literal["sigMissing"]
class MsgVerified_unsigned(TypedDict):
type: Literal["unsigned"]
MsgVerified = MsgVerified_signed | MsgVerified_sigMissing | MsgVerified_unsigned
MsgVerified_Tag = Literal["signed", "sigMissing", "unsigned"]
class NameErrorType_NO_RESOLVER(TypedDict):
type: Literal["NO_RESOLVER"]