Various improvements

This commit is contained in:
Ilya Laktyushin 2023-12-17 19:30:38 +04:00
parent 8f51eec89b
commit 3314a18165
43 changed files with 669 additions and 483 deletions

View File

@ -10641,10 +10641,6 @@ Sorry for the inconvenience.";
"Story.ViewList.TitleReactions" = "Reactions"; "Story.ViewList.TitleReactions" = "Reactions";
"Wallpaper.ApplyForChannel" = "Apply For This Channel";
"Notification.ChannelChangedWallpaper" = "Channel set a new wallpaper";
"Chat.Giveaway.Message.WinnersSelectedTitle.One" = "Winner Selected!"; "Chat.Giveaway.Message.WinnersSelectedTitle.One" = "Winner Selected!";
"Chat.Giveaway.Message.WinnersSelectedTitle.Many" = "Winners Selected!"; "Chat.Giveaway.Message.WinnersSelectedTitle.Many" = "Winners Selected!";
"Chat.Giveaway.Message.WinnersSelectedText_1" = "**%@** winner of the [Giveaway]() was randomly selected by Telegram."; "Chat.Giveaway.Message.WinnersSelectedText_1" = "**%@** winner of the [Giveaway]() was randomly selected by Telegram.";
@ -10751,3 +10747,15 @@ Sorry for the inconvenience.";
"ChannelBoost.CustomWallpaper" = "Set Custom Channel Background"; "ChannelBoost.CustomWallpaper" = "Set Custom Channel Background";
"ChannelBoost.EnableCustomWallpaperLevelText" = "Your channel needs **Level %1$@** to set custom channel background."; "ChannelBoost.EnableCustomWallpaperLevelText" = "Your channel needs **Level %1$@** to set custom channel background.";
"WallpaperPreview.ChannelHeader" = "All subscribers will see this wallpaper";
"WallpaperPreview.ChannelTopText" = "Details to follow shortly.\nStay tuned!";
"WallpaperPreview.ChannelReplyText" = "Breaking News";
"Wallpaper.ApplyForChannel" = "Apply Background";
"Notification.ChannelChangedWallpaper" = "Channel set a new wallpaper";
"Story.MessageReposted.Personal" = "Message reposted to your stories.";
"Story.MessageReposted.Channel" = "Message reposted to **%@**.";
"Story.Views.Commented" = " • commented";

View File

@ -462,6 +462,11 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin
} else { } else {
minSize.width += sideInset minSize.width += sideInset
} }
if self.item.additionalLeftIcon != nil {
minSize.width += 24.0
minSize.width += iconSideInset
minSize.width += iconSpacing
}
if let forcedHeight { if let forcedHeight {
minSize.height = forcedHeight minSize.height = forcedHeight
} else { } else {

View File

@ -2,10 +2,12 @@ import Foundation
import UIKit import UIKit
import Display import Display
import SwiftSignalKit import SwiftSignalKit
import TelegramCore
import LegacyComponents import LegacyComponents
import TelegramPresentationData import TelegramPresentationData
import DeviceAccess import DeviceAccess
import AccountContext import AccountContext
import LocalMediaResources
public func legacyWallpaperPicker(context: AccountContext, presentationData: PresentationData, subject: DeviceAccessMediaLibrarySubject = .wallpaper) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> { public func legacyWallpaperPicker(context: AccountContext, presentationData: PresentationData, subject: DeviceAccessMediaLibrarySubject = .wallpaper) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> {
return Signal { subscriber in return Signal { subscriber in
@ -45,3 +47,76 @@ public func legacyWallpaperPicker(context: AccountContext, presentationData: Pre
} }
} }
} }
public class LegacyWallpaperItem: NSObject, TGMediaEditableItem, TGMediaSelectableItem {
public var isVideo: Bool {
return false
}
public var uniqueIdentifier: String! {
return self.asset.localIdentifier
}
let asset: PHAsset
let screenImage: UIImage
private(set) var thumbnailResource: TelegramMediaResource?
private(set) var imageResource: TelegramMediaResource?
let dimensions: CGSize
public init(asset: PHAsset, screenImage: UIImage, dimensions: CGSize) {
self.asset = asset
self.screenImage = screenImage
self.dimensions = dimensions
}
public var originalSize: CGSize {
return self.dimensions
}
public func thumbnailImageSignal() -> SSignal! {
return SSignal.complete()
// return SSignal(generator: { subscriber -> SDisposable? in
// let disposable = self.thumbnailImage.start(next: { image in
// subscriber.putNext(image)
// subscriber.putCompletion()
// })
//
// return SBlockDisposable(block: {
// disposable.dispose()
// })
// })
}
public func screenImageSignal(_ position: TimeInterval) -> SSignal! {
return SSignal.single(self.screenImage)
}
public var originalImage: Signal<UIImage, NoError> {
return fetchPhotoLibraryImage(localIdentifier: self.asset.localIdentifier, thumbnail: false)
|> filter { value in
return !(value?.1 ?? true)
}
|> mapToSignal { result -> Signal<UIImage, NoError> in
if let result = result {
return .single(result.0)
} else {
return .complete()
}
}
}
public func originalImageSignal(_ position: TimeInterval) -> SSignal! {
return SSignal(generator: { subscriber -> SDisposable? in
let disposable = self.originalImage.start(next: { image in
subscriber.putNext(image)
if !image.degraded() {
subscriber.putCompletion()
}
})
return SBlockDisposable(block: {
disposable.dispose()
})
})
}
}

View File

@ -239,7 +239,7 @@ public func PremiumBoostScreen(
let controller = context.sharedContext.makePremiumGiftController(context: context) let controller = context.sharedContext.makePremiumGiftController(context: context)
pushController(controller) pushController(controller)
}), }),
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Close, action: {}) TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Close, action: {})
], ],
actionLayout: .vertical, actionLayout: .vertical,
parseMarkdown: true parseMarkdown: true

View File

@ -119,6 +119,8 @@ swift_library(
"//submodules/TelegramUI/Components/Settings/QuickReactionSetupController", "//submodules/TelegramUI/Components/Settings/QuickReactionSetupController",
"//submodules/TelegramUI/Components/Settings/ThemeCarouselItem", "//submodules/TelegramUI/Components/Settings/ThemeCarouselItem",
"//submodules/TelegramUI/Components/Settings/ThemeSettingsThemeItem", "//submodules/TelegramUI/Components/Settings/ThemeSettingsThemeItem",
"//submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen",
"//submodules/TelegramUI/Components/Settings/SettingsThemeWallpaperNode",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -12,6 +12,7 @@ import LegacyUI
import LegacyMediaPickerUI import LegacyMediaPickerUI
import LocalMediaResources import LocalMediaResources
import ImageBlur import ImageBlur
import WallpaperGalleryScreen
func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (ViewController) -> Void, push: @escaping (ViewController) -> Void) { func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (ViewController) -> Void, push: @escaping (ViewController) -> Void) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -318,77 +319,3 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
return croppedImage return croppedImage
}).start() }).start()
} }
class LegacyWallpaperItem: NSObject, TGMediaEditableItem, TGMediaSelectableItem {
var isVideo: Bool {
return false
}
var uniqueIdentifier: String! {
return self.asset.localIdentifier
}
let asset: PHAsset
let screenImage: UIImage
private(set) var thumbnailResource: TelegramMediaResource?
private(set) var imageResource: TelegramMediaResource?
let dimensions: CGSize
init(asset: PHAsset, screenImage: UIImage, dimensions: CGSize) {
self.asset = asset
self.screenImage = screenImage
self.dimensions = dimensions
}
var originalSize: CGSize {
return self.dimensions
}
func thumbnailImageSignal() -> SSignal! {
return SSignal.complete()
// return SSignal(generator: { subscriber -> SDisposable? in
// let disposable = self.thumbnailImage.start(next: { image in
// subscriber.putNext(image)
// subscriber.putCompletion()
// })
//
// return SBlockDisposable(block: {
// disposable.dispose()
// })
// })
}
func screenImageSignal(_ position: TimeInterval) -> SSignal! {
return SSignal.single(self.screenImage)
}
var originalImage: Signal<UIImage, NoError> {
return fetchPhotoLibraryImage(localIdentifier: self.asset.localIdentifier, thumbnail: false)
|> filter { value in
return !(value?.1 ?? true)
}
|> mapToSignal { result -> Signal<UIImage, NoError> in
if let result = result {
return .single(result.0)
} else {
return .complete()
}
}
}
func originalImageSignal(_ position: TimeInterval) -> SSignal! {
return SSignal(generator: { subscriber -> SDisposable? in
let disposable = self.originalImage.start(next: { image in
subscriber.putNext(image)
if !image.degraded() {
subscriber.putCompletion()
}
})
return SBlockDisposable(block: {
disposable.dispose()
})
})
}
}

View File

@ -10,6 +10,7 @@ import TelegramUIPreferences
import AccountContext import AccountContext
import PresentationDataUtils import PresentationDataUtils
import MediaResources import MediaResources
import WallpaperGalleryScreen
private let randomBackgroundColors: [Int32] = [0x007aff, 0x00c2ed, 0x29b327, 0xeb6ca4, 0xf08200, 0x9472ee, 0xd33213, 0xedb400, 0x6d839e] private let randomBackgroundColors: [Int32] = [0x007aff, 0x00c2ed, 0x29b327, 0xeb6ca4, 0xf08200, 0x9472ee, 0xd33213, 0xedb400, 0x6d839e]

View File

