mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Merge branch 'beta'
This commit is contained in:
commit
97c2834506
@ -24,20 +24,49 @@ public struct AuthTransferTokenInfo {
|
|||||||
|
|
||||||
public enum ExportAuthTransferTokenError {
|
public enum ExportAuthTransferTokenError {
|
||||||
case generic
|
case generic
|
||||||
|
case limitExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ExportAuthTransferTokenResult {
|
public enum ExportAuthTransferTokenResult {
|
||||||
case displayToken(AuthTransferExportedToken)
|
case displayToken(AuthTransferExportedToken)
|
||||||
case changeAccountAndRetry(UnauthorizedAccount)
|
case changeAccountAndRetry(UnauthorizedAccount)
|
||||||
case loggedIn
|
case loggedIn
|
||||||
|
case passwordRequested
|
||||||
}
|
}
|
||||||
|
|
||||||
public func exportAuthTransferToken(accountManager: AccountManager, account: UnauthorizedAccount, otherAccountUserIds: [Int32], syncContacts: Bool) -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> {
|
public func exportAuthTransferToken(accountManager: AccountManager, account: UnauthorizedAccount, otherAccountUserIds: [Int32], syncContacts: Bool) -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> {
|
||||||
return account.network.request(Api.functions.auth.exportLoginToken(apiId: account.networkArguments.apiId, apiHash: account.networkArguments.apiHash, exceptIds: otherAccountUserIds))
|
return account.network.request(Api.functions.auth.exportLoginToken(apiId: account.networkArguments.apiId, apiHash: account.networkArguments.apiHash, exceptIds: otherAccountUserIds))
|
||||||
|> mapError { _ -> ExportAuthTransferTokenError in
|
|> map(Optional.init)
|
||||||
return .generic
|
|> `catch` { error -> Signal<Api.auth.LoginToken?, ExportAuthTransferTokenError> in
|
||||||
|
if error.errorDescription == "SESSION_PASSWORD_NEEDED" {
|
||||||
|
return account.network.request(Api.functions.account.getPassword(), automaticFloodWait: false)
|
||||||
|
|> mapError { error -> ExportAuthTransferTokenError in
|
||||||
|
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||||
|
return .limitExceeded
|
||||||
|
} else {
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<Api.auth.LoginToken?, ExportAuthTransferTokenError> in
|
||||||
|
switch result {
|
||||||
|
case let .password(password):
|
||||||
|
return account.postbox.transaction { transaction -> Api.auth.LoginToken? in
|
||||||
|
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: password.hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|> castError(ExportAuthTransferTokenError.self)
|
||||||
|
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|> mapToSignal { result -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
|
|> mapToSignal { result -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
|
||||||
|
guard let result = result else {
|
||||||
|
return .single(.passwordRequested)
|
||||||
|
}
|
||||||
switch result {
|
switch result {
|
||||||
case let .loginToken(expires, token):
|
case let .loginToken(expires, token):
|
||||||
return .single(.displayToken(AuthTransferExportedToken(value: token.makeData(), validUntil: expires)))
|
return .single(.displayToken(AuthTransferExportedToken(value: token.makeData(), validUntil: expires)))
|
||||||
@ -47,8 +76,32 @@ public func exportAuthTransferToken(accountManager: AccountManager, account: Una
|
|||||||
|> castError(ExportAuthTransferTokenError.self)
|
|> castError(ExportAuthTransferTokenError.self)
|
||||||
|> mapToSignal { updatedAccount -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
|
|> mapToSignal { updatedAccount -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
|
||||||
return updatedAccount.network.request(Api.functions.auth.importLoginToken(token: token))
|
return updatedAccount.network.request(Api.functions.auth.importLoginToken(token: token))
|
||||||
|> mapError { _ -> ExportAuthTransferTokenError in
|
|> map(Optional.init)
|
||||||
return .generic
|
|> `catch` { error -> Signal<Api.auth.LoginToken?, ExportAuthTransferTokenError> in
|
||||||
|
if error.errorDescription == "SESSION_PASSWORD_NEEDED" {
|
||||||
|
return account.network.request(Api.functions.account.getPassword(), automaticFloodWait: false)
|
||||||
|
|> mapError { error -> ExportAuthTransferTokenError in
|
||||||
|
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||||
|
return .limitExceeded
|
||||||
|
} else {
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<Api.auth.LoginToken?, ExportAuthTransferTokenError> in
|
||||||
|
switch result {
|
||||||
|
case let .password(password):
|
||||||
|
return account.postbox.transaction { transaction -> Api.auth.LoginToken? in
|
||||||
|
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: password.hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|> castError(ExportAuthTransferTokenError.self)
|
||||||
|
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|> mapToSignal { result -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
|
|> mapToSignal { result -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -315,7 +315,9 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
|||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
self.titleNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.debugTap(_:))))
|
self.titleNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.debugTap(_:))))
|
||||||
//self.noticeNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.debugQrTap(_:))))
|
#if DEBUG
|
||||||
|
self.noticeNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.debugQrTap(_:))))
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
@ -452,7 +454,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
|||||||
self?.refreshQrToken()
|
self?.refreshQrToken()
|
||||||
}))
|
}))
|
||||||
strongSelf.refreshQrToken()
|
strongSelf.refreshQrToken()
|
||||||
case .loggedIn:
|
case .loggedIn, .passwordRequested:
|
||||||
strongSelf.exportTokenDisposable.set(nil)
|
strongSelf.exportTokenDisposable.set(nil)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -112,7 +112,7 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
|||||||
self.listView.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
|
self.listView.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
|
||||||
if let strongSelf = self, let state = opaqueTransactionState as? HorizontalListContextResultsOpaqueState {
|
if let strongSelf = self, let state = opaqueTransactionState as? HorizontalListContextResultsOpaqueState {
|
||||||
if let visible = displayedRange.visibleRange {
|
if let visible = displayedRange.visibleRange {
|
||||||
if state.hasMore && visible.lastIndex <= state.entryCount - 10 {
|
if state.hasMore && visible.lastIndex >= state.entryCount - 10 {
|
||||||
strongSelf.loadMore()
|
strongSelf.loadMore()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import TelegramPresentationData
|
|||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
import MergeLists
|
import MergeLists
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
private enum VerticalChatContextResultsEntryStableId: Hashable {
|
private enum VerticalChatContextResultsEntryStableId: Hashable {
|
||||||
case action
|
case action
|
||||||
@ -122,12 +123,16 @@ private func preparedTransition(from fromEntries: [VerticalListContextResultsCha
|
|||||||
|
|
||||||
final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContextPanelNode {
|
final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||||
private let listView: ListView
|
private let listView: ListView
|
||||||
private var currentResults: ChatContextResultCollection?
|
private var currentExternalResults: ChatContextResultCollection?
|
||||||
|
private var currentProcessedResults: ChatContextResultCollection?
|
||||||
private var currentEntries: [VerticalListContextResultsChatInputContextPanelEntry]?
|
private var currentEntries: [VerticalListContextResultsChatInputContextPanelEntry]?
|
||||||
|
|
||||||
private var enqueuedTransitions: [(VerticalListContextResultsChatInputContextPanelTransition, Bool)] = []
|
private var enqueuedTransitions: [(VerticalListContextResultsChatInputContextPanelTransition, Bool)] = []
|
||||||
private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat)?
|
private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat)?
|
||||||
|
|
||||||
|
private let loadMoreDisposable = MetaDisposable()
|
||||||
|
private var isLoadingMore: Bool = false
|
||||||
|
|
||||||
override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize) {
|
override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize) {
|
||||||
self.listView = ListView()
|
self.listView = ListView()
|
||||||
self.listView.isOpaque = false
|
self.listView.isOpaque = false
|
||||||
@ -143,10 +148,33 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
|||||||
self.clipsToBounds = true
|
self.clipsToBounds = true
|
||||||
|
|
||||||
self.addSubnode(self.listView)
|
self.addSubnode(self.listView)
|
||||||
|
|
||||||
|
self.listView.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||||
|
guard let strongSelf = self, !strongSelf.isLoadingMore, case let .known(value) = offset, value < 40.0 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.loadMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.loadMoreDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateResults(_ results: ChatContextResultCollection) {
|
func updateResults(_ results: ChatContextResultCollection) {
|
||||||
self.currentResults = results
|
if self.currentExternalResults == results {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.currentExternalResults = results
|
||||||
|
self.currentProcessedResults = results
|
||||||
|
|
||||||
|
self.isLoadingMore = false
|
||||||
|
self.loadMoreDisposable.set(nil)
|
||||||
|
|
||||||
|
self.updateInternalResults(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateInternalResults(_ results: ChatContextResultCollection) {
|
||||||
var entries: [VerticalListContextResultsChatInputContextPanelEntry] = []
|
var entries: [VerticalListContextResultsChatInputContextPanelEntry] = []
|
||||||
var index = 0
|
var index = 0
|
||||||
var resultIds = Set<VerticalChatContextResultsEntryStableId>()
|
var resultIds = Set<VerticalChatContextResultsEntryStableId>()
|
||||||
@ -203,15 +231,13 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
|||||||
|
|
||||||
var options = ListViewDeleteAndInsertOptions()
|
var options = ListViewDeleteAndInsertOptions()
|
||||||
if firstTime {
|
if firstTime {
|
||||||
//options.insert(.Synchronous)
|
|
||||||
//options.insert(.LowLatency)
|
|
||||||
} else {
|
} else {
|
||||||
options.insert(.AnimateTopItemPosition)
|
options.insert(.AnimateTopItemPosition)
|
||||||
options.insert(.AnimateCrossfade)
|
options.insert(.AnimateCrossfade)
|
||||||
}
|
}
|
||||||
|
|
||||||
var insets = UIEdgeInsets()
|
var insets = UIEdgeInsets()
|
||||||
insets.top = topInsetForLayout(size: validLayout.0, hasSwitchPeer: self.currentResults?.switchPeer != nil)
|
insets.top = topInsetForLayout(size: validLayout.0, hasSwitchPeer: self.currentExternalResults?.switchPeer != nil)
|
||||||
insets.left = validLayout.1
|
insets.left = validLayout.1
|
||||||
insets.right = validLayout.2
|
insets.right = validLayout.2
|
||||||
|
|
||||||
@ -251,7 +277,7 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
|||||||
self.validLayout = (size, leftInset, rightInset, bottomInset)
|
self.validLayout = (size, leftInset, rightInset, bottomInset)
|
||||||
|
|
||||||
var insets = UIEdgeInsets()
|
var insets = UIEdgeInsets()
|
||||||
insets.top = self.topInsetForLayout(size: size, hasSwitchPeer: self.currentResults?.switchPeer != nil)
|
insets.top = self.topInsetForLayout(size: size, hasSwitchPeer: self.currentExternalResults?.switchPeer != nil)
|
||||||
insets.left = leftInset
|
insets.left = leftInset
|
||||||
insets.right = rightInset
|
insets.right = rightInset
|
||||||
|
|
||||||
@ -268,12 +294,12 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.theme !== interfaceState.theme, let currentResults = currentResults {
|
if self.theme !== interfaceState.theme, let currentProcessedResults = self.currentProcessedResults {
|
||||||
self.theme = interfaceState.theme
|
self.theme = interfaceState.theme
|
||||||
self.listView.keepBottomItemOverscrollBackground = self.theme.list.plainBackgroundColor
|
self.listView.keepBottomItemOverscrollBackground = self.theme.list.plainBackgroundColor
|
||||||
|
|
||||||
let new = self.currentEntries?.map({$0.withUpdatedTheme(interfaceState.theme)}) ?? []
|
let new = self.currentEntries?.map({$0.withUpdatedTheme(interfaceState.theme)}) ?? []
|
||||||
prepareTransition(from: self.currentEntries, to: new, results: currentResults)
|
prepareTransition(from: self.currentEntries, to: new, results: currentProcessedResults)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,4 +325,33 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
|||||||
let listViewFrame = self.listView.frame
|
let listViewFrame = self.listView.frame
|
||||||
return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event)
|
return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func loadMore() {
|
||||||
|
guard !self.isLoadingMore, let currentProcessedResults = self.currentProcessedResults, let nextOffset = currentProcessedResults.nextOffset else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isLoadingMore = true
|
||||||
|
self.loadMoreDisposable.set((requestChatContextResults(account: self.context.account, botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, location: .single(currentProcessedResults.geoPoint), offset: nextOffset)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] nextResults in
|
||||||
|
guard let strongSelf = self, let nextResults = nextResults else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.isLoadingMore = false
|
||||||
|
var results: [ChatContextResult] = []
|
||||||
|
var existingIds = Set<String>()
|
||||||
|
for result in currentProcessedResults.results {
|
||||||
|
results.append(result)
|
||||||
|
existingIds.insert(result.id)
|
||||||
|
}
|
||||||
|
for result in nextResults.results {
|
||||||
|
if !existingIds.contains(result.id) {
|
||||||
|
results.append(result)
|
||||||
|
existingIds.insert(result.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.queryId, nextOffset: nextResults.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, results: results, cacheTimeout: currentProcessedResults.cacheTimeout)
|
||||||
|
strongSelf.currentProcessedResults = mergedResults
|
||||||
|
strongSelf.updateInternalResults(mergedResults)
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user