mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Various fixes
This commit is contained in:
parent
784b43934a
commit
265b502f76
11 changed files with 109 additions and 53 deletions
|
|
@ -16155,3 +16155,6 @@ Error: %8$@";
|
|||
"TextProcessing.StyleTooltip" = "Select Style";
|
||||
|
||||
"Bot.AlertCanNotCreateBots" = "%@ can't manage other bots.";
|
||||
|
||||
"MediaPlayer.PlaylistTitle" = "%@'s Playlist";
|
||||
"MediaPlayer.PlaylistYourTitle" = "Your Playlist";
|
||||
|
|
|
|||
|
|
@ -1235,7 +1235,7 @@ public enum ChatHistoryListDisplayHeaders {
|
|||
|
||||
public enum ChatHistoryListMode: Equatable {
|
||||
case bubbles
|
||||
case list(reversed: Bool, reverseGroups: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool)
|
||||
case list(reversed: Bool, reverseGroups: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool, isMusicPlaylist: Bool)
|
||||
}
|
||||
|
||||
public protocol ChatControllerInteractionProtocol: AnyObject {
|
||||
|
|
|
|||
|
|
@ -209,7 +209,8 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||
reverseGroups: false,
|
||||
displayHeaders: .none,
|
||||
hintLinks: true,
|
||||
isGlobalSearch: false
|
||||
isGlobalSearch: false,
|
||||
isMusicPlaylist: false
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2717,7 +2717,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
let isForceLivePhoto = editingContext.isForceLivePhotoEnabled()
|
||||
rightControlItems.insert(GlassControlGroupComponent.Item(
|
||||
id: AnyHashable(isForceLivePhoto ? "livePhoto_on" : "livePhoto_off"),
|
||||
content: .icon(isForceLivePhoto ? "Media Editor/LiveOn" : "Media Editor/LiveOff"),
|
||||
content: .icon(isForceLivePhoto ? "Media Editor/LiveLargeOn" : "Media Editor/LiveLargeOff"),
|
||||
action: { [weak self, weak editingContext] in
|
||||
guard let self, let editingContext else {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ private final class BoostsTabsItemNode: ListViewItemNode {
|
|||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||
}
|
||||
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: true) : nil
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ final class MonetizationBalanceItemNode: ListViewItemNode, ItemListItemNode {
|
|||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||
}
|
||||
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: true) : nil
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
|||
self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds }
|
||||
self.selectedMessagesPromise.set(.single(self.selectedMessages))
|
||||
|
||||
self.listNode = context.sharedContext.makeChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tag: .tag(tagMask), source: .default, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(reversed: false, reverseGroups: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false))
|
||||
self.listNode = context.sharedContext.makeChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tag: .tag(tagMask), source: .default, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(reversed: false, reverseGroups: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false, isMusicPlaylist: false))
|
||||
self.listNode.clipsToBounds = true
|
||||
self.listNode.defaultToSynchronousTransactionWhileScrolling = true
|
||||
self.listNode.scroller.bounces = false
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ func chatHistoryEntriesForView(
|
|||
customThreadOutgoingReadState: MessageId?,
|
||||
cachedData: CachedPeerData?,
|
||||
adMessage: Message?,
|
||||
dynamicAdMessages: [Message]
|
||||
dynamicAdMessages: [Message],
|
||||
isMusicPlaylist: Bool
|
||||
) -> ([ChatHistoryEntry], ChatHistoryEntriesForViewState) {
|
||||
var currentState = currentState
|
||||
|
||||
|
|
@ -453,7 +454,7 @@ func chatHistoryEntriesForView(
|
|||
}
|
||||
|
||||
var addedThreadHead = false
|
||||
if case let .replyThread(replyThreadMessage) = location, !replyThreadMessage.isForumPost, view.earlierId == nil, !view.holeEarlier, !view.isLoading {
|
||||
if case let .replyThread(replyThreadMessage) = location, !replyThreadMessage.isForumPost, view.earlierId == nil, !view.holeEarlier, !view.isLoading, !isMusicPlaylist {
|
||||
loop: for entry in view.additionalData {
|
||||
switch entry {
|
||||
case let .message(id, messages) where id == replyThreadMessage.effectiveTopId:
|
||||
|
|
@ -833,6 +834,10 @@ func chatHistoryEntriesForView(
|
|||
}
|
||||
}
|
||||
|
||||
if isMusicPlaylist && entries.count == 1 {
|
||||
return ([], currentState)
|
||||
}
|
||||
|
||||
if reverse {
|
||||
return (entries.reversed(), currentState)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
|||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders || message.timestamp < 10)
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch, _):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
@ -284,7 +284,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
|||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders || message.timestamp < 10)
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch, _):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
@ -676,6 +676,9 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
private var messageReadMetricsTrackerPendingMetrics: [TelegramMessageReadMetric] = []
|
||||
private var messageReadMetricsTrackerPendingMetricTimer: Foundation.Timer?
|
||||
|
||||
public private(set) var hasAnyMessages: Bool = false
|
||||
public var hasAnyMessagesUpdated: ((Bool) -> Void)?
|
||||
|
||||
public private(set) var hasAtLeast3Messages: Bool = false
|
||||
public var hasAtLeast3MessagesUpdated: ((Bool) -> Void)?
|
||||
|
||||
|
|
@ -2051,9 +2054,11 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
|
||||
var reverse = false
|
||||
var reverseGroups = false
|
||||
if case let .list(reverseValue, reverseGroupsValue, _, _, _) = mode {
|
||||
var isMusicPlaylist = false
|
||||
if case let .list(reverseValue, reverseGroupsValue, _, _, _, isMusicPlaylistValue) = mode {
|
||||
reverse = reverseValue
|
||||
reverseGroups = reverseGroupsValue
|
||||
isMusicPlaylist = isMusicPlaylistValue
|
||||
}
|
||||
|
||||
var isPremium = false
|
||||
|
|
@ -2108,9 +2113,8 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
if case let .replyThread(message) = chatLocation, message.peerId == context.account.peerId, !rotated {
|
||||
includeEmbeddedSavedChatInfo = true
|
||||
}
|
||||
|
||||
|
||||
let previousChatHistoryEntriesForViewState = chatHistoryEntriesForViewState.with({ $0 })
|
||||
|
||||
let (filteredEntries, updatedChatHistoryEntriesForViewState) = chatHistoryEntriesForView(
|
||||
currentState: previousChatHistoryEntriesForViewState,
|
||||
context: context,
|
||||
|
|
@ -2136,7 +2140,8 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
customThreadOutgoingReadState: customThreadOutgoingReadState,
|
||||
cachedData: data.cachedData,
|
||||
adMessage: allAdMessages.fixed,
|
||||
dynamicAdMessages: allAdMessages.opportunistic
|
||||
dynamicAdMessages: allAdMessages.opportunistic,
|
||||
isMusicPlaylist: isMusicPlaylist
|
||||
)
|
||||
let lastHeaderId = filteredEntries.last.flatMap { listMessageDateHeaderId(timestamp: $0.index.timestamp) } ?? 0
|
||||
let processedView = ChatHistoryView(originalView: view, filteredEntries: filteredEntries, associatedData: associatedData, lastHeaderId: lastHeaderId, id: id, locationInput: update.2, ignoreMessagesInTimestampRange: update.3, ignoreMessageIds: update.4)
|
||||
|
|
@ -4095,15 +4100,20 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
}
|
||||
}
|
||||
|
||||
var hasAnyMessages = false
|
||||
var hasAtLeast3Messages = false
|
||||
var hasPlentyOfMessages = false
|
||||
var hasLotsOfMessages = false
|
||||
if let historyView = strongSelf.historyView {
|
||||
if historyView.originalView.holeEarlier || historyView.originalView.holeLater {
|
||||
hasAnyMessages = true
|
||||
hasAtLeast3Messages = true
|
||||
hasPlentyOfMessages = true
|
||||
hasLotsOfMessages = true
|
||||
} else if !historyView.originalView.holeEarlier && !historyView.originalView.holeLater {
|
||||
if historyView.filteredEntries.count >= 1 {
|
||||
hasAnyMessages = true
|
||||
}
|
||||
if historyView.filteredEntries.count >= 3 {
|
||||
hasAtLeast3Messages = true
|
||||
}
|
||||
|
|
@ -4116,6 +4126,11 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
}
|
||||
}
|
||||
|
||||
if strongSelf.hasAnyMessages != hasAnyMessages {
|
||||
strongSelf.hasAnyMessages = hasAnyMessages
|
||||
strongSelf.hasAnyMessagesUpdated?(hasAnyMessages)
|
||||
}
|
||||
|
||||
if strongSelf.hasAtLeast3Messages != hasAtLeast3Messages {
|
||||
strongSelf.hasAtLeast3Messages = hasAtLeast3Messages
|
||||
strongSelf.hasAtLeast3MessagesUpdated?(hasAtLeast3Messages)
|
||||
|
|
@ -4681,7 +4696,7 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
switch self.mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders)
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch, _):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
@ -4759,7 +4774,7 @@ public final class ChatHistoryListNodeImpl: ListViewImpl, ChatHistoryNode, ChatH
|
|||
switch self.mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders)
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch, _):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
|
||||
private var floatingHeaderOffset: CGFloat?
|
||||
private var historyContentOffset: CGFloat = 0.0
|
||||
private var hasAnyHistoryMessages: Bool?
|
||||
private var historyNode: ChatHistoryListNodeImpl
|
||||
private var replacementHistoryNode: ChatHistoryListNodeImpl?
|
||||
private var replacementHistoryNodeFloatingOffset: CGFloat?
|
||||
|
|
@ -305,8 +306,12 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
tagMask = .file
|
||||
}
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
var isMusicPlaylist = true
|
||||
if let playlistLocation = self.playlistLocation as? PeerMessagesPlaylistLocation, case .savedMusic = playlistLocation {
|
||||
isMusicPlaylist = false
|
||||
}
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
self.historyNode = ChatHistoryListNodeImpl(
|
||||
context: context,
|
||||
updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData),
|
||||
|
|
@ -319,7 +324,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
subject: .message(id: .id(initialMessageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false),
|
||||
controllerInteraction: self.controllerInteraction,
|
||||
selectedMessages: .single(nil),
|
||||
mode: .list(reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch),
|
||||
mode: .list(reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch, isMusicPlaylist: isMusicPlaylist),
|
||||
isChatPreview: false,
|
||||
messageTransitionNode: { return nil
|
||||
}
|
||||
|
|
@ -476,7 +481,9 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
|
||||
let copyProtectionEnabled: Signal<Bool, NoError>
|
||||
if case let .peer(peerId) = self.chatLocation {
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
if let playlistLocation = self.playlistLocation as? PeerMessagesPlaylistLocation, case .savedMusic = playlistLocation {
|
||||
copyProtectionEnabled = .single(false)
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
copyProtectionEnabled = context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.CopyProtectionEnabled(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.MyCopyProtectionEnabled(id: peerId)
|
||||
|
|
@ -622,10 +629,10 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
self.presentationData = presentationData
|
||||
|
||||
self.historyBackgroundContentNode.backgroundColor = self.presentationData.theme.list.itemModalBlocksBackgroundColor
|
||||
self.historyFrameLeftOverlayNode.backgroundColor = self.presentationData.theme.list.modalBlocksBackgroundColor
|
||||
self.historyFrameRightOverlayNode.backgroundColor = self.presentationData.theme.list.modalBlocksBackgroundColor
|
||||
self.historyFrameTopOverlayNode.backgroundColor = self.presentationData.theme.list.modalBlocksBackgroundColor
|
||||
self.historyBackgroundContentNode.backgroundColor = self.hasAnyHistoryMessages == true ? self.presentationData.theme.list.itemModalBlocksBackgroundColor : self.presentationData.theme.list.modalPlainBackgroundColor
|
||||
self.historyFrameLeftOverlayNode.backgroundColor = self.hasAnyHistoryMessages == true ? self.presentationData.theme.list.modalBlocksBackgroundColor : self.presentationData.theme.list.modalPlainBackgroundColor
|
||||
self.historyFrameRightOverlayNode.backgroundColor = self.hasAnyHistoryMessages == true ? self.presentationData.theme.list.modalBlocksBackgroundColor : self.presentationData.theme.list.modalPlainBackgroundColor
|
||||
self.historyFrameTopOverlayNode.backgroundColor = self.hasAnyHistoryMessages == true ? self.presentationData.theme.list.modalBlocksBackgroundColor : self.presentationData.theme.list.modalPlainBackgroundColor
|
||||
self.historyFrameTopMaskNode.image = PresentationResourcesItemList.cornersImage(self.presentationData.theme.withModalBlocksBackground(), top: true, bottom: false, glass: true)
|
||||
|
||||
self.collapseNode.setImage(generateCollapseIcon(theme: self.presentationData.theme), for: [])
|
||||
|
|
@ -894,14 +901,6 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
)
|
||||
)
|
||||
}
|
||||
// rightControlItems.append(
|
||||
// GlassControlGroupComponent.Item(
|
||||
// id: AnyHashable("search"),
|
||||
// content: .icon("Navigation/Search"),
|
||||
// action: {
|
||||
// }
|
||||
// )
|
||||
// )
|
||||
|
||||
let headerInset: CGFloat = 16.0
|
||||
let headerButtonsSize = self.headerButtons.update(
|
||||
|
|
@ -932,13 +931,12 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
headerButtonsView.frame = CGRect(origin: CGPoint(x: headerInset, y: headerInset), size: headerButtonsSize)
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let titleString: String
|
||||
if let peer = self.peer {
|
||||
if peer.id == self.context.account.peerId {
|
||||
titleString = "Your Playlist"
|
||||
titleString = self.presentationData.strings.MediaPlayer_PlaylistYourTitle
|
||||
} else {
|
||||
titleString = "\(peer.compactDisplayTitle)'s Playlist"
|
||||
titleString = self.presentationData.strings.MediaPlayer_PlaylistTitle(peer.compactDisplayTitle).string
|
||||
}
|
||||
} else {
|
||||
titleString = ""
|
||||
|
|
@ -965,7 +963,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
self.updateHistoryContentOffset(self.historyNode.visibleContentOffset(), transition: transition)
|
||||
|
||||
var layout = layout
|
||||
layout.intrinsicInsets.bottom = controlsHeight
|
||||
layout.intrinsicInsets.bottom = controlsHeight + 8.0
|
||||
self.getParentController()?.presentationContext.containerLayoutUpdated(layout, transition: transition)
|
||||
}
|
||||
|
||||
|
|
@ -990,6 +988,9 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
if !self.bounds.contains(point) {
|
||||
return nil
|
||||
}
|
||||
if point.y < self.historyFrameNode.frame.minY {
|
||||
return self.dimNode.view
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
@ -1069,14 +1070,20 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
return
|
||||
}
|
||||
self.floatingHeaderOffset = offset
|
||||
let previousHasAnyHistoryMessages = self.hasAnyHistoryMessages
|
||||
self.hasAnyHistoryMessages = self.historyNode.hasAnyMessages
|
||||
self.controlsNode.hasPlainBackground = !self.historyNode.hasAnyMessages
|
||||
|
||||
let sideInset: CGFloat = 16.0
|
||||
let headerHeight = self.effectiveHeaderHeight
|
||||
let headerHeight: CGFloat = self.effectiveHeaderHeight
|
||||
|
||||
let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top)
|
||||
|
||||
let rawControlsOffset = offset + layoutTopInset
|
||||
let backgroundOffset = max(layoutTopInset, rawControlsOffset)
|
||||
var backgroundOffset = max(layoutTopInset, rawControlsOffset)
|
||||
if !self.historyNode.hasAnyMessages {
|
||||
backgroundOffset += 25.0
|
||||
}
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: backgroundOffset + headerHeight), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
|
||||
|
|
@ -1093,6 +1100,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
if let image = self.historyFrameTopMaskNode.image {
|
||||
self.historyFrameTopMaskNode.frame = CGRect(origin: CGPoint(x: sideInset, y: topOverlayFrame.maxY), size: CGSize(width: layout.size.width - sideInset * 2.0, height: image.size.height))
|
||||
}
|
||||
self.historyFrameTopMaskNode.isHidden = self.controlsNode.hasPlainBackground
|
||||
|
||||
let previousBackgroundFrame = self.historyBackgroundNode.frame
|
||||
if !backgroundFrame.equalTo(previousBackgroundFrame) {
|
||||
|
|
@ -1103,6 +1111,10 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
|
||||
transition.animateOffsetAdditive(node: self.historyBackgroundNode, offset: positionDelta.y)
|
||||
}
|
||||
|
||||
if self.hasAnyHistoryMessages != previousHasAnyHistoryMessages {
|
||||
self.updatePresentationData(self.presentationData)
|
||||
}
|
||||
}
|
||||
|
||||
private func transitionToUpdatedHistoryNode(atMessage messageId: MessageId) {
|
||||
|
|
@ -1116,6 +1128,11 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
tagMask = .file
|
||||
}
|
||||
|
||||
var isMusicPlaylist = true
|
||||
if let playlistLocation = self.playlistLocation as? PeerMessagesPlaylistLocation, case .savedMusic = playlistLocation {
|
||||
isMusicPlaylist = false
|
||||
}
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
let historyNode = ChatHistoryListNodeImpl(
|
||||
context: self.context,
|
||||
|
|
@ -1129,10 +1146,11 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false),
|
||||
controllerInteraction: self.controllerInteraction,
|
||||
selectedMessages: .single(nil),
|
||||
mode: .list(reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch),
|
||||
mode: .list(reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch, isMusicPlaylist: isMusicPlaylist),
|
||||
isChatPreview: false,
|
||||
messageTransitionNode: { return nil
|
||||
})
|
||||
}
|
||||
)
|
||||
historyNode.clipsToBounds = true
|
||||
historyNode.preloadPages = true
|
||||
historyNode.stackFromBottom = true
|
||||
|
|
|
|||
|
|
@ -30,12 +30,20 @@ private func normalizeValue(_ value: CGFloat) -> CGFloat {
|
|||
}
|
||||
|
||||
private func generateBackground(theme: PresentationTheme) -> UIImage? {
|
||||
return generateImage(CGSize(width: 20.0, height: 10.0 + 8.0), rotatedContext: { size, context in
|
||||
return generateImage(CGSize(width: 20.0, height: 18.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setShadow(offset: CGSize(width: 0.0, height: -4.0), blur: 30.0, color: UIColor(white: 0.0, alpha: 0.2).cgColor)
|
||||
context.setFillColor(theme.list.modalPlainBackgroundColor.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(x: 0.0, y: 8.0), size: CGSize(width: 20.0, height: 20.0)))
|
||||
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 10 + 8)
|
||||
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 18)
|
||||
}
|
||||
|
||||
private func generatePlainBackground(theme: PresentationTheme) -> UIImage? {
|
||||
return generateImage(CGSize(width: 20.0, height: 18.0 + 25.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(theme.list.modalPlainBackgroundColor.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(x: 0.0, y: 8.0 + 25.0), size: CGSize(width: 20.0, height: 20.0)))
|
||||
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 18 + 25)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -176,6 +184,12 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
private let rateButton: AudioRateButton
|
||||
|
||||
let separatorNode: ASDisplayNode
|
||||
|
||||
var hasPlainBackground = false {
|
||||
didSet {
|
||||
self.backgroundNode.image = self.hasPlainBackground ? generatePlainBackground(theme: self.presentationData.theme) : generateBackground(theme: self.presentationData.theme)
|
||||
}
|
||||
}
|
||||
|
||||
var isExpanded = false
|
||||
var updateIsExpanded: (() -> Void)?
|
||||
|
|
@ -249,7 +263,7 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
self.shareNode = HighlightableButtonNode()
|
||||
self.shareNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Share"), color: presentationData.theme.list.itemPrimaryTextColor), for: [])
|
||||
|
||||
self.scrubberNode = MediaPlayerScrubbingNode(content: .standard(lineHeight: 7.0, lineCap: .round, scrubberHandle: .none, backgroundColor: presentationData.theme.list.controlSecondaryColor, foregroundColor: presentationData.theme.list.itemPrimaryTextColor, bufferingColor: presentationData.theme.list.itemPrimaryTextColor.withAlphaComponent(0.4), chapters: []))
|
||||
self.scrubberNode = MediaPlayerScrubbingNode(content: .standard(lineHeight: 7.0, lineCap: .round, scrubberHandle: .none, backgroundColor: presentationData.theme.list.controlSecondaryColor.withMultipliedAlpha(0.5), foregroundColor: presentationData.theme.list.itemPrimaryTextColor, bufferingColor: presentationData.theme.list.itemPrimaryTextColor.withAlphaComponent(0.4), chapters: []))
|
||||
self.leftDurationLabel = MediaPlayerTimeTextNode(textColor: presentationData.theme.list.itemSecondaryTextColor, textFont: Font.medium(12.0))
|
||||
self.leftDurationLabel.displaysAsynchronously = false
|
||||
self.leftDurationLabel.keepPreviousValueOnEmptyState = true
|
||||
|
|
@ -684,9 +698,9 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
self.backwardButton.circleColor = presentationData.theme.list.controlSecondaryColor.withAlphaComponent(0.35)
|
||||
self.forwardButton.circleColor = presentationData.theme.list.controlSecondaryColor.withAlphaComponent(0.35)
|
||||
|
||||
self.backgroundNode.image = generateBackground(theme: presentationData.theme)
|
||||
self.backgroundNode.image = self.hasPlainBackground ? generatePlainBackground(theme: presentationData.theme) : generateBackground(theme: presentationData.theme)
|
||||
self.shareNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Share"), color: presentationData.theme.list.itemPrimaryTextColor), for: [])
|
||||
self.scrubberNode.updateColors(backgroundColor: presentationData.theme.list.controlSecondaryColor, foregroundColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
self.scrubberNode.updateColors(backgroundColor: presentationData.theme.list.controlSecondaryColor.withMultipliedAlpha(0.5), foregroundColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
self.leftDurationLabel.textColor = presentationData.theme.list.itemSecondaryTextColor
|
||||
self.rightDurationLabel.textColor = presentationData.theme.list.itemSecondaryTextColor
|
||||
self.backwardButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Previous"), color: presentationData.theme.list.itemPrimaryTextColor)
|
||||
|
|
@ -709,18 +723,16 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
private func updateLabels(transition: ContainedViewLayoutTransition) {
|
||||
guard let (width, leftInset, rightInset, bottomInset, maxHeight, _) = self.validLayout else {
|
||||
guard let (width, leftInset, rightInset, _, _, _) = self.validLayout else {
|
||||
return
|
||||
}
|
||||
|
||||
let panelHeight = OverlayAudioPlayerControlsNode.heightForLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, maxHeight: maxHeight, isExpanded: self.isExpanded, savedMusic: nil)
|
||||
|
||||
let sideInset: CGFloat = 20.0
|
||||
|
||||
let infoLabelsLeftInset: CGFloat = 53.0
|
||||
let infoLabelsRightInset: CGFloat = 32.0
|
||||
|
||||
let infoVerticalOrigin: CGFloat = panelHeight - OverlayAudioPlayerControlsNode.basePanelHeight + 21.0
|
||||
let infoVerticalOrigin: CGFloat = 21.0
|
||||
|
||||
let (titleString, descriptionString, hasArtist, caption) = stringsForDisplayData(self.displayData, presentationData: self.presentationData)
|
||||
|
||||
|
|
@ -728,7 +740,7 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
self.previousCaption = caption
|
||||
let chapters = caption.flatMap { parseMediaPlayerChapters($0) } ?? []
|
||||
self.chaptersPromise.set(chapters)
|
||||
self.scrubberNode.updateContent(.standard(lineHeight: 7.0, lineCap: .round, scrubberHandle: .none, backgroundColor: self.presentationData.theme.list.controlSecondaryColor, foregroundColor: self.presentationData.theme.list.itemPrimaryTextColor, bufferingColor: self.presentationData.theme.list.itemPrimaryTextColor.withAlphaComponent(0.4), chapters: chapters))
|
||||
self.scrubberNode.updateContent(.standard(lineHeight: 7.0, lineCap: .round, scrubberHandle: .none, backgroundColor: self.presentationData.theme.list.controlSecondaryColor.withMultipliedAlpha(0.5), foregroundColor: self.presentationData.theme.list.itemPrimaryTextColor, bufferingColor: self.presentationData.theme.list.itemPrimaryTextColor.withAlphaComponent(0.4), chapters: chapters))
|
||||
}
|
||||
|
||||
self.artistButton.isUserInteractionEnabled = hasArtist
|
||||
|
|
@ -820,7 +832,7 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
self.rateButton.setContent(.image(optionsRateImage(rate: rate.stringValue.uppercased(), color: self.presentationData.theme.list.itemSecondaryTextColor)))
|
||||
}
|
||||
|
||||
static let basePanelHeight: CGFloat = 164.0
|
||||
static let basePanelHeight: CGFloat = 182.0
|
||||
|
||||
static func heightForLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, maxHeight: CGFloat, isExpanded: Bool, savedMusic: Bool?) -> CGFloat {
|
||||
var panelHeight: CGFloat = OverlayAudioPlayerControlsNode.basePanelHeight
|
||||
|
|
@ -830,9 +842,11 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
}
|
||||
var height = min(panelHeight, maxHeight)
|
||||
if let _ = savedMusic {
|
||||
height += 70.0
|
||||
height += 52.0
|
||||
let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: bottomInset, innerDiameter: 52.0, sideInset: 30.0)
|
||||
height += buttonInsets.bottom
|
||||
} else {
|
||||
height += 8.0
|
||||
}
|
||||
return height
|
||||
}
|
||||
|
|
@ -855,7 +869,7 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
let sideInset: CGFloat = 16.0
|
||||
let sideButtonsInset: CGFloat = sideInset + 60.0
|
||||
|
||||
let infoVerticalOrigin: CGFloat = panelHeight - OverlayAudioPlayerControlsNode.basePanelHeight + 21.0
|
||||
let infoVerticalOrigin: CGFloat = 21.0
|
||||
|
||||
self.updateLabels(transition: transition)
|
||||
|
||||
|
|
@ -986,7 +1000,7 @@ final class OverlayAudioPlayerControlsNode: ASDisplayNode {
|
|||
profileAudioButtonContent = AnyComponentWithIdentity(id: "removeFromProfile", component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: self.presentationData.strings.MediaPlayer_SavedMusic_RemoveFromProfileShort, font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)))
|
||||
))
|
||||
buttonBackgroundColor = self.presentationData.theme.list.controlSecondaryColor
|
||||
buttonBackgroundColor = self.presentationData.theme.list.controlSecondaryColor.withMultipliedAlpha(0.5)
|
||||
} else {
|
||||
profileAudioButtonContent = AnyComponentWithIdentity(id: "addToProfile", component: AnyComponent(
|
||||
HStack([
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue