Various Improvements

This commit is contained in:
Ilya Laktyushin 2021-03-15 16:14:52 +04:00
parent 64b80e92b4
commit 666b076867
13 changed files with 3191 additions and 3119 deletions

View File

@ -6257,7 +6257,8 @@ Sorry for the inconvenience.";
"VoiceChat.MutedByAdmin" = "Muted by Admin";
"VoiceChat.MutedByAdminHelp" = "Tap if you want to speak";
"Invitation.JoinVoiceChat" = "Join Voice Chat";
"Invitation.JoinVoiceChatAsSpeaker" = "Join as Speaker";
"Invitation.JoinVoiceChatAsListener" = "Join as Listener";
"VoiceChat.CancelSpeakRequest" = "Cancel Request to Speak";
@ -6281,3 +6282,8 @@ Sorry for the inconvenience.";
"Conversation.StickerRemovedFromFavorites" = "Sticker was removed from Favorites";
"Conversation.DeletedFromContacts" = "**%@** deleted from your contacts";
"Conversation.VoiceChat" = "Voice Chat";
"Conversation.JoinVoiceChatAsSpeaker" = "JOIN AS SPEAKER";
"Conversation.JoinVoiceChatAsListener" = "JOIN AS LISTENER";

View File

@ -136,6 +136,8 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
bool _shutterIsBusy;
UIImpactFeedbackGenerator *_feedbackGenerator;
NSMutableSet *_previousQRCodes;
}
@end
@ -172,6 +174,10 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
_saveCapturedMedia = saveCapturedMedia;
_previousQRCodes = [[NSMutableSet alloc] init];
if (iosMajorVersion() >= 10) {
_feedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
}
}
return self;
}
@ -905,6 +911,12 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
- (void)shutterPressed
{
if (iosMajorVersion() >= 13.0) {
[_feedbackGenerator impactOccurredWithIntensity:0.5];
} else {
[_feedbackGenerator impactOccurred];
}
PGCameraMode cameraMode = _camera.cameraMode;
switch (cameraMode)
{
@ -939,6 +951,12 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
- (void)shutterReleased
{
if (iosMajorVersion() >= 13.0) {
[_feedbackGenerator impactOccurredWithIntensity:0.6];
} else {
[_feedbackGenerator impactOccurred];
}
[_switchToVideoTimer invalidate];
_switchToVideoTimer = nil;

View File

@ -60,7 +60,8 @@ public func paragraphStyleWithAlignment(_ alignment: NSTextAlignment) -> NSParag
public func parseMarkdownIntoAttributedString(_ string: String, attributes: MarkdownAttributes, textAlignment: NSTextAlignment = .natural) -> NSAttributedString {
let nsString = string as NSString
let result = NSMutableAttributedString()
var remainingRange = NSMakeRange(0, nsString.length)
let wholeRange = NSMakeRange(0, nsString.length)
var remainingRange = wholeRange
var bodyAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: attributes.body.font, NSAttributedString.Key.foregroundColor: attributes.body.textColor, NSAttributedString.Key.paragraphStyle: paragraphStyleWithAlignment(textAlignment)]
if !attributes.body.additionalAttributes.isEmpty {
@ -93,7 +94,7 @@ public func parseMarkdownIntoAttributedString(_ string: String, attributes: Mark
result.append(NSAttributedString(string: parsedLinkText, attributes: linkAttributes))
}
} else if character == UInt16(("*" as UnicodeScalar).value) {
if range.location + 1 != remainingRange.length {
if range.location + 1 != wholeRange.length {
let nextCharacter = nsString.character(at: range.location + 1)
if nextCharacter == character {
remainingRange = NSMakeRange(range.location + range.length + 1, remainingRange.location + remainingRange.length - (range.location + range.length + 1))

View File

@ -773,9 +773,9 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
private var animating = false
public func animateTo(_ timestamp: Double) {
self.animateToValue = timestamp
ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut).animateView({
UIView.animate(withDuration: 0.2, delay: 0.0, options: [.curveEaseInOut, .allowAnimatedContent, .layoutSubviews], animations: {
self.updateProgress()
}, completion: { finished in
}, completion: { _ in
self.animateToValue = nil
self.animating = false
})
@ -804,11 +804,11 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
}
}
if let animateToValue = animateToValue {
if animating {
if let animateToValue = self.animateToValue {
if self.animating {
return
} else if let (_, duration) = timestampAndDuration {
animating = true
self.animating = true
timestampAndDuration = (animateToValue, duration)
}
}
@ -823,6 +823,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
node.foregroundContentNode.position = foregroundContentFrame.center
node.foregroundContentNode.bounds = CGRect(origin: CGPoint(), size: foregroundContentFrame.size)
node.bufferingNode.frame = backgroundFrame
node.bufferingNode.updateLayout(size: backgroundFrame.size, transition: .immediate)
@ -872,19 +873,28 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
handleNodeContainer.isHidden = false
}
} else if let statusValue = self.statusValue {
let actualTimestamp: Double
if statusValue.generationTimestamp.isZero || !isPlaying {
var actualTimestamp: Double
if statusValue.generationTimestamp.isZero || !isPlaying || self.animateToValue != nil {
actualTimestamp = timestamp
} else {
let currentTimestamp = CACurrentMediaTime()
actualTimestamp = timestamp + (currentTimestamp - statusValue.generationTimestamp) * statusValue.baseRate
}
var progress = CGFloat(actualTimestamp / duration)
if progress.isNaN || !progress.isFinite {
progress = 0.0
}
progress = min(1.0, progress)
node.foregroundNode.frame = CGRect(origin: backgroundFrame.origin, size: CGSize(width: floorToScreenPixels(progress * backgroundFrame.size.width), height: backgroundFrame.size.height))
let foregroundFrame = CGRect(origin: backgroundFrame.origin, size: CGSize(width: floorToScreenPixels(progress * backgroundFrame.size.width), height: backgroundFrame.size.height))
if let _ = self.animateToValue {
let previousFrame = node.foregroundNode.frame
node.foregroundNode.frame = foregroundFrame
node.foregroundNode.layer.animateFrame(from: previousFrame, to: foregroundFrame, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
} else {
node.foregroundNode.frame = foregroundFrame
}
if let handleNodeContainer = node.handleNodeContainer {
handleNodeContainer.bounds = bounds.offsetBy(dx: -floorToScreenPixels(bounds.size.width * progress), dy: 0.0)

View File

@ -594,6 +594,13 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
self.animateOut(shared: true, completion: {
})
self.completed?(peerIds)
Queue.mainQueue().after(0.15) {
if self.hapticFeedback == nil {
self.hapticFeedback = HapticFeedback()
}
self.hapticFeedback?.success()
}
}
let fromForeignApp = self.fromForeignApp
self.shareDisposable.set((signal

View File

@ -260,10 +260,13 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.joinButtonTitleNode.attributedText = NSAttributedString(string: presentationData.strings.VoiceChat_PanelJoin.uppercased(), font: Font.semibold(15.0), textColor: presentationData.theme.chat.inputPanel.actionControlForegroundColor)
self.joinButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: presentationData.theme.chat.inputPanel.actionControlFillColor)
self.titleNode.attributedText = NSAttributedString(string: presentationData.strings.VoiceChat_Title, font: Font.semibold(15.0), textColor: presentationData.theme.chat.inputPanel.primaryTextColor)
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: presentationData.theme.chat.inputPanel.secondaryTextColor)
self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(presentationData.theme)
if let (size, leftInset, rightInset) = self.validLayout {
self.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
}
}
private func animateTextChange() {
@ -498,7 +501,14 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
}
}
let titleSize = self.titleNode.updateLayout(CGSize(width: size.width, height: .greatestFiniteMagnitude))
var title = self.strings.VoiceChat_Title
if let voiceChatTitle = self.currentData?.info.title, voiceChatTitle.count < 15 {
title = voiceChatTitle
}
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(15.0), textColor: self.theme.chat.inputPanel.primaryTextColor)
let titleSize = self.titleNode.updateLayout(CGSize(width: size.width / 2.0 - 56.0, height: .greatestFiniteMagnitude))
let textSize = self.textNode.updateLayout(CGSize(width: size.width, height: .greatestFiniteMagnitude))
let titleFrame = CGRect(origin: CGPoint(x: leftInset + 16.0, y: 9.0), size: titleSize)

View File

@ -118,7 +118,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
}
return GroupCallPanelData(
peerId: peerId,
info: GroupCallInfo(id: call.id, accessHash: call.accessHash, participantCount: state.totalCount, clientParams: nil, streamDcId: nil, title: nil, recordingStartTimestamp: nil),
info: GroupCallInfo(id: call.id, accessHash: call.accessHash, participantCount: state.totalCount, clientParams: nil, streamDcId: nil, title: state.title, recordingStartTimestamp: nil),
topParticipants: topParticipants,
participantCount: state.totalCount,
activeSpeakers: activeSpeakers,

View File

@ -2157,8 +2157,12 @@ public final class VoiceChatController: ViewController {
self.hapticFeedback.impact(.light)
case .ended, .cancelled:
self.actionButton.pressing = false
self.call.raiseHand()
self.actionButton.playAnimation()
let location = gestureRecognizer.location(in: self.actionButton.view)
if self.actionButton.hitTest(location, with: nil) != nil {
self.call.raiseHand()
self.actionButton.playAnimation()
}
default:
break
}

View File

@ -55,7 +55,7 @@ public final class VoiceChatJoinScreen: ViewController {
override public func loadDisplayNode() {
self.displayNode = Node(context: self.context, requestLayout: { [weak self] transition in
self?.requestLayout(transition: transition)
})
}, asSpeaker: self.invite != nil)
self.controllerNode.dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
@ -187,6 +187,7 @@ public final class VoiceChatJoinScreen: ViewController {
class Node: ViewControllerTracingNode, UIScrollViewDelegate {
private let context: AccountContext
private var presentationData: PresentationData
private let asSpeaker: Bool
private var call: CachedChannelData.ActiveCall?
@ -222,10 +223,10 @@ public final class VoiceChatJoinScreen: ViewController {
private let disposable = MetaDisposable()
init(context: AccountContext, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void) {
init(context: AccountContext, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, asSpeaker: Bool) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.asSpeaker = asSpeaker
self.requestLayout = requestLayout
let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
@ -633,7 +634,7 @@ public final class VoiceChatJoinScreen: ViewController {
transition.updateAlpha(node: self.actionsBackgroundNode, alpha: 1.0)
self.actionButtonNode.isEnabled = true
self.actionButtonNode.setTitle(self.presentationData.strings.Invitation_JoinVoiceChat, with: Font.medium(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal)
self.actionButtonNode.setTitle(self.asSpeaker ? self.presentationData.strings.Invitation_JoinVoiceChatAsSpeaker : self.presentationData.strings.Invitation_JoinVoiceChatAsListener, with: Font.medium(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal)
self.transitionToContentNode(VoiceChatPreviewContentNode(context: self.context, peer: peer, title: title, memberCount: memberCount, theme: self.presentationData.theme, strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder))
}

View File

@ -10519,7 +10519,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongController.dismiss()
} else if peerId == strongSelf.context.account.peerId {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: true, text: messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: true, text: messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] value in
if case .info = value, let strongSelf = self, let navigationController = strongSelf.effectiveNavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(context.account.peerId), keepStack: .always, purposefulAction: {}, peekData: nil))
return true
}
return false
}), in: .current)
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messages.map { message -> EnqueueMessage in
return .forward(source: message.id, grouping: .auto, attributes: [])

View File

@ -280,7 +280,12 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
case "telegram_message":
actionTitle = item.presentationData.strings.Conversation_ViewMessage
case "telegram_voicechat":
actionTitle = item.presentationData.strings.Conversation_JoinVoiceChat
title = item.presentationData.strings.Conversation_VoiceChat
if webpage.url.contains("voicechat=") {
actionTitle = item.presentationData.strings.Conversation_JoinVoiceChatAsSpeaker
} else {
actionTitle = item.presentationData.strings.Conversation_JoinVoiceChatAsListener
}
case "telegram_background":
title = item.presentationData.strings.Conversation_ChatBackground
subtitle = nil