mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Moderation sheet improvements
This commit is contained in:
parent
b4e1173279
commit
2d65b3d90b
@ -11896,6 +11896,7 @@ Sorry for the inconvenience.";
|
|||||||
"BusinessLink.ErrorExpired" = "Link Expired";
|
"BusinessLink.ErrorExpired" = "Link Expired";
|
||||||
|
|
||||||
"WebApp.AlertBiometryAccessText" = "Do you want to allow %@ to use Face ID?";
|
"WebApp.AlertBiometryAccessText" = "Do you want to allow %@ to use Face ID?";
|
||||||
|
"WebApp.AlertBiometryAccessTouchIDText" = "Do you want to allow %@ to use Touch ID?";
|
||||||
|
|
||||||
"StoryList.SubtitleArchived_1" = "1 archived post";
|
"StoryList.SubtitleArchived_1" = "1 archived post";
|
||||||
"StoryList.SubtitleArchived_any" = "%d archived posts";
|
"StoryList.SubtitleArchived_any" = "%d archived posts";
|
||||||
@ -12089,3 +12090,6 @@ Sorry for the inconvenience.";
|
|||||||
"Map.SharingLocation" = "Sharing Location...";
|
"Map.SharingLocation" = "Sharing Location...";
|
||||||
|
|
||||||
"Channel.AdminLog.Settings" = "Settings";
|
"Channel.AdminLog.Settings" = "Settings";
|
||||||
|
|
||||||
|
"ChannelProfile.AboutActionCopy" = "Copy";
|
||||||
|
"ChannelProfile.ToastAboutCopied" = "Copied to clipboard.";
|
||||||
|
@ -5,5 +5,6 @@
|
|||||||
|
|
||||||
- (void)setPositiveContentColor:(UIColor *)color;
|
- (void)setPositiveContentColor:(UIColor *)color;
|
||||||
- (void)setNegativeContentColor:(UIColor *)color;
|
- (void)setNegativeContentColor:(UIColor *)color;
|
||||||
|
- (void)updateIsLocked:(bool)isLocked;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -30,8 +30,10 @@ static const void *positionChangedKey = &positionChangedKey;
|
|||||||
@interface TGIconSwitchView () {
|
@interface TGIconSwitchView () {
|
||||||
UIImageView *_offIconView;
|
UIImageView *_offIconView;
|
||||||
UIImageView *_onIconView;
|
UIImageView *_onIconView;
|
||||||
|
UIColor *_negativeContentColor;
|
||||||
|
|
||||||
bool _stateIsOn;
|
bool _stateIsOn;
|
||||||
|
bool _isLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -60,13 +62,8 @@ static const void *positionChangedKey = &positionChangedKey;
|
|||||||
object_setClass(handleView.layer, subclass);
|
object_setClass(handleView.layer, subclass);
|
||||||
});
|
});
|
||||||
|
|
||||||
CGPoint offset = CGPointZero;
|
[self updateIconFrame];
|
||||||
if (iosMajorVersion() >= 12) {
|
|
||||||
offset = CGPointMake(-7.0, -3.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
_offIconView.frame = CGRectOffset(_offIconView.bounds, TGScreenPixelFloor(21.5f) + offset.x, TGScreenPixelFloor(14.5f) + offset.y);
|
|
||||||
_onIconView.frame = CGRectOffset(_onIconView.bounds, 20.0f + offset.x, 15.0f + offset.y);
|
|
||||||
[handleView addSubview:_onIconView];
|
[handleView addSubview:_onIconView];
|
||||||
[handleView addSubview:_offIconView];
|
[handleView addSubview:_offIconView];
|
||||||
|
|
||||||
@ -92,6 +89,21 @@ static const void *positionChangedKey = &positionChangedKey;
|
|||||||
[self updateState:on animated:animated force:true];
|
[self updateState:on animated:animated force:true];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)updateIconFrame {
|
||||||
|
CGPoint offset = CGPointZero;
|
||||||
|
if (iosMajorVersion() >= 12) {
|
||||||
|
offset = CGPointMake(-7.0, -3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isLocked) {
|
||||||
|
_offIconView.frame = CGRectOffset(_offIconView.bounds, TGScreenPixelFloor(21.5f) + offset.x, TGScreenPixelFloor(12.5f) + offset.y);
|
||||||
|
} else {
|
||||||
|
_offIconView.frame = CGRectOffset(_offIconView.bounds, TGScreenPixelFloor(21.5f) + offset.x, TGScreenPixelFloor(14.5f) + offset.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onIconView.frame = CGRectOffset(_onIconView.bounds, 20.0f + offset.x, 15.0f + offset.y);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)updateState:(bool)on animated:(bool)animated force:(bool)force {
|
- (void)updateState:(bool)on animated:(bool)animated force:(bool)force {
|
||||||
if (_stateIsOn != on || force) {
|
if (_stateIsOn != on || force) {
|
||||||
_stateIsOn = on;
|
_stateIsOn = on;
|
||||||
@ -125,8 +137,25 @@ static const void *positionChangedKey = &positionChangedKey;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)setNegativeContentColor:(UIColor *)color {
|
- (void)setNegativeContentColor:(UIColor *)color {
|
||||||
|
_negativeContentColor = color;
|
||||||
|
if (_isLocked) {
|
||||||
|
_offIconView.image = TGTintedImage(TGComponentsImageNamed(@"Item List/SwitchLockIcon"), color);
|
||||||
|
_offIconView.frame = CGRectMake(_offIconView.frame.origin.x, _offIconView.frame.origin.y, _offIconView.image.size.width, _offIconView.image.size.height);
|
||||||
|
} else {
|
||||||
_offIconView.image = TGTintedImage(TGComponentsImageNamed(@"PermissionSwitchOff.png"), color);
|
_offIconView.image = TGTintedImage(TGComponentsImageNamed(@"PermissionSwitchOff.png"), color);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateIsLocked:(bool)isLocked {
|
||||||
|
if (_isLocked != isLocked) {
|
||||||
|
_isLocked = isLocked;
|
||||||
|
|
||||||
|
if (_negativeContentColor) {
|
||||||
|
[self setNegativeContentColor:_negativeContentColor];
|
||||||
|
}
|
||||||
|
[self updateIconFrame];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)currentValueChanged {
|
- (void)currentValueChanged {
|
||||||
[self updateState:self.isOn animated:true force:false];
|
[self updateState:self.isOn animated:true force:false];
|
||||||
|
@ -69,6 +69,8 @@ open class IconSwitchNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var _isLocked: Bool = false
|
||||||
|
|
||||||
override public init() {
|
override public init() {
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -82,8 +84,8 @@ open class IconSwitchNode: ASDisplayNode {
|
|||||||
|
|
||||||
(self.view as! UISwitch).backgroundColor = self.backgroundColor
|
(self.view as! UISwitch).backgroundColor = self.backgroundColor
|
||||||
(self.view as! UISwitch).tintColor = self.frameColor
|
(self.view as! UISwitch).tintColor = self.frameColor
|
||||||
//(self.view as! UISwitch).thumbTintColor = self.handleColor
|
|
||||||
(self.view as! UISwitch).onTintColor = self.contentColor
|
(self.view as! UISwitch).onTintColor = self.contentColor
|
||||||
|
(self.view as? TGIconSwitchView)?.updateIsLocked(self._isLocked)
|
||||||
(self.view as! IconSwitchNodeView).setNegativeContentColor(self.negativeContentColor)
|
(self.view as! IconSwitchNodeView).setNegativeContentColor(self.negativeContentColor)
|
||||||
(self.view as! IconSwitchNodeView).setPositiveContentColor(self.positiveContentColor)
|
(self.view as! IconSwitchNodeView).setPositiveContentColor(self.positiveContentColor)
|
||||||
|
|
||||||
@ -99,6 +101,16 @@ open class IconSwitchNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func updateIsLocked(_ value: Bool) {
|
||||||
|
if self._isLocked == value {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self._isLocked = value
|
||||||
|
if self.isNodeLoaded {
|
||||||
|
(self.view as? TGIconSwitchView)?.updateIsLocked(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override open func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
override open func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||||
return CGSize(width: 51.0, height: 31.0)
|
return CGSize(width: 51.0, height: 31.0)
|
||||||
}
|
}
|
||||||
|
@ -317,6 +317,8 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
|
|
||||||
case hideIconImage
|
case hideIconImage
|
||||||
case peerStatusLockedImage
|
case peerStatusLockedImage
|
||||||
|
case expandDownArrowImage
|
||||||
|
case expandSmallDownArrowImage
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ChatExpiredStoryIndicatorType: Hashable {
|
public enum ChatExpiredStoryIndicatorType: Hashable {
|
||||||
|
@ -414,4 +414,16 @@ public struct PresentationResourcesItemList {
|
|||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.list.itemSecondaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.list.itemSecondaryTextColor)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func expandDownArrowImage(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.expandDownArrowImage.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Item List/ExpandingItemVerticalRegularArrow"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func expandSmallDownArrowImage(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.expandSmallDownArrowImage.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Item List/ExpandingItemVerticalSmallArrow"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,16 +20,171 @@ import ListSectionComponent
|
|||||||
import ListActionItemComponent
|
import ListActionItemComponent
|
||||||
import PlainButtonComponent
|
import PlainButtonComponent
|
||||||
|
|
||||||
private let banSendMediaFlags: TelegramChatBannedRightsFlags = [
|
struct MediaRight: OptionSet, Hashable {
|
||||||
.banSendPhotos,
|
var rawValue: Int
|
||||||
.banSendVideos,
|
|
||||||
.banSendGifs,
|
static let photos = MediaRight(rawValue: 1 << 0)
|
||||||
.banSendMusic,
|
static let videos = MediaRight(rawValue: 1 << 1)
|
||||||
.banSendFiles,
|
static let stickersAndGifs = MediaRight(rawValue: 1 << 2)
|
||||||
.banSendVoice,
|
static let music = MediaRight(rawValue: 1 << 3)
|
||||||
.banSendInstantVideos,
|
static let files = MediaRight(rawValue: 1 << 4)
|
||||||
.banEmbedLinks,
|
static let voiceMessages = MediaRight(rawValue: 1 << 5)
|
||||||
.banSendPolls
|
static let videoMessages = MediaRight(rawValue: 1 << 6)
|
||||||
|
static let links = MediaRight(rawValue: 1 << 7)
|
||||||
|
static let polls = MediaRight(rawValue: 1 << 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MediaRight {
|
||||||
|
var count: Int {
|
||||||
|
var result = 0
|
||||||
|
var index = 0
|
||||||
|
while index < 31 {
|
||||||
|
let currentValue = self.rawValue >> UInt32(index)
|
||||||
|
index += 1
|
||||||
|
if currentValue == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentValue & 1) != 0 {
|
||||||
|
result += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ParticipantRight: OptionSet {
|
||||||
|
var rawValue: Int
|
||||||
|
|
||||||
|
static let sendMessages = ParticipantRight(rawValue: 1 << 0)
|
||||||
|
static let addMembers = ParticipantRight(rawValue: 1 << 2)
|
||||||
|
static let pinMessages = ParticipantRight(rawValue: 1 << 3)
|
||||||
|
static let changeInfo = ParticipantRight(rawValue: 1 << 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func rightsFromBannedRights(_ rights: TelegramChatBannedRightsFlags) -> (participantRights: ParticipantRight, mediaRights: MediaRight) {
|
||||||
|
var participantResult: ParticipantRight = [
|
||||||
|
.sendMessages,
|
||||||
|
.addMembers,
|
||||||
|
.pinMessages,
|
||||||
|
.changeInfo
|
||||||
|
]
|
||||||
|
var mediaResult: MediaRight = [
|
||||||
|
.photos,
|
||||||
|
.videos,
|
||||||
|
.stickersAndGifs,
|
||||||
|
.music,
|
||||||
|
.files,
|
||||||
|
.voiceMessages,
|
||||||
|
.videoMessages,
|
||||||
|
.links,
|
||||||
|
.polls
|
||||||
|
]
|
||||||
|
|
||||||
|
if rights.contains(.banSendText) {
|
||||||
|
participantResult.remove(.sendMessages)
|
||||||
|
}
|
||||||
|
if rights.contains(.banAddMembers) {
|
||||||
|
participantResult.remove(.addMembers)
|
||||||
|
}
|
||||||
|
if rights.contains(.banPinMessages) {
|
||||||
|
participantResult.remove(.pinMessages)
|
||||||
|
}
|
||||||
|
if rights.contains(.banChangeInfo) {
|
||||||
|
participantResult.remove(.changeInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rights.contains(.banSendPhotos) {
|
||||||
|
mediaResult.remove(.photos)
|
||||||
|
}
|
||||||
|
if rights.contains(.banSendVideos) {
|
||||||
|
mediaResult.remove(.videos)
|
||||||
|
}
|
||||||
|
if rights.contains(.banSendStickers) || rights.contains(.banSendGifs) || rights.contains(.banSendGames) || rights.contains(.banSendInline) {
|
||||||
|
mediaResult.remove(.stickersAndGifs)
|
||||||
|
}
|
||||||
|
if rights.contains(.banSendMusic) {
|
||||||
|
mediaResult.remove(.music)
|
||||||
|
}
|
||||||
|
if rights.contains(.banSendFiles) {
|
||||||
|
mediaResult.remove(.files)
|
||||||
|
}
|
||||||
|
if rights.contains(.banSendVoice) {
|
||||||
|
mediaResult.remove(.voiceMessages)
|
||||||
|
}
|
||||||
|
if rights.contains(.banSendInstantVideos) {
|
||||||
|
mediaResult.remove(.videoMessages)
|
||||||
|
}
|
||||||
|
if rights.contains(.banEmbedLinks) {
|
||||||
|
mediaResult.remove(.links)
|
||||||
|
}
|
||||||
|
if rights.contains(.banSendPolls) {
|
||||||
|
mediaResult.remove(.polls)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (participantResult, mediaResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func rightFlagsFromRights(participantRights: ParticipantRight, mediaRights: MediaRight) -> TelegramChatBannedRightsFlags {
|
||||||
|
var result: TelegramChatBannedRightsFlags = []
|
||||||
|
|
||||||
|
if !participantRights.contains(.sendMessages) {
|
||||||
|
result.insert(.banSendText)
|
||||||
|
}
|
||||||
|
if !participantRights.contains(.addMembers) {
|
||||||
|
result.insert(.banAddMembers)
|
||||||
|
}
|
||||||
|
if !participantRights.contains(.pinMessages) {
|
||||||
|
result.insert(.banPinMessages)
|
||||||
|
}
|
||||||
|
if !participantRights.contains(.changeInfo) {
|
||||||
|
result.insert(.banChangeInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mediaRights.contains(.photos) {
|
||||||
|
result.insert(.banSendPhotos)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.videos) {
|
||||||
|
result.insert(.banSendVideos)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.stickersAndGifs) {
|
||||||
|
result.insert(.banSendStickers)
|
||||||
|
result.insert(.banSendGifs)
|
||||||
|
result.insert(.banSendGames)
|
||||||
|
result.insert(.banSendInline)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.music) {
|
||||||
|
result.insert(.banSendMusic)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.files) {
|
||||||
|
result.insert(.banSendFiles)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.voiceMessages) {
|
||||||
|
result.insert(.banSendVoice)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.videoMessages) {
|
||||||
|
result.insert(.banSendInstantVideos)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.links) {
|
||||||
|
result.insert(.banEmbedLinks)
|
||||||
|
}
|
||||||
|
if !mediaRights.contains(.polls) {
|
||||||
|
result.insert(.banSendPolls)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private let allMediaRightItems: [MediaRight] = [
|
||||||
|
.photos,
|
||||||
|
.videos,
|
||||||
|
.stickersAndGifs,
|
||||||
|
.music,
|
||||||
|
.files,
|
||||||
|
.voiceMessages,
|
||||||
|
.videoMessages,
|
||||||
|
.links,
|
||||||
|
.polls
|
||||||
]
|
]
|
||||||
|
|
||||||
private final class AdminUserActionsSheetComponent: Component {
|
private final class AdminUserActionsSheetComponent: Component {
|
||||||
@ -37,14 +192,14 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let chatPeer: EnginePeer
|
let chatPeer: EnginePeer
|
||||||
let peers: [EnginePeer]
|
let peers: [RenderedChannelParticipant]
|
||||||
let messageCount: Int
|
let messageCount: Int
|
||||||
let completion: (AdminUserActionsSheet.Result) -> Void
|
let completion: (AdminUserActionsSheet.Result) -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
chatPeer: EnginePeer,
|
chatPeer: EnginePeer,
|
||||||
peers: [EnginePeer],
|
peers: [RenderedChannelParticipant],
|
||||||
messageCount: Int,
|
messageCount: Int,
|
||||||
completion: @escaping (AdminUserActionsSheet.Result) -> Void
|
completion: @escaping (AdminUserActionsSheet.Result) -> Void
|
||||||
) {
|
) {
|
||||||
@ -131,11 +286,12 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
private var optionBanSelectedPeers = Set<EnginePeer.Id>()
|
private var optionBanSelectedPeers = Set<EnginePeer.Id>()
|
||||||
|
|
||||||
private var isConfigurationExpanded: Bool = false
|
private var isConfigurationExpanded: Bool = false
|
||||||
private var configSendMessages: Bool = false
|
private var isMediaSectionExpanded: Bool = false
|
||||||
private var configSendMedia: Bool = false
|
|
||||||
private var configAddUsers: Bool = false
|
private var allowedParticipantRights: ParticipantRight = []
|
||||||
private var configPinMessages: Bool = false
|
private var allowedMediaRights: MediaRight = []
|
||||||
private var configChangeInfo: Bool = false
|
private var participantRights: ParticipantRight = []
|
||||||
|
private var mediaRights: MediaRight = []
|
||||||
|
|
||||||
private var previousWasConfigurationExpanded: Bool = false
|
private var previousWasConfigurationExpanded: Bool = false
|
||||||
|
|
||||||
@ -263,22 +419,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var banFlags: TelegramChatBannedRightsFlags = []
|
var banFlags: TelegramChatBannedRightsFlags = []
|
||||||
|
banFlags = rightFlagsFromRights(participantRights: self.participantRights, mediaRights: self.mediaRights)
|
||||||
if !self.configSendMessages {
|
|
||||||
banFlags.insert(.banSendText)
|
|
||||||
}
|
|
||||||
if !self.configSendMedia {
|
|
||||||
banFlags.formUnion(banSendMediaFlags)
|
|
||||||
}
|
|
||||||
if !self.configAddUsers {
|
|
||||||
banFlags.insert(.banAddMembers)
|
|
||||||
}
|
|
||||||
if !self.configPinMessages {
|
|
||||||
banFlags.insert(.banPinMessages)
|
|
||||||
}
|
|
||||||
if !self.configChangeInfo {
|
|
||||||
banFlags.insert(.banChangeInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
let bannedRights = TelegramChatBannedRights(flags: banFlags, untilDate: Int32.max)
|
let bannedRights = TelegramChatBannedRights(flags: banFlags, untilDate: Int32.max)
|
||||||
for id in self.optionBanSelectedPeers.sorted() {
|
for id in self.optionBanSelectedPeers.sorted() {
|
||||||
@ -370,6 +511,44 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
let sideInset: CGFloat = 16.0
|
let sideInset: CGFloat = 16.0
|
||||||
|
|
||||||
if self.component == nil {
|
if self.component == nil {
|
||||||
|
var (allowedParticipantRights, allowedMediaRights) = rightsFromBannedRights([])
|
||||||
|
if case let .channel(channel) = component.chatPeer {
|
||||||
|
(allowedParticipantRights, allowedMediaRights) = rightsFromBannedRights(channel.defaultBannedRights?.flags ?? [])
|
||||||
|
}
|
||||||
|
|
||||||
|
var (commonParticipantRights, commonMediaRights) = rightsFromBannedRights([])
|
||||||
|
|
||||||
|
loop: for peer in component.peers {
|
||||||
|
var (peerParticipantRights, peerMediaRights) = rightsFromBannedRights([])
|
||||||
|
switch peer.participant {
|
||||||
|
case .creator:
|
||||||
|
allowedParticipantRights = []
|
||||||
|
allowedMediaRights = []
|
||||||
|
break loop
|
||||||
|
case let .member(_, _, adminInfo, banInfo, _):
|
||||||
|
if adminInfo != nil {
|
||||||
|
allowedParticipantRights = []
|
||||||
|
allowedMediaRights = []
|
||||||
|
break loop
|
||||||
|
} else if let banInfo {
|
||||||
|
(peerParticipantRights, peerMediaRights) = rightsFromBannedRights(banInfo.rights.flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peerParticipantRights = peerParticipantRights.intersection(allowedParticipantRights)
|
||||||
|
peerMediaRights = peerMediaRights.intersection(allowedMediaRights)
|
||||||
|
|
||||||
|
commonParticipantRights = commonParticipantRights.intersection(peerParticipantRights)
|
||||||
|
commonMediaRights = commonMediaRights.intersection(peerMediaRights)
|
||||||
|
}
|
||||||
|
|
||||||
|
commonParticipantRights = commonParticipantRights.intersection(allowedParticipantRights)
|
||||||
|
commonMediaRights = commonMediaRights.intersection(allowedMediaRights)
|
||||||
|
|
||||||
|
self.allowedParticipantRights = allowedParticipantRights
|
||||||
|
self.participantRights = commonParticipantRights
|
||||||
|
|
||||||
|
self.allowedMediaRights = allowedMediaRights
|
||||||
|
self.mediaRights = commonMediaRights
|
||||||
}
|
}
|
||||||
|
|
||||||
self.component = component
|
self.component = component
|
||||||
@ -423,6 +602,43 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
case ban
|
case ban
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var availableOptions: [OptionsSection] = []
|
||||||
|
availableOptions.append(.report)
|
||||||
|
|
||||||
|
if case let .channel(channel) = component.chatPeer {
|
||||||
|
if channel.hasPermission(.deleteAllMessages) {
|
||||||
|
availableOptions.append(.deleteAll)
|
||||||
|
|
||||||
|
if channel.hasPermission(.banMembers) {
|
||||||
|
var canBanEveryone = true
|
||||||
|
for peer in component.peers {
|
||||||
|
if peer.peer.id == component.context.account.peerId {
|
||||||
|
canBanEveryone = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch peer.participant {
|
||||||
|
case .creator:
|
||||||
|
canBanEveryone = false
|
||||||
|
case let .member(_, _, adminInfo, banInfo, _):
|
||||||
|
let _ = banInfo
|
||||||
|
if let adminInfo {
|
||||||
|
if channel.flags.contains(.isCreator) {
|
||||||
|
} else if adminInfo.promotedBy == component.context.account.peerId {
|
||||||
|
} else {
|
||||||
|
canBanEveryone = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if canBanEveryone {
|
||||||
|
availableOptions.append(.ban)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let optionsItem: (OptionsSection) -> AnyComponentWithIdentity<Empty> = { section in
|
let optionsItem: (OptionsSection) -> AnyComponentWithIdentity<Empty> = { section in
|
||||||
let sectionId: AnyHashable
|
let sectionId: AnyHashable
|
||||||
let selectedPeers: Set<EnginePeer.Id>
|
let selectedPeers: Set<EnginePeer.Id>
|
||||||
@ -442,7 +658,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
isExpanded = self.isOptionDeleteAllExpanded
|
isExpanded = self.isOptionDeleteAllExpanded
|
||||||
|
|
||||||
if component.peers.count == 1 {
|
if component.peers.count == 1 {
|
||||||
title = "Delete All from \(component.peers[0].compactDisplayTitle)"
|
title = "Delete All from \(EnginePeer(component.peers[0].peer).compactDisplayTitle)"
|
||||||
} else {
|
} else {
|
||||||
title = "Delete All from Users"
|
title = "Delete All from Users"
|
||||||
}
|
}
|
||||||
@ -454,8 +670,8 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
let banTitle: String
|
let banTitle: String
|
||||||
let restrictTitle: String
|
let restrictTitle: String
|
||||||
if component.peers.count == 1 {
|
if component.peers.count == 1 {
|
||||||
banTitle = "Ban \(component.peers[0].compactDisplayTitle)"
|
banTitle = "Ban \(EnginePeer(component.peers[0].peer).compactDisplayTitle)"
|
||||||
restrictTitle = "Restrict \(component.peers[0].compactDisplayTitle)"
|
restrictTitle = "Restrict \(EnginePeer(component.peers[0].peer).compactDisplayTitle)"
|
||||||
} else {
|
} else {
|
||||||
banTitle = "Ban Users"
|
banTitle = "Ban Users"
|
||||||
restrictTitle = "Restrict Users"
|
restrictTitle = "Restrict Users"
|
||||||
@ -527,7 +743,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
|
|
||||||
if selectedPeers.isEmpty {
|
if selectedPeers.isEmpty {
|
||||||
for peer in component.peers {
|
for peer in component.peers {
|
||||||
selectedPeers.insert(peer.id)
|
selectedPeers.insert(peer.peer.id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectedPeers.removeAll()
|
selectedPeers.removeAll()
|
||||||
@ -567,7 +783,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
|
|
||||||
if selectedPeers.isEmpty {
|
if selectedPeers.isEmpty {
|
||||||
for peer in component.peers {
|
for peer in component.peers {
|
||||||
selectedPeers.insert(peer.id)
|
selectedPeers.insert(peer.peer.id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectedPeers.removeAll()
|
selectedPeers.removeAll()
|
||||||
@ -605,14 +821,14 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
|
|
||||||
var peerItems: [AnyComponentWithIdentity<Empty>] = []
|
var peerItems: [AnyComponentWithIdentity<Empty>] = []
|
||||||
for peer in component.peers {
|
for peer in component.peers {
|
||||||
peerItems.append(AnyComponentWithIdentity(id: peer.id, component: AnyComponent(AdminUserActionsPeerComponent(
|
peerItems.append(AnyComponentWithIdentity(id: peer.peer.id, component: AnyComponent(AdminUserActionsPeerComponent(
|
||||||
context: component.context,
|
context: component.context,
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
strings: environment.strings,
|
strings: environment.strings,
|
||||||
sideInset: 0.0,
|
sideInset: 0.0,
|
||||||
title: peer.displayTitle(strings: environment.strings, displayOrder: .firstLast),
|
title: EnginePeer(peer.peer).displayTitle(strings: environment.strings, displayOrder: .firstLast),
|
||||||
peer: peer,
|
peer: EnginePeer(peer.peer),
|
||||||
selectionState: .editing(isSelected: selectedPeers.contains(peer.id)),
|
selectionState: .editing(isSelected: selectedPeers.contains(peer.peer.id)),
|
||||||
action: { [weak self] peer in
|
action: { [weak self] peer in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -684,19 +900,21 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
|
|
||||||
var optionsSectionItems: [AnyComponentWithIdentity<Empty>] = []
|
var optionsSectionItems: [AnyComponentWithIdentity<Empty>] = []
|
||||||
|
|
||||||
optionsSectionItems.append(optionsItem(.report))
|
for option in availableOptions {
|
||||||
if self.isOptionReportExpanded {
|
let isOptionExpanded: Bool
|
||||||
optionsSectionItems.append(expandedPeersItem(.report))
|
switch option {
|
||||||
|
case .report:
|
||||||
|
isOptionExpanded = self.isOptionReportExpanded
|
||||||
|
case .deleteAll:
|
||||||
|
isOptionExpanded = self.isOptionDeleteAllExpanded
|
||||||
|
case .ban:
|
||||||
|
isOptionExpanded = self.isOptionBanExpanded
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsSectionItems.append(optionsItem(.deleteAll))
|
optionsSectionItems.append(optionsItem(option))
|
||||||
if self.isOptionDeleteAllExpanded {
|
if isOptionExpanded {
|
||||||
optionsSectionItems.append(expandedPeersItem(.deleteAll))
|
optionsSectionItems.append(expandedPeersItem(option))
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsSectionItems.append(optionsItem(.ban))
|
|
||||||
if self.isOptionBanExpanded {
|
|
||||||
optionsSectionItems.append(expandedPeersItem(.ban))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var optionsSectionTransition = transition
|
var optionsSectionTransition = transition
|
||||||
@ -748,7 +966,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
component: AnyComponent(PlainButtonComponent(
|
component: AnyComponent(PlainButtonComponent(
|
||||||
content: AnyComponent(OptionsSectionFooterComponent(
|
content: AnyComponent(OptionsSectionFooterComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
text: self.isConfigurationExpanded ? fullyBanTitle : partiallyRestrictTitle,
|
text: self.isConfigurationExpanded ? partiallyRestrictTitle : fullyBanTitle,
|
||||||
fontSize: presentationData.listsFontSize.itemListBaseHeaderFontSize,
|
fontSize: presentationData.listsFontSize.itemListBaseHeaderFontSize,
|
||||||
isExpanded: self.isConfigurationExpanded
|
isExpanded: self.isConfigurationExpanded
|
||||||
)),
|
)),
|
||||||
@ -761,7 +979,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
self.isConfigurationExpanded = !self.isConfigurationExpanded
|
self.isConfigurationExpanded = !self.isConfigurationExpanded
|
||||||
if self.isConfigurationExpanded && self.optionBanSelectedPeers.isEmpty {
|
if self.isConfigurationExpanded && self.optionBanSelectedPeers.isEmpty {
|
||||||
for peer in component.peers {
|
for peer in component.peers {
|
||||||
self.optionBanSelectedPeers.insert(peer.id)
|
self.optionBanSelectedPeers.insert(peer.peer.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.state?.updated(transition: .spring(duration: 0.35))
|
self.state?.updated(transition: .spring(duration: 0.35))
|
||||||
@ -776,7 +994,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
|
|
||||||
var configSectionItems: [AnyComponentWithIdentity<Empty>] = []
|
var configSectionItems: [AnyComponentWithIdentity<Empty>] = []
|
||||||
|
|
||||||
enum ConfigItem: Hashable {
|
enum ConfigItem: Hashable, CaseIterable {
|
||||||
case sendMessages
|
case sendMessages
|
||||||
case sendMedia
|
case sendMedia
|
||||||
case addUsers
|
case addUsers
|
||||||
@ -784,93 +1002,238 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
case changeInfo
|
case changeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
let allConfigItems: [ConfigItem] = [
|
var allConfigItems: [(ConfigItem, Bool)] = []
|
||||||
.sendMessages,
|
if !self.allowedMediaRights.isEmpty || !self.allowedParticipantRights.isEmpty {
|
||||||
.sendMedia,
|
for configItem in ConfigItem.allCases {
|
||||||
.addUsers,
|
let isEnabled: Bool
|
||||||
.pinMessages,
|
switch configItem {
|
||||||
.changeInfo
|
case .sendMessages:
|
||||||
]
|
isEnabled = self.allowedParticipantRights.contains(.sendMessages)
|
||||||
if case let .channel(channel) = component.chatPeer {
|
case .sendMedia:
|
||||||
let defaultBannedFlags = channel.defaultBannedRights?.flags ?? []
|
isEnabled = !self.allowedMediaRights.isEmpty
|
||||||
|
case .addUsers:
|
||||||
|
isEnabled = self.allowedParticipantRights.contains(.addMembers)
|
||||||
|
case .pinMessages:
|
||||||
|
isEnabled = self.allowedParticipantRights.contains(.pinMessages)
|
||||||
|
case .changeInfo:
|
||||||
|
isEnabled = self.allowedParticipantRights.contains(.changeInfo)
|
||||||
|
}
|
||||||
|
allConfigItems.append((configItem, isEnabled))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loop: for configItem in allConfigItems {
|
loop: for (configItem, isEnabled) in allConfigItems {
|
||||||
let itemTitle: String
|
let itemTitle: AnyComponent<Empty>
|
||||||
let itemValue: Bool
|
let itemValue: Bool
|
||||||
switch configItem {
|
switch configItem {
|
||||||
case .sendMessages:
|
case .sendMessages:
|
||||||
if defaultBannedFlags.contains(.banSendText) {
|
itemTitle = AnyComponent(MultilineTextComponent(
|
||||||
continue loop
|
text: .plain(NSAttributedString(
|
||||||
}
|
string: "Send Messages",
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
itemTitle = "Send Text Messages"
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
itemValue = self.configSendMessages
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))
|
||||||
|
itemValue = self.participantRights.contains(.sendMessages)
|
||||||
case .sendMedia:
|
case .sendMedia:
|
||||||
if !defaultBannedFlags.intersection(banSendMediaFlags).isEmpty {
|
if isEnabled {
|
||||||
continue loop
|
itemTitle = AnyComponent(HStack([
|
||||||
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: "Send Media",
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))),
|
||||||
|
AnyComponentWithIdentity(id: 1, component: AnyComponent(MediaSectionExpandIndicatorComponent(
|
||||||
|
theme: environment.theme,
|
||||||
|
title: "\(self.mediaRights.count)/\(self.allowedMediaRights.count)",
|
||||||
|
isExpanded: self.isMediaSectionExpanded
|
||||||
|
)))
|
||||||
|
], spacing: 7.0))
|
||||||
|
} else {
|
||||||
|
itemTitle = AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: "Send Media",
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
itemTitle = "Send Media"
|
itemValue = !self.mediaRights.isEmpty
|
||||||
itemValue = self.configSendMedia
|
|
||||||
case .addUsers:
|
case .addUsers:
|
||||||
if defaultBannedFlags.contains(.banAddMembers) {
|
itemTitle = AnyComponent(MultilineTextComponent(
|
||||||
continue loop
|
text: .plain(NSAttributedString(
|
||||||
}
|
string: "Add Users",
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
itemTitle = "Add Users"
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
itemValue = self.configAddUsers
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))
|
||||||
|
itemValue = self.participantRights.contains(.addMembers)
|
||||||
case .pinMessages:
|
case .pinMessages:
|
||||||
if defaultBannedFlags.contains(.banPinMessages) {
|
itemTitle = AnyComponent(MultilineTextComponent(
|
||||||
continue loop
|
text: .plain(NSAttributedString(
|
||||||
}
|
string: "Pin Messages",
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
itemTitle = "Pin Messages"
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
itemValue = self.configPinMessages
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))
|
||||||
|
itemValue = self.participantRights.contains(.pinMessages)
|
||||||
case .changeInfo:
|
case .changeInfo:
|
||||||
if defaultBannedFlags.contains(.banChangeInfo) {
|
itemTitle = AnyComponent(MultilineTextComponent(
|
||||||
continue loop
|
text: .plain(NSAttributedString(
|
||||||
}
|
string: "Change Chat Info",
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
itemTitle = "Change Chat Info"
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
itemValue = self.configChangeInfo
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))
|
||||||
|
itemValue = self.participantRights.contains(.changeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
configSectionItems.append(AnyComponentWithIdentity(id: configItem, component: AnyComponent(ListActionItemComponent(
|
configSectionItems.append(AnyComponentWithIdentity(id: configItem, component: AnyComponent(ListActionItemComponent(
|
||||||
|
theme: environment.theme,
|
||||||
|
title: itemTitle,
|
||||||
|
accessory: .toggle(ListActionItemComponent.Toggle(
|
||||||
|
style: isEnabled ? .icons : .lock,
|
||||||
|
isOn: itemValue,
|
||||||
|
isInteractive: isEnabled,
|
||||||
|
action: isEnabled ? { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch configItem {
|
||||||
|
case .sendMessages:
|
||||||
|
if self.participantRights.contains(.sendMessages) {
|
||||||
|
self.participantRights.remove(.sendMessages)
|
||||||
|
} else {
|
||||||
|
self.participantRights.insert(.sendMessages)
|
||||||
|
}
|
||||||
|
case .sendMedia:
|
||||||
|
if self.mediaRights.isEmpty {
|
||||||
|
self.mediaRights = self.allowedMediaRights
|
||||||
|
} else {
|
||||||
|
self.mediaRights = []
|
||||||
|
}
|
||||||
|
case .addUsers:
|
||||||
|
if self.participantRights.contains(.addMembers) {
|
||||||
|
self.participantRights.remove(.addMembers)
|
||||||
|
} else {
|
||||||
|
self.participantRights.insert(.addMembers)
|
||||||
|
}
|
||||||
|
case .pinMessages:
|
||||||
|
if self.participantRights.contains(.pinMessages) {
|
||||||
|
self.participantRights.remove(.pinMessages)
|
||||||
|
} else {
|
||||||
|
self.participantRights.insert(.pinMessages)
|
||||||
|
}
|
||||||
|
case .changeInfo:
|
||||||
|
if self.participantRights.contains(.changeInfo) {
|
||||||
|
self.participantRights.remove(.changeInfo)
|
||||||
|
} else {
|
||||||
|
self.participantRights.insert(.changeInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.state?.updated(transition: .spring(duration: 0.35))
|
||||||
|
} : nil
|
||||||
|
)),
|
||||||
|
action: (isEnabled && configItem == .sendMedia) ? { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isMediaSectionExpanded = !self.isMediaSectionExpanded
|
||||||
|
self.state?.updated(transition: .spring(duration: 0.35))
|
||||||
|
} : nil,
|
||||||
|
highlighting: .disabled
|
||||||
|
))))
|
||||||
|
|
||||||
|
if isEnabled, case .sendMedia = configItem, self.isMediaSectionExpanded {
|
||||||
|
var mediaItems: [AnyComponentWithIdentity<Empty>] = []
|
||||||
|
mediaRightsLoop: for possibleMediaItem in allMediaRightItems {
|
||||||
|
if !self.allowedMediaRights.contains(possibleMediaItem) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let mediaItemTitle: String
|
||||||
|
switch possibleMediaItem {
|
||||||
|
case .photos:
|
||||||
|
mediaItemTitle = "Send Photos"
|
||||||
|
case .videos:
|
||||||
|
mediaItemTitle = "Send Videos"
|
||||||
|
case .stickersAndGifs:
|
||||||
|
mediaItemTitle = "Send Stickers & GIFs"
|
||||||
|
case .music:
|
||||||
|
mediaItemTitle = "Send Music"
|
||||||
|
case .files:
|
||||||
|
mediaItemTitle = "Send Files"
|
||||||
|
case .voiceMessages:
|
||||||
|
mediaItemTitle = "Send Voice Messages"
|
||||||
|
case .videoMessages:
|
||||||
|
mediaItemTitle = "Send Video Messages"
|
||||||
|
case .links:
|
||||||
|
mediaItemTitle = "Embed Links"
|
||||||
|
case .polls:
|
||||||
|
mediaItemTitle = "Send Polls"
|
||||||
|
default:
|
||||||
|
continue mediaRightsLoop
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaItems.append(AnyComponentWithIdentity(id: possibleMediaItem, component: AnyComponent(ListActionItemComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
title: AnyComponent(VStack([
|
title: AnyComponent(VStack([
|
||||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: itemTitle,
|
string: mediaItemTitle,
|
||||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
textColor: environment.theme.list.itemPrimaryTextColor
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
)),
|
)),
|
||||||
maximumNumberOfLines: 1
|
maximumNumberOfLines: 1
|
||||||
))),
|
))),
|
||||||
], alignment: .left, spacing: 2.0)),
|
], alignment: .left, spacing: 2.0)),
|
||||||
accessory: .toggle(ListActionItemComponent.Toggle(
|
leftIcon: .check(ListActionItemComponent.LeftIcon.Check(
|
||||||
style: .icons,
|
isSelected: self.mediaRights.contains(possibleMediaItem),
|
||||||
isOn: itemValue,
|
toggle: { [weak self] in
|
||||||
isInteractive: true,
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.mediaRights.contains(possibleMediaItem) {
|
||||||
|
self.mediaRights.remove(possibleMediaItem)
|
||||||
|
} else {
|
||||||
|
self.mediaRights.insert(possibleMediaItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state?.updated(transition: .spring(duration: 0.35))
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
icon: .none,
|
||||||
|
accessory: .none,
|
||||||
action: { [weak self] _ in
|
action: { [weak self] _ in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch configItem {
|
|
||||||
case .sendMessages:
|
if self.mediaRights.contains(possibleMediaItem) {
|
||||||
self.configSendMessages = !self.configSendMessages
|
self.mediaRights.remove(possibleMediaItem)
|
||||||
case .sendMedia:
|
} else {
|
||||||
self.configSendMedia = !self.configSendMedia
|
self.mediaRights.insert(possibleMediaItem)
|
||||||
case .addUsers:
|
|
||||||
self.configAddUsers = !self.configAddUsers
|
|
||||||
case .pinMessages:
|
|
||||||
self.configPinMessages = !self.configPinMessages
|
|
||||||
case .changeInfo:
|
|
||||||
self.configChangeInfo = !self.configChangeInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state?.updated(transition: .spring(duration: 0.35))
|
self.state?.updated(transition: .spring(duration: 0.35))
|
||||||
|
},
|
||||||
|
highlighting: .disabled
|
||||||
|
))))
|
||||||
}
|
}
|
||||||
)),
|
configSectionItems.append(AnyComponentWithIdentity(id: "media-sub", component: AnyComponent(ListSubSectionComponent(
|
||||||
action: nil
|
theme: environment.theme,
|
||||||
|
leftInset: 0.0,
|
||||||
|
items: mediaItems
|
||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -911,6 +1274,7 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
transition.setAlpha(view: configSectionView, alpha: self.isConfigurationExpanded ? 1.0 : 0.0)
|
transition.setAlpha(view: configSectionView, alpha: self.isConfigurationExpanded ? 1.0 : 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if availableOptions.contains(.ban) && !configSectionItems.isEmpty {
|
||||||
let optionsFooterFrame: CGRect
|
let optionsFooterFrame: CGRect
|
||||||
if self.isConfigurationExpanded {
|
if self.isConfigurationExpanded {
|
||||||
contentHeight += 30.0
|
contentHeight += 30.0
|
||||||
@ -928,6 +1292,17 @@ private final class AdminUserActionsSheetComponent: Component {
|
|||||||
self.scrollContentView.addSubview(optionsFooterView)
|
self.scrollContentView.addSubview(optionsFooterView)
|
||||||
}
|
}
|
||||||
transition.setFrame(view: optionsFooterView, frame: optionsFooterFrame)
|
transition.setFrame(view: optionsFooterView, frame: optionsFooterFrame)
|
||||||
|
transition.setAlpha(view: optionsFooterView, alpha: 1.0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let optionsFooterView = self.optionsFooter.view {
|
||||||
|
if optionsFooterView.superview == nil {
|
||||||
|
self.scrollContentView.addSubview(optionsFooterView)
|
||||||
|
}
|
||||||
|
let optionsFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: optionsFooterSize)
|
||||||
|
transition.setFrame(view: optionsFooterView, frame: optionsFooterFrame)
|
||||||
|
transition.setAlpha(view: optionsFooterView, alpha: 0.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contentHeight += 30.0
|
contentHeight += 30.0
|
||||||
@ -1046,47 +1421,9 @@ public class AdminUserActionsSheet: ViewControllerComponentContainer {
|
|||||||
|
|
||||||
private var isDismissed: Bool = false
|
private var isDismissed: Bool = false
|
||||||
|
|
||||||
public init(context: AccountContext, chatPeer: EnginePeer, peers: [EnginePeer], messageCount: Int, completion: @escaping (Result) -> Void) {
|
public init(context: AccountContext, chatPeer: EnginePeer, peers: [RenderedChannelParticipant], messageCount: Int, completion: @escaping (Result) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
/*#if DEBUG
|
|
||||||
var peers = peers
|
|
||||||
|
|
||||||
if !"".isEmpty {
|
|
||||||
var nextPeerId: Int64 = 1
|
|
||||||
let makePeer: () -> EnginePeer = {
|
|
||||||
guard case let .user(user) = peers[0] else {
|
|
||||||
preconditionFailure()
|
|
||||||
}
|
|
||||||
let id = nextPeerId
|
|
||||||
nextPeerId += 1
|
|
||||||
return .user(TelegramUser(
|
|
||||||
id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id)),
|
|
||||||
accessHash: user.accessHash,
|
|
||||||
firstName: user.firstName,
|
|
||||||
lastName: user.lastName,
|
|
||||||
username: user.username,
|
|
||||||
phone: user.phone,
|
|
||||||
photo: user.photo,
|
|
||||||
botInfo: user.botInfo,
|
|
||||||
restrictionInfo: user.restrictionInfo,
|
|
||||||
flags: user.flags,
|
|
||||||
emojiStatus: user.emojiStatus,
|
|
||||||
usernames: user.usernames,
|
|
||||||
storiesHidden: user.storiesHidden,
|
|
||||||
nameColor: user.nameColor,
|
|
||||||
backgroundEmojiId: user.backgroundEmojiId,
|
|
||||||
profileColor: user.profileColor,
|
|
||||||
profileBackgroundEmojiId: user.profileBackgroundEmojiId
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _ in 0 ..< 3 {
|
|
||||||
peers.append(makePeer())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
super.init(context: context, component: AdminUserActionsSheetComponent(context: context, chatPeer: chatPeer, peers: peers, messageCount: messageCount, completion: completion), navigationBarAppearance: .none)
|
super.init(context: context, component: AdminUserActionsSheetComponent(context: context, chatPeer: chatPeer, peers: peers, messageCount: messageCount, completion: completion), navigationBarAppearance: .none)
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = .Ignore
|
self.statusBar.statusBarStyle = .Ignore
|
||||||
@ -1128,7 +1465,7 @@ public class AdminUserActionsSheet: ViewControllerComponentContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private let optionExpandUsersIcon: UIImage? = {
|
private let optionExpandUsersIcon: UIImage? = {
|
||||||
let sourceImage = UIImage(bundleImageName: "Chat/Input/Accessory Panels/PanelTextGroupIcon")!
|
let sourceImage = UIImage(bundleImageName: "Item List/InlineIconUsers")!
|
||||||
return generateImage(CGSize(width: sourceImage.size.width, height: sourceImage.size.height), rotatedContext: { size, context in
|
return generateImage(CGSize(width: sourceImage.size.width, height: sourceImage.size.height), rotatedContext: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
UIGraphicsPushContext(context)
|
UIGraphicsPushContext(context)
|
||||||
@ -1185,21 +1522,21 @@ private final class OptionSectionExpandIndicatorComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func update(component: OptionSectionExpandIndicatorComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(component: OptionSectionExpandIndicatorComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
let countArrowSpacing: CGFloat = -1.0
|
let countArrowSpacing: CGFloat = 1.0
|
||||||
let iconCountSpacing: CGFloat = 2.0
|
let iconCountSpacing: CGFloat = 1.0
|
||||||
|
|
||||||
if self.iconView.image == nil {
|
if self.iconView.image == nil {
|
||||||
self.iconView.image = optionExpandUsersIcon
|
self.iconView.image = optionExpandUsersIcon
|
||||||
}
|
}
|
||||||
self.iconView.tintColor = component.theme.list.itemPrimaryTextColor
|
self.iconView.tintColor = component.theme.list.itemPrimaryTextColor
|
||||||
let iconSize = CGSize(width: 12.0, height: 12.0)
|
let iconSize = self.iconView.image?.size ?? CGSize(width: 12.0, height: 12.0)
|
||||||
|
|
||||||
if self.arrowView.image == nil {
|
if self.arrowView.image == nil {
|
||||||
self.arrowView.image = PresentationResourcesItemList.downArrowImage(component.theme)?.withRenderingMode(.alwaysTemplate)
|
self.arrowView.image = PresentationResourcesItemList.expandDownArrowImage(component.theme)
|
||||||
}
|
}
|
||||||
self.arrowView.tintColor = component.theme.list.itemPrimaryTextColor
|
self.arrowView.tintColor = component.theme.list.itemPrimaryTextColor
|
||||||
|
let arrowSize = self.arrowView.image?.size ?? CGSize(width: 1.0, height: 1.0)
|
||||||
|
|
||||||
let arrowSize = CGSize(width: 20.0, height: 20.0)
|
|
||||||
let countSize = self.count.update(
|
let countSize = self.count.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(MultilineTextComponent(
|
component: AnyComponent(MultilineTextComponent(
|
||||||
@ -1211,12 +1548,7 @@ private final class OptionSectionExpandIndicatorComponent: Component {
|
|||||||
|
|
||||||
let size = CGSize(width: 60.0, height: availableSize.height)
|
let size = CGSize(width: 60.0, height: availableSize.height)
|
||||||
|
|
||||||
var arrowFrame = CGRect(origin: CGPoint(x: size.width - arrowSize.width - 10.0, y: floor((size.height - arrowSize.height) * 0.5)), size: arrowSize)
|
let arrowFrame = CGRect(origin: CGPoint(x: size.width - arrowSize.width - 12.0, y: floor((size.height - arrowSize.height) * 0.5)), size: arrowSize)
|
||||||
if component.isExpanded {
|
|
||||||
arrowFrame = arrowFrame.offsetBy(dx: 0.0, dy: -1.0)
|
|
||||||
} else {
|
|
||||||
arrowFrame = arrowFrame.offsetBy(dx: 0.0, dy: 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
let countFrame = CGRect(origin: CGPoint(x: arrowFrame.minX - countArrowSpacing - countSize.width, y: floor((size.height - countSize.height) * 0.5)), size: countSize)
|
let countFrame = CGRect(origin: CGPoint(x: arrowFrame.minX - countArrowSpacing - countSize.width, y: floor((size.height - countSize.height) * 0.5)), size: countSize)
|
||||||
|
|
||||||
@ -1229,9 +1561,9 @@ private final class OptionSectionExpandIndicatorComponent: Component {
|
|||||||
countView.frame = countFrame
|
countView.frame = countFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.setPosition(view: self.arrowView, position: arrowFrame.center)
|
self.arrowView.center = arrowFrame.center
|
||||||
self.arrowView.bounds = CGRect(origin: CGPoint(), size: arrowFrame.size)
|
self.arrowView.bounds = CGRect(origin: CGPoint(), size: arrowFrame.size)
|
||||||
transition.setTransform(view: self.arrowView, transform: CATransform3DMakeRotation(component.isExpanded ? CGFloat.pi : 0.0, 0.0, 0.0, 1.0))
|
transition.setTransform(view: self.arrowView, transform: CATransform3DTranslate(CATransform3DMakeRotation(component.isExpanded ? CGFloat.pi : 0.0, 0.0, 0.0, 1.0), 0.0, component.isExpanded ? 1.0 : 0.0, 0.0))
|
||||||
|
|
||||||
self.iconView.frame = iconFrame
|
self.iconView.frame = iconFrame
|
||||||
|
|
||||||
@ -1248,6 +1580,97 @@ private final class OptionSectionExpandIndicatorComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class MediaSectionExpandIndicatorComponent: Component {
|
||||||
|
let theme: PresentationTheme
|
||||||
|
let title: String
|
||||||
|
let isExpanded: Bool
|
||||||
|
|
||||||
|
init(
|
||||||
|
theme: PresentationTheme,
|
||||||
|
title: String,
|
||||||
|
isExpanded: Bool
|
||||||
|
) {
|
||||||
|
self.theme = theme
|
||||||
|
self.title = title
|
||||||
|
self.isExpanded = isExpanded
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: MediaSectionExpandIndicatorComponent, rhs: MediaSectionExpandIndicatorComponent) -> Bool {
|
||||||
|
if lhs.theme !== rhs.theme {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.title != rhs.title {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.isExpanded != rhs.isExpanded {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
final class View: UIView {
|
||||||
|
private let arrowView: UIImageView
|
||||||
|
private let title = ComponentView<Empty>()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
self.arrowView = UIImageView()
|
||||||
|
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.addSubview(self.arrowView)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(component: MediaSectionExpandIndicatorComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
let titleArrowSpacing: CGFloat = 1.0
|
||||||
|
|
||||||
|
if self.arrowView.image == nil {
|
||||||
|
self.arrowView.image = PresentationResourcesItemList.expandDownArrowImage(component.theme)
|
||||||
|
}
|
||||||
|
self.arrowView.tintColor = component.theme.list.itemPrimaryTextColor
|
||||||
|
let arrowSize = self.arrowView.image?.size ?? CGSize(width: 1.0, height: 1.0)
|
||||||
|
|
||||||
|
let titleSize = self.title.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(string: component.title, font: Font.semibold(13.0), textColor: component.theme.list.itemPrimaryTextColor))
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
let size = CGSize(width: titleSize.width + titleArrowSpacing + arrowSize.width, height: titleSize.height)
|
||||||
|
|
||||||
|
let titleFrame = CGRect(origin: CGPoint(x: 0.0, y: floor((size.height - titleSize.height) * 0.5)), size: titleSize)
|
||||||
|
let arrowFrame = CGRect(origin: CGPoint(x: titleFrame.maxX + titleArrowSpacing, y: floor((size.height - arrowSize.height) * 0.5) + 2.0), size: arrowSize)
|
||||||
|
|
||||||
|
if let titleView = self.title.view {
|
||||||
|
if titleView.superview == nil {
|
||||||
|
self.addSubview(titleView)
|
||||||
|
}
|
||||||
|
titleView.frame = titleFrame
|
||||||
|
}
|
||||||
|
|
||||||
|
self.arrowView.center = arrowFrame.center
|
||||||
|
self.arrowView.bounds = CGRect(origin: CGPoint(), size: arrowFrame.size)
|
||||||
|
transition.setTransform(view: self.arrowView, transform: CATransform3DTranslate(CATransform3DMakeRotation(component.isExpanded ? CGFloat.pi : 0.0, 0.0, 0.0, 1.0), 0.0, component.isExpanded ? 1.0 : -1.0, 0.0))
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeView() -> View {
|
||||||
|
return View(frame: CGRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final class OptionsSectionFooterComponent: Component {
|
private final class OptionsSectionFooterComponent: Component {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let text: String
|
let text: String
|
||||||
@ -1304,11 +1727,10 @@ private final class OptionsSectionFooterComponent: Component {
|
|||||||
|
|
||||||
func update(component: OptionsSectionFooterComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(component: OptionsSectionFooterComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
if self.arrowView.image == nil {
|
if self.arrowView.image == nil {
|
||||||
self.arrowView.image = PresentationResourcesItemList.downArrowImage(component.theme)?.withRenderingMode(.alwaysTemplate)
|
self.arrowView.image = PresentationResourcesItemList.expandSmallDownArrowImage(component.theme)
|
||||||
}
|
}
|
||||||
self.arrowView.tintColor = component.theme.list.itemAccentColor
|
self.arrowView.tintColor = component.theme.list.itemAccentColor
|
||||||
|
let arrowSize = self.arrowView.image?.size ?? CGSize(width: 1.0, height: 1.0)
|
||||||
let arrowSize = CGSize(width: 14.0, height: 14.0)
|
|
||||||
|
|
||||||
let attributedText = NSMutableAttributedString(attributedString: NSAttributedString(string: component.text, font: Font.regular(component.fontSize), textColor: component.theme.list.itemAccentColor))
|
let attributedText = NSMutableAttributedString(attributedString: NSAttributedString(string: component.text, font: Font.regular(component.fontSize), textColor: component.theme.list.itemAccentColor))
|
||||||
attributedText.append(NSAttributedString(string: ">", font: Font.regular(component.fontSize), textColor: .clear))
|
attributedText.append(NSAttributedString(string: ">", font: Font.regular(component.fontSize), textColor: .clear))
|
||||||
@ -1321,7 +1743,7 @@ private final class OptionsSectionFooterComponent: Component {
|
|||||||
|
|
||||||
var arrowFrame = CGRect()
|
var arrowFrame = CGRect()
|
||||||
if let lineRect = textLayout.linesRects().last {
|
if let lineRect = textLayout.linesRects().last {
|
||||||
arrowFrame = CGRect(origin: CGPoint(x: textFrame.minX + lineRect.maxX - arrowSize.width + 6.0, y: textFrame.minY + lineRect.maxY - lineRect.height - arrowSize.height + 4.0), size: arrowSize)
|
arrowFrame = CGRect(origin: CGPoint(x: textFrame.minX + lineRect.maxX - arrowSize.width + 6.0, y: textFrame.minY + lineRect.maxY - lineRect.height - arrowSize.height - 1.0), size: arrowSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.arrowView.center = arrowFrame.center
|
self.arrowView.center = arrowFrame.center
|
||||||
|
@ -403,7 +403,7 @@ public class ChatMessageForwardInfoNode: ASDisplayNode {
|
|||||||
if let current = node.avatarNode {
|
if let current = node.avatarNode {
|
||||||
avatarNode = current
|
avatarNode = current
|
||||||
} else {
|
} else {
|
||||||
avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 11.0))
|
avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 8.0))
|
||||||
node.avatarNode = avatarNode
|
node.avatarNode = avatarNode
|
||||||
node.addSubnode(avatarNode)
|
node.addSubnode(avatarNode)
|
||||||
}
|
}
|
||||||
|
@ -607,6 +607,7 @@ public final class ListActionItemComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switchNode.isUserInteractionEnabled = toggle.isInteractive
|
switchNode.isUserInteractionEnabled = toggle.isInteractive
|
||||||
|
|
||||||
if updateSwitchTheme {
|
if updateSwitchTheme {
|
||||||
@ -624,11 +625,15 @@ public final class ListActionItemComponent: Component {
|
|||||||
var updateSwitchTheme = themeUpdated
|
var updateSwitchTheme = themeUpdated
|
||||||
if let current = self.iconSwitchNode {
|
if let current = self.iconSwitchNode {
|
||||||
switchNode = current
|
switchNode = current
|
||||||
|
switchNode.updateIsLocked(toggle.style == .lock)
|
||||||
|
if switchNode.isOn != toggle.isOn {
|
||||||
switchNode.setOn(toggle.isOn, animated: !transition.animation.isImmediate)
|
switchNode.setOn(toggle.isOn, animated: !transition.animation.isImmediate)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switchTransition = switchTransition.withAnimation(.none)
|
switchTransition = switchTransition.withAnimation(.none)
|
||||||
updateSwitchTheme = true
|
updateSwitchTheme = true
|
||||||
switchNode = IconSwitchNode()
|
switchNode = IconSwitchNode()
|
||||||
|
switchNode.updateIsLocked(toggle.style == .lock)
|
||||||
switchNode.setOn(toggle.isOn, animated: false)
|
switchNode.setOn(toggle.isOn, animated: false)
|
||||||
self.iconSwitchNode = switchNode
|
self.iconSwitchNode = switchNode
|
||||||
self.addSubview(switchNode.view)
|
self.addSubview(switchNode.view)
|
||||||
|
@ -7000,7 +7000,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
UIPasteboard.general.string = bioText
|
UIPasteboard.general.string = bioText
|
||||||
|
|
||||||
self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: self.presentationData.strings.MyProfile_ToastBioCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
let toastText: String
|
||||||
|
if let _ = self.data?.peer as? TelegramUser {
|
||||||
|
toastText = self.presentationData.strings.MyProfile_ToastBioCopied
|
||||||
|
} else {
|
||||||
|
toastText = self.presentationData.strings.ChannelProfile_ToastAboutCopied
|
||||||
|
}
|
||||||
|
|
||||||
|
self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: toastText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||||
}
|
}
|
||||||
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
@ -7027,7 +7034,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_BioActionCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
let copyText: String
|
||||||
|
if let _ = self.data?.peer as? TelegramUser {
|
||||||
|
copyText = self.presentationData.strings.MyProfile_BioActionCopy
|
||||||
|
} else {
|
||||||
|
copyText = self.presentationData.strings.ChannelProfile_AboutActionCopy
|
||||||
|
}
|
||||||
|
items.append(.action(ContextMenuActionItem(text: copyText, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||||
c.dismiss {
|
c.dismiss {
|
||||||
copyAction()
|
copyAction()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "delmsgarrow_16.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
0.000000 -1.000000 1.000000 0.000000 6.177734 10.500000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.586899 7.409164 m
|
||||||
|
0.262763 7.733299 -0.262763 7.733299 -0.586899 7.409164 c
|
||||||
|
-0.911034 7.085029 -0.911034 6.559502 -0.586899 6.235367 c
|
||||||
|
0.586899 7.409164 l
|
||||||
|
h
|
||||||
|
5.000000 1.822266 m
|
||||||
|
5.586899 1.235367 l
|
||||||
|
5.911034 1.559502 5.911034 2.085029 5.586899 2.409164 c
|
||||||
|
5.000000 1.822266 l
|
||||||
|
h
|
||||||
|
-0.586899 -2.590836 m
|
||||||
|
-0.911034 -2.914971 -0.911034 -3.440497 -0.586899 -3.764633 c
|
||||||
|
-0.262763 -4.088768 0.262763 -4.088768 0.586899 -3.764633 c
|
||||||
|
-0.586899 -2.590836 l
|
||||||
|
h
|
||||||
|
-0.586899 6.235367 m
|
||||||
|
4.413101 1.235367 l
|
||||||
|
5.586899 2.409164 l
|
||||||
|
0.586899 7.409164 l
|
||||||
|
-0.586899 6.235367 l
|
||||||
|
h
|
||||||
|
4.413101 2.409164 m
|
||||||
|
-0.586899 -2.590836 l
|
||||||
|
0.586899 -3.764633 l
|
||||||
|
5.586899 1.235367 l
|
||||||
|
4.413101 2.409164 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
780
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 16.000000 16.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000000870 00000 n
|
||||||
|
0000000892 00000 n
|
||||||
|
0000001065 00000 n
|
||||||
|
0000001139 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1198
|
||||||
|
%%EOF
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "arrow.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
0.000000 -1.000000 1.000000 0.000000 3.682617 4.500000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.424264 5.241647 m
|
||||||
|
0.189949 5.475962 -0.189949 5.475962 -0.424264 5.241647 c
|
||||||
|
-0.658579 5.007332 -0.658579 4.627433 -0.424264 4.393119 c
|
||||||
|
0.424264 5.241647 l
|
||||||
|
h
|
||||||
|
3.500000 1.317383 m
|
||||||
|
3.924264 0.893119 l
|
||||||
|
4.158579 1.127433 4.158579 1.507332 3.924264 1.741647 c
|
||||||
|
3.500000 1.317383 l
|
||||||
|
h
|
||||||
|
-0.424264 -1.758353 m
|
||||||
|
-0.658579 -1.992668 -0.658579 -2.372567 -0.424264 -2.606881 c
|
||||||
|
-0.189949 -2.841196 0.189949 -2.841196 0.424264 -2.606881 c
|
||||||
|
-0.424264 -1.758353 l
|
||||||
|
h
|
||||||
|
-0.424264 4.393119 m
|
||||||
|
3.075736 0.893119 l
|
||||||
|
3.924264 1.741647 l
|
||||||
|
0.424264 5.241647 l
|
||||||
|
-0.424264 4.393119 l
|
||||||
|
h
|
||||||
|
3.075736 1.741647 m
|
||||||
|
-0.424264 -1.758353 l
|
||||||
|
0.424264 -2.606881 l
|
||||||
|
3.924264 0.893119 l
|
||||||
|
3.075736 1.741647 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
779
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 10.000000 6.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000000869 00000 n
|
||||||
|
0000000891 00000 n
|
||||||
|
0000001063 00000 n
|
||||||
|
0000001137 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1196
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Item List/InlineIconUsers.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Item List/InlineIconUsers.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "delmsgusers_16.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
98
submodules/TelegramUI/Images.xcassets/Item List/InlineIconUsers.imageset/delmsgusers_16.pdf
vendored
Normal file
98
submodules/TelegramUI/Images.xcassets/Item List/InlineIconUsers.imageset/delmsgusers_16.pdf
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 1.385620 3.388916 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
4.505642 6.066639 m
|
||||||
|
5.622485 6.066639 6.527864 6.972019 6.527864 8.088861 c
|
||||||
|
6.527864 9.205704 5.622485 10.111084 4.505642 10.111084 c
|
||||||
|
3.388799 10.111084 2.483420 9.205704 2.483420 8.088861 c
|
||||||
|
2.483420 6.972019 3.388799 6.066639 4.505642 6.066639 c
|
||||||
|
h
|
||||||
|
9.128903 6.066618 m
|
||||||
|
10.086196 6.066618 10.862236 6.842658 10.862236 7.799952 c
|
||||||
|
10.862236 8.757245 10.086196 9.533284 9.128903 9.533284 c
|
||||||
|
8.171610 9.533284 7.395570 8.757245 7.395570 7.799952 c
|
||||||
|
7.395570 6.842658 8.171610 6.066618 9.128903 6.066618 c
|
||||||
|
h
|
||||||
|
8.084225 3.303497 m
|
||||||
|
8.414125 2.965264 8.662351 2.592029 8.849121 2.221855 c
|
||||||
|
9.037642 1.848210 9.052315 1.480731 8.941890 1.155545 c
|
||||||
|
8.715535 0.488963 7.963518 0.000092 7.105636 0.000092 c
|
||||||
|
1.905633 0.000092 l
|
||||||
|
0.629242 0.000092 -0.412813 1.082295 0.162149 2.221854 c
|
||||||
|
0.759815 3.406412 1.986777 4.622314 4.505635 4.622314 c
|
||||||
|
5.505974 4.622314 6.302553 4.430541 6.936879 4.125120 c
|
||||||
|
6.951430 4.118114 6.965898 4.111050 6.980279 4.103925 c
|
||||||
|
7.194489 3.997796 7.389868 3.878607 7.568068 3.749475 c
|
||||||
|
7.759200 3.610973 7.930571 3.461031 8.084225 3.303497 c
|
||||||
|
h
|
||||||
|
7.816253 4.510825 m
|
||||||
|
8.649220 3.970058 9.188520 3.255078 9.535180 2.568007 c
|
||||||
|
9.778294 2.086163 9.829369 1.599931 9.736712 1.155545 c
|
||||||
|
11.150474 1.155545 l
|
||||||
|
12.107767 1.155545 12.888267 1.965531 12.464911 2.824125 c
|
||||||
|
12.013588 3.739441 11.076003 4.690186 9.128251 4.690186 c
|
||||||
|
8.623553 4.690186 8.186680 4.626350 7.808517 4.515837 c
|
||||||
|
7.816253 4.510825 l
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1521
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 16.000000 16.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000001611 00000 n
|
||||||
|
0000001634 00000 n
|
||||||
|
0000001807 00000 n
|
||||||
|
0000001881 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1940
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Item List/SwitchLockIcon.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Item List/SwitchLockIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "lock.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
91
submodules/TelegramUI/Images.xcassets/Item List/SwitchLockIcon.imageset/lock.pdf
vendored
Normal file
91
submodules/TelegramUI/Images.xcassets/Item List/SwitchLockIcon.imageset/lock.pdf
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.904785 0.982666 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
6.094680 16.137451 m
|
||||||
|
3.493683 16.137451 1.385156 14.028931 1.385156 11.427931 c
|
||||||
|
1.385156 8.649511 l
|
||||||
|
0.873086 8.316221 0.469098 7.833959 0.231986 7.261518 c
|
||||||
|
0.000000 6.701453 0.000000 5.991447 0.000000 4.571436 c
|
||||||
|
0.000000 3.151424 0.000000 2.441419 0.231986 1.881354 c
|
||||||
|
0.541301 1.134602 1.134594 0.541308 1.881347 0.231994 c
|
||||||
|
2.441411 0.000008 3.151414 0.000008 4.571422 0.000008 c
|
||||||
|
7.619050 0.000008 l
|
||||||
|
9.039061 0.000008 9.749065 0.000008 10.309130 0.231994 c
|
||||||
|
11.055882 0.541308 11.649176 1.134602 11.958490 1.881354 c
|
||||||
|
12.190476 2.441419 12.190476 3.151424 12.190476 4.571436 c
|
||||||
|
12.190476 5.991447 12.190476 6.701453 11.958490 7.261518 c
|
||||||
|
11.721206 7.834374 11.316802 8.316923 10.804203 8.650238 c
|
||||||
|
10.804203 11.427927 l
|
||||||
|
10.804203 14.028925 8.695679 16.137451 6.094680 16.137451 c
|
||||||
|
h
|
||||||
|
9.004204 9.128557 m
|
||||||
|
9.004204 11.427927 l
|
||||||
|
9.004204 13.034813 7.701565 14.337451 6.094680 14.337451 c
|
||||||
|
4.487793 14.337451 3.185156 13.034816 3.185156 11.427931 c
|
||||||
|
3.185156 9.128514 l
|
||||||
|
3.559292 9.142864 4.009834 9.142864 4.571427 9.142864 c
|
||||||
|
7.619054 9.142864 l
|
||||||
|
8.180087 9.142864 8.630290 9.142864 9.004204 9.128557 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1216
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 14.000000 18.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000001306 00000 n
|
||||||
|
0000001329 00000 n
|
||||||
|
0000001502 00000 n
|
||||||
|
0000001576 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1635
|
||||||
|
%%EOF
|
@ -26,7 +26,7 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
let title: String = "Messages Deleted"
|
var title: String? = messageIds.count == 1 ? "Message Deleted" : "Messages Deleted"
|
||||||
var text: String = ""
|
var text: String = ""
|
||||||
var undoRights: [EnginePeer.Id: InitialBannedRights] = [:]
|
var undoRights: [EnginePeer.Id: InitialBannedRights] = [:]
|
||||||
|
|
||||||
@ -35,9 +35,9 @@ extension ChatControllerImpl {
|
|||||||
text.append("\n")
|
text.append("\n")
|
||||||
}
|
}
|
||||||
if result.reportSpamPeers.count == 1 {
|
if result.reportSpamPeers.count == 1 {
|
||||||
text.append("**1** user reported for spam")
|
text.append("**1** user reported for spam.")
|
||||||
} else {
|
} else {
|
||||||
text.append("**\(result.reportSpamPeers.count)** users reported for spam")
|
text.append("**\(result.reportSpamPeers.count)** users reported for spam.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !result.banPeers.isEmpty {
|
if !result.banPeers.isEmpty {
|
||||||
@ -45,9 +45,9 @@ extension ChatControllerImpl {
|
|||||||
text.append("\n")
|
text.append("\n")
|
||||||
}
|
}
|
||||||
if result.banPeers.count == 1 {
|
if result.banPeers.count == 1 {
|
||||||
text.append("**1** user banned")
|
text.append("**1** user banned.")
|
||||||
} else {
|
} else {
|
||||||
text.append("**\(result.banPeers.count)** users banned")
|
text.append("**\(result.banPeers.count)** users banned.")
|
||||||
}
|
}
|
||||||
for id in result.banPeers {
|
for id in result.banPeers {
|
||||||
if let value = initialUserBannedRights[id] {
|
if let value = initialUserBannedRights[id] {
|
||||||
@ -60,9 +60,9 @@ extension ChatControllerImpl {
|
|||||||
text.append("\n")
|
text.append("\n")
|
||||||
}
|
}
|
||||||
if result.updateBannedRights.count == 1 {
|
if result.updateBannedRights.count == 1 {
|
||||||
text.append("**1** user restricted")
|
text.append("**1** user restricted.")
|
||||||
} else {
|
} else {
|
||||||
text.append("**\(result.updateBannedRights.count)** users restricted")
|
text.append("**\(result.updateBannedRights.count)** users restricted.")
|
||||||
}
|
}
|
||||||
for id in result.banPeers {
|
for id in result.banPeers {
|
||||||
if let value = initialUserBannedRights[id] {
|
if let value = initialUserBannedRights[id] {
|
||||||
@ -92,10 +92,15 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if text.isEmpty {
|
||||||
|
text = messageIds.count == 1 ? "Message Deleted." : "Messages Deleted."
|
||||||
|
title = nil
|
||||||
|
}
|
||||||
|
|
||||||
self.present(
|
self.present(
|
||||||
UndoOverlayController(
|
UndoOverlayController(
|
||||||
presentationData: self.presentationData,
|
presentationData: self.presentationData,
|
||||||
content: undoRights.isEmpty ? .actionSucceeded(title: text.isEmpty ? nil : title, text: text.isEmpty ? title : text, cancel: nil, destructive: false) : .removedChat(title: title, text: text),
|
content: undoRights.isEmpty ? .actionSucceeded(title: title, text: text, cancel: nil, destructive: false) : .removedChat(title: title ?? text, text: title == nil ? nil : text),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
action: { [weak self] action in
|
action: { [weak self] action in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -140,12 +145,19 @@ extension ChatControllerImpl {
|
|||||||
guard let self, let chatPeer else {
|
guard let self, let chatPeer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var peers: [EnginePeer] = []
|
var renderedParticipants: [RenderedChannelParticipant] = []
|
||||||
var initialUserBannedRights: [EnginePeer.Id: InitialBannedRights] = [:]
|
var initialUserBannedRights: [EnginePeer.Id: InitialBannedRights] = [:]
|
||||||
for maybeParticipant in participants {
|
for maybeParticipant in participants {
|
||||||
guard let participant = maybeParticipant else {
|
guard let participant = maybeParticipant else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
guard let peer = authors.first(where: { $0.id == participant.peerId }) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
renderedParticipants.append(RenderedChannelParticipant(
|
||||||
|
participant: participant,
|
||||||
|
peer: peer
|
||||||
|
))
|
||||||
switch participant {
|
switch participant {
|
||||||
case .creator:
|
case .creator:
|
||||||
break
|
break
|
||||||
@ -157,13 +169,10 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for author in authors {
|
|
||||||
peers.append(EnginePeer(author))
|
|
||||||
}
|
|
||||||
self.push(AdminUserActionsSheet(
|
self.push(AdminUserActionsSheet(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
chatPeer: chatPeer,
|
chatPeer: chatPeer,
|
||||||
peers: peers,
|
peers: renderedParticipants,
|
||||||
messageCount: messageIds.count,
|
messageCount: messageIds.count,
|
||||||
completion: { [weak self] result in
|
completion: { [weak self] result in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -186,6 +195,9 @@ extension ChatControllerImpl {
|
|||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] participant in
|
|> deliverOnMainQueue).startStrict(next: { [weak self] participant in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
|
guard let participant else {
|
||||||
|
return
|
||||||
|
}
|
||||||
let _ = (strongSelf.context.engine.data.get(
|
let _ = (strongSelf.context.engine.data.get(
|
||||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
|
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
|
||||||
TelegramEngine.EngineData.Item.Peer.Peer(id: author.id)
|
TelegramEngine.EngineData.Item.Peer.Peer(id: author.id)
|
||||||
@ -198,7 +210,6 @@ extension ChatControllerImpl {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var initialUserBannedRights: [EnginePeer.Id: InitialBannedRights] = [:]
|
var initialUserBannedRights: [EnginePeer.Id: InitialBannedRights] = [:]
|
||||||
if let participant {
|
|
||||||
switch participant {
|
switch participant {
|
||||||
case .creator:
|
case .creator:
|
||||||
break
|
break
|
||||||
@ -209,11 +220,13 @@ extension ChatControllerImpl {
|
|||||||
initialUserBannedRights[participant.peerId] = InitialBannedRights(value: nil)
|
initialUserBannedRights[participant.peerId] = InitialBannedRights(value: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.push(AdminUserActionsSheet(
|
self.push(AdminUserActionsSheet(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
chatPeer: chatPeer,
|
chatPeer: chatPeer,
|
||||||
peers: [authorPeer],
|
peers: [RenderedChannelParticipant(
|
||||||
|
participant: participant,
|
||||||
|
peer: authorPeer._asPeer()
|
||||||
|
)],
|
||||||
messageCount: messageIds.count,
|
messageCount: messageIds.count,
|
||||||
completion: { [weak self] result in
|
completion: { [weak self] result in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
@ -2182,7 +2182,7 @@ func chatAvailableMessageActionsImpl(engine: TelegramEngine, accountPeerId: Peer
|
|||||||
if message.flags.contains(.Incoming) {
|
if message.flags.contains(.Incoming) {
|
||||||
optionsMap[id]!.insert(.report)
|
optionsMap[id]!.insert(.report)
|
||||||
}
|
}
|
||||||
if channel.hasPermission(.banMembers), case .group = channel.info {
|
if (channel.hasPermission(.banMembers) || channel.hasPermission(.deleteAllMessages)), case .group = channel.info {
|
||||||
if message.flags.contains(.Incoming) {
|
if message.flags.contains(.Incoming) {
|
||||||
if let author = message.author {
|
if let author = message.author {
|
||||||
if author is TelegramUser {
|
if author is TelegramUser {
|
||||||
|
@ -1501,11 +1501,19 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
var alertTitle: String?
|
var alertTitle: String?
|
||||||
let alertText: String
|
let alertText: String
|
||||||
if let reason {
|
if let reason {
|
||||||
|
if case .touchId = LocalAuth.biometricAuthentication {
|
||||||
|
alertTitle = self.presentationData.strings.WebApp_AlertBiometryAccessTouchIDText(botPeer.compactDisplayTitle).string
|
||||||
|
} else {
|
||||||
alertTitle = self.presentationData.strings.WebApp_AlertBiometryAccessText(botPeer.compactDisplayTitle).string
|
alertTitle = self.presentationData.strings.WebApp_AlertBiometryAccessText(botPeer.compactDisplayTitle).string
|
||||||
|
}
|
||||||
alertText = reason
|
alertText = reason
|
||||||
|
} else {
|
||||||
|
if case .touchId = LocalAuth.biometricAuthentication {
|
||||||
|
alertText = self.presentationData.strings.WebApp_AlertBiometryAccessTouchIDText(botPeer.compactDisplayTitle).string
|
||||||
} else {
|
} else {
|
||||||
alertText = self.presentationData.strings.WebApp_AlertBiometryAccessText(botPeer.compactDisplayTitle).string
|
alertText = self.presentationData.strings.WebApp_AlertBiometryAccessText(botPeer.compactDisplayTitle).string
|
||||||
}
|
}
|
||||||
|
}
|
||||||
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: alertTitle, text: alertText, actions: [
|
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: alertTitle, text: alertText, actions: [
|
||||||
TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_No, action: {
|
TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_No, action: {
|
||||||
updateAccessGranted(false)
|
updateAccessGranted(false)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user