Member Label view controller UI
This commit is contained in:
parent
212cefb9ec
commit
3b6d3f5e0e
@ -52,6 +52,7 @@
|
||||
04441DDE2F115CAF0095E1F4 /* chat_item_pin_message_04.txtproto in Resources */ = {isa = PBXBuildFile; fileRef = 04441DA02F115CAF0095E1F4 /* chat_item_pin_message_04.txtproto */; };
|
||||
04441DEA2F17EF6C0095E1F4 /* CVMemberLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04441DE92F17EF690095E1F4 /* CVMemberLabel.swift */; };
|
||||
04441DED2F1816BB0095E1F4 /* MemberLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04441DEB2F18121C0095E1F4 /* MemberLabel.swift */; };
|
||||
04441DEF2F194B800095E1F4 /* MemberLabelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04441DEE2F194B770095E1F4 /* MemberLabelViewController.swift */; };
|
||||
04472D5E2E8AD74200D69EE0 /* OutgoingPollVote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04472D5D2E8AD73A00D69EE0 /* OutgoingPollVote.swift */; };
|
||||
044A2C6E2EEB444E00AA3CA0 /* BackupArchivePinMessageChatUpdateArchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044A2C6D2EEB443E00AA3CA0 /* BackupArchivePinMessageChatUpdateArchiver.swift */; };
|
||||
044D77782E5E6D750048C21A /* PollVoteRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044D77772E5E6D700048C21A /* PollVoteRecord.swift */; };
|
||||
@ -4108,6 +4109,7 @@
|
||||
04441DBA2F115CAF0095E1F4 /* chat_item_pin_message_update_02.txtproto */ = {isa = PBXFileReference; lastKnownFileType = text; path = chat_item_pin_message_update_02.txtproto; sourceTree = "<group>"; };
|
||||
04441DE92F17EF690095E1F4 /* CVMemberLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CVMemberLabel.swift; sourceTree = "<group>"; };
|
||||
04441DEB2F18121C0095E1F4 /* MemberLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberLabel.swift; sourceTree = "<group>"; };
|
||||
04441DEE2F194B770095E1F4 /* MemberLabelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberLabelViewController.swift; sourceTree = "<group>"; };
|
||||
04472D5D2E8AD73A00D69EE0 /* OutgoingPollVote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingPollVote.swift; sourceTree = "<group>"; };
|
||||
044A2C6D2EEB443E00AA3CA0 /* BackupArchivePinMessageChatUpdateArchiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupArchivePinMessageChatUpdateArchiver.swift; sourceTree = "<group>"; };
|
||||
044D77772E5E6D700048C21A /* PollVoteRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollVoteRecord.swift; sourceTree = "<group>"; };
|
||||
@ -9172,6 +9174,7 @@
|
||||
76C87FE028BE8E2400BD8709 /* LinkPreviewAttachmentViewController.swift */,
|
||||
88A9729322FB4D02004B4FBF /* LocationPicker.swift */,
|
||||
3496744E2076ACCE00080B5F /* LongTextViewController.swift */,
|
||||
04441DEE2F194B770095E1F4 /* MemberLabelViewController.swift */,
|
||||
4CFF4C0920F55BBA005DA313 /* MessageActionsToolbar.swift */,
|
||||
34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */,
|
||||
881218EF238CA51600E6F271 /* MessageReactionPicker.swift */,
|
||||
@ -18134,6 +18137,7 @@
|
||||
4C8A6DFC22E5499300469AE7 /* MediaZoomAnimationController.swift in Sources */,
|
||||
8837F74123DA0B0F00772A32 /* MegaphoneView.swift in Sources */,
|
||||
88A357B923639384009D6B9A /* MemberActionSheet.swift in Sources */,
|
||||
04441DEF2F194B800095E1F4 /* MemberLabelViewController.swift in Sources */,
|
||||
346EAA14250199A400E8AB6F /* MemberRequestView.swift in Sources */,
|
||||
4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */,
|
||||
4CB5F26720F6E1E2004D1B42 /* MessageActionsToolbar.swift in Sources */,
|
||||
|
||||
438
Signal/src/ViewControllers/MemberLabelViewController.swift
Normal file
438
Signal/src/ViewControllers/MemberLabelViewController.swift
Normal file
@ -0,0 +1,438 @@
|
||||
//
|
||||
// Copyright 2026 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import LibSignalClient
|
||||
import SignalServiceKit
|
||||
import SignalUI
|
||||
import SwiftUI
|
||||
|
||||
class MemberLabelViewController: OWSViewController {
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
view.backgroundColor = UIColor.Signal.groupedBackground
|
||||
navigationItem.title = OWSLocalizedString("MEMBER_LABEL_VIEW_TITLE", comment: "Title for a view where users can edit and preview their member label.")
|
||||
|
||||
// TODO: fade if text field empty
|
||||
navigationItem.rightBarButtonItem = .init(barButtonSystemItem: .done, target: self, action: #selector(didTapDone))
|
||||
navigationItem.leftBarButtonItem = .init(barButtonSystemItem: .cancel, target: self, action: #selector(didTapCancel))
|
||||
navigationItem.rightBarButtonItem?.tintColor = UIColor.Signal.ultramarine
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
createViews()
|
||||
}
|
||||
|
||||
private func createViews() {
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .vertical
|
||||
stackView.spacing = 20
|
||||
|
||||
let subtitleLabel = UILabel()
|
||||
subtitleLabel.text = OWSLocalizedString(
|
||||
"MEMBER_LABEL_VIEW_SUBTITLE",
|
||||
comment: "Subtitle for a view where users can edit and preview their member label.",
|
||||
)
|
||||
subtitleLabel.numberOfLines = 0
|
||||
subtitleLabel.font = .dynamicTypeCaption1Clamped
|
||||
subtitleLabel.textColor = UIColor.Signal.secondaryLabel
|
||||
subtitleLabel.textAlignment = .center
|
||||
|
||||
stackView.addArrangedSubview(subtitleLabel)
|
||||
|
||||
let textFieldStack = UIStackView()
|
||||
textFieldStack.layer.cornerRadius = 27
|
||||
textFieldStack.backgroundColor = UIColor.Signal.tertiaryBackground
|
||||
textFieldStack.axis = .horizontal
|
||||
textFieldStack.alignment = .center
|
||||
textFieldStack.distribution = .fill
|
||||
textFieldStack.spacing = 8
|
||||
textFieldStack.isLayoutMarginsRelativeArrangement = true
|
||||
textFieldStack.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
|
||||
|
||||
let addEmojiButton = UIButton(type: .system)
|
||||
addEmojiButton.setImage(UIImage(named: "emoji-plus"), for: .normal)
|
||||
addEmojiButton.tintColor = UIColor.Signal.secondaryLabel
|
||||
addEmojiButton.setContentHuggingPriority(.required, for: .horizontal)
|
||||
addEmojiButton.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
|
||||
let textField = UITextField()
|
||||
textField.placeholder = OWSLocalizedString(
|
||||
"MEMBER_LABEL_VIEW_PLACEHOLDER_TEXT",
|
||||
comment: "Placeholder text in text field where user can edit their member label.",
|
||||
)
|
||||
textField.font = .dynamicTypeBodyClamped
|
||||
|
||||
textFieldStack.addArrangedSubview(addEmojiButton)
|
||||
textFieldStack.addArrangedSubview(textField)
|
||||
stackView.addArrangedSubview(textFieldStack)
|
||||
stackView.setCustomSpacing(34, after: textFieldStack)
|
||||
|
||||
textFieldStack.translatesAutoresizingMaskIntoConstraints = false
|
||||
textFieldStack.heightAnchor.constraint(equalToConstant: 52).isActive = true
|
||||
|
||||
guard
|
||||
let mockConversationItem = buildMockConversationItem(),
|
||||
let previewContainer = messageBubblePreviewContainer(renderItem: mockConversationItem)
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
stackView.addArrangedSubview(previewContainer)
|
||||
|
||||
view.addSubview(stackView)
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
|
||||
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 22),
|
||||
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -22),
|
||||
])
|
||||
|
||||
}
|
||||
|
||||
private func buildMockConversationItem() -> CVRenderItem? {
|
||||
let db = DependenciesBridge.shared.db
|
||||
let attachmentContentValidator = DependenciesBridge.shared.attachmentContentValidator
|
||||
let tsAccountManager = DependenciesBridge.shared.tsAccountManager
|
||||
|
||||
let messageBody = db.write { tx in
|
||||
attachmentContentValidator.truncatedMessageBodyForInlining(
|
||||
MessageBody(text: OWSLocalizedString(
|
||||
"MEMBER_LABEL_VIEW_MESSAGE_PREVIEW_TEXT",
|
||||
comment: "Text shown in the preview message bubble when a user is editing their member label.",
|
||||
), ranges: .empty),
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
|
||||
guard
|
||||
let localAci = db.read(block: { tx in
|
||||
tsAccountManager.localIdentifiers(tx: tx)?.aci
|
||||
}),
|
||||
let secretParams = try? GroupSecretParams.generate()
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var groupModelBuilder = TSGroupModelBuilder(secretParams: secretParams)
|
||||
var groupMembershipBuilder = groupModelBuilder.groupMembership.asBuilder
|
||||
groupMembershipBuilder.setMemberLabel(label: "test123", aci: localAci)
|
||||
groupModelBuilder.groupMembership = groupMembershipBuilder.build()
|
||||
|
||||
guard let groupModel = try? groupModelBuilder.buildAsV2() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let mockGroupThread = MockGroupThread(groupModel: groupModel)
|
||||
let mockMessage = MockIncomingMessage(messageBody: messageBody, thread: mockGroupThread, authorAci: localAci)
|
||||
|
||||
let renderItem = db.read { tx in
|
||||
let threadAssociatedData = ThreadAssociatedData.fetchOrDefault(for: mockGroupThread, ignoreMissing: true, transaction: tx)
|
||||
|
||||
let conversationStyle = ConversationStyle(
|
||||
type: .`default`,
|
||||
thread: mockGroupThread,
|
||||
viewWidth: view.width - 44, // stack view padding
|
||||
hasWallpaper: false,
|
||||
isWallpaperPhoto: false,
|
||||
chatColor: PaletteChatColor.ultramarine.colorSetting,
|
||||
)
|
||||
|
||||
return CVLoader.buildStandaloneRenderItem(
|
||||
interaction: mockMessage,
|
||||
thread: mockGroupThread,
|
||||
threadAssociatedData: threadAssociatedData,
|
||||
conversationStyle: conversationStyle,
|
||||
spoilerState: SpoilerRenderState(),
|
||||
transaction: tx,
|
||||
)
|
||||
}
|
||||
return renderItem
|
||||
}
|
||||
|
||||
func messageBubblePreviewContainer(renderItem: CVRenderItem) -> UIView? {
|
||||
|
||||
let previewTitle = UILabel()
|
||||
previewTitle.text = OWSLocalizedString(
|
||||
"MEMBER_LABEL_PREVIEW_HEADING",
|
||||
comment: "Heading shown above the preview of a message bubble with the edited member label.",
|
||||
)
|
||||
previewTitle.font = .dynamicTypeBodyClamped.semibold()
|
||||
|
||||
let cellView = CVCellView()
|
||||
cellView.configure(renderItem: renderItem, componentDelegate: self)
|
||||
cellView.isCellVisible = true
|
||||
cellView.autoSetDimension(.height, toSize: renderItem.cellMeasurement.cellSize.height)
|
||||
cellView.autoSetDimension(.width, toSize: renderItem.cellMeasurement.cellSize.width)
|
||||
|
||||
let cellContainer = UIView()
|
||||
cellContainer.layer.cornerRadius = 27
|
||||
cellContainer.layer.masksToBounds = true
|
||||
cellContainer.backgroundColor = UIColor.Signal.tertiaryBackground
|
||||
|
||||
cellContainer.addSubview(cellView)
|
||||
cellView.autoPinEdge(toSuperviewEdge: .top, withInset: 20)
|
||||
cellView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 20)
|
||||
|
||||
let previewContainer = UIStackView()
|
||||
previewContainer.axis = .vertical
|
||||
previewContainer.spacing = 8
|
||||
previewContainer.addArrangedSubview(previewTitle)
|
||||
previewContainer.addArrangedSubview(cellContainer)
|
||||
|
||||
return previewContainer
|
||||
}
|
||||
|
||||
@objc
|
||||
private func didTapDone() {
|
||||
dismiss(animated: true)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func didTapCancel() {
|
||||
dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
extension MemberLabelViewController: CVComponentDelegate {
|
||||
var spoilerState: SignalUI.SpoilerRenderState {
|
||||
return SpoilerRenderState()
|
||||
}
|
||||
|
||||
func enqueueReload() {}
|
||||
|
||||
func enqueueReloadWithoutCaches() {}
|
||||
|
||||
func didTapBodyTextItem(_ item: CVTextLabel.Item) {}
|
||||
|
||||
func didLongPressBodyTextItem(_ item: CVTextLabel.Item) {}
|
||||
|
||||
func didTapSystemMessageItem(_ item: CVTextLabel.Item) {}
|
||||
|
||||
func didDoubleTapTextViewItem(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func didLongPressTextViewItem(
|
||||
_ cell: CVCell,
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
shouldAllowReply: Bool,
|
||||
) {}
|
||||
|
||||
func didLongPressMediaViewItem(
|
||||
_ cell: CVCell,
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
shouldAllowReply: Bool,
|
||||
) {}
|
||||
|
||||
func didLongPressQuote(
|
||||
_ cell: CVCell,
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
shouldAllowReply: Bool,
|
||||
) {}
|
||||
|
||||
func didLongPressSystemMessage(
|
||||
_ cell: CVCell,
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
) {}
|
||||
|
||||
func didLongPressSticker(
|
||||
_ cell: CVCell,
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
shouldAllowReply: Bool,
|
||||
) {}
|
||||
|
||||
func didLongPressPaymentMessage(
|
||||
_ cell: CVCell,
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
shouldAllowReply: Bool,
|
||||
) {}
|
||||
|
||||
func didLongPressPoll(
|
||||
_ cell: CVCell,
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
shouldAllowReply: Bool,
|
||||
) {}
|
||||
|
||||
func didTapPayment(_ payment: PaymentsHistoryItem) {}
|
||||
|
||||
func didChangeLongPress(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func didEndLongPress(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func didCancelLongPress(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
// MARK: -
|
||||
|
||||
func willBecomeVisibleWithFailedOrPendingDownloads(_ message: TSMessage) {}
|
||||
|
||||
func didTapFailedOrPendingDownloads(_ message: TSMessage) {}
|
||||
|
||||
func didCancelDownload(_ message: TSMessage, attachmentId: Attachment.IDType) {}
|
||||
|
||||
// MARK: -
|
||||
|
||||
func didTapReplyToItem(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func didTapSenderAvatar(_ interaction: TSInteraction) {}
|
||||
|
||||
func shouldAllowReplyForItem(_ itemViewModel: CVItemViewModelImpl) -> Bool { false }
|
||||
|
||||
func didTapReactions(
|
||||
reactionState: InteractionReactionState,
|
||||
message: TSMessage,
|
||||
) {}
|
||||
|
||||
func didTapTruncatedTextMessage(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func didTapShowEditHistory(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
var hasPendingMessageRequest: Bool { false }
|
||||
|
||||
func didTapUndownloadableMedia() {}
|
||||
|
||||
func didTapUndownloadableGenericFile() {}
|
||||
|
||||
func didTapUndownloadableOversizeText() {}
|
||||
|
||||
func didTapUndownloadableAudio() {}
|
||||
|
||||
func didTapUndownloadableSticker() {}
|
||||
|
||||
func didTapBrokenVideo() {}
|
||||
|
||||
func didTapBodyMedia(
|
||||
itemViewModel: CVItemViewModelImpl,
|
||||
attachmentStream: ReferencedAttachmentStream,
|
||||
imageView: UIView,
|
||||
) {}
|
||||
|
||||
func didTapGenericAttachment(
|
||||
_ attachment: CVComponentGenericAttachment,
|
||||
) -> CVAttachmentTapAction { .default }
|
||||
|
||||
func didTapQuotedReply(_ quotedReply: QuotedReplyModel) {}
|
||||
|
||||
func didTapLinkPreview(_ linkPreview: OWSLinkPreview) {}
|
||||
|
||||
func didTapContactShare(_ contactShare: ContactShareViewModel) {}
|
||||
|
||||
func didTapSendMessage(to phoneNumbers: [String]) {}
|
||||
|
||||
func didTapSendInvite(toContactShare contactShare: ContactShareViewModel) {}
|
||||
|
||||
func didTapAddToContacts(contactShare: ContactShareViewModel) {}
|
||||
|
||||
func didTapStickerPack(_ stickerPackInfo: StickerPackInfo) {}
|
||||
|
||||
func didTapGroupInviteLink(url: URL) {}
|
||||
|
||||
func didTapProxyLink(url: URL) {}
|
||||
|
||||
func didTapShowMessageDetail(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func willWrapGift(_ messageUniqueId: String) -> Bool { false }
|
||||
|
||||
func willShakeGift(_ messageUniqueId: String) -> Bool { false }
|
||||
|
||||
func willUnwrapGift(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func didTapGiftBadge(
|
||||
_ itemViewModel: CVItemViewModelImpl,
|
||||
profileBadge: ProfileBadge,
|
||||
isExpired: Bool,
|
||||
isRedeemed: Bool,
|
||||
) {}
|
||||
|
||||
func prepareMessageDetailForInteractivePresentation(_ itemViewModel: CVItemViewModelImpl) {}
|
||||
|
||||
func beginCellAnimation(maximumDuration: TimeInterval) -> EndCellAnimation {
|
||||
return {}
|
||||
}
|
||||
|
||||
var wallpaperBlurProvider: WallpaperBlurProvider? { nil }
|
||||
|
||||
var selectionState: CVSelectionState { CVSelectionState() }
|
||||
|
||||
func didTapPreviouslyVerifiedIdentityChange(_ address: SignalServiceAddress) {}
|
||||
|
||||
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress) {}
|
||||
|
||||
func didTapCorruptedMessage(_ message: TSErrorMessage) {}
|
||||
|
||||
func didTapSessionRefreshMessage(_ message: TSErrorMessage) {}
|
||||
|
||||
func didTapResendGroupUpdateForErrorMessage(_ errorMessage: TSErrorMessage) {}
|
||||
|
||||
func didTapShowFingerprint(_ address: SignalServiceAddress) {}
|
||||
|
||||
func didTapIndividualCall(_ call: TSCall) {}
|
||||
|
||||
func didTapLearnMoreMissedCallFromBlockedContact(_ call: TSCall) {}
|
||||
|
||||
func didTapGroupCall() {}
|
||||
|
||||
func didTapPendingOutgoingMessage(_ message: TSOutgoingMessage) {}
|
||||
|
||||
func didTapFailedOutgoingMessage(_ message: TSOutgoingMessage) {}
|
||||
|
||||
func didTapGroupMigrationLearnMore() {}
|
||||
|
||||
func didTapGroupInviteLinkPromotion(groupModel: TSGroupModel) {}
|
||||
|
||||
func didTapViewGroupDescription(newGroupDescription: String) {}
|
||||
|
||||
func didTapNameEducation(type: SafetyTipsType) {}
|
||||
|
||||
func didTapShowConversationSettings() {}
|
||||
|
||||
func didTapShowConversationSettingsAndShowMemberRequests() {}
|
||||
|
||||
func didTapBlockRequest(
|
||||
groupModel: TSGroupModelV2,
|
||||
requesterName: String,
|
||||
requesterAci: Aci,
|
||||
) {}
|
||||
|
||||
func didTapShowUpgradeAppUI() {}
|
||||
|
||||
func didTapUpdateSystemContact(
|
||||
_ address: SignalServiceAddress,
|
||||
newNameComponents: PersonNameComponents,
|
||||
) {}
|
||||
|
||||
func didTapPhoneNumberChange(aci: Aci, phoneNumberOld: String, phoneNumberNew: String) {}
|
||||
|
||||
func didTapViewOnceAttachment(_ interaction: TSInteraction) {}
|
||||
|
||||
func didTapViewOnceExpired(_ interaction: TSInteraction) {}
|
||||
|
||||
func didTapContactName(thread: TSContactThread) {}
|
||||
|
||||
func didTapUnknownThreadWarningGroup() {}
|
||||
func didTapUnknownThreadWarningContact() {}
|
||||
func didTapDeliveryIssueWarning(_ message: TSErrorMessage) {}
|
||||
|
||||
func didTapActivatePayments() {}
|
||||
func didTapSendPayment() {}
|
||||
|
||||
func didTapThreadMergeLearnMore(phoneNumber: String) {}
|
||||
|
||||
func didTapReportSpamLearnMore() {}
|
||||
|
||||
func didTapMessageRequestAcceptedOptions() {}
|
||||
|
||||
func didTapJoinCallLinkCall(callLink: CallLink) {}
|
||||
|
||||
func didTapViewVotes(poll: OWSPoll) {}
|
||||
|
||||
func didTapViewPoll(pollInteractionUniqueId: String) {}
|
||||
|
||||
func didTapVoteOnPoll(poll: OWSPoll, optionIndex: UInt32, isUnvote: Bool) {}
|
||||
|
||||
func didTapViewPinnedMessage(pinnedMessageUniqueId: String) {}
|
||||
}
|
||||
@ -896,8 +896,9 @@ extension ConversationSettingsViewController {
|
||||
"CONVERSATION_SETTINGS_MEMBER_TAG",
|
||||
comment: "Label for 'member label' action in conversation settings view.",
|
||||
),
|
||||
actionBlock: {
|
||||
print("Unimplemented!")
|
||||
actionBlock: { [weak self] in
|
||||
let memberLabelViewController = MemberLabelViewController()
|
||||
self?.present(OWSNavigationController(rootViewController: memberLabelViewController), animated: true)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
import LibSignalClient
|
||||
import SignalServiceKit
|
||||
public import SignalServiceKit
|
||||
import SignalUI
|
||||
|
||||
protocol MockConversationDelegate: AnyObject {
|
||||
@ -215,10 +215,23 @@ private class MockThread: TSContactThread {
|
||||
}
|
||||
}
|
||||
|
||||
public class MockGroupThread: TSGroupThread {
|
||||
override public var shouldBeSaved: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
override public var uniqueId: String { "MockGroupThread" }
|
||||
|
||||
override public func anyWillInsert(with transaction: DBWriteTransaction) {
|
||||
// no - op
|
||||
owsFailDebug("shouldn't save mock thread")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private class MockIncomingMessage: TSIncomingMessage {
|
||||
init(messageBody: ValidatedInlineMessageBody, thread: MockThread) {
|
||||
public class MockIncomingMessage: TSIncomingMessage {
|
||||
fileprivate init(messageBody: ValidatedInlineMessageBody, thread: MockThread) {
|
||||
let builder: TSIncomingMessageBuilder = .withDefaultValues(
|
||||
thread: thread,
|
||||
authorAci: thread.contactAddress.aci!,
|
||||
@ -227,18 +240,27 @@ private class MockIncomingMessage: TSIncomingMessage {
|
||||
super.init(incomingMessageWithBuilder: builder)
|
||||
}
|
||||
|
||||
override var shouldBeSaved: Bool {
|
||||
init(messageBody: ValidatedInlineMessageBody, thread: MockGroupThread, authorAci: Aci) {
|
||||
let builder: TSIncomingMessageBuilder = .withDefaultValues(
|
||||
thread: thread,
|
||||
authorAci: authorAci,
|
||||
messageBody: messageBody,
|
||||
)
|
||||
super.init(incomingMessageWithBuilder: builder)
|
||||
}
|
||||
|
||||
override public var shouldBeSaved: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
override func anyWillInsert(with transaction: DBWriteTransaction) {
|
||||
override public func anyWillInsert(with transaction: DBWriteTransaction) {
|
||||
owsFailDebug("shouldn't save mock message")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private class MockOutgoingMessage: TSOutgoingMessage {
|
||||
public class MockOutgoingMessage: TSOutgoingMessage {
|
||||
init(messageBody: ValidatedInlineMessageBody, thread: TSThread, transaction: DBReadTransaction) {
|
||||
let builder: TSOutgoingMessageBuilder = .withDefaultValues(thread: thread, messageBody: messageBody)
|
||||
super.init(
|
||||
@ -254,22 +276,22 @@ private class MockOutgoingMessage: TSOutgoingMessage {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override var shouldBeSaved: Bool {
|
||||
override public var shouldBeSaved: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
override func anyWillInsert(with transaction: DBWriteTransaction) {
|
||||
override public func anyWillInsert(with transaction: DBWriteTransaction) {
|
||||
owsFailDebug("shouldn't save mock message")
|
||||
}
|
||||
|
||||
override var messageState: TSOutgoingMessageState { .sent }
|
||||
override public var messageState: TSOutgoingMessageState { .sent }
|
||||
|
||||
override func readRecipientAddresses() -> [SignalServiceAddress] {
|
||||
override public func readRecipientAddresses() -> [SignalServiceAddress] {
|
||||
// makes message appear as read
|
||||
return [MockConversationView.mockAddress]
|
||||
}
|
||||
|
||||
override func recipientState(for recipientAddress: SignalServiceAddress) -> TSOutgoingMessageRecipientState? {
|
||||
override public func recipientState(for recipientAddress: SignalServiceAddress) -> TSOutgoingMessageRecipientState? {
|
||||
return TSOutgoingMessageRecipientState(
|
||||
status: .read,
|
||||
statusTimestamp: Date().ows_millisecondsSince1970,
|
||||
|
||||
@ -4987,6 +4987,21 @@
|
||||
/* Label for an action to add a member label */
|
||||
"MEMBER_LABEL_ADD" = "Add a Member Label";
|
||||
|
||||
/* Heading shown above the preview of a message bubble with the edited member label. */
|
||||
"MEMBER_LABEL_PREVIEW_HEADING" = "Preview";
|
||||
|
||||
/* Text shown in the preview message bubble when a user is editing their member label. */
|
||||
"MEMBER_LABEL_VIEW_MESSAGE_PREVIEW_TEXT" = "Hello!";
|
||||
|
||||
/* Placeholder text in text field where user can edit their member label. */
|
||||
"MEMBER_LABEL_VIEW_PLACEHOLDER_TEXT" = "Add your label";
|
||||
|
||||
/* Subtitle for a view where users can edit and preview their member label. */
|
||||
"MEMBER_LABEL_VIEW_SUBTITLE" = "Set a member label to describe yourself or your role in this group. Member labels are only visible within this group.";
|
||||
|
||||
/* Title for a view where users can edit and preview their member label. */
|
||||
"MEMBER_LABEL_VIEW_TITLE" = "Member Label";
|
||||
|
||||
/* Action sheet button title */
|
||||
"MESSAGE_ACTION_COPY_TEXT" = "Copy Message Text";
|
||||
|
||||
|
||||
@ -9,9 +9,10 @@ extension TSMessage {
|
||||
|
||||
/// Dangerous to use for uninserted messages; exposed only in the Signal target because most rendering
|
||||
/// uses already-inserted messages, obviating the concern.
|
||||
/// There are some exceptions to this, such as mock messages we insert for purely UI previewing purposes.
|
||||
public func hasRenderableContent(tx: DBReadTransaction) -> Bool {
|
||||
guard let rowId = self.sqliteRowId else {
|
||||
owsFailDebug("Checking renderable content for uninserted message!")
|
||||
owsAssertDebug(((self as? MockIncomingMessage) != nil) || ((self as? MockOutgoingMessage) != nil), "Checking renderable content for uninserted message")
|
||||
return TSMessageBuilder.hasRenderableContent(
|
||||
hasNonemptyBody: body?.nilIfEmpty != nil,
|
||||
hasBodyAttachmentsOrOversizeText: false,
|
||||
|
||||
@ -71,7 +71,7 @@ public class ThreadAssociatedData: NSObject, Codable, FetchableRecord, Persistab
|
||||
) -> ThreadAssociatedData {
|
||||
DependenciesBridge.shared.threadAssociatedDataStore.fetchOrDefault(
|
||||
for: threadUniqueId,
|
||||
ignoreMissing: ignoreMissing || CurrentAppContext().isRunningTests || threadUniqueId == "MockThread",
|
||||
ignoreMissing: ignoreMissing || CurrentAppContext().isRunningTests || threadUniqueId == "MockThread" || threadUniqueId == "MockGroupThread",
|
||||
tx: transaction,
|
||||
)
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ public class ThreadViewModel: NSObject {
|
||||
if let threadId = thread.grdbId?.int64Value {
|
||||
pinnedMessages = DependenciesBridge.shared.pinnedMessageManager.fetchPinnedMessagesForThread(threadId: threadId, tx: transaction)
|
||||
} else {
|
||||
owsFailDebug("missing thread Id")
|
||||
owsAssertDebug(thread.uniqueId == "MockThread" || thread.uniqueId == "MockGroupThread", "missing thread Id")
|
||||
pinnedMessages = []
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user