@ -14,6 +14,7 @@ import PresentationDataUtils
import WallpaperBackgroundNode import WallpaperBackgroundNode
import AnimationCache import AnimationCache
import MultiAnimationRenderer import MultiAnimationRenderer
import WallpaperGalleryScreen
private func generateMaskImage(color: UIColor) -> UIImage? { private func generateMaskImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in

View File

@ -9,6 +9,7 @@ import TelegramPresentationData
import TelegramUIPreferences import TelegramUIPreferences
import AccountContext import AccountContext
import AttachmentUI import AttachmentUI
import WallpaperGalleryScreen
private func availableGradients(dark: Bool) -> [[UInt32]] { private func availableGradients(dark: Bool) -> [[UInt32]] {
if dark { if dark {

View File

@ -6,6 +6,7 @@ import SwiftSignalKit
import AsyncDisplayKit import AsyncDisplayKit
import AccountContext import AccountContext
import GridMessageSelectionNode import GridMessageSelectionNode
import SettingsThemeWallpaperNode
final class ThemeColorsGridControllerItem: GridItem { final class ThemeColorsGridControllerItem: GridItem {
let context: AccountContext let context: AccountContext

View File

@ -9,6 +9,7 @@ import MergeLists
import ItemListUI import ItemListUI
import PresentationDataUtils import PresentationDataUtils
import AccountContext import AccountContext
import WallpaperGalleryScreen
final class ThemeColorsGridControllerInteraction { final class ThemeColorsGridControllerInteraction {
let openWallpaper: (TelegramWallpaper) -> Void let openWallpaper: (TelegramWallpaper) -> Void

View File

@ -15,6 +15,7 @@ import SearchUI
import HexColor import HexColor
import PresentationDataUtils import PresentationDataUtils
import MediaPickerUI import MediaPickerUI
import WallpaperGalleryScreen
public final class ThemeGridController: ViewController { public final class ThemeGridController: ViewController {
private var controllerNode: ThemeGridControllerNode { private var controllerNode: ThemeGridControllerNode {

View File

@ -7,6 +7,7 @@ import AsyncDisplayKit
import Postbox import Postbox
import AccountContext import AccountContext
import GridMessageSelectionNode import GridMessageSelectionNode
import SettingsThemeWallpaperNode
final class ThemeGridControllerItem: GridItem { final class ThemeGridControllerItem: GridItem {
let context: AccountContext let context: AccountContext

View File

@ -15,6 +15,7 @@ import AccountContext
import SearchBarNode import SearchBarNode
import SearchUI import SearchUI
import WallpaperResources import WallpaperResources
import WallpaperGalleryScreen
struct ThemeGridControllerNodeState: Equatable { struct ThemeGridControllerNodeState: Equatable {
var editing: Bool var editing: Bool

View File

@ -14,6 +14,7 @@ import LegacyComponents
import WallpaperBackgroundNode import WallpaperBackgroundNode
import AnimationCache import AnimationCache
import MultiAnimationRenderer import MultiAnimationRenderer
import WallpaperGalleryScreen
private func generateMaskImage(color: UIColor) -> UIImage? { private func generateMaskImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in

View File

@ -417,6 +417,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatQrCodeScreen", "//submodules/TelegramUI/Components/Chat/ChatQrCodeScreen",
"//submodules/UIKitRuntimeUtils", "//submodules/UIKitRuntimeUtils",
"//submodules/TelegramUI/Components/SavedMessages/SavedMessagesScreen", "//submodules/TelegramUI/Components/SavedMessages/SavedMessagesScreen",
"//submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen",
] + select({ ] + select({
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
"//build-system:ios_sim_arm64": [], "//build-system:ios_sim_arm64": [],

View File

@ -580,7 +580,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
var viewCount: Int? var viewCount: Int?
var dateReplies = 0 var dateReplies = 0
var dateReactionsAndPeers = mergedMessageReactionsAndPeers(accountPeer: associatedData.accountPeer, message: message) var dateReactionsAndPeers = mergedMessageReactionsAndPeers(accountPeer: associatedData.accountPeer, message: message)
if message.isRestricted(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) { if message.isRestricted(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) || presentationData.isPreview {
dateReactionsAndPeers = ([], []) dateReactionsAndPeers = ([], [])
} }
for attribute in message.attributes { for attribute in message.attributes {

View File

@ -531,7 +531,6 @@ private final class PeerInfoInteraction {
let performBotCommand: (PeerInfoBotCommand) -> Void let performBotCommand: (PeerInfoBotCommand) -> Void
let editingOpenPublicLinkSetup: () -> Void let editingOpenPublicLinkSetup: () -> Void
let editingOpenNameColorSetup: () -> Void let editingOpenNameColorSetup: () -> Void
let editingOpenPeerWallpaperSetup: () -> Void
let editingOpenInviteLinksSetup: () -> Void let editingOpenInviteLinksSetup: () -> Void
let editingOpenDiscussionGroupSetup: () -> Void let editingOpenDiscussionGroupSetup: () -> Void
let editingToggleMessageSignatures: (Bool) -> Void let editingToggleMessageSignatures: (Bool) -> Void
@ -587,7 +586,6 @@ private final class PeerInfoInteraction {
performBotCommand: @escaping (PeerInfoBotCommand) -> Void, performBotCommand: @escaping (PeerInfoBotCommand) -> Void,
editingOpenPublicLinkSetup: @escaping () -> Void, editingOpenPublicLinkSetup: @escaping () -> Void,
editingOpenNameColorSetup: @escaping () -> Void, editingOpenNameColorSetup: @escaping () -> Void,
editingOpenPeerWallpaperSetup: @escaping () -> Void,
editingOpenInviteLinksSetup: @escaping () -> Void, editingOpenInviteLinksSetup: @escaping () -> Void,
editingOpenDiscussionGroupSetup: @escaping () -> Void, editingOpenDiscussionGroupSetup: @escaping () -> Void,
editingToggleMessageSignatures: @escaping (Bool) -> Void, editingToggleMessageSignatures: @escaping (Bool) -> Void,
@ -642,7 +640,6 @@ private final class PeerInfoInteraction {
self.performBotCommand = performBotCommand self.performBotCommand = performBotCommand
self.editingOpenPublicLinkSetup = editingOpenPublicLinkSetup self.editingOpenPublicLinkSetup = editingOpenPublicLinkSetup
self.editingOpenNameColorSetup = editingOpenNameColorSetup self.editingOpenNameColorSetup = editingOpenNameColorSetup
self.editingOpenPeerWallpaperSetup = editingOpenPeerWallpaperSetup
self.editingOpenInviteLinksSetup = editingOpenInviteLinksSetup self.editingOpenInviteLinksSetup = editingOpenInviteLinksSetup
self.editingOpenDiscussionGroupSetup = editingOpenDiscussionGroupSetup self.editingOpenDiscussionGroupSetup = editingOpenDiscussionGroupSetup
self.editingToggleMessageSignatures = editingToggleMessageSignatures self.editingToggleMessageSignatures = editingToggleMessageSignatures
@ -1581,7 +1578,6 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
case .broadcast: case .broadcast:
let ItemUsername = 1 let ItemUsername = 1
let ItemPeerColor = 2 let ItemPeerColor = 2
let ItemPeerWallpaper = 3
let ItemInviteLinks = 4 let ItemInviteLinks = 4
let ItemDiscussionGroup = 5 let ItemDiscussionGroup = 5
let ItemSignMessages = 6 let ItemSignMessages = 6
@ -1683,10 +1679,6 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerColor, label: .image(colorImage, colorImage.size), additionalBadgeIcon: boostIcon, text: "Appearance", icon: UIImage(bundleImageName: "Chat/Info/NameColorIcon"), action: { items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerColor, label: .image(colorImage, colorImage.size), additionalBadgeIcon: boostIcon, text: "Appearance", icon: UIImage(bundleImageName: "Chat/Info/NameColorIcon"), action: {
interaction.editingOpenNameColorSetup() interaction.editingOpenNameColorSetup()
})) }))
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerWallpaper, label: .none, text: "Wallpaper", icon: UIImage(bundleImageName: "Settings/Menu/Appearance"), action: {
interaction.editingOpenPeerWallpaperSetup()
}))
} }
if isCreator || (channel.adminRights != nil && channel.hasPermission(.sendSomething)) { if isCreator || (channel.adminRights != nil && channel.hasPermission(.sendSomething)) {
@ -2364,9 +2356,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
editingOpenNameColorSetup: { [weak self] in editingOpenNameColorSetup: { [weak self] in
self?.editingOpenNameColorSetup() self?.editingOpenNameColorSetup()
}, },
editingOpenPeerWallpaperSetup: { [weak self] in
self?.editingOpenPeerWallpaperSetup()
},
editingOpenInviteLinksSetup: { [weak self] in editingOpenInviteLinksSetup: { [weak self] in
self?.editingOpenInviteLinksSetup() self?.editingOpenInviteLinksSetup()
}, },
@ -7209,80 +7198,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
self.controller?.push(ChannelAppearanceScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId)) self.controller?.push(ChannelAppearanceScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId))
} }
} }
private func editingOpenPeerWallpaperSetup() {
// let link = status.url
// let controller = PremiumLimitScreen(context: context, subject: .storiesChannelBoost(peer: peer, boostSubject: .nameColors, isCurrent: true, level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), link: link, myBoostCount: 0, canBoostAgain: false), count: Int32(status.boosts), action: {
// UIPasteboard.general.string = link
// let presentationData = context.sharedContext.currentPresentationData.with { $0 }
// presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }))
// return true
// }, openStats: nil, openGift: premiumConfiguration.giveawayGiftsPurchaseAvailable ? {
// let controller = createGiveawayController(context: context, peerId: peerId, subject: .generic)
// pushImpl?(controller)
// } : nil)
// pushImpl?(controller)
let dismissControllers = { [weak self] in
if let self, let navigationController = self.controller?.navigationController as? NavigationController {
let controllers = navigationController.viewControllers.filter({ controller in
if controller is WallpaperGalleryController || controller is AttachmentController || controller is PeerInfoScreenImpl {
return false
}
return true
})
navigationController.setViewControllers(controllers, animated: true)
}
}
var openWallpaperPickerImpl: ((Bool) -> Void)?
let openWallpaperPicker: (Bool) -> Void = { [weak self] animateAppearance in
guard let self, let peer = self.data?.peer else {
return
}
let controller = wallpaperMediaPickerController(
context: self.context,
updatedPresentationData: self.controller?.updatedPresentationData,
peer: EnginePeer(peer),
animateAppearance: true,
completion: { [weak self] _, result in
guard let strongSelf = self, let asset = result as? PHAsset 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, editedImage, cropRect, brightness, forBoth in
if let strongSelf = self {
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, editedImage: editedImage, cropRect: cropRect, brightness: brightness, peerId: peer.id, forBoth: forBoth, completion: {
Queue.mainQueue().after(0.3, {
dismissControllers()
})
})
}
}
strongSelf.controller?.push(controller)
},
openColors: { [weak self] in
guard let strongSelf = self else {
return
}
let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), push: { [weak self] controller in
if let strongSelf = self {
strongSelf.controller?.push(controller)
}
}, openGallery: {
openWallpaperPickerImpl?(false)
})
controller.navigationPresentation = .flatModal
strongSelf.controller?.push(controller)
}
)
controller.navigationPresentation = .flatModal
self.controller?.push(controller)
}
openWallpaperPickerImpl = openWallpaperPicker
openWallpaperPicker(true)
}
private func editingOpenInviteLinksSetup() { private func editingOpenInviteLinksSetup() {
self.controller?.push(inviteLinkListController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, admin: nil)) self.controller?.push(inviteLinkListController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, admin: nil))
} }

View File

@ -43,6 +43,8 @@ swift_library(
"//submodules/TelegramUI/Components/DynamicCornerRadiusView", "//submodules/TelegramUI/Components/DynamicCornerRadiusView",
"//submodules/Components/ComponentDisplayAdapters", "//submodules/Components/ComponentDisplayAdapters",
"//submodules/WallpaperResources", "//submodules/WallpaperResources",
"//submodules/MediaPickerUI",
"//submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import UIKit import UIKit
import Photos
import Display import Display
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit
@ -29,6 +30,8 @@ import EmojiStatusComponent
import DynamicCornerRadiusView import DynamicCornerRadiusView
import ComponentDisplayAdapters import ComponentDisplayAdapters
import WallpaperResources import WallpaperResources
import MediaPickerUI
import WallpaperGalleryScreen
private final class EmojiActionIconComponent: Component { private final class EmojiActionIconComponent: Component {
let context: AccountContext let context: AccountContext
@ -590,6 +593,58 @@ final class ChannelAppearanceScreenComponent: Component {
self.environment?.controller()?.push(statsController) self.environment?.controller()?.push(statsController)
} }
private func openCustomWallpaperSetup() {
guard let _ = self.component, let contentsData = self.contentsData else {
return
}
// let dismissControllers = { [weak self] in
// if let self, let navigationController = self.controller?.navigationController as? NavigationController {
// let controllers = navigationController.viewControllers.filter({ controller in
// if controller is WallpaperGalleryController || controller is AttachmentController || controller is PeerInfoScreenImpl {
// return false
// }
// return true
// })
// navigationController.setViewControllers(controllers, animated: true)
// }
// }
// var openWallpaperPickerImpl: ((Bool) -> Void)?
let openWallpaperPicker: (Bool) -> Void = { [weak self] animateAppearance in
guard let self, let component = self.component, let peer = contentsData.peer else {
return
}
let controller = wallpaperMediaPickerController(
context: component.context,
updatedPresentationData: nil,
peer: peer,
animateAppearance: true,
completion: { [weak self] _, result in
guard let self, let component = self.component, let asset = result as? PHAsset else {
return
}
let controller = WallpaperGalleryController(context: component.context, source: .asset(asset), mode: .peer(peer, false))
controller.navigationPresentation = .modal
controller.apply = { wallpaper, options, editedImage, cropRect, brightness, forBoth in
// if let strongSelf = self {
// uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, editedImage: editedImage, cropRect: cropRect, brightness: brightness, peerId: peer.id, forBoth: forBoth, completion: {
// Queue.mainQueue().after(0.3, {
// dismissControllers()
// })
// })
// }
}
self.environment?.controller()?.push(controller)
},
openColors: {
}
)
controller.navigationPresentation = .flatModal
self.environment?.controller()?.push(controller)
}
// openWallpaperPickerImpl = openWallpaperPicker
openWallpaperPicker(true)
}
private enum EmojiSetupSubject { private enum EmojiSetupSubject {
case reply case reply
case profile case profile
@ -1055,7 +1110,7 @@ final class ChannelAppearanceScreenComponent: Component {
guard let self else { guard let self else {
return return
} }
let _ = self self.openCustomWallpaperSetup()
} }
))) )))
] ]

View File

@ -0,0 +1,27 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "SettingsThemeWallpaperNode",
module_name = "SettingsThemeWallpaperNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/AsyncDisplayKit",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/GradientBackground",
"//submodules/WallpaperResources",
"//submodules/AccountContext",
"//submodules/RadialStatusNode",
],
visibility = [
"//visibility:public",
],
)

