Youtube player fixes

This commit is contained in:
Ilya Laktyushin 2020-10-06 09:23:16 +04:00
parent 7fb0b48ded
commit c899d1dfa7
25 changed files with 1301 additions and 1183 deletions

View File

@ -4098,7 +4098,7 @@ Unused sets are archived when you add more.";
"GroupPermission.PermissionGloballyDisabled" = "This permission is disabled in this group."; "GroupPermission.PermissionGloballyDisabled" = "This permission is disabled in this group.";
"ChannelInfo.Stats" = "Statistics"; "ChannelInfo.Stats" = "View Statistics";
"Conversation.PressVolumeButtonForSound" = "Press volume button\nto unmute the video"; "Conversation.PressVolumeButtonForSound" = "Press volume button\nto unmute the video";
@ -5813,3 +5813,5 @@ Any member of this group will be able to see messages in the channel.";
"Channel.CommentsGroup.HeaderGroupSet" = "%@ is linking the group as it's discussion board."; "Channel.CommentsGroup.HeaderGroupSet" = "%@ is linking the group as it's discussion board.";
"RepliesChat.DescriptionText" = "This chat helps you keep track of replies to your comments in Channels."; "RepliesChat.DescriptionText" = "This chat helps you keep track of replies to your comments in Channels.";
"Conversation.ContextViewStats" = "View Statistics";

View File

@ -1494,6 +1494,18 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
if let strongSelf = self { if let strongSelf = self {
strongSelf.presentationData = presentationData strongSelf.presentationData = presentationData
strongSelf.presentationDataPromise.set(.single(ChatListPresentationData(theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations))) strongSelf.presentationDataPromise.set(.single(ChatListPresentationData(theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)))
strongSelf.listNode.forEachItemHeaderNode({ itemHeaderNode in
if let itemHeaderNode = itemHeaderNode as? ChatListSearchItemHeaderNode {
itemHeaderNode.updateTheme(theme: presentationData.theme)
}
})
strongSelf.recentListNode.forEachItemHeaderNode({ itemHeaderNode in
if let itemHeaderNode = itemHeaderNode as? ChatListSearchItemHeaderNode {
itemHeaderNode.updateTheme(theme: presentationData.theme)
}
})
} }
}) })

View File

@ -210,7 +210,9 @@ public func galleryItemForEntry(context: AccountContext, presentationData: Prese
content = SystemVideoContent(url: embedUrl, imageReference: .webPage(webPage: WebpageReference(webpage), media: image), dimensions: webpageContent.embedSize?.cgSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0)) content = SystemVideoContent(url: embedUrl, imageReference: .webPage(webPage: WebpageReference(webpage), media: image), dimensions: webpageContent.embedSize?.cgSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0))
} }
} }
if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent, forcedTimestamp: timecode.flatMap(Int.init)) { if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent, forcedTimestamp: timecode.flatMap(Int.init), openUrl: { url in
performAction(.url(url: url.absoluteString, concealed: false))
}) {
content = webEmbedContent content = webEmbedContent
} }
} }

View File

