Shared media improvements

This commit is contained in:
Ali 2021-10-28 19:02:11 +04:00
parent 87890295be
commit c821cc1ab3
9 changed files with 403 additions and 66 deletions

View File

@ -296,6 +296,14 @@
"Weekday.Today" = "Today";
"Weekday.Yesterday" = "Yesterday";
"Calendar.ShortMonday" = "M";
"Calendar.ShortTuesday" = "T";
"Calendar.ShortWednesday" = "W";
"Calendar.ShortThursday" = "T";
"Calendar.ShortFriday" = "F";
"Calendar.ShortSaturday" = "S";
"Calendar.ShortSunday" = "S";
"Time.TodayAt" = "today at %@";
"Time.YesterdayAt" = "yesterday at %@";
@ -6986,3 +6994,33 @@ Sorry for the inconvenience.";
"AuthSessions.View.IP" = "IP Address";
"AuthSessions.View.TerminateSession" = "Terminate Session";
"AuthSessions.View.Logout" = "Log Out";
"MessageCalendar.Title" = "Calendar";
"MessageCalendar.DaysSelectedTitle_1" = "1 day selected";
"MessageCalendar.DaysSelectedTitle_any" = "%@ days selected";
"MessageCalendar.DeleteConfirmation_1" = "Are you sure you want to delete all messages for the selected day?";
"MessageCalendar.DeleteConfirmation_1" = "Are you sure you want to delete all messages for the selected %@ days?";
"SharedMedia.PhotoCount_1" = "1 photo";
"SharedMedia.PhotoCount_any" = "%@ photos";
"SharedMedia.VideoCount_1" = "1 video";
"SharedMedia.VideoCount_any" = "%@ videos";
"SharedMedia.GifCount_1" = "1 gif";
"SharedMedia.GifCount_any" = "%@ gifs";
"SharedMedia.FileCount_1" = "1 file";
"SharedMedia.FileCount_any" = "%@ files";
"SharedMedia.MusicCount_1" = "1 music file";
"SharedMedia.MusicCount_any" = "%@ music files";
"SharedMedia.VoiceMessageCount_1" = "1 voice message";
"SharedMedia.VoiceMessageCount_any" = "%@ voice messages";
"SharedMedia.LinkCount_1" = "1 link";
"SharedMedia.LinkCount_any" = "%@ links";
"SharedMedia.FastScrollTooltip" = "You can hold and move this bar for faster scrolling";
"SharedMedia.CalendarTooltip" = "Tap on this icon for calendar view";
"SharedMedia.ZoomIn" = "Zoom In";
"SharedMedia.ZoomOut" = "Zoom Out";
"SharedMedia.ShowCalendar" = "Show Calendar";
"SharedMedia.ShowPhotos" = "Show Photos";
"SharedMedia.ShowVideos" = "Show Videos";

View File