View File

@ -42,17 +42,17 @@ private let blackColorImage: UIImage? = {
return context.generateImage() return context.generateImage()
}() }()
final class SettingsThemeWallpaperNode: ASDisplayNode { public final class SettingsThemeWallpaperNode: ASDisplayNode {
var wallpaper: TelegramWallpaper? public var wallpaper: TelegramWallpaper?
private var arguments: PatternWallpaperArguments? private var arguments: PatternWallpaperArguments?
let buttonNode = HighlightTrackingButtonNode() public let buttonNode = HighlightTrackingButtonNode()
let backgroundNode = ASImageNode() public let backgroundNode = ASImageNode()
let imageNode = TransformImageNode() public let imageNode = TransformImageNode()
private var gradientNode: GradientBackgroundNode? private var gradientNode: GradientBackgroundNode?
private let statusNode: RadialStatusNode private let statusNode: RadialStatusNode
var pressed: (() -> Void)? public var pressed: (() -> Void)?
private let displayLoading: Bool private let displayLoading: Bool
private var isSelected: Bool = false private var isSelected: Bool = false
@ -60,7 +60,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
private let isLoadedDisposable = MetaDisposable() private let isLoadedDisposable = MetaDisposable()
init(displayLoading: Bool = false, overlayBackgroundColor: UIColor = UIColor(white: 0.0, alpha: 0.3)) { public init(displayLoading: Bool = false, overlayBackgroundColor: UIColor = UIColor(white: 0.0, alpha: 0.3)) {
self.displayLoading = displayLoading self.displayLoading = displayLoading
self.imageNode.contentAnimations = [.subsequentUpdates] self.imageNode.contentAnimations = [.subsequentUpdates]
@ -83,7 +83,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
self.isLoadedDisposable.dispose() self.isLoadedDisposable.dispose()
} }
func setSelected(_ selected: Bool, animated: Bool = false) { public func setSelected(_ selected: Bool, animated: Bool = false) {
if self.isSelected != selected { if self.isSelected != selected {
self.isSelected = selected self.isSelected = selected
@ -110,11 +110,11 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
} }
} }
func setOverlayBackgroundColor(_ color: UIColor) { public func setOverlayBackgroundColor(_ color: UIColor) {
self.statusNode.backgroundNodeColor = color self.statusNode.backgroundNodeColor = color
} }
func setWallpaper(context: AccountContext, wallpaper: TelegramWallpaper, selected: Bool, size: CGSize, cornerRadius: CGFloat = 0.0, synchronousLoad: Bool = false) { public func setWallpaper(context: AccountContext, wallpaper: TelegramWallpaper, selected: Bool, size: CGSize, cornerRadius: CGFloat = 0.0, synchronousLoad: Bool = false) {
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size) self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size) self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size)
self.imageNode.frame = CGRect(origin: CGPoint(), size: size) self.imageNode.frame = CGRect(origin: CGPoint(), size: size)

View File

@ -0,0 +1,38 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "WallpaperGalleryScreen",
module_name = "WallpaperGalleryScreen",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/TelegramPresentationData",
"//submodules/AccountContext",
"//submodules/PresentationDataUtils",
"//submodules/WallpaperBackgroundNode",
"//submodules/ComponentFlow",
"//submodules/SolidRoundedButtonNode",
"//submodules/AppBundle",
"//submodules/PremiumUI",
"//submodules/WallpaperResources",
"//submodules/HexColor",
"//submodules/MergeLists",
"//submodules/ShareController",
"//submodules/GalleryUI",
"//submodules/CounterContollerTitleView",
"//submodules/LegacyMediaPickerUI",
"//submodules/TelegramUI/Components/Settings/SettingsThemeWallpaperNode",
],
visibility = [
"//visibility:public",
],
)

View File

@ -56,8 +56,8 @@ private class BlurLayer: CALayer {
} }
} }
class BlurView: UIView { public class BlurView: UIView {
override class var layerClass : AnyClass { public override class var layerClass : AnyClass {
return BlurLayer.self return BlurLayer.self
} }
@ -71,7 +71,7 @@ class BlurView: UIView {
return Queue(name: nil, qos: .userInteractive) return Queue(name: nil, qos: .userInteractive)
}() }()
open var blurRadius: CGFloat { public var blurRadius: CGFloat {
set { self.blurLayer.blurRadius = newValue } set { self.blurLayer.blurRadius = newValue }
get { return self.blurLayer.blurRadius } get { return self.blurLayer.blurRadius }
} }
@ -104,7 +104,7 @@ class BlurView: UIView {
} }
} }
override func display(_ layer: CALayer) { public override func display(_ layer: CALayer) {
let blurRadius = self.blurLayer.presentationRadius let blurRadius = self.blurLayer.presentationRadius
if let image = self.image { if let image = self.image {
self.draw(image, blurRadius: blurRadius) self.draw(image, blurRadius: blurRadius)
@ -112,19 +112,19 @@ class BlurView: UIView {
} }
} }
final class BlurredImageNode: ASDisplayNode { public final class BlurredImageNode: ASDisplayNode {
var image: UIImage? { public var image: UIImage? {
didSet { didSet {
self.blurView.image = self.image self.blurView.image = self.image
self.blurView.layer.setNeedsDisplay() self.blurView.layer.setNeedsDisplay()
} }
} }
var blurView: BlurView { public var blurView: BlurView {
return (self.view as? BlurView)! return (self.view as? BlurView)!
} }
override init() { public override init() {
super.init() super.init()
self.setViewBlock({ self.setViewBlock({

View File

@ -313,15 +313,26 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
} }
} }
struct WallpaperColorPanelNodeState: Equatable { public struct WallpaperColorPanelNodeState: Equatable {
var selection: Int? public var selection: Int?
var colors: [HSBColor] public var colors: [HSBColor]
var maximumNumberOfColors: Int public var maximumNumberOfColors: Int
var rotateAvailable: Bool public var rotateAvailable: Bool
var rotation: Int32 public var rotation: Int32
var preview: Bool public var preview: Bool
var simpleGradientGeneration: Bool public var simpleGradientGeneration: Bool
var suggestedNewColor: HSBColor? public var suggestedNewColor: HSBColor?
public init(selection: Int? = nil, colors: [HSBColor], maximumNumberOfColors: Int, rotateAvailable: Bool, rotation: Int32, preview: Bool, simpleGradientGeneration: Bool, suggestedNewColor: HSBColor? = nil) {
self.selection = selection
self.colors = colors
self.maximumNumberOfColors = maximumNumberOfColors
self.rotateAvailable = rotateAvailable
self.rotation = rotation
self.preview = preview
self.simpleGradientGeneration = simpleGradientGeneration
self.suggestedNewColor = suggestedNewColor
}
} }
private final class ColorSampleItemNode: ASImageNode { private final class ColorSampleItemNode: ASImageNode {
@ -377,7 +388,7 @@ private final class ColorSampleItemNode: ASImageNode {
} }
} }
final class WallpaperColorPanelNode: ASDisplayNode { public final class WallpaperColorPanelNode: ASDisplayNode {
private var theme: PresentationTheme private var theme: PresentationTheme
private var state: WallpaperColorPanelNodeState private var state: WallpaperColorPanelNodeState
@ -394,16 +405,16 @@ final class WallpaperColorPanelNode: ASDisplayNode {
private var sampleItemNodes: [ColorSampleItemNode] = [] private var sampleItemNodes: [ColorSampleItemNode] = []
private let multiColorFieldNode: ColorInputFieldNode private let multiColorFieldNode: ColorInputFieldNode
var colorsChanged: (([HSBColor], Int, Bool) -> Void)? public var colorsChanged: (([HSBColor], Int, Bool) -> Void)?
var colorSelected: (() -> Void)? public var colorSelected: (() -> Void)?
var rotate: (() -> Void)? public var rotate: (() -> Void)?
var colorAdded: (() -> Void)? public var colorAdded: (() -> Void)?
var colorRemoved: (() -> Void)? public var colorRemoved: (() -> Void)?
private var validLayout: (CGSize, CGFloat)? private var validLayout: (CGSize, CGFloat)?
init(theme: PresentationTheme, strings: PresentationStrings) { public init(theme: PresentationTheme, strings: PresentationStrings) {
self.theme = theme self.theme = theme
self.backgroundNode = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColor) self.backgroundNode = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColor)
@ -512,7 +523,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
} }
} }
func updateTheme(_ theme: PresentationTheme) { public func updateTheme(_ theme: PresentationTheme) {
self.theme = theme self.theme = theme
self.backgroundNode.updateColor(color: self.theme.chat.inputPanel.panelBackgroundColor, transition: .immediate) self.backgroundNode.updateColor(color: self.theme.chat.inputPanel.panelBackgroundColor, transition: .immediate)
self.topSeparatorNode.backgroundColor = self.theme.chat.inputPanel.panelSeparatorColor self.topSeparatorNode.backgroundColor = self.theme.chat.inputPanel.panelSeparatorColor
@ -520,7 +531,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
self.multiColorFieldNode.updateTheme(theme) self.multiColorFieldNode.updateTheme(theme)
} }
func updateState(_ f: (WallpaperColorPanelNodeState) -> WallpaperColorPanelNodeState, updateLayout: Bool = true, animated: Bool = true) { public func updateState(_ f: (WallpaperColorPanelNodeState) -> WallpaperColorPanelNodeState, updateLayout: Bool = true, animated: Bool = true) {
var updateLayout = updateLayout var updateLayout = updateLayout
let previousColors = self.state.colors let previousColors = self.state.colors
let previousPreview = self.state.preview let previousPreview = self.state.preview
@ -560,7 +571,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
} }
} }
func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { public func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, bottomInset) self.validLayout = (size, bottomInset)
let condensedLayout = size.width < 375.0 let condensedLayout = size.width < 375.0
@ -724,7 +735,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
}) })
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if let result = super.hitTest(point, with: event) { if let result = super.hitTest(point, with: event) {
return result return result
} }