@ -493,6 +493,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var disablePictureInPicture = false var disablePictureInPicture = false
var disablePlayerControls = false var disablePlayerControls = false
var forceEnablePiP = false var forceEnablePiP = false
var forceEnableUserInteraction = false
var isAnimated = false var isAnimated = false
if let content = item.content as? NativeVideoContent { if let content = item.content as? NativeVideoContent {
isAnimated = content.fileReference.media.isAnimated isAnimated = content.fileReference.media.isAnimated
@ -503,6 +504,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
let type = webEmbedType(content: content.webpageContent) let type = webEmbedType(content: content.webpageContent)
switch type { switch type {
case .youtube: case .youtube:
forceEnableUserInteraction = true
disablePictureInPicture = !(item.configuration?.youtubePictureInPictureEnabled ?? false) disablePictureInPicture = !(item.configuration?.youtubePictureInPictureEnabled ?? false)
self.videoFramePreview = YoutubeEmbedFramePreview(context: item.context, content: content) self.videoFramePreview = YoutubeEmbedFramePreview(context: item.context, content: content)
case .iframe: case .iframe:
@ -527,7 +529,14 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
let mediaManager = item.context.sharedContext.mediaManager let mediaManager = item.context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: item.content, priority: .gallery) let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: item.content, priority: .gallery)
let videoSize = CGSize(width: item.content.dimensions.width * 2.0, height: item.content.dimensions.height * 2.0)
let videoScale: CGFloat
if item.content is WebEmbedVideoContent {
videoScale = 1.0
} else {
videoScale = 2.0
}
let videoSize = CGSize(width: item.content.dimensions.width * videoScale, height: item.content.dimensions.height * videoScale)
videoNode.updateLayout(size: videoSize, transition: .immediate) videoNode.updateLayout(size: videoSize, transition: .immediate)
videoNode.ownsContentNodeUpdated = { [weak self] value in videoNode.ownsContentNodeUpdated = { [weak self] value in
if let strongSelf = self { if let strongSelf = self {
@ -546,7 +555,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
} }
} }
self.videoNode = videoNode self.videoNode = videoNode
videoNode.isUserInteractionEnabled = disablePlayerControls videoNode.isUserInteractionEnabled = disablePlayerControls || forceEnableUserInteraction
videoNode.backgroundColor = videoNode.ownsContentNode ? UIColor.black : UIColor(rgb: 0x333335) videoNode.backgroundColor = videoNode.ownsContentNode ? UIColor.black : UIColor(rgb: 0x333335)
if item.fromPlayingVideo { if item.fromPlayingVideo {
videoNode.canAttachContent = false videoNode.canAttachContent = false

View File

@ -44,6 +44,15 @@ public class BaseLinesChartController: BaseChartController {
self.setBackButtonVisibilityClosure?(isZoomed, animated) self.setBackButtonVisibilityClosure?(isZoomed, animated)
updateChartRangeTitle(animated: animated) updateChartRangeTitle(animated: animated)
let initial = initialChartsCollection
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
if let lastDate = initial.axisValues.last {
TimeInterval.animationDurationMultipler = 0.00001
self.didTapZoomIn(date: lastDate, pointIndex: initial.axisValues.count - 1)
TimeInterval.animationDurationMultipler = 1.0
}
}
} }
func updateChartRangeTitle(animated: Bool) { func updateChartRangeTitle(animated: Bool) {

View File

@ -137,7 +137,9 @@ public struct InstantPageGalleryEntry: Equatable {
})) }))
}), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _ in }, present: { _, _ in }) }), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _ in }, present: { _, _ in })
} else { } else {
if let content = WebEmbedVideoContent(webPage: embedWebpage, webpageContent: webpageContent) { if let content = WebEmbedVideoContent(webPage: embedWebpage, webpageContent: webpageContent, openUrl: { url in
}) {
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage, nil), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _ in }, present: { _, _ in }) return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage, nil), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _ in }, present: { _, _ in })
} else { } else {
preconditionFailure() preconditionFailure()

View File

@ -39,7 +39,7 @@ private enum StatsEntry: ItemListNodeEntry {
case overview(PresentationTheme, MessageStats, Int32?) case overview(PresentationTheme, MessageStats, Int32?)
case interactionsTitle(PresentationTheme, String) case interactionsTitle(PresentationTheme, String)
case interactionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType) case interactionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, StatsGraph?, ChartType)
case publicForwardsTitle(PresentationTheme, String) case publicForwardsTitle(PresentationTheme, String)
case publicForward(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Message) case publicForward(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Message)
@ -92,8 +92,8 @@ private enum StatsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .interactionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph, lhsType): case let .interactionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph, lhsDetailedGraph, lhsType):
if case let .interactionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph, rhsType) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph, lhsType == rhsType { if case let .interactionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph, rhsDetailedGraph, rhsType) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph, lhsDetailedGraph == rhsDetailedGraph, lhsType == rhsType {
return true return true
} else { } else {
return false return false
@ -126,13 +126,17 @@ private enum StatsEntry: ItemListNodeEntry {
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .overview(_, stats, publicShares): case let .overview(_, stats, publicShares):
return MessageStatsOverviewItem(presentationData: presentationData, stats: stats, publicShares: publicShares, sectionId: self.section, style: .blocks) return MessageStatsOverviewItem(presentationData: presentationData, stats: stats, publicShares: publicShares, sectionId: self.section, style: .blocks)
case let .interactionsGraph(_, _, _, graph, type): case let .interactionsGraph(_, _, _, graph, detailedGraph, type):
return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, getDetailsData: { date, completion in return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, getDetailsData: { date, completion in
let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in if let detailedGraph = detailedGraph, case let .Loaded(_, data) = detailedGraph {
if let graph = graph, case let .Loaded(_, data) = graph { completion(data)
completion(data) } else {
} let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in
}) if let graph = graph, case let .Loaded(_, data) = graph {
completion(data)
}
})
}
}, sectionId: self.section, style: .blocks) }, sectionId: self.section, style: .blocks)
case let .publicForward(_, _, _, _, message): case let .publicForward(_, _, _, _, message):
var views: Int = 0 var views: Int = 0
@ -148,9 +152,6 @@ private enum StatsEntry: ItemListNodeEntry {
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .military, dateFormat: .dayFirst, dateSeparator: ".", decimalSeparator: ",", groupingSeparator: ""), nameDisplayOrder: .firstLast, context: arguments.context, peer: message.peers[message.id.peerId]!, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(text), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: { return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .military, dateFormat: .dayFirst, dateSeparator: ".", decimalSeparator: ",", groupingSeparator: ""), nameDisplayOrder: .firstLast, context: arguments.context, peer: message.peers[message.id.peerId]!, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(text), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: {
arguments.openMessage(message.id) arguments.openMessage(message.id)
}, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil)
// return StatsMessageItem(context: arguments.context, presentationData: presentationData, message: message, views: 0, forwards: 0, sectionId: self.section, style: .blocks, action: {
// arguments.openMessage(message.id)
// })
} }
} }
} }
@ -164,7 +165,7 @@ private func messageStatsControllerEntries(data: MessageStats?, messages: Search
if !data.interactionsGraph.isEmpty { if !data.interactionsGraph.isEmpty {
entries.append(.interactionsTitle(presentationData.theme, presentationData.strings.Stats_MessageInteractionsTitle.uppercased())) entries.append(.interactionsTitle(presentationData.theme, presentationData.strings.Stats_MessageInteractionsTitle.uppercased()))
entries.append(.interactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.interactionsGraph, .twoAxisStep)) entries.append(.interactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.interactionsGraph, data.detailedInteractionsGraph, .twoAxisStep))
} }
if let messages = messages, !messages.messages.isEmpty { if let messages = messages, !messages.messages.isEmpty {

View File

@ -9,11 +9,13 @@ public struct MessageStats: Equatable {
public let views: Int public let views: Int
public let forwards: Int public let forwards: Int
public let interactionsGraph: StatsGraph public let interactionsGraph: StatsGraph
public let detailedInteractionsGraph: StatsGraph?
init(views: Int, forwards: Int, interactionsGraph: StatsGraph) { init(views: Int, forwards: Int, interactionsGraph: StatsGraph, detailedInteractionsGraph: StatsGraph?) {
self.views = views self.views = views
self.forwards = forwards self.forwards = forwards
self.interactionsGraph = interactionsGraph self.interactionsGraph = interactionsGraph
self.detailedInteractionsGraph = detailedInteractionsGraph
} }
public static func == (lhs: MessageStats, rhs: MessageStats) -> Bool { public static func == (lhs: MessageStats, rhs: MessageStats) -> Bool {
@ -26,11 +28,14 @@ public struct MessageStats: Equatable {
if lhs.interactionsGraph != rhs.interactionsGraph { if lhs.interactionsGraph != rhs.interactionsGraph {
return false return false
} }
if lhs.detailedInteractionsGraph != rhs.detailedInteractionsGraph {
return false
}
return true return true
} }
public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> MessageStats { public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> MessageStats {
return MessageStats(views: self.views, forwards: self.forwards, interactionsGraph: self.interactionsGraph) return MessageStats(views: self.views, forwards: self.forwards, interactionsGraph: interactionsGraph, detailedInteractionsGraph: self.detailedInteractionsGraph)
} }
} }
@ -39,8 +44,7 @@ public struct MessageStatsContextState: Equatable {
} }
private func requestMessageStats(postbox: Postbox, network: Network, datacenterId: Int32, messageId: MessageId, dark: Bool = false) -> Signal<MessageStats?, NoError> { private func requestMessageStats(postbox: Postbox, network: Network, datacenterId: Int32, messageId: MessageId, dark: Bool = false) -> Signal<MessageStats?, NoError> {
return .single(nil) return postbox.transaction { transaction -> (Peer, Message)? in
/*return postbox.transaction { transaction -> (Peer, Message)? in
if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) { if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) {
return (peer, message) return (peer, message)
} else { } else {
@ -79,15 +83,25 @@ private func requestMessageStats(postbox: Postbox, network: Network, datacenterI
} }
return signal return signal
|> map { result -> MessageStats? in |> mapToSignal { result -> Signal<MessageStats?, MTRpcError> in
if case let .messageStats(apiViewsGraph) = result { if case let .messageStats(apiViewsGraph) = result {
return MessageStats(views: views, forwards: forwards, interactionsGraph: StatsGraph(apiStatsGraph: apiViewsGraph)) let interactionsGraph = StatsGraph(apiStatsGraph: apiViewsGraph)
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if case let .Loaded(tokenValue, _) = interactionsGraph, let token = tokenValue, Int64(message.timestamp + 60 * 60 * 24 * 2) > Int64(timestamp) {
return requestGraph(network: network, datacenterId: datacenterId, token: token, x: 1601596800000)
|> castError(MTRpcError.self)
|> map { detailedGraph -> MessageStats? in
return MessageStats(views: views, forwards: forwards, interactionsGraph: interactionsGraph, detailedInteractionsGraph: detailedGraph)
}
} else {
return .single(MessageStats(views: views, forwards: forwards, interactionsGraph: interactionsGraph, detailedInteractionsGraph: nil))
}
} else { } else {
return nil return .single(nil)
} }
} }
|> retryRequest |> retryRequest
}*/ }
} }
private final class MessageStatsContextImpl { private final class MessageStatsContextImpl {

View File

@ -345,15 +345,32 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
|> mapToSignal { result, additionalResult -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> in |> mapToSignal { result, additionalResult -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> in
return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
var additional: SearchMessagesPeerState? = mergedState(transaction: transaction, state: state?.additional, result: additionalResult) var additional: SearchMessagesPeerState? = mergedState(transaction: transaction, state: state?.additional, result: additionalResult)
if state?.additional == nil, case let .general(tags, _, _) = location {
let secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: tags) if state?.additional == nil {
var readStates: [PeerId: CombinedPeerReadState] = [:] switch location {
for message in secretMessages { case let .general(tags, minDate, maxDate), let .group(_, tags, minDate, maxDate):
if let readState = transaction.getCombinedPeerReadState(message.id.peerId) { let secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: tags)
readStates[message.id.peerId] = readState var filteredMessages: [Message] = []
} var readStates: [PeerId: CombinedPeerReadState] = [:]
for message in secretMessages {
var match = true
if let minDate = minDate, message.timestamp < minDate {
match = false
}
if let maxDate = maxDate, message.timestamp > maxDate {
match = false
}
if match {
filteredMessages.append(message)
if let readState = transaction.getCombinedPeerReadState(message.id.peerId) {
readStates[message.id.peerId] = readState
}
}
}
additional = SearchMessagesPeerState(messages: filteredMessages, readStates: readStates, totalCount: Int32(filteredMessages.count), completed: true, nextRate: nil)
default:
break
} }
additional = SearchMessagesPeerState(messages: secretMessages, readStates: readStates, totalCount: Int32(secretMessages.count), completed: true, nextRate: nil)
} }
let updatedState = SearchMessagesState(main: mergedState(transaction: transaction, state: state?.main, result: result) ?? SearchMessagesPeerState(messages: [], readStates: [:], totalCount: 0, completed: true, nextRate: nil), additional: additional) let updatedState = SearchMessagesState(main: mergedState(transaction: transaction, state: state?.main, result: result) ?? SearchMessagesPeerState(messages: [], readStates: [:], totalCount: 0, completed: true, nextRate: nil), additional: additional)

View File

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization { public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt { public func currentLayer() -> UInt {
return 119 return 120
} }
public func parseMessage(_ data: Data!) -> Any! { public func parseMessage(_ data: Data!) -> Any! {

View File

@ -38,7 +38,7 @@
function getCurrentTime() { function getCurrentTime() {
downloadProgress = player.getVideoLoadedFraction(); downloadProgress = player.getVideoLoadedFraction();
position = player.getCurrentTime(); position = player.getCurrentTime();
storyboardSpec = player.getStoryboardFormat(); //storyboardSpec = player.getStoryboardFormat();
updateState(); updateState();
invoke("tick"); invoke("tick");
@ -67,6 +67,7 @@
function onReady(event) { function onReady(event) {
window.location.href = "embed://onReady?data=" + event.data; window.location.href = "embed://onReady?data=" + event.data;
iframe = document.getElementById("player"); iframe = document.getElementById("player");
iframe.referrerPolicy = "origin";
duration = player.getDuration(); duration = player.getDuration();
invoke("tick"); invoke("tick");
} }

View File

@ -16,56 +16,56 @@ function initialize() {
function tick() { function tick() {
var watermark = document.getElementsByClassName("ytp-watermark")[0]; var watermark = document.getElementsByClassName("ytp-watermark")[0];
if (watermark != null) { if (watermark != null) {
watermark.style.display = "none"; // watermark.style.display = "none";
} }
var button = document.getElementsByClassName("ytp-large-play-button")[0]; var button = document.getElementsByClassName("ytp-large-play-button")[0];
if (button != null) { if (button != null) {
button.style.display = "none"; // button.style.display = "none";
button.style.opacity = "0"; // button.style.opacity = "0";
} }
var progress = document.getElementsByClassName("ytp-spinner-container")[0]; var progress = document.getElementsByClassName("ytp-spinner-container")[0];
if (progress != null) { if (progress != null) {
progress.style.display = "none"; // progress.style.display = "none";
progress.style.opacity = "0"; // progress.style.opacity = "0";
} }
var pause = document.getElementsByClassName("ytp-pause-overlay")[0]; var pause = document.getElementsByClassName("ytp-pause-overlay")[0];
if (pause != null) { if (pause != null) {
pause.style.display = "none"; // pause.style.display = "none";
pause.style.opacity = "0"; // pause.style.opacity = "0";
} }
var chrome = document.getElementsByClassName("ytp-chrome-top")[0]; var chrome = document.getElementsByClassName("ytp-chrome-top")[0];
if (chrome != null) { if (chrome != null) {
chrome.style.display = "none"; // chrome.style.display = "none";
chrome.style.opacity = "0"; // chrome.style.opacity = "0";
} }
var paid = document.getElementsByClassName("ytp-paid-content-overlay")[0]; var paid = document.getElementsByClassName("ytp-paid-content-overlay")[0];
if (paid != null) { if (paid != null) {
paid.style.display = "none"; // paid.style.display = "none";
paid.style.opacity = "0"; // paid.style.opacity = "0";
} }
var gradient = document.getElementsByClassName("ytp-gradient-top")[0]; var gradient = document.getElementsByClassName("ytp-gradient-top")[0];
if (gradient != null) { if (gradient != null) {
gradient.style.display = "none"; // gradient.style.display = "none";
gradient.style.opacity = "0"; // gradient.style.opacity = "0";
} }
var end = document.getElementsByClassName("html5-endscreen")[0]; var end = document.getElementsByClassName("html5-endscreen")[0];
if (end != null) { if (end != null) {
end.style.display = "none"; // end.style.display = "none";
end.style.opacity = "0"; // end.style.opacity = "0";
} }
var elements = document.getElementsByClassName("ytp-ce-element"); var elements = document.getElementsByClassName("ytp-ce-element");
for (var i = 0; i < elements.length; i++) { for (var i = 0; i < elements.length; i++) {
var element = elements[i] var element = elements[i]
element.style.display = "none"; // element.style.display = "none";
element.style.opacity = "0"; // element.style.opacity = "0";
} }
var video = document.getElementsByTagName("video")[0]; var video = document.getElementsByTagName("video")[0];

View File

@ -2219,6 +2219,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break break
} }
} }
}, openMessageStats: { [weak self] id in
let _ = (context.account.postbox.transaction { transaction -> CachedPeerData? in
return transaction.getPeerCachedData(peerId: id.peerId)
} |> deliverOnMainQueue).start(next: { [weak self] cachedPeerData in
guard let strongSelf = self, let cachedPeerData = cachedPeerData else {
return
}
strongSelf.push(messageStatsController(context: context, messageId: id, cachedPeerData: cachedPeerData))
})
}, requestMessageUpdate: { [weak self] id in }, requestMessageUpdate: { [weak self] id in
if let strongSelf = self { if let strongSelf = self {
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id) strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)

View File

@ -114,6 +114,7 @@ public final class ChatControllerInteraction {
let openPeerContextMenu: (Peer, ASDisplayNode, CGRect, ContextGesture?) -> Void let openPeerContextMenu: (Peer, ASDisplayNode, CGRect, ContextGesture?) -> Void
let openMessageReplies: (MessageId, Bool, Bool) -> Void let openMessageReplies: (MessageId, Bool, Bool) -> Void
let openReplyThreadOriginalMessage: (Message) -> Void let openReplyThreadOriginalMessage: (Message) -> Void
let openMessageStats: (MessageId) -> Void
let requestMessageUpdate: (MessageId) -> Void let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void let cancelInteractiveKeyboardGestures: () -> Void
@ -199,6 +200,7 @@ public final class ChatControllerInteraction {
openPeerContextMenu: @escaping (Peer, ASDisplayNode, CGRect, ContextGesture?) -> Void, openPeerContextMenu: @escaping (Peer, ASDisplayNode, CGRect, ContextGesture?) -> Void,
openMessageReplies: @escaping (MessageId, Bool, Bool) -> Void, openMessageReplies: @escaping (MessageId, Bool, Bool) -> Void,
openReplyThreadOriginalMessage: @escaping (Message) -> Void, openReplyThreadOriginalMessage: @escaping (Message) -> Void,
openMessageStats: @escaping (MessageId) -> Void,
requestMessageUpdate: @escaping (MessageId) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void,
cancelInteractiveKeyboardGestures: @escaping () -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void,
automaticMediaDownloadSettings: MediaAutoDownloadSettings, automaticMediaDownloadSettings: MediaAutoDownloadSettings,
@ -271,6 +273,7 @@ public final class ChatControllerInteraction {
self.openPeerContextMenu = openPeerContextMenu self.openPeerContextMenu = openPeerContextMenu
self.openMessageReplies = openMessageReplies self.openMessageReplies = openMessageReplies
self.openReplyThreadOriginalMessage = openReplyThreadOriginalMessage self.openReplyThreadOriginalMessage = openReplyThreadOriginalMessage
self.openMessageStats = openMessageStats
self.requestMessageUpdate = requestMessageUpdate self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
@ -321,6 +324,7 @@ public final class ChatControllerInteraction {
}, openPeerContextMenu: { _, _, _, _ in }, openPeerContextMenu: { _, _, _, _ in
}, openMessageReplies: { _, _, _ in }, openMessageReplies: { _, _, _ in
}, openReplyThreadOriginalMessage: { _ in }, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -605,7 +605,7 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
}) })
}))) })))
} }
if data.canEdit { if data.canEdit {
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_MessageDialogEdit, icon: { theme in actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_MessageDialogEdit, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor)
@ -808,9 +808,26 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
} }
var clearCacheAsDelete = false var clearCacheAsDelete = false
if let _ = message.peers[message.id.peerId] as? TelegramChannel { if message.id.peerId.namespace == Namespaces.Peer.CloudChannel {
var views: Int = 0
for attribute in message.attributes {
if let attribute = attribute as? ViewCountMessageAttribute {
views = attribute.count
}
}
if views >= 100 {
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextViewStats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in
c.dismiss(completion: {
controllerInteraction.openMessageStats(messages[0].id)
})
})))
}
clearCacheAsDelete = true clearCacheAsDelete = true
} }
if !isReplyThreadHead, (!data.messageActions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty || clearCacheAsDelete) && !isAction { if !isReplyThreadHead, (!data.messageActions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty || clearCacheAsDelete) && !isAction {
let title: String let title: String
var isSending = false var isSending = false

View File

@ -453,6 +453,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, openPeerContextMenu: { _, _, _, _ in }, openPeerContextMenu: { _, _, _, _ in
}, openMessageReplies: { _, _, _ in }, openMessageReplies: { _, _, _ in
}, openReplyThreadOriginalMessage: { _ in }, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,

View File

@ -146,6 +146,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
}, openPeerContextMenu: { _, _, _, _ in }, openPeerContextMenu: { _, _, _, _ in
}, openMessageReplies: { _, _, _ in }, openMessageReplies: { _, _, _ in
}, openReplyThreadOriginalMessage: { _ in }, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -136,6 +136,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, openPeerContextMenu: { _, _, _, _ in }, openPeerContextMenu: { _, _, _, _ in
}, openMessageReplies: { _, _, _ in }, openMessageReplies: { _, _, _ in
}, openReplyThreadOriginalMessage: { _ in }, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false)) }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))

