mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '5b80b9a85b5595e4c2eac40f644705a181b87330' into beta
This commit is contained in:
commit
4211868217
@ -255,6 +255,8 @@
|
||||
|
||||
"PUSH_MESSAGE_SUGGEST_USERPIC" = "%1$@|suggested you new profile photo";
|
||||
|
||||
"PUSH_MESSAGE_WALLPAPER" = "%1$@ set a new background for the chat with you";
|
||||
"PUSH_MESSAGE_SAME_WALLPAPER" = "%1$@ set the same background for the chat with you";
|
||||
|
||||
"PUSH_REMINDER_TITLE" = "🗓 Reminder";
|
||||
"PUSH_SENDER_YOU" = "📅 You";
|
||||
@ -9133,3 +9135,19 @@ Sorry for the inconvenience.";
|
||||
"Premium.MaxChannelsText" = "You can only join **%1$@** groups and channels. Upgrade to **Telegram Premium** to increase the links limit to **%2$@**.";
|
||||
"Premium.MaxChannelsNoPremiumText" = "You can only join **%1$@** groups and channels. We are working to let you increase this limit in the future.";
|
||||
"Premium.MaxChannelsFinalText" = "Sorry, you can only join **%1$@** groups and channels";
|
||||
|
||||
"Username.BotLinkHint" = "This username cannot be edited.";
|
||||
"Username.BotLinkHintExtended" = "This username cannot be edited. You can acquire additional usernames on [Fragment]().";
|
||||
|
||||
"PeerInfo.Bot.EditIntro" = "Edit Intro";
|
||||
"PeerInfo.Bot.EditCommands" = "Edit Commands";
|
||||
"PeerInfo.Bot.ChangeSettings" = "Change Bot Settings";
|
||||
"PeerInfo.Bot.BotFatherInfo" = "Use [@BotFather]() to manage this bot.";
|
||||
|
||||
"WallpaperPreview.NotAppliedInfo" = "Background will not be applied for **%@**";
|
||||
"WallpaperPreview.ChatTopText" = "Apply the background in this chat.";
|
||||
"WallpaperPreview.ChatBottomText" = "Enjoy the view.";
|
||||
|
||||
"Conversation.Theme.SetPhotoWallpaper" = "Choose Background from Photos";
|
||||
"Conversation.Theme.SetColorWallpaper" = "Choose Color as a Background";
|
||||
"Conversation.Theme.OtherOptions" = "Other Options...";
|
||||
|
@ -853,7 +853,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
||||
var didBeginSelectingChats: (() -> Void)?
|
||||
public var displayFilterLimit: (() -> Void)?
|
||||
|
||||
public init(context: AccountContext, location: ChatListControllerLocation, chatListMode: ChatListNodeMode = .chatList, previewing: Bool, controlsHistoryPreload: Bool, isInlineMode: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, filterBecameEmpty: @escaping (ChatListFilter?) -> Void, filterEmptyAction: @escaping (ChatListFilter?) -> Void, secondaryEmptyAction: @escaping () -> Void) {
|
||||
public init(context: AccountContext, location: ChatListControllerLocation, chatListMode: ChatListNodeMode = .chatList(appendContacts: true), previewing: Bool, controlsHistoryPreload: Bool, isInlineMode: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, filterBecameEmpty: @escaping (ChatListFilter?) -> Void, filterEmptyAction: @escaping (ChatListFilter?) -> Void, secondaryEmptyAction: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.location = location
|
||||
self.chatListMode = chatListMode
|
||||
|
@ -3349,7 +3349,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
if let currentMutedIconImage = currentMutedIconImage {
|
||||
strongSelf.mutedIconNode.image = currentMutedIconImage
|
||||
strongSelf.mutedIconNode.isHidden = false
|
||||
transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: titleFrame.maxY - currentMutedIconImage.size.height + 0.0 + UIScreenPixel), size: currentMutedIconImage.size))
|
||||
transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: floorToScreenPixels(titleFrame.midY - currentMutedIconImage.size.height / 2.0)), size: currentMutedIconImage.size))
|
||||
nextTitleIconOrigin += currentMutedIconImage.size.width + 1.0
|
||||
} else {
|
||||
strongSelf.mutedIconNode.image = nil
|
||||
|
@ -20,7 +20,7 @@ import Postbox
|
||||
import ChatFolderLinkPreviewScreen
|
||||
|
||||
public enum ChatListNodeMode {
|
||||
case chatList
|
||||
case chatList(appendContacts: Bool)
|
||||
case peers(filter: ChatListNodePeersFilter, isSelecting: Bool, additionalCategories: [ChatListNodeAdditionalCategory], chatListFilters: [ChatListFilter]?, displayAutoremoveTimeout: Bool)
|
||||
case peerType(type: [ReplyMarkupButtonRequestPeerType], hasCreate: Bool)
|
||||
}
|
||||
@ -1668,7 +1668,16 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
|
||||
let currentPeerId: EnginePeer.Id = context.account.peerId
|
||||
|
||||
|
||||
/*let contactList: Signal<EngineContactList?, NoError>
|
||||
if case let .chatList(appendContacts) = mode, appendContacts {
|
||||
contactList = self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Contacts.List(includePresences: true))
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
contactList = .single(nil)
|
||||
}
|
||||
let _ = contactList*/
|
||||
|
||||
|
||||
/*let emptyInitialView = ChatListNodeView(
|
||||
originalList: EngineChatList(
|
||||
|
@ -225,7 +225,7 @@ open class ViewControllerComponentContainer: ViewController {
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
var theme = presentationData.theme
|
||||
if case .modal = presentationMode, theme.list.blocksBackgroundColor.rgb == theme.list.plainBackgroundColor.rgb {
|
||||
if case .modal = presentationMode {
|
||||
theme = theme.withModalBlocksBackground()
|
||||
}
|
||||
|
||||
|
@ -870,10 +870,9 @@ public func createPollController(context: AccountContext, updatedPresentationDat
|
||||
)
|
||||
|> map { presentationData, state, limitsConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var presentationData = presentationData
|
||||
if presentationData.theme.list.blocksBackgroundColor.rgb == presentationData.theme.list.plainBackgroundColor.rgb {
|
||||
let updatedTheme = presentationData.theme.withModalBlocksBackground()
|
||||
presentationData = presentationData.withUpdated(theme: updatedTheme)
|
||||
}
|
||||
|
||||
let updatedTheme = presentationData.theme.withModalBlocksBackground()
|
||||
presentationData = presentationData.withUpdated(theme: updatedTheme)
|
||||
|
||||
var enabled = true
|
||||
if processPollText(state.text).isEmpty {
|
||||
|
@ -114,7 +114,7 @@ final class ContactsControllerNode: ASDisplayNode {
|
||||
|
||||
strongSelf.presentationData = presentationData
|
||||
|
||||
if previousStrings !== presentationData.strings {
|
||||
if previousStrings.baseLanguageCode != presentationData.strings.baseLanguageCode {
|
||||
strongSelf.stringsPromise.set(.single(presentationData.strings))
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,8 @@ public class ItemListTextItem: ListViewItem, ItemListItem {
|
||||
}
|
||||
|
||||
public class ItemListTextItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let titleNode: TextNode
|
||||
private let textNode: TextNode
|
||||
private var linkHighlightingNode: LinkHighlightingNode?
|
||||
private let activateArea: AccessibilityAreaNode
|
||||
|
||||
private var item: ItemListTextItem?
|
||||
@ -85,17 +86,17 @@ public class ItemListTextItemNode: ListViewItemNode, ItemListItemNode {
|
||||
}
|
||||
|
||||
public init() {
|
||||
self.titleNode = TextNode()
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
self.titleNode.contentMode = .left
|
||||
self.titleNode.contentsScale = UIScreen.main.scale
|
||||
self.textNode = TextNode()
|
||||
self.textNode.isUserInteractionEnabled = false
|
||||
self.textNode.contentMode = .left
|
||||
self.textNode.contentsScale = UIScreen.main.scale
|
||||
|
||||
self.activateArea = AccessibilityAreaNode()
|
||||
self.activateArea.accessibilityTraits = .staticText
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.activateArea)
|
||||
}
|
||||
|
||||
@ -106,11 +107,16 @@ public class ItemListTextItemNode: ListViewItemNode, ItemListItemNode {
|
||||
recognizer.tapActionAtPoint = { _ in
|
||||
return .waitForSingleTap
|
||||
}
|
||||
recognizer.highlight = { [weak self] point in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateTouchesAtPoint(point)
|
||||
}
|
||||
}
|
||||
self.view.addGestureRecognizer(recognizer)
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ item: ItemListTextItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.textNode)
|
||||
|
||||
return { item, params, neighbors in
|
||||
let leftInset: CGFloat = 15.0
|
||||
@ -158,7 +164,7 @@ public class ItemListTextItemNode: ListViewItemNode, ItemListItemNode {
|
||||
|
||||
let _ = titleApply()
|
||||
|
||||
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + params.leftInset, y: topInset), size: titleLayout.size)
|
||||
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset + params.leftInset, y: topInset), size: titleLayout.size)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -178,9 +184,9 @@ public class ItemListTextItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
switch gesture {
|
||||
case .tap:
|
||||
let titleFrame = self.titleNode.frame
|
||||
let titleFrame = self.textNode.frame
|
||||
if let item = self.item, titleFrame.contains(location) {
|
||||
if let (_, attributes) = self.titleNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) {
|
||||
if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) {
|
||||
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
item.linkAction?(.tap(url))
|
||||
}
|
||||
@ -194,4 +200,46 @@ public class ItemListTextItemNode: ListViewItemNode, ItemListItemNode {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func updateTouchesAtPoint(_ point: CGPoint?) {
|
||||
if let item = self.item {
|
||||
var rects: [CGRect]?
|
||||
if let point = point {
|
||||
let textNodeFrame = self.textNode.frame
|
||||
if let (index, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||
let possibleNames: [String] = [
|
||||
TelegramTextAttributes.URL,
|
||||
TelegramTextAttributes.PeerMention,
|
||||
TelegramTextAttributes.PeerTextMention,
|
||||
TelegramTextAttributes.BotCommand,
|
||||
TelegramTextAttributes.Hashtag
|
||||
]
|
||||
for name in possibleNames {
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: name)] {
|
||||
rects = self.textNode.attributeRects(name: name, at: index)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let rects = rects {
|
||||
let linkHighlightingNode: LinkHighlightingNode
|
||||
if let current = self.linkHighlightingNode {
|
||||
linkHighlightingNode = current
|
||||
} else {
|
||||
linkHighlightingNode = LinkHighlightingNode(color: item.presentationData.theme.list.itemAccentColor.withAlphaComponent(0.2))
|
||||
self.linkHighlightingNode = linkHighlightingNode
|
||||
self.insertSubnode(linkHighlightingNode, belowSubnode: self.textNode)
|
||||
}
|
||||
linkHighlightingNode.frame = self.textNode.frame
|
||||
linkHighlightingNode.updateRects(rects)
|
||||
} else if let linkHighlightingNode = self.linkHighlightingNode {
|
||||
self.linkHighlightingNode = nil
|
||||
linkHighlightingNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false, completion: { [weak linkHighlightingNode] _ in
|
||||
linkHighlightingNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ UIImage *TGPaintCombineCroppedImages(UIImage *background, UIImage *foreground, b
|
||||
CGFloat pRatio = foreground.size.width / originalSize.width;
|
||||
CGSize rotatedContentSize = TGRotatedContentSize(foreground.size, cropRotation);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(background.size, opaque, 0.0);
|
||||
UIGraphicsBeginImageContextWithOptions(background.size, opaque, 1.0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGRect backgroundRect = CGRectMake(0, 0, background.size.width, background.size.height);
|
||||
|
@ -1317,7 +1317,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self.navigationItem.titleView = self.titleView
|
||||
|
||||
if case let .assets(_, isStandalone) = self.subject, isStandalone {
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.backPressed))
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
} else {
|
||||
if case let .assets(collection, _) = self.subject, collection != nil {
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.backPressed))
|
||||
|
@ -1063,6 +1063,10 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
let previousEditingPhoneIds = Atomic<Set<Int64>?>(value: nil)
|
||||
let signal = combineLatest(presentationData, statePromise.get(), contactData, hiddenAvatarPromise.get())
|
||||
|> map { presentationData, state, peerAndContactData, hiddenAvatar -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var presentationData = presentationData
|
||||
let updatedTheme = presentationData.theme.withModalBlocksBackground()
|
||||
presentationData = presentationData.withUpdated(theme: updatedTheme)
|
||||
|
||||
var leftNavigationButton: ItemListNavigationButton?
|
||||
switch subject {
|
||||
case .vcard:
|
||||
|
@ -196,7 +196,7 @@ func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryE
|
||||
}).start()
|
||||
}
|
||||
|
||||
func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, peerId: PeerId, completion: @escaping () -> Void) {
|
||||
public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, peerId: PeerId, completion: @escaping () -> Void) {
|
||||
let imageSignal: Signal<UIImage, NoError>
|
||||
switch wallpaper {
|
||||
case let .wallpaper(wallpaper, _):
|
||||
@ -276,7 +276,7 @@ func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGall
|
||||
croppedImage = TGPhotoEditorCrop(image, nil, .up, 0.0, finalCropRect, false, CGSize(width: 1440.0, height: 2960.0), image.size, true)
|
||||
|
||||
if mode.contains(.blur) {
|
||||
croppedImage = blurredImage(croppedImage, radius: 45.0)!
|
||||
croppedImage = blurredImage(croppedImage, radius: 30.0)!
|
||||
}
|
||||
|
||||
let thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0))
|
||||
|
@ -35,8 +35,13 @@ enum ThemeAccentColorControllerMode {
|
||||
}
|
||||
|
||||
final class ThemeAccentColorController: ViewController {
|
||||
enum ResultMode {
|
||||
case `default`
|
||||
case peer(EnginePeer)
|
||||
}
|
||||
private let context: AccountContext
|
||||
private let mode: ThemeAccentColorControllerMode
|
||||
private let resultMode: ResultMode
|
||||
private let section: ThemeColorSection
|
||||
private let initialBackgroundColor: UIColor?
|
||||
private var presentationData: PresentationData
|
||||
@ -57,9 +62,10 @@ final class ThemeAccentColorController: ViewController {
|
||||
|
||||
var completion: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, mode: ThemeAccentColorControllerMode) {
|
||||
init(context: AccountContext, mode: ThemeAccentColorControllerMode, resultMode: ResultMode = .default) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.resultMode = resultMode
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let section: ThemeColorSection = .background
|
||||
@ -143,7 +149,7 @@ final class ThemeAccentColorController: ViewController {
|
||||
initialWallpaper = self.presentationData.chatWallpaper
|
||||
}
|
||||
|
||||
self.displayNode = ThemeAccentColorControllerNode(context: self.context, mode: self.mode, theme: theme, wallpaper: initialWallpaper, dismiss: { [weak self] in
|
||||
self.displayNode = ThemeAccentColorControllerNode(context: self.context, mode: self.mode, resultMode: self.resultMode, theme: theme, wallpaper: initialWallpaper, dismiss: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss()
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
init(context: AccountContext, mode: ThemeAccentColorControllerMode, theme: PresentationTheme, wallpaper: TelegramWallpaper, dismiss: @escaping () -> Void, apply: @escaping (ThemeColorState, UIColor?) -> Void, ready: Promise<Bool>) {
|
||||
init(context: AccountContext, mode: ThemeAccentColorControllerMode, resultMode: ThemeAccentColorController.ResultMode, theme: PresentationTheme, wallpaper: TelegramWallpaper, dismiss: @escaping () -> Void, apply: @escaping (ThemeColorState, UIColor?) -> Void, ready: Promise<Bool>) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.state = ThemeColorState()
|
||||
@ -305,10 +305,13 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
let doneButtonType: WallpaperGalleryToolbarDoneButtonType
|
||||
if case .edit(_, _, _, _, _, true, _) = self.mode {
|
||||
doneButtonType = .proceed
|
||||
} else if case .peer = resultMode {
|
||||
doneButtonType = .setPeer
|
||||
} else {
|
||||
doneButtonType = .set
|
||||
}
|
||||
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.theme, strings: self.presentationData.strings, doneButtonType: doneButtonType)
|
||||
self.toolbarNode.setDoneIsSolid(true, transition: .immediate)
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
self.maskNode.displaysAsynchronously = false
|
||||
|
@ -102,17 +102,41 @@ private func availableColors(theme: PresentationTheme) -> [UInt32] {
|
||||
}
|
||||
}
|
||||
|
||||
final class ThemeColorsGridController: ViewController {
|
||||
public final class ThemeColorsGridController: ViewController {
|
||||
public enum Mode {
|
||||
case `default`
|
||||
case peer(EnginePeer)
|
||||
|
||||
var galleryMode: WallpaperGalleryController.Mode {
|
||||
switch self {
|
||||
case .default:
|
||||
return .default
|
||||
case let .peer(peer):
|
||||
return .peer(peer, false)
|
||||
}
|
||||
}
|
||||
|
||||
var colorPickerMode: ThemeAccentColorController.ResultMode {
|
||||
switch self {
|
||||
case .default:
|
||||
return .default
|
||||
case let .peer(peer):
|
||||
return .peer(peer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var controllerNode: ThemeColorsGridControllerNode {
|
||||
return self.displayNode as! ThemeColorsGridControllerNode
|
||||
}
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
override var ready: Promise<Bool> {
|
||||
public override var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
let mode: Mode
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
@ -121,8 +145,9 @@ final class ThemeColorsGridController: ViewController {
|
||||
|
||||
private var previousContentOffset: GridNodeVisibleContentOffset?
|
||||
|
||||
init(context: AccountContext) {
|
||||
public init(context: AccountContext, mode: Mode = .default) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
@ -169,9 +194,9 @@ final class ThemeColorsGridController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
override func loadDisplayNode() {
|
||||
self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, gradients: availableGradients(theme: self.presentationData.theme), colors: availableColors(theme: self.presentationData.theme), present: { [weak self] controller, arguments in
|
||||
self?.present(controller, in: .window(.root), with: arguments, blockInteraction: true)
|
||||
public override func loadDisplayNode() {
|
||||
self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, controller: self, gradients: availableGradients(theme: self.presentationData.theme), colors: availableColors(theme: self.presentationData.theme), push: { [weak self] controller in
|
||||
self?.push(controller)
|
||||
}, pop: { [weak self] in
|
||||
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
let _ = navigationController.popViewController(animated: true)
|
||||
@ -193,8 +218,8 @@ final class ThemeColorsGridController: ViewController {
|
||||
} else {
|
||||
themeReference = settings.theme
|
||||
}
|
||||
|
||||
let controller = ThemeAccentColorController(context: strongSelf.context, mode: .background(themeReference: themeReference))
|
||||
|
||||
let controller = ThemeAccentColorController(context: strongSelf.context, mode: .background(themeReference: themeReference), resultMode: strongSelf.mode.colorPickerMode)
|
||||
controller.completion = { [weak self] in
|
||||
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
var controllers = navigationController.viewControllers
|
||||
@ -249,7 +274,7 @@ final class ThemeColorsGridController: ViewController {
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
public override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
|
@ -63,11 +63,12 @@ private func preparedThemeColorsGridEntryTransition(context: AccountContext, fro
|
||||
return ThemeColorsGridEntryTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: nil, stationaryItems: stationaryItems, scrollToItem: scrollToItem)
|
||||
}
|
||||
|
||||
final class ThemeColorsGridControllerNode: ASDisplayNode {
|
||||
final class ThemeColorsGridControllerNode: ASDisplayNode {
|
||||
private let context: AccountContext
|
||||
private weak var controller: ThemeColorsGridController?
|
||||
private var presentationData: PresentationData
|
||||
private var controllerInteraction: ThemeColorsGridControllerInteraction?
|
||||
private let present: (ViewController, Any?) -> Void
|
||||
private let push: (ViewController) -> Void
|
||||
private let presentColorPicker: () -> Void
|
||||
|
||||
let ready = ValuePromise<Bool>()
|
||||
@ -87,10 +88,11 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
||||
|
||||
private var disposable: Disposable?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, gradients: [[UInt32]], colors: [UInt32], present: @escaping (ViewController, Any?) -> Void, pop: @escaping () -> Void, presentColorPicker: @escaping () -> Void) {
|
||||
init(context: AccountContext, presentationData: PresentationData, controller: ThemeColorsGridController, gradients: [[UInt32]], colors: [UInt32], push: @escaping (ViewController) -> Void, pop: @escaping () -> Void, presentColorPicker: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.controller = controller
|
||||
self.presentationData = presentationData
|
||||
self.present = present
|
||||
self.push = push
|
||||
self.presentColorPicker = presentColorPicker
|
||||
|
||||
self.gridNode = GridNode()
|
||||
@ -126,16 +128,36 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
||||
|
||||
let previousEntries = Atomic<[ThemeColorsGridControllerEntry]?>(value: nil)
|
||||
|
||||
let dismissControllers = { [weak self] in
|
||||
if let self, let navigationController = self.controller?.navigationController as? NavigationController {
|
||||
let controllers = navigationController.viewControllers.filter({ controller in
|
||||
if controller is ThemeColorsGridController || controller is WallpaperGalleryController {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
let interaction = ThemeColorsGridControllerInteraction(openWallpaper: { [weak self] wallpaper in
|
||||
if let strongSelf = self {
|
||||
let entries = previousEntries.with { $0 }
|
||||
if let entries = entries, !entries.isEmpty {
|
||||
let wallpapers = entries.map { $0.wallpaper }
|
||||
let controller = WallpaperGalleryController(context: context, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors))
|
||||
controller.apply = { _, _, _ in
|
||||
pop()
|
||||
let controller = WallpaperGalleryController(context: context, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors), mode: strongSelf.controller?.mode.galleryMode ?? .default)
|
||||
controller.navigationPresentation = .modal
|
||||
controller.apply = { [weak self] wallpaper, _, _ in
|
||||
if let strongSelf = self, let mode = strongSelf.controller?.mode, case let .peer(peer) = mode, case let .wallpaper(wallpaperValue, _) = wallpaper {
|
||||
let _ = (strongSelf.context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: wallpaperValue)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
dismissControllers()
|
||||
})
|
||||
} else {
|
||||
pop()
|
||||
}
|
||||
}
|
||||
strongSelf.present(controller, nil)
|
||||
strongSelf.push(controller)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -17,20 +17,6 @@ import PresentationDataUtils
|
||||
import MediaPickerUI
|
||||
|
||||
public final class ThemeGridController: ViewController {
|
||||
public enum Mode: Equatable {
|
||||
case `default`
|
||||
case peer(EnginePeer.Id, TelegramWallpaper?)
|
||||
|
||||
var galleryMode: WallpaperGalleryController.Mode {
|
||||
switch self {
|
||||
case .default:
|
||||
return .default
|
||||
case let .peer(peerId, _):
|
||||
return .peer(peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var controllerNode: ThemeGridControllerNode {
|
||||
return self.displayNode as! ThemeGridControllerNode
|
||||
}
|
||||
@ -41,7 +27,6 @@ public final class ThemeGridController: ViewController {
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
private let mode: Mode
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private let presentationDataPromise = Promise<PresentationData>()
|
||||
@ -60,9 +45,8 @@ public final class ThemeGridController: ViewController {
|
||||
|
||||
private var previousContentOffset: GridNodeVisibleContentOffset?
|
||||
|
||||
public init(context: AccountContext, mode: Mode = .default) {
|
||||
public init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationDataPromise.set(.single(self.presentationData))
|
||||
|
||||
@ -133,44 +117,25 @@ public final class ThemeGridController: ViewController {
|
||||
}
|
||||
|
||||
public override func loadDisplayNode() {
|
||||
let dismissControllers = { [weak self] in
|
||||
if let self, let navigationController = self.navigationController as? NavigationController {
|
||||
let controllers = navigationController.viewControllers.filter({ controller in
|
||||
if controller is ThemeGridController || controller is WallpaperGalleryController || controller is MediaPickerScreen {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
self.displayNode = ThemeGridControllerNode(context: self.context, presentationData: self.presentationData, mode: self.mode, presentPreviewController: { [weak self] source in
|
||||
self.displayNode = ThemeGridControllerNode(context: self.context, presentationData: self.presentationData, presentPreviewController: { [weak self] source in
|
||||
if let strongSelf = self {
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: source, mode: strongSelf.mode.galleryMode)
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: source)
|
||||
controller.apply = { [weak self, weak controller] wallpaper, options, cropRect in
|
||||
if let strongSelf = self, case let .wallpaper(wallpaperValue, _) = wallpaper {
|
||||
switch strongSelf.mode {
|
||||
case .default:
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, completion: { [weak self, weak controller] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.deactivateSearch(animated: false)
|
||||
strongSelf.controllerNode.scrollToTop(animated: false)
|
||||
if let strongSelf = self {
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, completion: { [weak self, weak controller] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.deactivateSearch(animated: false)
|
||||
strongSelf.controllerNode.scrollToTop(animated: false)
|
||||
}
|
||||
if let controller = controller {
|
||||
switch wallpaper {
|
||||
case .asset, .contextResult:
|
||||
controller.dismiss(animated: true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
if let controller = controller {
|
||||
switch wallpaper {
|
||||
case .asset, .contextResult:
|
||||
controller.dismiss(animated: true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
case let .peer(peerId, _):
|
||||
let _ = (strongSelf.context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: wallpaperValue)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
dismissControllers()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
self?.push(controller)
|
||||
@ -182,21 +147,14 @@ public final class ThemeGridController: ViewController {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: strongSelf.mode.galleryMode)
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset))
|
||||
controller.apply = { [weak self, weak controller] wallpaper, options, cropRect in
|
||||
if let strongSelf = self, let controller = controller {
|
||||
switch strongSelf.mode {
|
||||
case .default:
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, completion: { [weak controller] in
|
||||
if let controller = controller {
|
||||
controller.dismiss(forceAway: true)
|
||||
}
|
||||
})
|
||||
case let .peer(peerId, _):
|
||||
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, peerId: peerId, completion: {
|
||||
dismissControllers()
|
||||
})
|
||||
}
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, completion: { [weak controller] in
|
||||
if let controller = controller {
|
||||
controller.dismiss(forceAway: true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
|
@ -141,7 +141,6 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
|
||||
private let context: AccountContext
|
||||
private var presentationData: PresentationData
|
||||
private let mode: ThemeGridController.Mode
|
||||
private var controllerInteraction: ThemeGridControllerInteraction?
|
||||
|
||||
private let presentPreviewController: (WallpaperListSource) -> Void
|
||||
@ -193,9 +192,8 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
|
||||
private var disposable: Disposable?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, mode: ThemeGridController.Mode, presentPreviewController: @escaping (WallpaperListSource) -> Void, presentGallery: @escaping () -> Void, presentColors: @escaping () -> Void, emptyStateUpdated: @escaping (Bool) -> Void, deleteWallpapers: @escaping ([TelegramWallpaper], @escaping () -> Void) -> Void, shareWallpapers: @escaping ([TelegramWallpaper]) -> Void, resetWallpapers: @escaping () -> Void, popViewController: @escaping () -> Void) {
|
||||
init(context: AccountContext, presentationData: PresentationData, presentPreviewController: @escaping (WallpaperListSource) -> Void, presentGallery: @escaping () -> Void, presentColors: @escaping () -> Void, emptyStateUpdated: @escaping (Bool) -> Void, deleteWallpapers: @escaping ([TelegramWallpaper], @escaping () -> Void) -> Void, shareWallpapers: @escaping ([TelegramWallpaper]) -> Void, resetWallpapers: @escaping () -> Void, popViewController: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.presentationData = presentationData
|
||||
self.presentPreviewController = presentPreviewController
|
||||
self.presentGallery = presentGallery
|
||||
@ -265,6 +263,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
self.gridNode.addSubnode(self.descriptionItemNode)
|
||||
self.gridNode.addSubnode(self.resetItemNode)
|
||||
self.gridNode.addSubnode(self.resetDescriptionItemNode)
|
||||
|
||||
self.addSubnode(self.gridNode)
|
||||
|
||||
let previousEntries = Atomic<[ThemeGridControllerEntry]?>(value: nil)
|
||||
@ -340,19 +339,13 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
})
|
||||
self.controllerInteraction = interaction
|
||||
|
||||
var selectFirst = true
|
||||
if case .peer = self.mode {
|
||||
selectFirst = false
|
||||
}
|
||||
|
||||
let transition = combineLatest(self.wallpapersPromise.get(), deletedWallpaperIdsPromise.get(), context.sharedContext.presentationData)
|
||||
|> map { wallpapers, deletedWallpaperIds, presentationData -> (ThemeGridEntryTransition, Bool) in
|
||||
var entries: [ThemeGridControllerEntry] = []
|
||||
var index = 1
|
||||
var index: Int = 0
|
||||
|
||||
if selectFirst {
|
||||
entries.insert(ThemeGridControllerEntry(index: 0, wallpaper: presentationData.chatWallpaper, isEditable: false, isSelected: true), at: 0)
|
||||
}
|
||||
entries.insert(ThemeGridControllerEntry(index: 0, wallpaper: presentationData.chatWallpaper, isEditable: false, isSelected: true), at: 0)
|
||||
index += 1
|
||||
|
||||
var defaultWallpaper: TelegramWallpaper?
|
||||
if !presentationData.chatWallpaper.isBasicallyEqual(to: presentationData.theme.chat.defaultWallpaper) {
|
||||
@ -422,10 +415,6 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
/*if !entries.isEmpty {
|
||||
entries = [entries[0]]
|
||||
}*/
|
||||
|
||||
let previous = previousEntries.swap(entries)
|
||||
return (preparedThemeGridEntryTransition(context: context, from: previous ?? [], to: entries, interaction: interaction), previous == nil)
|
||||
}
|
||||
@ -757,6 +746,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
|
||||
let makeResetDescriptionLayout = self.resetDescriptionItemNode.asyncLayout()
|
||||
let (resetDescriptionLayout, _) = makeResetDescriptionLayout(self.resetDescriptionItem, params, ItemListNeighbors(top: .none, bottom: .none))
|
||||
|
||||
insets.bottom += buttonHeight + 35.0 + resetDescriptionLayout.contentSize.height + 32.0
|
||||
|
||||
self.gridNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
||||
|
@ -167,7 +167,7 @@ private func updatedFileWallpaper(id: Int64? = nil, accessHash: Int64? = nil, sl
|
||||
public class WallpaperGalleryController: ViewController {
|
||||
public enum Mode {
|
||||
case `default`
|
||||
case peer(EnginePeer.Id)
|
||||
case peer(EnginePeer, Bool)
|
||||
}
|
||||
private var galleryNode: GalleryControllerNode {
|
||||
return self.displayNode as! GalleryControllerNode
|
||||
@ -350,7 +350,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
var i: Int = 0
|
||||
var updateItems: [GalleryPagerUpdateItem] = []
|
||||
for entry in entries {
|
||||
let item = GalleryPagerUpdateItem(index: i, previousIndex: i, item: WallpaperGalleryItem(context: self.context, index: updateItems.count, entry: entry, arguments: arguments, source: self.source))
|
||||
let item = GalleryPagerUpdateItem(index: i, previousIndex: i, item: WallpaperGalleryItem(context: self.context, index: updateItems.count, entry: entry, arguments: arguments, source: self.source, mode: self.mode))
|
||||
updateItems.append(item)
|
||||
i += 1
|
||||
}
|
||||
@ -361,7 +361,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
var updateItems: [GalleryPagerUpdateItem] = []
|
||||
for i in 0 ..< self.entries.count {
|
||||
if i == index {
|
||||
let item = GalleryPagerUpdateItem(index: index, previousIndex: index, item: WallpaperGalleryItem(context: self.context, index: index, entry: entry, arguments: arguments, source: self.source))
|
||||
let item = GalleryPagerUpdateItem(index: index, previousIndex: index, item: WallpaperGalleryItem(context: self.context, index: index, entry: entry, arguments: arguments, source: self.source, mode: self.mode))
|
||||
updateItems.append(item)
|
||||
}
|
||||
}
|
||||
@ -457,7 +457,6 @@ public class WallpaperGalleryController: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
switch entry {
|
||||
case let .wallpaper(wallpaper, _):
|
||||
var resource: MediaResource?
|
||||
@ -496,7 +495,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
}
|
||||
return current.withUpdatedThemeSpecificChatWallpapers(themeSpecificChatWallpapers)
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
self?.dismiss(forceAway: true)
|
||||
self?.dismiss(animated: true)
|
||||
})
|
||||
|
||||
switch strongSelf.source {
|
||||
@ -955,7 +954,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
colors = true
|
||||
}
|
||||
|
||||
self.galleryNode.pager.replaceItems(zip(0 ..< self.entries.count, self.entries).map({ WallpaperGalleryItem(context: self.context, index: $0, entry: $1, arguments: WallpaperGalleryItemArguments(isColorsList: colors), source: self.source) }), centralItemIndex: self.centralEntryIndex)
|
||||
self.galleryNode.pager.replaceItems(zip(0 ..< self.entries.count, self.entries).map({ WallpaperGalleryItem(context: self.context, index: $0, entry: $1, arguments: WallpaperGalleryItemArguments(isColorsList: colors), source: self.source, mode: self.mode) }), centralItemIndex: self.centralEntryIndex)
|
||||
|
||||
if let initialOptions = self.initialOptions, let itemNode = self.galleryNode.pager.centralItemNode() as? WallpaperGalleryItemNode {
|
||||
itemNode.options = initialOptions
|
||||
|
@ -18,6 +18,7 @@ import LocalMediaResources
|
||||
import WallpaperResources
|
||||
import AppBundle
|
||||
import WallpaperBackgroundNode
|
||||
import TextFormat
|
||||
|
||||
struct WallpaperGalleryItemArguments {
|
||||
let colorPreview: Bool
|
||||
@ -42,24 +43,26 @@ class WallpaperGalleryItem: GalleryItem {
|
||||
let entry: WallpaperGalleryEntry
|
||||
let arguments: WallpaperGalleryItemArguments
|
||||
let source: WallpaperListSource
|
||||
let mode: WallpaperGalleryController.Mode
|
||||
|
||||
init(context: AccountContext, index: Int, entry: WallpaperGalleryEntry, arguments: WallpaperGalleryItemArguments, source: WallpaperListSource) {
|
||||
init(context: AccountContext, index: Int, entry: WallpaperGalleryEntry, arguments: WallpaperGalleryItemArguments, source: WallpaperListSource, mode: WallpaperGalleryController.Mode) {
|
||||
self.context = context
|
||||
self.index = index
|
||||
self.entry = entry
|
||||
self.arguments = arguments
|
||||
self.source = source
|
||||
self.mode = mode
|
||||
}
|
||||
|
||||
func node(synchronous: Bool) -> GalleryItemNode {
|
||||
let node = WallpaperGalleryItemNode(context: self.context)
|
||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source, mode: self.mode)
|
||||
return node
|
||||
}
|
||||
|
||||
func updateNode(node: GalleryItemNode, synchronous: Bool) {
|
||||
if let node = node as? WallpaperGalleryItemNode {
|
||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source)
|
||||
node.setEntry(self.entry, arguments: self.arguments, source: self.source, mode: self.mode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,6 +87,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
var entry: WallpaperGalleryEntry?
|
||||
var source: WallpaperListSource?
|
||||
var mode: WallpaperGalleryController.Mode?
|
||||
private var colorPreview: Bool = false
|
||||
private var contentSize: CGSize?
|
||||
private var arguments = WallpaperGalleryItemArguments()
|
||||
@ -263,10 +267,11 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
func setEntry(_ entry: WallpaperGalleryEntry, arguments: WallpaperGalleryItemArguments, source: WallpaperListSource) {
|
||||
func setEntry(_ entry: WallpaperGalleryEntry, arguments: WallpaperGalleryItemArguments, source: WallpaperListSource, mode: WallpaperGalleryController.Mode) {
|
||||
let previousArguments = self.arguments
|
||||
self.arguments = arguments
|
||||
self.source = source
|
||||
self.mode = mode
|
||||
|
||||
if self.arguments.colorPreview != previousArguments.colorPreview {
|
||||
if self.arguments.colorPreview {
|
||||
@ -1063,6 +1068,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
var topMessageText = ""
|
||||
var bottomMessageText = ""
|
||||
var serviceMessageText: String?
|
||||
var currentWallpaper: TelegramWallpaper = self.presentationData.chatWallpaper
|
||||
if let entry = self.entry, case let .wallpaper(wallpaper, _) = entry {
|
||||
currentWallpaper = wallpaper
|
||||
@ -1125,6 +1131,14 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let mode = self.mode, case let .peer(peer, existing) = mode {
|
||||
topMessageText = presentationData.strings.WallpaperPreview_ChatTopText
|
||||
bottomMessageText = presentationData.strings.WallpaperPreview_ChatBottomText
|
||||
if !existing {
|
||||
serviceMessageText = presentationData.strings.WallpaperPreview_NotAppliedInfo(peer.compactDisplayTitle).string
|
||||
}
|
||||
}
|
||||
|
||||
let theme = self.presentationData.theme.withUpdated(preview: true)
|
||||
|
||||
let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||
@ -1133,6 +1147,14 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, isCentered: false))
|
||||
|
||||
if let serviceMessageText {
|
||||
let attributedText = convertMarkdownToAttributes(NSAttributedString(string: serviceMessageText))
|
||||
let entities = generateChatInputTextEntities(attributedText)
|
||||
|
||||
let message3 = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: attributedText.string, entities: entities))], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, isCentered: false))
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
if self.validMessages != [topMessageText, bottomMessageText] {
|
||||
|
@ -350,7 +350,11 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
|
||||
let otherUsernames = peer.usernames.filter { !$0.flags.contains(.isEditable) }
|
||||
if case .bot = mode {
|
||||
entries.append(.publicLinkInfo(presentationData.theme, "This username cannot be edited."))
|
||||
var infoText = presentationData.strings.Username_BotLinkHint
|
||||
if otherUsernames.isEmpty {
|
||||
infoText = presentationData.strings.Username_BotLinkHintExtended
|
||||
}
|
||||
entries.append(.publicLinkInfo(presentationData.theme, infoText))
|
||||
} else {
|
||||
var infoText = presentationData.strings.Username_Help
|
||||
if otherUsernames.isEmpty {
|
||||
@ -460,21 +464,25 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
var currentAddressName: String = peer.addressName ?? ""
|
||||
updateState { state in
|
||||
if let current = state.editingPublicLinkText {
|
||||
currentAddressName = current
|
||||
if let user = peer as? TelegramUser, user.botInfo != nil {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: "https://fragment.com/", forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
|
||||
} else {
|
||||
var currentAddressName: String = peer.addressName ?? ""
|
||||
updateState { state in
|
||||
if let current = state.editingPublicLinkText {
|
||||
currentAddressName = current
|
||||
}
|
||||
return state
|
||||
}
|
||||
return state
|
||||
}
|
||||
if !currentAddressName.isEmpty {
|
||||
dismissInputImpl?()
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/\(currentAddressName)"))
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
if !currentAddressName.isEmpty {
|
||||
dismissInputImpl?()
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/\(currentAddressName)"))
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
presentControllerImpl?(shareController, nil)
|
||||
}
|
||||
presentControllerImpl?(shareController, nil)
|
||||
}
|
||||
})
|
||||
}, activateLink: { name in
|
||||
|
@ -160,7 +160,6 @@ private final class BadgeNode: ASDisplayNode {
|
||||
|
||||
public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
private var theme: SolidRoundedButtonTheme
|
||||
private var font: SolidRoundedButtonFont
|
||||
private var fontSize: CGFloat
|
||||
private let gloss: Bool
|
||||
|
||||
@ -204,6 +203,14 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public var font: SolidRoundedButtonFont {
|
||||
didSet {
|
||||
if let width = self.validLayout {
|
||||
_ = self.updateLayout(width: width, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var subtitle: String? {
|
||||
didSet {
|
||||
self.updateAccessibilityLabels()
|
||||
|
@ -111,7 +111,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
case let .messageActionSetChatWallPaper(wallpaper):
|
||||
return TelegramMediaAction(action: .setChatWallpaper(wallpaper: TelegramWallpaper(apiWallpaper: wallpaper)))
|
||||
case .messageActionSetSameChatWallPaper:
|
||||
return nil
|
||||
return TelegramMediaAction(action: .setSameChatWallpaper)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,8 @@ func _internal_setChatWallpaper(account: Account, peerId: PeerId, wallpaper: Tel
|
||||
inputSettings = inputWallpaperAndInputSettings.1
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.messages.setChatWallPaper(flags: 0, peer: inputPeer, wallpaper: inputWallpaper ?? .inputWallPaperNoFile(id: 0), settings: inputSettings ?? apiWallpaperSettings(WallpaperSettings()), id: nil))
|
||||
let flags: Int32 = 1 << 0
|
||||
return account.network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: inputWallpaper ?? .inputWallPaperNoFile(id: 0), settings: inputSettings ?? apiWallpaperSettings(WallpaperSettings()), id: nil))
|
||||
|> `catch` { error in
|
||||
return .complete()
|
||||
}
|
||||
@ -159,7 +160,20 @@ public enum SetExistingChatWallpaperError {
|
||||
|
||||
func _internal_setExistingChatWallpaper(account: Account, messageId: MessageId) -> Signal<Void, SetExistingChatWallpaperError> {
|
||||
return account.postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(messageId.peerId)
|
||||
if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) {
|
||||
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction, case let .setChatWallpaper(wallpaper) = action.action {
|
||||
transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in
|
||||
if let current = current as? CachedUserData {
|
||||
return current.withUpdatedWallpaper(wallpaper)
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
})
|
||||
}
|
||||
return peer
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> castError(SetExistingChatWallpaperError.self)
|
||||
|> mapToSignal { peer -> Signal<Void, SetExistingChatWallpaperError> in
|
||||
|
@ -1603,7 +1603,11 @@ public final class PresentationTheme: Equatable {
|
||||
}
|
||||
|
||||
public func withModalBlocksBackground() -> PresentationTheme {
|
||||
let list = self.list.withUpdated(blocksBackgroundColor: self.list.modalBlocksBackgroundColor, itemBlocksBackgroundColor: self.list.itemModalBlocksBackgroundColor)
|
||||
return PresentationTheme(name: self.name, index: self.index, referenceTheme: self.referenceTheme, overallDarkAppearance: self.overallDarkAppearance, intro: self.intro, passcode: self.passcode, rootController: self.rootController, list: list, chatList: self.chatList, chat: self.chat, actionSheet: self.actionSheet, contextMenu: self.contextMenu, inAppNotification: self.inAppNotification, chart: self.chart, preview: self.preview)
|
||||
if self.list.blocksBackgroundColor.rgb == self.list.plainBackgroundColor.rgb {
|
||||
let list = self.list.withUpdated(blocksBackgroundColor: self.list.modalBlocksBackgroundColor, itemBlocksBackgroundColor: self.list.itemModalBlocksBackgroundColor)
|
||||
return PresentationTheme(name: self.name, index: self.index, referenceTheme: self.referenceTheme, overallDarkAppearance: self.overallDarkAppearance, intro: self.intro, passcode: self.passcode, rootController: self.rootController, list: list, chatList: self.chatList, chat: self.chat, actionSheet: self.actionSheet, contextMenu: self.contextMenu, inAppNotification: self.inAppNotification, chart: self.chart, preview: self.preview)
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1029,25 +1029,52 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let resultSignal = signal
|
||||
|> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||
let resultSignal = combineLatest(
|
||||
signal,
|
||||
hasPremium
|
||||
)
|
||||
|> mapToSignal { keywords, hasPremium -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||
var allEmoticons: [String: String] = [:]
|
||||
for keyword in keywords {
|
||||
for emoticon in keyword.emoticons {
|
||||
allEmoticons[emoticon] = keyword.keyword
|
||||
}
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
hasPremium,
|
||||
context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys))
|
||||
)
|
||||
|> mapToSignal { hasPremium, foundEmoji -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||
let remoteSignal: Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError>
|
||||
if hasPremium {
|
||||
remoteSignal = context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys))
|
||||
} else {
|
||||
remoteSignal = .single(([], true))
|
||||
}
|
||||
return remoteSignal
|
||||
|> mapToSignal { foundEmoji -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||
if foundEmoji.items.isEmpty && !foundEmoji.isFinalResult {
|
||||
return .complete()
|
||||
}
|
||||
var items: [EmojiPagerContentComponent.Item] = []
|
||||
|
||||
let appendUnicodeEmoji = {
|
||||
for (_, list) in EmojiPagerContentComponent.staticEmojiMapping {
|
||||
for emojiString in list {
|
||||
if allEmoticons[emojiString] != nil {
|
||||
let item = EmojiPagerContentComponent.Item(
|
||||
animationData: nil,
|
||||
content: .staticEmoji(emojiString),
|
||||
itemFile: nil,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
tintMode: .none
|
||||
)
|
||||
items.append(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !hasPremium {
|
||||
appendUnicodeEmoji()
|
||||
}
|
||||
|
||||
var existingIds = Set<MediaId>()
|
||||
for itemFile in foundEmoji.items {
|
||||
if existingIds.contains(itemFile.fileId) {
|
||||
@ -1061,12 +1088,17 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
let item = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
content: .animation(animationData),
|
||||
itemFile: itemFile, subgroupId: nil,
|
||||
itemFile: itemFile,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
tintMode: animationData.isTemplate ? .primary : .none
|
||||
)
|
||||
items.append(item)
|
||||
}
|
||||
|
||||
if hasPremium {
|
||||
appendUnicodeEmoji()
|
||||
}
|
||||
|
||||
return .single([EmojiPagerContentComponent.ItemGroup(
|
||||
supergroupId: "search",
|
||||
|
@ -29,26 +29,6 @@ private let premiumBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bund
|
||||
private let featuredBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PanelBadgeAdd"), color: .white)
|
||||
private let lockedBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PanelBadgeLock"), color: .white)
|
||||
|
||||
private let staticEmojiMapping: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = {
|
||||
guard let path = getAppBundle().path(forResource: "emoji1016", ofType: "txt") else {
|
||||
return []
|
||||
}
|
||||
guard let string = try? String(contentsOf: URL(fileURLWithPath: path)) else {
|
||||
return []
|
||||
}
|
||||
|
||||
var result: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = []
|
||||
|
||||
let orderedSegments = EmojiPagerContentComponent.StaticEmojiSegment.allCases
|
||||
|
||||
let segments = string.components(separatedBy: "\n\n")
|
||||
for i in 0 ..< min(segments.count, orderedSegments.count) {
|
||||
let list = segments[i].components(separatedBy: " ")
|
||||
result.append((orderedSegments[i], list))
|
||||
}
|
||||
|
||||
return result
|
||||
}()
|
||||
|
||||
private final class WarpView: UIView {
|
||||
private final class WarpPartView: UIView {
|
||||
@ -2226,6 +2206,27 @@ public protocol EmojiContentPeekBehavior: AnyObject {
|
||||
}
|
||||
|
||||
public final class EmojiPagerContentComponent: Component {
|
||||
public static let staticEmojiMapping: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = {
|
||||
guard let path = getAppBundle().path(forResource: "emoji1016", ofType: "txt") else {
|
||||
return []
|
||||
}
|
||||
guard let string = try? String(contentsOf: URL(fileURLWithPath: path)) else {
|
||||
return []
|
||||
}
|
||||
|
||||
var result: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = []
|
||||
|
||||
let orderedSegments = EmojiPagerContentComponent.StaticEmojiSegment.allCases
|
||||
|
||||
let segments = string.components(separatedBy: "\n\n")
|
||||
for i in 0 ..< min(segments.count, orderedSegments.count) {
|
||||
let list = segments[i].components(separatedBy: " ")
|
||||
result.append((orderedSegments[i], list))
|
||||
}
|
||||
|
||||
return result
|
||||
}()
|
||||
|
||||
public typealias EnvironmentType = (EntityKeyboardChildEnvironment, PagerComponentChildEnvironment)
|
||||
|
||||
public final class ContentAnimation {
|
||||
|
@ -273,10 +273,9 @@ func attachmentFileController(context: AccountContext, updatedPresentationData:
|
||||
)
|
||||
|> map { presentationData, recentDocuments, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var presentationData = presentationData
|
||||
if presentationData.theme.list.blocksBackgroundColor.rgb == presentationData.theme.list.plainBackgroundColor.rgb {
|
||||
let updatedTheme = presentationData.theme.withModalBlocksBackground()
|
||||
presentationData = presentationData.withUpdated(theme: updatedTheme)
|
||||
}
|
||||
|
||||
let updatedTheme = presentationData.theme.withModalBlocksBackground()
|
||||
presentationData = presentationData.withUpdated(theme: updatedTheme)
|
||||
|
||||
let previousRecentDocuments = previousRecentDocuments.swap(recentDocuments)
|
||||
let crossfade = previousRecentDocuments == nil && recentDocuments != nil
|
||||
|
@ -839,10 +839,26 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.presentThemeSelection()
|
||||
return true
|
||||
case let .setChatWallpaper(wallpaper):
|
||||
guard message.effectivelyIncoming(strongSelf.context.account.peerId), let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
|
||||
return true
|
||||
}
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
let wallpaperPreviewController = WallpaperGalleryController(context: strongSelf.context, source: .wallpaper(wallpaper, nil, [], nil, nil, nil))
|
||||
let wallpaperPreviewController = WallpaperGalleryController(context: strongSelf.context, source: .wallpaper(wallpaper, nil, [], nil, nil, nil), mode: .peer(EnginePeer(peer), true))
|
||||
wallpaperPreviewController.apply = { wallpaper, options, _ in
|
||||
let _ = (strongSelf.context.engine.themes.setExistingChatWallpaper(messageId: message.id)
|
||||
|> deliverOnMainQueue).start(completed: { [weak wallpaperPreviewController] in
|
||||
wallpaperPreviewController?.dismiss()
|
||||
})
|
||||
}
|
||||
strongSelf.push(wallpaperPreviewController)
|
||||
return true
|
||||
case .setSameChatWallpaper:
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? ReplyMessageAttribute {
|
||||
strongSelf.controllerInteraction?.navigateToMessage(message.id, attribute.messageId)
|
||||
return true
|
||||
}
|
||||
}
|
||||
case let .giftPremium(_, _, duration, _, _):
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
let fromPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? strongSelf.context.account.peerId : message.id.peerId
|
||||
@ -16928,7 +16944,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
Queue.mainQueue().async {
|
||||
unblockingPeer.set(false)
|
||||
if let strongSelf = self, restartBot {
|
||||
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: [.message(text: "/start", attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]).start()
|
||||
strongSelf.startBot(strongSelf.presentationInterfaceState.botStartPayload)
|
||||
}
|
||||
}
|
||||
})).start())
|
||||
@ -18464,10 +18480,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
let _ = (combineLatest(queue: Queue.mainQueue(), self.chatThemeEmoticonPromise.get(), animatedEmojiStickers)
|
||||
|> take(1)).start(next: { [weak self] themeEmoticon, animatedEmojiStickers in
|
||||
guard let strongSelf = self else {
|
||||
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
let selectedEmoticon: String? = themeEmoticon
|
||||
|
||||
let controller = ChatThemeScreen(
|
||||
@ -18489,8 +18506,47 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let themeController = strongSelf.themeScreen {
|
||||
strongSelf.themeScreen = nil
|
||||
themeController.dimTapped()
|
||||
}
|
||||
let dismissControllers = { [weak self] in
|
||||
if let self, let navigationController = self.navigationController as? NavigationController {
|
||||
let controllers = navigationController.viewControllers.filter({ controller in
|
||||
if controller is WallpaperGalleryController || controller is MediaPickerScreen {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
let controller = ThemeGridController(context: strongSelf.context, mode: .peer(peerId, strongSelf.presentationData.chatWallpaper))
|
||||
|
||||
let controller = MediaPickerScreen(context: strongSelf.context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, true))
|
||||
controller.navigationPresentation = .modal
|
||||
controller.customSelection = { [weak self] asset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: .peer(EnginePeer(peer), false))
|
||||
controller.navigationPresentation = .modal
|
||||
controller.apply = { [weak self] wallpaper, options, cropRect in
|
||||
if let strongSelf = self {
|
||||
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, peerId: peerId, completion: {
|
||||
dismissControllers()
|
||||
})
|
||||
}
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
},
|
||||
changeColor: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let themeController = strongSelf.themeScreen {
|
||||
strongSelf.themeScreen = nil
|
||||
themeController.dimTapped()
|
||||
}
|
||||
let controller = ThemeColorsGridController(context: context, mode: .peer(EnginePeer(peer)))
|
||||
controller.navigationPresentation = .modal
|
||||
strongSelf.push(controller)
|
||||
},
|
||||
|
@ -187,7 +187,7 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Notification_Wallpaper_View, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let backgroundSize = CGSize(width: width, height: subtitleLayout.size.height + 145.0 + (fromYou ? 0.0 : 37.0))
|
||||
let backgroundSize = CGSize(width: width, height: subtitleLayout.size.height + 140.0 + (fromYou ? 0.0 : 42.0))
|
||||
|
||||
return (backgroundSize.width, { boundingWidth in
|
||||
return (backgroundSize, { [weak self] animation, synchronousLoads, _ in
|
||||
|
@ -1394,8 +1394,10 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
if case .scheduledMessages = interfaceState.subject {
|
||||
|
||||
} else {
|
||||
if let chatHistoryState = interfaceState.chatHistoryState, case .loaded(true) = chatHistoryState {
|
||||
if let user = interfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
|
||||
if let user = interfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
|
||||
if let chatHistoryState = interfaceState.chatHistoryState, case .loaded(true) = chatHistoryState {
|
||||
displayBotStartButton = true
|
||||
} else if interfaceState.peerIsBlocked {
|
||||
displayBotStartButton = true
|
||||
}
|
||||
}
|
||||
|
@ -556,6 +556,7 @@ final class ChatThemeScreen: ViewController {
|
||||
private let peerName: String
|
||||
private let previewTheme: (String?, Bool?) -> Void
|
||||
fileprivate let changeWallpaper: () -> Void
|
||||
fileprivate let changeColor: () -> Void
|
||||
private let completion: (String?) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
@ -579,6 +580,7 @@ final class ChatThemeScreen: ViewController {
|
||||
peerName: String,
|
||||
previewTheme: @escaping (String?, Bool?) -> Void,
|
||||
changeWallpaper: @escaping () -> Void,
|
||||
changeColor: @escaping () -> Void,
|
||||
completion: @escaping (String?) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
@ -588,6 +590,7 @@ final class ChatThemeScreen: ViewController {
|
||||
self.peerName = peerName
|
||||
self.previewTheme = previewTheme
|
||||
self.changeWallpaper = changeWallpaper
|
||||
self.changeColor = changeColor
|
||||
self.completion = completion
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
@ -714,6 +717,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
private let wrappingScrollNode: ASScrollNode
|
||||
private let contentContainerNode: ASDisplayNode
|
||||
private let topContentContainerNode: SparseNode
|
||||
private let buttonsContentContainerNode: SparseNode
|
||||
private let effectNode: ASDisplayNode
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let contentBackgroundNode: ASDisplayNode
|
||||
@ -724,7 +728,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
private let animationContainerNode: ASDisplayNode
|
||||
private var animationNode: AnimationNode
|
||||
private let doneButton: SolidRoundedButtonNode
|
||||
private let wallpaperButton: HighlightableButtonNode
|
||||
private let colorButton: HighlightableButtonNode
|
||||
|
||||
private let listNode: ListView
|
||||
private var entries: [ThemeSettingsThemeEntry]?
|
||||
@ -781,6 +785,9 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.topContentContainerNode = SparseNode()
|
||||
self.topContentContainerNode.isOpaque = false
|
||||
|
||||
self.buttonsContentContainerNode = SparseNode()
|
||||
self.buttonsContentContainerNode.isOpaque = false
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.clipsToBounds = true
|
||||
self.backgroundNode.cornerRadius = 16.0
|
||||
@ -817,10 +824,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.animationNode.isUserInteractionEnabled = false
|
||||
|
||||
self.doneButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: self.presentationData.theme), height: 52.0, cornerRadius: 11.0, gloss: false)
|
||||
self.doneButton.title = initiallySelectedEmoticon == nil ? self.presentationData.strings.Conversation_Theme_DontSetTheme : self.presentationData.strings.Conversation_Theme_Apply
|
||||
|
||||
self.wallpaperButton = HighlightableButtonNode()
|
||||
self.wallpaperButton.setTitle("Set Background from Gallery", with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
self.colorButton = HighlightableButtonNode()
|
||||
|
||||
self.listNode = ListView()
|
||||
self.listNode.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
@ -830,6 +835,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.backgroundColor = nil
|
||||
self.isOpaque = false
|
||||
|
||||
self.updateButtons()
|
||||
|
||||
self.addSubnode(self.dimNode)
|
||||
|
||||
self.wrappingScrollNode.view.delegate = self
|
||||
@ -838,13 +845,14 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.wrappingScrollNode.addSubnode(self.backgroundNode)
|
||||
self.wrappingScrollNode.addSubnode(self.contentContainerNode)
|
||||
self.wrappingScrollNode.addSubnode(self.topContentContainerNode)
|
||||
self.wrappingScrollNode.addSubnode(self.buttonsContentContainerNode)
|
||||
|
||||
self.backgroundNode.addSubnode(self.effectNode)
|
||||
self.backgroundNode.addSubnode(self.contentBackgroundNode)
|
||||
self.contentContainerNode.addSubnode(self.titleNode)
|
||||
self.contentContainerNode.addSubnode(self.textNode)
|
||||
self.contentContainerNode.addSubnode(self.doneButton)
|
||||
self.contentContainerNode.addSubnode(self.wallpaperButton)
|
||||
self.buttonsContentContainerNode.addSubnode(self.doneButton)
|
||||
self.buttonsContentContainerNode.addSubnode(self.colorButton)
|
||||
|
||||
self.topContentContainerNode.addSubnode(self.animationContainerNode)
|
||||
self.animationContainerNode.addSubnode(self.animationNode)
|
||||
@ -860,7 +868,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
strongSelf.completion?(strongSelf.selectedEmoticon)
|
||||
}
|
||||
}
|
||||
self.wallpaperButton.addTarget(self, action: #selector(self.wallpaperButtonPressed), forControlEvents: .touchUpInside)
|
||||
self.colorButton.addTarget(self, action: #selector(self.colorButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
self.disposable.set(combineLatest(queue: Queue.mainQueue(), self.context.engine.themes.getChatThemes(accountManager: self.context.sharedContext.accountManager), self.selectedEmoticonPromise.get(), self.isDarkAppearancePromise.get()).start(next: { [weak self] themes, selectedEmoticon, isDarkAppearance in
|
||||
guard let strongSelf = self else {
|
||||
@ -881,24 +889,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
|
||||
let action: (String?) -> Void = { [weak self] emoticon in
|
||||
if let strongSelf = self, strongSelf.selectedEmoticon != emoticon {
|
||||
strongSelf.animateCrossfade(animateIcon: true)
|
||||
|
||||
strongSelf.previewTheme?(emoticon, strongSelf.isDarkAppearance)
|
||||
strongSelf.selectedEmoticon = emoticon
|
||||
let _ = ensureThemeVisible(listNode: strongSelf.listNode, emoticon: emoticon, animated: true)
|
||||
|
||||
let doneButtonTitle: String
|
||||
if emoticon == nil {
|
||||
doneButtonTitle = strongSelf.initiallySelectedEmoticon == nil ? strongSelf.presentationData.strings.Conversation_Theme_DontSetTheme : strongSelf.presentationData.strings.Conversation_Theme_Reset
|
||||
} else {
|
||||
doneButtonTitle = strongSelf.presentationData.strings.Conversation_Theme_Apply
|
||||
}
|
||||
strongSelf.doneButton.title = doneButtonTitle
|
||||
|
||||
strongSelf.themeSelectionsCount += 1
|
||||
if strongSelf.themeSelectionsCount == 2 {
|
||||
strongSelf.maybePresentPreviewTooltip()
|
||||
}
|
||||
strongSelf.setEmoticon(emoticon)
|
||||
}
|
||||
}
|
||||
let previousEntries = strongSelf.entries ?? []
|
||||
@ -987,6 +978,51 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
})
|
||||
}
|
||||
|
||||
private func setEmoticon(_ emoticon: String?) {
|
||||
self.animateCrossfade(animateIcon: true)
|
||||
|
||||
self.previewTheme?(emoticon, self.isDarkAppearance)
|
||||
self.selectedEmoticon = emoticon
|
||||
let _ = ensureThemeVisible(listNode: self.listNode, emoticon: emoticon, animated: true)
|
||||
|
||||
self.updateButtons()
|
||||
|
||||
self.themeSelectionsCount += 1
|
||||
if self.themeSelectionsCount == 2 {
|
||||
self.maybePresentPreviewTooltip()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateButtons() {
|
||||
let doneButtonTitle: String
|
||||
let otherButtonTitle: String
|
||||
var accentButtonTheme = true
|
||||
if self.selectedEmoticon == self.initiallySelectedEmoticon {
|
||||
doneButtonTitle = self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper
|
||||
otherButtonTitle = self.presentationData.strings.Conversation_Theme_SetColorWallpaper
|
||||
accentButtonTheme = false
|
||||
} else if self.selectedEmoticon == nil && self.initiallySelectedEmoticon != nil {
|
||||
doneButtonTitle = self.presentationData.strings.Conversation_Theme_Reset
|
||||
otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions
|
||||
} else {
|
||||
doneButtonTitle = self.presentationData.strings.Conversation_Theme_Apply
|
||||
otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions
|
||||
}
|
||||
|
||||
let buttonTheme: SolidRoundedButtonTheme
|
||||
if accentButtonTheme {
|
||||
buttonTheme = SolidRoundedButtonTheme(theme: self.presentationData.theme)
|
||||
} else {
|
||||
buttonTheme = SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.actionSheet.itemBackgroundColor, foregroundColor: self.presentationData.theme.actionSheet.controlAccentColor)
|
||||
}
|
||||
self.doneButton.title = doneButtonTitle
|
||||
self.doneButton.font = accentButtonTheme ? .bold : .regular
|
||||
self.doneButton.updateTheme(buttonTheme)
|
||||
|
||||
|
||||
self.colorButton.setTitle(otherButtonTitle, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
guard !self.animatedOut else {
|
||||
return
|
||||
@ -1003,6 +1039,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
|
||||
self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal)
|
||||
self.doneButton.updateTheme(SolidRoundedButtonTheme(theme: self.presentationData.theme))
|
||||
self.updateButtons()
|
||||
|
||||
if self.animationNode.isPlaying {
|
||||
if let animationNode = self.animationNode.makeCopy(colors: iconColors(theme: self.presentationData.theme), progress: 0.2) {
|
||||
@ -1037,8 +1074,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.cancel?()
|
||||
}
|
||||
|
||||
@objc func wallpaperButtonPressed() {
|
||||
self.controller?.changeWallpaper()
|
||||
@objc func colorButtonPressed() {
|
||||
self.controller?.changeColor()
|
||||
}
|
||||
|
||||
func dimTapped() {
|
||||
@ -1258,11 +1295,12 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
let doneButtonHeight = self.doneButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
|
||||
transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - 50.0 - insets.bottom - 6.0, width: contentFrame.width, height: doneButtonHeight))
|
||||
|
||||
let wallpaperButtonSize = self.wallpaperButton.measure(CGSize(width: contentFrame.width - buttonInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
transition.updateFrame(node: self.wallpaperButton, frame: CGRect(origin: CGPoint(x: floor((contentFrame.width - wallpaperButtonSize.width) / 2.0), y: contentHeight - wallpaperButtonSize.height - insets.bottom - 6.0 - 9.0), size: wallpaperButtonSize))
|
||||
let colorButtonSize = self.colorButton.measure(CGSize(width: contentFrame.width - buttonInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
transition.updateFrame(node: self.colorButton, frame: CGRect(origin: CGPoint(x: floor((contentFrame.width - colorButtonSize.width) / 2.0), y: contentHeight - colorButtonSize.height - insets.bottom - 6.0 - 9.0), size: colorButtonSize))
|
||||
|
||||
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
||||
transition.updateFrame(node: self.topContentContainerNode, frame: contentContainerFrame)
|
||||
transition.updateFrame(node: self.buttonsContentContainerNode, frame: contentContainerFrame)
|
||||
|
||||
var listInsets = UIEdgeInsets()
|
||||
listInsets.top += layout.safeInsets.left + 12.0
|
||||
|
@ -398,7 +398,7 @@ private func fetchCachedBlurredWallpaperRepresentation(resource: MediaResource,
|
||||
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
if let colorImage = blurredImage(image, radius: 45.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary)
|
||||
|
||||
let colorQuality: Float = 0.5
|
||||
@ -447,7 +447,7 @@ private func fetchCachedBlurredWallpaperRepresentation(account: Account, resourc
|
||||
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
if let colorImage = blurredImage(image, radius: 45.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary)
|
||||
|
||||
let colorQuality: Float = 0.5
|
||||
|
@ -5,12 +5,18 @@ import TextFormat
|
||||
import Markdown
|
||||
|
||||
final class PeerInfoScreenCommentItem: PeerInfoScreenItem {
|
||||
enum LinkAction {
|
||||
case tap(String)
|
||||
}
|
||||
|
||||
let id: AnyHashable
|
||||
let text: String
|
||||
let linkAction: ((LinkAction) -> Void)?
|
||||
|
||||
init(id: AnyHashable, text: String) {
|
||||
init(id: AnyHashable, text: String, linkAction: ((LinkAction) -> Void)? = nil) {
|
||||
self.id = id
|
||||
self.text = text
|
||||
self.linkAction = linkAction
|
||||
}
|
||||
|
||||
func node() -> PeerInfoScreenItemNode {
|
||||
@ -20,9 +26,11 @@ final class PeerInfoScreenCommentItem: PeerInfoScreenItem {
|
||||
|
||||
private final class PeerInfoScreenCommentItemNode: PeerInfoScreenItemNode {
|
||||
private let textNode: ImmediateTextNode
|
||||
private var linkHighlightingNode: LinkHighlightingNode?
|
||||
private let activateArea: AccessibilityAreaNode
|
||||
|
||||
private var item: PeerInfoScreenCommentItem?
|
||||
private var presentationData: PresentationData?
|
||||
|
||||
override init() {
|
||||
self.textNode = ImmediateTextNode()
|
||||
@ -38,12 +46,28 @@ private final class PeerInfoScreenCommentItemNode: PeerInfoScreenItemNode {
|
||||
self.addSubnode(self.activateArea)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
||||
recognizer.tapActionAtPoint = { _ in
|
||||
return .waitForSingleTap
|
||||
}
|
||||
recognizer.highlight = { [weak self] point in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateTouchesAtPoint(point)
|
||||
}
|
||||
}
|
||||
self.view.addGestureRecognizer(recognizer)
|
||||
}
|
||||
|
||||
override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
guard let item = item as? PeerInfoScreenCommentItem else {
|
||||
return 10.0
|
||||
}
|
||||
|
||||
self.item = item
|
||||
self.presentationData = presentationData
|
||||
|
||||
let sideInset: CGFloat = 16.0 + safeInsets.left
|
||||
let verticalInset: CGFloat = 7.0
|
||||
@ -72,4 +96,69 @@ private final class PeerInfoScreenCommentItemNode: PeerInfoScreenItemNode {
|
||||
|
||||
return height
|
||||
}
|
||||
|
||||
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
switch gesture {
|
||||
case .tap:
|
||||
let titleFrame = self.textNode.frame
|
||||
if let item = self.item, titleFrame.contains(location) {
|
||||
if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) {
|
||||
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
item.linkAction?(.tap(url))
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func updateTouchesAtPoint(_ point: CGPoint?) {
|
||||
if let _ = self.item, let presentationData = self.presentationData {
|
||||
var rects: [CGRect]?
|
||||
if let point = point {
|
||||
let textNodeFrame = self.textNode.frame
|
||||
if let (index, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||
let possibleNames: [String] = [
|
||||
TelegramTextAttributes.URL,
|
||||
TelegramTextAttributes.PeerMention,
|
||||
TelegramTextAttributes.PeerTextMention,
|
||||
TelegramTextAttributes.BotCommand,
|
||||
TelegramTextAttributes.Hashtag
|
||||
]
|
||||
for name in possibleNames {
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: name)] {
|
||||
rects = self.textNode.attributeRects(name: name, at: index)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let rects = rects {
|
||||
let linkHighlightingNode: LinkHighlightingNode
|
||||
if let current = self.linkHighlightingNode {
|
||||
linkHighlightingNode = current
|
||||
} else {
|
||||
linkHighlightingNode = LinkHighlightingNode(color: presentationData.theme.list.itemAccentColor.withAlphaComponent(0.2))
|
||||
self.linkHighlightingNode = linkHighlightingNode
|
||||
self.insertSubnode(linkHighlightingNode, belowSubnode: self.textNode)
|
||||
}
|
||||
linkHighlightingNode.frame = self.textNode.frame
|
||||
linkHighlightingNode.updateRects(rects)
|
||||
} else if let linkHighlightingNode = self.linkHighlightingNode {
|
||||
self.linkHighlightingNode = nil
|
||||
linkHighlightingNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false, completion: { [weak linkHighlightingNode] _ in
|
||||
linkHighlightingNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1405,16 +1405,18 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
|
||||
interaction.editingOpenPublicLinkSetup()
|
||||
}))
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemIntro, text: "Edit Intro", icon: UIImage(bundleImageName: "Peer Info/BotIntro"), action: {
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemIntro, text: presentationData.strings.PeerInfo_Bot_EditIntro, icon: UIImage(bundleImageName: "Peer Info/BotIntro"), action: {
|
||||
interaction.openPeerMention("botfather", .withBotStartPayload(ChatControllerInitialBotStart(payload: "\(user.addressName ?? "")-intro", behavior: .interactive)))
|
||||
}))
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemCommands, text: "Edit Commands", icon: UIImage(bundleImageName: "Peer Info/BotCommands"), action: {
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemCommands, text: presentationData.strings.PeerInfo_Bot_EditCommands, icon: UIImage(bundleImageName: "Peer Info/BotCommands"), action: {
|
||||
interaction.openPeerMention("botfather", .withBotStartPayload(ChatControllerInitialBotStart(payload: "\(user.addressName ?? "")-commands", behavior: .interactive)))
|
||||
}))
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemBotSettings, text: "Change Bot Settings", icon: UIImage(bundleImageName: "Peer Info/BotSettings"), action: {
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemBotSettings, text: presentationData.strings.PeerInfo_Bot_ChangeSettings, icon: UIImage(bundleImageName: "Peer Info/BotSettings"), action: {
|
||||
interaction.openPeerMention("botfather", .withBotStartPayload(ChatControllerInitialBotStart(payload: user.addressName ?? "", behavior: .interactive)))
|
||||
}))
|
||||
items[.peerSettings]!.append(PeerInfoScreenCommentItem(id: ItemBotInfo, text: "Use [@BotFather]() to manage this bot."))
|
||||
items[.peerSettings]!.append(PeerInfoScreenCommentItem(id: ItemBotInfo, text: presentationData.strings.PeerInfo_Bot_BotFatherInfo, linkAction: { _ in
|
||||
interaction.openPeerMention("botfather", .default)
|
||||
}))
|
||||
} else if !user.flags.contains(.isSupport) {
|
||||
let compactName = EnginePeer(user).compactDisplayTitle
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemSuggest, text: presentationData.strings.UserInfo_SuggestPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Peer Info/SuggestAvatar"), action: {
|
||||
|
@ -300,6 +300,7 @@ public func wallpaperImage(account: Account, accountManager: AccountManager<Tele
|
||||
c.setBlendMode(.normal)
|
||||
}
|
||||
}
|
||||
addCorners(context, arguments: arguments)
|
||||
return context
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user