Various Voice Chats improvements

This commit is contained in:
Ilya Laktyushin 2021-03-05 20:00:00 +04:00
parent 556002df68
commit 13fd591ee0
19 changed files with 3307 additions and 3112 deletions

View File

@ -6221,3 +6221,8 @@ Sorry for the inconvenience.";
"VoiceChat.InviteLink.InviteListeners_any" = "[%@] Invite Listeners";
"Conversation.JoinVoiceChat" = "JOIN VOICE CHAT";
"Conversation.CancelForwardTitle" = "Cancel Forwarding";
"Conversation.CancelForwardText" = "Do you want to cancel this forwarding or would like to send this messages to another chat?";
"Conversation.CancelForwardCancelForward" = "Cancel Forwarding";
"Conversation.CancelForwardSelectChat" = "Select Chat";

View File

@ -34,10 +34,11 @@ private struct ArchivedStickersNoticeEntry: Comparable, Identifiable {
}
func item(account: Account, presentationData: PresentationData) -> ListViewItem {
return ItemListStickerPackItem(presentationData: ItemListPresentationData(presentationData), account: account, packInfo: info, itemCount: self.count, topItem: topItem, unread: false, control: .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false), enabled: true, playAnimatedStickers: true, sectionId: 0, action: {
return ItemListStickerPackItem(presentationData: ItemListPresentationData(presentationData), account: account, packInfo: info, itemCount: self.count, topItem: topItem, unread: false, control: .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: true, sectionId: 0, action: {
}, setPackIdWithRevealedOptions: { current, previous in
}, addPack: {
}, removePack: {
}, toggleSelected: {
})
}
}

View File

@ -296,8 +296,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
return .like
case .unlike:
return .unlike
default:
return nil
}
}
if strongSelf.highlightedReaction != highlightedReaction {
@ -431,8 +429,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
reactionSelected(.like)
case .unlike:
reactionSelected(.unlike)
default:
break
}
}
}
@ -632,7 +628,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
if let contentNode = self.contentContainerNode.contentNode {
switch contentNode {
case let .reference(referenceNode):
case .reference:
let springDuration: Double = 0.42 * animationDurationFactor
let springDamping: CGFloat = 104.0
@ -758,10 +754,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
self.scrollNode.view.setContentOffset(self.scrollNode.view.contentOffset, animated: false)
var completedEffect = false
var completedContentNode = false
var completedActionsNode = false
if let transitionInfo = transitionInfo, let parentSupernode = referenceNode.supernode {
self.originalProjectedContentViewFrame = (convertFrame(referenceNode.frame, from: parentSupernode.view, to: self.view), convertFrame(referenceNode.bounds, from: referenceNode.view, to: self.view))
@ -794,8 +786,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
if animateOutToItem, let originalProjectedContentViewFrame = self.originalProjectedContentViewFrame {
let localSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.scrollNode.view)
let localContentSourceFrame = self.view.convert(originalProjectedContentViewFrame.1, to: self.contentContainerNode.view.superview)
self.actionsContainerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y), duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false, additive: true)
}
case let .extracted(source):
@ -864,7 +854,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
let propertyAnimator = propertyAnimator as? UIViewPropertyAnimator
propertyAnimator?.stopAnimation(true)
}
self.propertyAnimator = UIViewPropertyAnimator(duration: transitionDuration * UIView.animationDurationFactor(), curve: .easeInOut, animations: { [weak self] in
self.propertyAnimator = UIViewPropertyAnimator(duration: transitionDuration * UIView.animationDurationFactor(), curve: .easeInOut, animations: {
//self?.effectView.effect = nil
})
}

View File

@ -446,7 +446,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
}, mainLinkContextAction: { invite, node, gesture in
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?(), let invite = invite else {
guard let node = node as? ContextReferenceContentNode, let controller = getControllerImpl?(), let invite = invite else {
return
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -551,7 +551,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
})))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node, blurBackground: false)), items: .single(items), reactionItems: [], gesture: gesture)
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
presentInGlobalOverlayImpl?(contextController)
}, createLink: {
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: nil, completion: { invite in
@ -899,3 +899,17 @@ final class InviteLinkContextExtractedContentSource: ContextExtractedContentSour
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
}
}
final class InviteLinkContextReferenceContentSource: ContextReferenceContentSource {
private let controller: ViewController
private let sourceNode: ContextReferenceContentNode
init(controller: ViewController, sourceNode: ContextReferenceContentNode) {
self.controller = controller
self.sourceNode = sourceNode
}
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(referenceNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds)
}
}