View File

@ -1961,6 +1961,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}, openPeerContextMenu: { _, _, _, _ in }, openPeerContextMenu: { _, _, _, _ in
}, openMessageReplies: { _, _, _ in }, openMessageReplies: { _, _, _ in
}, openReplyThreadOriginalMessage: { _ in }, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -1200,6 +1200,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, openPeerContextMenu: { _, _, _, _ in }, openPeerContextMenu: { _, _, _, _ in
}, openMessageReplies: { _, _, _ in }, openMessageReplies: { _, _, _ in
}, openReplyThreadOriginalMessage: { _ in }, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -75,18 +75,24 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
let impl: WebEmbedImplementation let impl: WebEmbedImplementation
private let openUrl: (URL) -> Void
private let intrinsicDimensions: CGSize private let intrinsicDimensions: CGSize
private let webView: WKWebView private let webView: WKWebView
private let semaphore = DispatchSemaphore(value: 0) private let semaphore = DispatchSemaphore(value: 0)
private let queue = Queue() private let queue = Queue()
init(impl: WebEmbedImplementation, intrinsicDimensions: CGSize) { init(impl: WebEmbedImplementation, intrinsicDimensions: CGSize, openUrl: @escaping (URL) -> Void) {
self.impl = impl self.impl = impl
self.intrinsicDimensions = intrinsicDimensions self.intrinsicDimensions = intrinsicDimensions
self.openUrl = openUrl
let userContentController = WKUserContentController() let userContentController = WKUserContentController()
userContentController.addUserScript(WKUserScript(source: "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta)", injectionTime: .atDocumentEnd, forMainFrameOnly: true)) if impl is YoutubeEmbedImplementation {
} else {
userContentController.addUserScript(WKUserScript(source: "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta)", injectionTime: .atDocumentEnd, forMainFrameOnly: true))
}
let configuration = WKWebViewConfiguration() let configuration = WKWebViewConfiguration()
configuration.allowsInlineMediaPlayback = true configuration.allowsInlineMediaPlayback = true
@ -112,6 +118,8 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
self.webView.navigationDelegate = self self.webView.navigationDelegate = self
self.webView.scrollView.isScrollEnabled = false self.webView.scrollView.isScrollEnabled = false
self.webView.allowsLinkPreview = false
self.webView.allowsBackForwardNavigationGestures = false
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
self.webView.accessibilityIgnoresInvertColors = true self.webView.accessibilityIgnoresInvertColors = true
self.webView.scrollView.contentInsetAdjustmentBehavior = .never self.webView.scrollView.contentInsetAdjustmentBehavior = .never
@ -159,19 +167,19 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
} }
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("w")
} }
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.impl.pageReady() self.impl.pageReady()
} }
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
if let error = error as? WKError, error.code.rawValue == 204 { if let error = error as? WKError, error.code.rawValue == 204 {
return return
} }
} }
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url, url.scheme == "embed" { if let url = navigationAction.request.url, url.scheme == "embed" {
self.impl.callback(url: url) self.impl.callback(url: url)
@ -179,6 +187,9 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
} else if let _ = navigationAction.targetFrame { } else if let _ = navigationAction.targetFrame {
decisionHandler(.allow) decisionHandler(.allow)
} else { } else {
if let url = navigationAction.request.url, url.absoluteString.contains("youtube") {
self.openUrl(url)
}
decisionHandler(.cancel) decisionHandler(.cancel)
} }
} }

