mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Story reporting
This commit is contained in:
parent
53aa40353a
commit
3ec2d62783
@ -2515,7 +2515,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
let isMuted = notificationSettings.storiesMuted == true
|
||||
items.append(.action(ContextMenuActionItem(text: isMuted ? "Notify" : "Not Notify", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Muted": "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor)
|
||||
return generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
|
@ -8667,6 +8667,28 @@ public extension Api.functions.stories {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.stories {
|
||||
static func report(userId: Api.InputUser, id: [Int32], reason: Api.ReportReason, message: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-916725654)
|
||||
userId.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(id.count))
|
||||
for item in id {
|
||||
serializeInt32(item, buffer: buffer, boxed: false)
|
||||
}
|
||||
reason.serialize(buffer, true)
|
||||
serializeString(message, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "stories.report", parameters: [("userId", String(describing: userId)), ("id", String(describing: id)), ("reason", String(describing: reason)), ("message", String(describing: message))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.stories {
|
||||
static func sendStory(flags: Int32, media: Api.InputMedia, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule], randomId: Int64, period: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
|
@ -170,6 +170,22 @@ func _internal_reportPeerMessages(account: Account, messageIds: [MessageId], rea
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
func _internal_reportPeerStory(account: Account, peerId: PeerId, storyId: Int32, reason: ReportReason, message: String) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) {
|
||||
return account.network.request(Api.functions.stories.report(userId: inputUser, id: [storyId], reason: reason.apiReason, message: message))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
func _internal_reportPeerReaction(account: Account, authorId: PeerId, messageId: MessageId) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> (Api.InputPeer, Api.InputPeer)? in
|
||||
guard let peer = transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) else {
|
||||
|
@ -231,6 +231,10 @@ public extension TelegramEngine {
|
||||
return _internal_reportPeerMessages(account: self.account, messageIds: messageIds, reason: reason, message: message)
|
||||
}
|
||||
|
||||
public func reportPeerStory(peerId: PeerId, storyId: Int32, reason: ReportReason, message: String) -> Signal<Void, NoError> {
|
||||
return _internal_reportPeerStory(account: self.account, peerId: peerId, storyId: storyId, reason: reason, message: message)
|
||||
}
|
||||
|
||||
public func reportPeerReaction(authorId: PeerId, messageId: MessageId) -> Signal<Never, NoError> {
|
||||
return _internal_reportPeerReaction(account: self.account, authorId: authorId, messageId: messageId)
|
||||
}
|
||||
|
@ -377,6 +377,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Stories/StorySetIndicatorComponent",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatAvatarNavigationNode",
|
||||
"//submodules/TelegramUI/Components/PeerReportScreen",
|
||||
"//submodules/Utils/VolumeButtons",
|
||||
"//submodules/ChatContextQuery",
|
||||
] + select({
|
||||
|
@ -968,6 +968,7 @@ final class MediaEditorScreenComponent: Component {
|
||||
})
|
||||
},
|
||||
forwardAction: nil,
|
||||
moreAction: nil,
|
||||
presentVoiceMessagesUnavailableTooltip: nil,
|
||||
audioRecorder: nil,
|
||||
videoRecordingStatus: nil,
|
||||
|
@ -264,7 +264,8 @@ final class StoryPreviewComponent: Component {
|
||||
attachmentAction: { },
|
||||
inputModeAction: nil,
|
||||
timeoutAction: nil,
|
||||
forwardAction: nil,
|
||||
forwardAction: {},
|
||||
moreAction: { _, _ in },
|
||||
presentVoiceMessagesUnavailableTooltip: nil,
|
||||
audioRecorder: nil,
|
||||
videoRecordingStatus: nil,
|
||||
|
@ -27,6 +27,7 @@ swift_library(
|
||||
"//submodules/ChatContextQuery",
|
||||
"//submodules/TextFormat",
|
||||
"//submodules/TelegramUI/Components/Stories/PeerListItemComponent",
|
||||
"//submodules/TelegramUI/Components/MoreHeaderButton",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -7,6 +7,7 @@ import ChatTextInputMediaRecordingButton
|
||||
import AccountContext
|
||||
import TelegramPresentationData
|
||||
import ChatPresentationInterfaceState
|
||||
import MoreHeaderButton
|
||||
|
||||
private extension MessageInputActionButtonComponent.Mode {
|
||||
var iconName: String? {
|
||||
@ -34,6 +35,7 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
case delete
|
||||
case attach
|
||||
case forward
|
||||
case more
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
@ -47,6 +49,7 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
public let updateMediaCancelFraction: (CGFloat) -> Void
|
||||
public let lockMediaRecording: () -> Void
|
||||
public let stopAndPreviewMediaRecording: () -> Void
|
||||
public let moreAction: (UIView, ContextGesture?) -> Void
|
||||
public let context: AccountContext
|
||||
public let theme: PresentationTheme
|
||||
public let strings: PresentationStrings
|
||||
@ -61,6 +64,7 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
updateMediaCancelFraction: @escaping (CGFloat) -> Void,
|
||||
lockMediaRecording: @escaping () -> Void,
|
||||
stopAndPreviewMediaRecording: @escaping () -> Void,
|
||||
moreAction: @escaping (UIView, ContextGesture?) -> Void,
|
||||
context: AccountContext,
|
||||
theme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
@ -74,6 +78,7 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
self.updateMediaCancelFraction = updateMediaCancelFraction
|
||||
self.lockMediaRecording = lockMediaRecording
|
||||
self.stopAndPreviewMediaRecording = stopAndPreviewMediaRecording
|
||||
self.moreAction = moreAction
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
@ -107,6 +112,7 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
public final class View: HighlightTrackingButton {
|
||||
private var micButton: ChatTextInputMediaRecordingButton?
|
||||
private let sendIconView: UIImageView
|
||||
private var moreButton: MoreHeaderButton?
|
||||
|
||||
private var component: MessageInputActionButtonComponent?
|
||||
private weak var componentState: EmptyComponentState?
|
||||
@ -228,20 +234,47 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
if self.moreButton == nil {
|
||||
let moreButton = MoreHeaderButton(color: .white)
|
||||
self.moreButton = moreButton
|
||||
self.addSubnode(moreButton)
|
||||
|
||||
moreButton.isUserInteractionEnabled = true
|
||||
moreButton.setContent(.more(MoreHeaderButton.optionsCircleImage(color: .white)))
|
||||
moreButton.onPressed = { [weak self] in
|
||||
guard let self, let component = self.component, let moreButton = self.moreButton else {
|
||||
return
|
||||
}
|
||||
moreButton.play()
|
||||
component.moreAction(moreButton.view, nil)
|
||||
}
|
||||
moreButton.contextAction = { [weak self] sourceNode, gesture in
|
||||
guard let self, let component = self.component, let moreButton = self.moreButton else {
|
||||
return
|
||||
}
|
||||
moreButton.play()
|
||||
component.moreAction(moreButton.view, gesture)
|
||||
}
|
||||
self.moreButton = moreButton
|
||||
self.addSubnode(moreButton)
|
||||
}
|
||||
|
||||
var sendAlpha: CGFloat = 0.0
|
||||
var microphoneAlpha: CGFloat = 0.0
|
||||
var moreAlpha: CGFloat = 0.0
|
||||
switch component.mode {
|
||||
case .none:
|
||||
break
|
||||
case .send, .apply, .attach, .delete, .forward:
|
||||
sendAlpha = 1.0
|
||||
case .more:
|
||||
moreAlpha = 1.0
|
||||
case .videoInput, .voiceInput:
|
||||
microphoneAlpha = 1.0
|
||||
case .unavailableVoiceInput:
|
||||
microphoneAlpha = 0.4
|
||||
}
|
||||
|
||||
|
||||
if self.sendIconView.image == nil || previousComponent?.mode.iconName != component.mode.iconName {
|
||||
if let iconName = component.mode.iconName {
|
||||
self.sendIconView.image = generateTintedImage(image: UIImage(bundleImageName: iconName), color: .white)
|
||||
@ -310,6 +343,17 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
transition.setBounds(view: self.sendIconView, bounds: CGRect(origin: CGPoint(), size: iconFrame.size))
|
||||
}
|
||||
|
||||
if let moreButton = self.moreButton {
|
||||
let buttonSize = CGSize(width: 32.0, height: 44.0)
|
||||
moreButton.setContent(.more(MoreHeaderButton.optionsCircleImage(color: .white)))
|
||||
let moreFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - buttonSize.width) * 0.5), y: floorToScreenPixels((availableSize.height - buttonSize.height) * 0.5)), size: buttonSize)
|
||||
transition.setPosition(view: moreButton.view, position: moreFrame.center)
|
||||
transition.setBounds(view: moreButton.view, bounds: CGRect(origin: CGPoint(), size: moreFrame.size))
|
||||
|
||||
transition.setAlpha(view: moreButton.view, alpha: moreAlpha)
|
||||
transition.setScale(view: moreButton.view, scale: moreAlpha == 0.0 ? 0.01 : 1.0)
|
||||
}
|
||||
|
||||
if let micButton = self.micButton {
|
||||
if themeUpdated {
|
||||
micButton.updateTheme(theme: component.theme)
|
||||
@ -325,7 +369,7 @@ public final class MessageInputActionButtonComponent: Component {
|
||||
|
||||
if previousComponent?.mode != component.mode {
|
||||
switch component.mode {
|
||||
case .none, .send, .apply, .voiceInput, .attach, .delete, .forward, .unavailableVoiceInput:
|
||||
case .none, .send, .apply, .voiceInput, .attach, .delete, .forward, .unavailableVoiceInput, .more:
|
||||
micButton.updateMode(mode: .audio, animated: !transition.animation.isImmediate)
|
||||
case .videoInput:
|
||||
micButton.updateMode(mode: .video, animated: !transition.animation.isImmediate)
|
||||
|
@ -55,6 +55,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
public let inputModeAction: (() -> Void)?
|
||||
public let timeoutAction: ((UIView) -> Void)?
|
||||
public let forwardAction: (() -> Void)?
|
||||
public let moreAction: ((UIView, ContextGesture?) -> Void)?
|
||||
public let presentVoiceMessagesUnavailableTooltip: ((UIView) -> Void)?
|
||||
public let audioRecorder: ManagedAudioRecorder?
|
||||
public let videoRecordingStatus: InstantVideoControllerRecordingStatus?
|
||||
@ -87,6 +88,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
inputModeAction: (() -> Void)?,
|
||||
timeoutAction: ((UIView) -> Void)?,
|
||||
forwardAction: (() -> Void)?,
|
||||
moreAction: ((UIView, ContextGesture?) -> Void)?,
|
||||
presentVoiceMessagesUnavailableTooltip: ((UIView) -> Void)?,
|
||||
audioRecorder: ManagedAudioRecorder?,
|
||||
videoRecordingStatus: InstantVideoControllerRecordingStatus?,
|
||||
@ -118,6 +120,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
self.inputModeAction = inputModeAction
|
||||
self.timeoutAction = timeoutAction
|
||||
self.forwardAction = forwardAction
|
||||
self.moreAction = moreAction
|
||||
self.presentVoiceMessagesUnavailableTooltip = presentVoiceMessagesUnavailableTooltip
|
||||
self.audioRecorder = audioRecorder
|
||||
self.videoRecordingStatus = videoRecordingStatus
|
||||
@ -189,6 +192,9 @@ public final class MessageInputPanelComponent: Component {
|
||||
if (lhs.forwardAction == nil) != (rhs.forwardAction == nil) {
|
||||
return false
|
||||
}
|
||||
if (lhs.moreAction == nil) != (rhs.moreAction == nil) {
|
||||
return false
|
||||
}
|
||||
if lhs.hideKeyboard != rhs.hideKeyboard {
|
||||
return false
|
||||
}
|
||||
@ -498,7 +504,11 @@ public final class MessageInputPanelComponent: Component {
|
||||
|
||||
if component.attachmentAction != nil {
|
||||
let attachmentButtonMode: MessageInputActionButtonComponent.Mode
|
||||
attachmentButtonMode = .attach
|
||||
if !self.textFieldExternalState.isEditing && component.moreAction != nil {
|
||||
attachmentButtonMode = .more
|
||||
} else {
|
||||
attachmentButtonMode = .attach
|
||||
}
|
||||
|
||||
let attachmentButtonSize = self.attachmentButton.update(
|
||||
transition: transition,
|
||||
@ -526,6 +536,12 @@ public final class MessageInputPanelComponent: Component {
|
||||
},
|
||||
stopAndPreviewMediaRecording: {
|
||||
},
|
||||
moreAction: { [weak self] view, gesture in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.moreAction?(view, gesture)
|
||||
},
|
||||
context: component.context,
|
||||
theme: component.theme,
|
||||
strings: component.strings,
|
||||
@ -709,6 +725,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
}
|
||||
component.stopAndPreviewMediaRecording?()
|
||||
},
|
||||
moreAction: { _, _ in },
|
||||
context: component.context,
|
||||
theme: component.theme,
|
||||
strings: component.strings,
|
||||
|
35
submodules/TelegramUI/Components/PeerReportScreen/BUILD
Normal file
35
submodules/TelegramUI/Components/PeerReportScreen/BUILD
Normal file
@ -0,0 +1,35 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "PeerReportScreen",
|
||||
module_name = "PeerReportScreen",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/ContextUI",
|
||||
"//submodules/UndoUI",
|
||||
"//submodules/PresentationDataUtils",
|
||||
"//submodules/AlertUI",
|
||||
"//submodules/AppBundle",
|
||||
"//submodules/TelegramUIPreferences",
|
||||
"//submodules/TelegramPermissionsUI",
|
||||
"//submodules/Markdown",
|
||||
"//submodules/AnimatedStickerNode",
|
||||
"//submodules/TelegramAnimatedStickerNode",
|
||||
"//submodules/ShareController",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
@ -19,6 +19,7 @@ public enum PeerReportSubject {
|
||||
case peer(EnginePeer.Id)
|
||||
case messages([EngineMessage.Id])
|
||||
case profilePhoto(EnginePeer.Id, Int64)
|
||||
case story(EnginePeer.Id, Int32)
|
||||
}
|
||||
|
||||
public enum PeerReportOption {
|
||||
@ -33,10 +34,34 @@ public enum PeerReportOption {
|
||||
case other
|
||||
}
|
||||
|
||||
public func presentPeerReportOptions(context: AccountContext, parent: ViewController, contextController: ContextControllerProtocol?, backAction: ((ContextControllerProtocol) -> Void)? = nil, subject: PeerReportSubject, options: [PeerReportOption] = [.spam, .violence, .pornography, .childAbuse, .copyright, .other], passthrough: Bool = false, completion: @escaping (ReportReason?, Bool) -> Void) {
|
||||
public func presentPeerReportOptions(
|
||||
context: AccountContext,
|
||||
parent: ViewController,
|
||||
contextController: ContextControllerProtocol?,
|
||||
backAction: ((ContextControllerProtocol) -> Void)? = nil,
|
||||
subject: PeerReportSubject,
|
||||
options: [PeerReportOption] = [.spam, .violence, .pornography, .childAbuse, .copyright, .other],
|
||||
passthrough: Bool = false,
|
||||
forceTheme: PresentationTheme? = nil,
|
||||
isDetailedReportingVisible: ((Bool) -> Void)? = nil,
|
||||
completion: @escaping (ReportReason?, Bool) -> Void
|
||||
) {
|
||||
if let contextController = contextController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
var presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
if let forceTheme {
|
||||
presentationData = presentationData.withUpdated(theme: forceTheme)
|
||||
}
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
if let _ = backAction {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconPosition: .left, action: { (c, _) in
|
||||
c.popItems()
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
|
||||
for option in options {
|
||||
let title: String
|
||||
let color: ContextMenuActionItemTextColor = .primary
|
||||
@ -73,8 +98,6 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
items.append(.action(ContextMenuActionItem(text: title, textColor: color, icon: { theme in
|
||||
return generateTintedImage(image: icon, color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak parent] _, f in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let reportReason: ReportReason
|
||||
switch option {
|
||||
case .spam:
|
||||
@ -114,36 +137,46 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
completion(reportReason, true)
|
||||
} else {
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
let _ = (context.engine.peers.reportPeer(peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
case let .messages(messageIds):
|
||||
let _ = (context.engine.peers.reportPeerMessages(messageIds: messageIds, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
case let .profilePhoto(peerId, _):
|
||||
let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
case let .peer(peerId):
|
||||
let _ = (context.engine.peers.reportPeer(peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
case let .messages(messageIds):
|
||||
let _ = (context.engine.peers.reportPeerMessages(messageIds: messageIds, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
case let .profilePhoto(peerId, _):
|
||||
let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
case let .story(peerId, storyId):
|
||||
let _ = (context.engine.peers.reportPeerStory(peerId: peerId, storyId: storyId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, false)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isDetailedReportingVisible?(true)
|
||||
let controller = ActionSheetController(presentationData: presentationData, allowInputInset: true)
|
||||
controller.dismissed = { _ in
|
||||
isDetailedReportingVisible?(false)
|
||||
}
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
var message = ""
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ReportPeerHeaderActionSheetItem(context: context, text: presentationData.strings.Report_AdditionalDetailsText))
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: context, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: context, theme: presentationData.theme, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
message = text
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Report_Report, color: .accent, font: .bold, enabled: true, action: {
|
||||
@ -154,22 +187,16 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissAction()
|
||||
})])
|
||||
])
|
||||
parent?.present(controller, in: .window(.root))
|
||||
}
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
}
|
||||
if let backAction = backAction {
|
||||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconPosition: .left, action: { (c, _) in
|
||||
backAction(c)
|
||||
})))
|
||||
}
|
||||
contextController.setItems(.single(ContextController.Items(content: .list(items))), minHeight: nil)
|
||||
contextController.pushItems(items: .single(ContextController.Items(content: .list(items))))
|
||||
} else {
|
||||
contextController?.dismiss(completion: nil)
|
||||
parent.view.endEditing(true)
|
||||
@ -246,24 +273,30 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
completion(reportReason, true)
|
||||
} else {
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
let _ = (context.engine.peers.reportPeer(peerId: peerId, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, true)
|
||||
})
|
||||
case let .messages(messageIds):
|
||||
let _ = (context.engine.peers.reportPeerMessages(messageIds: messageIds, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, true)
|
||||
})
|
||||
case let .profilePhoto(peerId, _):
|
||||
let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, true)
|
||||
})
|
||||
case let .peer(peerId):
|
||||
let _ = (context.engine.peers.reportPeer(peerId: peerId, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, true)
|
||||
})
|
||||
case let .messages(messageIds):
|
||||
let _ = (context.engine.peers.reportPeerMessages(messageIds: messageIds, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, true)
|
||||
})
|
||||
case let .profilePhoto(peerId, _):
|
||||
let _ = (context.engine.peers.reportPeerPhoto(peerId: peerId, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, true)
|
||||
})
|
||||
case let .story(peerId, storyId):
|
||||
let _ = (context.engine.peers.reportPeerStory(peerId: peerId, storyId: storyId, reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
displaySuccess()
|
||||
completion(nil, true)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -276,7 +309,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
var message = ""
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ReportPeerHeaderActionSheetItem(context: context, text: presentationData.strings.Report_AdditionalDetailsText))
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: context, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: context, theme: presentationData.theme, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
message = text
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Report_Report, color: .accent, font: .bold, enabled: true, action: {
|
@ -10,17 +10,19 @@ import AppBundle
|
||||
|
||||
public final class ReportPeerDetailsActionSheetItem: ActionSheetItem {
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let placeholderText: String
|
||||
let textUpdated: (String) -> Void
|
||||
|
||||
public init(context: AccountContext, placeholderText: String, textUpdated: @escaping (String) -> Void) {
|
||||
public init(context: AccountContext, theme: PresentationTheme, placeholderText: String, textUpdated: @escaping (String) -> Void) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.placeholderText = placeholderText
|
||||
self.textUpdated = textUpdated
|
||||
}
|
||||
|
||||
public func node(theme: ActionSheetControllerTheme) -> ActionSheetItemNode {
|
||||
return ReportPeerDetailsActionSheetItemNode(theme: theme, context: self.context, placeholderText: self.placeholderText, textUpdated: self.textUpdated)
|
||||
return ReportPeerDetailsActionSheetItemNode(theme: theme, presentationTheme: self.theme, context: self.context, placeholderText: self.placeholderText, textUpdated: self.textUpdated)
|
||||
}
|
||||
|
||||
public func updateNode(_ node: ActionSheetItemNode) {
|
||||
@ -34,11 +36,10 @@ private final class ReportPeerDetailsActionSheetItemNode: ActionSheetItemNode {
|
||||
|
||||
private let accessibilityArea: AccessibilityAreaNode
|
||||
|
||||
init(theme: ActionSheetControllerTheme, context: AccountContext, placeholderText: String, textUpdated: @escaping (String) -> Void) {
|
||||
init(theme: ActionSheetControllerTheme, presentationTheme: PresentationTheme, context: AccountContext, placeholderText: String, textUpdated: @escaping (String) -> Void) {
|
||||
self.theme = theme
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.inputFieldNode = ShareInputFieldNode(theme: ShareInputFieldNodeTheme(presentationTheme: presentationData.theme), placeholder: placeholderText)
|
||||
self.inputFieldNode = ShareInputFieldNode(theme: ShareInputFieldNodeTheme(presentationTheme: presentationTheme), placeholder: placeholderText)
|
||||
|
||||
self.accessibilityArea = AccessibilityAreaNode()
|
||||
|
@ -64,6 +64,7 @@ swift_library(
|
||||
"//submodules/UrlEscaping",
|
||||
"//submodules/OverlayStatusController",
|
||||
"//submodules/Utils/VolumeButtons",
|
||||
"//submodules/TelegramUI/Components/PeerReportScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -120,12 +120,17 @@ public final class StoryContentItemSlice {
|
||||
public final class StoryContentContextState {
|
||||
public final class AdditionalPeerData: Equatable {
|
||||
public static func == (lhs: StoryContentContextState.AdditionalPeerData, rhs: StoryContentContextState.AdditionalPeerData) -> Bool {
|
||||
return lhs.areVoiceMessagesAvailable == rhs.areVoiceMessagesAvailable
|
||||
return lhs.isMuted == rhs.isMuted && lhs.areVoiceMessagesAvailable == rhs.areVoiceMessagesAvailable
|
||||
}
|
||||
|
||||
public let isMuted: Bool
|
||||
public let areVoiceMessagesAvailable: Bool
|
||||
|
||||
public init(areVoiceMessagesAvailable: Bool) {
|
||||
public init(
|
||||
isMuted: Bool,
|
||||
areVoiceMessagesAvailable: Bool
|
||||
) {
|
||||
self.isMuted = isMuted
|
||||
self.areVoiceMessagesAvailable = areVoiceMessagesAvailable
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import ShareWithPeersScreen
|
||||
import PlainButtonComponent
|
||||
import TooltipUI
|
||||
import PresentationDataUtils
|
||||
import PeerReportScreen
|
||||
|
||||
public final class StoryItemSetContainerComponent: Component {
|
||||
public final class ExternalState {
|
||||
@ -265,6 +266,8 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
weak var contextController: ContextController?
|
||||
weak var privacyController: ShareWithPeersScreen?
|
||||
|
||||
var isReporting: Bool = false
|
||||
|
||||
var component: StoryItemSetContainerComponent?
|
||||
weak var state: EmptyComponentState?
|
||||
|
||||
@ -552,6 +555,9 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
if self.privacyController != nil {
|
||||
return true
|
||||
}
|
||||
if self.isReporting {
|
||||
return true
|
||||
}
|
||||
if self.isEditingStory {
|
||||
return true
|
||||
}
|
||||
@ -1167,6 +1173,95 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
}
|
||||
self.sendMessageContext.performShareAction(view: self)
|
||||
} : nil,
|
||||
moreAction: { [weak self] sourceView, gesture in
|
||||
guard let self, let component = self.component, let controller = component.controller() else {
|
||||
return
|
||||
}
|
||||
|
||||
component.controller()?.forEachController { c in
|
||||
if let c = c as? UndoOverlayController {
|
||||
c.dismiss()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme)
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: component.slice.additionalPeerData.isMuted ? "Notify" : "Not Notify", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: component.slice.additionalPeerData.isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
a(.default)
|
||||
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = component.context.engine.peers.togglePeerStoriesMuted(peerId: component.slice.peer.id).start()
|
||||
})))
|
||||
|
||||
var isHidden = false
|
||||
if case let .user(user) = component.slice.peer, let storiesHidden = user.storiesHidden {
|
||||
isHidden = storiesHidden
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: isHidden ? "Unhide \(component.slice.peer.compactDisplayTitle)" : "Hide \(component.slice.peer.compactDisplayTitle)", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: component.slice.item.storyItem.isPinned ? "Chat/Context Menu/Archive" : "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
a(.default)
|
||||
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = component.context.engine.peers.updatePeerStoriesHidden(id: component.slice.peer.id, isHidden: true)
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: "Report", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Report"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, a in
|
||||
guard let self, let component = self.component, let controller = component.controller() else {
|
||||
return
|
||||
}
|
||||
|
||||
let options: [PeerReportOption] = [.spam, .violence, .pornography, .childAbuse, .copyright, .illegalDrugs, .personalDetails, .other]
|
||||
presentPeerReportOptions(
|
||||
context: component.context,
|
||||
parent: controller,
|
||||
contextController: c,
|
||||
backAction: { _ in },
|
||||
subject: .story(component.slice.peer.id, component.slice.item.storyItem.id),
|
||||
options: options,
|
||||
passthrough: true,
|
||||
forceTheme: defaultDarkPresentationTheme,
|
||||
isDetailedReportingVisible: { [weak self] isReporting in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isReporting = isReporting
|
||||
self.updateIsProgressPaused()
|
||||
},
|
||||
completion: { [weak self] reason, _ in
|
||||
guard let self, let component = self.component, let controller = component.controller(), let reason else {
|
||||
return
|
||||
}
|
||||
let _ = component.context.engine.peers.reportPeerStory(peerId: component.slice.peer.id, storyId: component.slice.item.storyItem.id, reason: reason, message: "").start()
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .emoji(name: "PoliceCar", text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
)
|
||||
})))
|
||||
|
||||
let contextController = ContextController(account: component.context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
contextController.dismissed = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.contextController = nil
|
||||
self.updateIsProgressPaused()
|
||||
}
|
||||
self.contextController = contextController
|
||||
self.updateIsProgressPaused()
|
||||
controller.present(contextController, in: .window(.root))
|
||||
},
|
||||
presentVoiceMessagesUnavailableTooltip: { [weak self] view in
|
||||
guard let self, let component = self.component, self.voiceMessagesRestrictedTooltipController == nil else {
|
||||
return
|
||||
@ -1337,6 +1432,13 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
component.controller()?.forEachController { c in
|
||||
if let c = c as? UndoOverlayController {
|
||||
c.dismiss()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
let additionalCount = component.slice.item.storyItem.privacy?.additionallyIncludePeers.count ?? 0
|
||||
@ -1392,14 +1494,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
|
||||
component.controller()?.forEachController { c in
|
||||
if let c = c as? UndoOverlayController {
|
||||
c.dismiss()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: component.slice.item.storyItem.isPinned ? "Remove from profile" : "Save to profile", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: component.slice.item.storyItem.isPinned ? "Chat/Context Menu/Check" : "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
|
@ -51,7 +51,7 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
PostboxViewKey.basicPeer(peerId),
|
||||
PostboxViewKey.cachedPeerData(peerId: peerId),
|
||||
PostboxViewKey.storiesState(key: .peer(peerId)),
|
||||
PostboxViewKey.storyItems(peerId: peerId)
|
||||
PostboxViewKey.storyItems(peerId: peerId),
|
||||
]
|
||||
if peerId == context.account.peerId {
|
||||
inputKeys.append(PostboxViewKey.storiesState(key: .local))
|
||||
@ -60,10 +60,11 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
self.currentFocusedIdUpdatedPromise.get(),
|
||||
context.account.postbox.combinedView(
|
||||
keys: inputKeys
|
||||
)
|
||||
),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global())
|
||||
)
|
||||
|> mapToSignal { _, views -> Signal<(CombinedView, [PeerId: Peer]), NoError> in
|
||||
return context.account.postbox.transaction { transaction -> (CombinedView, [PeerId: Peer]) in
|
||||
|> mapToSignal { _, views, globalNotificationSettings -> Signal<(CombinedView, [PeerId: Peer], EngineGlobalNotificationSettings), NoError> in
|
||||
return context.account.postbox.transaction { transaction -> (CombinedView, [PeerId: Peer], EngineGlobalNotificationSettings) in
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
if let itemsView = views.views[PostboxViewKey.storyItems(peerId: peerId)] as? StoryItemsView {
|
||||
for item in itemsView.items {
|
||||
@ -78,10 +79,10 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
return (views, peers)
|
||||
return (views, peers, globalNotificationSettings)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] views, peers in
|
||||
|> deliverOnMainQueue).start(next: { [weak self] views, peers, globalNotificationSettings in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -99,10 +100,15 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
}
|
||||
let additionalPeerData: StoryContentContextState.AdditionalPeerData
|
||||
if let cachedPeerDataView = views.views[PostboxViewKey.cachedPeerData(peerId: peerId)] as? CachedPeerDataView, let cachedUserData = cachedPeerDataView.cachedPeerData as? CachedUserData {
|
||||
let _ = cachedUserData
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(areVoiceMessagesAvailable: cachedUserData.voiceMessagesAvailable)
|
||||
var isMuted = false
|
||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings, let storiesMuted = notificationSettings.storiesMuted {
|
||||
isMuted = storiesMuted
|
||||
} else {
|
||||
isMuted = globalNotificationSettings.privateChats.storiesMuted
|
||||
}
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(isMuted: isMuted, areVoiceMessagesAvailable: cachedUserData.voiceMessagesAvailable)
|
||||
} else {
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(areVoiceMessagesAvailable: true)
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(isMuted: true, areVoiceMessagesAvailable: true)
|
||||
}
|
||||
let state = stateView.value?.get(Stories.PeerState.self)
|
||||
|
||||
@ -874,7 +880,9 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
|
||||
self.storyDisposable = (combineLatest(queue: .mainQueue(),
|
||||
context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: storyId.peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable(id: storyId.peerId)
|
||||
TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable(id: storyId.peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: storyId.peerId),
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global()
|
||||
),
|
||||
context.account.postbox.transaction { transaction -> (Stories.StoredItem?, [PeerId: Peer]) in
|
||||
guard let item = transaction.getStory(id: storyId)?.get(Stories.StoredItem.self) else {
|
||||
@ -893,15 +901,23 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
|
||||
return (item, peers)
|
||||
}
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerAndVoiceMessages, itemAndPeers in
|
||||
|> deliverOnMainQueue).start(next: { [weak self] data, itemAndPeers in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let (peer, areVoiceMessagesAvailable) = peerAndVoiceMessages
|
||||
let (peer, areVoiceMessagesAvailable, notificationSettings, globalNotificationSettings) = data
|
||||
let (item, peers) = itemAndPeers
|
||||
|
||||
var isMuted = false
|
||||
if let storiesMuted = notificationSettings.storiesMuted {
|
||||
isMuted = storiesMuted
|
||||
} else {
|
||||
isMuted = globalNotificationSettings.privateChats.storiesMuted
|
||||
}
|
||||
|
||||
let additionalPeerData = StoryContentContextState.AdditionalPeerData(
|
||||
isMuted: isMuted,
|
||||
areVoiceMessagesAvailable: areVoiceMessagesAvailable
|
||||
)
|
||||
|
||||
@ -1039,19 +1055,30 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
|
||||
self.storyDisposable = (combineLatest(queue: .mainQueue(),
|
||||
context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable(id: peerId)
|
||||
TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peerId),
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global()
|
||||
),
|
||||
listContext.state,
|
||||
self.focusedIdUpdated.get()
|
||||
)
|
||||
//|> delay(0.4, queue: .mainQueue())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerAndVoiceMessages, state, _ in
|
||||
|> deliverOnMainQueue).start(next: { [weak self] data, state, _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let (peer, areVoiceMessagesAvailable) = peerAndVoiceMessages
|
||||
let (peer, areVoiceMessagesAvailable, notificationSettings, globalNotificationSettings) = data
|
||||
|
||||
var isMuted = false
|
||||
if let storiesMuted = notificationSettings.storiesMuted {
|
||||
isMuted = storiesMuted
|
||||
} else {
|
||||
isMuted = globalNotificationSettings.privateChats.storiesMuted
|
||||
}
|
||||
|
||||
let additionalPeerData = StoryContentContextState.AdditionalPeerData(
|
||||
isMuted: isMuted,
|
||||
areVoiceMessagesAvailable: areVoiceMessagesAvailable
|
||||
)
|
||||
|
||||
|
@ -100,6 +100,7 @@ import MoreHeaderButton
|
||||
import VolumeButtons
|
||||
import ChatAvatarNavigationNode
|
||||
import ChatContextQuery
|
||||
import PeerReportScreen
|
||||
|
||||
#if DEBUG
|
||||
import os.signpost
|
||||
@ -8249,7 +8250,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var message = ""
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ReportPeerHeaderActionSheetItem(context: strongSelf.context, text: presentationData.strings.Report_AdditionalDetailsText))
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: strongSelf.context, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: strongSelf.context, theme: presentationData.theme, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
message = text
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Report_Report, color: .accent, font: .bold, enabled: true, action: {
|
||||
|
@ -91,6 +91,7 @@ import PeerInfoStoryGridScreen
|
||||
import StoryContainerScreen
|
||||
import StoryContentComponent
|
||||
import ChatAvatarNavigationNode
|
||||
import PeerReportScreen
|
||||
|
||||
enum PeerInfoAvatarEditingMode {
|
||||
case generic
|
||||
|
Loading…
x
Reference in New Issue
Block a user