mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-30 15:10:56 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
f6858dfc94
@ -4485,6 +4485,8 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Chat.AttachmentMultipleFilesDisabled" = "Slowmode is enabled. You can't send multiple files at once.";
|
||||
"Chat.AttachmentMultipleForwardDisabled" = "Slowmode is enabled. You can't forward multiple messages at once.";
|
||||
"Chat.MultipleTextMessagesDisabled" = "Slowmode is enabled. You can't send multiple messages at once.";
|
||||
"Share.MultipleMessagesDisabled" = "Slowmode is enabled. You can't send multiple messages at once.";
|
||||
"Chat.SlowmodeSendError" = "Slowmode is enabled.";
|
||||
"StickerPacksSettings.AnimatedStickersInfo" = "Animated stickers in a chat will play continuously.";
|
||||
|
||||
"Conversation.Owner" = "owner";
|
||||
|
@ -622,6 +622,12 @@ final class FFMpegMediaFrameSourceContext: NSObject {
|
||||
}
|
||||
if let closestFrame = closestFrame {
|
||||
actualPts = closestFrame.pts
|
||||
} else {
|
||||
if let videoStream = initializedState.videoStream {
|
||||
actualPts = videoStream.duration
|
||||
} else {
|
||||
actualPts = extraVideoFrames.last!.pts
|
||||
}
|
||||
}
|
||||
}
|
||||
if let audioStream = initializedState.audioStream {
|
||||
|
@ -784,7 +784,7 @@ private final class MediaPlayerContext {
|
||||
}
|
||||
} else if let worstStatus = worstStatus, case let .finished(finishedAt) = worstStatus, finishedAt.isFinite {
|
||||
let nextTickDelay = max(0.0, finishedAt - timestamp) / self.baseRate
|
||||
if nextTickDelay.isLessThanOrEqualTo(0.0) || timestamp.isEqual(to: 0.0) {
|
||||
if nextTickDelay.isLessThanOrEqualTo(0.0) {
|
||||
rate = 0.0
|
||||
performActionAtEndNow = true
|
||||
} else {
|
||||
|
@ -655,74 +655,97 @@ struct ctr_state {
|
||||
|
||||
if (!_addedControlHeader) {
|
||||
_addedControlHeader = true;
|
||||
uint8_t controlBytes[64];
|
||||
arc4random_buf(controlBytes, 64);
|
||||
|
||||
int32_t controlVersion;
|
||||
if (_useIntermediateFormat) {
|
||||
controlVersion = 0xdddddddd;
|
||||
} else {
|
||||
controlVersion = 0xefefefef;
|
||||
}
|
||||
|
||||
memcpy(controlBytes + 56, &controlVersion, 4);
|
||||
int16_t datacenterTag = (int16_t)_datacenterTag;
|
||||
memcpy(controlBytes + 60, &datacenterTag, 2);
|
||||
|
||||
uint8_t controlBytesReversed[64];
|
||||
for (int i = 0; i < 64; i++) {
|
||||
controlBytesReversed[i] = controlBytes[64 - 1 - i];
|
||||
}
|
||||
|
||||
NSData *aesKey = [[NSData alloc] initWithBytes:controlBytes + 8 length:32];
|
||||
NSData *aesIv = [[NSData alloc] initWithBytes:controlBytes + 8 + 32 length:16];
|
||||
|
||||
NSData *incomingAesKey = [[NSData alloc] initWithBytes:controlBytesReversed + 8 length:32];
|
||||
NSData *incomingAesIv = [[NSData alloc] initWithBytes:controlBytesReversed + 8 + 32 length:16];
|
||||
|
||||
NSData *effectiveSecret = nil;
|
||||
if (_mtpSecret != nil) {
|
||||
effectiveSecret = _mtpSecret.secret;
|
||||
}
|
||||
if (effectiveSecret.length != 16 && effectiveSecret.length != 17) {
|
||||
effectiveSecret = nil;
|
||||
}
|
||||
|
||||
if (effectiveSecret) {
|
||||
NSMutableData *aesKeyData = [[NSMutableData alloc] init];
|
||||
[aesKeyData appendData:aesKey];
|
||||
if (effectiveSecret.length == 16) {
|
||||
[aesKeyData appendData:effectiveSecret];
|
||||
} else if (effectiveSecret.length == 17) {
|
||||
[aesKeyData appendData:[effectiveSecret subdataWithRange:NSMakeRange(1, effectiveSecret.length - 1)]];
|
||||
}
|
||||
NSData *aesKeyHash = MTSha256(aesKeyData);
|
||||
aesKey = [aesKeyHash subdataWithRange:NSMakeRange(0, 32)];
|
||||
for (int retryCount = 0; retryCount < 10; retryCount++) {
|
||||
uint8_t controlBytes[64];
|
||||
arc4random_buf(controlBytes, 64);
|
||||
|
||||
NSMutableData *incomingAesKeyData = [[NSMutableData alloc] init];
|
||||
[incomingAesKeyData appendData:incomingAesKey];
|
||||
if (effectiveSecret.length == 16) {
|
||||
[incomingAesKeyData appendData:effectiveSecret];
|
||||
} else if (effectiveSecret.length == 17) {
|
||||
[incomingAesKeyData appendData:[effectiveSecret subdataWithRange:NSMakeRange(1, effectiveSecret.length - 1)]];
|
||||
int32_t controlVersion;
|
||||
if (_useIntermediateFormat) {
|
||||
controlVersion = 0xdddddddd;
|
||||
} else {
|
||||
controlVersion = 0xefefefef;
|
||||
}
|
||||
NSData *incomingAesKeyHash = MTSha256(incomingAesKeyData);
|
||||
incomingAesKey = [incomingAesKeyHash subdataWithRange:NSMakeRange(0, 32)];
|
||||
|
||||
memcpy(controlBytes + 56, &controlVersion, 4);
|
||||
int16_t datacenterTag = (int16_t)_datacenterTag;
|
||||
memcpy(controlBytes + 60, &datacenterTag, 2);
|
||||
|
||||
uint8_t controlBytesReversed[64];
|
||||
for (int i = 0; i < 64; i++) {
|
||||
controlBytesReversed[i] = controlBytes[64 - 1 - i];
|
||||
}
|
||||
|
||||
NSData *aesKey = [[NSData alloc] initWithBytes:controlBytes + 8 length:32];
|
||||
NSData *aesIv = [[NSData alloc] initWithBytes:controlBytes + 8 + 32 length:16];
|
||||
|
||||
NSData *incomingAesKey = [[NSData alloc] initWithBytes:controlBytesReversed + 8 length:32];
|
||||
NSData *incomingAesIv = [[NSData alloc] initWithBytes:controlBytesReversed + 8 + 32 length:16];
|
||||
|
||||
NSData *effectiveSecret = nil;
|
||||
if (_mtpSecret != nil) {
|
||||
effectiveSecret = _mtpSecret.secret;
|
||||
}
|
||||
if (effectiveSecret.length != 16 && effectiveSecret.length != 17) {
|
||||
effectiveSecret = nil;
|
||||
}
|
||||
|
||||
if (effectiveSecret) {
|
||||
NSMutableData *aesKeyData = [[NSMutableData alloc] init];
|
||||
[aesKeyData appendData:aesKey];
|
||||
if (effectiveSecret.length == 16) {
|
||||
[aesKeyData appendData:effectiveSecret];
|
||||
} else if (effectiveSecret.length == 17) {
|
||||
[aesKeyData appendData:[effectiveSecret subdataWithRange:NSMakeRange(1, effectiveSecret.length - 1)]];
|
||||
}
|
||||
NSData *aesKeyHash = MTSha256(aesKeyData);
|
||||
aesKey = [aesKeyHash subdataWithRange:NSMakeRange(0, 32)];
|
||||
|
||||
NSMutableData *incomingAesKeyData = [[NSMutableData alloc] init];
|
||||
[incomingAesKeyData appendData:incomingAesKey];
|
||||
if (effectiveSecret.length == 16) {
|
||||
[incomingAesKeyData appendData:effectiveSecret];
|
||||
} else if (effectiveSecret.length == 17) {
|
||||
[incomingAesKeyData appendData:[effectiveSecret subdataWithRange:NSMakeRange(1, effectiveSecret.length - 1)]];
|
||||
}
|
||||
NSData *incomingAesKeyHash = MTSha256(incomingAesKeyData);
|
||||
incomingAesKey = [incomingAesKeyHash subdataWithRange:NSMakeRange(0, 32)];
|
||||
}
|
||||
|
||||
MTAesCtr *outgoingAesCtr = [[MTAesCtr alloc] initWithKey:aesKey.bytes keyLength:32 iv:aesIv.bytes decrypt:false];
|
||||
MTAesCtr *incomingAesCtr = [[MTAesCtr alloc] initWithKey:incomingAesKey.bytes keyLength:32 iv:incomingAesIv.bytes decrypt:false];
|
||||
|
||||
uint8_t encryptedControlBytes[64];
|
||||
[outgoingAesCtr encryptIn:controlBytes out:encryptedControlBytes len:64];
|
||||
|
||||
uint32_t intHeader = 0;
|
||||
memcpy(&intHeader, encryptedControlBytes, 4);
|
||||
|
||||
if (retryCount == 9) {
|
||||
assert(false);
|
||||
} else {
|
||||
if (intHeader == 0x44414548 ||
|
||||
intHeader == 0x54534f50 ||
|
||||
intHeader == 0x20544547 ||
|
||||
intHeader == 0x4954504f ||
|
||||
intHeader == 0xdddddddd ||
|
||||
intHeader == 0xeeeeeeee ||
|
||||
intHeader == 0x02010316) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
NSMutableData *outData = [[NSMutableData alloc] initWithLength:64 + packetData.length];
|
||||
memcpy(outData.mutableBytes, controlBytes, 56);
|
||||
memcpy(outData.mutableBytes + 56, encryptedControlBytes + 56, 8);
|
||||
|
||||
[outgoingAesCtr encryptIn:packetData.bytes out:outData.mutableBytes + 64 len:packetData.length];
|
||||
|
||||
_incomingAesCtr = incomingAesCtr;
|
||||
_outgoingAesCtr = outgoingAesCtr;
|
||||
[completeData appendData:outData];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
_outgoingAesCtr = [[MTAesCtr alloc] initWithKey:aesKey.bytes keyLength:32 iv:aesIv.bytes decrypt:false];
|
||||
_incomingAesCtr = [[MTAesCtr alloc] initWithKey:incomingAesKey.bytes keyLength:32 iv:incomingAesIv.bytes decrypt:false];
|
||||
|
||||
uint8_t encryptedControlBytes[64];
|
||||
[_outgoingAesCtr encryptIn:controlBytes out:encryptedControlBytes len:64];
|
||||
|
||||
NSMutableData *outData = [[NSMutableData alloc] initWithLength:64 + packetData.length];
|
||||
memcpy(outData.mutableBytes, controlBytes, 56);
|
||||
memcpy(outData.mutableBytes + 56, encryptedControlBytes + 56, 8);
|
||||
|
||||
[_outgoingAesCtr encryptIn:packetData.bytes out:outData.mutableBytes + 64 len:packetData.length];
|
||||
|
||||
[completeData appendData:outData];
|
||||
} else {
|
||||
NSMutableData *encryptedData = [[NSMutableData alloc] initWithLength:packetData.length];
|
||||
[_outgoingAesCtr encryptIn:packetData.bytes out:encryptedData.mutableBytes len:packetData.length];
|
||||
|
@ -18,10 +18,6 @@ import Foundation
|
||||
public struct PendingMessageStatus: Equatable {
|
||||
public let isRunning: Bool
|
||||
public let progress: Float
|
||||
|
||||
public static func ==(lhs: PendingMessageStatus, rhs: PendingMessageStatus) -> Bool {
|
||||
return lhs.isRunning == rhs.isRunning && lhs.progress.isEqual(to: rhs.progress)
|
||||
}
|
||||
}
|
||||
|
||||
private enum PendingMessageState {
|
||||
@ -58,7 +54,8 @@ private final class PendingMessageContext {
|
||||
var contentType: PendingMessageUploadedContentType? = nil
|
||||
let activityDisposable = MetaDisposable()
|
||||
var status: PendingMessageStatus?
|
||||
var statusSubscribers = Bag<(PendingMessageStatus?) -> Void>()
|
||||
var error: PendingMessageFailureReason?
|
||||
var statusSubscribers = Bag<(PendingMessageStatus?, PendingMessageFailureReason?) -> Void>()
|
||||
var forcedReuploadOnce: Bool = false
|
||||
}
|
||||
|
||||
@ -66,6 +63,7 @@ public enum PendingMessageFailureReason {
|
||||
case flood
|
||||
case publicBan
|
||||
case mediaRestricted
|
||||
case slowmodeActive
|
||||
}
|
||||
|
||||
private func reasonForError(_ error: String) -> PendingMessageFailureReason? {
|
||||
@ -75,6 +73,8 @@ private func reasonForError(_ error: String) -> PendingMessageFailureReason? {
|
||||
return .publicBan
|
||||
} else if error.hasPrefix("CHAT_SEND_") && error.hasSuffix("_FORBIDDEN") {
|
||||
return .mediaRestricted
|
||||
} else if error.hasPrefix("SLOWMODE_WAIT") {
|
||||
return .slowmodeActive
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -202,7 +202,7 @@ public final class PendingMessageManager {
|
||||
if context.status != nil {
|
||||
context.status = nil
|
||||
for subscriber in context.statusSubscribers.copyItems() {
|
||||
subscriber(nil)
|
||||
subscriber(nil, context.error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@ public final class PendingMessageManager {
|
||||
}
|
||||
}
|
||||
|
||||
public func pendingMessageStatus(_ id: MessageId) -> Signal<PendingMessageStatus?, NoError> {
|
||||
public func pendingMessageStatus(_ id: MessageId) -> Signal<(PendingMessageStatus?, PendingMessageFailureReason?), NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
@ -274,11 +274,11 @@ public final class PendingMessageManager {
|
||||
self.messageContexts[id] = messageContext
|
||||
}
|
||||
|
||||
let index = messageContext.statusSubscribers.add({ status in
|
||||
subscriber.putNext(status)
|
||||
let index = messageContext.statusSubscribers.add({ status, error in
|
||||
subscriber.putNext((status, error))
|
||||
})
|
||||
|
||||
subscriber.putNext(messageContext.status)
|
||||
subscriber.putNext((messageContext.status, messageContext.error))
|
||||
|
||||
disposable.set(ActionDisposable {
|
||||
self.queue.async {
|
||||
@ -334,7 +334,7 @@ public final class PendingMessageManager {
|
||||
if status != messageContext.status {
|
||||
messageContext.status = status
|
||||
for subscriber in messageContext.statusSubscribers.copyItems() {
|
||||
subscriber(status)
|
||||
subscriber(messageContext.status, messageContext.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,23 +445,7 @@ public final class PendingMessageManager {
|
||||
return .progress(1.0)
|
||||
}
|
||||
messages[0].0.sendDisposable.set((sendMessage
|
||||
|> deliverOn(self.queue)
|
||||
|> afterDisposed { [weak self] in
|
||||
/*if let strongSelf = self {
|
||||
assert(strongSelf.queue.isCurrent())
|
||||
for (_, id, _) in messages {
|
||||
if let current = strongSelf.messageContexts[id] {
|
||||
current.status = .none
|
||||
for subscriber in current.statusSubscribers.copyItems() {
|
||||
subscriber(nil)
|
||||
}
|
||||
if current.statusSubscribers.isEmpty {
|
||||
strongSelf.messageContexts.removeValue(forKey: id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}).start())
|
||||
|> deliverOn(self.queue)).start())
|
||||
}
|
||||
|
||||
private func commitSendingSingleMessage(messageContext: PendingMessageContext, messageId: MessageId, content: PendingMessageUploadedContentAndReuploadInfo) {
|
||||
@ -471,21 +455,7 @@ public final class PendingMessageManager {
|
||||
return .progress(1.0)
|
||||
}
|
||||
messageContext.sendDisposable.set((sendMessage
|
||||
|> deliverOn(self.queue)
|
||||
|> afterDisposed { [weak self] in
|
||||
/*if let strongSelf = self {
|
||||
assert(strongSelf.queue.isCurrent())
|
||||
if let current = strongSelf.messageContexts[messageId] {
|
||||
current.status = .none
|
||||
for subscriber in current.statusSubscribers.copyItems() {
|
||||
subscriber(nil)
|
||||
}
|
||||
if current.statusSubscribers.isEmpty {
|
||||
strongSelf.messageContexts.removeValue(forKey: messageId)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}).start(next: { [weak self] next in
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] next in
|
||||
if let strongSelf = self {
|
||||
assert(strongSelf.queue.isCurrent())
|
||||
|
||||
@ -495,7 +465,7 @@ public final class PendingMessageManager {
|
||||
let status = PendingMessageStatus(isRunning: true, progress: progress)
|
||||
current.status = status
|
||||
for subscriber in current.statusSubscribers.copyItems() {
|
||||
subscriber(status)
|
||||
subscriber(current.status, current.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -513,7 +483,7 @@ public final class PendingMessageManager {
|
||||
let status = PendingMessageStatus(isRunning: true, progress: 0.0)
|
||||
messageContext.status = status
|
||||
for subscriber in messageContext.statusSubscribers.copyItems() {
|
||||
subscriber(status)
|
||||
subscriber(messageContext.status, messageContext.error)
|
||||
}
|
||||
self.addContextActivityIfNeeded(messageContext, peerId: id.peerId)
|
||||
|
||||
@ -548,7 +518,7 @@ public final class PendingMessageManager {
|
||||
let status = PendingMessageStatus(isRunning: true, progress: progress)
|
||||
current.status = status
|
||||
for subscriber in current.statusSubscribers.copyItems() {
|
||||
subscriber(status)
|
||||
subscriber(current.status, current.error)
|
||||
}
|
||||
}
|
||||
case let .content(content):
|
||||
@ -582,7 +552,7 @@ public final class PendingMessageManager {
|
||||
let status = PendingMessageStatus(isRunning: true, progress: 0.0)
|
||||
context.status = status
|
||||
for subscriber in context.statusSubscribers.copyItems() {
|
||||
subscriber(status)
|
||||
subscriber(context.status, context.error)
|
||||
}
|
||||
self.addContextActivityIfNeeded(context, peerId: peerId)
|
||||
context.uploadDisposable.set((uploadSignal
|
||||
@ -596,7 +566,7 @@ public final class PendingMessageManager {
|
||||
let status = PendingMessageStatus(isRunning: true, progress: progress)
|
||||
current.status = status
|
||||
for subscriber in current.statusSubscribers.copyItems() {
|
||||
subscriber(status)
|
||||
subscriber(context.status, context.error)
|
||||
}
|
||||
}
|
||||
case let .content(content):
|
||||
@ -780,6 +750,15 @@ public final class PendingMessageManager {
|
||||
return .complete()
|
||||
}
|
||||
} else if let failureReason = reasonForError(error.errorDescription), let message = messages.first?.0 {
|
||||
for (message, _) in messages {
|
||||
if let context = strongSelf.messageContexts[message.id] {
|
||||
context.error = failureReason
|
||||
for f in context.statusSubscribers.copyItems() {
|
||||
f(context.status, context.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let context = strongSelf.peerSummaryContexts[message.id.peerId] {
|
||||
for subscriber in context.messageFailedSubscribers.copyItems() {
|
||||
subscriber(failureReason)
|
||||
@ -996,6 +975,13 @@ public final class PendingMessageManager {
|
||||
return
|
||||
}
|
||||
} else if let failureReason = reasonForError(error.errorDescription) {
|
||||
if let context = strongSelf.messageContexts[message.id] {
|
||||
context.error = failureReason
|
||||
for f in context.statusSubscribers.copyItems() {
|
||||
f(context.status, context.error)
|
||||
}
|
||||
}
|
||||
|
||||
if let context = strongSelf.peerSummaryContexts[message.id.peerId] {
|
||||
for subscriber in context.messageFailedSubscribers.copyItems() {
|
||||
subscriber(failureReason)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationTheme {
|
||||
private func makeDarkPresentationTheme(accentColor: UIColor, preview: Bool) -> PresentationTheme {
|
||||
let destructiveColor: UIColor = UIColor(rgb: 0xeb5545)
|
||||
let constructiveColor: UIColor = UIColor(rgb: 0x08a723)
|
||||
let secretColor: UIColor = UIColor(rgb: 0x00b12c)
|
||||
@ -313,13 +313,14 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem
|
||||
chatList: chatList,
|
||||
chat: chat,
|
||||
actionSheet: actionSheet,
|
||||
inAppNotification: inAppNotification
|
||||
inAppNotification: inAppNotification,
|
||||
preview: preview
|
||||
)
|
||||
}
|
||||
|
||||
public let defaultDarkPresentationTheme = makeDarkPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff))
|
||||
public let defaultDarkPresentationTheme = makeDarkPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff), preview: false)
|
||||
|
||||
public func makeDarkPresentationTheme(accentColor: UIColor?) -> PresentationTheme {
|
||||
public func makeDarkPresentationTheme(accentColor: UIColor?, preview: Bool) -> PresentationTheme {
|
||||
let accentColor = accentColor ?? defaultDayAccentColor
|
||||
return makeDarkPresentationTheme(accentColor: accentColor)
|
||||
return makeDarkPresentationTheme(accentColor: accentColor, preview: preview)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationTheme {
|
||||
private func makeDarkPresentationTheme(accentColor: UIColor, preview: Bool) -> PresentationTheme {
|
||||
let destructiveColor: UIColor = UIColor(rgb: 0xff6767)
|
||||
let constructiveColor: UIColor = UIColor(rgb: 0x08a723)
|
||||
let secretColor: UIColor = UIColor(rgb: 0x89df9e)
|
||||
@ -317,13 +317,14 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem
|
||||
chatList: chatList,
|
||||
chat: chat,
|
||||
actionSheet: actionSheet,
|
||||
inAppNotification: inAppNotification
|
||||
inAppNotification: inAppNotification,
|
||||
preview: preview
|
||||
)
|
||||
}
|
||||
|
||||
public let defaultDarkAccentPresentationTheme = makeDarkAccentPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff))
|
||||
public let defaultDarkAccentPresentationTheme = makeDarkAccentPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff), preview: false)
|
||||
|
||||
public func makeDarkAccentPresentationTheme(accentColor: UIColor?) -> PresentationTheme {
|
||||
public func makeDarkAccentPresentationTheme(accentColor: UIColor?, preview: Bool) -> PresentationTheme {
|
||||
let accentColor = accentColor ?? defaultDayAccentColor
|
||||
return makeDarkPresentationTheme(accentColor: accentColor)
|
||||
return makeDarkPresentationTheme(accentColor: accentColor, preview: preview)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import Foundation
|
||||
import UIKit
|
||||
import TelegramCore
|
||||
|
||||
private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgroundColor: UIColor, day: Bool) -> PresentationTheme {
|
||||
private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgroundColor: UIColor, day: Bool, preview: Bool) -> PresentationTheme {
|
||||
let destructiveColor: UIColor = UIColor(rgb: 0xff3b30)
|
||||
let constructiveColor: UIColor = UIColor(rgb: 0x00c900)
|
||||
let secretColor: UIColor = UIColor(rgb: 0x00b12c)
|
||||
@ -323,16 +323,17 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
|
||||
chatList: chatList,
|
||||
chat: chat,
|
||||
actionSheet: actionSheet,
|
||||
inAppNotification: inAppNotification
|
||||
inAppNotification: inAppNotification,
|
||||
preview: preview
|
||||
)
|
||||
}
|
||||
|
||||
public let defaultPresentationTheme = makeDefaultDayPresentationTheme(accentColor: UIColor(rgb: 0x007ee5), serviceBackgroundColor: defaultServiceBackgroundColor, day: false)
|
||||
public let defaultPresentationTheme = makeDefaultDayPresentationTheme(accentColor: UIColor(rgb: 0x007ee5), serviceBackgroundColor: defaultServiceBackgroundColor, day: false, preview: false)
|
||||
|
||||
public let defaultDayAccentColor = UIColor(rgb: 0x007ee5)
|
||||
public let defaultServiceBackgroundColor = UIColor(rgb: 0x000000, alpha: 0.3)
|
||||
|
||||
public func makeDefaultDayPresentationTheme(accentColor: UIColor? = nil, serviceBackgroundColor: UIColor, day: Bool) -> PresentationTheme {
|
||||
public func makeDefaultDayPresentationTheme(accentColor: UIColor? = nil, serviceBackgroundColor: UIColor, day: Bool, preview: Bool) -> PresentationTheme {
|
||||
let accentColor = accentColor ?? defaultDayAccentColor
|
||||
return makeDefaultDayPresentationTheme(accentColor: accentColor, serviceBackgroundColor: serviceBackgroundColor, day: day)
|
||||
return makeDefaultDayPresentationTheme(accentColor: accentColor, serviceBackgroundColor: serviceBackgroundColor, day: day, preview: preview)
|
||||
}
|
||||
|
@ -2,19 +2,19 @@ import Foundation
|
||||
import UIKit
|
||||
import TelegramUIPreferences
|
||||
|
||||
public func makePresentationTheme(themeReference: PresentationThemeReference, accentColor: UIColor, serviceBackgroundColor: UIColor) -> PresentationTheme {
|
||||
public func makePresentationTheme(themeReference: PresentationThemeReference, accentColor: UIColor, serviceBackgroundColor: UIColor, preview: Bool = false) -> PresentationTheme {
|
||||
let theme: PresentationTheme
|
||||
switch themeReference {
|
||||
case let .builtin(reference):
|
||||
switch reference {
|
||||
case .dayClassic:
|
||||
theme = makeDefaultDayPresentationTheme(serviceBackgroundColor: serviceBackgroundColor, day: false)
|
||||
theme = makeDefaultDayPresentationTheme(serviceBackgroundColor: serviceBackgroundColor, day: false, preview: preview)
|
||||
case .night:
|
||||
theme = makeDarkPresentationTheme(accentColor: accentColor)
|
||||
theme = makeDarkPresentationTheme(accentColor: accentColor, preview: preview)
|
||||
case .nightAccent:
|
||||
theme = makeDarkAccentPresentationTheme(accentColor: accentColor)
|
||||
theme = makeDarkAccentPresentationTheme(accentColor: accentColor, preview: preview)
|
||||
case .day:
|
||||
theme = makeDefaultDayPresentationTheme(accentColor: accentColor, serviceBackgroundColor: serviceBackgroundColor, day: true)
|
||||
theme = makeDefaultDayPresentationTheme(accentColor: accentColor, serviceBackgroundColor: serviceBackgroundColor, day: true, preview: preview)
|
||||
}
|
||||
}
|
||||
return theme
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -914,10 +914,11 @@ public final class PresentationTheme: Equatable {
|
||||
public let chat: PresentationThemeChat
|
||||
public let actionSheet: PresentationThemeActionSheet
|
||||
public let inAppNotification: PresentationThemeInAppNotification
|
||||
public let preview: Bool
|
||||
|
||||
public let resourceCache: PresentationsResourceCache = PresentationsResourceCache()
|
||||
|
||||
public init(name: PresentationThemeName, author: String?, overallDarkAppearance: Bool, intro: PresentationThemeIntro, passcode: PresentationThemePasscode, rootController: PresentationThemeRootController, list: PresentationThemeList, chatList: PresentationThemeChatList, chat: PresentationThemeChat, actionSheet: PresentationThemeActionSheet, inAppNotification: PresentationThemeInAppNotification) {
|
||||
public init(name: PresentationThemeName, author: String?, overallDarkAppearance: Bool, intro: PresentationThemeIntro, passcode: PresentationThemePasscode, rootController: PresentationThemeRootController, list: PresentationThemeList, chatList: PresentationThemeChatList, chat: PresentationThemeChat, actionSheet: PresentationThemeActionSheet, inAppNotification: PresentationThemeInAppNotification, preview: Bool = false) {
|
||||
self.name = name
|
||||
self.author = author
|
||||
self.overallDarkAppearance = overallDarkAppearance
|
||||
@ -929,6 +930,7 @@ public final class PresentationTheme: Equatable {
|
||||
self.chat = chat
|
||||
self.actionSheet = actionSheet
|
||||
self.inAppNotification = inAppNotification
|
||||
self.preview = preview
|
||||
}
|
||||
|
||||
public func image(_ key: Int32, _ generate: (PresentationTheme) -> UIImage?) -> UIImage? {
|
||||
|
@ -57,7 +57,7 @@ public class LocalBundleResource: TelegramMediaResource {
|
||||
}
|
||||
|
||||
public func isEqual(to: MediaResource) -> Bool {
|
||||
if let to = to as? LocalBundleResourceId {
|
||||
if let to = to as? LocalBundleResource {
|
||||
return self.name == to.name && self.ext == to.ext
|
||||
} else {
|
||||
return false
|
||||
|
@ -1870,8 +1870,8 @@ final class SharedApplicationContext {
|
||||
unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
replyLegacyMessageCategory = UNNotificationCategory(identifier: "r", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
replyLegacyMediaMessageCategory = UNNotificationCategory(identifier: "m", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
replyMediaMessageCategory = UNNotificationCategory(identifier: "withReplyMedia", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
replyLegacyMediaMessageCategory = UNNotificationCategory(identifier: "m", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
replyMediaMessageCategory = UNNotificationCategory(identifier: "withReplyMedia", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
legacyChannelMessageCategory = UNNotificationCategory(identifier: "c", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
muteMessageCategory = UNNotificationCategory(identifier: "withMute", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
muteMediaMessageCategory = UNNotificationCategory(identifier: "withMuteMedia", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
@ -1882,7 +1882,7 @@ final class SharedApplicationContext {
|
||||
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], options: carPlayOptions)
|
||||
replyLegacyMessageCategory = UNNotificationCategory(identifier: "r", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], options: carPlayOptions)
|
||||
replyLegacyMediaMessageCategory = UNNotificationCategory(identifier: "m", actions: [reply], intentIdentifiers: [], options: [])
|
||||
replyMediaMessageCategory = UNNotificationCategory(identifier: "withReplyMedia", actions: [reply], intentIdentifiers: [], options: [])
|
||||
replyMediaMessageCategory = UNNotificationCategory(identifier: "withReplyMedia", actions: [reply], intentIdentifiers: [], options: carPlayOptions)
|
||||
legacyChannelMessageCategory = UNNotificationCategory(identifier: "c", actions: [], intentIdentifiers: [], options: [])
|
||||
muteMessageCategory = UNNotificationCategory(identifier: "withMute", actions: [], intentIdentifiers: [], options: [])
|
||||
muteMediaMessageCategory = UNNotificationCategory(identifier: "withMuteMedia", actions: [], intentIdentifiers: [], options: [])
|
||||
|
@ -761,6 +761,7 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
|
||||
var dismissInputImpl: (() -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
var errorImpl: (() -> Void)?
|
||||
var scrollToRankImpl: (() -> Void)?
|
||||
|
||||
let actualPeerId = Atomic<PeerId>(value: peerId)
|
||||
let upgradedToSupergroupImpl: (PeerId, @escaping () -> Void) -> Void = { peerId, completion in
|
||||
@ -809,6 +810,10 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
|
||||
}
|
||||
}, updateFocusedOnRank: { focusedOnRank in
|
||||
updateState { $0.withUpdatedFocusedOnRank(focusedOnRank) }
|
||||
|
||||
if focusedOnRank {
|
||||
scrollToRankImpl?()
|
||||
}
|
||||
}, dismissAdmin: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let actionSheet = ActionSheetController(presentationTheme: presentationData.theme)
|
||||
@ -1082,7 +1087,7 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Channel_Management_LabelEditor), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
|
||||
let listState = ItemListNodeState(entries: channelAdminControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelView: channelView, adminView: adminView, initialParticipant: initialParticipant, canEdit: canEdit), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: nil, animateChanges: true)
|
||||
let listState = ItemListNodeState(entries: channelAdminControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelView: channelView, adminView: adminView, initialParticipant: initialParticipant, canEdit: canEdit), style: .blocks, focusItemTag: focusItemTag, ensureVisibleItemTag: nil, emptyStateItem: nil, animateChanges: true)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
@ -1091,6 +1096,7 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
|
||||
}
|
||||
|
||||
let controller = ItemListController(context: context, state: signal)
|
||||
controller.experimentalSnapScrollToItem = true
|
||||
dismissImpl = { [weak controller] in
|
||||
controller?.view.endEditing(true)
|
||||
controller?.dismiss()
|
||||
@ -1111,6 +1117,27 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
|
||||
}
|
||||
}
|
||||
}
|
||||
scrollToRankImpl = { [weak controller] in
|
||||
controller?.afterLayout({
|
||||
guard let controller = controller else {
|
||||
return
|
||||
}
|
||||
|
||||
var resultItemNode: ListViewItemNode?
|
||||
let _ = controller.frameForItemNode({ itemNode in
|
||||
if let itemNode = itemNode as? ItemListSingleLineInputItemNode {
|
||||
if let tag = itemNode.tag as? ChannelAdminEntryTag, tag == .rank {
|
||||
resultItemNode = itemNode
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
if let resultItemNode = resultItemNode {
|
||||
controller.ensureItemNodeVisible(resultItemNode)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
@ -3759,20 +3759,21 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
|
||||
self.failedMessageEventsDisposable.set((self.context.account.pendingMessageManager.failedMessageEvents(peerId: peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] reason in
|
||||
if let strongSelf = self {
|
||||
let subjectFlags: TelegramChatBannedRightsFlags = .banSendMedia
|
||||
|
||||
let text: String
|
||||
let moreInfo: Bool
|
||||
switch reason {
|
||||
case .flood:
|
||||
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorFlood
|
||||
moreInfo = true
|
||||
case .publicBan:
|
||||
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorGroupRestricted
|
||||
moreInfo = true
|
||||
case .mediaRestricted:
|
||||
strongSelf.interfaceInteraction?.displayRestrictedInfo(.mediaRecording, .alert)
|
||||
return
|
||||
case .flood:
|
||||
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorFlood
|
||||
moreInfo = true
|
||||
case .publicBan:
|
||||
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorGroupRestricted
|
||||
moreInfo = true
|
||||
case .mediaRestricted:
|
||||
strongSelf.interfaceInteraction?.displayRestrictedInfo(.mediaRecording, .alert)
|
||||
return
|
||||
case .slowmodeActive:
|
||||
text = strongSelf.presentationData.strings.Chat_SlowmodeSendError
|
||||
moreInfo = false
|
||||
}
|
||||
let actions: [TextAlertAction]
|
||||
if moreInfo {
|
||||
@ -5837,7 +5838,7 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
|
||||
return nil
|
||||
}
|
||||
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
||||
|> mapToSignal { status -> Signal<Bool, NoError> in
|
||||
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
||||
if status != nil {
|
||||
return .never()
|
||||
} else {
|
||||
|
@ -41,7 +41,11 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
case let .MessageEntry(message, presentationData, _, _, _, _):
|
||||
var type = 2
|
||||
if presentationData.largeEmoji && message.elligibleForLargeEmoji && messageIsElligibleForLargeEmoji(message) {
|
||||
type = 3
|
||||
if animatedEmojiResource(emoji: message.text) != nil {
|
||||
type = 3
|
||||
} else {
|
||||
type = 4
|
||||
}
|
||||
}
|
||||
return UInt64(message.stableId) | ((UInt64(type) << 40))
|
||||
case let .MessageGroupEntry(groupInfo, _, _):
|
||||
|
@ -195,7 +195,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
|
||||
var updatedPlaybackStatus: Signal<FileMediaResourceStatus, NoError>?
|
||||
if let updatedFile = updatedFile, updatedMedia || updatedMessageId {
|
||||
updatedPlaybackStatus = combineLatest(messageFileMediaResourceStatus(context: item.context, file: updatedFile, message: item.message, isRecentActions: item.associatedData.isRecentActions), item.context.account.pendingMessageManager.pendingMessageStatus(item.message.id))
|
||||
updatedPlaybackStatus = combineLatest(messageFileMediaResourceStatus(context: item.context, file: updatedFile, message: item.message, isRecentActions: item.associatedData.isRecentActions), item.context.account.pendingMessageManager.pendingMessageStatus(item.message.id) |> map { $0.0 })
|
||||
|> map { resourceStatus, pendingStatus -> FileMediaResourceStatus in
|
||||
if let pendingStatus = pendingStatus {
|
||||
var progress = pendingStatus.progress
|
||||
|
@ -555,7 +555,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
||||
if statusUpdated {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
if message.flags.isSending {
|
||||
updatedStatusSignal = combineLatest(chatMessagePhotoStatus(context: context, messageId: message.id, photoReference: .message(message: MessageReference(message), media: image)), context.account.pendingMessageManager.pendingMessageStatus(message.id))
|
||||
updatedStatusSignal = combineLatest(chatMessagePhotoStatus(context: context, messageId: message.id, photoReference: .message(message: MessageReference(message), media: image)), context.account.pendingMessageManager.pendingMessageStatus(message.id) |> map { $0.0 })
|
||||
|> map { resourceStatus, pendingStatus -> (MediaResourceStatus, MediaResourceStatus?) in
|
||||
if let pendingStatus = pendingStatus {
|
||||
let adjustedProgress = max(pendingStatus.progress, 0.027)
|
||||
@ -571,7 +571,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
updatedStatusSignal = combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id))
|
||||
updatedStatusSignal = combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id) |> map { $0.0 })
|
||||
|> map { resourceStatus, pendingStatus -> (MediaResourceStatus, MediaResourceStatus?) in
|
||||
if let pendingStatus = pendingStatus {
|
||||
let adjustedProgress = max(pendingStatus.progress, 0.027)
|
||||
|
@ -6,6 +6,9 @@ import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
|
||||
private let leftInset: CGFloat = 16.0
|
||||
private let rightInset: CGFloat = 46.0
|
||||
|
||||
private final class ActionSheetItemNode: ASDisplayNode {
|
||||
private let title: String
|
||||
private let action: () -> Void
|
||||
@ -16,6 +19,8 @@ private final class ActionSheetItemNode: ASDisplayNode {
|
||||
private let iconNode: ASImageNode
|
||||
private let titleNode: ImmediateTextNode
|
||||
|
||||
private var maxWidth: CGFloat?
|
||||
|
||||
init(theme: PresentationTheme, title: String, action: @escaping () -> Void) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
@ -62,13 +67,17 @@ private final class ActionSheetItemNode: ASDisplayNode {
|
||||
func updateTheme(_ theme: PresentationTheme) {
|
||||
self.separatorNode.backgroundColor = theme.actionSheet.opaqueItemSeparatorColor
|
||||
self.highlightedBackgroundNode.backgroundColor = theme.actionSheet.opaqueItemHighlightedBackgroundColor
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.regular(17.0), textColor: theme.actionSheet.primaryTextColor)
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.regular(17.0), textColor: theme.actionSheet.primaryTextColor)
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.actionSheet.primaryTextColor)
|
||||
|
||||
if let maxWidth = self.maxWidth {
|
||||
let _ = self.titleNode.updateLayout(CGSize(width: maxWidth - leftInset - rightInset, height: .greatestFiniteMagnitude))
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(maxWidth: CGFloat) -> (CGFloat, CGFloat, (CGFloat) -> Void) {
|
||||
let leftInset: CGFloat = 16.0
|
||||
let rightInset: CGFloat = 46.0
|
||||
self.maxWidth = maxWidth
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: maxWidth - leftInset - rightInset, height: .greatestFiniteMagnitude))
|
||||
let height: CGFloat = 44.0
|
||||
|
||||
|
@ -52,7 +52,7 @@ func messageFileMediaResourceStatus(context: AccountContext, file: TelegramMedia
|
||||
}
|
||||
|
||||
if message.flags.isSending {
|
||||
return combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id), playbackStatus)
|
||||
return combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id) |> map { $0.0 }, playbackStatus)
|
||||
|> map { resourceStatus, pendingStatus, playbackStatus -> FileMediaResourceStatus in
|
||||
let mediaStatus: FileMediaResourceMediaStatus
|
||||
if let playbackStatus = playbackStatus {
|
||||
|
@ -353,7 +353,7 @@ func openChatMessage(context: AccountContext, message: Message, standalone: Bool
|
||||
return nil
|
||||
}))
|
||||
case let .theme(media):
|
||||
let controller = ThemePreviewController(context: context, previewTheme: makeDefaultDayPresentationTheme(accentColor: nil, serviceBackgroundColor: .black, day: true), media: .message(message: MessageReference(message), media: media))
|
||||
let controller = ThemePreviewController(context: context, previewTheme: makeDefaultDayPresentationTheme(accentColor: nil, serviceBackgroundColor: .black, day: true, preview: false), media: .message(message: MessageReference(message), media: media))
|
||||
present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
}
|
||||
|
@ -663,7 +663,7 @@ public class PeerMediaCollectionController: TelegramController {
|
||||
return nil
|
||||
}
|
||||
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
||||
|> mapToSignal { status -> Signal<Bool, NoError> in
|
||||
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
||||
if status != nil {
|
||||
return .never()
|
||||
} else {
|
||||
|
@ -71,7 +71,7 @@ struct PresentationResourcesChat {
|
||||
let hasWallpaper = !wallpaper.isEmpty
|
||||
let key: PresentationResourceKey = !hasWallpaper ? PresentationResourceKey.chatPrincipalThemeEssentialGraphicsWithoutWallpaper : PresentationResourceKey.chatPrincipalThemeEssentialGraphicsWithWallpaper
|
||||
return theme.object(key.rawValue, { theme in
|
||||
return PrincipalThemeEssentialGraphics(theme.chat, wallpaper: wallpaper)
|
||||
return PrincipalThemeEssentialGraphics(theme.chat, wallpaper: wallpaper, preview: theme.preview)
|
||||
}) as! PrincipalThemeEssentialGraphics
|
||||
}
|
||||
|
||||
|
@ -127,82 +127,134 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
public let radialIndicatorFileIconIncoming: UIImage
|
||||
public let radialIndicatorFileIconOutgoing: UIImage
|
||||
|
||||
init(_ theme: PresentationThemeChat, wallpaper: TelegramWallpaper) {
|
||||
init(_ theme: PresentationThemeChat, wallpaper: TelegramWallpaper, preview: Bool = false) {
|
||||
let incoming: PresentationThemeBubbleColorComponents = wallpaper.isEmpty ? theme.message.incoming.bubble.withoutWallpaper : theme.message.incoming.bubble.withWallpaper
|
||||
let outgoing: PresentationThemeBubbleColorComponents = wallpaper.isEmpty ? theme.message.outgoing.bubble.withoutWallpaper : theme.message.outgoing.bubble.withWallpaper
|
||||
|
||||
self.chatMessageBackgroundIncomingImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundIncomingHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundIncomingMergedTopHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundIncomingMergedTopSideImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundIncomingMergedTopSideHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundIncomingMergedBottomHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundIncomingMergedBothImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both)
|
||||
self.chatMessageBackgroundIncomingMergedBothHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .both)
|
||||
|
||||
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundOutgoingHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundOutgoingMergedTopHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both)
|
||||
self.chatMessageBackgroundOutgoingMergedBothHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .both)
|
||||
let emptyImage = UIImage()
|
||||
if preview {
|
||||
self.chatMessageBackgroundIncomingImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundIncomingHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopSideImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopSideHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBottomImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBottomHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBothImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBothHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedSideImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedSideHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundOutgoingHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedBottomImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedBottomHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedBothImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedBothHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedSideImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedSideHighlightedImage = emptyImage
|
||||
self.checkBubbleFullImage = emptyImage
|
||||
self.checkBubblePartialImage = emptyImage
|
||||
self.checkMediaFullImage = emptyImage
|
||||
self.checkMediaPartialImage = emptyImage
|
||||
self.checkFreeFullImage = emptyImage
|
||||
self.checkFreePartialImage = emptyImage
|
||||
self.clockBubbleIncomingFrameImage = emptyImage
|
||||
self.clockBubbleIncomingMinImage = emptyImage
|
||||
self.clockBubbleOutgoingFrameImage = emptyImage
|
||||
self.clockBubbleOutgoingMinImage = emptyImage
|
||||
self.clockMediaFrameImage = emptyImage
|
||||
self.clockMediaMinImage = emptyImage
|
||||
self.clockFreeFrameImage = emptyImage
|
||||
self.clockFreeMinImage = emptyImage
|
||||
self.dateAndStatusMediaBackground = emptyImage
|
||||
self.dateAndStatusFreeBackground = emptyImage
|
||||
self.incomingDateAndStatusImpressionIcon = emptyImage
|
||||
self.outgoingDateAndStatusImpressionIcon = emptyImage
|
||||
self.mediaImpressionIcon = emptyImage
|
||||
self.freeImpressionIcon = emptyImage
|
||||
self.dateStaticBackground = emptyImage
|
||||
self.dateFloatingBackground = emptyImage
|
||||
self.radialIndicatorFileIconIncoming = emptyImage
|
||||
self.radialIndicatorFileIconOutgoing = emptyImage
|
||||
} else {
|
||||
self.chatMessageBackgroundIncomingImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundIncomingHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundIncomingMergedTopHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundIncomingMergedTopSideImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundIncomingMergedTopSideHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundIncomingMergedBottomHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundIncomingMergedBothImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both)
|
||||
self.chatMessageBackgroundIncomingMergedBothHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .both)
|
||||
|
||||
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundOutgoingHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .none)
|
||||
self.chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundOutgoingMergedTopHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: false))
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: true))
|
||||
self.chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .bottom)
|
||||
self.chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both)
|
||||
self.chatMessageBackgroundOutgoingMergedBothHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .both)
|
||||
|
||||
self.chatMessageBackgroundIncomingMergedSideImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side)
|
||||
self.chatMessageBackgroundOutgoingMergedSideImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side)
|
||||
self.chatMessageBackgroundIncomingMergedSideHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .side)
|
||||
self.chatMessageBackgroundOutgoingMergedSideHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .side)
|
||||
|
||||
self.checkBubbleFullImage = generateCheckImage(partial: false, color: theme.message.outgoingCheckColor)!
|
||||
self.checkBubblePartialImage = generateCheckImage(partial: true, color: theme.message.outgoingCheckColor)!
|
||||
|
||||
self.checkMediaFullImage = generateCheckImage(partial: false, color: .white)!
|
||||
self.checkMediaPartialImage = generateCheckImage(partial: true, color: .white)!
|
||||
|
||||
let serviceColor = serviceMessageColorComponents(chatTheme: theme, wallpaper: wallpaper)
|
||||
self.checkFreeFullImage = generateCheckImage(partial: false, color: serviceColor.primaryText)!
|
||||
self.checkFreePartialImage = generateCheckImage(partial: true, color: serviceColor.primaryText)!
|
||||
|
||||
self.clockBubbleIncomingFrameImage = generateClockFrameImage(color: theme.message.incoming.pendingActivityColor)!
|
||||
self.clockBubbleIncomingMinImage = generateClockMinImage(color: theme.message.incoming.pendingActivityColor)!
|
||||
self.clockBubbleOutgoingFrameImage = generateClockFrameImage(color: theme.message.outgoing.pendingActivityColor)!
|
||||
self.clockBubbleOutgoingMinImage = generateClockMinImage(color: theme.message.outgoing.pendingActivityColor)!
|
||||
|
||||
self.clockMediaFrameImage = generateClockFrameImage(color: .white)!
|
||||
self.clockMediaMinImage = generateClockMinImage(color: .white)!
|
||||
|
||||
self.clockFreeFrameImage = generateClockFrameImage(color: serviceColor.primaryText)!
|
||||
self.clockFreeMinImage = generateClockMinImage(color: serviceColor.primaryText)!
|
||||
|
||||
self.dateAndStatusMediaBackground = generateStretchableFilledCircleImage(diameter: 18.0, color: theme.message.mediaDateAndStatusFillColor)!
|
||||
self.dateAndStatusFreeBackground = generateStretchableFilledCircleImage(diameter: 18.0, color: serviceColor.dateFillStatic)!
|
||||
|
||||
let impressionCountImage = UIImage(bundleImageName: "Chat/Message/ImpressionCount")!
|
||||
self.incomingDateAndStatusImpressionIcon = generateTintedImage(image: impressionCountImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusImpressionIcon = generateTintedImage(image: impressionCountImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
self.mediaImpressionIcon = generateTintedImage(image: impressionCountImage, color: .white)!
|
||||
self.freeImpressionIcon = generateTintedImage(image: impressionCountImage, color: serviceColor.primaryText)!
|
||||
|
||||
let chatDateSize: CGFloat = 20.0
|
||||
self.dateStaticBackground = generateImage(CGSize(width: chatDateSize, height: chatDateSize), contextGenerator: { size, context -> Void in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(serviceColor.dateFillStatic.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
})!.stretchableImage(withLeftCapWidth: Int(chatDateSize) / 2, topCapHeight: Int(chatDateSize) / 2)
|
||||
|
||||
self.dateFloatingBackground = generateImage(CGSize(width: chatDateSize, height: chatDateSize), contextGenerator: { size, context -> Void in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(serviceColor.dateFillFloating.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
})!.stretchableImage(withLeftCapWidth: Int(chatDateSize) / 2, topCapHeight: Int(chatDateSize) / 2)
|
||||
|
||||
self.radialIndicatorFileIconIncoming = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/RadialProgressIconDocumentIncoming"), color: incoming.fill)!
|
||||
self.radialIndicatorFileIconOutgoing = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/RadialProgressIconDocumentIncoming"), color: outgoing.fill)!
|
||||
self.chatMessageBackgroundIncomingMergedSideImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side)
|
||||
self.chatMessageBackgroundOutgoingMergedSideImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side)
|
||||
self.chatMessageBackgroundIncomingMergedSideHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .side)
|
||||
self.chatMessageBackgroundOutgoingMergedSideHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .side)
|
||||
|
||||
self.checkBubbleFullImage = generateCheckImage(partial: false, color: theme.message.outgoingCheckColor)!
|
||||
self.checkBubblePartialImage = generateCheckImage(partial: true, color: theme.message.outgoingCheckColor)!
|
||||
|
||||
self.checkMediaFullImage = generateCheckImage(partial: false, color: .white)!
|
||||
self.checkMediaPartialImage = generateCheckImage(partial: true, color: .white)!
|
||||
|
||||
let serviceColor = serviceMessageColorComponents(chatTheme: theme, wallpaper: wallpaper)
|
||||
self.checkFreeFullImage = generateCheckImage(partial: false, color: serviceColor.primaryText)!
|
||||
self.checkFreePartialImage = generateCheckImage(partial: true, color: serviceColor.primaryText)!
|
||||
|
||||
self.clockBubbleIncomingFrameImage = generateClockFrameImage(color: theme.message.incoming.pendingActivityColor)!
|
||||
self.clockBubbleIncomingMinImage = generateClockMinImage(color: theme.message.incoming.pendingActivityColor)!
|
||||
self.clockBubbleOutgoingFrameImage = generateClockFrameImage(color: theme.message.outgoing.pendingActivityColor)!
|
||||
self.clockBubbleOutgoingMinImage = generateClockMinImage(color: theme.message.outgoing.pendingActivityColor)!
|
||||
|
||||
self.clockMediaFrameImage = generateClockFrameImage(color: .white)!
|
||||
self.clockMediaMinImage = generateClockMinImage(color: .white)!
|
||||
|
||||
self.clockFreeFrameImage = generateClockFrameImage(color: serviceColor.primaryText)!
|
||||
self.clockFreeMinImage = generateClockMinImage(color: serviceColor.primaryText)!
|
||||
|
||||
self.dateAndStatusMediaBackground = generateStretchableFilledCircleImage(diameter: 18.0, color: theme.message.mediaDateAndStatusFillColor)!
|
||||
self.dateAndStatusFreeBackground = generateStretchableFilledCircleImage(diameter: 18.0, color: serviceColor.dateFillStatic)!
|
||||
|
||||
let impressionCountImage = UIImage(bundleImageName: "Chat/Message/ImpressionCount")!
|
||||
self.incomingDateAndStatusImpressionIcon = generateTintedImage(image: impressionCountImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusImpressionIcon = generateTintedImage(image: impressionCountImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
self.mediaImpressionIcon = generateTintedImage(image: impressionCountImage, color: .white)!
|
||||
self.freeImpressionIcon = generateTintedImage(image: impressionCountImage, color: serviceColor.primaryText)!
|
||||
|
||||
let chatDateSize: CGFloat = 20.0
|
||||
self.dateStaticBackground = generateImage(CGSize(width: chatDateSize, height: chatDateSize), contextGenerator: { size, context -> Void in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(serviceColor.dateFillStatic.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
})!.stretchableImage(withLeftCapWidth: Int(chatDateSize) / 2, topCapHeight: Int(chatDateSize) / 2)
|
||||
|
||||
self.dateFloatingBackground = generateImage(CGSize(width: chatDateSize, height: chatDateSize), contextGenerator: { size, context -> Void in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(serviceColor.dateFillFloating.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
})!.stretchableImage(withLeftCapWidth: Int(chatDateSize) / 2, topCapHeight: Int(chatDateSize) / 2)
|
||||
|
||||
self.radialIndicatorFileIconIncoming = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/RadialProgressIconDocumentIncoming"), color: incoming.fill)!
|
||||
self.radialIndicatorFileIconOutgoing = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/RadialProgressIconDocumentIncoming"), color: outgoing.fill)!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@ -340,6 +340,11 @@ public final class ShareController: ViewController {
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = ShareControllerNode(sharedContext: self.sharedContext, defaultAction: self.defaultAction, requestLayout: { [weak self] transition in
|
||||
self?.requestLayout(transition: transition)
|
||||
}, presentError: { [weak self] title, text in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare)
|
||||
self.controllerNode.dismiss = { [weak self] shared in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
@ -353,98 +358,141 @@ public final class ShareController: ViewController {
|
||||
})
|
||||
}
|
||||
self.controllerNode.share = { [weak self] text, peerIds in
|
||||
if let strongSelf = self {
|
||||
switch strongSelf.subject {
|
||||
case let .url(url):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: url, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
|
||||
}
|
||||
return .complete()
|
||||
case let .text(string):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: string, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
|
||||
}
|
||||
return .complete()
|
||||
case let .quote(string, url):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
|
||||
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
|
||||
let entities = generateChatInputTextEntities(attributedText)
|
||||
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
|
||||
}
|
||||
return .complete()
|
||||
case let .image(representations):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil)), replyToMessageId: nil, localGroupingKey: nil))
|
||||
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
|
||||
}
|
||||
return .complete()
|
||||
case let .media(mediaReference):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil))
|
||||
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
|
||||
}
|
||||
return .complete()
|
||||
case let .mapMedia(media):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil))
|
||||
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
|
||||
}
|
||||
return .complete()
|
||||
case let .messages(messages):
|
||||
for peerId in peerIds {
|
||||
var messagesToEnqueue: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messagesToEnqueue.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
for message in messages {
|
||||
messagesToEnqueue.append(.forward(source: message.id, grouping: .auto, attributes: []))
|
||||
}
|
||||
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue).start()
|
||||
}
|
||||
return .single(.done)
|
||||
case let .fromExternal(f):
|
||||
return f(peerIds, text, strongSelf.currentAccount)
|
||||
|> map { state -> ShareState in
|
||||
switch state {
|
||||
case .preparing:
|
||||
return .preparing
|
||||
case let .progress(value):
|
||||
return .progress(value)
|
||||
case .done:
|
||||
return .done
|
||||
}
|
||||
}
|
||||
guard let strongSelf = self else {
|
||||
return .complete()
|
||||
}
|
||||
var shareSignals: [Signal<[MessageId?], NoError>] = []
|
||||
switch strongSelf.subject {
|
||||
case let .url(url):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: url, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||
}
|
||||
case let .text(string):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: string, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||
}
|
||||
case let .quote(string, url):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
|
||||
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
|
||||
let entities = generateChatInputTextEntities(attributedText)
|
||||
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||
}
|
||||
case let .image(representations):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil)), replyToMessageId: nil, localGroupingKey: nil))
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||
}
|
||||
case let .media(mediaReference):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil))
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||
}
|
||||
case let .mapMedia(media):
|
||||
for peerId in peerIds {
|
||||
var messages: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil))
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||
}
|
||||
case let .messages(messages):
|
||||
for peerId in peerIds {
|
||||
var messagesToEnqueue: [EnqueueMessage] = []
|
||||
if !text.isEmpty {
|
||||
messagesToEnqueue.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
for message in messages {
|
||||
messagesToEnqueue.append(.forward(source: message.id, grouping: .auto, attributes: []))
|
||||
}
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
|
||||
}
|
||||
case let .fromExternal(f):
|
||||
return f(peerIds, text, strongSelf.currentAccount)
|
||||
|> map { state -> ShareState in
|
||||
switch state {
|
||||
case .preparing:
|
||||
return .preparing
|
||||
case let .progress(value):
|
||||
return .progress(value)
|
||||
case .done:
|
||||
return .done
|
||||
}
|
||||
}
|
||||
}
|
||||
return .complete()
|
||||
let account = strongSelf.currentAccount
|
||||
let queue = Queue.mainQueue()
|
||||
var displayedError = false
|
||||
return combineLatest(queue: queue, shareSignals)
|
||||
|> mapToSignal { messageIdSets -> Signal<ShareState, NoError> in
|
||||
var statuses: [Signal<(MessageId, PendingMessageStatus?, PendingMessageFailureReason?), NoError>] = []
|
||||
for messageIds in messageIdSets {
|
||||
for case let id? in messageIds {
|
||||
statuses.append(account.pendingMessageManager.pendingMessageStatus(id)
|
||||
|> map { status, error -> (MessageId, PendingMessageStatus?, PendingMessageFailureReason?) in
|
||||
return (id, status, error)
|
||||
})
|
||||
}
|
||||
}
|
||||
return combineLatest(queue: queue, statuses)
|
||||
|> mapToSignal { statuses -> Signal<ShareState, NoError> in
|
||||
var hasStatuses = false
|
||||
for (id, status, error) in statuses {
|
||||
if let error = error {
|
||||
Queue.mainQueue().async {
|
||||
let _ = (account.postbox.transaction { transaction -> Peer? in
|
||||
transaction.deleteMessages([id])
|
||||
return transaction.getPeer(id.peerId)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard let strongSelf = self, let peer = peer else {
|
||||
return
|
||||
}
|
||||
if !displayedError, case .slowmodeActive = error {
|
||||
displayedError = true
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: peer.displayTitle, text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
let _ = account.postbox.transaction({ transaction in
|
||||
|
||||
}).start()
|
||||
if status != nil {
|
||||
hasStatuses = true
|
||||
}
|
||||
}
|
||||
if !hasStatuses {
|
||||
return .single(.done)
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|> take(1)
|
||||
}
|
||||
}
|
||||
self.controllerNode.shareExternal = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
|
@ -30,6 +30,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
private let defaultAction: ShareControllerAction?
|
||||
private let requestLayout: (ContainedViewLayoutTransition) -> Void
|
||||
private let presentError: (String?, String) -> Void
|
||||
|
||||
private var containerLayout: (ContainerViewLayout, CGFloat, CGFloat)?
|
||||
|
||||
@ -70,11 +71,12 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
private var hapticFeedback: HapticFeedback?
|
||||
|
||||
init(sharedContext: SharedAccountContext, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, externalShare: Bool, immediateExternalShare: Bool) {
|
||||
init(sharedContext: SharedAccountContext, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool) {
|
||||
self.sharedContext = sharedContext
|
||||
self.presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||
self.externalShare = externalShare
|
||||
self.immediateExternalShare = immediateExternalShare
|
||||
self.presentError = presentError
|
||||
|
||||
self.defaultAction = defaultAction
|
||||
self.requestLayout = requestLayout
|
||||
@ -500,6 +502,15 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
defaultAction.action()
|
||||
}
|
||||
} else {
|
||||
if !self.inputFieldNode.text.isEmpty {
|
||||
for peer in self.controllerInteraction!.selectedPeers {
|
||||
if let channel = peer.peer as? TelegramChannel, channel.isRestrictedBySlowmode {
|
||||
self.presentError(channel.title, self.presentationData.strings.Share_MultipleMessagesDisabled)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.inputFieldNode.deactivateInput()
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.12, curve: .easeInOut)
|
||||
transition.updateAlpha(node: self.actionButtonNode, alpha: 0.0)
|
||||
|
@ -111,7 +111,7 @@ final class ShareControllerPeerGridItem: GridItem {
|
||||
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
|
||||
let node = ShareControllerPeerGridItemNode()
|
||||
node.controllerInteraction = self.controllerInteraction
|
||||
node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, search: self.search, synchronousLoad: synchronousLoad)
|
||||
node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, search: self.search, synchronousLoad: synchronousLoad, force: false)
|
||||
return node
|
||||
}
|
||||
|
||||
@ -121,13 +121,14 @@ final class ShareControllerPeerGridItem: GridItem {
|
||||
return
|
||||
}
|
||||
node.controllerInteraction = self.controllerInteraction
|
||||
node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, search: self.search, synchronousLoad: false)
|
||||
node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, presence: self.presence, search: self.search, synchronousLoad: false, force: false)
|
||||
}
|
||||
}
|
||||
|
||||
final class ShareControllerPeerGridItemNode: GridItemNode {
|
||||
private var currentState: (Account, RenderedPeer, Bool, PeerPresence?)?
|
||||
private var currentState: (Account, PresentationTheme, PresentationStrings, RenderedPeer, Bool, PeerPresence?)?
|
||||
private let peerNode: SelectablePeerNode
|
||||
private var presenceManager: PeerPresenceStatusManager?
|
||||
|
||||
var controllerInteraction: ShareControllerInteraction?
|
||||
|
||||
@ -138,7 +139,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
|
||||
|
||||
self.peerNode.toggleSelection = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let (_, peer, search, _) = strongSelf.currentState {
|
||||
if let (_, _, _, peer, search, _) = strongSelf.currentState {
|
||||
if let _ = peer.peers[peer.peerId] {
|
||||
strongSelf.controllerInteraction?.togglePeer(peer, search)
|
||||
}
|
||||
@ -146,10 +147,16 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
|
||||
}
|
||||
}
|
||||
self.addSubnode(self.peerNode)
|
||||
self.presenceManager = PeerPresenceStatusManager(update: { [weak self] in
|
||||
guard let strongSelf = self, let currentState = strongSelf.currentState else {
|
||||
return
|
||||
}
|
||||
strongSelf.setup(account: currentState.0, theme: currentState.1, strings: currentState.2, peer: currentState.3, presence: currentState.5, search: currentState.4, synchronousLoad: false, force: true)
|
||||
})
|
||||
}
|
||||
|
||||
func setup(account: Account, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, presence: PeerPresence?, search: Bool, synchronousLoad: Bool) {
|
||||
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != peer || !arePeerPresencesEqual(self.currentState!.3, presence) {
|
||||
func setup(account: Account, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, presence: PeerPresence?, search: Bool, synchronousLoad: Bool, force: Bool) {
|
||||
if force || self.currentState == nil || self.currentState!.0 !== account || self.currentState!.3 != peer || !arePeerPresencesEqual(self.currentState!.5, presence) {
|
||||
let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor)
|
||||
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
@ -163,15 +170,18 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
|
||||
|
||||
self.peerNode.theme = itemTheme
|
||||
self.peerNode.setup(account: account, theme: theme, strings: strings, peer: peer, online: online, synchronousLoad: synchronousLoad)
|
||||
self.currentState = (account, peer, search, presence)
|
||||
self.currentState = (account, theme, strings, peer, search, presence)
|
||||
self.setNeedsLayout()
|
||||
if let presence = presence as? TelegramUserPresence {
|
||||
self.presenceManager?.reset(presence: presence)
|
||||
}
|
||||
}
|
||||
self.updateSelection(animated: false)
|
||||
}
|
||||
|
||||
func updateSelection(animated: Bool) {
|
||||
var selected = false
|
||||
if let controllerInteraction = self.controllerInteraction, let (_, peer, _, _) = self.currentState {
|
||||
if let controllerInteraction = self.controllerInteraction, let (_, _, _, peer, _, _) = self.currentState {
|
||||
selected = controllerInteraction.selectedPeerIds.contains(peer.peerId)
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,7 @@ final class ThemeSettingsColorSliderNode: ASDisplayNode {
|
||||
private let brightnessKnobNode: ThemeSettingsColorKnobNode
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var panning = false
|
||||
|
||||
var valueChanged: ((CGFloat) -> Void)?
|
||||
|
||||
@ -143,6 +144,7 @@ final class ThemeSettingsColorSliderNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var _value: CGFloat = 0.5
|
||||
var lastReportedValue: CGFloat?
|
||||
|
||||
var value: CGFloat {
|
||||
get {
|
||||
@ -196,7 +198,9 @@ final class ThemeSettingsColorSliderNode: ASDisplayNode {
|
||||
let inset: CGFloat = 16.0
|
||||
transition.updateFrame(node: self.brightnessNode, frame: CGRect(x: inset, y: floor((size.height - 30.0) / 2.0), width: size.width - inset * 2.0, height: 30.0))
|
||||
|
||||
self.updateKnobLayout(size: size, transition: .immediate)
|
||||
if !self.panning {
|
||||
self.updateKnobLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func brightnessPan(_ recognizer: UIPanGestureRecognizer) {
|
||||
@ -213,18 +217,27 @@ final class ThemeSettingsColorSliderNode: ASDisplayNode {
|
||||
var ended = false
|
||||
switch recognizer.state {
|
||||
case .changed:
|
||||
self.panning = true
|
||||
self.updateKnobLayout(size: size, transition: .immediate)
|
||||
recognizer.setTranslation(CGPoint(), in: recognizer.view)
|
||||
case .ended:
|
||||
self.updateKnobLayout(size: size, transition: .immediate)
|
||||
self.panning = false
|
||||
ended = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if self.value != previousValue || ended {
|
||||
var update = true
|
||||
if let lastReportedValue = self.lastReportedValue, abs(self.value - lastReportedValue) < 0.05 {
|
||||
update = false
|
||||
}
|
||||
|
||||
if update || ended {
|
||||
self.update()
|
||||
self.valueChanged?(self.value)
|
||||
self.lastReportedValue = self.value
|
||||
print("upda")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,6 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
case wallpaper(PresentationTheme, String)
|
||||
case accentColor(PresentationTheme, String, PresentationThemeAccentColor?)
|
||||
case autoNightTheme(PresentationTheme, String, String)
|
||||
case themeTint(PresentationTheme, String, Bool)
|
||||
case themeItem(PresentationTheme, PresentationStrings, [PresentationThemeReference], PresentationThemeReference, [Int64: PresentationThemeAccentColor], PresentationThemeAccentColor?, Bool)
|
||||
case iconHeader(PresentationTheme, String)
|
||||
case iconItem(PresentationTheme, PresentationStrings, [PresentationAppIcon], String?)
|
||||
@ -78,7 +77,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .themeListHeader, .chatPreview, .themeItem, .themeTint, .accentColor:
|
||||
case .themeListHeader, .chatPreview, .themeItem, .accentColor:
|
||||
return ThemeSettingsControllerSection.chatPreview.rawValue
|
||||
case .fontSizeHeader, .fontSize:
|
||||
return ThemeSettingsControllerSection.fontSize.rawValue
|
||||
@ -99,8 +98,6 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return 1
|
||||
case .themeItem:
|
||||
return 2
|
||||
case .themeTint:
|
||||
return 3
|
||||
case .accentColor:
|
||||
return 4
|
||||
case .wallpaper:
|
||||
@ -140,12 +137,6 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .themeTint(lhsTheme, lhsTitle, lhsValue):
|
||||
if case let .themeTint(rhsTheme, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .accentColor(lhsTheme, lhsText, lhsColor):
|
||||
if case let .accentColor(rhsTheme, rhsText, rhsColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsColor == rhsColor {
|
||||
return true
|
||||
@ -239,10 +230,6 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return ItemListDisclosureItem(theme: theme, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openWallpaperSettings()
|
||||
})
|
||||
case let .themeTint(theme, title, value):
|
||||
return ItemListSwitchItem(theme: theme, title: title, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleLargeEmoji(value)
|
||||
}, tag: ThemeSettingsEntryTag.tint)
|
||||
case let .accentColor(theme, _, color):
|
||||
var colors = PresentationThemeBaseColor.allCases
|
||||
if theme.overallDarkAppearance {
|
||||
@ -450,7 +437,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
let disableAnimations = settings.disableAnimations
|
||||
|
||||
let accentColor = settings.themeSpecificAccentColors[settings.theme.index]?.color ?? defaultDayAccentColor
|
||||
let theme = makePresentationTheme(themeReference: settings.theme, accentColor: accentColor, serviceBackgroundColor: defaultServiceBackgroundColor)
|
||||
let theme = makePresentationTheme(themeReference: settings.theme, accentColor: accentColor, serviceBackgroundColor: defaultServiceBackgroundColor, preview: true)
|
||||
|
||||
let wallpaper: TelegramWallpaper
|
||||
if let themeSpecificWallpaper = settings.themeSpecificChatWallpapers[settings.theme.index] {
|
||||
|
Loading…
x
Reference in New Issue
Block a user