Various improvements

This commit is contained in:
Ilya Laktyushin 2025-05-25 22:36:50 +02:00
parent 7b5883c115
commit 4e804bf9d9
13 changed files with 201 additions and 16 deletions

View File

@ -14338,3 +14338,6 @@ Sorry for the inconvenience.";
"Gift.Buy.ErrorTooEarly.Title" = "Try Later";
"Gift.Buy.ErrorTooEarly.Text" = "You will be able to buy this gift on %@.";
"Chat.PauseVoiceMessageTooltip" = "Pause to trim or replay.";
"Chat.PauseVideoMessageTooltip" = "Pause to trim or replay.";

View File

@ -1265,6 +1265,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
}, openMessagePayment: {
}, openBoostToUnrestrict: {
}, updateRecordingTrimRange: { _, _, _, _ in
}, dismissAllTooltips: {
}, updateHistoryFilter: { _ in
}, updateChatLocationThread: { _, _ in
}, toggleChatSidebarMode: {

View File

@ -109,7 +109,7 @@ final class CameraOutput: NSObject {
private var videoConnection: AVCaptureConnection?
private var previewConnection: AVCaptureConnection?
private var roundVideoFilter: CameraRoundVideoFilter?
private var roundVideoFilter: CameraRoundLegacyVideoFilter?
private let semaphore = DispatchSemaphore(value: 1)
private let videoQueue = DispatchQueue(label: "", qos: .userInitiated)
@ -577,11 +577,11 @@ final class CameraOutput: NSObject {
return nil
}
let filter: CameraRoundVideoFilter
let filter: CameraRoundLegacyVideoFilter
if let current = self.roundVideoFilter {
filter = current
} else {
filter = CameraRoundVideoFilter(ciContext: self.ciContext, colorSpace: self.colorSpace, simple: self.exclusive)
filter = CameraRoundLegacyVideoFilter(ciContext: self.ciContext, colorSpace: self.colorSpace, simple: self.exclusive)
self.roundVideoFilter = filter
}
if !filter.isPrepared {

View File

@ -176,6 +176,7 @@ public final class ChatPanelInterfaceInteraction {
public let updateDisplayHistoryFilterAsList: (Bool) -> Void
public let openBoostToUnrestrict: () -> Void
public let updateRecordingTrimRange: (Double, Double, Bool, Bool) -> Void
public let dismissAllTooltips: () -> Void
public let requestLayout: (ContainedViewLayoutTransition) -> Void
public let chatController: () -> ViewController?
public let statuses: ChatPanelInterfaceInteractionStatuses?
@ -291,6 +292,7 @@ public final class ChatPanelInterfaceInteraction {
openMessagePayment: @escaping () -> Void,
openBoostToUnrestrict: @escaping () -> Void,
updateRecordingTrimRange: @escaping (Double, Double, Bool, Bool) -> Void,
dismissAllTooltips: @escaping () -> Void,
updateHistoryFilter: @escaping ((ChatPresentationInterfaceState.HistoryFilter?) -> ChatPresentationInterfaceState.HistoryFilter?) -> Void,
updateChatLocationThread: @escaping (Int64?, ChatControllerAnimateInnerChatSwitchDirection?) -> Void,
toggleChatSidebarMode: @escaping () -> Void,
@ -409,6 +411,7 @@ public final class ChatPanelInterfaceInteraction {
self.openMessagePayment = openMessagePayment
self.openBoostToUnrestrict = openBoostToUnrestrict
self.updateRecordingTrimRange = updateRecordingTrimRange
self.dismissAllTooltips = dismissAllTooltips
self.updateHistoryFilter = updateHistoryFilter
self.updateChatLocationThread = updateChatLocationThread
self.toggleChatSidebarMode = toggleChatSidebarMode
@ -536,6 +539,7 @@ public final class ChatPanelInterfaceInteraction {
}, openMessagePayment: {
}, openBoostToUnrestrict: {
}, updateRecordingTrimRange: { _, _, _, _ in
}, dismissAllTooltips: {
}, updateHistoryFilter: { _ in
}, updateChatLocationThread: { _, _ in
}, toggleChatSidebarMode: {

View File

@ -204,6 +204,8 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case starGiftWearTips = 77
case channelSuggestTooltip = 78
case multipleStoriesTooltip = 79
case voiceMessagesPauseSuggestion = 80
case videoMessagesPauseSuggestion = 81
var key: ValueBoxKey {
let v = ValueBoxKey(length: 4)
@ -569,6 +571,14 @@ private struct ApplicationSpecificNoticeKeys {
static func multipleStoriesTooltip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.multipleStoriesTooltip.key)
}
static func voiceMessagesPauseSuggestion() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.voiceMessagesPauseSuggestion.key)
}
static func videoMessagesPauseSuggestion() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.videoMessagesPauseSuggestion.key)
}
}
public struct ApplicationSpecificNotice {
@ -2458,4 +2468,58 @@ public struct ApplicationSpecificNotice {
return Int(previousValue)
}
}
public static func getVoiceMessagesPauseSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
return accountManager.transaction { transaction -> Int32 in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.voiceMessagesPauseSuggestion())?.get(ApplicationSpecificCounterNotice.self) {
return value.value
} else {
return 0
}
}
}
public static func incrementVoiceMessagesPauseSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
return accountManager.transaction { transaction -> Int in
var currentValue: Int32 = 0
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.voiceMessagesPauseSuggestion())?.get(ApplicationSpecificCounterNotice.self) {
currentValue = value.value
}
let previousValue = currentValue
currentValue += Int32(count)
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
transaction.setNotice(ApplicationSpecificNoticeKeys.voiceMessagesPauseSuggestion(), entry)
}
return Int(previousValue)
}
}
public static func getVideoMessagesPauseSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
return accountManager.transaction { transaction -> Int32 in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.videoMessagesPauseSuggestion())?.get(ApplicationSpecificCounterNotice.self) {
return value.value
} else {
return 0
}
}
}
public static func incrementVideoMessagesPauseSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
return accountManager.transaction { transaction -> Int in
var currentValue: Int32 = 0
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.videoMessagesPauseSuggestion())?.get(ApplicationSpecificCounterNotice.self) {
currentValue = value.value
}
let previousValue = currentValue
currentValue += Int32(count)
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
transaction.setNotice(ApplicationSpecificNoticeKeys.videoMessagesPauseSuggestion(), entry)
}
return Int(previousValue)
}
}
}

