Merge commit '34062b0a06a4172597284b423349b806b53120f2'

This commit is contained in:
Ali 2023-04-06 19:19:50 +04:00
commit a74350b5cd
15 changed files with 437 additions and 148 deletions

View File

@ -9151,3 +9151,10 @@ Sorry for the inconvenience.";
"Conversation.Theme.SetPhotoWallpaper" = "Choose Background from Photos";
"Conversation.Theme.SetColorWallpaper" = "Choose Color as a Background";
"Conversation.Theme.OtherOptions" = "Other Options...";
"Conversation.Theme.ChooseWallpaperTitle" = "Choose Background";
"Conversation.Theme.ResetWallpaper" = "Reset to Default Background";
"Conversation.Theme.ChooseColorTitle" = "Set a Color";
"Conversation.Theme.SetCustomColor" = "Set Custom";
"Appearance.ShowNextMediaOnTap" = "Show Next Media on Tap";

View File

@ -177,7 +177,7 @@ private func generateMaskImage() -> UIImage? {
public class AttachmentController: ViewController {
private let context: AccountContext
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
private let chatLocation: ChatLocation
private let chatLocation: ChatLocation?
private let buttons: [AttachmentButtonType]
private let initialButton: AttachmentButtonType
private let fromMenu: Bool
@ -888,7 +888,7 @@ public class AttachmentController: ViewController {
public var getSourceRect: (() -> CGRect?)?
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, chatLocation: ChatLocation, buttons: [AttachmentButtonType], initialButton: AttachmentButtonType = .gallery, fromMenu: Bool = false, hasTextInput: Bool = true, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView? = { return nil}) {
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, chatLocation: ChatLocation?, buttons: [AttachmentButtonType], initialButton: AttachmentButtonType = .gallery, fromMenu: Bool = false, hasTextInput: Bool = true, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView? = { return nil}) {
self.context = context
self.updatedPresentationData = updatedPresentationData
self.chatLocation = chatLocation

View File

@ -387,7 +387,13 @@ public struct AttachmentMainButtonState {
case center
}
public enum Font: Equatable {
case regular
case bold
}
public let text: String?
public let font: Font
public let background: Background
public let textColor: UIColor
public let isVisible: Bool
@ -396,6 +402,7 @@ public struct AttachmentMainButtonState {
public init(
text: String?,
font: Font,
background: Background,
textColor: UIColor,
isVisible: Bool,
@ -403,6 +410,7 @@ public struct AttachmentMainButtonState {
isEnabled: Bool
) {
self.text = text
self.font = font
self.background = background
self.textColor = textColor
self.isVisible = isVisible
@ -411,7 +419,7 @@ public struct AttachmentMainButtonState {
}
static var initial: AttachmentMainButtonState {
return AttachmentMainButtonState(text: nil, background: .color(.clear), textColor: .clear, isVisible: false, progress: .none, isEnabled: false)
return AttachmentMainButtonState(text: nil, font: .bold, background: .color(.clear), textColor: .clear, isVisible: false, progress: .none, isEnabled: false)
}
}
@ -643,7 +651,14 @@ private final class MainButtonNode: HighlightTrackingButtonNode {
self.setupShimmering()
if let text = state.text {
self.textNode.attributedText = NSAttributedString(string: text, font: Font.semibold(17.0), textColor: state.textColor)
let font: UIFont
switch state.font {
case .regular:
font = Font.regular(17.0)
case .bold:
font = Font.semibold(17.0)
}
self.textNode.attributedText = NSAttributedString(string: text, font: font, textColor: state.textColor)
let textSize = self.textNode.updateLayout(size)
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: floorToScreenPixels((size.height - textSize.height) / 2.0)), size: textSize)
@ -758,13 +773,13 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
var mainButtonPressed: () -> Void = { }
init(context: AccountContext, chatLocation: ChatLocation, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView?) {
init(context: AccountContext, chatLocation: ChatLocation?, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView?) {
self.context = context
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
self.makeEntityInputView = makeEntityInputView
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: chatLocation, subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: chatLocation ?? .peer(id: context.account.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
self.containerNode = ASDisplayNode()
self.containerNode.clipsToBounds = true
@ -936,7 +951,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
return
}
textInputPanelNode.loadTextInputNodeIfNeeded()
guard let textInputNode = textInputPanelNode.textInputNode, let peerId = chatLocation.peerId else {
guard let textInputNode = textInputPanelNode.textInputNode, let peerId = chatLocation?.peerId else {
return
}
@ -1267,7 +1282,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
func updateMainButtonState(_ mainButtonState: AttachmentMainButtonState?) {
var currentButtonState = self.mainButtonState
if mainButtonState == nil {
currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, background: currentButtonState.background, textColor: currentButtonState.textColor, isVisible: false, progress: .none, isEnabled: currentButtonState.isEnabled)
currentButtonState = AttachmentMainButtonState(text: currentButtonState.text, font: currentButtonState.font, background: currentButtonState.background, textColor: currentButtonState.textColor, isVisible: false, progress: .none, isEnabled: currentButtonState.isEnabled)
}
self.mainButtonState = mainButtonState ?? currentButtonState
}
@ -1417,6 +1432,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
self.scrollNode.isUserInteractionEnabled = !isSelecting
let isButtonVisible = self.mainButtonState.isVisible
let isNarrowButton = isButtonVisible && self.mainButtonState.font == .regular
var insets = layout.insets(options: [])
if let inputHeight = layout.inputHeight, inputHeight > 0.0 && (isSelecting || isButtonVisible) {
@ -1457,7 +1473,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
if isButtonVisible {
var height: CGFloat
if layout.intrinsicInsets.bottom > 0.0 && (layout.inputHeight ?? 0.0).isZero {
height = bounds.height + 9.0
height = bounds.height
if case .regular = layout.metrics.widthClass {
if self.isStandalone {
height -= 3.0
@ -1466,7 +1482,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
}
}
} else {
height = bounds.height + 9.0 + 8.0
height = bounds.height + 8.0
}
if !isNarrowButton {
height += 9.0
}
containerFrame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: height))
} else if isSelecting {
@ -1532,11 +1551,13 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
let sideInset: CGFloat = 16.0
let buttonSize = CGSize(width: layout.size.width - (sideInset + layout.safeInsets.left) * 2.0, height: 50.0)
let buttonTopInset: CGFloat = isNarrowButton ? 2.0 : 8.0
if !self.dismissed {
self.mainButtonNode.updateLayout(size: buttonSize, state: self.mainButtonState, transition: transition)
}
if !self.animatingTransition {
transition.updateFrame(node: self.mainButtonNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + sideInset, y: isButtonVisible || self.fromMenu ? 8.0 : containerFrame.height), size: buttonSize))
transition.updateFrame(node: self.mainButtonNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + sideInset, y: isButtonVisible || self.fromMenu ? buttonTopInset : containerFrame.height), size: buttonSize))
}
return containerFrame.height

View File

@ -5,12 +5,16 @@ import Photos
import AVFoundation
class MediaAssetsContext: NSObject, PHPhotoLibraryChangeObserver {
private let assetType: PHAssetMediaType?
private var registeredChangeObserver = false
private let changeSink = ValuePipe<PHChange>()
private let mediaAccessSink = ValuePipe<PHAuthorizationStatus>()
private let cameraAccessSink = ValuePipe<AVAuthorizationStatus?>()
override init() {
init(assetType: PHAssetMediaType?) {
self.assetType = assetType
super.init()
if PHPhotoLibrary.authorizationStatus() == .authorized {
@ -30,7 +34,12 @@ class MediaAssetsContext: NSObject, PHPhotoLibraryChangeObserver {
}
func fetchAssets(_ collection: PHAssetCollection) -> Signal<PHFetchResult<PHAsset>, NoError> {
let initialFetchResult = PHAsset.fetchAssets(in: collection, options: nil)
let options = PHFetchOptions()
if let assetType = self.assetType {
options.predicate = NSPredicate(format: "mediaType = %d", assetType.rawValue)
}
let initialFetchResult = PHAsset.fetchAssets(in: collection, options: options)
let fetchResult = Atomic<PHFetchResult<PHAsset>>(value: initialFetchResult)
return .single(initialFetchResult)
|> then(

View File

@ -128,7 +128,12 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
}
case assets(PHAssetCollection?, Bool)
public enum AssetsMode: Equatable {
case `default`
case wallpaper
}
case assets(PHAssetCollection?, AssetsMode)
case media([Media])
}
@ -238,7 +243,11 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.controller = controller
self.presentationData = controller.presentationData
let mediaAssetsContext = MediaAssetsContext()
var assetType: PHAssetMediaType?
if case let .assets(_, mode) = controller.subject, case .wallpaper = mode {
assetType = .image
}
let mediaAssetsContext = MediaAssetsContext(assetType: assetType)
self.mediaAssetsContext = mediaAssetsContext
self.containerNode = ASDisplayNode()
@ -253,7 +262,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
super.init()
if case .assets(nil, false) = controller.subject {
if case .assets(nil, .default) = controller.subject {
} else {
self.preloadPromise.set(false)
}
@ -454,7 +463,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
})
if let controller = self.controller, case .assets(nil, false) = controller.subject {
if let controller = self.controller, case .assets(nil, .default) = controller.subject {
let enableAnimations = self.controller?.context.sharedContext.energyUsageSettings.fullTranslucency ?? true
let cameraView = TGAttachmentCameraView(forSelfPortrait: false, videoModeByDefault: controller.bannedSendPhotos != nil && controller.bannedSendVideos == nil)!
@ -556,7 +565,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
var updateLayout = false
var selectable = true
if case let .assets(_, isStandalone) = controller.subject, isStandalone {
if case let .assets(_, mode) = controller.subject, mode != .default {
selectable = false
}
@ -1229,7 +1238,24 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
private var isDismissing = false
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, bannedSendPhotos: (Int32, Bool)?, bannedSendVideos: (Int32, Bool)?, subject: Subject, editingContext: TGMediaEditingContext? = nil, selectionContext: TGMediaSelectionContext? = nil, saveEditedPhotos: Bool = false) {
fileprivate let mainButtonState: AttachmentMainButtonState?
private let mainButtonAction: (() -> Void)?
public init(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
peer: EnginePeer?,
threadTitle: String?,
chatLocation: ChatLocation?,
bannedSendPhotos: (Int32, Bool)?,
bannedSendVideos: (Int32, Bool)?,
subject: Subject,
editingContext: TGMediaEditingContext? = nil,
selectionContext: TGMediaSelectionContext? = nil,
saveEditedPhotos: Bool = false,
mainButtonState: AttachmentMainButtonState? = nil,
mainButtonAction: (() -> Void)? = nil
) {
self.context = context
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
@ -1242,13 +1268,24 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.bannedSendVideos = bannedSendVideos
self.subject = subject
self.saveEditedPhotos = saveEditedPhotos
self.mainButtonState = mainButtonState
self.mainButtonAction = mainButtonAction
let selectionContext = selectionContext ?? TGMediaSelectionContext()
self.titleView = MediaPickerTitleView(theme: self.presentationData.theme, segments: [self.presentationData.strings.Attachment_AllMedia, self.presentationData.strings.Attachment_SelectedMedia(1)], selectedIndex: 0)
if case let .assets(collection, _) = subject, let collection = collection {
self.titleView.title = collection.localizedTitle ?? presentationData.strings.Attachment_Gallery
if case let .assets(collection, mode) = subject {
if let collection = collection {
self.titleView.title = collection.localizedTitle ?? presentationData.strings.Attachment_Gallery
} else {
switch mode {
case .default:
self.titleView.title = presentationData.strings.Attachment_Gallery
case .wallpaper:
self.titleView.title = presentationData.strings.Conversation_Theme_ChooseWallpaperTitle
}
}
} else {
self.titleView.title = presentationData.strings.Attachment_Gallery
}
@ -1316,7 +1353,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.navigationItem.titleView = self.titleView
if case let .assets(_, isStandalone) = self.subject, isStandalone {
if case let .assets(_, mode) = self.subject, mode != .default {
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 {
@ -1609,6 +1646,10 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
}
func mainButtonPressed() {
self.mainButtonAction?()
}
func dismissAllTooltips() {
self.undoOverlayController?.dismissWithCommitAction()
}
@ -1674,13 +1715,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
private func presentSearch(activateOnDisplay: Bool) {
guard self.moreButtonNode.iconNode.iconState == .search else {
guard self.moreButtonNode.iconNode.iconState == .search, case let .assets(_, mode) = self.subject else {
return
}
self.requestAttachmentMenuExpansion()
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
if let strongSelf = self {
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendPhotos: strongSelf.bannedSendPhotos, bannedSendVideos: strongSelf.bannedSendVideos, subject: .assets(collection, false), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendPhotos: strongSelf.bannedSendPhotos, bannedSendVideos: strongSelf.bannedSendVideos, subject: .assets(collection, mode), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
mediaPicker.presentSchedulePicker = strongSelf.presentSchedulePicker
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker
@ -1793,21 +1834,17 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
public var mediaPickerContext: AttachmentMediaPickerContext? {
if let interaction = self.interaction {
return MediaPickerContext(interaction: interaction)
} else {
return nil
}
return MediaPickerContext(controller: self)
}
}
final class MediaPickerContext: AttachmentMediaPickerContext {
private weak var interaction: MediaPickerInteraction?
private weak var controller: MediaPickerScreen?
var selectionCount: Signal<Int, NoError> {
return Signal { [weak self] subscriber in
let disposable = self?.interaction?.selectionState?.selectionChangedSignal().start(next: { [weak self] value in
subscriber.putNext(Int(self?.interaction?.selectionState?.count() ?? 0))
let disposable = self?.controller?.interaction?.selectionState?.selectionChangedSignal().start(next: { [weak self] value in
subscriber.putNext(Int(self?.controller?.interaction?.selectionState?.count() ?? 0))
}, error: { _ in }, completed: { })
return ActionDisposable {
disposable?.dispose()
@ -1817,7 +1854,7 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
var caption: Signal<NSAttributedString?, NoError> {
return Signal { [weak self] subscriber in
let disposable = self?.interaction?.editingState.forcedCaption().start(next: { caption in
let disposable = self?.controller?.interaction?.editingState.forcedCaption().start(next: { caption in
if let caption = caption as? NSAttributedString {
subscriber.putNext(caption)
} else {
@ -1835,27 +1872,27 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
return .single(self.controller?.mainButtonState)
}
init(interaction: MediaPickerInteraction) {
self.interaction = interaction
init(controller: MediaPickerScreen) {
self.controller = controller
}
func setCaption(_ caption: NSAttributedString) {
self.interaction?.editingState.setForcedCaption(caption, skipUpdate: true)
self.controller?.interaction?.editingState.setForcedCaption(caption, skipUpdate: true)
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
self.interaction?.sendSelected(nil, mode == .silently, mode == .whenOnline ? scheduleWhenOnlineTimestamp : nil, true, {})
self.controller?.interaction?.sendSelected(nil, mode == .silently, mode == .whenOnline ? scheduleWhenOnlineTimestamp : nil, true, {})
}
func schedule() {
self.interaction?.schedule()
self.controller?.interaction?.schedule()
}
func mainButtonAction() {
self.controller?.mainButtonPressed()
}
}
@ -1968,3 +2005,25 @@ public class MediaPickerGridSelectionGesture<T> : UIPanGestureRecognizer {
self.updateIsScrollEnabled(true)
}
}
public func wallpaperMediaPickerController(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
peer: EnginePeer,
canDelete: Bool,
completion: @escaping (PHAsset) -> Void = { _ in }
) -> ViewController {
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: {
return nil
})
controller.requestController = { [weak controller] _, present in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let mediaPickerController = MediaPickerScreen(context: context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper), mainButtonState: canDelete ? AttachmentMainButtonState(text: presentationData.strings.Conversation_Theme_ResetWallpaper, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true) : nil, mainButtonAction: canDelete ? {
let _ = context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: nil).start()
controller?.dismiss(animated: true)
} : nil)
mediaPickerController.customSelection = completion
present(mediaPickerController, mediaPickerController.mediaPickerContext)
}
return controller
}

View File

@ -88,7 +88,7 @@ final class MediaPickerTitleView: UIView {
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: min(300.0, size.width - 36.0)), transition: .immediate)
self.segmentedControlNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - controlSize.width) / 2.0), y: floorToScreenPixels((size.height - controlSize.height) / 2.0)), size: controlSize)
let titleSize = self.titleNode.updateLayout(CGSize(width: 160.0, height: 44.0))
let titleSize = self.titleNode.updateLayout(CGSize(width: 210.0, height: 44.0))
self.titleNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: floorToScreenPixels((size.height - titleSize.height) / 2.0)), size: titleSize)
}
}

View File

@ -645,7 +645,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
price = nil
}
let buttonText = presentationData.strings.Premium_Gift_GiftSubscription(price ?? "").string
self.buttonStatePromise.set(.single(AttachmentMainButtonState(text: buttonText, background: .premium, textColor: .white, isVisible: true, progress: self.inProgress ? .center : .none, isEnabled: true)))
self.buttonStatePromise.set(.single(AttachmentMainButtonState(text: buttonText, font: .bold, background: .premium, textColor: .white, isVisible: true, progress: self.inProgress ? .center : .none, isEnabled: true)))
}
func buy() {

View File

@ -112,6 +112,7 @@ swift_library(
"//submodules/FeaturedStickersScreen:FeaturedStickersScreen",
"//submodules/MediaPickerUI:MediaPickerUI",
"//submodules/ImageBlur:ImageBlur",
"//submodules/AttachmentUI:AttachmentUI",
],
visibility = [
"//visibility:public",

View File

@ -309,6 +309,9 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
if let node = node {
contentSize.height += node.frame.size.height
}
if item.reaction == nil {
contentSize.height += 34.0
}
insets = itemListNeighborsGroupedInsets(neighbors, params)
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
@ -333,7 +336,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
var topOffset: CGFloat = 16.0
var topOffset: CGFloat = 16.0 + 17.0
if let node = node {
strongSelf.messageNode = node
if node.supernode == nil {

View File

@ -9,6 +9,7 @@ import LegacyComponents
import TelegramPresentationData
import TelegramUIPreferences
import AccountContext
import AttachmentUI
private func availableGradients(theme: PresentationTheme) -> [[UInt32]] {
if theme.overallDarkAppearance {
@ -102,7 +103,7 @@ private func availableColors(theme: PresentationTheme) -> [UInt32] {
}
}
public final class ThemeColorsGridController: ViewController {
public final class ThemeColorsGridController: ViewController, AttachmentContainable {
public enum Mode {
case `default`
case peer(EnginePeer)
@ -145,14 +146,17 @@ public final class ThemeColorsGridController: ViewController {
private var previousContentOffset: GridNodeVisibleContentOffset?
public init(context: AccountContext, mode: Mode = .default) {
fileprivate let mainButtonStatePromise = Promise<AttachmentMainButtonState?>(nil)
var pushController: (ViewController) -> Void = { _ in }
public init(context: AccountContext, mode: Mode = .default, canDelete: Bool = false) {
self.context = context
self.mode = mode
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
self.title = self.presentationData.strings.WallpaperColors_Title
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
self.scrollToTop = { [weak self] in
@ -174,6 +178,22 @@ public final class ThemeColorsGridController: ViewController {
}
}
})
if case .peer = mode {
self.title = self.presentationData.strings.Conversation_Theme_ChooseColorTitle
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Conversation_Theme_SetCustomColor, style: .plain, target: self, action: #selector(self.customPressed))
} else {
self.title = self.presentationData.strings.WallpaperColors_Title
}
self.pushController = { [weak self] controller in
self?.push(controller)
}
if canDelete {
self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.Conversation_Theme_ResetWallpaper, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true)))
}
}
required public init(coder aDecoder: NSCoder) {
@ -184,6 +204,14 @@ public final class ThemeColorsGridController: ViewController {
self.presentationDataDisposable?.dispose()
}
@objc private func cancelPressed() {
self.dismiss()
}
@objc private func customPressed() {
self.presentColorPicker()
}
private func updateThemeAndStrings() {
self.title = self.presentationData.strings.WallpaperColors_Title
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
@ -194,56 +222,68 @@ public final class ThemeColorsGridController: ViewController {
}
}
private func presentColorPicker() {
let _ = (self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings])
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
guard let strongSelf = self else {
return
}
let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings
let autoNightModeTriggered = strongSelf.presentationData.autoNightModeTriggered
let themeReference: PresentationThemeReference
if autoNightModeTriggered {
themeReference = settings.automaticThemeSwitchSetting.theme
} else {
themeReference = settings.theme
}
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
controllers = controllers.filter { controller in
if controller is ThemeColorsGridController {
return false
}
return true
}
navigationController.setViewControllers(controllers, animated: false)
controllers = controllers.filter { controller in
if controller is ThemeAccentColorController {
return false
}
return true
}
navigationController.setViewControllers(controllers, animated: true)
}
}
strongSelf.pushController(controller)
})
}
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)
self?.pushController(controller)
}, pop: { [weak self] in
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
let _ = navigationController.popViewController(animated: true)
}
}, presentColorPicker: { [weak self] in
if let strongSelf = self {
let _ = (strongSelf.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings])
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
guard let strongSelf = self else {
return
}
let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings
let autoNightModeTriggered = strongSelf.presentationData.autoNightModeTriggered
let themeReference: PresentationThemeReference
if autoNightModeTriggered {
themeReference = settings.automaticThemeSwitchSetting.theme
} else {
themeReference = settings.theme
}
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
controllers = controllers.filter { controller in
if controller is ThemeColorsGridController {
return false
}
return true
}
navigationController.setViewControllers(controllers, animated: false)
controllers = controllers.filter { controller in
if controller is ThemeAccentColorController {
return false
}
return true
}
navigationController.setViewControllers(controllers, animated: true)
}
}
strongSelf.push(controller)
})
strongSelf.presentColorPicker()
}
})
let transitionOffset: CGFloat
switch self.mode {
case .default:
transitionOffset = 30.0
case .peer:
transitionOffset = 2.0
}
self.controllerNode.gridNode.visibleContentOffsetChanged = { [weak self] offset in
if let strongSelf = self {
var previousContentOffsetValue: CGFloat?
@ -253,12 +293,12 @@ public final class ThemeColorsGridController: ViewController {
switch offset {
case let .known(value):
let transition: ContainedViewLayoutTransition
if let previousContentOffsetValue = previousContentOffsetValue, value <= 0.0, previousContentOffsetValue > 30.0 {
if let previousContentOffsetValue = previousContentOffsetValue, value <= 0.0, previousContentOffsetValue > transitionOffset {
transition = .animated(duration: 0.2, curve: .easeInOut)
} else {
transition = .immediate
}
strongSelf.navigationBar?.updateBackgroundAlpha(min(30.0, value) / 30.0, transition: transition)
strongSelf.navigationBar?.updateBackgroundAlpha(min(transitionOffset, value) / transitionOffset, transition: transition)
case .unknown, .none:
strongSelf.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
}
@ -279,4 +319,76 @@ public final class ThemeColorsGridController: ViewController {
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
}
@objc fileprivate func mainButtonPressed() {
guard case let .peer(peer) = self.mode else {
return
}
let _ = self.context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: nil).start()
self.dismiss(animated: true)
}
public var requestAttachmentMenuExpansion: () -> Void = {}
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var cancelPanGesture: () -> Void = { }
public var isContainerPanning: () -> Bool = { return false }
public var isContainerExpanded: () -> Bool = { return false }
public var mediaPickerContext: AttachmentMediaPickerContext? {
return ThemeColorsGridContext(controller: self)
}
}
private final class ThemeColorsGridContext: AttachmentMediaPickerContext {
private weak var controller: ThemeColorsGridController?
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return self.controller?.mainButtonStatePromise.get() ?? .single(nil)
}
init(controller: ThemeColorsGridController) {
self.controller = controller
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode) {
}
func schedule() {
}
func mainButtonAction() {
self.controller?.mainButtonPressed()
}
}
public func standaloneColorPickerController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, canDelete: Bool, push: @escaping (ViewController) -> Void) -> ViewController {
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: {
return nil
})
controller.requestController = { _, present in
let colorPickerController = ThemeColorsGridController(context: context, mode: .peer(peer), canDelete: canDelete)
colorPickerController.pushController = { controller in
push(controller)
}
present(colorPickerController, colorPickerController.mediaPickerContext)
}
return controller
}

View File

@ -73,7 +73,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
let ready = ValuePromise<Bool>()
private var backgroundNode: ASDisplayNode
private var topBackgroundNode: ASDisplayNode
private var separatorNode: ASDisplayNode
private let customColorItemNode: ItemListActionItemNode
@ -102,8 +102,8 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
self.rightOverlayNode = ASDisplayNode()
self.rightOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
self.topBackgroundNode = ASDisplayNode()
self.topBackgroundNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
self.separatorNode = ASDisplayNode()
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
@ -121,9 +121,14 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
self.gridNode.addSubnode(self.backgroundNode)
self.gridNode.addSubnode(self.separatorNode)
self.gridNode.addSubnode(self.customColorItemNode)
if case .default = controller.mode {
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
self.gridNode.addSubnode(self.topBackgroundNode)
self.gridNode.addSubnode(self.separatorNode)
self.gridNode.addSubnode(self.customColorItemNode)
} else {
self.backgroundColor = presentationData.theme.list.plainBackgroundColor
}
self.addSubnode(self.gridNode)
let previousEntries = Atomic<[ThemeColorsGridControllerEntry]?>(value: nil)
@ -240,9 +245,13 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
func updatePresentationData(_ presentationData: PresentationData) {
self.presentationData = presentationData
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
self.leftOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
self.rightOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
if let controller = self.controller, case .default = controller.mode {
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
self.leftOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
self.rightOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
} else {
self.backgroundColor = presentationData.theme.list.plainBackgroundColor
}
self.customColorItem = ItemListActionItem(presentationData: ItemListPresentationData(presentationData), title: presentationData.strings.WallpaperColors_SetCustomColor, kind: .generic, alignment: .natural, sectionId: 0, style: .blocks, action: { [weak self] in
self?.presentColorPicker()
@ -272,6 +281,9 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
guard let controller = self.controller else {
return
}
let hadValidLayout = self.validLayout != nil
var insets = layout.insets(options: [.input])
@ -280,7 +292,18 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
insets.right = layout.safeInsets.right
let scrollIndicatorInsets = insets
let minSpacing: CGFloat = 8.0
let itemsPerRow: Int
if case .compact = layout.metrics.widthClass {
switch layout.orientation {
case .portrait:
itemsPerRow = 3
case .landscape:
itemsPerRow = 5
}
} else {
itemsPerRow = 3
}
let referenceImageSize: CGSize
let screenWidth = min(layout.size.width, layout.size.height)
if screenWidth >= 375.0 {
@ -288,29 +311,56 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
} else {
referenceImageSize = CGSize(width: 91.0, height: 91.0)
}
let imageCount = Int((layout.size.width - insets.left - insets.right - minSpacing * 2.0) / (referenceImageSize.width + minSpacing))
let imageSize = referenceImageSize.aspectFilled(CGSize(width: floor((layout.size.width - CGFloat(imageCount + 1) * minSpacing) / CGFloat(imageCount)), height: referenceImageSize.height))
let spacing = floor((layout.size.width - CGFloat(imageCount) * imageSize.width) / CGFloat(imageCount + 1))
let width = layout.size.width - layout.safeInsets.left - layout.safeInsets.right
let imageSize: CGSize
let spacing: CGFloat
var fillWidth: Bool?
if case .peer = controller.mode {
spacing = 1.0
let itemWidth = floorToScreenPixels((width - spacing * CGFloat(itemsPerRow - 1)) / CGFloat(itemsPerRow))
imageSize = CGSize(width: itemWidth, height: itemWidth)
fillWidth = true
} else {
let minSpacing = 8.0
imageSize = referenceImageSize.aspectFilled(CGSize(width: floor((width - CGFloat(itemsPerRow + 1) * minSpacing) / CGFloat(itemsPerRow)), height: referenceImageSize.height))
spacing = floor((width - CGFloat(itemsPerRow) * imageSize.width) / CGFloat(itemsPerRow + 1))
}
let buttonTopInset: CGFloat = 32.0
let buttonHeight: CGFloat = 44.0
let buttonBottomInset: CGFloat = 35.0
var buttonInset: CGFloat = buttonTopInset + buttonHeight + buttonBottomInset
var buttonOffset = buttonInset + 10.0
var listInsets = insets
if layout.size.width >= 375.0 {
let inset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
listInsets.left += inset
listInsets.right += inset
if self.leftOverlayNode.supernode == nil {
self.gridNode.addSubnode(self.leftOverlayNode)
}
if self.rightOverlayNode.supernode == nil {
self.gridNode.addSubnode(self.rightOverlayNode)
if case .default = controller.mode {
if layout.size.width >= 375.0 {
let inset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
listInsets.left += inset
listInsets.right += inset
if self.leftOverlayNode.supernode == nil {
self.gridNode.addSubnode(self.leftOverlayNode)
}
if self.rightOverlayNode.supernode == nil {
self.gridNode.addSubnode(self.rightOverlayNode)
}
} else {
if self.leftOverlayNode.supernode != nil {
self.leftOverlayNode.removeFromSupernode()
}
if self.rightOverlayNode.supernode != nil {
self.rightOverlayNode.removeFromSupernode()
}
}
} else {
if self.leftOverlayNode.supernode != nil {
self.leftOverlayNode.removeFromSupernode()
}
if self.rightOverlayNode.supernode != nil {
self.rightOverlayNode.removeFromSupernode()
}
self.customColorItemNode.isHidden = true
buttonOffset = 0.0
buttonInset = 0.0
}
let makeColorLayout = self.customColorItemNode.asyncLayout()
@ -318,14 +368,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
let (colorLayout, colorApply) = makeColorLayout(self.customColorItem, params, ItemListNeighbors(top: .none, bottom: .none))
colorApply()
let buttonTopInset: CGFloat = 32.0
let buttonHeight: CGFloat = 44.0
let buttonBottomInset: CGFloat = 35.0
let buttonInset: CGFloat = buttonTopInset + buttonHeight + buttonBottomInset
let buttonOffset = buttonInset + 10.0
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -buttonOffset - 500.0), size: CGSize(width: layout.size.width, height: buttonInset + 500.0)))
transition.updateFrame(node: self.topBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -buttonOffset - 500.0), size: CGSize(width: layout.size.width, height: buttonInset + 500.0)))
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -buttonOffset + buttonInset - UIScreenPixel), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
transition.updateFrame(node: self.customColorItemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -buttonOffset + buttonTopInset), size: colorLayout.contentSize))
@ -334,7 +377,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
insets.top += spacing + buttonInset
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, preloadSize: 300.0, type: .fixed(itemSize: imageSize, fillWidth: nil, lineSpacing: spacing, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, preloadSize: 300.0, type: .fixed(itemSize: imageSize, fillWidth: fillWidth, lineSpacing: spacing, itemSpacing: fillWidth != nil ? spacing : nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
self.gridNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
@ -350,7 +393,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: GridNodeScrollToItem(index: 0, position: .top(0.0), transition: .animated(duration: 0.25, curve: .easeInOut), directionHint: .up, adjustForSection: true, adjustForTopInset: true), updateLayout: nil, itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
self.backgroundNode.layer.animatePosition(from: self.backgroundNode.layer.position.offsetBy(dx: 0.0, dy: -offset), to: self.backgroundNode.layer.position, duration: duration)
self.topBackgroundNode.layer.animatePosition(from: self.topBackgroundNode.layer.position.offsetBy(dx: 0.0, dy: -offset), to: self.topBackgroundNode.layer.position, duration: duration)
self.separatorNode.layer.animatePosition(from: self.separatorNode.layer.position.offsetBy(dx: 0.0, dy: -offset), to: self.separatorNode.layer.position, duration: duration)
self.customColorItemNode.layer.animatePosition(from: self.customColorItemNode.layer.position.offsetBy(dx: 0.0, dy: -offset), to: self.customColorItemNode.layer.position, duration: duration)
}

View File

@ -142,7 +142,7 @@ public final class ThemeGridController: ViewController {
}
}, presentGallery: { [weak self] in
if let strongSelf = self {
let controller = MediaPickerScreen(context: strongSelf.context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, true))
let controller = MediaPickerScreen(context: strongSelf.context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper))
controller.customSelection = { [weak self] asset in
guard let strongSelf = self else {
return

View File

@ -3405,6 +3405,22 @@ func replayFinalState(
for (space, _) in holesAtHistoryStart {
transaction.removeHole(peerId: chatPeerId, threadId: nil, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id)
}
case let .setChatWallpaper(wallpaper):
if chatPeerId == accountPeerId {
transaction.updatePeerCachedData(peerIds: [message.id.peerId], update: { peerId, current in
var current = current
if current == nil {
if peerId.namespace == Namespaces.Peer.CloudUser {
current = CachedUserData()
}
}
if let cachedData = current as? CachedUserData {
return cachedData.withUpdatedWallpaper(wallpaper)
} else {
return current
}
})
}
default:
break
}

View File

@ -13826,7 +13826,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.present(actionSheet, in: .window(.root))
}
private func presentMediaPicker(subject: MediaPickerScreen.Subject = .assets(nil, false), saveEditedPhotos: Bool, bannedSendPhotos: (Int32, Bool)?, bannedSendVideos: (Int32, Bool)?, present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping ([Any], Bool, Int32?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) {
private func presentMediaPicker(subject: MediaPickerScreen.Subject = .assets(nil, .default), saveEditedPhotos: Bool, bannedSendPhotos: (Int32, Bool)?, bannedSendVideos: (Int32, Bool)?, present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping ([Any], Bool, Int32?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) {
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
return
}
@ -18511,7 +18511,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
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 {
if controller is WallpaperGalleryController || controller is AttachmentController {
return false
}
return true
@ -18520,23 +18520,32 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
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)
var canDelete = false
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData {
canDelete = cachedUserData.wallpaper != nil
}
let controller = wallpaperMediaPickerController(
context: strongSelf.context,
updatedPresentationData: strongSelf.updatedPresentationData,
peer: EnginePeer(peer),
canDelete: canDelete,
completion: { 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)
}
)
controller.navigationPresentation = .flatModal
strongSelf.push(controller)
},
changeColor: {
@ -18547,8 +18556,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.themeScreen = nil
themeController.dimTapped()
}
let controller = ThemeColorsGridController(context: context, mode: .peer(EnginePeer(peer)))
controller.navigationPresentation = .modal
var canDelete = false
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData {
canDelete = cachedUserData.wallpaper != nil
}
let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), canDelete: canDelete, push: { [weak self] controller in
if let strongSelf = self {
strongSelf.push(controller)
}
})
controller.navigationPresentation = .flatModal
strongSelf.push(controller)
},
completion: { [weak self] emoticon in

View File

@ -675,7 +675,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
let isLoading = json["is_progress_visible"] as? Bool
let isEnabled = json["is_active"] as? Bool
let state = AttachmentMainButtonState(text: text, background: .color(backgroundColor), textColor: textColor, isVisible: isVisible, progress: (isLoading ?? false) ? .side : .none, isEnabled: isEnabled ?? true)
let state = AttachmentMainButtonState(text: text, font: .bold, background: .color(backgroundColor), textColor: textColor, isVisible: isVisible, progress: (isLoading ?? false) ? .side : .none, isEnabled: isEnabled ?? true)
self.mainButtonState = state
}
}