View File

@ -19,8 +19,9 @@ public final class WebEmbedVideoContent: UniversalVideoContent {
public let dimensions: CGSize public let dimensions: CGSize
public let duration: Int32 public let duration: Int32
let forcedTimestamp: Int? let forcedTimestamp: Int?
let openUrl: (URL) -> Void
public init?(webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil) { public init?(webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil, openUrl: @escaping (URL) -> Void) {
guard let embedUrl = webpageContent.embedUrl else { guard let embedUrl = webpageContent.embedUrl else {
return nil return nil
} }
@ -30,10 +31,11 @@ public final class WebEmbedVideoContent: UniversalVideoContent {
self.dimensions = webpageContent.embedSize?.cgSize ?? CGSize(width: 128.0, height: 128.0) self.dimensions = webpageContent.embedSize?.cgSize ?? CGSize(width: 128.0, height: 128.0)
self.duration = Int32(webpageContent.duration ?? (0 as Int)) self.duration = Int32(webpageContent.duration ?? (0 as Int))
self.forcedTimestamp = forcedTimestamp self.forcedTimestamp = forcedTimestamp
self.openUrl = openUrl
} }
public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode { public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode {
return WebEmbedVideoContentNode(postbox: postbox, audioSessionManager: audioSession, webPage: self.webPage, webpageContent: self.webpageContent, forcedTimestamp: self.forcedTimestamp) return WebEmbedVideoContentNode(postbox: postbox, audioSessionManager: audioSession, webPage: self.webPage, webpageContent: self.webpageContent, forcedTimestamp: self.forcedTimestamp, openUrl: self.openUrl)
} }
} }
@ -70,7 +72,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
private var readyDisposable = MetaDisposable() private var readyDisposable = MetaDisposable()
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil) { init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil, openUrl: @escaping (URL) -> Void) {
self.webpageContent = webpageContent self.webpageContent = webpageContent
if let embedSize = webpageContent.embedSize { if let embedSize = webpageContent.embedSize {
@ -83,7 +85,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
let embedType = webEmbedType(content: webpageContent, forcedTimestamp: forcedTimestamp) let embedType = webEmbedType(content: webpageContent, forcedTimestamp: forcedTimestamp)
let embedImpl = webEmbedImplementation(for: embedType) let embedImpl = webEmbedImplementation(for: embedType)
self.playerNode = WebEmbedPlayerNode(impl: embedImpl, intrinsicDimensions: self.intrinsicDimensions) self.playerNode = WebEmbedPlayerNode(impl: embedImpl, intrinsicDimensions: self.intrinsicDimensions, openUrl: openUrl)
super.init() super.init()

View File

@ -174,8 +174,8 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
updateStatus(self.status) updateStatus(self.status)
let html = String(format: htmlTemplate, paramsJson) let html = String(format: htmlTemplate, paramsJson)
webView.loadHTMLString(html, baseURL: URL(string: "https://youtube.com/")) webView.loadHTMLString(html, baseURL: URL(string: "https://messenger.telegram.org"))
webView.isUserInteractionEnabled = false // webView.isUserInteractionEnabled = false
userContentController.addUserScript(WKUserScript(source: userScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)) userContentController.addUserScript(WKUserScript(source: userScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false))
} }