View File

@ -266,50 +266,50 @@ private final class WallpaperColorBrightnessNode: ASDisplayNode {
} }
} }
struct HSBColor: Equatable { public struct HSBColor: Equatable {
static func == (lhs: HSBColor, rhs: HSBColor) -> Bool { public static func == (lhs: HSBColor, rhs: HSBColor) -> Bool {
return lhs.values.h == rhs.values.h && lhs.values.s == rhs.values.s && lhs.values.b == rhs.values.b return lhs.values.h == rhs.values.h && lhs.values.s == rhs.values.s && lhs.values.b == rhs.values.b
} }
let values: (h: CGFloat, s: CGFloat, b: CGFloat) public let values: (h: CGFloat, s: CGFloat, b: CGFloat)
let backingColor: UIColor public let backingColor: UIColor
var hue: CGFloat { public var hue: CGFloat {
return self.values.h return self.values.h
} }
var saturation: CGFloat { public var saturation: CGFloat {
return self.values.s return self.values.s
} }
var brightness: CGFloat { public var brightness: CGFloat {
return self.values.b return self.values.b
} }
var rgb: UInt32 { public var rgb: UInt32 {
return self.color.argb return self.color.argb
} }
init(values: (h: CGFloat, s: CGFloat, b: CGFloat)) { public init(values: (h: CGFloat, s: CGFloat, b: CGFloat)) {
self.values = values self.values = values
self.backingColor = UIColor(hue: values.h, saturation: values.s, brightness: values.b, alpha: 1.0) self.backingColor = UIColor(hue: values.h, saturation: values.s, brightness: values.b, alpha: 1.0)
} }
init(hue: CGFloat, saturation: CGFloat, brightness: CGFloat) { public init(hue: CGFloat, saturation: CGFloat, brightness: CGFloat) {
self.values = (h: hue, s: saturation, b: brightness) self.values = (h: hue, s: saturation, b: brightness)
self.backingColor = UIColor(hue: self.values.h, saturation: self.values.s, brightness: self.values.b, alpha: 1.0) self.backingColor = UIColor(hue: self.values.h, saturation: self.values.s, brightness: self.values.b, alpha: 1.0)
} }
init(color: UIColor) { public init(color: UIColor) {
self.values = color.hsb self.values = color.hsb
self.backingColor = color self.backingColor = color
} }
init(rgb: UInt32) { public init(rgb: UInt32) {
self.init(color: UIColor(rgb: rgb)) self.init(color: UIColor(rgb: rgb))
} }
var color: UIColor { public var color: UIColor {
return self.backingColor return self.backingColor
} }
} }

View File

@ -401,7 +401,7 @@ public class WallpaperGalleryController: ViewController {
self.colorsPanelNode?.updateTheme(self.presentationData.theme) self.colorsPanelNode?.updateTheme(self.presentationData.theme)
} }
func dismiss(forceAway: Bool) { public func dismiss(forceAway: Bool) {
// let completion: () -> Void = { [weak self] in // let completion: () -> Void = { [weak self] in
// self?.presentingViewController?.dismiss(animated: false, completion: nil) // self?.presentingViewController?.dismiss(animated: false, completion: nil)
// } // }

View File

@ -1370,7 +1370,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
let editFrame = CGRect(origin: CGPoint(x: layout.size.width - 16.0 - 28.0 + offset.x - 46.0, y: 16.0), size: CGSize(width: 28.0, height: 28.0)) let editFrame = CGRect(origin: CGPoint(x: layout.size.width - 16.0 - 28.0 + offset.x - 46.0, y: 16.0), size: CGSize(width: 28.0, height: 28.0))
let centerOffset: CGFloat = 32.0 let centerOffset: CGFloat = 32.0
if let entry = self.entry { if let entry = self.entry {
switch entry { switch entry {
case .asset: case .asset:
@ -1451,6 +1451,11 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
} }
if let mode = self.mode, case let .peer(peer, _) = mode, case .channel = peer {
motionAlpha = 0.0
blurFrame = centerButtonFrame
}
transition.updateFrame(node: self.patternButtonNode, frame: patternFrame) transition.updateFrame(node: self.patternButtonNode, frame: patternFrame)
transition.updateAlpha(node: self.patternButtonNode, alpha: patternAlpha * alpha) transition.updateAlpha(node: self.patternButtonNode, alpha: patternAlpha * alpha)
@ -1487,13 +1492,29 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
var items: [ListViewItem] = [] var items: [ListViewItem] = []
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)) var peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
let otherPeerId = self.context.account.peerId let otherPeerId = self.context.account.peerId
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
let messages = SimpleDictionary<MessageId, Message>() var messages = SimpleDictionary<MessageId, Message>()
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_PreviewReplyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil)
peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_PreviewReplyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil)
let replyAuthor = self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName
var messageAuthor: Peer = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_PreviewReplyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil)
let otherAuthor = TelegramUser(id: otherPeerId, accessHash: nil, firstName: replyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil)
peers[otherPeerId] = otherAuthor
var messageAttributes: [MessageAttribute] = []
if let mode = self.mode, case let .peer(peer, _) = mode, case .channel = peer {
peerId = peer.id
messageAuthor = peer._asPeer()
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageAuthor, text: self.presentationData.strings.WallpaperPreview_ChannelReplyText, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
messageAttributes = [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)]
}
peers[peerId] = messageAuthor
var topMessageText = "" var topMessageText = ""
var bottomMessageText = "" var bottomMessageText = ""
var serviceMessageText: String? var serviceMessageText: String?
@ -1566,10 +1587,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
if let mode = self.mode, case let .peer(peer, existing) = mode { if let mode = self.mode, case let .peer(peer, existing) = mode {
topMessageText = presentationData.strings.WallpaperPreview_ChatTopText if case .channel = peer {
bottomMessageText = presentationData.strings.WallpaperPreview_ChatBottomText topMessageText = presentationData.strings.WallpaperPreview_ChannelTopText
if !existing { bottomMessageText = ""
serviceMessageText = presentationData.strings.WallpaperPreview_NotAppliedInfo(peer.compactDisplayTitle).string serviceMessageText = presentationData.strings.WallpaperPreview_ChannelHeader
} else {
topMessageText = presentationData.strings.WallpaperPreview_ChatTopText
bottomMessageText = presentationData.strings.WallpaperPreview_ChatBottomText
if !existing {
serviceMessageText = presentationData.strings.WallpaperPreview_NotAppliedInfo(peer.compactDisplayTitle).string
}
} }
} }
@ -1579,10 +1606,13 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
let theme = self.presentationData.theme let theme = self.presentationData.theme
let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) if !bottomMessageText.isEmpty {
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, accountPeer: nil, isCentered: false)) let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, accountPeer: nil, isCentered: false))
}
let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: messageAttributes, media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, accountPeer: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, accountPeer: nil, isCentered: false))
if let serviceMessageText { if let serviceMessageText {

View File

@ -5,12 +5,12 @@ import Display
import TelegramPresentationData import TelegramPresentationData
import ManagedAnimationNode import ManagedAnimationNode
enum WallpaperGalleryToolbarCancelButtonType { public enum WallpaperGalleryToolbarCancelButtonType {
case cancel case cancel
case discard case discard
} }
enum WallpaperGalleryToolbarDoneButtonType { public enum WallpaperGalleryToolbarDoneButtonType {
case set case set
case setPeer(String, Bool) case setPeer(String, Bool)
case setChannel case setChannel
@ -19,7 +19,7 @@ enum WallpaperGalleryToolbarDoneButtonType {
case none case none
} }
protocol WallpaperGalleryToolbar: ASDisplayNode { public protocol WallpaperGalleryToolbar: ASDisplayNode {
var cancelButtonType: WallpaperGalleryToolbarCancelButtonType { get set } var cancelButtonType: WallpaperGalleryToolbarCancelButtonType { get set }
var doneButtonType: WallpaperGalleryToolbarDoneButtonType { get set } var doneButtonType: WallpaperGalleryToolbarDoneButtonType { get set }
@ -31,7 +31,7 @@ protocol WallpaperGalleryToolbar: ASDisplayNode {
func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition)
} }
final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar { public final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar {
class ButtonNode: ASDisplayNode { class ButtonNode: ASDisplayNode {
private let doneButton = HighlightTrackingButtonNode() private let doneButton = HighlightTrackingButtonNode()
private var doneButtonBackgroundNode: ASDisplayNode private var doneButtonBackgroundNode: ASDisplayNode
@ -205,18 +205,18 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
private var theme: PresentationTheme private var theme: PresentationTheme
private let strings: PresentationStrings private let strings: PresentationStrings
var cancelButtonType: WallpaperGalleryToolbarCancelButtonType { public var cancelButtonType: WallpaperGalleryToolbarCancelButtonType {
didSet { didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings) self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
} }
} }
var doneButtonType: WallpaperGalleryToolbarDoneButtonType { public var doneButtonType: WallpaperGalleryToolbarDoneButtonType {
didSet { didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings) self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
} }
} }
var dark: Bool = false { public var dark: Bool = false {
didSet { didSet {
self.applyButton.dark = self.dark self.applyButton.dark = self.dark
self.applyForBothButton.dark = self.dark self.applyForBothButton.dark = self.dark
@ -226,10 +226,10 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
private let applyButton = ButtonNode() private let applyButton = ButtonNode()
private let applyForBothButton = ButtonNode() private let applyForBothButton = ButtonNode()
var cancel: (() -> Void)? public var cancel: (() -> Void)?
var done: ((Bool) -> Void)? public var done: ((Bool) -> Void)?
init(theme: PresentationTheme, strings: PresentationStrings, cancelButtonType: WallpaperGalleryToolbarCancelButtonType = .cancel, doneButtonType: WallpaperGalleryToolbarDoneButtonType = .set) { public init(theme: PresentationTheme, strings: PresentationStrings, cancelButtonType: WallpaperGalleryToolbarCancelButtonType = .cancel, doneButtonType: WallpaperGalleryToolbarDoneButtonType = .set) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.cancelButtonType = cancelButtonType self.cancelButtonType = cancelButtonType
@ -256,13 +256,13 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
} }
} }
func setDoneEnabled(_ enabled: Bool) { public func setDoneEnabled(_ enabled: Bool) {
self.applyButton.setEnabled(enabled) self.applyButton.setEnabled(enabled)
self.applyForBothButton.setEnabled(enabled) self.applyForBothButton.setEnabled(enabled)
} }
private var isSolid = false private var isSolid = false
func setDoneIsSolid(_ isSolid: Bool, transition: ContainedViewLayoutTransition) { public func setDoneIsSolid(_ isSolid: Bool, transition: ContainedViewLayoutTransition) {
guard self.isSolid != isSolid else { guard self.isSolid != isSolid else {
return return
} }
@ -272,7 +272,7 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
self.applyForBothButton.setIsSolid(isSolid, transition: transition) self.applyForBothButton.setIsSolid(isSolid, transition: transition)
} }
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
self.theme = theme self.theme = theme
let applyTitle: String let applyTitle: String
@ -303,7 +303,7 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
self.applyForBothButton.isLocked = applyForBothLocked self.applyForBothButton.isLocked = applyForBothLocked
} }
func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { public func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
let inset: CGFloat = 16.0 let inset: CGFloat = 16.0
let buttonHeight: CGFloat = 50.0 let buttonHeight: CGFloat = 50.0
@ -329,16 +329,16 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
} }
} }
final class WallpaperGalleryOldToolbarNode: ASDisplayNode, WallpaperGalleryToolbar { public final class WallpaperGalleryOldToolbarNode: ASDisplayNode, WallpaperGalleryToolbar {
private var theme: PresentationTheme private var theme: PresentationTheme
private let strings: PresentationStrings private let strings: PresentationStrings
var cancelButtonType: WallpaperGalleryToolbarCancelButtonType { public var cancelButtonType: WallpaperGalleryToolbarCancelButtonType {
didSet { didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings) self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
} }
} }
var doneButtonType: WallpaperGalleryToolbarDoneButtonType { public var doneButtonType: WallpaperGalleryToolbarDoneButtonType {
didSet { didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings) self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
} }
@ -352,10 +352,10 @@ final class WallpaperGalleryOldToolbarNode: ASDisplayNode, WallpaperGalleryToolb
private let separatorNode = ASDisplayNode() private let separatorNode = ASDisplayNode()
private let topSeparatorNode = ASDisplayNode() private let topSeparatorNode = ASDisplayNode()
var cancel: (() -> Void)? public var cancel: (() -> Void)?
var done: ((Bool) -> Void)? public var done: ((Bool) -> Void)?
init(theme: PresentationTheme, strings: PresentationStrings, cancelButtonType: WallpaperGalleryToolbarCancelButtonType = .cancel, doneButtonType: WallpaperGalleryToolbarDoneButtonType = .set) { public init(theme: PresentationTheme, strings: PresentationStrings, cancelButtonType: WallpaperGalleryToolbarCancelButtonType = .cancel, doneButtonType: WallpaperGalleryToolbarDoneButtonType = .set) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.cancelButtonType = cancelButtonType self.cancelButtonType = cancelButtonType
@ -404,12 +404,12 @@ final class WallpaperGalleryOldToolbarNode: ASDisplayNode, WallpaperGalleryToolb
self.doneButton.addTarget(self, action: #selector(self.donePressed), forControlEvents: .touchUpInside) self.doneButton.addTarget(self, action: #selector(self.donePressed), forControlEvents: .touchUpInside)
} }
func setDoneEnabled(_ enabled: Bool) { public func setDoneEnabled(_ enabled: Bool) {
self.doneButton.alpha = enabled ? 1.0 : 0.4 self.doneButton.alpha = enabled ? 1.0 : 0.4
self.doneButton.isUserInteractionEnabled = enabled self.doneButton.isUserInteractionEnabled = enabled
} }
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
self.theme = theme self.theme = theme
self.backgroundNode.updateColor(color: theme.rootController.tabBar.backgroundColor, transition: .immediate) self.backgroundNode.updateColor(color: theme.rootController.tabBar.backgroundColor, transition: .immediate)
self.separatorNode.backgroundColor = theme.rootController.tabBar.separatorColor self.separatorNode.backgroundColor = theme.rootController.tabBar.separatorColor
@ -440,7 +440,7 @@ final class WallpaperGalleryOldToolbarNode: ASDisplayNode, WallpaperGalleryToolb
self.doneButton.setTitle(doneTitle, with: Font.regular(17.0), with: theme.list.itemPrimaryTextColor, for: []) self.doneButton.setTitle(doneTitle, with: Font.regular(17.0), with: theme.list.itemPrimaryTextColor, for: [])
} }
func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { public func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.cancelButton.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height)) self.cancelButton.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height))
self.cancelHighlightBackgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height)) self.cancelHighlightBackgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height))
self.doneButton.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: size.width - floor(size.width / 2.0), height: size.height)) self.doneButton.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: size.width - floor(size.width / 2.0), height: size.height))