View File

@ -122,7 +122,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
private let fieldNode: ASImageNode
private let addressNode: TextNode
private let fieldButtonNode: HighlightTrackingButtonNode
private let extractedContainerNode: ContextExtractedContentContainingNode
private let referenceContainerNode: ContextReferenceContentNode
private let containerNode: ContextControllerSourceNode
private let addressButtonNode: HighlightTrackingButtonNode
private let addressButtonIconNode: ASImageNode
@ -172,7 +172,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.fieldButtonNode = HighlightTrackingButtonNode()
self.addressButtonNode = HighlightTrackingButtonNode()
self.extractedContainerNode = ContextExtractedContentContainingNode()
self.referenceContainerNode = ContextReferenceContentNode()
self.containerNode = ContextControllerSourceNode()
self.containerNode.isGestureEnabled = false
self.addressButtonIconNode = ASImageNode()
@ -196,9 +196,8 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.addSubnode(self.invitedPeersNode)
self.addSubnode(self.avatarsButtonNode)
self.containerNode.addSubnode(self.extractedContainerNode)
self.extractedContainerNode.contentNode.addSubnode(self.addressButtonIconNode)
self.containerNode.targetNodeForActivationProgress = self.extractedContainerNode.contentNode
self.containerNode.addSubnode(self.referenceContainerNode)
self.referenceContainerNode.addSubnode(self.addressButtonIconNode)
self.addressButtonNode.addSubnode(self.containerNode)
self.addSubnode(self.addressButtonNode)
@ -260,7 +259,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
@objc private func addressButtonPressed() {
if let item = self.item {
item.contextAction?(self.extractedContainerNode)
item.contextAction?(self.referenceContainerNode)
}
}
@ -432,8 +431,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
strongSelf.addressNode.frame = CGRect(origin: CGPoint(x: fieldFrame.minX + (alignCentrally ? floorToScreenPixels((fieldFrame.width - addressLayout.size.width) / 2.0) : 14.0), y: fieldFrame.minY + floorToScreenPixels((fieldFrame.height - addressLayout.size.height) / 2.0) + 1.0), size: addressLayout.size)
strongSelf.addressButtonNode.frame = CGRect(origin: CGPoint(x: params.width - rightInset - 38.0 - 14.0, y: verticalInset), size: CGSize(width: 52.0, height: 52.0))
strongSelf.extractedContainerNode.frame = strongSelf.addressButtonNode.bounds
strongSelf.extractedContainerNode.contentRect = strongSelf.addressButtonNode.bounds
strongSelf.referenceContainerNode.frame = strongSelf.addressButtonNode.bounds
strongSelf.addressButtonIconNode.frame = strongSelf.addressButtonNode.bounds
let shareButtonNode: SolidRoundedButtonNode

View File