@ -151,24 +151,21 @@ private func monthName(index: Int, strings: PresentationStrings) -> String {
}
private func dayName(index: Int, strings: PresentationStrings) -> String {
let _ = strings
//TODO:localize
switch index {
case 0:
return "M"
return strings.Calendar_ShortMonday
case 1:
return "T"
return strings.Calendar_ShortTuesday
case 2:
return "W"
return strings.Calendar_ShortWednesday
case 3:
return "T"
return strings.Calendar_ShortThursday
case 4:
return "F"
return strings.Calendar_ShortFriday
case 5:
return "S"
return strings.Calendar_ShortSaturday
case 6:
return "S"
return strings.Calendar_ShortSunday
default:
return ""
}
@ -1402,8 +1399,7 @@ public final class CalendarMessageScreen: ViewController {
}
if let _ = info.canClearForMyself ?? info.canClearForEveryone {
//TODO:localize
items.append(ActionSheetTextItem(title: "Are you sure you want to delete all messages for the \(selectedCount) selected days?"))
items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.MessageCalendar_DeleteConfirmation(Int32(selectedCount))))
if let canClearForEveryone = info.canClearForEveryone {
let text: String
@ -1627,8 +1623,7 @@ public final class CalendarMessageScreen: ViewController {
}
private func updateSelectionState() {
//TODO:localize
var title = "Calendar"
var title = self.presentationData.strings.MessageCalendar_Title
if let selectionState = self.selectionState, let dayRange = selectionState.dayRange {
var selectedCount = 0
for i in 0 ..< self.months.count {
@ -1643,11 +1638,7 @@ public final class CalendarMessageScreen: ViewController {
}
if selectedCount != 0 {
if selectedCount == 1 {
title = "1 day selected"
} else {
title = "\(selectedCount) days selected"
}
title = self.presentationData.strings.MessageCalendar_DaysSelectedTitle(Int32(selectedCount))
}
}
@ -1732,8 +1723,7 @@ public final class CalendarMessageScreen: ViewController {
self.navigationPresentation = .modal
self.navigationItem.setLeftBarButton(UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(dismissPressed)), animated: false)
//TODO:localize
self.navigationItem.setTitle("Calendar", animated: false)
self.navigationItem.setTitle(self.presentationData.strings.MessageCalendar_Title, animated: false)
/*if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat {
self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Common_Select, style: .plain, target: self, action: #selector(self.toggleSelectPressed)), animated: false)

View File

@ -290,3 +290,177 @@ public class InteractiveCheckNode: CheckNode {
self.buttonNode.frame = self.bounds
}
}
private final class NullActionClass: NSObject, CAAction {
@objc func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
}
}
private let nullAction = NullActionClass()
public class CheckLayer: CALayer {
private var animatingOut = false
private var animationProgress: CGFloat = 0.0
public var theme: CheckNodeTheme {
didSet {
self.setNeedsDisplay()
}
}
public init(theme: CheckNodeTheme, content: CheckNodeContent = .check) {
self.theme = theme
self.content = content
super.init()
self.isOpaque = false
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func action(forKey event: String) -> CAAction? {
return nullAction
}
public var content: CheckNodeContent {
didSet {
self.setNeedsDisplay()
}
}
public var selected = false
public func setSelected(_ selected: Bool, animated: Bool = false) {
guard self.selected != selected else {
return
}
self.selected = selected
if animated {
self.animatingOut = !selected
let animation = POPBasicAnimation()
animation.property = (POPAnimatableProperty.property(withName: "progress", initializer: { property in
property?.readBlock = { node, values in
values?.pointee = (node as! CheckLayer).animationProgress
}
property?.writeBlock = { node, values in
(node as! CheckLayer).animationProgress = values!.pointee
(node as! CheckLayer).setNeedsDisplay()
}
property?.threshold = 0.01
}) as! POPAnimatableProperty)
animation.fromValue = (selected ? 0.0 : 1.0) as NSNumber
animation.toValue = (selected ? 1.0 : 0.0) as NSNumber
animation.timingFunction = CAMediaTimingFunction(name: selected ? CAMediaTimingFunctionName.easeOut : CAMediaTimingFunctionName.easeIn)
animation.duration = selected ? 0.21 : 0.15
self.pop_add(animation, forKey: "progress")
} else {
self.pop_removeAllAnimations()
self.animatingOut = false
self.animationProgress = selected ? 1.0 : 0.0
self.setNeedsDisplay()
}
}
public func setHighlighted(_ highlighted: Bool, animated: Bool = false) {
}
override public func display() {
if self.bounds.isEmpty {
return
}
self.contents = generateImage(self.bounds.size, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
let parameters = CheckNodeParameters(theme: self.theme, content: self.content, animationProgress: self.animationProgress, selected: self.selected, animatingOut: self.animatingOut)
let center = CGPoint(x: bounds.width / 2.0, y: bounds.width / 2.0)
var borderWidth: CGFloat = 1.0 + UIScreenPixel
if parameters.theme.hasInset {
borderWidth = 1.5
}
if let customBorderWidth = parameters.theme.borderWidth {
borderWidth = customBorderWidth
}
let checkWidth: CGFloat = 1.5
let inset: CGFloat = parameters.theme.hasInset ? 2.0 - UIScreenPixel : 0.0
let checkProgress = parameters.animatingOut ? 1.0 : parameters.animationProgress
let fillProgress = parameters.animatingOut ? 1.0 : min(1.0, parameters.animationProgress * 1.35)
context.setStrokeColor(parameters.theme.borderColor.cgColor)
context.setLineWidth(borderWidth)
let maybeScaleOut = {
if parameters.animatingOut {
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.scaleBy(x: parameters.animationProgress, y: parameters.animationProgress)
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
context.setAlpha(parameters.animationProgress)
}
}
let borderInset = borderWidth / 2.0 + inset
let borderProgress: CGFloat = parameters.theme.filledBorder ? fillProgress : 1.0
let borderFrame = bounds.insetBy(dx: borderInset, dy: borderInset)
if parameters.theme.filledBorder {
maybeScaleOut()
}
context.saveGState()
if parameters.theme.hasShadow {
context.setShadow(offset: CGSize(), blur: 2.5, color: UIColor(rgb: 0x000000, alpha: 0.22).cgColor)
}
context.strokeEllipse(in: borderFrame.insetBy(dx: borderFrame.width * (1.0 - borderProgress), dy: borderFrame.height * (1.0 - borderProgress)))
context.restoreGState()
if !parameters.theme.filledBorder {
maybeScaleOut()
}
context.setFillColor(parameters.theme.backgroundColor.cgColor)
let fillInset = parameters.theme.overlayBorder ? borderWidth + inset : inset
let fillFrame = bounds.insetBy(dx: fillInset, dy: fillInset)
context.fillEllipse(in: fillFrame.insetBy(dx: fillFrame.width * (1.0 - fillProgress), dy: fillFrame.height * (1.0 - fillProgress)))
let scale = (bounds.width - inset) / 18.0
let firstSegment: CGFloat = max(0.0, min(1.0, checkProgress * 3.0))
let s = CGPoint(x: center.x - (4.0 - 0.3333) * scale, y: center.y + 0.5 * scale)
let p1 = CGPoint(x: 2.5 * scale, y: 3.0 * scale)
let p2 = CGPoint(x: 4.6667 * scale, y: -6.0 * scale)
if !firstSegment.isZero {
if firstSegment < 1.0 {
context.move(to: CGPoint(x: s.x + p1.x * firstSegment, y: s.y + p1.y * firstSegment))
context.addLine(to: s)
} else {
let secondSegment = (checkProgress - 0.33) * 1.5
context.move(to: CGPoint(x: s.x + p1.x + p2.x * secondSegment, y: s.y + p1.y + p2.y * secondSegment))
context.addLine(to: CGPoint(x: s.x + p1.x, y: s.y + p1.y))
context.addLine(to: s)
}
}
context.setStrokeColor(parameters.theme.strokeColor.cgColor)
if parameters.theme.strokeColor == .clear {
context.setBlendMode(.clear)
}
context.setLineWidth(checkWidth)
context.setLineCap(.round)
context.setLineJoin(.round)
context.setMiterLimit(10.0)
context.strokePath()
})?.cgImage
}
}

View File

@ -59,3 +59,59 @@ public final class GridMessageSelectionNode: ASDisplayNode {
self.checkNode.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width - 2.0, y: 2.0), size: checkSize)
}
}
private final class NullActionClass: NSObject, CAAction {
@objc func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
}
}
private let nullAction = NullActionClass()
public final class GridMessageSelectionLayer: CALayer {
private var selected = false
private let checkLayer: CheckLayer
public init(theme: CheckNodeTheme) {
self.checkLayer = CheckLayer(theme: theme, content: .check)
super.init()
self.addSublayer(self.checkLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func action(forKey event: String) -> CAAction? {
return nullAction
}
public func animateIn() {
self.checkLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
self.checkLayer.animateScale(from: 0.2, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
}
public func animateOut(completion: @escaping () -> Void) {
self.checkLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
self.checkLayer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
completion()
})
}
public func updateSelected(_ selected: Bool, animated: Bool) {
if self.selected != selected {
self.selected = selected
self.checkLayer.setSelected(selected, animated: animated)
}
}
public func updateLayout(size: CGSize) {
let checkSize = CGSize(width: 28.0, height: 28.0)
let previousSize = self.checkLayer.bounds.size
self.checkLayer.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width - 2.0, y: 2.0), size: checkSize)
if self.checkLayer.bounds.size != previousSize {
self.checkLayer.setNeedsDisplay()
}
}
}

View File

@ -1214,6 +1214,12 @@ public final class SparseItemGrid: ASDisplayNode {
public var cancelExternalContentGestures: (() -> Void)?
public var zoomLevelUpdated: ((ZoomLevel) -> Void)?
public var pinchEnabled: Bool = true {
didSet {
self.pinchRecognizer?.isEnabled = self.pinchEnabled
}
}
public init(theme: PresentationTheme) {
self.theme = theme

View File

@ -148,16 +148,17 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
return nil
}
//TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
switch tagMask {
case MessageTags.file:
return PeerInfoStatusData(text: "\(count) files", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_FileCount(Int32(count)), isActivity: false)
case MessageTags.music:
return PeerInfoStatusData(text: "\(count) music files", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_MusicCount(Int32(count)), isActivity: false)
case MessageTags.voiceOrInstantVideo:
return PeerInfoStatusData(text: "\(count) voice messages", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_VoiceMessageCount(Int32(count)), isActivity: false)
case MessageTags.webPage:
return PeerInfoStatusData(text: "\(count) links", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_LinkCount(Int32(count)), isActivity: false)
default:
return nil
}

View File

@ -20,6 +20,7 @@ import DirectMediaImageCache
import ComponentFlow
import TelegramNotices
import TelegramUIPreferences
import CheckNode
private final class FrameSequenceThumbnailNode: ASDisplayNode {
private let context: AccountContext
@ -754,6 +755,7 @@ private final class DurationLayer: CALayer {
private final class ItemLayer: CALayer, SparseItemGridLayer {
var item: VisualMediaItem?
var durationLayer: DurationLayer?
var selectionLayer: GridMessageSelectionLayer?
var disposable: Disposable?
var hasContents: Bool = false
@ -796,6 +798,35 @@ private final class ItemLayer: CALayer, SparseItemGridLayer {
}
}
func updateSelection(theme: CheckNodeTheme, isSelected: Bool?, animated: Bool) {
if let isSelected = isSelected {
if let selectionLayer = self.selectionLayer {
selectionLayer.updateSelected(isSelected, animated: animated)
} else {
let selectionLayer = GridMessageSelectionLayer(theme: theme)
selectionLayer.updateSelected(isSelected, animated: false)
self.selectionLayer = selectionLayer
self.addSublayer(selectionLayer)
if !self.bounds.isEmpty {
selectionLayer.frame = CGRect(origin: CGPoint(), size: self.bounds.size)
selectionLayer.updateLayout(size: self.bounds.size)
if animated {
selectionLayer.animateIn()
}
}
}
} else if let selectionLayer = self.selectionLayer {
self.selectionLayer = nil
if animated {
selectionLayer.animateOut { [weak selectionLayer] in
selectionLayer?.removeFromSuperlayer()
}
} else {
selectionLayer.removeFromSuperlayer()
}
}
}
func unbind() {
self.item = nil
}
@ -975,6 +1006,7 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
let listItemInteraction: ListMessageItemInteraction
let chatControllerInteraction: ChatControllerInteraction
let chatPresentationData: ChatPresentationData
let checkNodeTheme: CheckNodeTheme
var loadHoleImpl: ((SparseItemGrid.HoleAnchor, SparseItemGrid.HoleLocation) -> Signal<Never, NoError>)?
var onTapImpl: ((VisualMediaItem) -> Void)?
@ -1000,6 +1032,8 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
let themeData = ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper)
self.chatPresentationData = ChatPresentationData(theme: themeData, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners, animatedEmojiScale: 1.0)
self.checkNodeTheme = CheckNodeTheme(theme: presentationData.theme, style: .overlay, hasInset: true)
}
func getListShimmerImage(height: CGFloat) -> UIImage {
@ -1250,6 +1284,12 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
layer.updateDuration(duration: duration)
}
if let selectionState = self.chatControllerInteraction.selectionState {
layer.updateSelection(theme: self.checkNodeTheme, isSelected: selectionState.selectedIds.contains(message.id), animated: false)
} else {
layer.updateSelection(theme: self.checkNodeTheme, isSelected: nil, animated: false)
}
layer.bind(item: item)
}
}
@ -1484,8 +1524,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
return
}
if count < 1 {
//TODO:localize
strongSelf.itemGrid.updateScrollingAreaTooltip(tooltip: SparseItemGridScrollingArea.DisplayTooltip(animation: "anim_infotip", text: "You can hold and move this bar for faster scrolling", completed: {
strongSelf.itemGrid.updateScrollingAreaTooltip(tooltip: SparseItemGridScrollingArea.DisplayTooltip(animation: "anim_infotip", text: strongSelf.itemGridBinding.chatPresentationData.strings.SharedMedia_FastScrollTooltip, completed: {
guard let strongSelf = self else {
return
}
@ -1505,8 +1544,16 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
guard let strongSelf = self else {
return
}
if let selectionState = strongSelf.chatControllerInteraction.selectionState {
var toggledValue = true
if selectionState.selectedIds.contains(item.message.id) {
toggledValue = false
}
strongSelf.chatControllerInteraction.toggleMessagesSelection([item.message.id], toggledValue)
} else {
let _ = strongSelf.chatControllerInteraction.openMessage(item.message, .default)
}
}
self.itemGridBinding.onTagTapImpl = { [weak self] in
guard let strongSelf = self else {
@ -1813,72 +1860,67 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
return true
})
|> map { contentType, dict -> PeerInfoStatusData? in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
switch contentType {
case .photoOrVideo:
let photoCount: Int32 = dict[.photo] ?? 0
let videoCount: Int32 = dict[.video] ?? 0
//TODO:localize
if photoCount != 0 && videoCount != 0 {
return PeerInfoStatusData(text: "\(photoCount) photos, \(videoCount) videos", isActivity: false)
return PeerInfoStatusData(text: "\(presentationData.strings.SharedMedia_PhotoCount(Int32(photoCount))), \(presentationData.strings.SharedMedia_VideoCount(Int32(videoCount)))", isActivity: false)
} else if photoCount != 0 {
return PeerInfoStatusData(text: "\(photoCount) photos", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_PhotoCount(Int32(photoCount)), isActivity: false)
} else if videoCount != 0 {
return PeerInfoStatusData(text: "\(videoCount) videos", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_VideoCount(Int32(videoCount)), isActivity: false)
} else {
return nil
}
case .photo:
let photoCount: Int32 = dict[.photo] ?? 0
//TODO:localize
if photoCount != 0 {
return PeerInfoStatusData(text: "\(photoCount) photos", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_PhotoCount(Int32(photoCount)), isActivity: false)
} else {
return nil
}
case .video:
let videoCount: Int32 = dict[.video] ?? 0
//TODO:localize
if videoCount != 0 {
return PeerInfoStatusData(text: "\(videoCount) videos", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_VideoCount(Int32(videoCount)), isActivity: false)
} else {
return nil
}
case .gifs:
let gifCount: Int32 = dict[.gif] ?? 0
//TODO:localize
if gifCount != 0 {
return PeerInfoStatusData(text: "\(gifCount) gifs", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_GifCount(Int32(gifCount)), isActivity: false)
} else {
return nil
}
case .files:
let fileCount: Int32 = dict[.file] ?? 0
//TODO:localize
if fileCount != 0 {
return PeerInfoStatusData(text: "\(fileCount) files", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_FileCount(Int32(fileCount)), isActivity: false)
} else {
return nil
}
case .voiceAndVideoMessages:
let itemCount: Int32 = dict[.voiceOrInstantVideo] ?? 0
//TODO:localize
if itemCount != 0 {
return PeerInfoStatusData(text: "\(itemCount) voice messages", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_VoiceMessageCount(Int32(itemCount)), isActivity: false)
} else {
return nil
}
case .music:
let itemCount: Int32 = dict[.music] ?? 0
//TODO:localize
if itemCount != 0 {
return PeerInfoStatusData(text: "\(itemCount) music files", isActivity: false)
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_MusicCount(Int32(itemCount)), isActivity: false)
} else {
return nil
}
@ -2105,6 +2147,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
}
func updateSelectedMessages(animated: Bool) {
switch self.contentType {
case .files, .music, .voiceAndVideoMessages:
self.itemGrid.forEachVisibleItem { item in
guard let itemView = item.view as? ItemView else {
return
@ -2121,6 +2165,16 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
)
}
}
case .photo, .video, .photoOrVideo, .gifs:
self.itemGrid.forEachVisibleItem { item in
guard let itemLayer = item.layer as? ItemLayer, let item = itemLayer.item else {
return
}
itemLayer.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: self.chatControllerInteraction.selectionState?.selectedIds.contains(item.message.id), animated: animated)
}
self.itemGrid.pinchEnabled = self.chatControllerInteraction.selectionState == nil
}
}
func update(size: CGSize, topInset: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, expandProgress: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) {

View File

@ -6061,8 +6061,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
return
}
let buttonFrame = buttonNode.view.convert(buttonNode.bounds, to: self.view)
//TODO:localize
controller.present(TooltipScreen(account: self.context.account, text: "Tap on this icon for calendar view", style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in
controller.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.SharedMedia_CalendarTooltip, style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in
return .dismiss(consume: false)
}), in: .current)
}
@ -6099,14 +6098,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
var items: [ContextMenuItem] = []
//TODO:localize
let strings = strongSelf.presentationData.strings
var recurseGenerateAction: ((Bool) -> ContextMenuActionItem)?
let generateAction: (Bool) -> ContextMenuActionItem = { [weak pane] isZoomIn in
let nextZoomLevel = isZoomIn ? pane?.availableZoomLevels().increment : pane?.availableZoomLevels().decrement
let canZoom: Bool = nextZoomLevel != nil
return ContextMenuActionItem(id: isZoomIn ? 0 : 1, text: isZoomIn ? "Zoom In" : "Zoom Out", textColor: canZoom ? .primary : .disabled, icon: { theme in
return ContextMenuActionItem(id: isZoomIn ? 0 : 1, text: isZoomIn ? strings.SharedMedia_ZoomIn : strings.SharedMedia_ZoomOut, textColor: canZoom ? .primary : .disabled, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: isZoomIn ? "Chat/Context Menu/ZoomIn" : "Chat/Context Menu/ZoomOut"), color: canZoom ? theme.contextMenu.primaryColor : theme.contextMenu.primaryColor.withMultipliedAlpha(0.4))
}, action: canZoom ? { action in
guard let pane = pane, let zoomLevel = isZoomIn ? pane.availableZoomLevels().increment : pane.availableZoomLevels().decrement else {
@ -6127,7 +6127,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
items.append(.action(generateAction(false)))
var ignoreNextActions = false
items.append(.action(ContextMenuActionItem(text: "Show Calendar", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowCalendar, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.contextMenu.primaryColor)
}, action: { _, a in
if ignoreNextActions {
@ -6157,7 +6157,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
showVideos = false
}
items.append(.action(ContextMenuActionItem(text: "Show Photos", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowPhotos, icon: { theme in
if !showPhotos {
return nil
}
@ -6181,7 +6181,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
pane.updateContentType(contentType: updatedContentType)
})))
items.append(.action(ContextMenuActionItem(text: "Show Videos", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowVideos, icon: { theme in
if !showVideos {
return nil
}

View File

@ -798,8 +798,9 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
private var animationTimer: SwiftSignalKit.Timer?
private let statusPromise = Promise<PeerInfoStatusData?>(nil)
var status: Signal<PeerInfoStatusData?, NoError> {
return .single(nil)
self.statusPromise.get()
}
var tabBarOffsetUpdated: ((ContainedViewLayoutTransition) -> Void)?
@ -872,6 +873,23 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
}, queue: .mainQueue())
self.animationTimer = animationTimer
animationTimer.start()
self.statusPromise.set(context.account.postbox.combinedView(keys: [PostboxViewKey.historyTagSummaryView(tag: tagMaskForType(self.contentType), peerId: peerId, namespace: Namespaces.Message.Cloud)])
|> map { views -> PeerInfoStatusData? in
let count: Int32 = (views.views[PostboxViewKey.historyTagSummaryView(tag: tagMaskForType(self.contentType), peerId: peerId, namespace: Namespaces.Message.Cloud)] as? MessageHistoryTagSummaryView)?.count ?? 0
if count == 0 {
return nil
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
switch contentType {
case .gifs:
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_GifCount(Int32(count)), isActivity: false)
default:
return nil
}
})
}
deinit {