View File

@ -6,7 +6,7 @@ import SwiftSignalKit
import CheckNode import CheckNode
import AnimationUI import AnimationUI
enum WallpaperOptionButtonValue { public enum WallpaperOptionButtonValue {
case check(Bool) case check(Bool)
case color(Bool, UIColor) case color(Bool, UIColor)
case colors(Bool, [UIColor]) case colors(Bool, [UIColor])
@ -270,7 +270,7 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
} }
final class WallpaperOptionButtonNode: HighlightTrackingButtonNode { public final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
let backgroundNode: WallpaperOptionBackgroundNode let backgroundNode: WallpaperOptionBackgroundNode
private let checkNode: CheckNode private let checkNode: CheckNode
@ -281,7 +281,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
private var textSize: CGSize? private var textSize: CGSize?
private var _value: WallpaperOptionButtonValue private var _value: WallpaperOptionButtonValue
override var isSelected: Bool { public override var isSelected: Bool {
get { get {
switch self._value { switch self._value {
case let .check(selected), let .color(selected, _), let .colors(selected, _): case let .check(selected), let .color(selected, _), let .colors(selected, _):
@ -301,13 +301,13 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
} }
} }
var title: String { public var title: String {
didSet { didSet {
self.textNode.attributedText = NSAttributedString(string: title, font: Font.medium(13), textColor: .white) self.textNode.attributedText = NSAttributedString(string: title, font: Font.medium(13), textColor: .white)
} }
} }
init(title: String, value: WallpaperOptionButtonValue) { public init(title: String, value: WallpaperOptionButtonValue) {
self._value = value self._value = value
self.title = title self.title = title
@ -368,12 +368,12 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
} }
} }
var buttonColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) { public var buttonColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) {
didSet { didSet {
} }
} }
var color: UIColor? { public var color: UIColor? {
get { get {
switch self._value { switch self._value {
case let .color(_, color): case let .color(_, color):
@ -395,7 +395,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
} }
} }
var colors: [UIColor]? { public var colors: [UIColor]? {
get { get {
switch self._value { switch self._value {
case let .colors(_, colors): case let .colors(_, colors):
@ -429,7 +429,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
} }
} }
func setSelected(_ selected: Bool, animated: Bool = false) { public func setSelected(_ selected: Bool, animated: Bool = false) {
switch self._value { switch self._value {
case .check: case .check:
self._value = .check(selected) self._value = .check(selected)
@ -441,7 +441,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
self.checkNode.setSelected(selected, animated: animated) self.checkNode.setSelected(selected, animated: animated)
} }
func setEnabled(_ enabled: Bool) { public func setEnabled(_ enabled: Bool) {
let alpha: CGFloat = enabled ? 1.0 : 0.4 let alpha: CGFloat = enabled ? 1.0 : 0.4
self.checkNode.alpha = alpha self.checkNode.alpha = alpha
self.colorNode.alpha = alpha self.colorNode.alpha = alpha
@ -449,13 +449,13 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
self.isUserInteractionEnabled = enabled self.isUserInteractionEnabled = enabled
} }
override func measure(_ constrainedSize: CGSize) -> CGSize { public override func measure(_ constrainedSize: CGSize) -> CGSize {
let size = self.textNode.updateLayout(constrainedSize) let size = self.textNode.updateLayout(constrainedSize)
self.textSize = size self.textSize = size
return CGSize(width: ceil(size.width) + 48.0, height: 30.0) return CGSize(width: ceil(size.width) + 48.0, height: 30.0)
} }
override func layout() { public override func layout() {
super.layout() super.layout()
self.backgroundNode.frame = self.bounds self.backgroundNode.frame = self.bounds

View File

@ -9,6 +9,7 @@ import LegacyComponents
import AccountContext import AccountContext
import MergeLists import MergeLists
import Postbox import Postbox
import SettingsThemeWallpaperNode
private let itemSize = CGSize(width: 88.0, height: 88.0) private let itemSize = CGSize(width: 88.0, height: 88.0)
private let inset: CGFloat = 12.0 private let inset: CGFloat = 12.0
@ -172,24 +173,24 @@ private final class WallpaperPatternItemNode : ListViewItemNode {
} }
} }
final class WallpaperPatternPanelNode: ASDisplayNode { public final class WallpaperPatternPanelNode: ASDisplayNode {
private let context: AccountContext private let context: AccountContext
private var theme: PresentationTheme private var theme: PresentationTheme
private let backgroundNode: NavigationBackgroundNode private let backgroundNode: NavigationBackgroundNode
private let topSeparatorNode: ASDisplayNode private let topSeparatorNode: ASDisplayNode
let scrollNode: ASScrollNode public let scrollNode: ASScrollNode
private let titleNode: ImmediateTextNode private let titleNode: ImmediateTextNode
private let labelNode: ImmediateTextNode private let labelNode: ImmediateTextNode
private var sliderView: TGPhotoEditorSliderView? private var sliderView: TGPhotoEditorSliderView?
private var disposable: Disposable? private var disposable: Disposable?
var wallpapers: [TelegramWallpaper] = [] public var wallpapers: [TelegramWallpaper] = []
private var currentWallpaper: TelegramWallpaper? private var currentWallpaper: TelegramWallpaper?
var serviceBackgroundColor: UIColor = UIColor(rgb: 0x748698) { public var serviceBackgroundColor: UIColor = UIColor(rgb: 0x748698) {
didSet { didSet {
guard let nodes = self.scrollNode.subnodes else { guard let nodes = self.scrollNode.subnodes else {
return return
@ -200,7 +201,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
} }
} }
var backgroundColors: ([HSBColor], Int32?, Int32?)? = nil { public var backgroundColors: ([HSBColor], Int32?, Int32?)? = nil {
didSet { didSet {
var updated = false var updated = false
if oldValue?.0 != self.backgroundColors?.0 || oldValue?.1 != self.backgroundColors?.1 { if oldValue?.0 != self.backgroundColors?.0 || oldValue?.1 != self.backgroundColors?.1 {
@ -223,11 +224,11 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
private var validLayout: (CGSize, CGFloat)? private var validLayout: (CGSize, CGFloat)?
var patternChanged: ((TelegramWallpaper?, Int32?, Bool) -> Void)? public var patternChanged: ((TelegramWallpaper?, Int32?, Bool) -> Void)?
private let allowDark: Bool private let allowDark: Bool
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) { public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) {
self.context = context self.context = context
self.theme = theme self.theme = theme
self.allowDark = theme.overallDarkAppearance self.allowDark = theme.overallDarkAppearance
@ -287,7 +288,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
self.disposable?.dispose() self.disposable?.dispose()
} }
override func didLoad() { public override func didLoad() {
super.didLoad() super.didLoad()
self.scrollNode.view.showsHorizontalScrollIndicator = false self.scrollNode.view.showsHorizontalScrollIndicator = false
@ -320,7 +321,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
self.sliderView = sliderView self.sliderView = sliderView
} }
func updateWallpapers() { public func updateWallpapers() {
guard let subnodes = self.scrollNode.subnodes else { guard let subnodes = self.scrollNode.subnodes else {
return return
} }
@ -386,7 +387,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
self.layoutItemNodes(transition: .immediate) self.layoutItemNodes(transition: .immediate)
} }
func updateTheme(_ theme: PresentationTheme) { public func updateTheme(_ theme: PresentationTheme) {
self.theme = theme self.theme = theme
self.backgroundNode.updateColor(color: self.theme.chat.inputPanel.panelBackgroundColor, transition: .immediate) self.backgroundNode.updateColor(color: self.theme.chat.inputPanel.panelBackgroundColor, transition: .immediate)
@ -416,7 +417,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
} }
} }
func didAppear(initialWallpaper: TelegramWallpaper? = nil, intensity: Int32? = nil) { public func didAppear(initialWallpaper: TelegramWallpaper? = nil, intensity: Int32? = nil) {
let wallpaper: TelegramWallpaper? let wallpaper: TelegramWallpaper?
if self.wallpapers.isEmpty { if self.wallpapers.isEmpty {
@ -482,7 +483,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
} }
} }
func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { public func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, bottomInset) self.validLayout = (size, bottomInset)
let backgroundFrame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height + bottomInset) let backgroundFrame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height + bottomInset)

View File

@ -2578,119 +2578,123 @@ final class ShareWithPeersScreenComponent: Component {
} }
} }
let presentAlert: ([String]) -> Void = { usernames in if let sendAsPeerId = self.sendAsPeerId, sendAsPeerId.isGroupOrChannel {
let usernamesString = String(usernames.map { "@\($0)" }.joined(separator: ", ")) proceed()
let alertController = textAlertController( } else {
context: component.context, let presentAlert: ([String]) -> Void = { usernames in
forceTheme: defaultDarkColorPresentationTheme, let usernamesString = String(usernames.map { "@\($0)" }.joined(separator: ", "))
title: environment.strings.Story_Privacy_MentionRestrictedTitle, let alertController = textAlertController(
text: environment.strings.Story_Privacy_MentionRestrictedText(usernamesString).string, context: component.context,
actions: [ forceTheme: defaultDarkColorPresentationTheme,
TextAlertAction(type: .defaultAction, title: environment.strings.Story_Privacy_MentionRestrictedProceed, action: { title: environment.strings.Story_Privacy_MentionRestrictedTitle,
proceed() text: environment.strings.Story_Privacy_MentionRestrictedText(usernamesString).string,
}), actions: [
TextAlertAction(type: .genericAction, title: environment.strings.Common_Cancel, action: {}) TextAlertAction(type: .defaultAction, title: environment.strings.Story_Privacy_MentionRestrictedProceed, action: {
], proceed()
actionLayout: .vertical }),
) TextAlertAction(type: .genericAction, title: environment.strings.Common_Cancel, action: {})
controller.present(alertController, in: .window(.root)) ],
} actionLayout: .vertical
)
func matchingUsername(user: TelegramUser, usernames: Set<String>) -> String? { controller.present(alertController, in: .window(.root))
for username in user.usernames {
if usernames.contains(username.username) {
return username.username
}
} }
if let username = user.username {
if usernames.contains(username) { func matchingUsername(user: TelegramUser, usernames: Set<String>) -> String? {
return username for username in user.usernames {
if usernames.contains(username.username) {
return username.username
}
} }
if let username = user.username {
if usernames.contains(username) {
return username
}
}
return nil
} }
return nil
} let context = component.context
let selectedPeerIds = self.selectedPeers
let context = component.context
let selectedPeerIds = self.selectedPeers if case .stories = component.stateContext.subject {
if component.mentions.isEmpty {
if case .stories = component.stateContext.subject { proceed()
if component.mentions.isEmpty { } else if case .nobody = base {
proceed() if selectedPeerIds.isEmpty {
} else if case .nobody = base { presentAlert(component.mentions)
if selectedPeerIds.isEmpty { } else {
presentAlert(component.mentions) let _ = (context.account.postbox.transaction { transaction in
} else { var filteredMentions = Set(component.mentions)
let _ = (context.account.postbox.transaction { transaction in for peerId in selectedPeerIds {
var filteredMentions = Set(component.mentions) if let peer = transaction.getPeer(peerId) {
for peerId in selectedPeerIds { if let user = peer as? TelegramUser {
if let peer = transaction.getPeer(peerId) { if let username = matchingUsername(user: user, usernames: filteredMentions) {
if let user = peer as? TelegramUser { filteredMentions.remove(username)
if let username = matchingUsername(user: user, usernames: filteredMentions) { }
filteredMentions.remove(username) } else {
} if let username = peer.addressName {
} else { filteredMentions.remove(username)
if let username = peer.addressName { }
filteredMentions.remove(username)
} }
} }
} }
return Array(filteredMentions)
}
|> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty {
proceed()
} else {
presentAlert(mentions)
}
})
}
} else if case .contacts = base {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false))
|> map { contacts -> [String] in
var filteredMentions = Set(component.mentions)
let peers = contacts.peers
for peer in peers {
if selectedPeerIds.contains(peer.id) {
continue
}
if case let .user(user) = peer, let username = matchingUsername(user: user, usernames: filteredMentions) {
filteredMentions.remove(username)
}
} }
return Array(filteredMentions) return Array(filteredMentions)
} }
|> deliverOnMainQueue).start(next: { mentions in |> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty { if mentions.isEmpty {
proceed() proceed()
} else { } else {
presentAlert(mentions) presentAlert(mentions)
} }
}) })
} } else if case .closeFriends = base {
} else if case .contacts = base { let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false))
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false)) |> map { contacts -> [String] in
|> map { contacts -> [String] in var filteredMentions = Set(component.mentions)
var filteredMentions = Set(component.mentions) let peers = contacts.peers
let peers = contacts.peers for peer in peers {
for peer in peers { if case let .user(user) = peer, user.flags.contains(.isCloseFriend), let username = matchingUsername(user: user, usernames: filteredMentions) {
if selectedPeerIds.contains(peer.id) { filteredMentions.remove(username)
continue }
} }
if case let .user(user) = peer, let username = matchingUsername(user: user, usernames: filteredMentions) { return Array(filteredMentions)
filteredMentions.remove(username) }
|> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty {
proceed()
} else {
presentAlert(mentions)
} }
} })
return Array(filteredMentions) } else {
proceed()
} }
|> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty {
proceed()
} else {
presentAlert(mentions)
}
})
} else if case .closeFriends = base {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false))
|> map { contacts -> [String] in
var filteredMentions = Set(component.mentions)
let peers = contacts.peers
for peer in peers {
if case let .user(user) = peer, user.flags.contains(.isCloseFriend), let username = matchingUsername(user: user, usernames: filteredMentions) {
filteredMentions.remove(username)
}
}
return Array(filteredMentions)
}
|> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty {
proceed()
} else {
presentAlert(mentions)
}
})
} else { } else {
proceed() proceed()
} }
} else {
proceed()
} }
} }
)), )),

