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";
"Wallpaper.ApplyForChannel" = "Apply For This Channel";
"Notification.ChannelChangedWallpaper" = "Channel set a new wallpaper";
"Chat.Giveaway.Message.WinnersSelectedTitle.One" = "Winner Selected!";
"Chat.Giveaway.Message.WinnersSelectedTitle.Many" = "Winners Selected!";
"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.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 {
minSize.width += sideInset
}
if self.item.additionalLeftIcon != nil {
minSize.width += 24.0
minSize.width += iconSideInset
minSize.width += iconSpacing
}
if let forcedHeight {
minSize.height = forcedHeight
} else {

View File

@ -2,10 +2,12 @@ import Foundation
import UIKit
import Display
import SwiftSignalKit
import TelegramCore
import LegacyComponents
import TelegramPresentationData
import DeviceAccess
import AccountContext
import LocalMediaResources
public func legacyWallpaperPicker(context: AccountContext, presentationData: PresentationData, subject: DeviceAccessMediaLibrarySubject = .wallpaper) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> {
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)
pushController(controller)
}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Close, action: {})
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Close, action: {})
],
actionLayout: .vertical,
parseMarkdown: true

View File

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

View File

@ -12,6 +12,7 @@ import LegacyUI
import LegacyMediaPickerUI
import LocalMediaResources
import ImageBlur
import WallpaperGalleryScreen
func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (ViewController) -> Void, push: @escaping (ViewController) -> Void) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -318,77 +319,3 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
return croppedImage
}).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 PresentationDataUtils
import MediaResources
import WallpaperGalleryScreen
private let randomBackgroundColors: [Int32] = [0x007aff, 0x00c2ed, 0x29b327, 0xeb6ca4, 0xf08200, 0x9472ee, 0xd33213, 0xedb400, 0x6d839e]

View File

