mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Autoremove improvements
This commit is contained in:
parent
dc4a04daa7
commit
60ebcc847a
@ -835,6 +835,7 @@ public final class AvatarBadgeView: UIImageView {
|
||||
|
||||
private var originalContent: OriginalContent?
|
||||
private var parameters: Parameters?
|
||||
private var hasContent: Bool = false
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
@ -845,7 +846,7 @@ public final class AvatarBadgeView: UIImageView {
|
||||
}
|
||||
|
||||
func update(content: OriginalContent) {
|
||||
if self.originalContent != content {
|
||||
if self.originalContent != content || !self.hasContent {
|
||||
self.originalContent = content
|
||||
self.update()
|
||||
}
|
||||
@ -853,7 +854,7 @@ public final class AvatarBadgeView: UIImageView {
|
||||
|
||||
public func update(size: CGSize, text: String) {
|
||||
let parameters = Parameters(size: size, text: text)
|
||||
if self.parameters != parameters {
|
||||
if self.parameters != parameters || !self.hasContent {
|
||||
self.parameters = parameters
|
||||
self.update()
|
||||
}
|
||||
@ -864,6 +865,8 @@ public final class AvatarBadgeView: UIImageView {
|
||||
return
|
||||
}
|
||||
|
||||
self.hasContent = true
|
||||
|
||||
let blurredWidth = 16
|
||||
let blurredHeight = 16
|
||||
guard let blurredContext = DrawingContext(size: CGSize(width: CGFloat(blurredWidth), height: CGFloat(blurredHeight)), scale: 1.0, opaque: true) else {
|
||||
@ -876,8 +879,11 @@ public final class AvatarBadgeView: UIImageView {
|
||||
c.setFillColor(color.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: blurredSize))
|
||||
case let .image(image):
|
||||
c.setFillColor(UIColor.black.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: blurredSize))
|
||||
|
||||
c.scaleBy(x: blurredSize.width / parameters.size.width, y: blurredSize.height / parameters.size.height)
|
||||
let offsetFactor: CGFloat = 1.0 - 0.7071
|
||||
let offsetFactor: CGFloat = 1.0 - 0.6
|
||||
let imageFrame = CGRect(origin: CGPoint(x: parameters.size.width - image.size.width + offsetFactor * parameters.size.width, y: parameters.size.height - image.size.height + offsetFactor * parameters.size.height), size: image.size)
|
||||
|
||||
UIGraphicsPushContext(c)
|
||||
@ -900,7 +906,7 @@ public final class AvatarBadgeView: UIImageView {
|
||||
UInt32(15),
|
||||
UInt32(15),
|
||||
nil,
|
||||
vImage_Flags(kvImageEdgeExtend)
|
||||
vImage_Flags(kvImageTruncateKernel | kvImageDoNotTile)
|
||||
)
|
||||
|
||||
let divisor: Int32 = 0x1000
|
||||
@ -909,7 +915,7 @@ public final class AvatarBadgeView: UIImageView {
|
||||
let gwgt: CGFloat = 0.6094
|
||||
let bwgt: CGFloat = 0.0820
|
||||
|
||||
let adjustSaturation: CGFloat = 1.9
|
||||
let adjustSaturation: CGFloat = 1.7
|
||||
|
||||
let a = (1.0 - adjustSaturation) * rwgt + adjustSaturation
|
||||
let b = (1.0 - adjustSaturation) * rwgt
|
||||
@ -927,8 +933,31 @@ public final class AvatarBadgeView: UIImageView {
|
||||
g, h, i, 0,
|
||||
0, 0, 0, 1
|
||||
]
|
||||
|
||||
let brightness: CGFloat = 0.94
|
||||
let brighnessMatrix: [CGFloat] = [
|
||||
brightness, 0, 0, 0,
|
||||
0, brightness, 0, 0,
|
||||
0, 0, brightness, 0,
|
||||
0, 0, 0, 1
|
||||
]
|
||||
|
||||
func matrixMul(a: [CGFloat], b: [CGFloat], result: inout [CGFloat]) {
|
||||
for i in 0 ..< 4 {
|
||||
for j in 0 ..< 4 {
|
||||
var sum: CGFloat = 0.0
|
||||
for k in 0 ..< 4 {
|
||||
sum += a[i + k * 4] * b[k + j * 4]
|
||||
}
|
||||
result[i + j * 4] = sum
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var resultMatrix = Array<CGFloat>(repeating: 0.0, count: 4 * 4)
|
||||
matrixMul(a: satMatrix, b: brighnessMatrix, result: &resultMatrix)
|
||||
|
||||
var matrix: [Int16] = satMatrix.map { value in
|
||||
var matrix: [Int16] = resultMatrix.map { value in
|
||||
return Int16(value * CGFloat(divisor))
|
||||
}
|
||||
|
||||
@ -947,14 +976,14 @@ public final class AvatarBadgeView: UIImageView {
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setBlendMode(.sourceIn)
|
||||
|
||||
blurredImage.draw(in: CGRect(origin: CGPoint(), size: size), blendMode: .sourceIn, alpha: 1.0)
|
||||
|
||||
context.setBlendMode(.normal)
|
||||
|
||||
context.setFillColor(UIColor(white: 0.0, alpha: 0.05).cgColor)
|
||||
/*context.setFillColor(UIColor(white: 1.0, alpha: 0.08).cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(UIColor(white: 0.0, alpha: 0.05).cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))*/
|
||||
|
||||
let string = NSAttributedString(string: parameters.text, font: Font.bold(floor(parameters.size.height * 0.48)), textColor: .white)
|
||||
let stringBounds = string.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
|
||||
@ -970,7 +999,6 @@ public final class AvatarBadgeView: UIImageView {
|
||||
context.addArc(center: CGPoint(x: size.width * 0.5, y: size.height * 0.5), radius: lineRadius, startAngle: CGFloat.pi * 0.5, endAngle: -CGFloat.pi * 0.5, clockwise: false)
|
||||
context.strokePath()
|
||||
|
||||
|
||||
let sectionAngle: CGFloat = CGFloat.pi / 11.0
|
||||
|
||||
for i in 0 ..< 10 {
|
||||
@ -978,15 +1006,13 @@ public final class AvatarBadgeView: UIImageView {
|
||||
continue
|
||||
}
|
||||
|
||||
let startAngle = CGFloat.pi * 0.5 - CGFloat(i) * sectionAngle - sectionAngle * 0.1
|
||||
let endAngle = startAngle - sectionAngle * 0.8
|
||||
let startAngle = CGFloat.pi * 0.5 - CGFloat(i) * sectionAngle - sectionAngle * 0.15
|
||||
let endAngle = startAngle - sectionAngle * 0.75
|
||||
|
||||
context.addArc(center: CGPoint(x: size.width * 0.5, y: size.height * 0.5), radius: lineRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||
context.strokePath()
|
||||
}
|
||||
|
||||
//context.strokeEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 2.0 + lineWidth * 0.5, dy: 2.0 + lineWidth * 0.5))
|
||||
|
||||
UIGraphicsPopContext()
|
||||
})
|
||||
}
|
||||
|
@ -2665,19 +2665,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
avatarBadgeBackground.bounds = CGRect(origin: CGPoint(), size: avatarBadgeBackgroundFrame.size)
|
||||
|
||||
if animateIn {
|
||||
ContainedViewLayoutTransition.immediate.updateSublayerTransformScale(node: avatarBadgeNode, scale: 0.001)
|
||||
ContainedViewLayoutTransition.immediate.updateTransformScale(layer: avatarBadgeBackground.layer, scale: 0.001)
|
||||
ContainedViewLayoutTransition.immediate.updateSublayerTransformScale(node: avatarBadgeNode, scale: 0.00001)
|
||||
ContainedViewLayoutTransition.immediate.updateTransformScale(layer: avatarBadgeBackground.layer, scale: 0.00001)
|
||||
}
|
||||
transition.updateSublayerTransformScale(node: avatarBadgeNode, scale: max(0.001, inlineNavigationLocation.progress))
|
||||
transition.updateTransformScale(layer: avatarBadgeBackground.layer, scale: max(0.001, inlineNavigationLocation.progress))
|
||||
transition.updateSublayerTransformScale(node: avatarBadgeNode, scale: max(0.00001, inlineNavigationLocation.progress))
|
||||
transition.updateTransformScale(layer: avatarBadgeBackground.layer, scale: max(0.00001, inlineNavigationLocation.progress))
|
||||
} else if let avatarBadgeNode = strongSelf.avatarBadgeNode {
|
||||
strongSelf.avatarBadgeNode = nil
|
||||
transition.updateSublayerTransformScale(node: avatarBadgeNode, scale: 0.001, completion: { [weak avatarBadgeNode] _ in
|
||||
transition.updateSublayerTransformScale(node: avatarBadgeNode, scale: 0.00001, completion: { [weak avatarBadgeNode] _ in
|
||||
avatarBadgeNode?.removeFromSupernode()
|
||||
})
|
||||
if let avatarBadgeBackground = strongSelf.avatarBadgeBackground {
|
||||
strongSelf.avatarBadgeBackground = nil
|
||||
transition.updateTransformScale(layer: avatarBadgeBackground.layer, scale: 0.001, completion: { [weak avatarBadgeBackground] _ in
|
||||
transition.updateTransformScale(layer: avatarBadgeBackground.layer, scale: 0.00001, completion: { [weak avatarBadgeBackground] _ in
|
||||
avatarBadgeBackground?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
@ -2747,7 +2747,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
let onlineInlineNavigationFraction: CGFloat = item.interaction.inlineNavigationLocation?.progress ?? 0.0
|
||||
transition.updateAlpha(node: strongSelf.onlineNode, alpha: 1.0 - onlineInlineNavigationFraction)
|
||||
transition.updateSublayerTransformScale(node: strongSelf.onlineNode, scale: (1.0 - onlineInlineNavigationFraction) * 1.0 + onlineInlineNavigationFraction * 0.001)
|
||||
transition.updateSublayerTransformScale(node: strongSelf.onlineNode, scale: (1.0 - onlineInlineNavigationFraction) * 1.0 + onlineInlineNavigationFraction * 0.00001)
|
||||
|
||||
let onlineIcon: UIImage?
|
||||
if strongSelf.reallyHighlighted {
|
||||
@ -2775,7 +2775,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
avatarTimerTransition = .immediate
|
||||
avatarTimerBadge = AvatarBadgeView(frame: CGRect())
|
||||
strongSelf.avatarTimerBadge = avatarTimerBadge
|
||||
strongSelf.avatarNode.badgeView = avatarTimerBadge
|
||||
strongSelf.contextContainer.view.addSubview(avatarTimerBadge)
|
||||
}
|
||||
let avatarBadgeSize = CGSize(width: avatarTimerBadgeDiameter, height: avatarTimerBadgeDiameter)
|
||||
@ -2783,7 +2782,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
let avatarBadgeFrame = CGRect(origin: CGPoint(x: avatarFrame.maxX - avatarBadgeSize.width, y: avatarFrame.maxY - avatarBadgeSize.height), size: avatarBadgeSize)
|
||||
avatarTimerTransition.updatePosition(layer: avatarTimerBadge.layer, position: avatarBadgeFrame.center)
|
||||
avatarTimerTransition.updateBounds(layer: avatarTimerBadge.layer, bounds: CGRect(origin: CGPoint(), size: avatarBadgeFrame.size))
|
||||
avatarTimerTransition.updateTransformScale(layer: avatarTimerBadge.layer, scale: autoremoveTimeoutFraction * 1.0 + (1.0 - autoremoveTimeoutFraction) * 0.001)
|
||||
avatarTimerTransition.updateTransformScale(layer: avatarTimerBadge.layer, scale: autoremoveTimeoutFraction * 1.0 + (1.0 - autoremoveTimeoutFraction) * 0.00001)
|
||||
|
||||
strongSelf.avatarNode.badgeView = avatarTimerBadge
|
||||
} else if let avatarTimerBadge = strongSelf.avatarTimerBadge {
|
||||
strongSelf.avatarTimerBadge = nil
|
||||
strongSelf.avatarNode.badgeView = nil
|
||||
|
@ -187,7 +187,8 @@ private func globalAutoremoveScreenEntries(presentationData: PresentationData, s
|
||||
if effectiveCurrentValue == 0 {
|
||||
entries.append(.info("If enabled, all new messages in chats you start will be automatically deleted for everyone at some point after they have been sent. This will not affect your existing chats."))
|
||||
} else {
|
||||
entries.append(.info("All new messages in chats you started will be automatically deleted for everyone 3 weeks after they have been sent. You can also [apply this setting for your existing chats]()."))
|
||||
|
||||
entries.append(.info("All new messages in chats you started will be automatically deleted for everyone \(timeIntervalString(strings: presentationData.strings, value: effectiveCurrentValue)) after they have been sent. You can also [apply this setting for your existing chats]()."))
|
||||
}
|
||||
|
||||
return entries
|
||||
|
@ -207,3 +207,23 @@ extension SelectivePrivacySettings {
|
||||
self = current.withEnabledPeers(enableFor).withDisabledPeers(disableFor)
|
||||
}
|
||||
}
|
||||
|
||||
public struct GlobalMessageAutoremoveTimeoutSettings: Equatable, Codable {
|
||||
public static var `default` = GlobalMessageAutoremoveTimeoutSettings(
|
||||
messageAutoremoveTimeout: nil
|
||||
)
|
||||
|
||||
public var messageAutoremoveTimeout: Int32?
|
||||
|
||||
public init(messageAutoremoveTimeout: Int32?) {
|
||||
self.messageAutoremoveTimeout = messageAutoremoveTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func updateGlobalMessageAutoremoveTimeoutSettings(transaction: Transaction, _ f: (GlobalMessageAutoremoveTimeoutSettings) -> GlobalMessageAutoremoveTimeoutSettings) {
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.globalMessageAutoremoveTimeoutSettings, { current in
|
||||
let previous = current?.get(GlobalMessageAutoremoveTimeoutSettings.self) ?? GlobalMessageAutoremoveTimeoutSettings.default
|
||||
let updated = f(previous)
|
||||
return PreferencesEntry(updated)
|
||||
})
|
||||
}
|
||||
|
@ -46,8 +46,31 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
let messageId: Int32?
|
||||
var apiMessage: Api.Message?
|
||||
|
||||
var correspondingMessageId: Int32?
|
||||
|
||||
for update in result.allUpdates {
|
||||
switch update {
|
||||
case let .updateMessageID(id, randomId):
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? OutgoingMessageInfoAttribute {
|
||||
if attribute.uniqueId == randomId {
|
||||
correspondingMessageId = id
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for resultMessage in result.messages {
|
||||
if let id = resultMessage.id() {
|
||||
if let correspondingMessageId = correspondingMessageId {
|
||||
if id.id != correspondingMessageId {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if id.peerId == message.id.peerId {
|
||||
apiMessage = resultMessage
|
||||
break
|
||||
|
@ -7,9 +7,11 @@ import MtProtoKit
|
||||
|
||||
func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountManagerTypes>, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = Signal<Void, NoError> { subscriber in
|
||||
return (network.request(Api.functions.help.getConfig())
|
||||
|> retryRequest
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return (combineLatest(
|
||||
network.request(Api.functions.help.getConfig()) |> retryRequest,
|
||||
network.request(Api.functions.messages.getDefaultHistoryTTL()) |> retryRequest
|
||||
)
|
||||
|> mapToSignal { result, defaultHistoryTtl -> Signal<Void, NoError> in
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
switch result {
|
||||
case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, savedGifsLimit, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, stickersFavedLimit, _, _, pinnedDialogsCountMax, pinnedInfolderCountMax, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, captionLengthMax, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion, defaultReaction):
|
||||
@ -71,6 +73,21 @@ func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountM
|
||||
})
|
||||
}
|
||||
|
||||
let messageAutoremoveSeconds: Int32?
|
||||
switch defaultHistoryTtl {
|
||||
case let .defaultHistoryTTL(period):
|
||||
if period != 0 {
|
||||
messageAutoremoveSeconds = period
|
||||
} else {
|
||||
messageAutoremoveSeconds = nil
|
||||
}
|
||||
}
|
||||
updateGlobalMessageAutoremoveTimeoutSettings(transaction: transaction, { settings in
|
||||
var settings = settings
|
||||
settings.messageAutoremoveTimeout = messageAutoremoveSeconds
|
||||
return settings
|
||||
})
|
||||
|
||||
return accountManager.transaction { transaction -> Signal<Void, NoError> in
|
||||
let (primary, secondary) = getLocalization(transaction)
|
||||
var invalidateLocalization = false
|
||||
|
@ -246,6 +246,7 @@ private enum PreferencesKeyValues: Int32 {
|
||||
case secretChatSettings = 23
|
||||
case reactionSettings = 24
|
||||
case premiumPromo = 26
|
||||
case globalMessageAutoremoveTimeoutSettings = 27
|
||||
}
|
||||
|
||||
public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey {
|
||||
@ -374,6 +375,12 @@ public struct PreferencesKeys {
|
||||
key.setInt32(0, value: PreferencesKeyValues.premiumPromo.rawValue)
|
||||
return key
|
||||
}()
|
||||
|
||||
public static let globalMessageAutoremoveTimeoutSettings: ValueBoxKey = {
|
||||
let key = ValueBoxKey(length: 4)
|
||||
key.setInt32(0, value: PreferencesKeyValues.globalMessageAutoremoveTimeoutSettings.rawValue)
|
||||
return key
|
||||
}()
|
||||
}
|
||||
|
||||
private enum SharedDataKeyValues: Int32 {
|
||||
|
@ -379,5 +379,26 @@ public extension TelegramEngine.EngineData.Item {
|
||||
return premiumPromoConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
public struct GlobalAutoremoveTimeout: TelegramEngineDataItem, PostboxViewDataItem {
|
||||
public typealias Result = Int32?
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .preferences(keys: Set([PreferencesKeys.globalMessageAutoremoveTimeoutSettings]))
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? PreferencesView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
guard let settings = view.values[PreferencesKeys.globalMessageAutoremoveTimeoutSettings]?.get(GlobalMessageAutoremoveTimeoutSettings.self) else {
|
||||
return GlobalMessageAutoremoveTimeoutSettings.default.messageAutoremoveTimeout
|
||||
}
|
||||
return settings.messageAutoremoveTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +155,12 @@ func _internal_requestAccountPrivacySettings(account: Account) -> Signal<Account
|
||||
return updated
|
||||
})
|
||||
|
||||
updateGlobalMessageAutoremoveTimeoutSettings(transaction: transaction, { settings in
|
||||
var settings = settings
|
||||
settings.messageAutoremoveTimeout = messageAutoremoveSeconds
|
||||
return settings
|
||||
})
|
||||
|
||||
return AccountPrivacySettings(presence: SelectivePrivacySettings(apiRules: lastSeenRules, peers: peerMap), groupInvitations: SelectivePrivacySettings(apiRules: groupRules, peers: peerMap), voiceCalls: SelectivePrivacySettings(apiRules: voiceRules, peers: peerMap), voiceCallsP2P: SelectivePrivacySettings(apiRules: voiceP2PRules, peers: peerMap), profilePhoto: SelectivePrivacySettings(apiRules: profilePhotoRules, peers: peerMap), forwards: SelectivePrivacySettings(apiRules: forwardRules, peers: peerMap), phoneNumber: SelectivePrivacySettings(apiRules: phoneNumberRules, peers: peerMap), phoneDiscoveryEnabled: phoneDiscoveryValue, voiceMessages: SelectivePrivacySettings(apiRules: voiceMessagesRules, peers: peerMap), automaticallyArchiveAndMuteNonContacts: automaticallyArchiveAndMuteNonContacts, accountRemovalTimeout: accountTimeoutSeconds, messageAutoremoveTimeout: messageAutoremoveSeconds)
|
||||
}
|
||||
}
|
||||
|
@ -298,10 +298,10 @@ private struct CreateGroupState: Equatable {
|
||||
var nameSetFromVenue: Bool
|
||||
var avatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?
|
||||
var location: PeerGeoLocation?
|
||||
var autoremoveTimeout: Int32
|
||||
var autoremoveTimeout: Int32?
|
||||
}
|
||||
|
||||
private func createGroupEntries(presentationData: PresentationData, state: CreateGroupState, peerIds: [PeerId], view: MultiplePeersView, venues: [TelegramMediaMap]?) -> [CreateGroupEntry] {
|
||||
private func createGroupEntries(presentationData: PresentationData, state: CreateGroupState, peerIds: [PeerId], view: MultiplePeersView, venues: [TelegramMediaMap]?, globalAutoremoveTimeout: Int32) -> [CreateGroupEntry] {
|
||||
var entries: [CreateGroupEntry] = []
|
||||
|
||||
let groupInfoState = ItemListAvatarAndNameInfoItemState(editingName: state.editingName, updatingName: nil)
|
||||
@ -311,11 +311,12 @@ private func createGroupEntries(presentationData: PresentationData, state: Creat
|
||||
entries.append(.groupInfo(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, groupInfoState, state.avatar))
|
||||
|
||||
//TODO:localize
|
||||
let autoremoveTimeout = state.autoremoveTimeout ?? globalAutoremoveTimeout
|
||||
let autoRemoveText: String
|
||||
if state.autoremoveTimeout == 0 {
|
||||
if autoremoveTimeout == 0 {
|
||||
autoRemoveText = "Off"
|
||||
} else {
|
||||
autoRemoveText = timeIntervalString(strings: presentationData.strings, value: state.autoremoveTimeout)
|
||||
autoRemoveText = timeIntervalString(strings: presentationData.strings, value: autoremoveTimeout)
|
||||
}
|
||||
entries.append(.autoDelete(title: "Auto-Delete Messages", value: autoRemoveText))
|
||||
entries.append(.autoDeleteInfo("Automatically delete messages sent in this group for everyone after a period of time."))
|
||||
@ -382,7 +383,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
location = PeerGeoLocation(latitude: latitude, longitude: longitude, address: address ?? "")
|
||||
}
|
||||
|
||||
let initialState = CreateGroupState(creating: false, editingName: .title(title: initialTitle ?? "", type: .group), nameSetFromVenue: false, avatar: nil, location: location, autoremoveTimeout: 0)
|
||||
let initialState = CreateGroupState(creating: false, editingName: .title(title: initialTitle ?? "", type: .group), nameSetFromVenue: false, avatar: nil, location: location, autoremoveTimeout: nil)
|
||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: initialState)
|
||||
let updateState: ((CreateGroupState) -> CreateGroupState) -> Void = { f in
|
||||
@ -434,18 +435,21 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
}
|
||||
|
||||
if !creating && !title.isEmpty {
|
||||
updateState { current in
|
||||
var current = current
|
||||
current.creating = true
|
||||
return current
|
||||
}
|
||||
endEditingImpl?()
|
||||
|
||||
let autoremoveTimeout = stateValue.with({ $0 }).autoremoveTimeout
|
||||
let ttlPeriod: Int32? = autoremoveTimeout == 0 ? nil : autoremoveTimeout
|
||||
|
||||
let createSignal: Signal<PeerId?, CreateGroupError>
|
||||
switch mode {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.GlobalAutoremoveTimeout())
|
||||
|> deliverOnMainQueue).start(next: { maybeGlobalAutoremoveTimeout in
|
||||
updateState { current in
|
||||
var current = current
|
||||
current.creating = true
|
||||
return current
|
||||
}
|
||||
endEditingImpl?()
|
||||
|
||||
let globalAutoremoveTimeout: Int32 = maybeGlobalAutoremoveTimeout ?? 0
|
||||
let autoremoveTimeout = stateValue.with({ $0 }).autoremoveTimeout ?? globalAutoremoveTimeout
|
||||
let ttlPeriod: Int32? = autoremoveTimeout == 0 ? nil : autoremoveTimeout
|
||||
|
||||
let createSignal: Signal<PeerId?, CreateGroupError>
|
||||
switch mode {
|
||||
case .generic:
|
||||
createSignal = context.engine.peers.createGroup(title: title, peerIds: peerIds, ttlPeriod: ttlPeriod)
|
||||
case .supergroup:
|
||||
@ -453,16 +457,16 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
|> map(Optional.init)
|
||||
|> mapError { error -> CreateGroupError in
|
||||
switch error {
|
||||
case .generic:
|
||||
return .generic
|
||||
case .restricted:
|
||||
return .restricted
|
||||
case .tooMuchJoined:
|
||||
return .tooMuchJoined
|
||||
case .tooMuchLocationBasedGroups:
|
||||
return .tooMuchLocationBasedGroups
|
||||
case let .serverProvided(error):
|
||||
return .serverProvided(error)
|
||||
case .generic:
|
||||
return .generic
|
||||
case .restricted:
|
||||
return .restricted
|
||||
case .tooMuchJoined:
|
||||
return .tooMuchJoined
|
||||
case .tooMuchLocationBasedGroups:
|
||||
return .tooMuchLocationBasedGroups
|
||||
case let .serverProvided(error):
|
||||
return .serverProvided(error)
|
||||
}
|
||||
}
|
||||
case .locatedGroup:
|
||||
@ -480,72 +484,72 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
|> map(Optional.init)
|
||||
|> mapError { error -> CreateGroupError in
|
||||
switch error {
|
||||
case .generic:
|
||||
return .generic
|
||||
case .restricted:
|
||||
return .restricted
|
||||
case .tooMuchJoined:
|
||||
return .tooMuchJoined
|
||||
case .tooMuchLocationBasedGroups:
|
||||
return .tooMuchLocationBasedGroups
|
||||
case let .serverProvided(error):
|
||||
return .serverProvided(error)
|
||||
case .generic:
|
||||
return .generic
|
||||
case .restricted:
|
||||
return .restricted
|
||||
case .tooMuchJoined:
|
||||
return .tooMuchJoined
|
||||
case .tooMuchLocationBasedGroups:
|
||||
return .tooMuchLocationBasedGroups
|
||||
case let .serverProvided(error):
|
||||
return .serverProvided(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actionsDisposable.add((createSignal
|
||||
|> mapToSignal { peerId -> Signal<PeerId?, CreateGroupError> in
|
||||
guard let peerId = peerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
let updatingAvatar = stateValue.with {
|
||||
return $0.avatar
|
||||
}
|
||||
if let _ = updatingAvatar {
|
||||
return context.engine.peers.updatePeerPhoto(peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
|> ignoreValues
|
||||
|> `catch` { _ -> Signal<Never, CreateGroupError> in
|
||||
return .complete()
|
||||
|
||||
actionsDisposable.add((createSignal
|
||||
|> mapToSignal { peerId -> Signal<PeerId?, CreateGroupError> in
|
||||
guard let peerId = peerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<PeerId?, CreateGroupError> in
|
||||
let updatingAvatar = stateValue.with {
|
||||
return $0.avatar
|
||||
}
|
||||
|> then(.single(peerId))
|
||||
} else {
|
||||
return .single(peerId)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
updateState { current in
|
||||
var current = current
|
||||
current.creating = false
|
||||
return current
|
||||
}
|
||||
}
|
||||
}).start(next: { peerId in
|
||||
if let peerId = peerId {
|
||||
if let completion = completion {
|
||||
completion(peerId, {
|
||||
dismissImpl?()
|
||||
if let _ = updatingAvatar {
|
||||
return context.engine.peers.updatePeerPhoto(peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
|> ignoreValues
|
||||
|> `catch` { _ -> Signal<Never, CreateGroupError> in
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<PeerId?, CreateGroupError> in
|
||||
}
|
||||
|> then(.single(peerId))
|
||||
} else {
|
||||
let controller = ChatControllerImpl(context: context, chatLocation: .peer(id: peerId))
|
||||
replaceControllerImpl?(controller)
|
||||
return .single(peerId)
|
||||
}
|
||||
}
|
||||
}, error: { error in
|
||||
if case .serverProvided = error {
|
||||
return
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String?
|
||||
switch error {
|
||||
|> deliverOnMainQueue
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
updateState { current in
|
||||
var current = current
|
||||
current.creating = false
|
||||
return current
|
||||
}
|
||||
}
|
||||
}).start(next: { peerId in
|
||||
if let peerId = peerId {
|
||||
if let completion = completion {
|
||||
completion(peerId, {
|
||||
dismissImpl?()
|
||||
})
|
||||
} else {
|
||||
let controller = ChatControllerImpl(context: context, chatLocation: .peer(id: peerId))
|
||||
replaceControllerImpl?(controller)
|
||||
}
|
||||
}
|
||||
}, error: { error in
|
||||
if case .serverProvided = error {
|
||||
return
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String?
|
||||
switch error {
|
||||
case .privacy:
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelMultipleError
|
||||
case .generic:
|
||||
@ -559,12 +563,13 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
text = presentationData.strings.CreateGroup_ErrorLocatedGroupsTooMuch
|
||||
default:
|
||||
text = nil
|
||||
}
|
||||
|
||||
if let text = text {
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if let text = text {
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
}))
|
||||
})
|
||||
}
|
||||
}, changeProfilePhoto: {
|
||||
endEditingImpl?()
|
||||
@ -825,89 +830,100 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
})
|
||||
ensureItemVisibleImpl?(.info, true)
|
||||
}, updateAutoDelete: {
|
||||
var subItems: [ContextMenuItem] = []
|
||||
|
||||
let currentValue = stateValue.with({ $0 }).autoremoveTimeout
|
||||
|
||||
let applyValue: (Int32) -> Void = { value in
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.autoremoveTimeout = value
|
||||
return state
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.GlobalAutoremoveTimeout())
|
||||
|> deliverOnMainQueue).start(next: { maybeGlobalAutoremoveTimeout in
|
||||
var subItems: [ContextMenuItem] = []
|
||||
|
||||
let globalAutoremoveTimeout: Int32 = maybeGlobalAutoremoveTimeout ?? 0
|
||||
let currentValue: Int32 = stateValue.with({ $0 }).autoremoveTimeout ?? globalAutoremoveTimeout
|
||||
|
||||
let applyValue: (Int32) -> Void = { value in
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.autoremoveTimeout = value
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
//TODO:localize
|
||||
subItems.append(.action(ContextMenuActionItem(text: "Off", icon: { theme in
|
||||
if currentValue == 0 {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, action: { _, f in
|
||||
applyValue(0)
|
||||
f(.default)
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
var presetValues: [Int32] = [
|
||||
1 * 24 * 60 * 60,
|
||||
7 * 24 * 60 * 60,
|
||||
31 * 24 * 60 * 60
|
||||
]
|
||||
if currentValue != 0 && !presetValues.contains(currentValue) {
|
||||
presetValues.append(currentValue)
|
||||
presetValues.sort()
|
||||
}
|
||||
|
||||
for value in presetValues {
|
||||
subItems.append(.action(ContextMenuActionItem(text: timeIntervalString(strings: presentationData.strings, value: value), icon: { theme in
|
||||
if currentValue == value {
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
//TODO:localize
|
||||
subItems.append(.action(ContextMenuActionItem(text: "Off", icon: { theme in
|
||||
if currentValue == 0 {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, action: { _, f in
|
||||
applyValue(value)
|
||||
applyValue(0)
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
subItems.append(.action(ContextMenuActionItem(text: "Set Custom Time...", icon: { _ in
|
||||
return nil
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
subItems.append(.separator)
|
||||
|
||||
let controller = ChatTimerScreen(context: context, updatedPresentationData: nil, style: .default, mode: .autoremove, currentTime: currentValue == 0 ? nil : currentValue, dismissByTapOutside: true, completion: { value in
|
||||
applyValue(value)
|
||||
})
|
||||
endEditingImpl?()
|
||||
presentControllerImpl?(controller, nil)
|
||||
})))
|
||||
|
||||
if let sourceNode = findAutoremoveReferenceNode?() {
|
||||
let items: Signal<ContextController.Items, NoError> = .single(ContextController.Items(content: .list(subItems)))
|
||||
let source: ContextContentSource = .reference(CreateGroupContextReferenceContentSource(sourceView: sourceNode.labelNode.view))
|
||||
|
||||
let contextController = ContextController(
|
||||
account: context.account,
|
||||
presentationData: presentationData,
|
||||
source: source,
|
||||
items: items,
|
||||
gesture: nil
|
||||
)
|
||||
sourceNode.updateHasContextMenu(hasContextMenu: true)
|
||||
contextController.dismissed = { [weak sourceNode] in
|
||||
sourceNode?.updateHasContextMenu(hasContextMenu: false)
|
||||
var presetValues: [Int32] = [
|
||||
1 * 24 * 60 * 60,
|
||||
7 * 24 * 60 * 60,
|
||||
31 * 24 * 60 * 60
|
||||
]
|
||||
if currentValue != 0 && !presetValues.contains(currentValue) {
|
||||
presetValues.append(currentValue)
|
||||
presetValues.sort()
|
||||
}
|
||||
presentInGlobalOverlay?(contextController)
|
||||
}
|
||||
|
||||
for value in presetValues {
|
||||
subItems.append(.action(ContextMenuActionItem(text: timeIntervalString(strings: presentationData.strings, value: value), icon: { theme in
|
||||
if currentValue == value {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, action: { _, f in
|
||||
applyValue(value)
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
subItems.append(.action(ContextMenuActionItem(text: "Set Custom Time...", icon: { _ in
|
||||
return nil
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let controller = ChatTimerScreen(context: context, updatedPresentationData: nil, style: .default, mode: .autoremove, currentTime: currentValue == 0 ? nil : currentValue, dismissByTapOutside: true, completion: { value in
|
||||
applyValue(value)
|
||||
})
|
||||
endEditingImpl?()
|
||||
presentControllerImpl?(controller, nil)
|
||||
})))
|
||||
|
||||
if let sourceNode = findAutoremoveReferenceNode?() {
|
||||
let items: Signal<ContextController.Items, NoError> = .single(ContextController.Items(content: .list(subItems)))
|
||||
let source: ContextContentSource = .reference(CreateGroupContextReferenceContentSource(sourceView: sourceNode.labelNode.view))
|
||||
|
||||
let contextController = ContextController(
|
||||
account: context.account,
|
||||
presentationData: presentationData,
|
||||
source: source,
|
||||
items: items,
|
||||
gesture: nil
|
||||
)
|
||||
sourceNode.updateHasContextMenu(hasContextMenu: true)
|
||||
contextController.dismissed = { [weak sourceNode] in
|
||||
sourceNode?.updateHasContextMenu(hasContextMenu: false)
|
||||
}
|
||||
presentInGlobalOverlay?(contextController)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), context.account.postbox.multiplePeersView(peerIds), .single(nil) |> then(addressPromise.get()), .single(nil) |> then(venuesPromise.get()))
|
||||
|> map { presentationData, state, view, address, venues -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let signal = combineLatest(queue: .mainQueue(),
|
||||
context.sharedContext.presentationData,
|
||||
statePromise.get(),
|
||||
context.account.postbox.multiplePeersView(peerIds),
|
||||
.single(nil) |> then(addressPromise.get()),
|
||||
.single(nil) |> then(venuesPromise.get()),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.GlobalAutoremoveTimeout())
|
||||
)
|
||||
|> map { presentationData, state, view, address, venues, globalAutoremoveTimeout -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
|
||||
let rightNavigationButton: ItemListNavigationButton
|
||||
if state.creating {
|
||||
@ -919,7 +935,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Compose_NewGroupTitle), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: createGroupEntries(presentationData: presentationData, state: state, peerIds: peerIds, view: view, venues: venues), style: .blocks, focusItemTag: CreateGroupEntryTag.info)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: createGroupEntries(presentationData: presentationData, state: state, peerIds: peerIds, view: view, venues: venues, globalAutoremoveTimeout: globalAutoremoveTimeout ?? 0), style: .blocks, focusItemTag: CreateGroupEntryTag.info)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
displayUndo = false
|
||||
self.originalRemainingSeconds = 3.5
|
||||
self.originalRemainingSeconds = 4.5
|
||||
case let .succeed(text):
|
||||
self.avatarNode = nil
|
||||
self.iconNode = nil
|
||||
|
Loading…
x
Reference in New Issue
Block a user