View File

@ -96,6 +96,7 @@ public final class ForwardInfoPanelComponent: Component {
iconView.alpha = 0.55 iconView.alpha = 0.55
iconView.tintColor = .white iconView.tintColor = .white
self.addSubview(iconView) self.addSubview(iconView)
self.iconView = iconView
} }
if let image = iconView.image { if let image = iconView.image {
iconView.frame = CGRect(origin: CGPoint(x: sideInset + UIScreenPixel, y: 5.0), size: image.size) iconView.frame = CGRect(origin: CGPoint(x: sideInset + UIScreenPixel, y: 5.0), size: image.size)

View File

@ -112,6 +112,10 @@ public final class StoryContentContextImpl: StoryContentContext {
} }
} }
} }
} else if case let .channelMessage(_, messageId) = mediaArea {
if let peer = transaction.getPeer(messageId.peerId) {
peers[peer.id] = peer
}
} }
} }
} }
@ -216,6 +220,17 @@ public final class StoryContentContextImpl: StoryContentContext {
guard let media = item.media else { guard let media = item.media else {
return nil return nil
} }
var forwardInfo = item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
if forwardInfo == nil {
for mediaArea in item.mediaAreas {
if case let .channelMessage(_, messageId) = mediaArea, let peer = peers[messageId.peerId] {
forwardInfo = .known(peer: EnginePeer(peer), storyId: 0, isModified: false)
break
}
}
}
return EngineStoryItem( return EngineStoryItem(
id: item.id, id: item.id,
timestamp: item.timestamp, timestamp: item.timestamp,
@ -248,7 +263,7 @@ public final class StoryContentContextImpl: StoryContentContext {
isEdited: item.isEdited, isEdited: item.isEdited,
isMy: item.isMy, isMy: item.isMy,
myReaction: item.myReaction, myReaction: item.myReaction,
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) } forwardInfo: forwardInfo
) )
} }
var totalCount = peerStoryItemsView.items.count var totalCount = peerStoryItemsView.items.count
@ -1131,6 +1146,10 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
} }
} }
} }
} else if case let .channelMessage(_, messageId) = mediaArea {
if let peer = transaction.getPeer(messageId.peerId) {
peers[peer.id] = peer
}
} }
} }
} }
@ -1186,6 +1205,16 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
} }
if let item, case let .item(itemValue) = item, let media = itemValue.media { if let item, case let .item(itemValue) = item, let media = itemValue.media {
var forwardInfo = itemValue.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
if forwardInfo == nil {
for mediaArea in itemValue.mediaAreas {
if case let .channelMessage(_, messageId) = mediaArea, let peer = peers[messageId.peerId] {
forwardInfo = .known(peer: EnginePeer(peer), storyId: 0, isModified: false)
break
}
}
}
let mappedItem = EngineStoryItem( let mappedItem = EngineStoryItem(
id: itemValue.id, id: itemValue.id,
timestamp: itemValue.timestamp, timestamp: itemValue.timestamp,
@ -1218,7 +1247,7 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
isEdited: itemValue.isEdited, isEdited: itemValue.isEdited,
isMy: itemValue.isMy, isMy: itemValue.isMy,
myReaction: itemValue.myReaction, myReaction: itemValue.myReaction,
forwardInfo: itemValue.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) } forwardInfo: forwardInfo
) )
let mainItem = StoryContentItem( let mainItem = StoryContentItem(
@ -2073,13 +2102,22 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
private var currentForwardInfoStories: [StoryId: Promise<EngineStoryItem?>] = [:] private var currentForwardInfoStories: [StoryId: Promise<EngineStoryItem?>] = [:]
init(context: AccountContext, peerId: EnginePeer.Id, focusedId initialFocusedId: Int32?, items: [EngineStoryItem]) { init(
context: AccountContext,
originalPeerId: EnginePeer.Id,
originalStory: EngineStoryItem,
peerId: EnginePeer.Id,
focusedId initialFocusedId: Int32?,
items: [EngineStoryItem]
) {
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
self.currentFocusedId = initialFocusedId self.currentFocusedId = initialFocusedId
self.currentFocusedIdUpdatedPromise.set(.single(Void())) self.currentFocusedIdUpdatedPromise.set(.single(Void()))
let originalStoryId = StoryId(peerId: originalPeerId, id: originalStory.id)
let inputKeys: [PostboxViewKey] = [ let inputKeys: [PostboxViewKey] = [
PostboxViewKey.basicPeer(peerId), PostboxViewKey.basicPeer(peerId),
PostboxViewKey.cachedPeerData(peerId: peerId), PostboxViewKey.cachedPeerData(peerId: peerId),
@ -2098,53 +2136,43 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
var forwardInfoStories: [StoryId: EngineStoryItem?] = [:] var forwardInfoStories: [StoryId: EngineStoryItem?] = [:]
var allEntityFiles: [MediaId: TelegramMediaFile] = [:] var allEntityFiles: [MediaId: TelegramMediaFile] = [:]
if let itemsView = views.views[PostboxViewKey.storyItems(peerId: peerId)] as? StoryItemsView { for item in items {
for item in itemsView.items { if let forwardInfo = item.forwardInfo, case let .known(peer, id, _) = forwardInfo {
if let item = item.value.get(Stories.StoredItem.self), case let .item(itemValue) = item { let storyId = StoryId(peerId: peer.id, id: id)
if let views = itemValue.views { if storyId == originalStoryId {
for peerId in views.seenPeerIds { forwardInfoStories[storyId] = originalStory
if let peer = transaction.getPeer(peerId) { } else {
peers[peer.id] = peer forwardInfoStories.updateValue(nil, forKey: storyId)
} }
} }
} for entity in item.entities {
if let forwardInfo = itemValue.forwardInfo, case let .known(peerId, id, _) = forwardInfo { if case let .CustomEmoji(_, fileId) = entity.type {
if let peer = transaction.getPeer(peerId) { let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
peers[peer.id] = peer if allEntityFiles[mediaId] == nil {
} if let file = transaction.getMedia(mediaId) as? TelegramMediaFile {
let storyId = StoryId(peerId: peerId, id: id) allEntityFiles[file.fileId] = file
if let story = getCachedStory(storyId: storyId, transaction: transaction) {
forwardInfoStories[storyId] = story
} else {
forwardInfoStories.updateValue(nil, forKey: storyId)
}
}
for entity in itemValue.entities {
if case let .CustomEmoji(_, fileId) = entity.type {
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
if allEntityFiles[mediaId] == nil {
if let file = transaction.getMedia(mediaId) as? TelegramMediaFile {
allEntityFiles[file.fileId] = file
}
}
}
}
for mediaArea in itemValue.mediaAreas {
if case let .reaction(_, reaction, _) = mediaArea {
if case let .custom(fileId) = reaction {
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
if allEntityFiles[mediaId] == nil {
if let file = transaction.getMedia(mediaId) as? TelegramMediaFile {
allEntityFiles[file.fileId] = file
}
}
}
} }
} }
} }
} }
for mediaArea in item.mediaAreas {
if case let .reaction(_, reaction, _) = mediaArea {
if case let .custom(fileId) = reaction {
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
if allEntityFiles[mediaId] == nil {
if let file = transaction.getMedia(mediaId) as? TelegramMediaFile {
allEntityFiles[file.fileId] = file
}
}
}
} else if case let .channelMessage(_, messageId) = mediaArea {
if let peer = transaction.getPeer(messageId.peerId) {
peers[peer.id] = peer
}
}
}
} }
return (views, peers, globalNotificationSettings, allEntityFiles, forwardInfoStories) return (views, peers, globalNotificationSettings, allEntityFiles, forwardInfoStories)
} }
} }
@ -2163,7 +2191,6 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
if let presencesView = views.views[PostboxViewKey.peerPresences(peerIds: Set([peerId]))] as? PeerPresencesView { if let presencesView = views.views[PostboxViewKey.peerPresences(peerIds: Set([peerId]))] as? PeerPresencesView {
peerPresence = presencesView.presences[peerId] peerPresence = presencesView.presences[peerId]
} }
for (storyId, story) in forwardInfoStories { for (storyId, story) in forwardInfoStories {
let promise: Promise<EngineStoryItem?> let promise: Promise<EngineStoryItem?>
var added = false var added = false
@ -2174,7 +2201,9 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
self.currentForwardInfoStories[storyId] = promise self.currentForwardInfoStories[storyId] = promise
added = true added = true
} }
if let story { if storyId == originalStoryId {
promise.set(.single(originalStory))
} else if let story {
promise.set(.single(story)) promise.set(.single(story))
} else if added { } else if added {
promise.set(self.context.engine.messages.getStory(peerId: storyId.peerId, id: storyId.id)) promise.set(self.context.engine.messages.getStory(peerId: storyId.peerId, id: storyId.id))
@ -2274,7 +2303,6 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
let mappedFocusedIndex = mappedItems.firstIndex(where: { $0.id == mappedItems[focusedIndex].id }) let mappedFocusedIndex = mappedItems.firstIndex(where: { $0.id == mappedItems[focusedIndex].id })
do { do {
let mappedItem = mappedItems[focusedIndex] let mappedItem = mappedItems[focusedIndex]
@ -2416,6 +2444,8 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
} }
private let context: AccountContext private let context: AccountContext
private let originalPeerId: EnginePeer.Id
private let originalStory: EngineStoryItem
private let viewListContext: EngineStoryViewListContext private let viewListContext: EngineStoryViewListContext
private let readGlobally: Bool private let readGlobally: Bool
@ -2449,11 +2479,15 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
public init( public init(
context: AccountContext, context: AccountContext,
originalPeerId: EnginePeer.Id,
originalStory: EngineStoryItem,
focusedStoryId: StoryId, focusedStoryId: StoryId,
viewListContext: EngineStoryViewListContext, viewListContext: EngineStoryViewListContext,
readGlobally: Bool readGlobally: Bool
) { ) {
self.context = context self.context = context
self.originalPeerId = originalPeerId
self.originalStory = originalStory
self.focusedItem = (focusedStoryId.peerId, focusedStoryId.id) self.focusedItem = (focusedStoryId.peerId, focusedStoryId.id)
self.viewListContext = viewListContext self.viewListContext = viewListContext
self.readGlobally = readGlobally self.readGlobally = readGlobally
@ -2530,7 +2564,7 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: currentStoryItems[centralIndex].peer.id) { if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: currentStoryItems[centralIndex].peer.id) {
centralPeerContext = existingContext centralPeerContext = existingContext
} else { } else {
centralPeerContext = PeerContext(context: self.context, peerId: currentStoryItems[centralIndex].peer.id, focusedId: nil, items: [currentStoryItems[centralIndex].story]) centralPeerContext = PeerContext(context: self.context, originalPeerId: self.originalPeerId, originalStory: self.originalStory, peerId: currentStoryItems[centralIndex].peer.id, focusedId: nil, items: [currentStoryItems[centralIndex].story])
} }
var previousPeerContext: PeerContext? var previousPeerContext: PeerContext?
@ -2538,7 +2572,7 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: currentStoryItems[centralIndex - 1].peer.id) { if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: currentStoryItems[centralIndex - 1].peer.id) {
previousPeerContext = existingContext previousPeerContext = existingContext
} else { } else {
previousPeerContext = PeerContext(context: self.context, peerId: currentStoryItems[centralIndex - 1].peer.id, focusedId: nil, items: [currentStoryItems[centralIndex - 1].story]) previousPeerContext = PeerContext(context: self.context, originalPeerId: self.originalPeerId, originalStory: self.originalStory, peerId: currentStoryItems[centralIndex - 1].peer.id, focusedId: nil, items: [currentStoryItems[centralIndex - 1].story])
} }
} }
@ -2547,7 +2581,7 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: currentStoryItems[centralIndex + 1].peer.id) { if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: currentStoryItems[centralIndex + 1].peer.id) {
nextPeerContext = existingContext nextPeerContext = existingContext
} else { } else {
nextPeerContext = PeerContext(context: self.context, peerId: currentStoryItems[centralIndex + 1].peer.id, focusedId: nil, items: [currentStoryItems[centralIndex + 1].story]) nextPeerContext = PeerContext(context: self.context, originalPeerId: self.originalPeerId, originalStory: self.originalStory, peerId: currentStoryItems[centralIndex + 1].peer.id, focusedId: nil, items: [currentStoryItems[centralIndex + 1].story])
} }
} }

