mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '34062b0a06a4172597284b423349b806b53120f2'
This commit is contained in:
commit
a74350b5cd
@ -9151,3 +9151,10 @@ Sorry for the inconvenience.";
|
|||||||
"Conversation.Theme.SetPhotoWallpaper" = "Choose Background from Photos";
|
"Conversation.Theme.SetPhotoWallpaper" = "Choose Background from Photos";
|
||||||
"Conversation.Theme.SetColorWallpaper" = "Choose Color as a Background";
|
"Conversation.Theme.SetColorWallpaper" = "Choose Color as a Background";
|
||||||
"Conversation.Theme.OtherOptions" = "Other Options...";
|
"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";
|
||||||
|
@ -177,7 +177,7 @@ private func generateMaskImage() -> UIImage? {
|
|||||||
public class AttachmentController: ViewController {
|
public class AttachmentController: ViewController {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||||
private let chatLocation: ChatLocation
|
private let chatLocation: ChatLocation?
|
||||||
private let buttons: [AttachmentButtonType]
|
private let buttons: [AttachmentButtonType]
|
||||||
private let initialButton: AttachmentButtonType
|
private let initialButton: AttachmentButtonType
|
||||||
private let fromMenu: Bool
|
private let fromMenu: Bool
|
||||||
@ -888,7 +888,7 @@ public class AttachmentController: ViewController {
|
|||||||
|
|
||||||
public var getSourceRect: (() -> CGRect?)?
|
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.context = context
|
||||||
self.updatedPresentationData = updatedPresentationData
|
self.updatedPresentationData = updatedPresentationData
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
|
@ -387,7 +387,13 @@ public struct AttachmentMainButtonState {
|
|||||||
case center
|
case center
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Font: Equatable {
|
||||||
|
case regular
|
||||||
|
case bold
|
||||||
|
}
|
||||||
|
|
||||||
public let text: String?
|
public let text: String?
|
||||||
|
public let font: Font
|
||||||
public let background: Background
|
public let background: Background
|
||||||
public let textColor: UIColor
|
public let textColor: UIColor
|
||||||
public let isVisible: Bool
|
public let isVisible: Bool
|
||||||
@ -396,6 +402,7 @@ public struct AttachmentMainButtonState {
|
|||||||
|
|
||||||
public init(
|
public init(
|
||||||
text: String?,
|
text: String?,
|
||||||
|
font: Font,
|
||||||
background: Background,
|
background: Background,
|
||||||
textColor: UIColor,
|
textColor: UIColor,
|
||||||
isVisible: Bool,
|
isVisible: Bool,
|
||||||
@ -403,6 +410,7 @@ public struct AttachmentMainButtonState {
|
|||||||
isEnabled: Bool
|
isEnabled: Bool
|
||||||
) {
|
) {
|
||||||
self.text = text
|
self.text = text
|
||||||
|
self.font = font
|
||||||
self.background = background
|
self.background = background
|
||||||
self.textColor = textColor
|
self.textColor = textColor
|
||||||
self.isVisible = isVisible
|
self.isVisible = isVisible
|
||||||
@ -411,7 +419,7 @@ public struct AttachmentMainButtonState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var initial: 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()
|
self.setupShimmering()
|
||||||
|
|
||||||
if let text = state.text {
|
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)
|
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)
|
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 = { }
|
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.context = context
|
||||||
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
self.makeEntityInputView = makeEntityInputView
|
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 = ASDisplayNode()
|
||||||
self.containerNode.clipsToBounds = true
|
self.containerNode.clipsToBounds = true
|
||||||
@ -936,7 +951,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
textInputPanelNode.loadTextInputNodeIfNeeded()
|
textInputPanelNode.loadTextInputNodeIfNeeded()
|
||||||
guard let textInputNode = textInputPanelNode.textInputNode, let peerId = chatLocation.peerId else {
|
guard let textInputNode = textInputPanelNode.textInputNode, let peerId = chatLocation?.peerId else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1267,7 +1282,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
func updateMainButtonState(_ mainButtonState: AttachmentMainButtonState?) {
|
func updateMainButtonState(_ mainButtonState: AttachmentMainButtonState?) {
|
||||||
var currentButtonState = self.mainButtonState
|
var currentButtonState = self.mainButtonState
|
||||||
if mainButtonState == nil {
|
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
|
self.mainButtonState = mainButtonState ?? currentButtonState
|
||||||
}
|
}
|
||||||
@ -1417,6 +1432,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.scrollNode.isUserInteractionEnabled = !isSelecting
|
self.scrollNode.isUserInteractionEnabled = !isSelecting
|
||||||
|
|
||||||
let isButtonVisible = self.mainButtonState.isVisible
|
let isButtonVisible = self.mainButtonState.isVisible
|
||||||
|
let isNarrowButton = isButtonVisible && self.mainButtonState.font == .regular
|
||||||
|
|
||||||
var insets = layout.insets(options: [])
|
var insets = layout.insets(options: [])
|
||||||
if let inputHeight = layout.inputHeight, inputHeight > 0.0 && (isSelecting || isButtonVisible) {
|
if let inputHeight = layout.inputHeight, inputHeight > 0.0 && (isSelecting || isButtonVisible) {
|
||||||
@ -1457,7 +1473,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if isButtonVisible {
|
if isButtonVisible {
|
||||||
var height: CGFloat
|
var height: CGFloat
|
||||||
if layout.intrinsicInsets.bottom > 0.0 && (layout.inputHeight ?? 0.0).isZero {
|
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 case .regular = layout.metrics.widthClass {
|
||||||
if self.isStandalone {
|
if self.isStandalone {
|
||||||
height -= 3.0
|
height -= 3.0
|
||||||
@ -1466,7 +1482,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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))
|
containerFrame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: height))
|
||||||
} else if isSelecting {
|
} else if isSelecting {
|
||||||
@ -1532,11 +1551,13 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
let sideInset: CGFloat = 16.0
|
let sideInset: CGFloat = 16.0
|
||||||
let buttonSize = CGSize(width: layout.size.width - (sideInset + layout.safeInsets.left) * 2.0, height: 50.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 {
|
if !self.dismissed {
|
||||||
self.mainButtonNode.updateLayout(size: buttonSize, state: self.mainButtonState, transition: transition)
|
self.mainButtonNode.updateLayout(size: buttonSize, state: self.mainButtonState, transition: transition)
|
||||||
}
|
}
|
||||||
if !self.animatingTransition {
|
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
|
return containerFrame.height
|
||||||
|
@ -5,12 +5,16 @@ import Photos
|
|||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
|
||||||
class MediaAssetsContext: NSObject, PHPhotoLibraryChangeObserver {
|
class MediaAssetsContext: NSObject, PHPhotoLibraryChangeObserver {
|
||||||
|
private let assetType: PHAssetMediaType?
|
||||||
|
|
||||||
private var registeredChangeObserver = false
|
private var registeredChangeObserver = false
|
||||||
private let changeSink = ValuePipe<PHChange>()
|
private let changeSink = ValuePipe<PHChange>()
|
||||||
private let mediaAccessSink = ValuePipe<PHAuthorizationStatus>()
|
private let mediaAccessSink = ValuePipe<PHAuthorizationStatus>()
|
||||||
private let cameraAccessSink = ValuePipe<AVAuthorizationStatus?>()
|
private let cameraAccessSink = ValuePipe<AVAuthorizationStatus?>()
|
||||||
|
|
||||||
override init() {
|
init(assetType: PHAssetMediaType?) {
|
||||||
|
self.assetType = assetType
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
if PHPhotoLibrary.authorizationStatus() == .authorized {
|
if PHPhotoLibrary.authorizationStatus() == .authorized {
|
||||||
@ -30,7 +34,12 @@ class MediaAssetsContext: NSObject, PHPhotoLibraryChangeObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func fetchAssets(_ collection: PHAssetCollection) -> Signal<PHFetchResult<PHAsset>, NoError> {
|
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)
|
let fetchResult = Atomic<PHFetchResult<PHAsset>>(value: initialFetchResult)
|
||||||
return .single(initialFetchResult)
|
return .single(initialFetchResult)
|
||||||
|> then(
|
|> then(
|
||||||
|
@ -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])
|
case media([Media])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +243,11 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.presentationData = controller.presentationData
|
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.mediaAssetsContext = mediaAssetsContext
|
||||||
|
|
||||||
self.containerNode = ASDisplayNode()
|
self.containerNode = ASDisplayNode()
|
||||||
@ -253,7 +262,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
if case .assets(nil, false) = controller.subject {
|
if case .assets(nil, .default) = controller.subject {
|
||||||
} else {
|
} else {
|
||||||
self.preloadPromise.set(false)
|
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 enableAnimations = self.controller?.context.sharedContext.energyUsageSettings.fullTranslucency ?? true
|
||||||
|
|
||||||
let cameraView = TGAttachmentCameraView(forSelfPortrait: false, videoModeByDefault: controller.bannedSendPhotos != nil && controller.bannedSendVideos == nil)!
|
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 updateLayout = false
|
||||||
|
|
||||||
var selectable = true
|
var selectable = true
|
||||||
if case let .assets(_, isStandalone) = controller.subject, isStandalone {
|
if case let .assets(_, mode) = controller.subject, mode != .default {
|
||||||
selectable = false
|
selectable = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1229,7 +1238,24 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
private var isDismissing = false
|
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
|
self.context = context
|
||||||
|
|
||||||
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||||
@ -1242,13 +1268,24 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self.bannedSendVideos = bannedSendVideos
|
self.bannedSendVideos = bannedSendVideos
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.saveEditedPhotos = saveEditedPhotos
|
self.saveEditedPhotos = saveEditedPhotos
|
||||||
|
self.mainButtonState = mainButtonState
|
||||||
|
self.mainButtonAction = mainButtonAction
|
||||||
|
|
||||||
let selectionContext = selectionContext ?? TGMediaSelectionContext()
|
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)
|
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 {
|
if case let .assets(collection, mode) = subject {
|
||||||
self.titleView.title = collection.localizedTitle ?? presentationData.strings.Attachment_Gallery
|
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 {
|
} else {
|
||||||
self.titleView.title = presentationData.strings.Attachment_Gallery
|
self.titleView.title = presentationData.strings.Attachment_Gallery
|
||||||
}
|
}
|
||||||
@ -1316,7 +1353,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
self.navigationItem.titleView = self.titleView
|
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))
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||||
} else {
|
} else {
|
||||||
if case let .assets(collection, _) = self.subject, collection != nil {
|
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() {
|
func dismissAllTooltips() {
|
||||||
self.undoOverlayController?.dismissWithCommitAction()
|
self.undoOverlayController?.dismissWithCommitAction()
|
||||||
}
|
}
|
||||||
@ -1674,13 +1715,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func presentSearch(activateOnDisplay: Bool) {
|
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
|
return
|
||||||
}
|
}
|
||||||
self.requestAttachmentMenuExpansion()
|
self.requestAttachmentMenuExpansion()
|
||||||
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
|
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
|
||||||
if let strongSelf = self {
|
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.presentSchedulePicker = strongSelf.presentSchedulePicker
|
||||||
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker
|
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker
|
||||||
@ -1793,21 +1834,17 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var mediaPickerContext: AttachmentMediaPickerContext? {
|
public var mediaPickerContext: AttachmentMediaPickerContext? {
|
||||||
if let interaction = self.interaction {
|
return MediaPickerContext(controller: self)
|
||||||
return MediaPickerContext(interaction: interaction)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class MediaPickerContext: AttachmentMediaPickerContext {
|
final class MediaPickerContext: AttachmentMediaPickerContext {
|
||||||
private weak var interaction: MediaPickerInteraction?
|
private weak var controller: MediaPickerScreen?
|
||||||
|
|
||||||
var selectionCount: Signal<Int, NoError> {
|
var selectionCount: Signal<Int, NoError> {
|
||||||
return Signal { [weak self] subscriber in
|
return Signal { [weak self] subscriber in
|
||||||
let disposable = self?.interaction?.selectionState?.selectionChangedSignal().start(next: { [weak self] value in
|
let disposable = self?.controller?.interaction?.selectionState?.selectionChangedSignal().start(next: { [weak self] value in
|
||||||
subscriber.putNext(Int(self?.interaction?.selectionState?.count() ?? 0))
|
subscriber.putNext(Int(self?.controller?.interaction?.selectionState?.count() ?? 0))
|
||||||
}, error: { _ in }, completed: { })
|
}, error: { _ in }, completed: { })
|
||||||
return ActionDisposable {
|
return ActionDisposable {
|
||||||
disposable?.dispose()
|
disposable?.dispose()
|
||||||
@ -1817,7 +1854,7 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
|
|||||||
|
|
||||||
var caption: Signal<NSAttributedString?, NoError> {
|
var caption: Signal<NSAttributedString?, NoError> {
|
||||||
return Signal { [weak self] subscriber in
|
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 {
|
if let caption = caption as? NSAttributedString {
|
||||||
subscriber.putNext(caption)
|
subscriber.putNext(caption)
|
||||||
} else {
|
} else {
|
||||||
@ -1835,27 +1872,27 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
|
||||||
return .single(nil)
|
return .single(self.controller?.mainButtonState)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(interaction: MediaPickerInteraction) {
|
init(controller: MediaPickerScreen) {
|
||||||
self.interaction = interaction
|
self.controller = controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCaption(_ caption: NSAttributedString) {
|
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) {
|
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() {
|
func schedule() {
|
||||||
self.interaction?.schedule()
|
self.controller?.interaction?.schedule()
|
||||||
}
|
}
|
||||||
|
|
||||||
func mainButtonAction() {
|
func mainButtonAction() {
|
||||||
|
self.controller?.mainButtonPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1968,3 +2005,25 @@ public class MediaPickerGridSelectionGesture<T> : UIPanGestureRecognizer {
|
|||||||
self.updateIsScrollEnabled(true)
|
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
|
||||||
|
}
|
||||||
|
@ -88,7 +88,7 @@ final class MediaPickerTitleView: UIView {
|
|||||||
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: min(300.0, size.width - 36.0)), transition: .immediate)
|
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)
|
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)
|
self.titleNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: floorToScreenPixels((size.height - titleSize.height) / 2.0)), size: titleSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,7 +645,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|
|||||||
price = nil
|
price = nil
|
||||||
}
|
}
|
||||||
let buttonText = presentationData.strings.Premium_Gift_GiftSubscription(price ?? "—").string
|
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() {
|
func buy() {
|
||||||
|
@ -112,6 +112,7 @@ swift_library(
|
|||||||
"//submodules/FeaturedStickersScreen:FeaturedStickersScreen",
|
"//submodules/FeaturedStickersScreen:FeaturedStickersScreen",
|
||||||
"//submodules/MediaPickerUI:MediaPickerUI",
|
"//submodules/MediaPickerUI:MediaPickerUI",
|
||||||
"//submodules/ImageBlur:ImageBlur",
|
"//submodules/ImageBlur:ImageBlur",
|
||||||
|
"//submodules/AttachmentUI:AttachmentUI",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -309,6 +309,9 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
if let node = node {
|
if let node = node {
|
||||||
contentSize.height += node.frame.size.height
|
contentSize.height += node.frame.size.height
|
||||||
}
|
}
|
||||||
|
if item.reaction == nil {
|
||||||
|
contentSize.height += 34.0
|
||||||
|
}
|
||||||
insets = itemListNeighborsGroupedInsets(neighbors, params)
|
insets = itemListNeighborsGroupedInsets(neighbors, params)
|
||||||
|
|
||||||
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||||
@ -333,7 +336,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
|
||||||
|
|
||||||
var topOffset: CGFloat = 16.0
|
var topOffset: CGFloat = 16.0 + 17.0
|
||||||
if let node = node {
|
if let node = node {
|
||||||
strongSelf.messageNode = node
|
strongSelf.messageNode = node
|
||||||
if node.supernode == nil {
|
if node.supernode == nil {
|
||||||
|
@ -9,6 +9,7 @@ import LegacyComponents
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import AttachmentUI
|
||||||
|
|
||||||
private func availableGradients(theme: PresentationTheme) -> [[UInt32]] {
|
private func availableGradients(theme: PresentationTheme) -> [[UInt32]] {
|
||||||
if theme.overallDarkAppearance {
|
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 {
|
public enum Mode {
|
||||||
case `default`
|
case `default`
|
||||||
case peer(EnginePeer)
|
case peer(EnginePeer)
|
||||||
@ -145,14 +146,17 @@ public final class ThemeColorsGridController: ViewController {
|
|||||||
|
|
||||||
private var previousContentOffset: GridNodeVisibleContentOffset?
|
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.context = context
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
self.title = self.presentationData.strings.WallpaperColors_Title
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
self.scrollToTop = { [weak self] in
|
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) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
@ -184,6 +204,14 @@ public final class ThemeColorsGridController: ViewController {
|
|||||||
self.presentationDataDisposable?.dispose()
|
self.presentationDataDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func cancelPressed() {
|
||||||
|
self.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func customPressed() {
|
||||||
|
self.presentColorPicker()
|
||||||
|
}
|
||||||
|
|
||||||
private func updateThemeAndStrings() {
|
private func updateThemeAndStrings() {
|
||||||
self.title = self.presentationData.strings.WallpaperColors_Title
|
self.title = self.presentationData.strings.WallpaperColors_Title
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
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() {
|
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.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
|
}, pop: { [weak self] in
|
||||||
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
||||||
let _ = navigationController.popViewController(animated: true)
|
let _ = navigationController.popViewController(animated: true)
|
||||||
}
|
}
|
||||||
}, presentColorPicker: { [weak self] in
|
}, presentColorPicker: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let _ = (strongSelf.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings])
|
strongSelf.presentColorPicker()
|
||||||
|> 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)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let transitionOffset: CGFloat
|
||||||
|
switch self.mode {
|
||||||
|
case .default:
|
||||||
|
transitionOffset = 30.0
|
||||||
|
case .peer:
|
||||||
|
transitionOffset = 2.0
|
||||||
|
}
|
||||||
|
|
||||||
self.controllerNode.gridNode.visibleContentOffsetChanged = { [weak self] offset in
|
self.controllerNode.gridNode.visibleContentOffsetChanged = { [weak self] offset in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var previousContentOffsetValue: CGFloat?
|
var previousContentOffsetValue: CGFloat?
|
||||||
@ -253,12 +293,12 @@ public final class ThemeColorsGridController: ViewController {
|
|||||||
switch offset {
|
switch offset {
|
||||||
case let .known(value):
|
case let .known(value):
|
||||||
let transition: ContainedViewLayoutTransition
|
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)
|
transition = .animated(duration: 0.2, curve: .easeInOut)
|
||||||
} else {
|
} else {
|
||||||
transition = .immediate
|
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:
|
case .unknown, .none:
|
||||||
strongSelf.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
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)
|
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
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
let ready = ValuePromise<Bool>()
|
let ready = ValuePromise<Bool>()
|
||||||
|
|
||||||
private var backgroundNode: ASDisplayNode
|
private var topBackgroundNode: ASDisplayNode
|
||||||
private var separatorNode: ASDisplayNode
|
private var separatorNode: ASDisplayNode
|
||||||
|
|
||||||
private let customColorItemNode: ItemListActionItemNode
|
private let customColorItemNode: ItemListActionItemNode
|
||||||
@ -102,8 +102,8 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
|||||||
self.rightOverlayNode = ASDisplayNode()
|
self.rightOverlayNode = ASDisplayNode()
|
||||||
self.rightOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
self.rightOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
||||||
|
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.topBackgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
self.topBackgroundNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
||||||
|
|
||||||
self.separatorNode = ASDisplayNode()
|
self.separatorNode = ASDisplayNode()
|
||||||
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
@ -121,9 +121,14 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
|
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
|
|
||||||
self.gridNode.addSubnode(self.backgroundNode)
|
if case .default = controller.mode {
|
||||||
self.gridNode.addSubnode(self.separatorNode)
|
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
self.gridNode.addSubnode(self.customColorItemNode)
|
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)
|
self.addSubnode(self.gridNode)
|
||||||
|
|
||||||
let previousEntries = Atomic<[ThemeColorsGridControllerEntry]?>(value: nil)
|
let previousEntries = Atomic<[ThemeColorsGridControllerEntry]?>(value: nil)
|
||||||
@ -240,9 +245,13 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
|||||||
func updatePresentationData(_ presentationData: PresentationData) {
|
func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
|
if let controller = self.controller, case .default = controller.mode {
|
||||||
self.leftOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
self.rightOverlayNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
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.customColorItem = ItemListActionItem(presentationData: ItemListPresentationData(presentationData), title: presentationData.strings.WallpaperColors_SetCustomColor, kind: .generic, alignment: .natural, sectionId: 0, style: .blocks, action: { [weak self] in
|
||||||
self?.presentColorPicker()
|
self?.presentColorPicker()
|
||||||
@ -272,6 +281,9 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
guard let controller = self.controller else {
|
||||||
|
return
|
||||||
|
}
|
||||||
let hadValidLayout = self.validLayout != nil
|
let hadValidLayout = self.validLayout != nil
|
||||||
|
|
||||||
var insets = layout.insets(options: [.input])
|
var insets = layout.insets(options: [.input])
|
||||||
@ -280,7 +292,18 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
|||||||
insets.right = layout.safeInsets.right
|
insets.right = layout.safeInsets.right
|
||||||
let scrollIndicatorInsets = insets
|
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 referenceImageSize: CGSize
|
||||||
let screenWidth = min(layout.size.width, layout.size.height)
|
let screenWidth = min(layout.size.width, layout.size.height)
|
||||||
if screenWidth >= 375.0 {
|
if screenWidth >= 375.0 {
|
||||||
@ -288,29 +311,56 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
referenceImageSize = CGSize(width: 91.0, height: 91.0)
|
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 width = layout.size.width - layout.safeInsets.left - layout.safeInsets.right
|
||||||
let spacing = floor((layout.size.width - CGFloat(imageCount) * imageSize.width) / CGFloat(imageCount + 1))
|
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
|
var listInsets = insets
|
||||||
if layout.size.width >= 375.0 {
|
if case .default = controller.mode {
|
||||||
let inset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
|
if layout.size.width >= 375.0 {
|
||||||
listInsets.left += inset
|
let inset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
|
||||||
listInsets.right += inset
|
listInsets.left += inset
|
||||||
|
listInsets.right += inset
|
||||||
if self.leftOverlayNode.supernode == nil {
|
|
||||||
self.gridNode.addSubnode(self.leftOverlayNode)
|
if self.leftOverlayNode.supernode == nil {
|
||||||
}
|
self.gridNode.addSubnode(self.leftOverlayNode)
|
||||||
if self.rightOverlayNode.supernode == nil {
|
}
|
||||||
self.gridNode.addSubnode(self.rightOverlayNode)
|
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 {
|
} else {
|
||||||
if self.leftOverlayNode.supernode != nil {
|
self.customColorItemNode.isHidden = true
|
||||||
self.leftOverlayNode.removeFromSupernode()
|
buttonOffset = 0.0
|
||||||
}
|
buttonInset = 0.0
|
||||||
if self.rightOverlayNode.supernode != nil {
|
|
||||||
self.rightOverlayNode.removeFromSupernode()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let makeColorLayout = self.customColorItemNode.asyncLayout()
|
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))
|
let (colorLayout, colorApply) = makeColorLayout(self.customColorItem, params, ItemListNeighbors(top: .none, bottom: .none))
|
||||||
colorApply()
|
colorApply()
|
||||||
|
|
||||||
let buttonTopInset: CGFloat = 32.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)))
|
||||||
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.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -buttonOffset + buttonInset - UIScreenPixel), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
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))
|
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
|
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)
|
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.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.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)
|
self.customColorItemNode.layer.animatePosition(from: self.customColorItemNode.layer.position.offsetBy(dx: 0.0, dy: -offset), to: self.customColorItemNode.layer.position, duration: duration)
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ public final class ThemeGridController: ViewController {
|
|||||||
}
|
}
|
||||||
}, presentGallery: { [weak self] in
|
}, presentGallery: { [weak self] in
|
||||||
if let strongSelf = self {
|
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
|
controller.customSelection = { [weak self] asset in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
@ -3405,6 +3405,22 @@ func replayFinalState(
|
|||||||
for (space, _) in holesAtHistoryStart {
|
for (space, _) in holesAtHistoryStart {
|
||||||
transaction.removeHole(peerId: chatPeerId, threadId: nil, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id)
|
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:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -13826,7 +13826,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.present(actionSheet, in: .window(.root))
|
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 {
|
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -18511,7 +18511,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let dismissControllers = { [weak self] in
|
let dismissControllers = { [weak self] in
|
||||||
if let self, let navigationController = self.navigationController as? NavigationController {
|
if let self, let navigationController = self.navigationController as? NavigationController {
|
||||||
let controllers = navigationController.viewControllers.filter({ controller in
|
let controllers = navigationController.viewControllers.filter({ controller in
|
||||||
if controller is WallpaperGalleryController || controller is MediaPickerScreen {
|
if controller is WallpaperGalleryController || controller is AttachmentController {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
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))
|
var canDelete = false
|
||||||
controller.navigationPresentation = .modal
|
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData {
|
||||||
controller.customSelection = { [weak self] asset in
|
canDelete = cachedUserData.wallpaper != nil
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
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)
|
strongSelf.push(controller)
|
||||||
},
|
},
|
||||||
changeColor: {
|
changeColor: {
|
||||||
@ -18547,8 +18556,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.themeScreen = nil
|
strongSelf.themeScreen = nil
|
||||||
themeController.dimTapped()
|
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)
|
strongSelf.push(controller)
|
||||||
},
|
},
|
||||||
completion: { [weak self] emoticon in
|
completion: { [weak self] emoticon in
|
||||||
|
@ -675,7 +675,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
let isLoading = json["is_progress_visible"] as? Bool
|
let isLoading = json["is_progress_visible"] as? Bool
|
||||||
let isEnabled = json["is_active"] 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
|
self.mainButtonState = state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user