@ -19,12 +19,14 @@ public struct ItemListStickerPackItemEditing: Equatable {
public var editing: Bool
public var revealed: Bool
public var reorderable: Bool
public var selectable: Bool
public init(editable: Bool, editing: Bool, revealed: Bool, reorderable: Bool) {
public init(editable: Bool, editing: Bool, revealed: Bool, reorderable: Bool, selectable: Bool) {
self.editable = editable
self.editing = editing
self.revealed = revealed
self.reorderable = reorderable
self.selectable = selectable
}
}
@ -51,8 +53,9 @@ public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
let setPackIdWithRevealedOptions: (ItemCollectionId?, ItemCollectionId?) -> Void
let addPack: () -> Void
let removePack: () -> Void
let toggleSelected: () -> Void
public init(presentationData: ItemListPresentationData, account: Account, packInfo: StickerPackCollectionInfo, itemCount: String, topItem: StickerPackItem?, unread: Bool, control: ItemListStickerPackItemControl, editing: ItemListStickerPackItemEditing, enabled: Bool, playAnimatedStickers: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping () -> Void, removePack: @escaping () -> Void) {
public init(presentationData: ItemListPresentationData, account: Account, packInfo: StickerPackCollectionInfo, itemCount: String, topItem: StickerPackItem?, unread: Bool, control: ItemListStickerPackItemControl, editing: ItemListStickerPackItemEditing, enabled: Bool, playAnimatedStickers: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping () -> Void, removePack: @escaping () -> Void, toggleSelected: @escaping () -> Void) {
self.presentationData = presentationData
self.account = account
self.packInfo = packInfo
@ -68,6 +71,7 @@ public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions
self.addPack = addPack
self.removePack = removePack
self.toggleSelected = toggleSelected
}
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -160,6 +164,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
private var layoutParams: (ItemListStickerPackItem, ListViewItemLayoutParams, ItemListNeighbors)?
private var selectableControlNode: ItemListSelectableControlNode?
private var editableControlNode: ItemListEditableControlNode?
private var reorderControlNode: ItemListEditableReorderControlNode?
@ -168,7 +173,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
private let fetchDisposable = MetaDisposable()
override var canBeSelected: Bool {
if self.editableControlNode != nil || self.disabledOverlayNode != nil {
if self.selectableControlNode != nil || self.editableControlNode != nil || self.disabledOverlayNode != nil {
return false
}
if let item = self.layoutParams?.0, item.action != nil {
@ -309,12 +314,20 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
}
}
override func tapped() {
guard let item = self.layoutParams?.0, item.editing.editing && item.editing.selectable else {
return
}
item.toggleSelected()
}
func asyncLayout() -> (_ item: ItemListStickerPackItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) {
let makeImageLayout = self.imageNode.asyncLayout()
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeStatusLayout = TextNode.asyncLayout(self.statusNode)
let editableControlLayout = ItemListEditableControlNode.asyncLayout(self.editableControlNode)
let reorderControlLayout = ItemListEditableReorderControlNode.asyncLayout(self.reorderControlNode)
let selectableControlLayout = ItemListSelectableControlNode.asyncLayout(self.selectableControlNode)
let previousThumbnailItem = self.currentThumbnailItem
var currentDisabledOverlayNode = self.disabledOverlayNode
@ -358,8 +371,8 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
case .selection:
rightInset += 16.0
checkImage = PresentationResourcesItemList.checkIconImage(item.presentationData.theme)
case .check:
rightInset += 16.0
default:
break
}
var unreadImage: UIImage?
@ -380,14 +393,25 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
var editableControlSizeAndApply: (CGFloat, (CGFloat) -> ItemListEditableControlNode)?
var reorderControlSizeAndApply: (CGFloat, (CGFloat, Bool, ContainedViewLayoutTransition) -> ItemListEditableReorderControlNode)?
var selectableControlSizeAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
var editingOffset: CGFloat = 0.0
var reorderInset: CGFloat = 0.0
if item.editing.editing {
let sizeAndApply = editableControlLayout(item.presentationData.theme, false)
editableControlSizeAndApply = sizeAndApply
editingOffset = sizeAndApply.0
if item.editing.selectable {
var selected = false
if case let .check(checked) = item.control {
selected = checked
}
let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, true)
selectableControlSizeAndApply = sizeAndApply
editingOffset = sizeAndApply.0
} else {
let sizeAndApply = editableControlLayout(item.presentationData.theme, false)
editableControlSizeAndApply = sizeAndApply
editingOffset = sizeAndApply.0
}
if item.editing.reorderable {
let sizeAndApply = reorderControlLayout(item.presentationData.theme)
@ -547,6 +571,31 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
})
}
if let selectableControlSizeAndApply = selectableControlSizeAndApply {
let selectableControlSize = CGSize(width: selectableControlSizeAndApply.0, height: layout.contentSize.height)
let selectableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: selectableControlSize)
if strongSelf.selectableControlNode == nil {
let selectableControlNode = selectableControlSizeAndApply.1(selectableControlSize, false)
strongSelf.selectableControlNode = selectableControlNode
strongSelf.addSubnode(selectableControlNode)
selectableControlNode.frame = selectableControlFrame
transition.animatePosition(node: selectableControlNode, from: CGPoint(x: -selectableControlFrame.size.width / 2.0, y: selectableControlFrame.midY))
selectableControlNode.alpha = 0.0
transition.updateAlpha(node: selectableControlNode, alpha: 1.0)
} else if let selectableControlNode = strongSelf.selectableControlNode {
transition.updateFrame(node: selectableControlNode, frame: selectableControlFrame)
let _ = selectableControlSizeAndApply.1(selectableControlSize, transition.isAnimated)
}
} else if let selectableControlNode = strongSelf.selectableControlNode {
var selectableControlFrame = selectableControlNode.frame
selectableControlFrame.origin.x = -selectableControlFrame.size.width
strongSelf.selectableControlNode = nil
transition.updateAlpha(node: selectableControlNode, alpha: 0.0)
transition.updateFrame(node: selectableControlNode, frame: selectableControlFrame, completion: { [weak selectableControlNode] _ in
selectableControlNode?.removeFromSupernode()
})
}
if let reorderControlSizeAndApply = reorderControlSizeAndApply {
if strongSelf.reorderControlNode == nil {
let reorderControlNode = reorderControlSizeAndApply.1(layout.contentSize.height, false, .immediate)

View File

@ -76,10 +76,20 @@ public struct ItemListToolbarItem {
public let title: String
public let isEnabled: Bool
public let action: () -> Void
public init(title: String, isEnabled: Bool, action: @escaping () -> Void) {
self.title = title
self.isEnabled = isEnabled
self.action = action
}
}
let actions: [Action]
public init(actions: [Action]) {
self.actions = actions
}
var toolbar: Toolbar {
var leftAction: ToolbarAction?
var middleAction: ToolbarAction?
@ -644,9 +654,25 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
return transition.strings.VoiceOver_ScrollStatus(row, count).0
}
let toolbarFrame = CGRect()
let layoutTransition: ContainedViewLayoutTransition = .immediate
if let toolbarItem = transition.toolbarItem, let (layout, _) = self.validLayout {
var options: ContainerViewLayoutInsetOptions = []
if layout.metrics.widthClass == .regular {
options.insert(.input)
}
var tabBarHeight: CGFloat
let bottomInset: CGFloat = layout.insets(options: options).bottom
if !layout.safeInsets.left.isZero {
tabBarHeight = 34.0 + bottomInset
// insets.bottom += 34.0
} else {
tabBarHeight = 49.0 + bottomInset
// insets.bottom += 49.0
}
let toolbarFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - tabBarHeight), size: CGSize(width: layout.size.width, height: tabBarHeight))
if let toolbarNode = self.toolbarNode {
layoutTransition.updateFrame(node: toolbarNode, frame: toolbarFrame)
toolbarNode.updateLayout(size: toolbarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: layout.intrinsicInsets.bottom, toolbar: toolbarItem.toolbar, transition: layoutTransition)

View File

@ -228,7 +228,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
case let .packsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .pack(_, _, _, info, topItem, count, playAnimatedStickers, selected):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: selected ? .selection : .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: selected ? .selection : .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
if selected {
arguments.openStickerPack(info)
} else {
@ -237,6 +237,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
}, setPackIdWithRevealedOptions: { _, _ in
}, addPack: {
}, removePack: {
}, toggleSelected: {
})
case let .currentPack(_, theme, strings, content):
return GroupStickerPackCurrentItem(theme: theme, strings: strings, account: arguments.account, content: content, sectionId: self.section, action: {

View File

@ -169,6 +169,7 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
arguments.addPack(info)
}, removePack: {
arguments.removePack(info)
}, toggleSelected: {
})
}
}
@ -232,7 +233,7 @@ private func archivedStickerPacksControllerEntries(presentationData: Presentatio
var index: Int32 = 0
for item in packs {
if !installedIds.contains(item.info.id) {
entries.append(.pack(index, presentationData.theme, presentationData.strings, item.info, item.topItems.first, presentationData.strings.StickerPack_StickerCount(item.info.count), stickerSettings.loopAnimatedStickers, !state.removingPackIds.contains(item.info.id), ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == item.info.id, reorderable: false)))
entries.append(.pack(index, presentationData.theme, presentationData.strings, item.info, item.topItems.first, presentationData.strings.StickerPack_StickerCount(item.info.count), stickerSettings.loopAnimatedStickers, !state.removingPackIds.contains(item.info.id), ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == item.info.id, reorderable: false, selectable: true)))
index += 1
}
}