@ -14,6 +14,7 @@ import PresentationDataUtils
import WallpaperBackgroundNode
import AnimationCache
import MultiAnimationRenderer
import WallpaperGalleryScreen
private func generateMaskImage(color: UIColor) -> UIImage? {
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 AccountContext
import AttachmentUI
import WallpaperGalleryScreen
private func availableGradients(dark: Bool) -> [[UInt32]] {
if dark {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,6 +14,7 @@ import LegacyComponents
import WallpaperBackgroundNode
import AnimationCache
import MultiAnimationRenderer
import WallpaperGalleryScreen
private func generateMaskImage(color: UIColor) -> UIImage? {
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/UIKitRuntimeUtils",
"//submodules/TelegramUI/Components/SavedMessages/SavedMessagesScreen",
"//submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen",
] + select({
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
"//build-system:ios_sim_arm64": [],

View File

@ -580,7 +580,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
var viewCount: Int?
var dateReplies = 0
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 = ([], [])
}
for attribute in message.attributes {

View File

@ -531,7 +531,6 @@ private final class PeerInfoInteraction {
let performBotCommand: (PeerInfoBotCommand) -> Void
let editingOpenPublicLinkSetup: () -> Void
let editingOpenNameColorSetup: () -> Void
let editingOpenPeerWallpaperSetup: () -> Void
let editingOpenInviteLinksSetup: () -> Void
let editingOpenDiscussionGroupSetup: () -> Void
let editingToggleMessageSignatures: (Bool) -> Void
@ -587,7 +586,6 @@ private final class PeerInfoInteraction {
performBotCommand: @escaping (PeerInfoBotCommand) -> Void,
editingOpenPublicLinkSetup: @escaping () -> Void,
editingOpenNameColorSetup: @escaping () -> Void,
editingOpenPeerWallpaperSetup: @escaping () -> Void,
editingOpenInviteLinksSetup: @escaping () -> Void,
editingOpenDiscussionGroupSetup: @escaping () -> Void,
editingToggleMessageSignatures: @escaping (Bool) -> Void,
@ -642,7 +640,6 @@ private final class PeerInfoInteraction {
self.performBotCommand = performBotCommand
self.editingOpenPublicLinkSetup = editingOpenPublicLinkSetup
self.editingOpenNameColorSetup = editingOpenNameColorSetup
self.editingOpenPeerWallpaperSetup = editingOpenPeerWallpaperSetup
self.editingOpenInviteLinksSetup = editingOpenInviteLinksSetup
self.editingOpenDiscussionGroupSetup = editingOpenDiscussionGroupSetup
self.editingToggleMessageSignatures = editingToggleMessageSignatures
@ -1581,7 +1578,6 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
case .broadcast:
let ItemUsername = 1
let ItemPeerColor = 2
let ItemPeerWallpaper = 3
let ItemInviteLinks = 4
let ItemDiscussionGroup = 5
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: {
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)) {
@ -2364,9 +2356,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
editingOpenNameColorSetup: { [weak self] in
self?.editingOpenNameColorSetup()
},
editingOpenPeerWallpaperSetup: { [weak self] in
self?.editingOpenPeerWallpaperSetup()
},
editingOpenInviteLinksSetup: { [weak self] in
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))
}
}
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() {
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/Components/ComponentDisplayAdapters",
"//submodules/WallpaperResources",
"//submodules/MediaPickerUI",
"//submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen",
],
visibility = [
"//visibility:public",

View File

@ -1,5 +1,6 @@
import Foundation
import UIKit
import Photos
import Display
import AsyncDisplayKit
import SwiftSignalKit
@ -29,6 +30,8 @@ import EmojiStatusComponent
import DynamicCornerRadiusView
import ComponentDisplayAdapters
import WallpaperResources
import MediaPickerUI
import WallpaperGalleryScreen
private final class EmojiActionIconComponent: Component {
let context: AccountContext
@ -590,6 +593,58 @@ final class ChannelAppearanceScreenComponent: Component {
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 {
case reply
case profile
@ -1055,7 +1110,7 @@ final class ChannelAppearanceScreenComponent: Component {
guard let self else {
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()
}()
final class SettingsThemeWallpaperNode: ASDisplayNode {
var wallpaper: TelegramWallpaper?
public final class SettingsThemeWallpaperNode: ASDisplayNode {
public var wallpaper: TelegramWallpaper?
private var arguments: PatternWallpaperArguments?
let buttonNode = HighlightTrackingButtonNode()
let backgroundNode = ASImageNode()
let imageNode = TransformImageNode()
public let buttonNode = HighlightTrackingButtonNode()
public let backgroundNode = ASImageNode()
public let imageNode = TransformImageNode()
private var gradientNode: GradientBackgroundNode?
private let statusNode: RadialStatusNode
var pressed: (() -> Void)?
public var pressed: (() -> Void)?
private let displayLoading: Bool
private var isSelected: Bool = false
@ -60,7 +60,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
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.imageNode.contentAnimations = [.subsequentUpdates]
@ -83,7 +83,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
self.isLoadedDisposable.dispose()
}
func setSelected(_ selected: Bool, animated: Bool = false) {
public func setSelected(_ selected: Bool, animated: Bool = false) {
if 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
}
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.backgroundNode.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 {
override class var layerClass : AnyClass {
public class BlurView: UIView {
public override class var layerClass : AnyClass {
return BlurLayer.self
}
@ -71,7 +71,7 @@ class BlurView: UIView {
return Queue(name: nil, qos: .userInteractive)
}()
open var blurRadius: CGFloat {
public var blurRadius: CGFloat {
set { self.blurLayer.blurRadius = newValue }
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
if let image = self.image {
self.draw(image, blurRadius: blurRadius)
@ -112,19 +112,19 @@ class BlurView: UIView {
}
}
final class BlurredImageNode: ASDisplayNode {
var image: UIImage? {
public final class BlurredImageNode: ASDisplayNode {
public var image: UIImage? {
didSet {
self.blurView.image = self.image
self.blurView.layer.setNeedsDisplay()
}
}
var blurView: BlurView {
public var blurView: BlurView {
return (self.view as? BlurView)!
}
override init() {
public override init() {
super.init()
self.setViewBlock({

View File

@ -313,15 +313,26 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
}
}
struct WallpaperColorPanelNodeState: Equatable {
var selection: Int?
var colors: [HSBColor]
var maximumNumberOfColors: Int
var rotateAvailable: Bool
var rotation: Int32
var preview: Bool
var simpleGradientGeneration: Bool
var suggestedNewColor: HSBColor?
public struct WallpaperColorPanelNodeState: Equatable {
public var selection: Int?
public var colors: [HSBColor]
public var maximumNumberOfColors: Int
public var rotateAvailable: Bool
public var rotation: Int32
public var preview: Bool
public var simpleGradientGeneration: Bool
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 {
@ -377,7 +388,7 @@ private final class ColorSampleItemNode: ASImageNode {
}
}
final class WallpaperColorPanelNode: ASDisplayNode {
public final class WallpaperColorPanelNode: ASDisplayNode {
private var theme: PresentationTheme
private var state: WallpaperColorPanelNodeState
@ -394,16 +405,16 @@ final class WallpaperColorPanelNode: ASDisplayNode {
private var sampleItemNodes: [ColorSampleItemNode] = []
private let multiColorFieldNode: ColorInputFieldNode
var colorsChanged: (([HSBColor], Int, Bool) -> Void)?
var colorSelected: (() -> Void)?
var rotate: (() -> Void)?
public var colorsChanged: (([HSBColor], Int, Bool) -> Void)?
public var colorSelected: (() -> Void)?
public var rotate: (() -> Void)?
var colorAdded: (() -> Void)?
var colorRemoved: (() -> Void)?
public var colorAdded: (() -> Void)?
public var colorRemoved: (() -> Void)?
private var validLayout: (CGSize, CGFloat)?
init(theme: PresentationTheme, strings: PresentationStrings) {
public init(theme: PresentationTheme, strings: PresentationStrings) {
self.theme = theme
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.backgroundNode.updateColor(color: self.theme.chat.inputPanel.panelBackgroundColor, transition: .immediate)
self.topSeparatorNode.backgroundColor = self.theme.chat.inputPanel.panelSeparatorColor
@ -520,7 +531,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
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
let previousColors = self.state.colors
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)
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) {
return result
}

View File

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

View File

@ -401,7 +401,7 @@ public class WallpaperGalleryController: ViewController {
self.colorsPanelNode?.updateTheme(self.presentationData.theme)
}
func dismiss(forceAway: Bool) {
public func dismiss(forceAway: Bool) {
// let completion: () -> Void = { [weak self] in
// 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 centerOffset: CGFloat = 32.0
if let entry = self.entry {
switch entry {
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.updateAlpha(node: self.patternButtonNode, alpha: patternAlpha * alpha)
@ -1487,13 +1492,29 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
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
var peers = SimpleDictionary<PeerId, Peer>()
let 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)
var messages = SimpleDictionary<MessageId, Message>()
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 bottomMessageText = ""
var serviceMessageText: String?
@ -1566,10 +1587,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
if let mode = self.mode, case let .peer(peer, existing) = mode {
topMessageText = presentationData.strings.WallpaperPreview_ChatTopText
bottomMessageText = presentationData.strings.WallpaperPreview_ChatBottomText
if !existing {
serviceMessageText = presentationData.strings.WallpaperPreview_NotAppliedInfo(peer.compactDisplayTitle).string
if case .channel = peer {
topMessageText = presentationData.strings.WallpaperPreview_ChannelTopText
bottomMessageText = ""
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 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))
if !bottomMessageText.isEmpty {
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))
if let serviceMessageText {

View File

@ -5,12 +5,12 @@ import Display
import TelegramPresentationData
import ManagedAnimationNode
enum WallpaperGalleryToolbarCancelButtonType {
public enum WallpaperGalleryToolbarCancelButtonType {
case cancel
case discard
}
enum WallpaperGalleryToolbarDoneButtonType {
public enum WallpaperGalleryToolbarDoneButtonType {
case set
case setPeer(String, Bool)
case setChannel
@ -19,7 +19,7 @@ enum WallpaperGalleryToolbarDoneButtonType {
case none
}
protocol WallpaperGalleryToolbar: ASDisplayNode {
public protocol WallpaperGalleryToolbar: ASDisplayNode {
var cancelButtonType: WallpaperGalleryToolbarCancelButtonType { get set }
var doneButtonType: WallpaperGalleryToolbarDoneButtonType { get set }
@ -31,7 +31,7 @@ protocol WallpaperGalleryToolbar: ASDisplayNode {
func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition)
}
final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar {
public final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar {
class ButtonNode: ASDisplayNode {
private let doneButton = HighlightTrackingButtonNode()
private var doneButtonBackgroundNode: ASDisplayNode
@ -205,18 +205,18 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
private var theme: PresentationTheme
private let strings: PresentationStrings
var cancelButtonType: WallpaperGalleryToolbarCancelButtonType {
public var cancelButtonType: WallpaperGalleryToolbarCancelButtonType {
didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
}
}
var doneButtonType: WallpaperGalleryToolbarDoneButtonType {
public var doneButtonType: WallpaperGalleryToolbarDoneButtonType {
didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
}
}
var dark: Bool = false {
public var dark: Bool = false {
didSet {
self.applyButton.dark = self.dark
self.applyForBothButton.dark = self.dark
@ -226,10 +226,10 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
private let applyButton = ButtonNode()
private let applyForBothButton = ButtonNode()
var cancel: (() -> Void)?
var done: ((Bool) -> Void)?
public var cancel: (() -> 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.strings = strings
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.applyForBothButton.setEnabled(enabled)
}
private var isSolid = false
func setDoneIsSolid(_ isSolid: Bool, transition: ContainedViewLayoutTransition) {
public func setDoneIsSolid(_ isSolid: Bool, transition: ContainedViewLayoutTransition) {
guard self.isSolid != isSolid else {
return
}
@ -272,7 +272,7 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
self.applyForBothButton.setIsSolid(isSolid, transition: transition)
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
self.theme = theme
let applyTitle: String
@ -303,7 +303,7 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode, WallpaperGalleryToolbar
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 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 let strings: PresentationStrings
var cancelButtonType: WallpaperGalleryToolbarCancelButtonType {
public var cancelButtonType: WallpaperGalleryToolbarCancelButtonType {
didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
}
}
var doneButtonType: WallpaperGalleryToolbarDoneButtonType {
public var doneButtonType: WallpaperGalleryToolbarDoneButtonType {
didSet {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings)
}
@ -352,10 +352,10 @@ final class WallpaperGalleryOldToolbarNode: ASDisplayNode, WallpaperGalleryToolb
private let separatorNode = ASDisplayNode()
private let topSeparatorNode = ASDisplayNode()
var cancel: (() -> Void)?
var done: ((Bool) -> Void)?
public var cancel: (() -> 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.strings = strings
self.cancelButtonType = cancelButtonType
@ -404,12 +404,12 @@ final class WallpaperGalleryOldToolbarNode: ASDisplayNode, WallpaperGalleryToolb
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.isUserInteractionEnabled = enabled
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
self.theme = theme
self.backgroundNode.updateColor(color: theme.rootController.tabBar.backgroundColor, transition: .immediate)
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: [])
}
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.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))

View File

@ -6,7 +6,7 @@ import SwiftSignalKit
import CheckNode
import AnimationUI
enum WallpaperOptionButtonValue {
public enum WallpaperOptionButtonValue {
case check(Bool)
case color(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
private let checkNode: CheckNode
@ -281,7 +281,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
private var textSize: CGSize?
private var _value: WallpaperOptionButtonValue
override var isSelected: Bool {
public override var isSelected: Bool {
get {
switch self._value {
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 {
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.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 {
}
}
var color: UIColor? {
public var color: UIColor? {
get {
switch self._value {
case let .color(_, color):
@ -395,7 +395,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
}
}
var colors: [UIColor]? {
public var colors: [UIColor]? {
get {
switch self._value {
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 {
case .check:
self._value = .check(selected)
@ -441,7 +441,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
self.checkNode.setSelected(selected, animated: animated)
}
func setEnabled(_ enabled: Bool) {
public func setEnabled(_ enabled: Bool) {
let alpha: CGFloat = enabled ? 1.0 : 0.4
self.checkNode.alpha = alpha
self.colorNode.alpha = alpha
@ -449,13 +449,13 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
self.isUserInteractionEnabled = enabled
}
override func measure(_ constrainedSize: CGSize) -> CGSize {
public override func measure(_ constrainedSize: CGSize) -> CGSize {
let size = self.textNode.updateLayout(constrainedSize)
self.textSize = size
return CGSize(width: ceil(size.width) + 48.0, height: 30.0)
}
override func layout() {
public override func layout() {
super.layout()
self.backgroundNode.frame = self.bounds

View File

@ -9,6 +9,7 @@ import LegacyComponents
import AccountContext
import MergeLists
import Postbox
import SettingsThemeWallpaperNode
private let itemSize = CGSize(width: 88.0, height: 88.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 var theme: PresentationTheme
private let backgroundNode: NavigationBackgroundNode
private let topSeparatorNode: ASDisplayNode
let scrollNode: ASScrollNode
public let scrollNode: ASScrollNode
private let titleNode: ImmediateTextNode
private let labelNode: ImmediateTextNode
private var sliderView: TGPhotoEditorSliderView?
private var disposable: Disposable?
var wallpapers: [TelegramWallpaper] = []
public var wallpapers: [TelegramWallpaper] = []
private var currentWallpaper: TelegramWallpaper?
var serviceBackgroundColor: UIColor = UIColor(rgb: 0x748698) {
public var serviceBackgroundColor: UIColor = UIColor(rgb: 0x748698) {
didSet {
guard let nodes = self.scrollNode.subnodes else {
return
@ -200,7 +201,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
}
}
var backgroundColors: ([HSBColor], Int32?, Int32?)? = nil {
public var backgroundColors: ([HSBColor], Int32?, Int32?)? = nil {
didSet {
var updated = false
if oldValue?.0 != self.backgroundColors?.0 || oldValue?.1 != self.backgroundColors?.1 {
@ -223,11 +224,11 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
private var validLayout: (CGSize, CGFloat)?
var patternChanged: ((TelegramWallpaper?, Int32?, Bool) -> Void)?
public var patternChanged: ((TelegramWallpaper?, Int32?, Bool) -> Void)?
private let allowDark: Bool
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) {
public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) {
self.context = context
self.theme = theme
self.allowDark = theme.overallDarkAppearance
@ -287,7 +288,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
self.disposable?.dispose()
}
override func didLoad() {
public override func didLoad() {
super.didLoad()
self.scrollNode.view.showsHorizontalScrollIndicator = false
@ -320,7 +321,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
self.sliderView = sliderView
}
func updateWallpapers() {
public func updateWallpapers() {
guard let subnodes = self.scrollNode.subnodes else {
return
}
@ -386,7 +387,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
self.layoutItemNodes(transition: .immediate)
}
func updateTheme(_ theme: PresentationTheme) {
public func updateTheme(_ theme: PresentationTheme) {
self.theme = theme
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?
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)
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
let usernamesString = String(usernames.map { "@\($0)" }.joined(separator: ", "))
let alertController = textAlertController(
context: component.context,
forceTheme: defaultDarkColorPresentationTheme,
title: environment.strings.Story_Privacy_MentionRestrictedTitle,
text: environment.strings.Story_Privacy_MentionRestrictedText(usernamesString).string,
actions: [
TextAlertAction(type: .defaultAction, title: environment.strings.Story_Privacy_MentionRestrictedProceed, action: {
proceed()
}),
TextAlertAction(type: .genericAction, title: environment.strings.Common_Cancel, action: {})
],
actionLayout: .vertical
)
controller.present(alertController, in: .window(.root))
}
func matchingUsername(user: TelegramUser, usernames: Set<String>) -> String? {
for username in user.usernames {
if usernames.contains(username.username) {
return username.username
}
if let sendAsPeerId = self.sendAsPeerId, sendAsPeerId.isGroupOrChannel {
proceed()
} else {
let presentAlert: ([String]) -> Void = { usernames in
let usernamesString = String(usernames.map { "@\($0)" }.joined(separator: ", "))
let alertController = textAlertController(
context: component.context,
forceTheme: defaultDarkColorPresentationTheme,
title: environment.strings.Story_Privacy_MentionRestrictedTitle,
text: environment.strings.Story_Privacy_MentionRestrictedText(usernamesString).string,
actions: [
TextAlertAction(type: .defaultAction, title: environment.strings.Story_Privacy_MentionRestrictedProceed, action: {
proceed()
}),
TextAlertAction(type: .genericAction, title: environment.strings.Common_Cancel, action: {})
],
actionLayout: .vertical
)
controller.present(alertController, in: .window(.root))
}
if let username = user.username {
if usernames.contains(username) {
return username
func matchingUsername(user: TelegramUser, usernames: Set<String>) -> String? {
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
if case .stories = component.stateContext.subject {
if component.mentions.isEmpty {
proceed()
} else if case .nobody = base {
if selectedPeerIds.isEmpty {
presentAlert(component.mentions)
} else {
let _ = (context.account.postbox.transaction { transaction in
var filteredMentions = Set(component.mentions)
for peerId in selectedPeerIds {
if let peer = transaction.getPeer(peerId) {
if let user = peer as? TelegramUser {
if let username = matchingUsername(user: user, usernames: filteredMentions) {
filteredMentions.remove(username)
}
} else {
if let username = peer.addressName {
filteredMentions.remove(username)
let context = component.context
let selectedPeerIds = self.selectedPeers
if case .stories = component.stateContext.subject {
if component.mentions.isEmpty {
proceed()
} else if case .nobody = base {
if selectedPeerIds.isEmpty {
presentAlert(component.mentions)
} else {
let _ = (context.account.postbox.transaction { transaction in
var filteredMentions = Set(component.mentions)
for peerId in selectedPeerIds {
if let peer = transaction.getPeer(peerId) {
if let user = peer as? TelegramUser {
if let username = matchingUsername(user: user, usernames: filteredMentions) {
filteredMentions.remove(username)
}
} else {
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)
}
|> deliverOnMainQueue).start(next: { mentions in
|> 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
} 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)
}
}
if case let .user(user) = peer, 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)
}
}
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 {
proceed()
}
} else {
proceed()
}
}
)),

View File

@ -96,6 +96,7 @@ public final class ForwardInfoPanelComponent: Component {
iconView.alpha = 0.55
iconView.tintColor = .white
self.addSubview(iconView)
self.iconView = iconView
}
if let image = iconView.image {
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 {
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(
id: item.id,
timestamp: item.timestamp,
@ -248,7 +263,7 @@ public final class StoryContentContextImpl: StoryContentContext {
isEdited: item.isEdited,
isMy: item.isMy,
myReaction: item.myReaction,
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
forwardInfo: forwardInfo
)
}
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 {
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(
id: itemValue.id,
timestamp: itemValue.timestamp,
@ -1218,7 +1247,7 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
isEdited: itemValue.isEdited,
isMy: itemValue.isMy,
myReaction: itemValue.myReaction,
forwardInfo: itemValue.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
forwardInfo: forwardInfo
)
let mainItem = StoryContentItem(
@ -2073,13 +2102,22 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
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.peerId = peerId
self.currentFocusedId = initialFocusedId
self.currentFocusedIdUpdatedPromise.set(.single(Void()))
let originalStoryId = StoryId(peerId: originalPeerId, id: originalStory.id)
let inputKeys: [PostboxViewKey] = [
PostboxViewKey.basicPeer(peerId),
PostboxViewKey.cachedPeerData(peerId: peerId),
@ -2098,53 +2136,43 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
var forwardInfoStories: [StoryId: EngineStoryItem?] = [:]
var allEntityFiles: [MediaId: TelegramMediaFile] = [:]
if let itemsView = views.views[PostboxViewKey.storyItems(peerId: peerId)] as? StoryItemsView {
for item in itemsView.items {
if let item = item.value.get(Stories.StoredItem.self), case let .item(itemValue) = item {
if let views = itemValue.views {
for peerId in views.seenPeerIds {
if let peer = transaction.getPeer(peerId) {
peers[peer.id] = peer
}
}
}
if let forwardInfo = itemValue.forwardInfo, case let .known(peerId, id, _) = forwardInfo {
if let peer = transaction.getPeer(peerId) {
peers[peer.id] = peer
}
let storyId = StoryId(peerId: peerId, id: id)
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 item in items {
if let forwardInfo = item.forwardInfo, case let .known(peer, id, _) = forwardInfo {
let storyId = StoryId(peerId: peer.id, id: id)
if storyId == originalStoryId {
forwardInfoStories[storyId] = originalStory
} else {
forwardInfoStories.updateValue(nil, forKey: storyId)
}
}
for entity in item.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 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)
}
}
@ -2163,7 +2191,6 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
if let presencesView = views.views[PostboxViewKey.peerPresences(peerIds: Set([peerId]))] as? PeerPresencesView {
peerPresence = presencesView.presences[peerId]
}
for (storyId, story) in forwardInfoStories {
let promise: Promise<EngineStoryItem?>
var added = false
@ -2174,7 +2201,9 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
self.currentForwardInfoStories[storyId] = promise
added = true
}
if let story {
if storyId == originalStoryId {
promise.set(.single(originalStory))
} else if let story {
promise.set(.single(story))
} else if added {
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 })
do {
let mappedItem = mappedItems[focusedIndex]
@ -2416,6 +2444,8 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
}
private let context: AccountContext
private let originalPeerId: EnginePeer.Id
private let originalStory: EngineStoryItem
private let viewListContext: EngineStoryViewListContext
private let readGlobally: Bool
@ -2449,11 +2479,15 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
public init(
context: AccountContext,
originalPeerId: EnginePeer.Id,
originalStory: EngineStoryItem,
focusedStoryId: StoryId,
viewListContext: EngineStoryViewListContext,
readGlobally: Bool
) {
self.context = context
self.originalPeerId = originalPeerId
self.originalStory = originalStory
self.focusedItem = (focusedStoryId.peerId, focusedStoryId.id)
self.viewListContext = viewListContext
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) {
centralPeerContext = existingContext
} 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?
@ -2538,7 +2572,7 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: currentStoryItems[centralIndex - 1].peer.id) {
previousPeerContext = existingContext
} 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) {
nextPeerContext = existingContext
} 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 textSelectionAction: (NSAttributedString, TextSelectionAction) -> Void
let controller: () -> ViewController?
let openStory: (EnginePeer, EngineStoryItem) -> Void
let openStory: (EnginePeer, EngineStoryItem?) -> Void
init(
externalState: ExternalState,
@ -85,7 +85,7 @@ final class StoryContentCaptionComponent: Component {
longTapAction: @escaping (Action) -> Void,
textSelectionAction: @escaping (NSAttributedString, TextSelectionAction) -> Void,
controller: @escaping () -> ViewController?,
openStory: @escaping (EnginePeer, EngineStoryItem) -> Void
openStory: @escaping (EnginePeer, EngineStoryItem?) -> Void
) {
self.externalState = externalState
self.context = context
@ -692,9 +692,9 @@ final class StoryContentCaptionComponent: Component {
}
}
})
text = nil
text = ""
} else {
text = nil
text = ""
}
case let .unknown(name, _):
authorName = name
@ -727,8 +727,8 @@ final class StoryContentCaptionComponent: Component {
effectAlignment: .center,
minSize: nil,
action: { [weak self] in
if let self, case let .known(peer, _, _) = forwardInfo, let story = self.forwardInfoStory {
self.component?.openStory(peer, story)
if let self, case let .known(peer, _, _) = forwardInfo {
self.component?.openStory(peer, self.forwardInfoStory)
} 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)
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 {
return
}
let context = component.context
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 {
return
}
if let nextController = controller.navigationController?.viewControllers.last as? StoryContainerScreen {
nextController.customBackAction = { [weak nextController] in
context.sharedContext.openResolvedUrl(
currentResult,
context: context,
urlContext: .generic,
navigationController: nextController?.navigationController as? NavigationController,
forceExternal: false,
openPeer: { _, _ in
},
sendFile: nil,
sendSticker: nil,
requestMessageActionUrlAuth: nil,
joinVoiceChat: nil,
present: { _, _ in
},
dismissInput: {
},
contentContext: nil,
progress: nil,
completion: { [weak nextController] in
Queue.mainQueue().after(0.5) {
nextController?.dismissWithoutTransitionOut()
if let story {
let context = component.context
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 {
return
}
if let nextController = controller.navigationController?.viewControllers.last as? StoryContainerScreen {
nextController.customBackAction = { [weak nextController] in
context.sharedContext.openResolvedUrl(
currentResult,
context: context,
urlContext: .generic,
navigationController: nextController?.navigationController as? NavigationController,
forceExternal: false,
openPeer: { _, _ in
},
sendFile: nil,
sendSticker: nil,
requestMessageActionUrlAuth: nil,
joinVoiceChat: nil,
present: { _, _ in
},
dismissInput: {
},
contentContext: nil,
progress: nil,
completion: { [weak nextController] in
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: {},
@ -5196,7 +5205,7 @@ public final class StoryItemSetContainerComponent: Component {
}
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
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak controller, weak viewListView, weak sourceView] _ in

View File

@ -3264,8 +3264,8 @@ final class StoryItemSetContainerSendMessage {
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 {
return
}
@ -3278,8 +3278,8 @@ final class StoryItemSetContainerSendMessage {
var actions: [ContextMenuAction] = []
switch mediaArea {
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: [:])
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 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(
context: context,
updatedPresentationData: updatedPresentationData,
@ -3302,9 +3302,16 @@ final class StoryItemSetContainerSendMessage {
})
}
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):
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)
|> mapToSignal { result -> Signal<Message?, NoError> in
if case let .result(messages) = result {
@ -3312,12 +3319,21 @@ final class StoryItemSetContainerSendMessage {
}
return .single(nil)
})
|> deliverOnMainQueue).startStandalone(next: { message in
guard let message else {
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak view] message in
guard let self, let view else {
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:
return

View File

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

View File

@ -118,6 +118,7 @@ import WebsiteType
import ChatQrCodeScreen
import PeerInfoScreen
import MediaEditorScreen
import WallpaperGalleryScreen
public enum ChatControllerPeekActions {
case standard
@ -18780,10 +18781,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let context = self.context
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(
storyTarget: nil,
isPeerArchived: false,
@ -18793,28 +18790,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let controller = MediaEditorScreen(
context: context,
subject: subject,
isEditing: false,
forwardSource: nil,
initialCaption: initialCaption,
initialPrivacy: initialPrivacy,
initialMediaAreas: initialMediaAreas,
initialVideoPosition: nil,
transitionIn: nil,
transitionOut: { _, _ in
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
if let sendAsPeerId = result.options.sendAsPeerId {
target = .peer(sendAsPeerId)
targetPeerId = sendAsPeerId
} else {
target = .myStories
targetPeerId = self.context.account.peerId
}
externalState.storyTarget = target
if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
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)

View File

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

View File

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

View File

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