mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Progress update
This commit is contained in:
parent
065150e048
commit
4a2f529941
@ -5916,7 +5916,7 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"ReportPeer.ReasonFake" = "Fake Account";
|
"ReportPeer.ReasonFake" = "Fake Account";
|
||||||
|
|
||||||
"ChatList.HeaderImportIntoAnExistingGroup" = "OR IMPORT INTO AN EXISTING GROUP";
|
"ChatList.HeaderImportIntoAnExistingGroup" = "SELECT A CHAT TO IMPORT MESSAGES TO";
|
||||||
|
|
||||||
"Group.ErrorAdminsTooMuch" = "Sorry, too many administrators in this group.";
|
"Group.ErrorAdminsTooMuch" = "Sorry, too many administrators in this group.";
|
||||||
"Channel.ErrorAdminsTooMuch" = "Sorry, too many administrators in this channel.";
|
"Channel.ErrorAdminsTooMuch" = "Sorry, too many administrators in this channel.";
|
||||||
@ -5948,7 +5948,7 @@ Sorry for the inconvenience.";
|
|||||||
"ChatImport.SelectionConfirmationUserWithTitle" = "Import messages from **%1$@** into the chat with **%2$@**?";
|
"ChatImport.SelectionConfirmationUserWithTitle" = "Import messages from **%1$@** into the chat with **%2$@**?";
|
||||||
"ChatImport.SelectionConfirmationUserWithoutTitle" = "Import messages into the chat with **%@?**";
|
"ChatImport.SelectionConfirmationUserWithoutTitle" = "Import messages into the chat with **%@?**";
|
||||||
|
|
||||||
"PeerSelection.CreateNewGroup" = "Create a New Group";
|
"PeerSelection.ImportIntoNewGroup" = "Import to a New Group";
|
||||||
"Message.ImportedDateFormat" = "%1$@, %2$@ Imported %3$@";
|
"Message.ImportedDateFormat" = "%1$@, %2$@ Imported %3$@";
|
||||||
|
|
||||||
"ChatImportActivity.Title" = "Importing Chat";
|
"ChatImportActivity.Title" = "Importing Chat";
|
||||||
|
@ -18,54 +18,34 @@ import TelegramUniversalVideoContent
|
|||||||
import SolidRoundedButtonNode
|
import SolidRoundedButtonNode
|
||||||
|
|
||||||
private final class ProgressEstimator {
|
private final class ProgressEstimator {
|
||||||
private var samples: [(Double, Float)] = []
|
private var averageProgressPerSecond: Double = 0.0
|
||||||
|
private var lastMeasurement: (Double, Float)?
|
||||||
private var estimatedCompletion: Double?
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func addSample(progress: Float) {
|
func update(progress: Float) -> Double? {
|
||||||
let timestamp = CACurrentMediaTime()
|
let timestamp = CACurrentMediaTime()
|
||||||
|
if let (lastTimestamp, lastProgress) = self.lastMeasurement {
|
||||||
self.samples.append((CACurrentMediaTime(), progress))
|
if abs(lastProgress - progress) >= 0.01 || abs(lastTimestamp - timestamp) > 1.0 {
|
||||||
|
let immediateProgressPerSecond = Double(progress - lastProgress) / (timestamp - lastTimestamp)
|
||||||
self.samples = self.samples.filter({ $0.0 >= timestamp - 3.0 })
|
let alpha: Double = 0.05
|
||||||
|
self.averageProgressPerSecond = alpha * immediateProgressPerSecond + (1.0 - alpha) * self.averageProgressPerSecond
|
||||||
|
self.lastMeasurement = (timestamp, progress)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.lastMeasurement = (timestamp, progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func estimateETA() -> Double? {
|
//print("progress = \(progress)")
|
||||||
if self.samples.count < 2 {
|
//print("averageProgressPerSecond = \(self.averageProgressPerSecond)")
|
||||||
|
|
||||||
|
if self.averageProgressPerSecond < 0.0001 {
|
||||||
return nil
|
return nil
|
||||||
}
|
} else {
|
||||||
|
let remainingProgress = Double(1.0 - progress)
|
||||||
var totalTime: Double = 0.0
|
let remainingTime = remainingProgress / self.averageProgressPerSecond
|
||||||
var totalProgress: Double = 0.0
|
return remainingTime
|
||||||
var lastProgress: Double = 0.0
|
|
||||||
var lastTimestamp: Double = 0.0
|
|
||||||
for i in 1 ..< samples.count {
|
|
||||||
totalTime += samples[i].0 - samples[i - 1].0
|
|
||||||
totalProgress += Double(samples[i].1 - samples[i - 1].1)
|
|
||||||
lastProgress = Double(samples[i].1)
|
|
||||||
lastTimestamp = samples[i].0
|
|
||||||
}
|
|
||||||
|
|
||||||
let remainingProgress = 1.0 - lastProgress
|
|
||||||
let timeOffset = CACurrentMediaTime() - lastTimestamp
|
|
||||||
let remainingTime = remainingProgress * totalTime / totalProgress - timeOffset
|
|
||||||
/*print("remainingProgress = \(remainingProgress)")
|
|
||||||
print("totalTime = \(totalTime)")
|
|
||||||
print("totalProgress = \(totalProgress)")
|
|
||||||
print("ETA = \(remainingProgress * totalTime / totalProgress) - \(timeOffset) = \(remainingTime)")*/
|
|
||||||
return max(0.0, remainingTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
func markEstimatedCompletion() {
|
|
||||||
self.estimatedCompletion = CACurrentMediaTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
func markActualCompletion() {
|
|
||||||
if let estimatedCompletion = self.estimatedCompletion {
|
|
||||||
print("Estimator error: \(CACurrentMediaTime() - estimatedCompletion)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,7 +262,7 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
effectiveProgress = 1.0
|
effectiveProgress = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(effectiveProgress * 100.0))%", font: Font.with(size: 42.0, design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(effectiveProgress * 100.0))%", font: Font.with(size: 36.0, design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||||
let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
||||||
|
|
||||||
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(effectiveProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(effectiveProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||||
@ -305,9 +285,9 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
case .chatAdminRequired:
|
case .chatAdminRequired:
|
||||||
errorText = self.presentationData.strings.ChatImportActivity_ErrorNotAdmin
|
errorText = self.presentationData.strings.ChatImportActivity_ErrorNotAdmin
|
||||||
case .invalidChatType:
|
case .invalidChatType:
|
||||||
errorText = self.presentationData.strings.ChatImportActivity_ErrorGeneric
|
|
||||||
case .generic:
|
|
||||||
errorText = self.presentationData.strings.ChatImportActivity_ErrorInvalidChatType
|
errorText = self.presentationData.strings.ChatImportActivity_ErrorInvalidChatType
|
||||||
|
case .generic:
|
||||||
|
errorText = self.presentationData.strings.ChatImportActivity_ErrorGeneric
|
||||||
}
|
}
|
||||||
self.statusText.attributedText = NSAttributedString(string: errorText, font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemDestructiveColor)
|
self.statusText.attributedText = NSAttributedString(string: errorText, font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemDestructiveColor)
|
||||||
case .done:
|
case .done:
|
||||||
@ -479,6 +459,7 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
private let totalMediaBytes: Int
|
private let totalMediaBytes: Int
|
||||||
|
|
||||||
private var progressEstimator: ProgressEstimator?
|
private var progressEstimator: ProgressEstimator?
|
||||||
|
private var totalMediaProgress: Float = 0.0
|
||||||
private var beganCompletion: Bool = false
|
private var beganCompletion: Bool = false
|
||||||
|
|
||||||
private var pendingEntries: [String: (Int, Float)] = [:]
|
private var pendingEntries: [String: (Int, Float)] = [:]
|
||||||
@ -704,11 +685,7 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
totalMediaProgress = CGFloat(totalDoneMediaBytes) / CGFloat(strongSelf.totalMediaBytes)
|
totalMediaProgress = CGFloat(totalDoneMediaBytes) / CGFloat(strongSelf.totalMediaBytes)
|
||||||
}
|
}
|
||||||
strongSelf.controllerNode.updateState(state: .progress(totalProgress), animated: true)
|
strongSelf.controllerNode.updateState(state: .progress(totalProgress), animated: true)
|
||||||
|
strongSelf.totalMediaProgress = Float(totalMediaProgress)
|
||||||
if let progressEstimator = strongSelf.progressEstimator {
|
|
||||||
progressEstimator.addSample(progress: Float(totalMediaProgress))
|
|
||||||
strongSelf.updateProgressEstimation()
|
|
||||||
}
|
|
||||||
}, error: { [weak self] error in
|
}, error: { [weak self] error in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -728,11 +705,14 @@ public final class ChatImportActivityScreen: ViewController {
|
|||||||
|
|
||||||
fileprivate func updateProgressEstimation() {
|
fileprivate func updateProgressEstimation() {
|
||||||
if !self.beganCompletion, let progressEstimator = self.progressEstimator, let remainingAnimationSeconds = self.controllerNode.remainingAnimationSeconds {
|
if !self.beganCompletion, let progressEstimator = self.progressEstimator, let remainingAnimationSeconds = self.controllerNode.remainingAnimationSeconds {
|
||||||
if let eta = progressEstimator.estimateETA(), eta <= remainingAnimationSeconds + 1.5 {
|
if let remainingSeconds = progressEstimator.update(progress: self.totalMediaProgress) {
|
||||||
|
//print("remainingSeconds: \(remainingSeconds)")
|
||||||
|
//print("remainingAnimationSeconds + 1.0: \(remainingAnimationSeconds + 1.0)")
|
||||||
|
if remainingSeconds <= remainingAnimationSeconds + 1.0 {
|
||||||
self.beganCompletion = true
|
self.beganCompletion = true
|
||||||
progressEstimator.markEstimatedCompletion()
|
|
||||||
self.controllerNode.transitionToDoneAnimation()
|
self.controllerNode.transitionToDoneAnimation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ public class ChatListAdditionalCategoryItem: ItemListItem, ListViewItemWithHeade
|
|||||||
image: UIImage?,
|
image: UIImage?,
|
||||||
appearance: ChatListNodeAdditionalCategory.Appearance,
|
appearance: ChatListNodeAdditionalCategory.Appearance,
|
||||||
isSelected: Bool,
|
isSelected: Bool,
|
||||||
|
header: ListViewItemHeader?,
|
||||||
action: @escaping () -> Void
|
action: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
@ -47,7 +48,7 @@ public class ChatListAdditionalCategoryItem: ItemListItem, ListViewItemWithHeade
|
|||||||
case .option:
|
case .option:
|
||||||
self.header = ChatListSearchItemHeader(type: .chatTypes, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
self.header = ChatListSearchItemHeader(type: .chatTypes, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||||
case .action:
|
case .action:
|
||||||
self.header = nil
|
self.header = header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +166,11 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||||
case let .AdditionalCategory(_, id, title, image, appearance, selected, presentationData):
|
case let .AdditionalCategory(_, id, title, image, appearance, selected, presentationData):
|
||||||
|
var header: ChatListSearchItemHeader?
|
||||||
|
if case .action = appearance {
|
||||||
|
// TODO: hack, generalize
|
||||||
|
header = ChatListSearchItemHeader(type: .orImportIntoAnExistingGroup, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||||
|
}
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
||||||
context: context,
|
context: context,
|
||||||
@ -173,6 +178,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
image: image,
|
image: image,
|
||||||
appearance: appearance,
|
appearance: appearance,
|
||||||
isSelected: selected,
|
isSelected: selected,
|
||||||
|
header: header,
|
||||||
action: {
|
action: {
|
||||||
nodeInteraction.additionalCategorySelected(id)
|
nodeInteraction.additionalCategorySelected(id)
|
||||||
}
|
}
|
||||||
@ -371,6 +377,11 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||||
case let .AdditionalCategory(index: _, id, title, image, appearance, selected, presentationData):
|
case let .AdditionalCategory(index: _, id, title, image, appearance, selected, presentationData):
|
||||||
|
var header: ChatListSearchItemHeader?
|
||||||
|
if case .action = appearance {
|
||||||
|
// TODO: hack, generalize
|
||||||
|
header = ChatListSearchItemHeader(type: .orImportIntoAnExistingGroup, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||||
|
}
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
||||||
context: context,
|
context: context,
|
||||||
@ -378,6 +389,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
image: image,
|
image: image,
|
||||||
appearance: appearance,
|
appearance: appearance,
|
||||||
isSelected: selected,
|
isSelected: selected,
|
||||||
|
header: header,
|
||||||
action: {
|
action: {
|
||||||
nodeInteraction.additionalCategorySelected(id)
|
nodeInteraction.additionalCategorySelected(id)
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -90,7 +90,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
var chatListcategories: [ChatListNodeAdditionalCategory] = []
|
var chatListcategories: [ChatListNodeAdditionalCategory] = []
|
||||||
|
|
||||||
if let _ = createNewGroup {
|
if let _ = createNewGroup {
|
||||||
chatListcategories.append(ChatListNodeAdditionalCategory(id: 0, icon: PresentationResourcesItemList.createGroupIcon(self.presentationData.theme), title: self.presentationData.strings.PeerSelection_CreateNewGroup, appearance: .action))
|
chatListcategories.append(ChatListNodeAdditionalCategory(id: 0, icon: PresentationResourcesItemList.createGroupIcon(self.presentationData.theme), title: self.presentationData.strings.PeerSelection_ImportIntoNewGroup, appearance: .action))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: filter, isSelecting: false, additionalCategories: chatListcategories, chatListFilters: nil), theme: self.presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
|
self.chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: filter, isSelecting: false, additionalCategories: chatListcategories, chatListFilters: nil), theme: self.presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
|
||||||
|
@ -223,7 +223,7 @@ public class ShareRootControllerImpl {
|
|||||||
}
|
}
|
||||||
|> castError(ShareAuthorizationError.self)
|
|> castError(ShareAuthorizationError.self)
|
||||||
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||||
Logger.shared.logToFile = loggingSettings.logToFile
|
Logger.shared.logToFile = true//loggingSettings.logToFile
|
||||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
Logger.shared.logToConsole = loggingSettings.logToConsole
|
||||||
|
|
||||||
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
||||||
|
Loading…
x
Reference in New Issue
Block a user