View File

@ -121,12 +121,13 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
let arguments = arguments as! FeaturedStickerPacksControllerArguments
switch self {
case let .pack(_, theme, strings, info, unread, topItem, count, playAnimatedStickers, installed):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { _, _ in
}, addPack: {
arguments.addPack(info)
}, removePack: {
}, toggleSelected: {
})
}
}

View File

@ -14,6 +14,7 @@ import AccountContext
import StickerPackPreviewUI
import ItemListStickerPackItem
import UndoUI
import ShareController
private final class InstalledStickerPacksControllerArguments {
let account: Account
@ -27,8 +28,9 @@ private final class InstalledStickerPacksControllerArguments {
let openArchived: ([ArchivedStickerPackItem]?) -> Void
let openSuggestOptions: () -> Void
let toggleAnimatedStickers: (Bool) -> Void
let togglePackSelected: (ItemCollectionId) -> Void
init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, removePack: @escaping (ArchivedStickerPackItem) -> Void, openStickersBot: @escaping () -> Void, openMasks: @escaping () -> Void, openFeatured: @escaping () -> Void, openArchived: @escaping ([ArchivedStickerPackItem]?) -> Void, openSuggestOptions: @escaping () -> Void, toggleAnimatedStickers: @escaping (Bool) -> Void) {
init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, removePack: @escaping (ArchivedStickerPackItem) -> Void, openStickersBot: @escaping () -> Void, openMasks: @escaping () -> Void, openFeatured: @escaping () -> Void, openArchived: @escaping ([ArchivedStickerPackItem]?) -> Void, openSuggestOptions: @escaping () -> Void, toggleAnimatedStickers: @escaping (Bool) -> Void, togglePackSelected: @escaping (ItemCollectionId) -> Void) {
self.account = account
self.openStickerPack = openStickerPack
self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions
@ -39,6 +41,7 @@ private final class InstalledStickerPacksControllerArguments {
self.openArchived = openArchived
self.openSuggestOptions = openSuggestOptions
self.toggleAnimatedStickers = toggleAnimatedStickers
self.togglePackSelected = togglePackSelected
}
}
@ -99,7 +102,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
case animatedStickers(PresentationTheme, String, Bool)
case animatedStickersInfo(PresentationTheme, String)
case packsTitle(PresentationTheme, String)
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing)
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing, Bool?)
case packsInfo(PresentationTheme, String)
var section: ItemListSectionId {
@ -127,7 +130,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
return .index(5)
case .packsTitle:
return .index(6)
case let .pack(_, _, _, info, _, _, _, _, _):
case let .pack(_, _, _, info, _, _, _, _, _, _):
return .pack(info.id)
case .packsInfo:
return .index(7)
@ -178,8 +181,8 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
} else {
return false
}
case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsAnimatedStickers, lhsEnabled, lhsEditing):
if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsAnimatedStickers, rhsEnabled, rhsEditing) = rhs {
case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsAnimatedStickers, lhsEnabled, lhsEditing, lhsSelected):
if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsAnimatedStickers, rhsEnabled, rhsEditing, rhsSelected) = rhs {
if lhsIndex != rhsIndex {
return false
}
@ -207,6 +210,9 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
if lhsEditing != rhsEditing {
return false
}
if lhsSelected != rhsSelected {
return false
}
return true
} else {
return false
@ -271,9 +277,9 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
default:
return true
}
case let .pack(lhsIndex, _, _, _, _, _, _, _, _):
case let .pack(lhsIndex, _, _, _, _, _, _, _, _, _):
switch rhs {
case let .pack(rhsIndex, _, _, _, _, _, _, _, _):
case let .pack(rhsIndex, _, _, _, _, _, _, _, _, _):
return lhsIndex < rhsIndex
case .packsInfo:
return true
@ -317,14 +323,16 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .packsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .pack(_, _, strings, info, topItem, count, animatedStickers, enabled, editing):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: .none, editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing, selected):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: editing.editing ? .check(checked: selected ?? false) : .none, editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { current, previous in
arguments.setPackIdWithRevealedOptions(current, previous)
}, addPack: {
}, removePack: {
arguments.removePack(ArchivedStickerPackItem(info: info, topItems: topItem != nil ? [topItem!] : []))
}, toggleSelected: {
arguments.togglePackSelected(info.id)
})
case let .packsInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { _ in
@ -336,7 +344,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
private struct InstalledStickerPacksControllerState: Equatable {
let editing: Bool
let selectedPackIds: Set<Int64>?
let selectedPackIds: Set<ItemCollectionId>?
let packIdWithRevealedOptions: ItemCollectionId?
init() {
@ -345,7 +353,7 @@ private struct InstalledStickerPacksControllerState: Equatable {
self.packIdWithRevealedOptions = nil
}
init(editing: Bool, selectedPackIds: Set<Int64>?, packIdWithRevealedOptions: ItemCollectionId?) {
init(editing: Bool, selectedPackIds: Set<ItemCollectionId>?, packIdWithRevealedOptions: ItemCollectionId?) {
self.editing = editing
self.selectedPackIds = selectedPackIds
self.packIdWithRevealedOptions = packIdWithRevealedOptions
@ -369,7 +377,7 @@ private struct InstalledStickerPacksControllerState: Equatable {
return InstalledStickerPacksControllerState(editing: editing, selectedPackIds: self.selectedPackIds, packIdWithRevealedOptions: self.packIdWithRevealedOptions)
}
func withUpdatedSelectedPackIds(_ selectedPackIds: Set<Int64>) -> InstalledStickerPacksControllerState {
func withUpdatedSelectedPackIds(_ selectedPackIds: Set<ItemCollectionId>?) -> InstalledStickerPacksControllerState {
return InstalledStickerPacksControllerState(editing: editing, selectedPackIds: selectedPackIds, packIdWithRevealedOptions: self.packIdWithRevealedOptions)
}
@ -454,7 +462,7 @@ private func installedStickerPacksControllerEntries(presentationData: Presentati
var index: Int32 = 0
for entry in sortedPacks {
if let info = entry.info as? StickerPackCollectionInfo {
entries.append(.pack(index, presentationData.theme, presentationData.strings, info, entry.firstItem as? StickerPackItem, presentationData.strings.StickerPack_StickerCount(info.count == 0 ? entry.count : info.count), stickerSettings.loopAnimatedStickers, true, ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == entry.id, reorderable: true)))
entries.append(.pack(index, presentationData.theme, presentationData.strings, info, entry.firstItem as? StickerPackItem, presentationData.strings.StickerPack_StickerCount(info.count == 0 ? entry.count : info.count), stickerSettings.loopAnimatedStickers, true, ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == entry.id, reorderable: true, selectable: true), state.selectedPackIds?.contains(info.id)))
index += 1
}
}
@ -485,7 +493,7 @@ public enum InstalledStickerPacksControllerMode {
}
public func installedStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode, archivedPacks: [ArchivedStickerPackItem]? = nil, updatedPacks: @escaping ([ArchivedStickerPackItem]?) -> Void = { _ in }, focusOnItemTag: InstalledStickerPacksEntryTag? = nil) -> ViewController {
let initialState = InstalledStickerPacksControllerState().withUpdatedEditing(mode == .modal)
let initialState = InstalledStickerPacksControllerState().withUpdatedEditing(mode == .modal).withUpdatedSelectedPackIds(mode == .modal ? Set() : nil)
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState)
let updateState: ((InstalledStickerPacksControllerState) -> InstalledStickerPacksControllerState) -> Void = { f in
@ -624,6 +632,19 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
let _ = updateStickerSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
return current.withUpdatedLoopAnimatedStickers(value)
}).start()
}, togglePackSelected: { packId in
updateState { state in
if var selectedPackIds = state.selectedPackIds {
if selectedPackIds.contains(packId) {
selectedPackIds.remove(packId)
} else {
selectedPackIds.insert(packId)
}
return state.withUpdatedSelectedPackIds(selectedPackIds)
} else {
return state
}
}
})
let stickerPacks = Promise<CombinedView>()
stickerPacks.set(context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [namespaceForMode(mode)])]))
@ -669,16 +690,32 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
if state.editing {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
updateState {
$0.withUpdatedEditing(false)
$0.withUpdatedEditing(false).withUpdatedSelectedPackIds(nil)
}
if case .modal = mode {
dismissImpl?()
}
})
let enabled = (state.selectedPackIds?.count ?? 0) > 0
toolbarItem = ItemListToolbarItem(actions: [.init(title: "Delete", isEnabled: enabled, action: {
updateState {
$0.withUpdatedEditing(false).withUpdatedSelectedPackIds(nil)
}
}), .init(title: "Archive", isEnabled: enabled, action: {
updateState {
$0.withUpdatedEditing(false).withUpdatedSelectedPackIds(nil)
}
}), .init(title: "Share", isEnabled: enabled, action: {
updateState {
$0.withUpdatedEditing(false).withUpdatedSelectedPackIds(nil)
}
let shareController = ShareController(context: context, subject: .text("test"), externalShare: true)
presentControllerImpl?(shareController, nil)
})])
} else {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Edit), style: .regular, enabled: true, action: {
updateState {
$0.withUpdatedEditing(true)
$0.withUpdatedEditing(true).withUpdatedSelectedPackIds(Set())
}
})
}
@ -711,7 +748,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
}
controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [InstalledStickerPacksEntry]) -> Signal<Bool, NoError> in
let fromEntry = entries[fromIndex]
guard case let .pack(_, _, _, fromPackInfo, _, _, _, _, _) = fromEntry else {
guard case let .pack(_, _, _, fromPackInfo, _, _, _, _, _, _) = fromEntry else {
return .single(false)
}
var referenceId: ItemCollectionId?
@ -719,7 +756,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
var afterAll = false
if toIndex < entries.count {
switch entries[toIndex] {
case let .pack(_, _, _, toPackInfo, _, _, _, _, _):
case let .pack(_, _, _, toPackInfo, _, _, _, _, _, _):
referenceId = toPackInfo.id
default:
if entries[toIndex] < fromEntry {

View File

@ -743,7 +743,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
activityRank: nil,
muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false),
volume: nil,
about: about
about: about,
raiseHandRating: nil
))
participants.sort()
}
@ -901,7 +902,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
strongSelf.requestDisposable.set((joinGroupCall(
account: strongSelf.account,
peerId: strongSelf.peerId,
joinAs: strongSelf.joinAsPeerId == strongSelf.account.peerId ? nil : strongSelf.joinAsPeerId,
joinAs: strongSelf.joinAsPeerId,
callId: callInfo.id,
accessHash: callInfo.accessHash,
preferMuted: true,
@ -1456,7 +1457,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
if id == peerId {
self.callContext?.setVolume(ssrc: ssrc, volume: Double(volume) / 10000.0)
if sync {
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: volume)
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: volume, raiseHand: nil)
}
break
}
@ -1564,19 +1565,19 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
canThenUnmute = true
}
let muteState = isMuted ? GroupCallParticipantsContext.Participant.MuteState(canUnmute: canThenUnmute, mutedByYou: mutedByYou) : nil
self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, volume: nil)
self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, volume: nil, raiseHand: nil)
return muteState
} else {
if peerId == self.joinAsPeerId {
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: nil)
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: nil, raiseHand: nil)
return nil
} else if self.stateValue.canManageCall || self.stateValue.adminIds.contains(self.accountContext.account.peerId) {
let muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false)
self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, volume: nil)
self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, volume: nil, raiseHand: nil)
return muteState
} else {
self.setVolume(peerId: peerId, volume: 10000, sync: true)
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: nil)
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: nil, raiseHand: nil)
return nil
}
}