View File

@ -169,6 +169,7 @@ public final class ChatRecentActionsController: TelegramBaseController {
}, openMessagePayment: {
}, openBoostToUnrestrict: {
}, updateRecordingTrimRange: { _, _, _, _ in
}, dismissAllTooltips: {
}, updateHistoryFilter: { _ in
}, updateChatLocationThread: { _, _ in
}, toggleChatSidebarMode: {

View File

@ -434,6 +434,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
}, openMessagePayment: {
}, openBoostToUnrestrict: {
}, updateRecordingTrimRange: { _, _, _, _ in
}, dismissAllTooltips: {
}, updateHistoryFilter: { _ in
}, updateChatLocationThread: { _, _ in
}, toggleChatSidebarMode: {

View File

@ -783,6 +783,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}, openMessagePayment: {
}, openBoostToUnrestrict: {
}, updateRecordingTrimRange: { _, _, _, _ in
}, dismissAllTooltips: {
}, updateHistoryFilter: { _ in
}, updateChatLocationThread: { _, _ in
}, toggleChatSidebarMode: {

View File

@ -1199,6 +1199,8 @@ public class VideoMessageCameraScreen: ViewController {
self.currentLiveUploadData = nil
}
let _ = ApplicationSpecificNotice.incrementVideoMessagesPauseSuggestion(accountManager: self.context.sharedContext.accountManager, count: 3).startStandalone()
self.pauseCameraCapture()
self.results.append(result)
@ -1251,22 +1253,35 @@ public class VideoMessageCameraScreen: ViewController {
return result
}
fileprivate func maybePresentViewOnceTooltip() {
fileprivate func maybePresentTooltips() {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let _ = (ApplicationSpecificNotice.getVideoMessagesPlayOnceSuggestion(accountManager: context.sharedContext.accountManager)
|> deliverOnMainQueue).startStandalone(next: { [weak self] counter in
let _ = (ApplicationSpecificNotice.getVideoMessagesPauseSuggestion(accountManager: self.context.sharedContext.accountManager)
|> deliverOnMainQueue).startStandalone(next: { [weak self] pauseCounter in
guard let self else {
return
}
if counter >= 3 {
return
if pauseCounter >= 3 {
let _ = (ApplicationSpecificNotice.getVideoMessagesPlayOnceSuggestion(accountManager: self.context.sharedContext.accountManager)
|> deliverOnMainQueue).startStandalone(next: { [weak self] counter in
guard let self else {
return
}
if counter >= 3 {
return
}
Queue.mainQueue().after(0.3) {
self.displayViewOnceTooltip(text: presentationData.strings.Chat_TapToPlayVideoMessageOnceTooltip, hasIcon: true)
}
let _ = ApplicationSpecificNotice.incrementVideoMessagesPlayOnceSuggestion(accountManager: self.context.sharedContext.accountManager).startStandalone()
})
} else {
Queue.mainQueue().after(0.3) {
self.displayPauseTooltip(text: presentationData.strings.Chat_PauseVideoMessageTooltip)
}
let _ = ApplicationSpecificNotice.incrementVideoMessagesPauseSuggestion(accountManager: self.context.sharedContext.accountManager).startStandalone()
}
Queue.mainQueue().after(0.3) {
self.displayViewOnceTooltip(text: presentationData.strings.Chat_TapToPlayVideoMessageOnceTooltip, hasIcon: true)
}
let _ = ApplicationSpecificNotice.incrementVideoMessagesPlayOnceSuggestion(accountManager: self.context.sharedContext.accountManager).startStandalone()
})
}
@ -1299,6 +1314,36 @@ public class VideoMessageCameraScreen: ViewController {
)
controller.present(tooltipController, in: .window(.root))
}
private func displayPauseTooltip(text: String) {
guard let controller = self.controller, let sourceView = self.componentHost.findTaggedView(tag: viewOnceButtonTag) else {
return
}
self.dismissAllTooltips()
let absoluteFrame = sourceView.convert(sourceView.bounds, to: self.view)
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX - 20.0, y: absoluteFrame.midY + 53.0), size: CGSize())
let tooltipController = TooltipScreen(
account: context.account,
sharedContext: context.sharedContext,
text: .markdown(text: text),
balancedTextLayout: true,
constrainWidth: 240.0,
style: .customBlur(UIColor(rgb: 0x18181a), 0.0),
arrowStyle: .small,
icon: nil,
location: .point(location, .right),
displayDuration: .default,
inset: 8.0,
cornerRadius: 8.0,
shouldDismissOnTouch: { _, _ in
return .ignore
}
)
controller.present(tooltipController, in: .window(.root))
}
fileprivate func dismissAllTooltips() {
guard let controller = self.controller else {
@ -1934,7 +1979,7 @@ public class VideoMessageCameraScreen: ViewController {
self.updateCameraState({ $0.updatedRecording(.handsFree) }, transition: .spring(duration: 0.4))
}
self.node.maybePresentViewOnceTooltip()
self.node.maybePresentTooltips()
}
public func discardVideo() {

View File

@ -4112,6 +4112,11 @@ extension ChatControllerImpl {
return
}
self.updateTrimRange(start: start, end: end, updatedEnd: updatedEnd, apply: apply)
}, dismissAllTooltips: { [weak self] in
guard let self else {
return
}
self.dismissAllTooltips()
}, updateHistoryFilter: { [weak self] update in
guard let self else {
return

View File

@ -276,6 +276,8 @@ extension ChatControllerImpl {
audioRecorderValue.stop()
}
self.dismissAllTooltips()
switch updatedAction {
case .dismiss:
self.recorderDataDisposable.set(nil)
@ -528,7 +530,11 @@ extension ChatControllerImpl {
})
}
self.videoRecorderValue?.lockVideoRecording()
if let _ = self.audioRecorderValue {
self.maybePresentAudioPauseTooltip()
} else if let videoRecorderValue = self.videoRecorderValue {
videoRecorderValue.lockVideoRecording()
}
}
func deleteMediaRecording() {
@ -544,6 +550,56 @@ extension ChatControllerImpl {
$0.updatedInterfaceState { $0.withUpdatedMediaDraftState(nil) }
})
self.updateDownButtonVisibility()
self.dismissAllTooltips()
}
private func maybePresentAudioPauseTooltip() {
let _ = (ApplicationSpecificNotice.getVoiceMessagesPauseSuggestion(accountManager: self.context.sharedContext.accountManager)
|> deliverOnMainQueue).startStandalone(next: { [weak self] pauseCounter in
guard let self else {
return
}
if pauseCounter >= 3 {
return
} else {
Queue.mainQueue().after(0.3) {
self.displayPauseTooltip(text: self.presentationData.strings.Chat_PauseVoiceMessageTooltip)
}
let _ = ApplicationSpecificNotice.incrementVoiceMessagesPauseSuggestion(accountManager: self.context.sharedContext.accountManager).startStandalone()
}
})
}
private func displayPauseTooltip(text: String) {
guard let layout = self.validLayout else {
return
}
self.dismissAllTooltips()
let insets = layout.insets(options: [.input])
let location = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.right - 42.0 - UIScreenPixel, y: layout.size.height - insets.bottom - 122.0), size: CGSize())
let tooltipController = TooltipScreen(
account: self.context.account,
sharedContext: self.context.sharedContext,
text: .markdown(text: text),
balancedTextLayout: true,
constrainWidth: 240.0,
style: .customBlur(UIColor(rgb: 0x18181a), 0.0),
arrowStyle: .small,
icon: nil,
location: .point(location, .right),
displayDuration: .default,
inset: 8.0,
cornerRadius: 8.0,
shouldDismissOnTouch: { _, _ in
return .ignore
}
)
self.present(tooltipController, in: .window(.root))
}
private func withAudioRecorder(_ f: (ManagedAudioRecorder) -> Void) {

View File

@ -9111,6 +9111,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let controller = controller as? QuickShareToastScreen {
controller.dismissWithCommitAction()
}
if let controller = controller as? TooltipScreen, !controller.alwaysVisible {
controller.dismiss()
}
})
self.forEachController({ controller in
if let controller = controller as? UndoOverlayController {

View File

@ -2924,6 +2924,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
self.tooltipController?.dismiss()
if self.viewOnce {
self.interfaceInteraction?.dismissAllTooltips()
self.displayViewOnceTooltip(text: interfaceState.strings.Chat_PlayVoiceMessageOnceTooltip)
let _ = ApplicationSpecificNotice.incrementVoiceMessagesPlayOnceSuggestion(accountManager: context.sharedContext.accountManager, count: 3).startStandalone()