mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
e31628c054
commit
cc60d82515
@ -13290,5 +13290,10 @@ Sorry for the inconvenience.";
|
|||||||
"MediaGallery.ToastVideoPip.Title" = "Video Minimized";
|
"MediaGallery.ToastVideoPip.Title" = "Video Minimized";
|
||||||
"MediaGallery.ToastVideoPip.Text" = "Swipe down on a video to close it.";
|
"MediaGallery.ToastVideoPip.Text" = "Swipe down on a video to close it.";
|
||||||
|
|
||||||
"Chat.ToastSubscribedToScheduledLiveStream.Text" = "You will be notified when the liver stream starts.";
|
"Chat.ToastSubscribedToScheduledLiveStream.Text" = "You will be notified when the live stream starts.";
|
||||||
"Chat.TitleVideochatPanel.NotifyScheduledButton" = "Notify Me";
|
"Chat.TitleVideochatPanel.NotifyScheduledButton" = "Notify Me";
|
||||||
|
|
||||||
|
"WebApp.ShareMessage.Title" = "Share Message";
|
||||||
|
"WebApp.ShareMessage.PreviewTitle" = "MESSAGE PREVIEW";
|
||||||
|
"WebApp.ShareMessage.Info" = "%@ mini app suggests you to send this message to a chat you select.";
|
||||||
|
"WebApp.ShareMessage.Share" = "Share With...";
|
||||||
|
@ -2,24 +2,39 @@ import Foundation
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
|
||||||
final class FileDownload: NSObject, URLSessionDownloadDelegate {
|
final class FileDownload: NSObject, URLSessionDownloadDelegate {
|
||||||
private let fileSize: Int64?
|
let fileName: String
|
||||||
|
let fileSize: Int64?
|
||||||
|
let isMedia: Bool
|
||||||
|
|
||||||
private var urlSession: URLSession!
|
private var urlSession: URLSession!
|
||||||
private var completion: ((URL?, Error?) -> Void)?
|
private var completion: ((URL?, Error?) -> Void)?
|
||||||
private var progressHandler: ((Double) -> Void)?
|
private var progressHandler: ((Double) -> Void)?
|
||||||
|
private var task: URLSessionDownloadTask!
|
||||||
|
|
||||||
init(from url: URL, fileSize: Int64?, progressHandler: @escaping (Double) -> Void, completion: @escaping (URL?, Error?) -> Void) {
|
private let progressPromise = ValuePromise<Double>(0.0)
|
||||||
self.progressHandler = progressHandler
|
var progressSignal: Signal<Double, NoError> {
|
||||||
|
return self.progressPromise.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(from url: URL, fileName: String, fileSize: Int64?, isMedia: Bool, progressHandler: @escaping (Double) -> Void, completion: @escaping (URL?, Error?) -> Void) {
|
||||||
|
self.fileName = fileName
|
||||||
self.fileSize = fileSize
|
self.fileSize = fileSize
|
||||||
|
self.isMedia = isMedia
|
||||||
self.completion = completion
|
self.completion = completion
|
||||||
|
self.progressHandler = progressHandler
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
let configuration = URLSessionConfiguration.default
|
let configuration = URLSessionConfiguration.default
|
||||||
urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
|
self.urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
|
||||||
|
|
||||||
let downloadTask = self.urlSession.downloadTask(with: url)
|
let downloadTask = self.urlSession.downloadTask(with: url)
|
||||||
downloadTask.resume()
|
downloadTask.resume()
|
||||||
|
self.task = downloadTask
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancel() {
|
||||||
|
self.task.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
|
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
|
||||||
@ -27,17 +42,18 @@ final class FileDownload: NSObject, URLSessionDownloadDelegate {
|
|||||||
if totalBytesExpectedToWrite == -1, let fileSize = self.fileSize {
|
if totalBytesExpectedToWrite == -1, let fileSize = self.fileSize {
|
||||||
totalBytesExpectedToWrite = fileSize
|
totalBytesExpectedToWrite = fileSize
|
||||||
}
|
}
|
||||||
let progress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
|
let progress = max(0.0, min(1.0, Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)))
|
||||||
progressHandler?(progress)
|
self.progressHandler?(progress)
|
||||||
|
self.progressPromise.set(progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
|
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
|
||||||
completion?(location, nil)
|
self.completion?(location, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
|
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
|
||||||
if let error = error {
|
if let error = error {
|
||||||
completion?(nil, error)
|
self.completion?(nil, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +145,8 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
public var isContainerPanning: () -> Bool = { return false }
|
public var isContainerPanning: () -> Bool = { return false }
|
||||||
public var isContainerExpanded: () -> Bool = { return false }
|
public var isContainerExpanded: () -> Bool = { return false }
|
||||||
|
|
||||||
|
static var activeDownloads: [FileDownload] = []
|
||||||
|
|
||||||
fileprivate class Node: ViewControllerTracingNode, WKNavigationDelegate, WKUIDelegate, ASScrollViewDelegate {
|
fileprivate class Node: ViewControllerTracingNode, WKNavigationDelegate, WKUIDelegate, ASScrollViewDelegate {
|
||||||
private weak var controller: WebAppController?
|
private weak var controller: WebAppController?
|
||||||
|
|
||||||
@ -2403,17 +2405,19 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private var fileDownload: FileDownload?
|
fileprivate weak var fileDownloadTooltip: UndoOverlayController?
|
||||||
private weak var fileDownloadTooltip: UndoOverlayController?
|
|
||||||
fileprivate func startDownload(url: String, fileName: String, fileSize: Int64?, isMedia: Bool) {
|
fileprivate func startDownload(url: String, fileName: String, fileSize: Int64?, isMedia: Bool) {
|
||||||
guard let controller = self.controller else {
|
guard let controller = self.controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.webView?.sendEvent(name: "file_download_requested", data: "{status: \"downloading\"}")
|
self.webView?.sendEvent(name: "file_download_requested", data: "{status: \"downloading\"}")
|
||||||
|
|
||||||
self.fileDownload = FileDownload(
|
var removeImpl: (() -> Void)?
|
||||||
|
let fileDownload = FileDownload(
|
||||||
from: URL(string: url)!,
|
from: URL(string: url)!,
|
||||||
|
fileName: fileName,
|
||||||
fileSize: fileSize,
|
fileSize: fileSize,
|
||||||
|
isMedia: isMedia,
|
||||||
progressHandler: { [weak self] progress in
|
progressHandler: { [weak self] progress in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -2435,6 +2439,8 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
},
|
},
|
||||||
completion: { [weak self] resultUrl, _ in
|
completion: { [weak self] resultUrl, _ in
|
||||||
if let resultUrl, let self {
|
if let resultUrl, let self {
|
||||||
|
removeImpl?()
|
||||||
|
|
||||||
let tooltipContent: UndoOverlayContent = .actionSucceeded(title: fileName, text: isMedia ? self.presentationData.strings.WebApp_Download_SavedToPhotos : self.presentationData.strings.WebApp_Download_SavedToFiles, cancel: nil, destructive: false)
|
let tooltipContent: UndoOverlayContent = .actionSucceeded(title: fileName, text: isMedia ? self.presentationData.strings.WebApp_Download_SavedToPhotos : self.presentationData.strings.WebApp_Download_SavedToFiles, cancel: nil, destructive: false)
|
||||||
if isMedia {
|
if isMedia {
|
||||||
let saveToPhotos: (URL, Bool) -> Void = { url, isVideo in
|
let saveToPhotos: (URL, Bool) -> Void = { url, isVideo in
|
||||||
@ -2499,6 +2505,13 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
WebAppController.activeDownloads.append(fileDownload)
|
||||||
|
|
||||||
|
removeImpl = { [weak fileDownload] in
|
||||||
|
if let fileDownload {
|
||||||
|
WebAppController.activeDownloads.removeAll(where: { $0 === fileDownload })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let text: String
|
let text: String
|
||||||
if let fileSize {
|
if let fileSize {
|
||||||
@ -2517,7 +2530,11 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
),
|
),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
position: .top,
|
position: .top,
|
||||||
action: { _ in
|
action: { [weak fileDownload] action in
|
||||||
|
if case .undo = action, let fileDownload {
|
||||||
|
fileDownload.cancel()
|
||||||
|
removeImpl?()
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -3075,18 +3092,55 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
let hasSettings = self.hasSettings
|
let hasSettings = self.hasSettings
|
||||||
|
|
||||||
|
let activeDownload = WebAppController.activeDownloads.first
|
||||||
|
let activeDownloadProgress: Signal<Double?, NoError>
|
||||||
|
if let activeDownload {
|
||||||
|
activeDownloadProgress = activeDownload.progressSignal
|
||||||
|
|> map(Optional.init)
|
||||||
|
|> mapToThrottled { next -> Signal<Double?, NoError> in
|
||||||
|
return .single(next) |> then(.complete() |> delay(0.2, queue: Queue.mainQueue()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
activeDownloadProgress = .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
let items = combineLatest(queue: Queue.mainQueue(),
|
let items = combineLatest(queue: Queue.mainQueue(),
|
||||||
context.engine.messages.attachMenuBots(),
|
context.engine.messages.attachMenuBots() |> take(1),
|
||||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.botId)),
|
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.botId)),
|
||||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotCommands(id: self.botId)),
|
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotCommands(id: self.botId)),
|
||||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotPrivacyPolicyUrl(id: self.botId))
|
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotPrivacyPolicyUrl(id: self.botId)),
|
||||||
|
activeDownloadProgress
|
||||||
)
|
)
|
||||||
|> take(1)
|
|> map { [weak self] attachMenuBots, botPeer, botCommands, privacyPolicyUrl, activeDownloadProgress -> ContextController.Items in
|
||||||
|> map { [weak self] attachMenuBots, botPeer, botCommands, privacyPolicyUrl -> ContextController.Items in
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
|
|
||||||
let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId && !$0.flags.contains(.notActivated) })
|
if let activeDownload, let progress = activeDownloadProgress {
|
||||||
|
let isActive = progress < 1.0 - .ulpOfOne
|
||||||
|
let progressString: String
|
||||||
|
if isActive {
|
||||||
|
if let fileSize = activeDownload.fileSize {
|
||||||
|
let downloadedSize = Int64(Double(fileSize) * progress)
|
||||||
|
progressString = "\(dataSizeString(downloadedSize, formatting: DataSizeStringFormatting(presentationData: presentationData))) / \(dataSizeString(fileSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))"
|
||||||
|
} else {
|
||||||
|
progressString = "\(Int32(progress))%"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
progressString = activeDownload.isMedia ? presentationData.strings.WebApp_Download_SavedToPhotos : presentationData.strings.WebApp_Download_SavedToFiles
|
||||||
|
}
|
||||||
|
items.append(.action(ContextMenuActionItem(text: activeDownload.fileName, textLayout: .secondLineWithValue(progressString), icon: { theme in return isActive ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.primaryColor) : nil }, iconPosition: .right, action: isActive ? { [weak self, weak activeDownload] _, f in
|
||||||
|
f(.default)
|
||||||
|
|
||||||
|
WebAppController.activeDownloads.removeAll(where: { $0 === activeDownload })
|
||||||
|
activeDownload?.cancel()
|
||||||
|
|
||||||
|
if let fileDownloadTooltip = self?.controllerNode.fileDownloadTooltip {
|
||||||
|
fileDownloadTooltip.dismissWithCommitAction()
|
||||||
|
}
|
||||||
|
} : nil)))
|
||||||
|
items.append(.separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId && !$0.flags.contains(.notActivated) })
|
||||||
if hasSettings {
|
if hasSettings {
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_Settings, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_Settings, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor)
|
||||||
|
@ -76,7 +76,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
|
|
||||||
let closeButton = closeButton.update(
|
let closeButton = closeButton.update(
|
||||||
component: Button(
|
component: Button(
|
||||||
content: AnyComponent(Text(text: "Cancel", font: Font.regular(17.0), color: theme.actionSheet.controlAccentColor)),
|
content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: theme.actionSheet.controlAccentColor)),
|
||||||
action: {
|
action: {
|
||||||
component.dismiss()
|
component.dismiss()
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
|
|
||||||
let title = title.update(
|
let title = title.update(
|
||||||
component: Text(text: "Share Message", font: Font.bold(17.0), color: theme.list.itemPrimaryTextColor),
|
component: Text(text: environment.strings.WebApp_ShareMessage_Title, font: Font.bold(17.0), color: theme.list.itemPrimaryTextColor),
|
||||||
availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height),
|
availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
@ -105,7 +105,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
return (TelegramTextAttributes.URL, contents)
|
return (TelegramTextAttributes.URL, contents)
|
||||||
})
|
})
|
||||||
|
|
||||||
let amountInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("\(component.botName) mini app suggests you to send this message to a chat you select.", attributes: amountMarkdownAttributes, textAlignment: .natural))
|
let amountInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.WebApp_ShareMessage_Info(component.botName).string, attributes: amountMarkdownAttributes, textAlignment: .natural))
|
||||||
let amountFooter = AnyComponent(MultilineTextComponent(
|
let amountFooter = AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(amountInfoString),
|
text: .plain(amountInfoString),
|
||||||
maximumNumberOfLines: 0,
|
maximumNumberOfLines: 0,
|
||||||
@ -192,7 +192,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
theme: theme,
|
theme: theme,
|
||||||
header: AnyComponent(MultilineTextComponent(
|
header: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: "Message Preview".uppercased(),
|
string: environment.strings.WebApp_ShareMessage_PreviewTitle.uppercased(),
|
||||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||||
textColor: theme.list.freeTextColor
|
textColor: theme.list.freeTextColor
|
||||||
)),
|
)),
|
||||||
@ -230,7 +230,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
contentSize.height += amountSection.size.height
|
contentSize.height += amountSection.size.height
|
||||||
contentSize.height += 32.0
|
contentSize.height += 32.0
|
||||||
|
|
||||||
let buttonString: String = "Share With..."
|
let buttonString: String = environment.strings.WebApp_ShareMessage_Share
|
||||||
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||||
|
|
||||||
let button = button.update(
|
let button = button.update(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user