View File

@ -1769,7 +1769,11 @@ public func cachedGroupCallDisplayAsAvailablePeers(account: Account) -> Signal<[
var peers: [FoundPeer] = []
for peerId in cached.peerIds {
if let peer = transaction.getPeer(peerId) {
peers.append(FoundPeer(peer: peer, subscribers: nil))
var subscribers: Int32?
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
subscribers = cachedData.participantsSummary.memberCount
}
peers.append(FoundPeer(peer: peer, subscribers: subscribers))
}
}
return (peers, cached.timestamp)

View File

@ -563,7 +563,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
statusController?.dismiss()
}
strongSelf.present(statusController, in: .window(.root))
strongSelf.createVoiceChatDisposable.set((createGroupCall(account: strongSelf.context.account, peerId: message.id.peerId, joinAs: nil)
strongSelf.createVoiceChatDisposable.set((createGroupCall(account: strongSelf.context.account, peerId: message.id.peerId, joinAs: strongSelf.context.account.peerId)
|> deliverOnMainQueue).start(next: { [weak self] info in
guard let strongSelf = self else {
return

View File

@ -9,6 +9,8 @@ import Display
import TelegramPresentationData
import AccountContext
import LocalizedPeerData
import AlertUI
import PresentationDataUtils
func textStringForForwardedMessage(_ message: Message, strings: PresentationStrings) -> (String, Bool) {
for media in message.media {
@ -81,11 +83,15 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
private let actionArea: AccessibilityAreaNode
let context: AccountContext
var theme: PresentationTheme
var strings: PresentationStrings
init(context: AccountContext, messageIds: [MessageId], theme: PresentationTheme, strings: PresentationStrings) {
self.context = context
self.messageIds = messageIds
self.theme = theme
self.strings = strings
self.closeButton = ASButtonNode()
self.closeButton.accessibilityLabel = strings.VoiceOver_DiscardPreparedContent
@ -167,8 +173,9 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
}
override func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
if self.theme !== theme {
if self.theme !== theme || self.strings !== strings {
self.theme = theme
self.strings = strings
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(theme), for: [])
@ -215,9 +222,12 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
}
@objc func closePressed() {
if let dismiss = self.dismiss {
dismiss()
}
let alertController = textAlertController(context: self.context, title: self.strings.Conversation_CancelForwardTitle, text: self.strings.Conversation_CancelForwardText, actions: [TextAlertAction(type: .genericAction, title: self.strings.Conversation_CancelForwardSelectChat, action: { [weak self] in
self?.interfaceInteraction?.forwardCurrentForwardMessages()
}), TextAlertAction(type: .defaultAction, title: self.strings.Conversation_CancelForwardCancelForward, action: { [weak self] in
self?.dismiss?()
})], actionLayout: .vertical)
self.interfaceInteraction?.presentController(alertController, nil)
}
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {

View File

@ -3828,7 +3828,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
statusController?.dismiss()
}
strongSelf.controller?.present(statusController, in: .window(.root))
strongSelf.activeActionDisposable.set((createGroupCall(account: strongSelf.context.account, peerId: peerId, joinAs: joinAsPeerId)
strongSelf.activeActionDisposable.set((createGroupCall(account: strongSelf.context.account, peerId: peerId, joinAs: joinAsPeerId ?? strongSelf.context.account.peerId)
|> deliverOnMainQueue).start(next: { [weak self] info in
guard let strongSelf = self else {
return

View File

@ -28,6 +28,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private let animationNode: AnimationNode?
private var animatedStickerNode: AnimatedStickerNode?
private var slotMachineNode: SlotMachineAnimationNode?
private var recordingIconNode: RecordingIconNode?
private var stillStickerNode: TransformImageNode?
private var stickerImageSize: CGSize?
private var stickerOffset: CGPoint?
@ -555,9 +556,11 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.avatarNode = nil
self.iconNode = nil
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_linkrevoked", colors: [:], scale: 0.066)
self.animationNode = nil
self.animatedStickerNode = nil
self.recordingIconNode = RecordingIconNode()
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .natural)
@ -609,6 +612,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.animatedStickerNode.flatMap(self.panelWrapperNode.addSubnode)
self.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode)
self.avatarNode.flatMap(self.panelWrapperNode.addSubnode)
self.recordingIconNode.flatMap(self.panelWrapperNode.addSubnode)
self.panelWrapperNode.addSubnode(self.titleNode)
self.panelWrapperNode.addSubnode(self.textNode)
self.panelWrapperNode.addSubnode(self.buttonNode)
@ -834,6 +838,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0)), size: iconSize)
transition.updateFrame(node: slotMachineNode, frame: iconFrame)
}
if let recordingIconNode = self.recordingIconNode {
let iconSize = CGSize(width: 24.0, height: 24.0)
let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0) + verticalOffset), size: iconSize)
transition.updateFrame(node: recordingIconNode, frame: iconFrame)
}
let timerTextSize = self.timerTextNode.updateLayout(CGSize(width: 100.0, height: 100.0))
transition.updateFrame(node: self.timerTextNode, frame: CGRect(origin: CGPoint(x: floor((leftInset - timerTextSize.width) / 2.0), y: floor((contentHeight - timerTextSize.height) / 2.0)), size: timerTextSize))
@ -909,3 +919,46 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
return super.hitTest(point, with: event)
}
}
private class RecordingIconNode: ASDisplayNode {
private let backgroundNode: ASImageNode
private let dotNode: ASImageNode
override init() {
let iconSize: CGFloat = 24.0
self.backgroundNode = ASImageNode()
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.displayWithoutProcessing = true
self.backgroundNode.image = generateCircleImage(diameter: iconSize, lineWidth: 1.0 + UIScreenPixel, color: UIColor.white, backgroundColor: nil)
self.dotNode = ASImageNode()
self.dotNode.displaysAsynchronously = false
self.dotNode.displayWithoutProcessing = true
self.dotNode.image = generateFilledCircleImage(diameter: 12.0, color: UIColor(rgb: 0xff3b30))
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.dotNode)
}
override func didLoad() {
super.didLoad()
let animation = CAKeyframeAnimation(keyPath: "opacity")
animation.values = [1.0 as NSNumber, 1.0 as NSNumber, 0.0 as NSNumber]
animation.keyTimes = [0.0 as NSNumber, 0.4546 as NSNumber, 0.9091 as NSNumber, 1 as NSNumber]
animation.duration = 0.5
animation.autoreverses = true
animation.repeatCount = Float.infinity
self.dotNode.layer.add(animation, forKey: "recording")
}
override func layout() {
super.layout()
self.backgroundNode.frame = self.bounds
let dotSize = CGSize(width: 12.0, height: 12.0)
self.dotNode.frame = CGRect(origin: CGPoint(x: (self.bounds.width - dotSize.width) / 2.0, y: (self.bounds.height - dotSize.height) / 2.0), size: dotSize)
}
}