View File

@ -68,7 +68,7 @@ final class StoryContentCaptionComponent: Component {
let longTapAction: (Action) -> Void let longTapAction: (Action) -> Void
let textSelectionAction: (NSAttributedString, TextSelectionAction) -> Void let textSelectionAction: (NSAttributedString, TextSelectionAction) -> Void
let controller: () -> ViewController? let controller: () -> ViewController?
let openStory: (EnginePeer, EngineStoryItem) -> Void let openStory: (EnginePeer, EngineStoryItem?) -> Void
init( init(
externalState: ExternalState, externalState: ExternalState,
@ -85,7 +85,7 @@ final class StoryContentCaptionComponent: Component {
longTapAction: @escaping (Action) -> Void, longTapAction: @escaping (Action) -> Void,
textSelectionAction: @escaping (NSAttributedString, TextSelectionAction) -> Void, textSelectionAction: @escaping (NSAttributedString, TextSelectionAction) -> Void,
controller: @escaping () -> ViewController?, controller: @escaping () -> ViewController?,
openStory: @escaping (EnginePeer, EngineStoryItem) -> Void openStory: @escaping (EnginePeer, EngineStoryItem?) -> Void
) { ) {
self.externalState = externalState self.externalState = externalState
self.context = context self.context = context
@ -692,9 +692,9 @@ final class StoryContentCaptionComponent: Component {
} }
} }
}) })
text = nil text = ""
} else { } else {
text = nil text = ""
} }
case let .unknown(name, _): case let .unknown(name, _):
authorName = name authorName = name
@ -727,8 +727,8 @@ final class StoryContentCaptionComponent: Component {
effectAlignment: .center, effectAlignment: .center,
minSize: nil, minSize: nil,
action: { [weak self] in action: { [weak self] in
if let self, case let .known(peer, _, _) = forwardInfo, let story = self.forwardInfoStory { if let self, case let .known(peer, _, _) = forwardInfo {
self.component?.openStory(peer, story) self.component?.openStory(peer, self.forwardInfoStory)
} else if let controller = self?.component?.controller() as? StoryContainerScreen { } else if let controller = self?.component?.controller() as? StoryContainerScreen {
let tooltipController = TooltipController(content: .text(component.strings.Story_ForwardAuthorHiddenTooltip), baseFontSize: 17.0, isBlurred: true, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true) let tooltipController = TooltipController(content: .text(component.strings.Story_ForwardAuthorHiddenTooltip), baseFontSize: 17.0, isBlurred: true, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
controller.present(tooltipController, in: .window(.root), with: TooltipControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak controller] in controller.present(tooltipController, in: .window(.root), with: TooltipControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak controller] in

View File

@ -4246,46 +4246,55 @@ public final class StoryItemSetContainerComponent: Component {
guard let self, let component = self.component else { guard let self, let component = self.component else {
return return
} }
let context = component.context if let story {
let peerId = component.slice.peer.id let context = component.context
let currentResult: ResolvedUrl = .story(peerId: peerId, id: component.slice.item.storyItem.id) let peerId = component.slice.peer.id
let currentResult: ResolvedUrl = .story(peerId: peerId, id: component.slice.item.storyItem.id)
self.sendMessageContext.openResolved(view: self, result: .story(peerId: peer.id, id: story.id), completion: { [weak self] in
guard let self, let controller = self.component?.controller() as? StoryContainerScreen else { self.sendMessageContext.openResolved(view: self, result: .story(peerId: peer.id, id: story.id), completion: { [weak self] in
return guard let self, let controller = self.component?.controller() as? StoryContainerScreen else {
} return
if let nextController = controller.navigationController?.viewControllers.last as? StoryContainerScreen { }
nextController.customBackAction = { [weak nextController] in if let nextController = controller.navigationController?.viewControllers.last as? StoryContainerScreen {
context.sharedContext.openResolvedUrl( nextController.customBackAction = { [weak nextController] in
currentResult, context.sharedContext.openResolvedUrl(
context: context, currentResult,
urlContext: .generic, context: context,
navigationController: nextController?.navigationController as? NavigationController, urlContext: .generic,
forceExternal: false, navigationController: nextController?.navigationController as? NavigationController,
openPeer: { _, _ in forceExternal: false,
}, openPeer: { _, _ in
sendFile: nil, },
sendSticker: nil, sendFile: nil,
requestMessageActionUrlAuth: nil, sendSticker: nil,
joinVoiceChat: nil, requestMessageActionUrlAuth: nil,
present: { _, _ in joinVoiceChat: nil,
}, present: { _, _ in
dismissInput: { },
}, dismissInput: {
contentContext: nil, },
progress: nil, contentContext: nil,
completion: { [weak nextController] in progress: nil,
Queue.mainQueue().after(0.5) { completion: { [weak nextController] in
nextController?.dismissWithoutTransitionOut() Queue.mainQueue().after(0.5) {
nextController?.dismissWithoutTransitionOut()
}
} }
} )
) }
}
Queue.mainQueue().after(0.5) {
controller.dismissWithoutTransitionOut()
}
})
} else {
for mediaArea in component.slice.item.storyItem.mediaAreas {
if case .channelMessage = mediaArea {
self.sendMessageContext.activateMediaArea(view: self, mediaArea: mediaArea, immediate: true)
break
} }
} }
Queue.mainQueue().after(0.5) { }
controller.dismissWithoutTransitionOut()
}
})
} }
)), )),
environment: {}, environment: {},
@ -5196,7 +5205,7 @@ public final class StoryItemSetContainerComponent: Component {
} }
let context = component.context let context = component.context
let storyContent = RepostStoriesContentContextImpl(context: context, focusedStoryId: StoryId(peerId: peer.id, id: id), viewListContext: viewListContext, readGlobally: false) let storyContent = RepostStoriesContentContextImpl(context: context, originalPeerId: component.slice.peer.id, originalStory: component.slice.item.storyItem, focusedStoryId: StoryId(peerId: peer.id, id: id), viewListContext: viewListContext, readGlobally: false)
let _ = (storyContent.state let _ = (storyContent.state
|> take(1) |> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak controller, weak viewListView, weak sourceView] _ in |> deliverOnMainQueue).startStandalone(next: { [weak controller, weak viewListView, weak sourceView] _ in

View File

@ -3264,8 +3264,8 @@ final class StoryItemSetContainerSendMessage {
controller.push(sheet) controller.push(sheet)
}) })
} }
func activateMediaArea(view: StoryItemSetContainerComponent.View, mediaArea: MediaArea) { func activateMediaArea(view: StoryItemSetContainerComponent.View, mediaArea: MediaArea, immediate: Bool = false) {
guard let component = view.component, let controller = component.controller() else { guard let component = view.component, let controller = component.controller() else {
return return
} }
@ -3278,8 +3278,8 @@ final class StoryItemSetContainerSendMessage {
var actions: [ContextMenuAction] = [] var actions: [ContextMenuAction] = []
switch mediaArea { switch mediaArea {
case let .venue(_, venue): case let .venue(_, venue):
let subject = EngineMessage(stableId: 0, stableVersion: 0, id: EngineMessage.Id(peerId: PeerId(0), namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [.geo(TelegramMediaMap(latitude: venue.latitude, longitude: venue.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: venue.venue, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil))], peers: [:], associatedMessages: [:], associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let action = { [weak controller, weak view] in
actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewLocation, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: { [weak controller, weak view] in let subject = EngineMessage(stableId: 0, stableVersion: 0, id: EngineMessage.Id(peerId: PeerId(0), namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [.geo(TelegramMediaMap(latitude: venue.latitude, longitude: venue.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: venue.venue, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil))], peers: [:], associatedMessages: [:], associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
let locationController = LocationViewController( let locationController = LocationViewController(
context: context, context: context,
updatedPresentationData: updatedPresentationData, updatedPresentationData: updatedPresentationData,
@ -3302,9 +3302,16 @@ final class StoryItemSetContainerSendMessage {
}) })
} }
controller?.push(locationController) controller?.push(locationController)
}
if immediate {
action()
return
}
actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewLocation, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: {
action()
})) }))
case let .channelMessage(_, messageId): case let .channelMessage(_, messageId):
actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewMessage, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: { let action = { [weak self, weak view] in
let _ = ((context.engine.messages.getMessagesLoadIfNecessary([messageId], strategy: .local) let _ = ((context.engine.messages.getMessagesLoadIfNecessary([messageId], strategy: .local)
|> mapToSignal { result -> Signal<Message?, NoError> in |> mapToSignal { result -> Signal<Message?, NoError> in
if case let .result(messages) = result { if case let .result(messages) = result {
@ -3312,12 +3319,21 @@ final class StoryItemSetContainerSendMessage {
} }
return .single(nil) return .single(nil)
}) })
|> deliverOnMainQueue).startStandalone(next: { message in |> deliverOnMainQueue).startStandalone(next: { [weak self, weak view] message in
guard let message else { guard let self, let view else {
return return
} }
context.sharedContext.navigateToChat(accountId: context.account.id, peerId: message.id.peerId, messageId: message.id) if let message, let peer = message.peers[message.id.peerId] {
self.openResolved(view: view, result: .channelMessage(peer: peer, messageId: message.id, timecode: nil))
}
}) })
}
if immediate {
action()
return
}
actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewMessage, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: {
action()
})) }))
case .reaction: case .reaction:
return return

View File

@ -518,7 +518,7 @@ final class StoryItemSetViewListComponent: Component {
)).string )).string
if let story = item.story, !story.text.isEmpty { if let story = item.story, !story.text.isEmpty {
dateText += " • commented" dateText += component.strings.Story_Views_Commented
} }
let subtitleAccessory: PeerListItemComponent.SubtitleAccessory let subtitleAccessory: PeerListItemComponent.SubtitleAccessory

View File

@ -118,6 +118,7 @@ import WebsiteType
import ChatQrCodeScreen import ChatQrCodeScreen
import PeerInfoScreen import PeerInfoScreen
import MediaEditorScreen import MediaEditorScreen
import WallpaperGalleryScreen
public enum ChatControllerPeekActions { public enum ChatControllerPeekActions {
case standard case standard
@ -18780,10 +18781,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let context = self.context let context = self.context
let subject: Signal<MediaEditorScreen.Subject?, NoError> = .single(.message(messages.map { $0.id })) let subject: Signal<MediaEditorScreen.Subject?, NoError> = .single(.message(messages.map { $0.id }))
let initialCaption: NSAttributedString? = nil
let initialPrivacy: EngineStoryPrivacy? = nil
let initialMediaAreas: [MediaArea] = []
let externalState = MediaEditorTransitionOutExternalState( let externalState = MediaEditorTransitionOutExternalState(
storyTarget: nil, storyTarget: nil,
isPeerArchived: false, isPeerArchived: false,
@ -18793,28 +18790,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let controller = MediaEditorScreen( let controller = MediaEditorScreen(
context: context, context: context,
subject: subject, subject: subject,
isEditing: false,
forwardSource: nil,
initialCaption: initialCaption,
initialPrivacy: initialPrivacy,
initialMediaAreas: initialMediaAreas,
initialVideoPosition: nil,
transitionIn: nil, transitionIn: nil,
transitionOut: { _, _ in transitionOut: { _, _ in
return nil return nil
}, },
completion: { result, commit in completion: { [weak self] result, commit in
guard let self else {
return
}
let targetPeerId: EnginePeer.Id
let target: Stories.PendingTarget let target: Stories.PendingTarget
if let sendAsPeerId = result.options.sendAsPeerId { if let sendAsPeerId = result.options.sendAsPeerId {
target = .peer(sendAsPeerId) target = .peer(sendAsPeerId)
targetPeerId = sendAsPeerId
} else { } else {
target = .myStories target = .myStories
targetPeerId = self.context.account.peerId
} }
externalState.storyTarget = target externalState.storyTarget = target
if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface { if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
rootController.proceedWithStoryUpload(target: target, result: result, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit) rootController.proceedWithStoryUpload(target: target, result: result, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit)
} }
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: targetPeerId))
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let self, let peer else {
return
}
let text: String
if case .channel = peer {
text = self.presentationData.strings.Story_MessageReposted_Channel(peer.compactDisplayTitle).string
} else {
text = self.presentationData.strings.Story_MessageReposted_Personal
}
self.present(UndoOverlayController(presentationData: self.presentationData, content: .succeed(text: text, timeout: nil, customUndoText: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
})
} }
) )
self.push(controller) self.push(controller)

View File

@ -19,6 +19,7 @@ import CameraScreen
import MediaEditorScreen import MediaEditorScreen
import ChatControllerInteraction import ChatControllerInteraction
import SavedMessagesScreen import SavedMessagesScreen
import WallpaperGalleryScreen
public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParams) { public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParams) {
if case let .peer(peer) = params.chatLocation { if case let .peer(peer) = params.chatLocation {

View File

@ -23,6 +23,7 @@ import UndoUI
import WebsiteType import WebsiteType
import GalleryData import GalleryData
import StoryContainerScreen import StoryContainerScreen
import WallpaperGalleryScreen
func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
var story: TelegramMediaStory? var story: TelegramMediaStory?

View File

@ -31,6 +31,7 @@ import PremiumUI
import AuthorizationUI import AuthorizationUI
import ChatFolderLinkPreviewScreen import ChatFolderLinkPreviewScreen
import StoryContainerScreen import StoryContainerScreen
import WallpaperGalleryScreen
private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer { private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer {
if case .default = navigation { if case .default = navigation {