mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
b7c9d2b233
@ -6528,3 +6528,13 @@ Sorry for the inconvenience.";
|
||||
"Settings.CheckPasswordText" = "Your account is protected by 2-Step Verification. Do you still remember your password?";
|
||||
"Settings.KeepPassword" = "Yes, definitely";
|
||||
"Settings.TryEnterPassword" = "Not sure, let me try";
|
||||
|
||||
"TwoFactorSetup.PasswordRecovery.Title" = "Create New Password";
|
||||
"TwoFactorSetup.PasswordRecovery.Text" = "You have successfully reset your password.\nPlease enter a new password to continue";
|
||||
"TwoFactorSetup.PasswordRecovery.PlaceholderPassword" = "New Password";
|
||||
"TwoFactorSetup.PasswordRecovery.PlaceholderConfirmPassword" = "Re-enter New Password";
|
||||
"TwoFactorSetup.PasswordRecovery.Action" = "Continue";
|
||||
"TwoFactorSetup.PasswordRecovery.Skip" = "Skip";
|
||||
"TwoFactorSetup.PasswordRecovery.SkipAlertTitle" = "Attention!";
|
||||
"TwoFactorSetup.PasswordRecovery.SkipAlertText" = "Skipping this step will disable 2-step verification for your account. Are you sure you want to skip?";
|
||||
"TwoFactorSetup.PasswordRecovery.SkipAlertAction" = "Skip";
|
||||
|
@ -952,7 +952,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
switch value {
|
||||
case .notSet:
|
||||
break
|
||||
case let .set(hint, _, _, _):
|
||||
case let .set(hint, _, _, _, _):
|
||||
if !hint.isEmpty {
|
||||
strongSelf.passwordTip = hint
|
||||
}
|
||||
|
@ -372,33 +372,88 @@ public enum DrawingContextBltMode {
|
||||
case Alpha
|
||||
}
|
||||
|
||||
public struct DeviceGraphicsContextSettings {
|
||||
public static let shared: DeviceGraphicsContextSettings = {
|
||||
public func getSharedDevideGraphicsContextSettings() -> DeviceGraphicsContextSettings {
|
||||
struct OpaqueSettings {
|
||||
let rowAlignment: Int
|
||||
let bitsPerPixel: Int
|
||||
let bitsPerComponent: Int
|
||||
let opaqueBitmapInfo: CGBitmapInfo
|
||||
let colorSpace: CGColorSpace
|
||||
|
||||
init(context: CGContext) {
|
||||
self.rowAlignment = context.bytesPerRow
|
||||
self.bitsPerPixel = context.bitsPerPixel
|
||||
self.bitsPerComponent = context.bitsPerComponent
|
||||
self.opaqueBitmapInfo = context.bitmapInfo
|
||||
if #available(iOS 10.0, *) {
|
||||
if UIScreen.main.traitCollection.displayGamut == .P3 {
|
||||
self.colorSpace = CGColorSpace(name: CGColorSpace.displayP3) ?? context.colorSpace!
|
||||
} else {
|
||||
self.colorSpace = context.colorSpace!
|
||||
}
|
||||
} else {
|
||||
self.colorSpace = context.colorSpace!
|
||||
}
|
||||
assert(self.rowAlignment == 32)
|
||||
assert(self.bitsPerPixel == 32)
|
||||
assert(self.bitsPerComponent == 8)
|
||||
}
|
||||
}
|
||||
|
||||
struct TransparentSettings {
|
||||
let transparentBitmapInfo: CGBitmapInfo
|
||||
|
||||
init(context: CGContext) {
|
||||
self.transparentBitmapInfo = context.bitmapInfo
|
||||
}
|
||||
}
|
||||
|
||||
var opaqueSettings: OpaqueSettings?
|
||||
var transparentSettings: TransparentSettings?
|
||||
|
||||
if #available(iOS 10.0, *) {
|
||||
let opaqueFormat = UIGraphicsImageRendererFormat()
|
||||
let transparentFormat = UIGraphicsImageRendererFormat()
|
||||
if #available(iOS 12.0, *) {
|
||||
opaqueFormat.preferredRange = .standard
|
||||
transparentFormat.preferredRange = .standard
|
||||
}
|
||||
opaqueFormat.opaque = true
|
||||
transparentFormat.opaque = false
|
||||
|
||||
let opaqueRenderer = UIGraphicsImageRenderer(bounds: CGRect(origin: CGPoint(), size: CGSize(width: 1.0, height: 1.0)), format: opaqueFormat)
|
||||
let _ = opaqueRenderer.image(actions: { context in
|
||||
opaqueSettings = OpaqueSettings(context: context.cgContext)
|
||||
})
|
||||
|
||||
let transparentRenderer = UIGraphicsImageRenderer(bounds: CGRect(origin: CGPoint(), size: CGSize(width: 1.0, height: 1.0)), format: transparentFormat)
|
||||
let _ = transparentRenderer.image(actions: { context in
|
||||
transparentSettings = TransparentSettings(context: context.cgContext)
|
||||
})
|
||||
} else {
|
||||
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), true, 1.0)
|
||||
let refContext = UIGraphicsGetCurrentContext()!
|
||||
let bytesPerRow = refContext.bytesPerRow
|
||||
let bitsPerPixel = refContext.bitsPerPixel
|
||||
let bitsPerComponent = refContext.bitsPerComponent
|
||||
let opaqueBitmapInfo = refContext.bitmapInfo
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()!
|
||||
let colorSpace = image.cgImage!.colorSpace!
|
||||
assert(bytesPerRow == 32)
|
||||
opaqueSettings = OpaqueSettings(context: refContext)
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), false, 1.0)
|
||||
let refCtxTransparent = UIGraphicsGetCurrentContext()!
|
||||
let transparentBitmapInfo = refCtxTransparent.bitmapInfo
|
||||
transparentSettings = TransparentSettings(context: refCtxTransparent)
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
|
||||
return DeviceGraphicsContextSettings(
|
||||
rowAlignment: bytesPerRow,
|
||||
bitsPerPixel: bitsPerPixel,
|
||||
bitsPerComponent: bitsPerComponent,
|
||||
opaqueBitmapInfo: opaqueBitmapInfo,
|
||||
transparentBitmapInfo: transparentBitmapInfo,
|
||||
colorSpace: colorSpace
|
||||
)
|
||||
}()
|
||||
return DeviceGraphicsContextSettings(
|
||||
rowAlignment: opaqueSettings!.rowAlignment,
|
||||
bitsPerPixel: opaqueSettings!.bitsPerPixel,
|
||||
bitsPerComponent: opaqueSettings!.bitsPerComponent,
|
||||
opaqueBitmapInfo: opaqueSettings!.opaqueBitmapInfo,
|
||||
transparentBitmapInfo: transparentSettings!.transparentBitmapInfo,
|
||||
colorSpace: opaqueSettings!.colorSpace
|
||||
)
|
||||
}
|
||||
|
||||
public struct DeviceGraphicsContextSettings {
|
||||
public static let shared: DeviceGraphicsContextSettings = getSharedDevideGraphicsContextSettings()
|
||||
|
||||
public let rowAlignment: Int
|
||||
public let bitsPerPixel: Int
|
||||
|
@ -117,68 +117,6 @@ public final class CachedBlurredWallpaperRepresentation: CachedMediaResourceRepr
|
||||
}
|
||||
}
|
||||
|
||||
public final class CachedPatternWallpaperMaskRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let size: CGSize?
|
||||
|
||||
public var uniqueId: String {
|
||||
if let size = self.size {
|
||||
var result = "pattern-wallpaper-mask-\(Int(size.width))x\(Int(size.height))"
|
||||
return result
|
||||
} else {
|
||||
return "pattern-wallpaper-mask"
|
||||
}
|
||||
}
|
||||
|
||||
public init(size: CGSize?) {
|
||||
self.size = size
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedPatternWallpaperMaskRepresentation {
|
||||
return self.size == to.size
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final class CachedPatternWallpaperRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public let colors: [UInt32]
|
||||
public let intensity: Int32
|
||||
public let rotation: Int32?
|
||||
|
||||
public var uniqueId: String {
|
||||
var id: String = "pattern-wallpaper"
|
||||
for color in self.colors {
|
||||
id.append("-\(color)")
|
||||
}
|
||||
id.append("-\(self.intensity)")
|
||||
if let rotation = self.rotation, rotation != 0 {
|
||||
id += "-\(rotation)deg"
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
public init(colors: [UInt32], intensity: Int32, rotation: Int32?) {
|
||||
self.colors = colors
|
||||
self.intensity = intensity
|
||||
self.rotation = rotation
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
if let to = to as? CachedPatternWallpaperRepresentation {
|
||||
return self.colors == to.colors && self.intensity == intensity && self.rotation == to.rotation
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class CachedAlbumArtworkRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
|
@ -11,7 +11,9 @@ import ProgressNavigationButtonNode
|
||||
import AccountContext
|
||||
|
||||
public class SetupTwoStepVerificationController: ViewController {
|
||||
private let context: AccountContext
|
||||
private let network: Network
|
||||
private let sharedContext: SharedAccountContext
|
||||
|
||||
private let initialState: SetupTwoStepVerificationInitialState
|
||||
private let stateUpdated: (SetupTwoStepVerificationStateUpdate, Bool, SetupTwoStepVerificationController) -> Void
|
||||
|
||||
@ -32,12 +34,18 @@ public class SetupTwoStepVerificationController: ViewController {
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, initialState: SetupTwoStepVerificationInitialState, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate, Bool, SetupTwoStepVerificationController) -> Void) {
|
||||
self.context = context
|
||||
convenience public init(context: AccountContext, initialState: SetupTwoStepVerificationInitialState, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate, Bool, SetupTwoStepVerificationController) -> Void) {
|
||||
self.init(sharedContext: context.sharedContext, network: context.account.network, initialState: initialState, stateUpdated: stateUpdated)
|
||||
}
|
||||
|
||||
public init(sharedContext: SharedAccountContext, network: Network, initialState: SetupTwoStepVerificationInitialState, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate, Bool, SetupTwoStepVerificationController) -> Void) {
|
||||
self.sharedContext = sharedContext
|
||||
self.network = network
|
||||
|
||||
self.initialState = initialState
|
||||
self.stateUpdated = stateUpdated
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(buttonColor: self.presentationData.theme.rootController.navigationBar.accentTextColor, disabledButtonColor: self.presentationData.theme.rootController.navigationBar.disabledButtonColor, primaryTextColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
|
||||
@ -45,7 +53,7 @@ public class SetupTwoStepVerificationController: ViewController {
|
||||
|
||||
self.navigationItem.setLeftBarButton(UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)), animated: false)
|
||||
|
||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||
self.presentationDataDisposable = (self.sharedContext.presentationData
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
let previousTheme = strongSelf.presentationData.theme
|
||||
@ -95,7 +103,7 @@ public class SetupTwoStepVerificationController: ViewController {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = SetupTwoStepVerificationControllerNode(context: self.context, updateBackAction: { [weak self] action in
|
||||
self.displayNode = SetupTwoStepVerificationControllerNode(sharedContext: self.sharedContext, network: self.network, updateBackAction: { [weak self] action in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -141,7 +141,8 @@ public enum SetupTwoStepVerificationStateUpdate {
|
||||
}
|
||||
|
||||
final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
private let context: AccountContext
|
||||
private let sharedContext: SharedAccountContext
|
||||
private let network: Network
|
||||
private var presentationData: PresentationData
|
||||
private let updateBackAction: (Bool) -> Void
|
||||
private let updateNextAction: (SetupTwoStepVerificationNextAction) -> Void
|
||||
@ -154,14 +155,15 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
private var contentNode: SetupTwoStepVerificationContentNode?
|
||||
private let actionDisposable = MetaDisposable()
|
||||
|
||||
init(context: AccountContext, updateBackAction: @escaping (Bool) -> Void, updateNextAction: @escaping (SetupTwoStepVerificationNextAction) -> Void, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate, Bool) -> Void, present: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void, initialState: SetupTwoStepVerificationInitialState) {
|
||||
self.context = context
|
||||
init(sharedContext: SharedAccountContext, network: Network, updateBackAction: @escaping (Bool) -> Void, updateNextAction: @escaping (SetupTwoStepVerificationNextAction) -> Void, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate, Bool) -> Void, present: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void, initialState: SetupTwoStepVerificationInitialState) {
|
||||
self.sharedContext = sharedContext
|
||||
self.network = network
|
||||
self.updateBackAction = updateBackAction
|
||||
self.updateNextAction = updateNextAction
|
||||
self.stateUpdated = stateUpdated
|
||||
self.present = present
|
||||
self.dismiss = dismiss
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
self.innerState = SetupTwoStepVerificationControllerInnerState(layout: nil, data: SetupTwoStepVerificationControllerDataState(activity: false, state: SetupTwoStepVerificationState(initialState: initialState)))
|
||||
self.activityIndicator = ActivityIndicator(type: .custom(self.presentationData.theme.list.itemAccentColor, 22.0, 2.0, false))
|
||||
|
||||
@ -171,7 +173,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
self.processStateUpdated()
|
||||
|
||||
if self.innerState.data.state == nil {
|
||||
self.actionDisposable.set((twoStepAuthData(context.account.network)
|
||||
self.actionDisposable.set((twoStepAuthData(self.network)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] data in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -340,7 +342,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
state.data.activity = true
|
||||
return state
|
||||
}, transition: .animated(duration: 0.5, curve: .spring))
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationPassword(network: strongSelf.context.account.network, currentPassword: nil, updatedPassword: .none)
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationPassword(network: strongSelf.network, currentPassword: nil, updatedPassword: .none)
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -356,7 +358,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.updateState({ state in
|
||||
var state = state
|
||||
state.data.activity = false
|
||||
@ -393,7 +395,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
state.data.activity = true
|
||||
return state
|
||||
}, transition: .animated(duration: 0.5, curve: .spring))
|
||||
strongSelf.actionDisposable.set((resendTwoStepRecoveryEmail(network: strongSelf.context.account.network)
|
||||
strongSelf.actionDisposable.set((resendTwoStepRecoveryEmail(network: strongSelf.network)
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -405,7 +407,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.updateState({ state in
|
||||
var state = state
|
||||
state.data.activity = false
|
||||
@ -526,7 +528,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
if password == confirmation {
|
||||
state.data.state = .enterHint(mode: mode, password: password, hint: "")
|
||||
} else {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.TwoStepAuth_SetupPasswordConfirmFailed, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: strongSelf.presentationData.strings.TwoStepAuth_SetupPasswordConfirmFailed, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
case let .enterHint(mode, password, hint):
|
||||
switch mode {
|
||||
@ -534,7 +536,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
state.data.state = .enterEmail(state: .create(password: password, hint: hint), email: "")
|
||||
case let .update(current, hasRecoveryEmail, hasSecureValues):
|
||||
state.data.activity = true
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationPassword(network: strongSelf.context.account.network, currentPassword: current, updatedPassword: .password(password: password, hint: hint, email: nil))
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationPassword(network: strongSelf.network, currentPassword: current, updatedPassword: .password(password: password, hint: hint, email: nil))
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -558,7 +560,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.updateState({ state in
|
||||
var state = state
|
||||
state.data.activity = false
|
||||
@ -570,7 +572,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
state.data.activity = true
|
||||
switch enterState {
|
||||
case let .create(password, hint):
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationPassword(network: strongSelf.context.account.network, currentPassword: nil, updatedPassword: .password(password: password, hint: hint, email: email))
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationPassword(network: strongSelf.network, currentPassword: nil, updatedPassword: .password(password: password, hint: hint, email: email))
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -602,7 +604,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.updateState({ state in
|
||||
var state = state
|
||||
state.data.activity = false
|
||||
@ -618,7 +620,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
state.data.activity = true
|
||||
return state
|
||||
}, transition: .animated(duration: 0.5, curve: .spring))
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationEmail(network: strongSelf.context.account.network, currentPassword: password, updatedEmail: email)
|
||||
strongSelf.actionDisposable.set((updateTwoStepVerificationEmail(network: strongSelf.network, currentPassword: password, updatedEmail: email)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -644,7 +646,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.updateState({ state in
|
||||
var state = state
|
||||
state.data.activity = false
|
||||
@ -654,7 +656,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
case let .confirmEmail(confirmState, _, _, code):
|
||||
state.data.activity = true
|
||||
strongSelf.actionDisposable.set((confirmTwoStepRecoveryEmail(network: strongSelf.context.account.network, code: code)
|
||||
strongSelf.actionDisposable.set((confirmTwoStepRecoveryEmail(network: strongSelf.network, code: code)
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -673,7 +675,7 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
|
||||
strongSelf.updateState({ state in
|
||||
var state = state
|
||||
@ -697,8 +699,8 @@ final class SetupTwoStepVerificationControllerNode: ViewControllerTracingNode {
|
||||
return state
|
||||
}, transition: .animated(duration: 0.5, curve: .spring))
|
||||
}
|
||||
if case let .enterEmail(enterEmail)? = self.innerState.data.state, case .create = enterEmail.state, enterEmail.email.isEmpty {
|
||||
self.present(textAlertController(context: self.context, title: nil, text: self.presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.TwoStepAuth_EmailSkip, action: {
|
||||
if case let .enterEmail(enterEmailState, enterEmailEmail)? = self.innerState.data.state, case .create = enterEmailState, enterEmailEmail.isEmpty {
|
||||
self.present(textAlertController(sharedContext: self.sharedContext, title: nil, text: self.presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.TwoStepAuth_EmailSkip, action: {
|
||||
continueImpl()
|
||||
})]), nil)
|
||||
} else {
|
||||
|
@ -13,25 +13,40 @@ import TelegramCore
|
||||
import AnimatedStickerNode
|
||||
|
||||
public enum TwoFactorDataInputMode {
|
||||
public struct Recovery {
|
||||
public var code: String
|
||||
public var syncContacts: Bool
|
||||
public var account: UnauthorizedAccount
|
||||
|
||||
public init(code: String, syncContacts: Bool, account: UnauthorizedAccount) {
|
||||
self.code = code
|
||||
self.syncContacts = syncContacts
|
||||
self.account = account
|
||||
}
|
||||
}
|
||||
|
||||
case password
|
||||
case passwordRecovery(Recovery)
|
||||
case emailAddress(password: String, hint: String)
|
||||
case updateEmailAddress(password: String)
|
||||
case emailConfirmation(passwordAndHint: (String, String)?, emailPattern: String, codeLength: Int?)
|
||||
case passwordHint(password: String)
|
||||
case passwordHint(recovery: Recovery?, password: String)
|
||||
}
|
||||
|
||||
public final class TwoFactorDataInputScreen: ViewController {
|
||||
private let context: AccountContext
|
||||
private let sharedContext: SharedAccountContext
|
||||
private let network: Network
|
||||
private var presentationData: PresentationData
|
||||
private let mode: TwoFactorDataInputMode
|
||||
private let stateUpdated: (SetupTwoStepVerificationStateUpdate) -> Void
|
||||
|
||||
public init(context: AccountContext, mode: TwoFactorDataInputMode, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate) -> Void) {
|
||||
self.context = context
|
||||
public init(sharedContext: SharedAccountContext, network: Network, mode: TwoFactorDataInputMode, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate) -> Void) {
|
||||
self.sharedContext = sharedContext
|
||||
self.network = network
|
||||
self.mode = mode
|
||||
self.stateUpdated = stateUpdated
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
|
||||
@ -86,7 +101,35 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(context: strongSelf.context, mode: .passwordHint(password: values[0]), stateUpdated: strongSelf.stateUpdated))
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .passwordHint(recovery: nil, password: values[0]), stateUpdated: strongSelf.stateUpdated))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
case let .passwordRecovery(recovery):
|
||||
let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText
|
||||
if values.count != 2 {
|
||||
return
|
||||
}
|
||||
if values[0] != values[1] {
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.presentationData.strings.TwoStepAuth_SetupPasswordConfirmFailed, actions: [
|
||||
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})
|
||||
]), in: .window(.root))
|
||||
return
|
||||
}
|
||||
if values[0].isEmpty {
|
||||
return
|
||||
}
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
var controllers = navigationController.viewControllers.filter { controller in
|
||||
if controller is TwoFactorAuthSplashScreen {
|
||||
return false
|
||||
}
|
||||
if controller is TwoFactorDataInputScreen && controller !== strongSelf {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .passwordHint(recovery: recovery, password: values[0]), stateUpdated: strongSelf.stateUpdated))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
case let .emailAddress(password, hint):
|
||||
guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
|
||||
@ -95,7 +138,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (updateTwoStepVerificationPassword(network: strongSelf.context.account.network, currentPassword: "", updatedPassword: .password(password: password, hint: hint, email: text))
|
||||
let _ = (updateTwoStepVerificationPassword(network: strongSelf.network, currentPassword: "", updatedPassword: .password(password: password, hint: hint, email: text))
|
||||
|> deliverOnMainQueue).start(next: { [weak statusController] result in
|
||||
statusController?.dismiss()
|
||||
|
||||
@ -120,7 +163,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(context: strongSelf.context, mode: .emailConfirmation(passwordAndHint: (password, hint), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated))
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .emailConfirmation(passwordAndHint: (password, hint), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
@ -135,7 +178,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorAuthSplashScreen(context: strongSelf.context, mode: .done))
|
||||
controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .done))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
@ -154,7 +197,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
case .invalidEmail:
|
||||
alertText = presentationData.strings.TwoStepAuth_EmailInvalid
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
case let .updateEmailAddress(password):
|
||||
guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
|
||||
@ -163,7 +206,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (updateTwoStepVerificationEmail(network: strongSelf.context.account.network, currentPassword: password, updatedEmail: text)
|
||||
let _ = (updateTwoStepVerificationEmail(network: strongSelf.network, currentPassword: password, updatedEmail: text)
|
||||
|> deliverOnMainQueue).start(next: { [weak statusController] result in
|
||||
statusController?.dismiss()
|
||||
|
||||
@ -188,7 +231,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(context: strongSelf.context, mode: .emailConfirmation(passwordAndHint: (password, ""), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated))
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .emailConfirmation(passwordAndHint: (password, ""), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
@ -203,7 +246,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorAuthSplashScreen(context: strongSelf.context, mode: .done))
|
||||
controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .done))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
@ -222,7 +265,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
case .invalidEmail:
|
||||
alertText = presentationData.strings.TwoStepAuth_EmailInvalid
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
case .emailConfirmation:
|
||||
guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
|
||||
@ -231,7 +274,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (confirmTwoStepRecoveryEmail(network: strongSelf.context.account.network, code: text)
|
||||
let _ = (confirmTwoStepRecoveryEmail(network: strongSelf.network, code: text)
|
||||
|> deliverOnMainQueue).start(error: { [weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
@ -253,7 +296,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
case .generic:
|
||||
text = presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak statusController] in
|
||||
statusController?.dismiss()
|
||||
|
||||
@ -273,15 +316,19 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorAuthSplashScreen(context: strongSelf.context, mode: .done))
|
||||
controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .done))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
})
|
||||
case let .passwordHint(password):
|
||||
case let .passwordHint(recovery, password):
|
||||
guard let value = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !value.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.push(TwoFactorDataInputScreen(context: strongSelf.context, mode: .emailAddress(password: password, hint: value), stateUpdated: strongSelf.stateUpdated))
|
||||
|
||||
if let recovery = recovery {
|
||||
strongSelf.performRecovery(recovery: recovery, password: password, hint: value)
|
||||
} else {
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .emailAddress(password: password, hint: value), stateUpdated: strongSelf.stateUpdated))
|
||||
}
|
||||
}
|
||||
}, skipAction: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
@ -297,7 +344,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (updateTwoStepVerificationPassword(network: strongSelf.context.account.network, currentPassword: "", updatedPassword: .password(password: password, hint: hint, email: nil))
|
||||
let _ = (updateTwoStepVerificationPassword(network: strongSelf.network, currentPassword: "", updatedPassword: .password(password: password, hint: hint, email: nil))
|
||||
|> deliverOnMainQueue).start(next: { [weak statusController] result in
|
||||
statusController?.dismiss()
|
||||
|
||||
@ -321,7 +368,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorAuthSplashScreen(context: strongSelf.context, mode: .done))
|
||||
controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .done))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}, error: { [weak statusController] error in
|
||||
@ -339,13 +386,27 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
case .invalidEmail:
|
||||
alertText = presentationData.strings.TwoStepAuth_EmailInvalid
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
}),
|
||||
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})
|
||||
]), in: .window(.root))
|
||||
case let .passwordHint(password):
|
||||
strongSelf.push(TwoFactorDataInputScreen(context: strongSelf.context, mode: .emailAddress(password: password, hint: ""), stateUpdated: strongSelf.stateUpdated))
|
||||
case let .passwordHint(recovery, password):
|
||||
if let recovery = recovery {
|
||||
strongSelf.performRecovery(recovery: recovery, password: password, hint: "")
|
||||
} else {
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .emailAddress(password: password, hint: ""), stateUpdated: strongSelf.stateUpdated))
|
||||
}
|
||||
case let .passwordRecovery(recovery):
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertTitle, text: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertText, actions: [
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertAction, action: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.performRecovery(recovery: recovery, password: "", hint: "")
|
||||
}),
|
||||
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})
|
||||
]), in: .window(.root))
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -368,7 +429,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(context: strongSelf.context, mode: .emailAddress(password: password, hint: hint), stateUpdated: strongSelf.stateUpdated))
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .emailAddress(password: password, hint: hint), stateUpdated: strongSelf.stateUpdated))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
}
|
||||
@ -383,7 +444,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (resendTwoStepRecoveryEmail(network: strongSelf.context.account.network)
|
||||
let _ = (resendTwoStepRecoveryEmail(network: strongSelf.network)
|
||||
|> deliverOnMainQueue).start(error: { [weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
@ -398,7 +459,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak statusController] in
|
||||
statusController?.dismiss()
|
||||
})
|
||||
@ -412,6 +473,42 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
|
||||
(self.displayNode as! TwoFactorDataInputScreenNode).containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
}
|
||||
|
||||
private func performRecovery(recovery: TwoFactorDataInputMode.Recovery, password: String, hint: String) {
|
||||
/*let statusController = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: nil))
|
||||
self.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (performPasswordRecovery(accountManager: self.sharedContext.accountManager, account: recovery.account, code: recovery.code, syncContacts: recovery.syncContacts, updatedPassword: password.isEmpty ? .none : .password(password: password, hint: hint, email: nil))
|
||||
|> deliverOnMainQueue).start(error: { [weak self, weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak self, weak statusController] in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.dismiss()
|
||||
})*/
|
||||
}
|
||||
}
|
||||
|
||||
private enum TwoFactorDataInputTextNodeType {
|
||||
@ -695,7 +792,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
self.scrollNode.canCancelAllTouchesInViews = true
|
||||
|
||||
switch mode {
|
||||
case .password, .emailAddress, .updateEmailAddress:
|
||||
case .password, .passwordRecovery, .emailAddress, .updateEmailAddress:
|
||||
self.monkeyNode = ManagedMonkeyAnimationNode()
|
||||
case .emailConfirmation:
|
||||
if let path = getAppBundle().path(forResource: "TwoFactorSetupMail", ofType: "tgs") {
|
||||
@ -754,6 +851,33 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
toggleTextHidden?(node)
|
||||
})
|
||||
]
|
||||
case .passwordRecovery:
|
||||
title = presentationData.strings.TwoFactorSetup_PasswordRecovery_Title
|
||||
text = NSAttributedString(string: presentationData.strings.TwoFactorSetup_PasswordRecovery_Text, font: Font.regular(16.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
buttonText = presentationData.strings.TwoFactorSetup_PasswordRecovery_Action
|
||||
skipActionText = presentationData.strings.TwoFactorSetup_PasswordRecovery_Skip
|
||||
changeEmailActionText = ""
|
||||
resendCodeActionText = ""
|
||||
inputNodes = [
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderPassword, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
}, updated: { node in
|
||||
updated?(node)
|
||||
}, toggleTextHidden: { node in
|
||||
toggleTextHidden?(node)
|
||||
}),
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderConfirmPassword, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
}, updated: { node in
|
||||
updated?(node)
|
||||
}, toggleTextHidden: { node in
|
||||
toggleTextHidden?(node)
|
||||
})
|
||||
]
|
||||
case .emailAddress, .updateEmailAddress:
|
||||
title = presentationData.strings.TwoFactorSetup_Email_Title
|
||||
text = NSAttributedString(string: presentationData.strings.TwoFactorSetup_Email_Text, font: Font.regular(16.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
@ -937,7 +1061,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let index = strongSelf.inputNodes.index(where: { $0 === node }) {
|
||||
if let index = strongSelf.inputNodes.firstIndex(where: { $0 === node }) {
|
||||
if index == strongSelf.inputNodes.count - 1 {
|
||||
strongSelf.action()
|
||||
} else if strongSelf.buttonNode.isUserInteractionEnabled {
|
||||
@ -953,14 +1077,12 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
switch strongSelf.mode {
|
||||
case .password:
|
||||
if strongSelf.inputNodes[1].isFocused {
|
||||
let textLength = strongSelf.inputNodes[1].text.count
|
||||
let maxWidth = strongSelf.inputNodes[1].bounds.width
|
||||
|
||||
let textNode = ImmediateTextNode()
|
||||
textNode.attributedText = NSAttributedString(string: strongSelf.inputNodes[1].text, font: Font.regular(17.0), textColor: .black)
|
||||
let textSize = textNode.updateLayout(CGSize(width: 1000.0, height: 100.0))
|
||||
|
||||
let maxTextLength = 20
|
||||
|
||||
var trackingOffset = textSize.width / maxWidth
|
||||
trackingOffset = max(0.0, min(1.0, trackingOffset))
|
||||
strongSelf.monkeyNode?.setState(.tracking(trackingOffset))
|
||||
@ -978,14 +1100,12 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
}
|
||||
case .emailAddress:
|
||||
if strongSelf.inputNodes[0].isFocused {
|
||||
let textLength = strongSelf.inputNodes[0].text.count
|
||||
let maxWidth = strongSelf.inputNodes[0].bounds.width
|
||||
|
||||
let textNode = ImmediateTextNode()
|
||||
textNode.attributedText = NSAttributedString(string: strongSelf.inputNodes[0].text, font: Font.regular(17.0), textColor: .black)
|
||||
let textSize = textNode.updateLayout(CGSize(width: 1000.0, height: 100.0))
|
||||
|
||||
let maxTextLength = 20
|
||||
|
||||
var trackingOffset = textSize.width / maxWidth
|
||||
trackingOffset = max(0.0, min(1.0, trackingOffset))
|
||||
strongSelf.monkeyNode?.setState(.tracking(trackingOffset))
|
||||
@ -998,9 +1118,6 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
}
|
||||
focusUpdated = { [weak self] node, _ in
|
||||
DispatchQueue.main.async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
updateAnimations()
|
||||
}
|
||||
}
|
||||
@ -1031,7 +1148,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
strongSelf.buttonNode.isHidden = !hasText
|
||||
strongSelf.skipActionTitleNode.isHidden = hasText
|
||||
strongSelf.skipActionButtonNode.isHidden = hasText
|
||||
case .password:
|
||||
case .password, .passwordRecovery:
|
||||
break
|
||||
}
|
||||
updateAnimations()
|
||||
@ -1113,7 +1230,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: contentAreaSize))
|
||||
|
||||
let iconSize: CGSize
|
||||
if let animatedStickerNode = self.animatedStickerNode {
|
||||
if let _ = self.animatedStickerNode {
|
||||
iconSize = CGSize(width: 136.0, height: 136.0)
|
||||
} else if let monkeyNode = self.monkeyNode {
|
||||
iconSize = monkeyNode.intrinsicSize
|
||||
@ -1194,9 +1311,15 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: floor((contentAreaSize.width - buttonWidth) / 2.0), y: max(contentHeight + buttonSpacing, maxButtonY)), size: CGSize(width: buttonWidth, height: buttonHeight))
|
||||
transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
|
||||
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
|
||||
transition.updateFrame(node: self.skipActionButtonNode, frame: buttonFrame)
|
||||
transition.updateFrame(node: self.skipActionTitleNode, frame: CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - skipActionSize.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - skipActionSize.height) / 2.0)), size: skipActionSize))
|
||||
let _ = self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
|
||||
|
||||
var skipButtonFrame = buttonFrame
|
||||
if !self.buttonNode.isHidden {
|
||||
skipButtonFrame.origin.y += skipButtonFrame.height
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.skipActionButtonNode, frame: skipButtonFrame)
|
||||
transition.updateFrame(node: self.skipActionTitleNode, frame: CGRect(origin: CGPoint(x: skipButtonFrame.minX + floor((skipButtonFrame.width - skipActionSize.width) / 2.0), y: skipButtonFrame.minY + floor((skipButtonFrame.height - skipActionSize.height) / 2.0)), size: skipActionSize))
|
||||
|
||||
let changeEmailActionFrame: CGRect
|
||||
let changeEmailActionButtonFrame: CGRect
|
||||
@ -1222,7 +1345,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
|
||||
transition.animateView {
|
||||
self.scrollNode.view.contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: layout.insets(options: [.input]).bottom, right: 0.0)
|
||||
self.scrollNode.view.contentSize = CGSize(width: contentAreaSize.width, height: max(availableAreaSize.height, buttonFrame.maxY + bottomInset))
|
||||
self.scrollNode.view.contentSize = CGSize(width: contentAreaSize.width, height: max(availableAreaSize.height, skipButtonFrame.maxY + bottomInset))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import AnimatedStickerNode
|
||||
import AccountContext
|
||||
import TelegramPresentationData
|
||||
import PresentationDataUtils
|
||||
import TelegramCore
|
||||
|
||||
public enum TwoFactorAuthSplashMode {
|
||||
case intro
|
||||
@ -17,15 +18,17 @@ public enum TwoFactorAuthSplashMode {
|
||||
}
|
||||
|
||||
public final class TwoFactorAuthSplashScreen: ViewController {
|
||||
private let context: AccountContext
|
||||
private let sharedContext: SharedAccountContext
|
||||
private let network: Network
|
||||
private var presentationData: PresentationData
|
||||
private var mode: TwoFactorAuthSplashMode
|
||||
|
||||
public init(context: AccountContext, mode: TwoFactorAuthSplashMode) {
|
||||
self.context = context
|
||||
public init(sharedContext: SharedAccountContext, network: Network, mode: TwoFactorAuthSplashMode) {
|
||||
self.sharedContext = sharedContext
|
||||
self.network = network
|
||||
self.mode = mode
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
|
||||
@ -48,13 +51,13 @@ public final class TwoFactorAuthSplashScreen: ViewController {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = TwoFactorAuthSplashScreenNode(context: self.context, presentationData: self.presentationData, mode: self.mode, action: { [weak self] in
|
||||
self.displayNode = TwoFactorAuthSplashScreenNode(sharedContext: self.sharedContext, presentationData: self.presentationData, mode: self.mode, action: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch strongSelf.mode {
|
||||
case .intro:
|
||||
strongSelf.push(TwoFactorDataInputScreen(context: strongSelf.context, mode: .password, stateUpdated: { _ in
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.network, mode: .password, stateUpdated: { _ in
|
||||
}))
|
||||
case .done:
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
@ -92,7 +95,7 @@ private final class TwoFactorAuthSplashScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, mode: TwoFactorAuthSplashMode, action: @escaping () -> Void) {
|
||||
init(sharedContext: SharedAccountContext, presentationData: PresentationData, mode: TwoFactorAuthSplashMode, action: @escaping () -> Void) {
|
||||
self.presentationData = presentationData
|
||||
self.mode = mode
|
||||
|
||||
@ -191,9 +194,9 @@ private final class TwoFactorAuthSplashScreenNode: ViewControllerTracingNode {
|
||||
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight))
|
||||
transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
|
||||
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
|
||||
let _ = self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
|
||||
|
||||
var maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight
|
||||
let maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight
|
||||
|
||||
contentVerticalOrigin = min(contentVerticalOrigin, maxContentVerticalOrigin)
|
||||
|
||||
|
@ -727,7 +727,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
|
||||
}
|
||||
})
|
||||
}, openTwoStepVerification: { data in
|
||||
var intro = false
|
||||
let intro = false
|
||||
if let data = data {
|
||||
switch data {
|
||||
case .set:
|
||||
@ -735,7 +735,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
|
||||
case let .notSet(pendingEmail):
|
||||
//intro = pendingEmail == nil
|
||||
if pendingEmail == nil {
|
||||
let controller = TwoFactorAuthSplashScreen(context: context, mode: .intro)
|
||||
let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, network: context.account.network, mode: .intro)
|
||||
pushControllerImpl?(controller, true)
|
||||
return
|
||||
} else {
|
||||
|
@ -246,7 +246,7 @@ enum TwoStepVerificationAccessConfiguration: Equatable {
|
||||
switch configuration {
|
||||
case let .notSet(pendingEmail):
|
||||
self = .notSet(pendingEmail: pendingEmail.flatMap({ TwoStepVerificationPendingEmailState(password: password, email: $0) }))
|
||||
case let .set(hint, hasRecoveryEmail, _, hasSecureValues):
|
||||
case let .set(hint, hasRecoveryEmail, _, hasSecureValues, _):
|
||||
self = .set(hint: hint, hasRecoveryEmail: hasRecoveryEmail, hasSecureValues: hasSecureValues)
|
||||
}
|
||||
}
|
||||
|
@ -514,7 +514,6 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
let prepare: Signal<CreateThemeResult, CreateThemeError>
|
||||
if let resolvedWallpaper = resolvedWallpaper, case let .file(file) = resolvedWallpaper, resolvedWallpaper.isPattern {
|
||||
let resource = file.file.resource
|
||||
let representation = CachedPatternWallpaperRepresentation(colors: file.settings.colors.count >= 1 ? file.settings.colors : [0xd6e2ee], intensity: file.settings.intensity ?? 50, rotation: file.settings.rotation)
|
||||
|
||||
var data: Data?
|
||||
if let path = context.account.postbox.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
@ -525,13 +524,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
|
||||
if let data = data {
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
prepare = (context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true)
|
||||
|> filter({ $0.complete })
|
||||
|> take(1)
|
||||
|> castError(CreateThemeError.self)
|
||||
|> mapToSignal { _ -> Signal<CreateThemeResult, CreateThemeError> in
|
||||
return .complete()
|
||||
})
|
||||
prepare = .complete()
|
||||
} else {
|
||||
prepare = .complete()
|
||||
}
|
||||
|
@ -176,8 +176,7 @@ final class ThemeAccentColorController: ViewController {
|
||||
let prepareWallpaper: Signal<CreateThemeResult, CreateThemeError>
|
||||
if let patternWallpaper = state.patternWallpaper, case let .file(file) = patternWallpaper, !state.backgroundColors.isEmpty {
|
||||
let resource = file.file.resource
|
||||
let representation = CachedPatternWallpaperRepresentation(colors: state.backgroundColors.count >= 1 ? state.backgroundColors : [0], intensity: state.patternIntensity, rotation: state.rotation)
|
||||
|
||||
|
||||
var data: Data?
|
||||
if let path = strongSelf.context.account.postbox.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
data = maybeData
|
||||
@ -187,13 +186,7 @@ final class ThemeAccentColorController: ViewController {
|
||||
|
||||
if let data = data {
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
prepareWallpaper = (strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true)
|
||||
|> filter({ $0.complete })
|
||||
|> take(1)
|
||||
|> castError(CreateThemeError.self)
|
||||
|> mapToSignal { _ -> Signal<CreateThemeResult, CreateThemeError> in
|
||||
return .complete()
|
||||
})
|
||||
prepareWallpaper = .complete()
|
||||
} else {
|
||||
prepareWallpaper = .complete()
|
||||
}
|
||||
@ -470,7 +463,7 @@ final class ThemeAccentColorController: ViewController {
|
||||
} else if let customWallpaper = settings.themeSpecificChatWallpapers[themeReference.index] {
|
||||
wallpaper = customWallpaper
|
||||
} else {
|
||||
let theme = makePresentationTheme(mediaBox: strongSelf.context.sharedContext.accountManager.mediaBox, themeReference: themeReference, accentColor: themeSpecificAccentColor?.color, wallpaper: themeSpecificAccentColor?.wallpaper, wallpaperGradientColors: themeSpecificAccentColor?.baseColor.wallpaperGradientColors) ?? defaultPresentationTheme
|
||||
let theme = makePresentationTheme(mediaBox: strongSelf.context.sharedContext.accountManager.mediaBox, themeReference: themeReference, accentColor: themeSpecificAccentColor?.color, wallpaper: themeSpecificAccentColor?.wallpaper, baseColor: themeSpecificAccentColor?.baseColor) ?? defaultPresentationTheme
|
||||
referenceTheme = theme
|
||||
wallpaper = theme.chat.defaultWallpaper
|
||||
}
|
||||
|
@ -4,31 +4,31 @@ import SyncCore
|
||||
import TelegramUIPreferences
|
||||
import TelegramPresentationData
|
||||
|
||||
private func patternWallpaper(colors: [UInt32], intensity: Int32?, rotation: Int32?) -> TelegramWallpaper {
|
||||
return defaultBuiltinWallpaper(colors: colors, intensity: intensity ?? 50, rotation: rotation)
|
||||
private func patternWallpaper(data: BuiltinWallpaperData, colors: [UInt32], intensity: Int32?, rotation: Int32?) -> TelegramWallpaper {
|
||||
return defaultBuiltinWallpaper(data: data, colors: colors, intensity: intensity ?? 50, rotation: rotation)
|
||||
}
|
||||
|
||||
var dayClassicColorPresets: [PresentationThemeAccentColor] = [
|
||||
// Pink with Blue
|
||||
PresentationThemeAccentColor(index: 106, baseColor: .preset, accentColor: 0xfff55783, bubbleColors: (0xffd6f5ff, 0xffc9fdfe), wallpaper: patternWallpaper(colors: [0x8dc0eb, 0xb9d1ea, 0xc6b1ef, 0xebd7ef], intensity: 50, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 106, baseColor: .preset, accentColor: 0xfff55783, bubbleColors: (0xffd6f5ff, 0xffc9fdfe), wallpaper: patternWallpaper(data: .default, colors: [0x8dc0eb, 0xb9d1ea, 0xc6b1ef, 0xebd7ef], intensity: 50, rotation: nil)),
|
||||
|
||||
// Pink with Gold
|
||||
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0xFFFF5FA9, bubbleColors: (0xFFFFF4D7, nil), wallpaper: patternWallpaper(colors: [0xeaa36e, 0xf0e486, 0xf29ebf, 0xe8c06e], intensity: 50, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0xFFFF5FA9, bubbleColors: (0xFFFFF4D7, nil), wallpaper: patternWallpaper(data: .variant12, colors: [0xeaa36e, 0xf0e486, 0xf29ebf, 0xe8c06e], intensity: 50, rotation: nil)),
|
||||
|
||||
// Green
|
||||
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xFF5A9E29, bubbleColors: (0xffFFF8DF, nil), wallpaper: patternWallpaper(colors: [0x7fc289, 0xe4d573, 0xafd677, 0xf0c07a], intensity: 50, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xFF5A9E29, bubbleColors: (0xffFFF8DF, nil), wallpaper: patternWallpaper(data: .variant13, colors: [0x7fc289, 0xe4d573, 0xafd677, 0xf0c07a], intensity: 50, rotation: nil)),
|
||||
|
||||
// Purple
|
||||
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0xFF7E5FE5, bubbleColors: (0xFFF5e2FF, nil), wallpaper: patternWallpaper(colors: [0xe4b2ea, 0x8376c2, 0xeab9d9, 0xb493e6], intensity: 50, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0xFF7E5FE5, bubbleColors: (0xFFF5e2FF, nil), wallpaper: patternWallpaper(data: .variant14, colors: [0xe4b2ea, 0x8376c2, 0xeab9d9, 0xb493e6], intensity: 50, rotation: nil)),
|
||||
|
||||
// Light Blue
|
||||
PresentationThemeAccentColor(index: 107, baseColor: .preset, accentColor: 0xFF2CB9ED, bubbleColors: (0xFFADF7B5, 0xFFFCFF8B), wallpaper: patternWallpaper(colors: [0x1a2e1a, 0x47623c, 0x222e24, 0x314429], intensity: 50, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 107, baseColor: .preset, accentColor: 0xFF2CB9ED, bubbleColors: (0xFFADF7B5, 0xFFFCFF8B), wallpaper: patternWallpaper(data: .variant3, colors: [0x1a2e1a, 0x47623c, 0x222e24, 0x314429], intensity: 50, rotation: nil)),
|
||||
|
||||
// Mint
|
||||
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xFF199972, bubbleColors: (0xFFFFFEC7, nil), wallpaper: patternWallpaper(colors: [0xdceb92, 0x8fe1d6, 0x67a3f2, 0x85d685], intensity: 50, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xFF199972, bubbleColors: (0xFFFFFEC7, nil), wallpaper: patternWallpaper(data: .variant3, colors: [0xdceb92, 0x8fe1d6, 0x67a3f2, 0x85d685], intensity: 50, rotation: nil)),
|
||||
|
||||
// Pink with Green
|
||||
PresentationThemeAccentColor(index: 105, baseColor: .preset, accentColor: 0xFFDA90D9, bubbleColors: (0xFF94FFF9, 0xFFCCFFC7), wallpaper: patternWallpaper(colors: [0xffc3b2, 0xe2c0ff, 0xffe7b2], intensity: 50, rotation: nil))
|
||||
PresentationThemeAccentColor(index: 105, baseColor: .preset, accentColor: 0xFFDA90D9, bubbleColors: (0xFF94FFF9, 0xFFCCFFC7), wallpaper: patternWallpaper(data: .variant9, colors: [0xffc3b2, 0xe2c0ff, 0xffe7b2], intensity: 50, rotation: nil))
|
||||
]
|
||||
|
||||
var dayColorPresets: [PresentationThemeAccentColor] = [
|
||||
@ -39,8 +39,8 @@ var dayColorPresets: [PresentationThemeAccentColor] = [
|
||||
]
|
||||
|
||||
var nightColorPresets: [PresentationThemeAccentColor] = [
|
||||
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x007aff, bubbleColors: (0x007aff, 0xff53f4), wallpaper: nil),
|
||||
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0x00b09b, bubbleColors: (0xaee946, 0x00b09b), wallpaper: nil),
|
||||
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xd33213, bubbleColors: (0xf9db00, 0xd33213), wallpaper: nil),
|
||||
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xea8ced, bubbleColors: (0xea8ced, 0x00c2ed), wallpaper: nil)
|
||||
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x007aff, bubbleColors: (0x007aff, 0xff53f4), wallpaper: patternWallpaper(data: .variant4, colors: [0xe4b2ea, 0x8376c2, 0xeab9d9, 0xb493e6], intensity: -35, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0x00b09b, bubbleColors: (0xaee946, 0x00b09b), wallpaper: patternWallpaper(data: .variant9, colors: [0xe4b2ea, 0x8376c2, 0xeab9d9, 0xb493e6], intensity: -35, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xd33213, bubbleColors: (0xf9db00, 0xd33213), wallpaper: patternWallpaper(data: .variant2, colors: [0xfec496, 0xdd6cb9, 0x962fbf, 0x4f5bd5], intensity: -40, rotation: nil)),
|
||||
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xea8ced, bubbleColors: (0xea8ced, 0x00c2ed), wallpaper: patternWallpaper(data: .variant6, colors: [0x8adbf2, 0x888dec, 0xe39fea, 0x679ced], intensity: -30, rotation: nil))
|
||||
]
|
||||
|
@ -549,6 +549,10 @@ private final class ThemeSettingsControllerImpl: ItemListController, ThemeSettin
|
||||
}
|
||||
|
||||
public func themeSettingsController(context: AccountContext, focusOnItemTag: ThemeSettingsEntryTag? = nil) -> ViewController {
|
||||
#if DEBUG
|
||||
BuiltinWallpaperData.generate(account: context.account)
|
||||
#endif
|
||||
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
var updateControllersImpl: ((([UIViewController]) -> [UIViewController]) -> Void)?
|
||||
@ -844,14 +848,14 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
if let accentColor = accentColor, case let .theme(themeReference) = accentColor {
|
||||
theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference)
|
||||
} else {
|
||||
var wallpaperGradientColors: [UInt32]?
|
||||
var baseColor: PresentationThemeBaseColor?
|
||||
switch accentColor {
|
||||
case let .accentColor(value):
|
||||
wallpaperGradientColors = value.baseColor.wallpaperGradientColors
|
||||
baseColor = value.baseColor
|
||||
default:
|
||||
break
|
||||
}
|
||||
theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.accentColor, bubbleColors: accentColor?.customBubbleColors, wallpaper: accentColor?.wallpaper, wallpaperGradientColors: wallpaperGradientColors)
|
||||
theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.accentColor, bubbleColors: accentColor?.customBubbleColors, wallpaper: accentColor?.wallpaper, baseColor: baseColor)
|
||||
}
|
||||
effectiveWallpaper = theme?.chat.defaultWallpaper ?? .builtin(WallpaperSettings())
|
||||
}
|
||||
@ -1252,21 +1256,9 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
|> mapToSignal { cachedWallpaper in
|
||||
if let wallpaper = cachedWallpaper?.wallpaper, case let .file(file) = wallpaper {
|
||||
let resource = file.file.resource
|
||||
let representation = CachedPatternWallpaperRepresentation(colors: file.settings.colors.count >= 1 ? file.settings.colors : [0xd6e2ee], intensity: file.settings.intensity ?? 50, rotation: file.settings.rotation)
|
||||
|
||||
let _ = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)).start()
|
||||
|
||||
let _ = (context.account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: false, fetch: true)
|
||||
|> filter({ $0.complete })).start(next: { data in
|
||||
if data.complete, let path = context.account.postbox.mediaBox.completedResourcePath(resource) {
|
||||
if let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: maybeData, synchronous: true)
|
||||
}
|
||||
if let maybeData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: .mappedRead) {
|
||||
context.sharedContext.accountManager.mediaBox.storeCachedResourceRepresentation(resource, representation: representation, data: maybeData)
|
||||
}
|
||||
}
|
||||
})
|
||||
return .single(wallpaper)
|
||||
|
||||
} else {
|
||||
@ -1301,7 +1293,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
updatedTheme = generalThemeReference
|
||||
}
|
||||
|
||||
guard let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.color, wallpaper: presetWallpaper, wallpaperGradientColors: accentColor?.baseColor.wallpaperGradientColors) else {
|
||||
guard let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.color, wallpaper: presetWallpaper, baseColor: accentColor?.baseColor) else {
|
||||
return current
|
||||
}
|
||||
|
||||
|
@ -516,8 +516,6 @@ public class WallpaperGalleryController: ViewController {
|
||||
}
|
||||
} else if case let .file(file) = wallpaper, let resource = resource {
|
||||
if wallpaper.isPattern, !file.settings.colors.isEmpty, let intensity = file.settings.intensity {
|
||||
let representation = CachedPatternWallpaperRepresentation(colors: file.settings.colors, intensity: intensity, rotation: file.settings.rotation)
|
||||
|
||||
var data: Data?
|
||||
var thumbnailData: Data?
|
||||
if let path = strongSelf.context.account.postbox.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
@ -541,12 +539,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
if let thumbnailResource = thumbnailResource, let thumbnailData = thumbnailData {
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData, synchronous: true)
|
||||
}
|
||||
let _ = (strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true)
|
||||
|> filter({ $0.complete })
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
completion(wallpaper)
|
||||
})
|
||||
completion(wallpaper)
|
||||
}
|
||||
} else if let path = strongSelf.context.account.postbox.mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data)
|
||||
|
@ -72,11 +72,11 @@ class WallpaperGalleryItem: GalleryItem {
|
||||
private let progressDiameter: CGFloat = 50.0
|
||||
private let motionAmount: CGFloat = 32.0
|
||||
|
||||
private func reference(for resource: MediaResource, media: Media, message: Message?) -> MediaResourceReference {
|
||||
private func reference(for resource: MediaResource, media: Media, message: Message?, slug: String?) -> MediaResourceReference {
|
||||
if let message = message {
|
||||
return .media(media: .message(message: MessageReference(message), media: media), resource: resource)
|
||||
}
|
||||
return .wallpaper(wallpaper: nil, resource: resource)
|
||||
return .wallpaper(wallpaper: slug.flatMap(WallpaperReference.slug), resource: resource)
|
||||
}
|
||||
|
||||
final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
@ -382,9 +382,9 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
||||
for representation in file.file.previewRepresentations {
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: reference(for: representation.resource, media: file.file, message: message)))
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: reference(for: representation.resource, media: file.file, message: message, slug: file.slug)))
|
||||
}
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: reference(for: file.file.resource, media: file.file, message: message)))
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: reference(for: file.file.resource, media: file.file, message: message, slug: file.slug)))
|
||||
|
||||
if wallpaper.isPattern {
|
||||
var patternColors: [UIColor] = []
|
||||
@ -407,32 +407,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
self.backgroundColor = patternColor.withAlphaComponent(1.0)
|
||||
|
||||
/*if let previousEntry = previousEntry, case let .wallpaper(wallpaper, _) = previousEntry, case let .file(previousFile) = wallpaper, file.id == previousFile.id && (file.settings.colors != previousFile.settings.colors || file.settings.intensity != previousFile.settings.intensity) && self.colorPreview == self.arguments.colorPreview {
|
||||
|
||||
let makeImageLayout = self.imageNode.asyncLayout()
|
||||
Queue.concurrentDefaultQueue().async {
|
||||
let apply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), custom: patternArguments))
|
||||
Queue.mainQueue().async {
|
||||
if self.colorPreview {
|
||||
apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
} else if let offset = self.validOffset, self.arguments.colorPreview && abs(offset) > 0.0 {
|
||||
return
|
||||
} else {
|
||||
patternArguments = PatternWallpaperArguments(colors: patternColors, rotation: file.settings.rotation)
|
||||
}*/
|
||||
|
||||
self.colorPreview = self.arguments.colorPreview
|
||||
|
||||
signal = .single({ _ in nil })
|
||||
/*if file.settings.colors.count >= 3 {
|
||||
signal = .single({ _ in nil })
|
||||
} else {
|
||||
signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
|
||||
}*/
|
||||
|
||||
colorSignal = chatServiceBackgroundColor(wallpaper: wallpaper, mediaBox: self.context.account.postbox.mediaBox)
|
||||
|
||||
isBlurrable = false
|
||||
@ -855,12 +833,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
|
||||
private func preparePatternEditing() {
|
||||
if let entry = self.entry, case let .wallpaper(wallpaper, _) = entry, case let .file(file) = wallpaper {
|
||||
let dimensions = file.file.dimensions ?? PixelDimensions(width: 1440, height: 2960)
|
||||
|
||||
let size = dimensions.cgSize.fitted(CGSize(width: 1280.0, height: 1280.0))
|
||||
let _ = self.context.account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start()
|
||||
}
|
||||
}
|
||||
|
||||
func setMotionEnabled(_ enabled: Bool, animated: Bool) {
|
||||
|
@ -29,7 +29,7 @@ private func intensityToSliderValue(_ value: Int32, allowDark: Bool) -> CGFloat
|
||||
private func sliderValueToIntensity(_ value: CGFloat, allowDark: Bool) -> Int32 {
|
||||
if allowDark {
|
||||
if value < 100.0 {
|
||||
return -Int32(value)
|
||||
return -Int32(max(1.0, value))
|
||||
} else {
|
||||
return Int32(value - 100.0)
|
||||
}
|
||||
|
14
submodules/SvgRendering/BUILD
Normal file
14
submodules/SvgRendering/BUILD
Normal file
@ -0,0 +1,14 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "SvgRendering",
|
||||
module_name = "SvgRendering",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
0
submodules/SvgRendering/Sources/SvgParser.swift
Normal file
0
submodules/SvgRendering/Sources/SvgParser.swift
Normal file
@ -5411,6 +5411,21 @@ public extension Api {
|
||||
})
|
||||
}
|
||||
|
||||
public static func resetBotCommands(scope: Api.BotCommandScope, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1032708345)
|
||||
scope.serialize(buffer, true)
|
||||
serializeString(langCode, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "bots.resetBotCommands", parameters: [("scope", scope), ("langCode", langCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func getBotCommands(scope: Api.BotCommandScope, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.BotCommand]>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-481554986)
|
||||
|
@ -370,13 +370,15 @@ public struct TwoStepAuthData {
|
||||
public let unconfirmedEmailPattern: String?
|
||||
public let secretRandom: Data
|
||||
public let nextSecurePasswordDerivation: TwoStepSecurePasswordDerivation
|
||||
public let pendingResetTimestamp: Int32?
|
||||
}
|
||||
|
||||
public func twoStepAuthData(_ network: Network) -> Signal<TwoStepAuthData, MTRpcError> {
|
||||
return network.request(Api.functions.account.getPassword())
|
||||
|> map { config -> TwoStepAuthData in
|
||||
switch config {
|
||||
case let .password(flags, currentAlgo, srpB, srpId, hint, emailUnconfirmedPattern, newAlgo, newSecureAlgo, secureRandom):
|
||||
case let .password(flags, currentAlgo, srpB, srpId, hint, emailUnconfirmedPattern, newAlgo, newSecureAlgo, secureRandom/*, pendingResetDate*/):
|
||||
let pendingResetDate: Int32? = nil
|
||||
let hasRecovery = (flags & (1 << 0)) != 0
|
||||
let hasSecureValues = (flags & (1 << 1)) != 0
|
||||
|
||||
@ -398,7 +400,7 @@ public func twoStepAuthData(_ network: Network) -> Signal<TwoStepAuthData, MTRpc
|
||||
srpSessionData = TwoStepSRPSessionData(id: srpId, B: srpB.makeData())
|
||||
}
|
||||
|
||||
return TwoStepAuthData(nextPasswordDerivation: nextDerivation, currentPasswordDerivation: currentDerivation, srpSessionData: srpSessionData, hasRecovery: hasRecovery, hasSecretValues: hasSecureValues, currentHint: hint, unconfirmedEmailPattern: emailUnconfirmedPattern, secretRandom: secureRandom.makeData(), nextSecurePasswordDerivation: nextSecureDerivation)
|
||||
return TwoStepAuthData(nextPasswordDerivation: nextDerivation, currentPasswordDerivation: currentDerivation, srpSessionData: srpSessionData, hasRecovery: hasRecovery, hasSecretValues: hasSecureValues, currentHint: hint, unconfirmedEmailPattern: emailUnconfirmedPattern, secretRandom: secureRandom.makeData(), nextSecurePasswordDerivation: nextSecureDerivation, pendingResetTimestamp: pendingResetDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -370,6 +370,7 @@ public enum PasswordRecoveryError {
|
||||
case invalidCode
|
||||
case limitExceeded
|
||||
case expired
|
||||
case generic
|
||||
}
|
||||
|
||||
public func performPasswordRecovery(accountManager: AccountManager, account: UnauthorizedAccount, code: String, syncContacts: Bool) -> Signal<Void, PasswordRecoveryError> {
|
||||
@ -406,6 +407,81 @@ public func performPasswordRecovery(accountManager: AccountManager, account: Una
|
||||
}
|
||||
}
|
||||
|
||||
/*public func checkPasswordRecoveryCode(network: Network, code: String) -> Signal<Never, PasswordRecoveryError> {
|
||||
return network.request(Api.functions.auth.checkRecoveryPassword(code: code), automaticFloodWait: false)
|
||||
|> mapError { error -> PasswordRecoveryError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .limitExceeded
|
||||
} else if error.errorDescription.hasPrefix("PASSWORD_RECOVERY_EXPIRED") {
|
||||
return .expired
|
||||
} else {
|
||||
return .invalidCode
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, PasswordRecoveryError> in
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
public func performPasswordRecovery(accountManager: AccountManager, account: UnauthorizedAccount, code: String, syncContacts: Bool, updatedPassword: UpdatedTwoStepVerificationPassword) -> Signal<Void, PasswordRecoveryError> {
|
||||
return twoStepAuthData(account.network)
|
||||
|> mapError { _ -> PasswordRecoveryError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { authData -> Signal<Void, PasswordRecoveryError> in
|
||||
let newSettings: Api.account.PasswordInputSettings?
|
||||
switch updatedPassword {
|
||||
case .none:
|
||||
newSettings = nil
|
||||
case let .password(password, hint, email):
|
||||
var flags: Int32 = 1 << 0
|
||||
if email != nil {
|
||||
flags |= (1 << 1)
|
||||
}
|
||||
|
||||
guard let (updatedPasswordHash, updatedPasswordDerivation) = passwordUpdateKDF(encryptionProvider: account.network.encryptionProvider, password: password, derivation: authData.nextPasswordDerivation) else {
|
||||
return .fail(.invalidCode)
|
||||
}
|
||||
|
||||
newSettings = Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newAlgo: updatedPasswordDerivation.apiAlgo, newPasswordHash: Buffer(data: updatedPasswordHash), hint: hint, email: email, newSecureSettings: nil)
|
||||
}
|
||||
|
||||
var flags: Int32 = 0
|
||||
if newSettings != nil {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
return account.network.request(Api.functions.auth.recoverPassword(flags: flags, code: code, newSettings: newSettings), automaticFloodWait: false)
|
||||
|> mapError { error -> PasswordRecoveryError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .limitExceeded
|
||||
} else if error.errorDescription.hasPrefix("PASSWORD_RECOVERY_EXPIRED") {
|
||||
return .expired
|
||||
} else {
|
||||
return .invalidCode
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, PasswordRecoveryError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
switch result {
|
||||
case let .authorization(_, _, user):
|
||||
let user = TelegramUser(user: user)
|
||||
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
|
||||
|
||||
initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts)
|
||||
transaction.setState(state)
|
||||
return accountManager.transaction { transaction -> Void in
|
||||
switchToAuthorizedAccount(transaction: transaction, account: account)
|
||||
}
|
||||
case .authorizationSignUpRequired:
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|> switchToLatest
|
||||
|> mapError { _ -> PasswordRecoveryError in }
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
public enum AccountResetError {
|
||||
case generic
|
||||
case limitExceeded
|
||||
|
@ -69,6 +69,19 @@ public func stickerPackFileReference(_ file: TelegramMediaFile) -> FileMediaRefe
|
||||
return .standalone(media: file)
|
||||
}
|
||||
|
||||
private func areResourcesEqual(_ lhs: MediaResource, _ rhs: MediaResource) -> Bool {
|
||||
if let lhsResource = lhs as? CloudDocumentMediaResource, let rhsResource = rhs as? CloudDocumentMediaResource {
|
||||
if lhsResource.fileId == rhsResource.fileId {
|
||||
return true
|
||||
}
|
||||
} else if let lhsResource = lhs as? CloudDocumentSizeMediaResource, let rhsResource = rhs as? CloudDocumentSizeMediaResource {
|
||||
if lhsResource.documentId == rhsResource.documentId && lhsResource.sizeSpec == rhsResource.sizeSpec {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return lhs.id.isEqual(to: rhs.id)
|
||||
}
|
||||
|
||||
private func findMediaResource(media: Media, previousMedia: Media?, resource: MediaResource) -> TelegramMediaResource? {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
for representation in image.representations {
|
||||
@ -87,11 +100,11 @@ private func findMediaResource(media: Media, previousMedia: Media?, resource: Me
|
||||
}
|
||||
}
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
if file.resource.id.isEqual(to: resource.id) {
|
||||
if areResourcesEqual(file.resource, resource) {
|
||||
return file.resource
|
||||
} else {
|
||||
for representation in file.previewRepresentations {
|
||||
if representation.resource.id.isEqual(to: resource.id) {
|
||||
if areResourcesEqual(representation.resource, resource) {
|
||||
return representation.resource
|
||||
}
|
||||
}
|
||||
@ -387,7 +400,13 @@ final class MediaReferenceRevalidationContext {
|
||||
}
|
||||
|
||||
func wallpapers(postbox: Postbox, network: Network, background: Bool, wallpaper: WallpaperReference?) -> Signal<[TelegramWallpaper], RevalidateMediaReferenceError> {
|
||||
return self.genericItem(key: .wallpapers, background: background, request: { next, error in
|
||||
let key: MediaReferenceRevalidationKey
|
||||
if let wallpaper = wallpaper {
|
||||
key = .wallpaper(wallpaper: wallpaper)
|
||||
} else {
|
||||
key = .wallpapers
|
||||
}
|
||||
return self.genericItem(key: key, background: background, request: { next, error in
|
||||
let signal: Signal<[TelegramWallpaper]?, RevalidateMediaReferenceError>
|
||||
if let wallpaper = wallpaper, case let .slug(slug) = wallpaper {
|
||||
signal = getWallpaper(network: network, slug: slug)
|
||||
@ -399,7 +418,6 @@ final class MediaReferenceRevalidationContext {
|
||||
signal = telegramWallpapers(postbox: postbox, network: network, forceUpdate: true)
|
||||
|> last
|
||||
|> mapError { _ -> RevalidateMediaReferenceError in
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
return (signal
|
||||
|
@ -8,7 +8,7 @@ import SyncCore
|
||||
|
||||
public enum TwoStepVerificationConfiguration {
|
||||
case notSet(pendingEmail: TwoStepVerificationPendingEmail?)
|
||||
case set(hint: String, hasRecoveryEmail: Bool, pendingEmail: TwoStepVerificationPendingEmail?, hasSecureValues: Bool)
|
||||
case set(hint: String, hasRecoveryEmail: Bool, pendingEmail: TwoStepVerificationPendingEmail?, hasSecureValues: Bool, pendingResetTimestamp: Int32?)
|
||||
}
|
||||
|
||||
public func twoStepVerificationConfiguration(account: Account) -> Signal<TwoStepVerificationConfiguration, NoError> {
|
||||
@ -18,7 +18,7 @@ public func twoStepVerificationConfiguration(account: Account) -> Signal<TwoStep
|
||||
switch result {
|
||||
case let .password(password):
|
||||
if password.currentAlgo != nil {
|
||||
return .set(hint: password.hint ?? "", hasRecoveryEmail: (password.flags & (1 << 0)) != 0, pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }), hasSecureValues: (password.flags & (1 << 1)) != 0)
|
||||
return .set(hint: password.hint ?? "", hasRecoveryEmail: (password.flags & (1 << 0)) != 0, pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }), hasSecureValues: (password.flags & (1 << 1)) != 0, pendingResetTimestamp: nil/*password.pendingResetDate*/)
|
||||
} else {
|
||||
return .notSet(pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }))
|
||||
}
|
||||
@ -335,21 +335,32 @@ public enum RecoverTwoStepVerificationPasswordError {
|
||||
}
|
||||
|
||||
public func recoverTwoStepVerificationPassword(network: Network, code: String) -> Signal<Void, RecoverTwoStepVerificationPasswordError> {
|
||||
return network.request(Api.functions.auth.recoverPassword(code: code), automaticFloodWait: false)
|
||||
|> mapError { error -> RecoverTwoStepVerificationPasswordError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT_") {
|
||||
return .limitExceeded
|
||||
} else if error.errorDescription == "PASSWORD_RECOVERY_EXPIRED" {
|
||||
return .codeExpired
|
||||
} else if error.errorDescription == "CODE_INVALID" {
|
||||
return .invalidCode
|
||||
} else {
|
||||
return .generic
|
||||
return twoStepAuthData(network)
|
||||
|> mapError { _ -> RecoverTwoStepVerificationPasswordError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { authData -> Signal<Void, RecoverTwoStepVerificationPasswordError> in
|
||||
var flags: Int32 = (1 << 1)
|
||||
if authData.currentPasswordDerivation != nil {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
|
||||
return network.request(Api.functions.auth.recoverPassword(code: code), automaticFloodWait: false)
|
||||
|> mapError { error -> RecoverTwoStepVerificationPasswordError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT_") {
|
||||
return .limitExceeded
|
||||
} else if error.errorDescription == "PASSWORD_RECOVERY_EXPIRED" {
|
||||
return .codeExpired
|
||||
} else if error.errorDescription == "CODE_INVALID" {
|
||||
return .invalidCode
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, RecoverTwoStepVerificationPasswordError> in
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, RecoverTwoStepVerificationPasswordError> in
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func cachedTwoStepPasswordToken(postbox: Postbox) -> Signal<TemporaryTwoStepPasswordToken?, NoError> {
|
||||
@ -402,3 +413,53 @@ public func requestTemporaryTwoStepPasswordToken(account: Account, password: Str
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum RequestTwoStepPasswordResetResult {
|
||||
public enum ErrorReason {
|
||||
case generic
|
||||
case limitExceeded
|
||||
}
|
||||
|
||||
case done
|
||||
case waitingForReset(resetAtTimestamp: Int32)
|
||||
case declined
|
||||
case error(reason: ErrorReason)
|
||||
}
|
||||
|
||||
/*public func requestTwoStepPasswordReset(network: Network) -> Signal<RequestTwoStepPasswordResetResult, NoError> {
|
||||
return network.request(Api.functions.account.resetPassword(), automaticFloodWait: false)
|
||||
|> map { _ -> RequestTwoStepPasswordResetResult in
|
||||
return .done
|
||||
}
|
||||
|> `catch` { error -> Signal<RequestTwoStepPasswordResetResult, NoError> in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .single(.error(reason: .limitExceeded))
|
||||
} else if error.errorDescription.hasPrefix("RESET_WAIT_") {
|
||||
if let remainingSeconds = Int32(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "RESET_WAIT_".count)...]) {
|
||||
let timestamp = Int32(network.globalTime)
|
||||
return .single(.waitingForReset(resetAtTimestamp: timestamp + remainingSeconds))
|
||||
} else {
|
||||
return .single(.error(reason: .generic))
|
||||
}
|
||||
} else if error.errorDescription.hasPrefix("RESET_PREVIOUS_WAIT_") {
|
||||
if let remainingSeconds = Int32(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "RESET_PREVIOUS_WAIT_".count)...]) {
|
||||
let timestamp = Int32(network.globalTime)
|
||||
return .single(.waitingForReset(resetAtTimestamp: timestamp + remainingSeconds))
|
||||
} else {
|
||||
return .single(.error(reason: .generic))
|
||||
}
|
||||
} else if error.errorDescription == "RESET_PREVIOUS_DECLINE" {
|
||||
return .single(.declined)
|
||||
} else {
|
||||
return .single(.error(reason: .generic))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func declineTwoStepPasswordReset(network: Network) -> Signal<Never, NoError> {
|
||||
return network.request(Api.functions.account.declinePasswordReset())
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> ignoreValues
|
||||
}*/
|
||||
|
@ -74,14 +74,8 @@ public func chatControllerBackgroundImage(theme: PresentationTheme?, wallpaper i
|
||||
}
|
||||
}
|
||||
case let .file(file):
|
||||
if wallpaper.isPattern, !file.settings.colors.isEmpty, let intensity = file.settings.intensity {
|
||||
var image: UIImage?
|
||||
let _ = mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperRepresentation(colors: file.settings.colors, intensity: intensity, rotation: file.settings.rotation), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in
|
||||
if data.complete {
|
||||
image = UIImage(contentsOfFile: data.path)?.precomposed()
|
||||
}
|
||||
})
|
||||
backgroundImage = image
|
||||
if wallpaper.isPattern {
|
||||
backgroundImage = nil
|
||||
} else {
|
||||
if file.settings.blur && composed {
|
||||
var image: UIImage?
|
||||
@ -174,55 +168,8 @@ public func chatControllerBackgroundImageSignal(wallpaper: TelegramWallpaper, me
|
||||
}
|
||||
}
|
||||
case let .file(file):
|
||||
if wallpaper.isPattern, !file.settings.colors.isEmpty, let intensity = file.settings.intensity {
|
||||
let representation = CachedPatternWallpaperRepresentation(colors: file.settings.colors, intensity: intensity, rotation: file.settings.rotation)
|
||||
|
||||
let effectiveMediaBox: MediaBox
|
||||
if FileManager.default.fileExists(atPath: mediaBox.cachedRepresentationCompletePath(file.file.resource.id, representation: representation)) {
|
||||
effectiveMediaBox = mediaBox
|
||||
} else {
|
||||
effectiveMediaBox = accountMediaBox
|
||||
}
|
||||
|
||||
return effectiveMediaBox.cachedResourceRepresentation(file.file.resource, representation: representation, complete: true, fetch: true, attemptSynchronously: true)
|
||||
|> take(1)
|
||||
|> mapToSignal { data -> Signal<(UIImage?, Bool)?, NoError> in
|
||||
if data.complete {
|
||||
return .single((UIImage(contentsOfFile: data.path)?.precomposed(), true))
|
||||
} else {
|
||||
let interimWallpaper: TelegramWallpaper
|
||||
if file.settings.colors.count >= 2 {
|
||||
interimWallpaper = .gradient(nil, file.settings.colors, file.settings)
|
||||
} else {
|
||||
interimWallpaper = .color(file.settings.colors.count >= 1 ? file.settings.colors[0] : 0)
|
||||
}
|
||||
|
||||
let settings = file.settings
|
||||
let interrimImage = generateImage(CGSize(width: 640.0, height: 1280.0), rotatedContext: { size, context in
|
||||
if file.settings.colors.count >= 1 {
|
||||
let gradientColors = [UIColor(argb: file.settings.colors[0]).cgColor, UIColor(argb: file.settings.colors.count >= 2 ? file.settings.colors[1] : file.settings.colors[0]).cgColor] as CFArray
|
||||
|
||||
var locations: [CGFloat] = [0.0, 1.0]
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
context.translateBy(x: 320.0, y: 640.0)
|
||||
context.rotate(by: CGFloat(settings.rotation ?? 0) * CGFloat.pi / 180.0)
|
||||
context.translateBy(x: -320.0, y: -640.0)
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
||||
}
|
||||
})
|
||||
|
||||
return .single((interrimImage, false)) |> then(effectiveMediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperRepresentation(colors: file.settings.colors, intensity: intensity, rotation: file.settings.rotation), complete: true, fetch: true, attemptSynchronously: false)
|
||||
|> map { data -> (UIImage?, Bool)? in
|
||||
return (UIImage(contentsOfFile: data.path)?.precomposed(), true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|> afterNext { image in
|
||||
cacheWallpaper(image?.0)
|
||||
}
|
||||
if wallpaper.isPattern {
|
||||
return .single((nil, true))
|
||||
} else {
|
||||
if file.settings.blur {
|
||||
let representation = CachedBlurredWallpaperRepresentation()
|
||||
|
@ -5,9 +5,56 @@ import SyncCore
|
||||
import TelegramUIPreferences
|
||||
|
||||
public let defaultDarkPresentationTheme = makeDefaultDarkPresentationTheme(preview: false)
|
||||
public let defaultDarkColorPresentationTheme = customizeDefaultDarkPresentationTheme(theme: defaultDarkPresentationTheme, editing: false, title: nil, accentColor: UIColor(rgb: 0x007aff), backgroundColors: [], bubbleColors: nil, wallpaper: nil)
|
||||
public let defaultDarkColorPresentationTheme = customizeDefaultDarkPresentationTheme(theme: defaultDarkPresentationTheme, editing: false, title: nil, accentColor: UIColor(rgb: 0x007aff), backgroundColors: [], bubbleColors: nil, wallpaper: nil, baseColor: nil)
|
||||
|
||||
public func customizeDefaultDarkPresentationTheme(theme: PresentationTheme, editing: Bool, title: String?, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: (UIColor, UIColor?)?, wallpaper forcedWallpaper: TelegramWallpaper? = nil) -> PresentationTheme {
|
||||
private extension PresentationThemeBaseColor {
|
||||
/*
|
||||
|
||||
Оранжевая с красным
|
||||
https://t.me/bg/9LW_RcoOSVACAAAAFTk3DTyXN-M?bg_color=fec496~dd6cb9~962fbf~4f5bd5&intensity=-40
|
||||
|
||||
Голубая с розовым
|
||||
https://t.me/bg/9iklpvIPQVABAAAAORQXKur_Eyc?bg_color=8adbf2~888dec~e39fea~679ced&intensity=-30
|
||||
|
||||
Мятная
|
||||
https://t.me/bg/CJNyxPMgSVAEAAAAvW9sMwc51cw?bg_color=7fa381~fff5c5~336f55~fbe37d&intensity=-20
|
||||
|
||||
Синяя с розовым
|
||||
https://t.me/bg/9LW_RcoOSVACAAAAFTk3DTyXN-M?bg_color=fec496~dd6cb9~962fbf~4f5bd5&intensity=-40
|
||||
|
||||
*/
|
||||
|
||||
var colorWallpaper: (BuiltinWallpaperData, Int32, [UInt32])? {
|
||||
switch self {
|
||||
case .blue:
|
||||
return nil
|
||||
case .cyan:
|
||||
return (.variant5, -30, [0xa4dbff, 0x009fdd, 0x527bdd])
|
||||
case .green:
|
||||
return (.variant3, -20, [0x7fa381, 0xfff5c5, 0x336f55, 0xfbe37d])
|
||||
case .pink:
|
||||
return (.variant9, -35, [0xe4b2ea, 0x8376c2, 0xeab9d9, 0xb493e6])
|
||||
case .orange:
|
||||
return (.variant2, -40, [0xfec496, 0xdd6cb9, 0x962fbf, 0x4f5bd5])
|
||||
case .purple:
|
||||
return (.variant6, -30, [0x8adbf2, 0x888dec, 0xe39fea, 0x679ced])
|
||||
case .red:
|
||||
return (.variant4, -35, [0xe4b2ea, 0x8376c2, 0xeab9d9, 0xb493e6])
|
||||
case .yellow:
|
||||
return (.variant1, -30, [0xeaa36e, 0xf0e486, 0xf29ebf, 0xe8c06e])
|
||||
case .gray:
|
||||
return nil
|
||||
case .black:
|
||||
return nil
|
||||
case .white:
|
||||
return nil
|
||||
case .custom, .preset, .theme:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func customizeDefaultDarkPresentationTheme(theme: PresentationTheme, editing: Bool, title: String?, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: (UIColor, UIColor?)?, wallpaper forcedWallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil) -> PresentationTheme {
|
||||
if (theme.referenceTheme != .night) {
|
||||
return theme
|
||||
}
|
||||
@ -82,6 +129,8 @@ public func customizeDefaultDarkPresentationTheme(theme: PresentationTheme, edit
|
||||
var defaultWallpaper: TelegramWallpaper?
|
||||
if let forcedWallpaper = forcedWallpaper {
|
||||
defaultWallpaper = forcedWallpaper
|
||||
} else if let baseColor = baseColor, let (variant, intensity, colors) = baseColor.colorWallpaper, !colors.isEmpty {
|
||||
defaultWallpaper = defaultBuiltinWallpaper(data: variant, colors: colors, intensity: intensity)
|
||||
} else if !backgroundColors.isEmpty {
|
||||
if backgroundColors.count >= 2 {
|
||||
defaultWallpaper = .gradient(nil, backgroundColors, WallpaperSettings())
|
||||
|
@ -8,7 +8,38 @@ import Postbox
|
||||
private let defaultDarkTintedAccentColor = UIColor(rgb: 0x2ea6ff)
|
||||
public let defaultDarkTintedPresentationTheme = makeDefaultDarkTintedPresentationTheme(preview: false)
|
||||
|
||||
public func customizeDefaultDarkTintedPresentationTheme(theme: PresentationTheme, editing: Bool, title: String?, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: (UIColor, UIColor?)?, wallpaper forcedWallpaper: TelegramWallpaper? = nil, wallpaperGradientColors: [UInt32]? = nil) -> PresentationTheme {
|
||||
private extension PresentationThemeBaseColor {
|
||||
var colorWallpaper: (BuiltinWallpaperData, Int32, [UInt32])? {
|
||||
switch self {
|
||||
case .blue:
|
||||
return (.variant7, 40, [0x1e3557, 0x182036, 0x1c4352, 0x16263a])
|
||||
case .cyan:
|
||||
return (.variant3, 40, [0x1e3557, 0x151a36, 0x1c4352, 0x2a4541])
|
||||
case .green:
|
||||
return (.variant3, 40, [0x2d4836, 0x172b19, 0x364331, 0x103231])
|
||||
case .pink:
|
||||
return (.variant9, 40, [0x2c0b22, 0x290020, 0x160a22, 0x3b1834])
|
||||
case .orange:
|
||||
return (.variant10, 40, [0x2c211b, 0x442917, 0x22191f, 0x3b2714])
|
||||
case .purple:
|
||||
return (.variant11, 40, [0x3a1c3a, 0x24193c, 0x392e3e, 0x1a1632])
|
||||
case .red:
|
||||
return (.variant4, 40, [0x2c211b, 0x44332a, 0x22191f, 0x3b2d36])
|
||||
case .yellow:
|
||||
return (.variant2, 40, [0x2c2512, 0x45360b, 0x221d08, 0x3b2f13])
|
||||
case .gray:
|
||||
return (.variant6, 40, [0x1c2731, 0x1a1c25, 0x27303b, 0x1b1b21])
|
||||
case .black:
|
||||
return nil
|
||||
case .white:
|
||||
return nil
|
||||
case .custom, .preset, .theme:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func customizeDefaultDarkTintedPresentationTheme(theme: PresentationTheme, editing: Bool, title: String?, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: (UIColor, UIColor?)?, wallpaper forcedWallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil) -> PresentationTheme {
|
||||
if (theme.referenceTheme != .nightAccent) {
|
||||
return theme
|
||||
}
|
||||
@ -47,8 +78,8 @@ public func customizeDefaultDarkTintedPresentationTheme(theme: PresentationTheme
|
||||
var bubbleColors = bubbleColors
|
||||
if bubbleColors == nil, editing {
|
||||
if let accentColor = accentColor {
|
||||
if let wallpaperGradientColors = wallpaperGradientColors, !wallpaperGradientColors.isEmpty {
|
||||
suggestedWallpaper = defaultBuiltinWallpaper(colors: wallpaperGradientColors)
|
||||
if let baseColor = baseColor, let (variant, intensity, colors) = baseColor.colorWallpaper, !colors.isEmpty {
|
||||
suggestedWallpaper = defaultBuiltinWallpaper(data: variant, colors: colors, intensity: intensity)
|
||||
} else {
|
||||
let color = accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18)
|
||||
suggestedWallpaper = .color(color.argb)
|
||||
@ -757,7 +788,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
|
||||
)
|
||||
|
||||
let chat = PresentationThemeChat(
|
||||
defaultWallpaper: defaultBuiltinWallpaper(colors: [0x1b2836, 0x121a22, 0x1b2836, 0x121a22]),
|
||||
defaultWallpaper: defaultBuiltinWallpaper(data: .default, colors: [0x1b2836, 0x121a22, 0x1b2836, 0x121a22]),
|
||||
message: message,
|
||||
serviceMessage: serviceMessage,
|
||||
inputPanel: inputPanel,
|
||||
|
@ -4,6 +4,7 @@ import TelegramCore
|
||||
import SyncCore
|
||||
import TelegramUIPreferences
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
|
||||
public func selectDateFillStaticColor(theme: PresentationTheme, wallpaper: TelegramWallpaper) -> UIColor {
|
||||
if case .color(0xffffff) = wallpaper {
|
||||
@ -738,7 +739,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
||||
badgeTextColor: UIColor(rgb: 0xffffff)
|
||||
)
|
||||
|
||||
let defaultPatternWallpaper: TelegramWallpaper = defaultBuiltinWallpaper(colors: defaultBuiltinWallpaperGradientColors.map(\.rgb))
|
||||
let defaultPatternWallpaper: TelegramWallpaper = defaultBuiltinWallpaper(data: .default, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb))
|
||||
|
||||
let chat = PresentationThemeChat(
|
||||
defaultWallpaper: day ? .color(0xffffff) : defaultPatternWallpaper,
|
||||
@ -842,23 +843,235 @@ public let defaultBuiltinWallpaperGradientColors: [UIColor] = [
|
||||
UIColor(rgb: 0x88b884)
|
||||
]
|
||||
|
||||
public func defaultBuiltinWallpaper(colors: [UInt32], intensity: Int32 = 50, rotation: Int32? = nil) -> TelegramWallpaper {
|
||||
public struct BuiltinWallpaperData {
|
||||
var wallpaperId: Int64
|
||||
var wallpaperAccessHash: Int64
|
||||
var slug: String
|
||||
var fileId: Int64
|
||||
var fileAccessHash: Int64
|
||||
var datacenterId: Int
|
||||
var fileSize: Int
|
||||
}
|
||||
|
||||
public extension BuiltinWallpaperData {
|
||||
static let `default` = BuiltinWallpaperData(
|
||||
wallpaperId: 5951821522514477057,
|
||||
wallpaperAccessHash: 542913527008942388,
|
||||
slug: "fqv01SQemVIBAAAApND8LDRUhRU",
|
||||
fileId: 5789658100176783156,
|
||||
fileAccessHash: 2106033778341319685,
|
||||
datacenterId: 4,
|
||||
fileSize: 183832
|
||||
)
|
||||
static let variant1 = BuiltinWallpaperData(
|
||||
wallpaperId: 5784984711902265347,
|
||||
wallpaperAccessHash: -7073897034484875424,
|
||||
slug: "RlZs2PJkSFADAAAAElGaGwgJBgU",
|
||||
fileId: 5924571028763183790,
|
||||
fileAccessHash: 8131740629580593134,
|
||||
datacenterId: 4,
|
||||
fileSize: 175995
|
||||
)
|
||||
static let variant2 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785171457080295426,
|
||||
wallpaperAccessHash: 7299737721761177260,
|
||||
slug: "9LW_RcoOSVACAAAAFTk3DTyXN-M",
|
||||
fileId: 5927041584146156278,
|
||||
fileAccessHash: -5921024951834087382,
|
||||
datacenterId: 4,
|
||||
fileSize: 134539
|
||||
)
|
||||
static let variant3 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785191424383254532,
|
||||
wallpaperAccessHash: 6428855567842967483,
|
||||
slug: "CJNyxPMgSVAEAAAAvW9sMwc51cw",
|
||||
fileId: 5785343895722264360,
|
||||
fileAccessHash: 3407562549390786397,
|
||||
datacenterId: 4,
|
||||
fileSize: 312605
|
||||
)
|
||||
static let variant4 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785123761468473345,
|
||||
wallpaperAccessHash: -6430405714673464374,
|
||||
slug: "BQqgrGnjSFABAAAA8mQDBXQcARE",
|
||||
fileId: 5924847998319201207,
|
||||
fileAccessHash: 6746675725325490532,
|
||||
datacenterId: 4,
|
||||
fileSize: 55699
|
||||
)
|
||||
static let variant5 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785021373743104005,
|
||||
wallpaperAccessHash: -1374597781576365315,
|
||||
slug: "MIo6r0qGSFAFAAAAtL8TsDzNX60",
|
||||
fileId: 5782630687571969871,
|
||||
fileAccessHash: 8944679612701303524,
|
||||
datacenterId: 4,
|
||||
fileSize: 100992
|
||||
)
|
||||
static let variant6 = BuiltinWallpaperData(
|
||||
wallpaperId: 5782920928576929793,
|
||||
wallpaperAccessHash: -2397741670740938317,
|
||||
slug: "9iklpvIPQVABAAAAORQXKur_Eyc",
|
||||
fileId: 5924714386181589959,
|
||||
fileAccessHash: -316419094644368953,
|
||||
datacenterId: 4,
|
||||
fileSize: 106249
|
||||
)
|
||||
static let variant7 = BuiltinWallpaperData(
|
||||
wallpaperId: 5931406765567508492,
|
||||
wallpaperAccessHash: 7991333610111953175,
|
||||
slug: "H6rz6geXUFIMAAAAuUs7m6cXbcc",
|
||||
fileId: 5931433527508732666,
|
||||
fileAccessHash: -8637914243010610774,
|
||||
datacenterId: 4,
|
||||
fileSize: 76332
|
||||
)
|
||||
static let variant8 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785007509588672513,
|
||||
wallpaperAccessHash: 8437532349638900210,
|
||||
slug: "kO4jyq55SFABAAAA0WEpcLfahXk",
|
||||
fileId: 5925009274341165314,
|
||||
fileAccessHash: 5091210796362176800,
|
||||
datacenterId: 4,
|
||||
fileSize: 78338
|
||||
)
|
||||
static let variant9 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785068300555780101,
|
||||
wallpaperAccessHash: -4335874468273472323,
|
||||
slug: "mP3FG_iwSFAFAAAA2AklJO978pA",
|
||||
fileId: 5924664689115007842,
|
||||
fileAccessHash: -4490072684673383370,
|
||||
datacenterId: 4,
|
||||
fileSize: 51705
|
||||
)
|
||||
static let variant10 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785165465600917506,
|
||||
wallpaperAccessHash: 4563443115749434444,
|
||||
slug: "Ujx2TFcJSVACAAAARJ4vLa50MkM",
|
||||
fileId: 5924792752154872619,
|
||||
fileAccessHash: -2210879717040856036,
|
||||
datacenterId: 4,
|
||||
fileSize: 114694
|
||||
)
|
||||
static let variant11 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785225431934304257,
|
||||
wallpaperAccessHash: 3814946612408881045,
|
||||
slug: "RepJ5uE_SVABAAAAr4d0YhgB850",
|
||||
fileId: 5927262354055105101,
|
||||
fileAccessHash: -435932841948252811,
|
||||
datacenterId: 4,
|
||||
fileSize: 66465
|
||||
)
|
||||
static let variant12 = BuiltinWallpaperData(
|
||||
wallpaperId: 5785328386595356675,
|
||||
wallpaperAccessHash: -5900784223259948847,
|
||||
slug: "9GcNVISdSVADAAAAUcw5BYjELW4",
|
||||
fileId: 5926924928539429325,
|
||||
fileAccessHash: -5306472339097647861,
|
||||
datacenterId: 4,
|
||||
fileSize: 57262
|
||||
)
|
||||
static let variant13 = BuiltinWallpaperData(
|
||||
wallpaperId: 6041986402319597570,
|
||||
wallpaperAccessHash: -8909137552203056986,
|
||||
slug: "-Xc-np9y2VMCAAAARKr0yNNPYW0",
|
||||
fileId: 5789856918507882132,
|
||||
fileAccessHash: 2327344847690632249,
|
||||
datacenterId: 4,
|
||||
fileSize: 104932
|
||||
)
|
||||
static let variant14 = BuiltinWallpaperData(
|
||||
wallpaperId: 5784981280223395841,
|
||||
wallpaperAccessHash: 8334701614156015552,
|
||||
slug: "JrNEYdNhSFABAAAA9WtRdJkPRbY",
|
||||
fileId: 5924784243824658746,
|
||||
fileAccessHash: -2563505106174626287,
|
||||
datacenterId: 4,
|
||||
fileSize: 122246
|
||||
)
|
||||
|
||||
static func generate(account: Account) {
|
||||
let slugToName: [(String, String)] = [
|
||||
("fqv01SQemVIBAAAApND8LDRUhRU", "`default`"),
|
||||
("RlZs2PJkSFADAAAAElGaGwgJBgU", "variant1"),
|
||||
("9LW_RcoOSVACAAAAFTk3DTyXN-M", "variant2"),
|
||||
("CJNyxPMgSVAEAAAAvW9sMwc51cw", "variant3"),
|
||||
("BQqgrGnjSFABAAAA8mQDBXQcARE", "variant4"),
|
||||
("MIo6r0qGSFAFAAAAtL8TsDzNX60", "variant5"),
|
||||
("9iklpvIPQVABAAAAORQXKur_Eyc", "variant6"),
|
||||
("H6rz6geXUFIMAAAAuUs7m6cXbcc", "variant7"),
|
||||
("kO4jyq55SFABAAAA0WEpcLfahXk", "variant8"),
|
||||
("mP3FG_iwSFAFAAAA2AklJO978pA", "variant9"),
|
||||
("Ujx2TFcJSVACAAAARJ4vLa50MkM", "variant10"),
|
||||
("RepJ5uE_SVABAAAAr4d0YhgB850", "variant11"),
|
||||
("9GcNVISdSVADAAAAUcw5BYjELW4", "variant12"),
|
||||
("-Xc-np9y2VMCAAAARKr0yNNPYW0", "variant13"),
|
||||
("JrNEYdNhSFABAAAA9WtRdJkPRbY", "variant14"),
|
||||
]
|
||||
|
||||
var signals: [Signal<String?, GetWallpaperError>] = []
|
||||
for (slug, name) in slugToName {
|
||||
signals.append(getWallpaper(network: account.network, slug: slug)
|
||||
|> map { wallpaper -> String? in
|
||||
switch wallpaper {
|
||||
case let .file(id, accessHash, _, _, _, _, _, file, _):
|
||||
guard let resource = file.resource as? CloudDocumentMediaResource else {
|
||||
return nil
|
||||
}
|
||||
guard let size = file.size else {
|
||||
return nil
|
||||
}
|
||||
return """
|
||||
static let \(name) = BuiltinWallpaperData(
|
||||
wallpaperId: \(id),
|
||||
wallpaperAccessHash: \(accessHash),
|
||||
slug: "\(slug)",
|
||||
fileId: \(file.fileId.id),
|
||||
fileAccessHash: \(resource.accessHash),
|
||||
datacenterId: \(resource.datacenterId),
|
||||
fileSize: \(size)
|
||||
)
|
||||
"""
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let _ = (combineLatest(signals)
|
||||
|> map { strings -> String in
|
||||
var result = ""
|
||||
for case let string? in strings {
|
||||
if !result.isEmpty {
|
||||
result.append("\n")
|
||||
}
|
||||
result.append(string)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
print("\(result)")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func defaultBuiltinWallpaper(data: BuiltinWallpaperData, colors: [UInt32], intensity: Int32 = 50, rotation: Int32? = nil) -> TelegramWallpaper {
|
||||
return .file(
|
||||
id: 5933856211186221059,
|
||||
accessHash: 7039846297018949116,
|
||||
id: data.wallpaperId,
|
||||
accessHash: data.wallpaperAccessHash,
|
||||
isCreator: false,
|
||||
isDefault: false,
|
||||
isPattern: true,
|
||||
isDark: false,
|
||||
slug: "fqv01SQemVIBAAAApND8LDRUhRU",
|
||||
slug: data.slug,
|
||||
file: TelegramMediaFile(
|
||||
fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: 5789658100176783156),
|
||||
fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: data.fileId),
|
||||
partialReference: nil,
|
||||
resource: CloudDocumentMediaResource(
|
||||
datacenterId: 1,
|
||||
fileId: 5789658100176783156,
|
||||
accessHash: 5949005087206403318,
|
||||
size: 183832,
|
||||
datacenterId: data.datacenterId,
|
||||
fileId: data.fileId,
|
||||
accessHash: data.fileAccessHash,
|
||||
size: data.fileSize,
|
||||
fileReference: Data(),
|
||||
fileName: "pattern.tgv"
|
||||
),
|
||||
@ -867,8 +1080,8 @@ public func defaultBuiltinWallpaper(colors: [UInt32], intensity: Int32 = 50, rot
|
||||
dimensions: PixelDimensions(width: 155, height: 320),
|
||||
resource: CloudDocumentSizeMediaResource(
|
||||
datacenterId: 1,
|
||||
documentId: 5789658100176783156,
|
||||
accessHash: 5949005087206403318,
|
||||
documentId: data.fileId,
|
||||
accessHash: data.fileAccessHash,
|
||||
sizeSpec: "m",
|
||||
fileReference: Data()
|
||||
),
|
||||
@ -879,7 +1092,7 @@ public func defaultBuiltinWallpaper(colors: [UInt32], intensity: Int32 = 50, rot
|
||||
videoThumbnails: [],
|
||||
immediateThumbnailData: nil,
|
||||
mimeType: "application/x-tgwallpattern",
|
||||
size: 183832,
|
||||
size: data.fileSize,
|
||||
attributes: [
|
||||
.ImageSize(size: PixelDimensions(width: 1440, height: 2960)),
|
||||
.FileName(fileName: "pattern.tgv")
|
||||
|
@ -19,7 +19,7 @@ public func makeDefaultPresentationTheme(reference: PresentationBuiltinThemeRefe
|
||||
return theme
|
||||
}
|
||||
|
||||
public func customizePresentationTheme(_ theme: PresentationTheme, editing: Bool, title: String? = nil, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: (UIColor, UIColor?)?, wallpaper: TelegramWallpaper? = nil, wallpaperGradientColors: [UInt32]? = nil) -> PresentationTheme {
|
||||
public func customizePresentationTheme(_ theme: PresentationTheme, editing: Bool, title: String? = nil, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: (UIColor, UIColor?)?, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil) -> PresentationTheme {
|
||||
if accentColor == nil && bubbleColors == nil && backgroundColors.isEmpty && wallpaper == nil {
|
||||
return theme
|
||||
}
|
||||
@ -27,9 +27,9 @@ public func customizePresentationTheme(_ theme: PresentationTheme, editing: Bool
|
||||
case .day, .dayClassic:
|
||||
return customizeDefaultDayTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper, serviceBackgroundColor: nil)
|
||||
case .night:
|
||||
return customizeDefaultDarkPresentationTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper)
|
||||
return customizeDefaultDarkPresentationTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper, baseColor: baseColor)
|
||||
case .nightAccent:
|
||||
return customizeDefaultDarkTintedPresentationTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper, wallpaperGradientColors: wallpaperGradientColors)
|
||||
return customizeDefaultDarkTintedPresentationTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper, baseColor: baseColor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,12 +38,12 @@ public func makePresentationTheme(settings: TelegramThemeSettings, title: String
|
||||
return customizePresentationTheme(defaultTheme, editing: true, title: title, accentColor: UIColor(argb: settings.accentColor), backgroundColors: [], bubbleColors: settings.messageColors.flatMap { (UIColor(argb: $0.top), UIColor(argb: $0.bottom)) }, wallpaper: settings.wallpaper)
|
||||
}
|
||||
|
||||
public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: (UIColor, UIColor?)? = nil, wallpaper: TelegramWallpaper? = nil, wallpaperGradientColors: [UInt32]? = nil, serviceBackgroundColor: UIColor? = nil, preview: Bool = false) -> PresentationTheme? {
|
||||
public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: (UIColor, UIColor?)? = nil, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil, serviceBackgroundColor: UIColor? = nil, preview: Bool = false) -> PresentationTheme? {
|
||||
let theme: PresentationTheme
|
||||
switch themeReference {
|
||||
case let .builtin(reference):
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: reference, extendingThemeReference: extendingThemeReference, serviceBackgroundColor: serviceBackgroundColor, preview: preview)
|
||||
theme = customizePresentationTheme(defaultTheme, editing: true, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper, wallpaperGradientColors: wallpaperGradientColors)
|
||||
theme = customizePresentationTheme(defaultTheme, editing: true, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper, baseColor: baseColor)
|
||||
case let .local(info):
|
||||
if let path = mediaBox.completedResourcePath(info.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let loadedTheme = makePresentationTheme(data: data, themeReference: themeReference, resolvedWallpaper: info.resolvedWallpaper) {
|
||||
theme = customizePresentationTheme(loadedTheme, editing: false, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper)
|
||||
|
@ -292,7 +292,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager, s
|
||||
}
|
||||
|
||||
let effectiveColors = themeSettings.themeSpecificAccentColors[effectiveTheme.index]
|
||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors, wallpaperGradientColors: effectiveColors?.baseColor.wallpaperGradientColors) ?? defaultPresentationTheme
|
||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors, baseColor: effectiveColors?.baseColor) ?? defaultPresentationTheme
|
||||
|
||||
|
||||
let effectiveChatWallpaper: TelegramWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: effectiveTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[effectiveTheme.index]) ?? theme.chat.defaultWallpaper
|
||||
@ -583,7 +583,7 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
||||
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
||||
currentWallpaper = themeSpecificWallpaper
|
||||
} else {
|
||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors, wallpaper: currentColors?.wallpaper, wallpaperGradientColors: currentColors?.baseColor.wallpaperGradientColors) ?? defaultPresentationTheme
|
||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors, wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor) ?? defaultPresentationTheme
|
||||
currentWallpaper = theme.chat.defaultWallpaper
|
||||
}
|
||||
|
||||
@ -619,7 +619,7 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
||||
effectiveColors = nil
|
||||
}
|
||||
|
||||
let themeValue = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors, wallpaper: effectiveColors?.wallpaper, wallpaperGradientColors: effectiveColors?.baseColor.wallpaperGradientColors, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme
|
||||
let themeValue = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors, wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme
|
||||
|
||||
if autoNightModeTriggered && !switchedToNightModeWallpaper {
|
||||
switch effectiveChatWallpaper {
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -17,6 +17,7 @@ import SettingsUI
|
||||
import PhoneNumberFormat
|
||||
import LegacyComponents
|
||||
import LegacyMediaPickerUI
|
||||
import PasswordSetupUI
|
||||
|
||||
private enum InnerState: Equatable {
|
||||
case state(UnauthorizedAccountStateContents)
|
||||
@ -564,29 +565,69 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
}).start()
|
||||
})
|
||||
controller.recoverWithCode = { [weak self, weak controller] code in
|
||||
if let strongSelf = self {
|
||||
controller?.inProgress = true
|
||||
|
||||
strongSelf.actionDisposable.set((performPasswordRecovery(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, code: code, syncContacts: syncContacts) |> deliverOnMainQueue).start(error: { error in
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self, let controller = controller {
|
||||
controller.inProgress = false
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
}
|
||||
|
||||
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}))
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
controller?.inProgress = true
|
||||
|
||||
strongSelf.actionDisposable.set((performPasswordRecovery(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, code: code, syncContacts: syncContacts) |> deliverOnMainQueue).start(error: { error in
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self, let controller = controller {
|
||||
controller.inProgress = false
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
|
||||
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
/*controller?.inProgress = true
|
||||
|
||||
strongSelf.actionDisposable.set((checkPasswordRecoveryCode(network: strongSelf.account.network, code: code)
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
guard let strongSelf = self, let controller = controller else {
|
||||
return
|
||||
}
|
||||
controller.inProgress = false
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
|
||||
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
controller?.inProgress = false
|
||||
|
||||
let setupController = TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, network: strongSelf.account.network, mode: .passwordRecovery(TwoFactorDataInputMode.Recovery(code: code, syncContacts: syncContacts, account: strongSelf.account)), stateUpdated: { _ in
|
||||
guard let _ = self else {
|
||||
return
|
||||
}
|
||||
})
|
||||
strongSelf.setViewControllers(strongSelf.viewControllers + [setupController], animated: true)
|
||||
}))*/
|
||||
}
|
||||
controller.noAccess = { [weak self, weak controller] in
|
||||
if let strongSelf = self, let controller = controller {
|
||||
|
@ -738,7 +738,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
||||
representations.append(ImageRepresentationWithReference(representation: .init(dimensions: PixelDimensions(width: 1440, height: 2960), resource: file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource)))
|
||||
}
|
||||
if ["image/png", "image/svg+xml", "application/x-tgwallpattern"].contains(file.mimeType) {
|
||||
return patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: representations, mode: .thumbnail)
|
||||
return patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: representations, mode: .screen)
|
||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let value = value {
|
||||
return .single(value)
|
||||
|
@ -16,7 +16,6 @@ import LocationResources
|
||||
import ImageBlur
|
||||
import TelegramAnimatedStickerNode
|
||||
import WallpaperResources
|
||||
import Svg
|
||||
import GZip
|
||||
import TelegramUniversalVideoContent
|
||||
import GradientBackground
|
||||
@ -68,22 +67,6 @@ public func fetchCachedResourceRepresentation(account: Account, resource: MediaR
|
||||
}
|
||||
return fetchCachedBlurredWallpaperRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
} else if let representation = representation as? CachedPatternWallpaperMaskRepresentation {
|
||||
return account.postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false))
|
||||
|> mapToSignal { data -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||
if !data.complete {
|
||||
return .complete()
|
||||
}
|
||||
return fetchCachedPatternWallpaperMaskRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
} else if let representation = representation as? CachedPatternWallpaperRepresentation {
|
||||
return account.postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false))
|
||||
|> mapToSignal { data -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||
if !data.complete {
|
||||
return .complete()
|
||||
}
|
||||
return fetchCachedPatternWallpaperRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
} else if let representation = representation as? CachedAlbumArtworkRepresentation {
|
||||
return account.postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false))
|
||||
|> mapToSignal { data -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||
@ -417,194 +400,6 @@ private func fetchCachedBlurredWallpaperRepresentation(resource: MediaResource,
|
||||
}) |> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
private func fetchCachedPatternWallpaperMaskRepresentation(resource: MediaResource, resourceData: MediaResourceData, representation: CachedPatternWallpaperMaskRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
|
||||
return Signal({ subscriber in
|
||||
if var data = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.mappedIfSafe]) {
|
||||
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
if let unzippedData = TGGUnzipData(data, 2 * 1024 * 1024) {
|
||||
data = unzippedData
|
||||
}
|
||||
|
||||
if data.count > 5, let string = String(data: data.subdata(in: 0 ..< 5), encoding: .utf8), string == "<?xml" {
|
||||
let size = representation.size ?? CGSize(width: 1440.0, height: 2960.0)
|
||||
|
||||
if let image = drawSvgImage(data, size, .black, .white) {
|
||||
if let alphaDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
CGImageDestinationSetProperties(alphaDestination, [:] as CFDictionary)
|
||||
|
||||
let colorQuality: Float = 0.87
|
||||
|
||||
let options = NSMutableDictionary()
|
||||
options.setObject(colorQuality as NSNumber, forKey: kCGImageDestinationLossyCompressionQuality as NSString)
|
||||
|
||||
CGImageDestinationAddImage(alphaDestination, image.cgImage!, options as CFDictionary)
|
||||
if CGImageDestinationFinalize(alphaDestination) {
|
||||
subscriber.putNext(.temporaryPath(path))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let image = UIImage(data: data) {
|
||||
let size = representation.size.flatMap { image.size.aspectFitted($0) } ?? CGSize(width: image.size.width * image.scale, height: image.size.height * image.scale)
|
||||
|
||||
let alphaImage = generateImage(size, contextGenerator: { size, context in
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
context.clip(to: CGRect(origin: CGPoint(), size: size), mask: image.cgImage!)
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
}, scale: 1.0)
|
||||
|
||||
if let alphaImage = alphaImage, let alphaDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
CGImageDestinationSetProperties(alphaDestination, [:] as CFDictionary)
|
||||
|
||||
let colorQuality: Float = 0.87
|
||||
|
||||
let options = NSMutableDictionary()
|
||||
options.setObject(colorQuality as NSNumber, forKey: kCGImageDestinationLossyCompressionQuality as NSString)
|
||||
|
||||
CGImageDestinationAddImage(alphaDestination, alphaImage.cgImage!, options as CFDictionary)
|
||||
if CGImageDestinationFinalize(alphaDestination) {
|
||||
subscriber.putNext(.temporaryPath(path))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EmptyDisposable
|
||||
}) |> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
private func fetchCachedPatternWallpaperRepresentation(resource: MediaResource, resourceData: MediaResourceData, representation: CachedPatternWallpaperRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
|
||||
return Signal({ subscriber in
|
||||
if var data = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.mappedIfSafe]) {
|
||||
if let unzippedData = TGGUnzipData(data, 2 * 1024 * 1024) {
|
||||
data = unzippedData
|
||||
}
|
||||
|
||||
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
let colors: [UIColor] = representation.colors.map(UIColor.init(rgb:))
|
||||
|
||||
let intensity = CGFloat(representation.intensity) / 100.0
|
||||
|
||||
var size: CGSize?
|
||||
var maskImage: UIImage?
|
||||
if data.count > 5, let string = String(data: data.subdata(in: 0 ..< 5), encoding: .utf8), string == "<?xml" {
|
||||
let defaultSize = CGSize(width: 1440.0, height: 2960.0)
|
||||
size = defaultSize
|
||||
if let image = drawSvgImage(data, defaultSize, .black, .white) {
|
||||
maskImage = image
|
||||
}
|
||||
} else if let image = UIImage(data: data) {
|
||||
size = CGSize(width: image.size.width * image.scale, height: image.size.height * image.scale)
|
||||
maskImage = image
|
||||
}
|
||||
|
||||
var colorImage: UIImage?
|
||||
if let size = size {
|
||||
colorImage = generateImage(size, contextGenerator: { size, c in
|
||||
let rect = CGRect(origin: CGPoint(), size: size)
|
||||
c.setBlendMode(.copy)
|
||||
|
||||
let averageBackgroundColor = UIColor.average(of: colors)
|
||||
|
||||
if colors.count == 1, let color = colors.first {
|
||||
c.setFillColor(color.cgColor)
|
||||
c.fill(rect)
|
||||
} else if colors.count >= 3 {
|
||||
let drawingRect = rect
|
||||
let image = GradientBackgroundNode.generatePreview(size: CGSize(width: 60.0, height: 60.0), colors: colors)
|
||||
c.translateBy(x: drawingRect.midX, y: drawingRect.midY)
|
||||
c.scaleBy(x: 1.0, y: 1.0)
|
||||
c.translateBy(x: -drawingRect.midX, y: -drawingRect.midY)
|
||||
c.draw(image.cgImage!, in: drawingRect)
|
||||
c.translateBy(x: drawingRect.midX, y: drawingRect.midY)
|
||||
c.scaleBy(x: 1.0, y: 1.0)
|
||||
c.translateBy(x: -drawingRect.midX, y: -drawingRect.midY)
|
||||
} else {
|
||||
let gradientColors = colors.map { $0.cgColor } as CFArray
|
||||
let delta: CGFloat = 1.0 / (CGFloat(colors.count) - 1.0)
|
||||
|
||||
var locations: [CGFloat] = []
|
||||
for i in 0 ..< colors.count {
|
||||
locations.append(delta * CGFloat(i))
|
||||
}
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
c.saveGState()
|
||||
c.translateBy(x: rect.width / 2.0, y: rect.height / 2.0)
|
||||
c.rotate(by: CGFloat(representation.rotation ?? 0) * CGFloat.pi / -180.0)
|
||||
c.translateBy(x: -rect.width / 2.0, y: -rect.height / 2.0)
|
||||
|
||||
c.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: rect.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
||||
c.restoreGState()
|
||||
}
|
||||
|
||||
c.setBlendMode(.normal)
|
||||
if let cgImage = maskImage?.cgImage {
|
||||
c.clip(to: rect, mask: cgImage)
|
||||
}
|
||||
|
||||
if colors.count >= 3 {
|
||||
c.setBlendMode(.softLight)
|
||||
}
|
||||
|
||||
let isLight = averageBackgroundColor.hsb.b >= 0.3
|
||||
if isLight {
|
||||
c.setFillColor(UIColor(white: 0.0, alpha: abs(intensity)).cgColor)
|
||||
c.fill(rect)
|
||||
} else {
|
||||
c.setFillColor(UIColor(white: 1.0, alpha: abs(intensity)).cgColor)
|
||||
c.fill(rect)
|
||||
}
|
||||
|
||||
/*if colors.count == 1, let color = colors.first {
|
||||
c.setFillColor(patternColor(for: color, intensity: intensity).cgColor)
|
||||
c.fill(rect)
|
||||
} else {
|
||||
let gradientColors = colors.map { patternColor(for: $0, intensity: intensity).cgColor } as CFArray
|
||||
let delta: CGFloat = 1.0 / (CGFloat(colors.count) - 1.0)
|
||||
|
||||
var locations: [CGFloat] = []
|
||||
for i in 0 ..< colors.count {
|
||||
locations.append(delta * CGFloat(i))
|
||||
}
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
c.translateBy(x: rect.width / 2.0, y: rect.height / 2.0)
|
||||
c.rotate(by: CGFloat(representation.rotation ?? 0) * CGFloat.pi / -180.0)
|
||||
c.translateBy(x: -rect.width / 2.0, y: -rect.height / 2.0)
|
||||
|
||||
c.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: rect.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
||||
}*/
|
||||
}, scale: 1.0)
|
||||
}
|
||||
|
||||
if let colorImage = colorImage, let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary)
|
||||
|
||||
let colorQuality: Float = 0.9
|
||||
|
||||
let options = NSMutableDictionary()
|
||||
options.setObject(colorQuality as NSNumber, forKey: kCGImageDestinationLossyCompressionQuality as NSString)
|
||||
|
||||
CGImageDestinationAddImage(colorDestination, colorImage.cgImage!, options as CFDictionary)
|
||||
if CGImageDestinationFinalize(colorDestination) {
|
||||
subscriber.putNext(.temporaryPath(path))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
}
|
||||
return EmptyDisposable
|
||||
}) |> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
public func fetchCachedSharedResourceRepresentation(accountManager: AccountManager, resource: MediaResource, representation: CachedMediaResourceRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
|
||||
if let representation = representation as? CachedScaledImageRepresentation {
|
||||
return accountManager.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false))
|
||||
@ -622,22 +417,6 @@ public func fetchCachedSharedResourceRepresentation(accountManager: AccountManag
|
||||
}
|
||||
return fetchCachedBlurredWallpaperRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
} else if let representation = representation as? CachedPatternWallpaperMaskRepresentation {
|
||||
return accountManager.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false))
|
||||
|> mapToSignal { data -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||
if !data.complete {
|
||||
return .complete()
|
||||
}
|
||||
return fetchCachedPatternWallpaperMaskRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
} else if let representation = representation as? CachedPatternWallpaperRepresentation {
|
||||
return accountManager.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false))
|
||||
|> mapToSignal { data -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||
if !data.complete {
|
||||
return .complete()
|
||||
}
|
||||
return fetchCachedPatternWallpaperRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
} else {
|
||||
return .never()
|
||||
}
|
||||
|
@ -122,7 +122,6 @@ public func upgradedAccounts(accountManager: AccountManager, rootPath: String, e
|
||||
}
|
||||
|> ignoreValues
|
||||
|> mapToSignal { _ -> Signal<Float, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
var signal: Signal<Float, NoError> = .complete()
|
||||
@ -166,9 +165,6 @@ public func upgradedAccounts(accountManager: AccountManager, rootPath: String, e
|
||||
accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data)
|
||||
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
|
||||
if wallpaper.isPattern {
|
||||
if !file.settings.colors.isEmpty, let intensity = file.settings.intensity {
|
||||
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperRepresentation(colors: file.settings.colors, intensity: intensity, rotation: file.settings.rotation), complete: true, fetch: true).start()
|
||||
}
|
||||
} else {
|
||||
if file.settings.blur {
|
||||
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start()
|
||||
|
@ -404,36 +404,6 @@ public enum PresentationThemeBaseColor: Int32, CaseIterable {
|
||||
}
|
||||
return UIColor(rgb: value)
|
||||
}
|
||||
|
||||
|
||||
public var wallpaperGradientColors: [UInt32]? {
|
||||
switch self {
|
||||
case .blue:
|
||||
return [0x1b2836, 0x121a22, 0x1b2836, 0x121a22]
|
||||
case .cyan:
|
||||
return [0x152b32, 0x0c181c, 0x152b32, 0x0c181c]
|
||||
case .green:
|
||||
return [0x142615, 0x0b160c, 0x142615, 0x0b160c]
|
||||
case .pink:
|
||||
return [0x2d1f23, 0x22171a, 0x2d1f23, 0x22171a]
|
||||
case .orange:
|
||||
return [0x2e2213, 0x221b0f, 0x2e2213, 0x221b0f]
|
||||
case .purple:
|
||||
return [0x25212e, 0x1b1822, 0x25212e, 0x1b1822]
|
||||
case .red:
|
||||
return [0x281613, 0x1e110e, 0x281613, 0x1e110e]
|
||||
case .yellow:
|
||||
return [0x2d2813, 0x221d0e, 0x2d2813, 0x221d0e]
|
||||
case .gray:
|
||||
return [0x1b1d21, 0x111315, 0x1b1d21, 0x111315]
|
||||
case .black:
|
||||
return nil
|
||||
case .white:
|
||||
return nil
|
||||
case .custom, .preset, .theme:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct PresentationThemeAccentColor: PostboxCoding, Equatable {
|
||||
|
@ -435,10 +435,6 @@ public final class OngoingCallVideoCapturer {
|
||||
self.impl.setIsVideoEnabled(value)
|
||||
}
|
||||
|
||||
public func injectSampleBuffer(_ sampleBuffer: CMSampleBuffer) {
|
||||
self.impl.submitSampleBuffer(sampleBuffer)
|
||||
}
|
||||
|
||||
public func injectPixelBuffer(_ pixelBuffer: CVPixelBuffer, rotation: CGImagePropertyOrientation) {
|
||||
var videoRotation: OngoingCallVideoOrientation = .rotation0
|
||||
switch rotation {
|
||||
|
@ -26,6 +26,9 @@ objc_library(
|
||||
"tgcalls/tgcalls/platform/darwin/DesktopSharingCapturer.*",
|
||||
"tgcalls/tgcalls/platform/darwin/DesktopCaptureSourceViewMac.*",
|
||||
"tgcalls/tgcalls/platform/darwin/DesktopCaptureSourceView.*",
|
||||
"tgcalls/tgcalls/platform/darwin/TGCMIODevice.*",
|
||||
"tgcalls/tgcalls/platform/darwin/TGCMIOCapturer.*",
|
||||
"tgcalls/tgcalls/platform/darwin/VideoCMIOCapture.*",
|
||||
"tgcalls/tgcalls/desktop_capturer/**",
|
||||
]),
|
||||
hdrs = glob([
|
||||
|
@ -126,7 +126,6 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
|
||||
- (void)setOnIsActiveUpdated:(void (^_Nonnull)(bool))onIsActiveUpdated;
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
- (void)submitSampleBuffer:(CMSampleBufferRef _Nonnull)sampleBuffer;
|
||||
- (void)submitPixelBuffer:(CVPixelBufferRef _Nonnull)pixelBuffer rotation:(OngoingCallVideoOrientationWebrtc)rotation;
|
||||
#endif
|
||||
|
||||
|
@ -50,8 +50,26 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface IsProcessingCustomSampleBufferFlag : NSObject
|
||||
|
||||
@property (nonatomic) bool value;
|
||||
|
||||
@end
|
||||
|
||||
@implementation IsProcessingCustomSampleBufferFlag
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface OngoingCallThreadLocalContextVideoCapturer () {
|
||||
std::shared_ptr<tgcalls::VideoCaptureInterface> _interface;
|
||||
IsProcessingCustomSampleBufferFlag *_isProcessingCustomSampleBuffer;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -217,6 +235,7 @@
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_interface = interface;
|
||||
_isProcessingCustomSampleBuffer = [[IsProcessingCustomSampleBufferFlag alloc] init];
|
||||
_croppingBuffer = std::make_shared<std::vector<uint8_t>>();
|
||||
}
|
||||
return self;
|
||||
@ -254,20 +273,6 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls:
|
||||
}
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
- (void)submitSampleBuffer:(CMSampleBufferRef _Nonnull)sampleBuffer {
|
||||
if (!sampleBuffer) {
|
||||
return;
|
||||
}
|
||||
tgcalls::StaticThreads::getThreads()->getMediaThread()->PostTask(RTC_FROM_HERE, [interface = _interface, sampleBuffer = CFRetain(sampleBuffer)]() {
|
||||
auto capture = GetVideoCaptureAssumingSameThread(interface.get());
|
||||
auto source = capture->source();
|
||||
if (source) {
|
||||
[CustomExternalCapturer passSampleBuffer:(CMSampleBufferRef)sampleBuffer toSource:source];
|
||||
}
|
||||
CFRelease(sampleBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)submitPixelBuffer:(CVPixelBufferRef _Nonnull)pixelBuffer rotation:(OngoingCallVideoOrientationWebrtc)rotation {
|
||||
if (!pixelBuffer) {
|
||||
return;
|
||||
@ -289,13 +294,19 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls:
|
||||
break;
|
||||
}
|
||||
|
||||
tgcalls::StaticThreads::getThreads()->getMediaThread()->PostTask(RTC_FROM_HERE, [interface = _interface, pixelBuffer = CFRetain(pixelBuffer), croppingBuffer = _croppingBuffer, videoRotation = videoRotation]() {
|
||||
if (_isProcessingCustomSampleBuffer.value) {
|
||||
return;
|
||||
}
|
||||
_isProcessingCustomSampleBuffer.value = true;
|
||||
|
||||
tgcalls::StaticThreads::getThreads()->getMediaThread()->PostTask(RTC_FROM_HERE, [interface = _interface, pixelBuffer = CFRetain(pixelBuffer), croppingBuffer = _croppingBuffer, videoRotation = videoRotation, isProcessingCustomSampleBuffer = _isProcessingCustomSampleBuffer]() {
|
||||
auto capture = GetVideoCaptureAssumingSameThread(interface.get());
|
||||
auto source = capture->source();
|
||||
if (source) {
|
||||
[CustomExternalCapturer passPixelBuffer:(CVPixelBufferRef)pixelBuffer rotation:videoRotation toSource:source croppingBuffer:*croppingBuffer];
|
||||
}
|
||||
CFRelease(pixelBuffer);
|
||||
isProcessingCustomSampleBuffer.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 91b711e620f7043113a40496f9dddc0ccea16d52
|
||||
Subproject commit 6ec339fd301781a4087ca1710814617e3502eec6
|
@ -550,15 +550,22 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
let contentAlpha = abs(intensity)
|
||||
self.gradientBackgroundNode?.contentView.alpha = contentAlpha
|
||||
self.contentNode.alpha = contentAlpha
|
||||
if self.patternImageNode.image != nil {
|
||||
self.patternImageNode.backgroundColor = nil
|
||||
} else {
|
||||
self.patternImageNode.backgroundColor = .black
|
||||
}
|
||||
} else {
|
||||
self.backgroundColor = nil
|
||||
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
||||
self.contentNode.alpha = 1.0
|
||||
self.patternImageNode.backgroundColor = nil
|
||||
}
|
||||
default:
|
||||
self.patternImageDisposable.set(nil)
|
||||
self.validPatternImage = nil
|
||||
self.patternImageNode.isHidden = true
|
||||
self.patternImageNode.backgroundColor = nil
|
||||
self.backgroundColor = nil
|
||||
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
||||
self.contentNode.alpha = 1.0
|
||||
@ -574,7 +581,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
var patternIsLight: Bool = false
|
||||
|
||||
switch wallpaper {
|
||||
case let .file(_, _, _, _, isPattern, _, _, file, settings) where isPattern:
|
||||
case let .file(_, _, _, _, isPattern, _, slug, file, settings) where isPattern:
|
||||
var updated = true
|
||||
let brightness = UIColor.average(of: settings.colors.map(UIColor.init(rgb:))).hsb.b
|
||||
patternIsLight = brightness > 0.3
|
||||
@ -600,7 +607,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
if let message = message {
|
||||
return .media(media: .message(message: MessageReference(message), media: media), resource: resource)
|
||||
}
|
||||
return .wallpaper(wallpaper: nil, resource: resource)
|
||||
return .wallpaper(wallpaper: .slug(slug), resource: resource)
|
||||
}
|
||||
|
||||
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
||||
@ -610,7 +617,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
let dimensions = file.dimensions ?? PixelDimensions(width: 2000, height: 4000)
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: reference(for: file.resource, media: file, message: nil)))
|
||||
|
||||
let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true, onlyFullSize: true)
|
||||
let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
|
||||
self.patternImageDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] generator in
|
||||
guard let strongSelf = self else {
|
||||
@ -642,6 +649,11 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
if invertPattern {
|
||||
patternColor = .clear
|
||||
patternBackgroundColor = .clear
|
||||
if self.patternImageNode.image == nil {
|
||||
self.patternImageNode.backgroundColor = .black
|
||||
} else {
|
||||
self.patternImageNode.backgroundColor = nil
|
||||
}
|
||||
} else {
|
||||
if patternIsLight {
|
||||
patternColor = .black
|
||||
@ -649,6 +661,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
patternColor = .white
|
||||
}
|
||||
patternBackgroundColor = .clear
|
||||
self.patternImageNode.backgroundColor = nil
|
||||
}
|
||||
|
||||
let updatedGeneratedImage = ValidPatternGeneratedImage(wallpaper: validPatternImage.wallpaper, size: size, patternColor: patternColor.rgb, backgroundColor: patternBackgroundColor.rgb, invertPattern: invertPattern)
|
||||
|
@ -20,6 +20,7 @@ swift_library(
|
||||
"//submodules/PersistentStringHash:PersistentStringHash",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/Svg:Svg",
|
||||
"//submodules/GZip:GZip",
|
||||
"//submodules/GradientBackground:GradientBackground",
|
||||
],
|
||||
visibility = [
|
||||
|
@ -16,6 +16,7 @@ import TelegramUIPreferences
|
||||
import AppBundle
|
||||
import Svg
|
||||
import GradientBackground
|
||||
import GZip
|
||||
|
||||
public func wallpaperDatas(account: Account, accountManager: AccountManager, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], alwaysShowThumbnailFirst: Bool = false, thumbnail: Bool = false, onlyFullSize: Bool = false, autoFetchFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.firstIndex(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.firstIndex(where: { $0.representation == largestRepresentation }) {
|
||||
@ -358,88 +359,47 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
||||
}
|
||||
}
|
||||
|
||||
private func patternWallpaperDatas(account: Account, accountManager: AccountManager, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
|
||||
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.firstIndex(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.firstIndex(where: { $0.representation == largestRepresentation }) {
|
||||
|
||||
let size: CGSize?
|
||||
switch mode {
|
||||
case .thumbnail:
|
||||
size = largestRepresentation.dimensions.cgSize.fitted(CGSize(width: 640.0, height: 640.0))
|
||||
default:
|
||||
size = nil
|
||||
private func patternWallpaperDatas(account: Account, accountManager: AccountManager, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false) -> Signal<(Data?, Bool), NoError> {
|
||||
var targetRepresentation: ImageRepresentationWithReference?
|
||||
switch mode {
|
||||
case .thumbnail:
|
||||
if let representation = smallestImageRepresentation(representations.map({ $0.representation })) {
|
||||
targetRepresentation = representations[representations.firstIndex(where: { $0.representation == representation })!]
|
||||
}
|
||||
let maybeFullSize = combineLatest(accountManager.mediaBox.cachedResourceRepresentation(largestRepresentation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: false), account.postbox.mediaBox.cachedResourceRepresentation(largestRepresentation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: false))
|
||||
case .screen:
|
||||
if let representation = largestImageRepresentation(representations.map({ $0.representation })) {
|
||||
targetRepresentation = representations[representations.firstIndex(where: { $0.representation == representation })!]
|
||||
}
|
||||
}
|
||||
|
||||
if let targetRepresentation = targetRepresentation {
|
||||
let maybeFullSize = combineLatest(
|
||||
accountManager.mediaBox.resourceData(targetRepresentation.representation.resource),
|
||||
account.postbox.mediaBox.resourceData(targetRepresentation.representation.resource)
|
||||
)
|
||||
|
||||
let signal = maybeFullSize
|
||||
|> take(1)
|
||||
|> mapToSignal { maybeSharedData, maybeData -> Signal<(Data?, Data?, Bool), NoError> in
|
||||
|> mapToSignal { maybeSharedData, maybeData -> Signal<(Data?, Bool), NoError> in
|
||||
if maybeSharedData.complete {
|
||||
if let loadedData = try? Data(contentsOf: URL(fileURLWithPath: maybeSharedData.path), options: [.mappedRead]) {
|
||||
return .single((nil, loadedData, true))
|
||||
return .single((loadedData, true))
|
||||
} else {
|
||||
return .single((nil, nil, true))
|
||||
return .single(( nil, true))
|
||||
}
|
||||
} else if maybeData.complete {
|
||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||
return .single((nil, loadedData, true))
|
||||
return .single((loadedData, true))
|
||||
} else {
|
||||
let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[smallestIndex].reference)
|
||||
let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[largestIndex].reference)
|
||||
|
||||
let accountThumbnailData = Signal<Data?, NoError> { subscriber in
|
||||
let fetchedDisposable = fetchedThumbnail.start()
|
||||
let thumbnailDisposable = account.postbox.mediaBox.cachedResourceRepresentation(representations[smallestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start(next: { next in
|
||||
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
|
||||
|
||||
if next.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedRead) {
|
||||
accountManager.mediaBox.storeResourceData(representations[smallestIndex].representation.resource.id, data: data)
|
||||
let _ = accountManager.mediaBox.cachedResourceRepresentation(representations[smallestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start()
|
||||
}
|
||||
}, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
||||
return ActionDisposable {
|
||||
fetchedDisposable.dispose()
|
||||
thumbnailDisposable.dispose()
|
||||
}
|
||||
}
|
||||
let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: targetRepresentation.reference)
|
||||
|
||||
let sharedThumbnailData = Signal<Data?, NoError> { subscriber in
|
||||
let thumbnailDisposable = accountManager.mediaBox.cachedResourceRepresentation(representations[smallestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start(next: { next in
|
||||
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
|
||||
}, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
||||
return ActionDisposable {
|
||||
thumbnailDisposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
let thumbnailData = combineLatest(accountThumbnailData, sharedThumbnailData)
|
||||
|> map { thumbnailData, sharedThumbnailData -> Data? in
|
||||
return thumbnailData ?? sharedThumbnailData
|
||||
}
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
if lhs == nil && rhs == nil {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|> take(until: { value in
|
||||
if value != nil {
|
||||
return SignalTakeAction(passthrough: true, complete: true)
|
||||
} else {
|
||||
return SignalTakeAction(passthrough: true, complete: false)
|
||||
}
|
||||
})
|
||||
|
||||
let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in
|
||||
let fetchedFullSizeDisposable = fetchedFullSize.start()
|
||||
let fullSizeDisposable = account.postbox.mediaBox.cachedResourceRepresentation(representations[largestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start(next: { next in
|
||||
let fullSizeDisposable = account.postbox.mediaBox.resourceData(targetRepresentation.representation.resource).start(next: { next in
|
||||
subscriber.putNext((next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete))
|
||||
|
||||
if next.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedRead) {
|
||||
accountManager.mediaBox.storeResourceData(representations[largestIndex].representation.resource.id, data: data)
|
||||
let _ = accountManager.mediaBox.cachedResourceRepresentation(representations[largestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start()
|
||||
accountManager.mediaBox.storeResourceData(targetRepresentation.representation.resource.id, data: data)
|
||||
}
|
||||
}, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
||||
@ -450,7 +410,7 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
|
||||
}
|
||||
|
||||
let sharedFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in
|
||||
let fullSizeDisposable = accountManager.mediaBox.cachedResourceRepresentation(representations[largestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start(next: { next in
|
||||
let fullSizeDisposable = accountManager.mediaBox.resourceData(targetRepresentation.representation.resource).start(next: { next in
|
||||
subscriber.putNext((next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete))
|
||||
}, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
||||
@ -481,12 +441,8 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
|
||||
return SignalTakeAction(passthrough: true, complete: false)
|
||||
}
|
||||
})
|
||||
|
||||
return thumbnailData |> mapToSignal { thumbnailData in
|
||||
return fullSizeData |> map { (fullSizeData, complete) in
|
||||
return (thumbnailData, fullSizeData, complete)
|
||||
}
|
||||
}
|
||||
|
||||
return fullSizeData
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,14 +452,14 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
|
||||
}
|
||||
}
|
||||
|
||||
public func patternWallpaperImage(account: Account, accountManager: AccountManager, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false, onlyFullSize: Bool = false) -> Signal<((TransformImageArguments) -> DrawingContext?)?, NoError> {
|
||||
public func patternWallpaperImage(account: Account, accountManager: AccountManager, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false) -> Signal<((TransformImageArguments) -> DrawingContext?)?, NoError> {
|
||||
return patternWallpaperDatas(account: account, accountManager: accountManager, representations: representations, mode: mode, autoFetchFullSize: autoFetchFullSize)
|
||||
|> mapToSignal { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||
return patternWallpaperImageInternal(thumbnailData: thumbnailData, fullSizeData: fullSizeData, fullSizeComplete: fullSizeComplete, mode: mode, onlyFullSize: onlyFullSize)
|
||||
|> mapToSignal { fullSizeData, fullSizeComplete in
|
||||
return patternWallpaperImageInternal(fullSizeData: fullSizeData, fullSizeComplete: fullSizeComplete, mode: mode)
|
||||
}
|
||||
}
|
||||
|
||||
public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Data?, fullSizeComplete: Bool, mode: PatternWallpaperDrawMode, onlyFullSize: Bool = false) -> Signal<((TransformImageArguments) -> DrawingContext?)?, NoError> {
|
||||
private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete: Bool, mode: PatternWallpaperDrawMode) -> Signal<((TransformImageArguments) -> DrawingContext?)?, NoError> {
|
||||
var prominent = false
|
||||
if case .thumbnail = mode {
|
||||
prominent = true
|
||||
@ -511,31 +467,8 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da
|
||||
|
||||
let scale: CGFloat = 0.0
|
||||
|
||||
return .single((thumbnailData, fullSizeData, fullSizeComplete))
|
||||
|> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||
var fullSizeImage: CGImage?
|
||||
var scaledSizeImage: CGImage?
|
||||
if let fullSizeData = fullSizeData, fullSizeComplete {
|
||||
let options = NSMutableDictionary()
|
||||
options[kCGImageSourceShouldCache as NSString] = false as NSNumber
|
||||
if let imageSource = CGImageSourceCreateWithData(fullSizeData as CFData, nil), let image = CGImageSourceCreateImageAtIndex(imageSource, 0, options as CFDictionary) {
|
||||
fullSizeImage = image
|
||||
|
||||
let options = NSMutableDictionary()
|
||||
options.setValue(960 as NSNumber, forKey: kCGImageSourceThumbnailMaxPixelSize as String)
|
||||
options.setValue(true as NSNumber, forKey: kCGImageSourceCreateThumbnailFromImageAlways as String)
|
||||
if let imageSource = CGImageSourceCreateWithData(fullSizeData as CFData, nil), let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options) {
|
||||
scaledSizeImage = image
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if onlyFullSize {
|
||||
if fullSizeData == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return .single((fullSizeData, fullSizeComplete))
|
||||
|> map { fullSizeData, fullSizeComplete in
|
||||
return { arguments in
|
||||
var scale = scale
|
||||
if scale.isZero {
|
||||
@ -554,7 +487,7 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da
|
||||
let color = combinedColor.withAlphaComponent(1.0)
|
||||
let intensity = combinedColor.alpha
|
||||
|
||||
let context = DrawingContext(size: arguments.drawingSize, scale: fullSizeImage == nil ? 1.0 : scale, clear: !arguments.corners.isEmpty)
|
||||
let context = DrawingContext(size: arguments.drawingSize, scale: scale, clear: !arguments.corners.isEmpty)
|
||||
context.withFlippedContext { c in
|
||||
c.setBlendMode(.copy)
|
||||
|
||||
@ -596,7 +529,12 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da
|
||||
|
||||
let overlayImage = generateImage(arguments.drawingRect.size, rotatedContext: { size, c in
|
||||
c.clear(CGRect(origin: CGPoint(), size: size))
|
||||
let image = customArguments.preview ? (scaledSizeImage ?? fullSizeImage) : fullSizeImage
|
||||
var image: UIImage?
|
||||
if let fullSizeData = fullSizeData, let unpackedData = TGGUnzipData(fullSizeData, 2 * 1024 * 1024) {
|
||||
image = drawSvgImage(unpackedData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, .white)
|
||||
} else if let fullSizeData = fullSizeData {
|
||||
image = UIImage(data: fullSizeData)
|
||||
}
|
||||
|
||||
if let customPatternColor = customArguments.customPatternColor, customPatternColor.alpha < 1.0 {
|
||||
c.setBlendMode(.copy)
|
||||
@ -607,7 +545,7 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da
|
||||
}
|
||||
|
||||
if let image = image {
|
||||
var fittedSize = CGSize(width: image.width, height: image.height)
|
||||
var fittedSize = image.size
|
||||
if abs(fittedSize.width - arguments.boundingSize.width).isLessThanOrEqualTo(CGFloat(1.0)) {
|
||||
fittedSize.width = arguments.boundingSize.width
|
||||
}
|
||||
@ -619,7 +557,7 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da
|
||||
let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
|
||||
|
||||
c.interpolationQuality = customArguments.preview ? .low : .medium
|
||||
c.clip(to: fittedRect, mask: image)
|
||||
c.clip(to: fittedRect, mask: image.cgImage!)
|
||||
|
||||
if let customPatternColor = customArguments.customPatternColor {
|
||||
c.setFillColor(customPatternColor.cgColor)
|
||||
@ -713,6 +651,55 @@ public func solidColorImage(_ color: UIColor) -> Signal<(TransformImageArguments
|
||||
})
|
||||
}
|
||||
|
||||
public func drawWallpaperGradientImage(_ colors: [UIColor], rotation: Int32? = nil, context: CGContext, size: CGSize) {
|
||||
guard !colors.isEmpty else {
|
||||
return
|
||||
}
|
||||
guard colors.count > 1 else {
|
||||
context.setFillColor(colors[0].cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
return
|
||||
}
|
||||
|
||||
let drawingRect = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
let c = context
|
||||
|
||||
if colors.count >= 3 {
|
||||
let image = GradientBackgroundNode.generatePreview(size: CGSize(width: 60.0, height: 60.0), colors: colors)
|
||||
c.translateBy(x: drawingRect.midX, y: drawingRect.midY)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -drawingRect.midX, y: -drawingRect.midY)
|
||||
c.draw(image.cgImage!, in: drawingRect)
|
||||
c.translateBy(x: drawingRect.midX, y: drawingRect.midY)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -drawingRect.midX, y: -drawingRect.midY)
|
||||
} else {
|
||||
let gradientColors = colors.map { $0.withAlphaComponent(1.0).cgColor } as CFArray
|
||||
let delta: CGFloat = 1.0 / (CGFloat(colors.count) - 1.0)
|
||||
|
||||
var locations: [CGFloat] = []
|
||||
for i in 0 ..< colors.count {
|
||||
locations.append(delta * CGFloat(i))
|
||||
}
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
if let rotation = rotation {
|
||||
c.saveGState()
|
||||
c.translateBy(x: drawingRect.width / 2.0, y: drawingRect.height / 2.0)
|
||||
c.rotate(by: CGFloat(rotation) * CGFloat.pi / 180.0)
|
||||
c.translateBy(x: -drawingRect.width / 2.0, y: -drawingRect.height / 2.0)
|
||||
}
|
||||
|
||||
c.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: drawingRect.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
||||
|
||||
if rotation != nil {
|
||||
c.restoreGState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func gradientImage(_ colors: [UIColor], rotation: Int32? = nil) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
guard !colors.isEmpty else {
|
||||
return .complete()
|
||||
@ -1157,18 +1144,23 @@ public func themeImage(account: Account, accountManager: AccountManager, source:
|
||||
case let .settings(settings):
|
||||
theme = .single((makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: .builtin(PresentationBuiltinThemeReference(baseTheme: settings.baseTheme)), accentColor: UIColor(argb: settings.accentColor), backgroundColors: [], bubbleColors: settings.messageColors.flatMap { (UIColor(argb: $0.top), UIColor(argb: $0.bottom)) }, wallpaper: settings.wallpaper, serviceBackgroundColor: nil, preview: false), nil))
|
||||
}
|
||||
|
||||
enum WallpaperImage {
|
||||
case image(UIImage)
|
||||
case pattern(data: Data, colors: [UInt32], intensity: Int32)
|
||||
}
|
||||
|
||||
let data = theme
|
||||
|> mapToSignal { (theme, thumbnailData) -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
|
||||
|> mapToSignal { (theme, thumbnailData) -> Signal<(PresentationTheme?, WallpaperImage?, Data?), NoError> in
|
||||
if let theme = theme {
|
||||
if case let .file(file) = theme.chat.defaultWallpaper {
|
||||
return cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
||||
|> mapToSignal { wallpaper -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
|
||||
|> mapToSignal { wallpaper -> Signal<(PresentationTheme?, WallpaperImage?, Data?), NoError> in
|
||||
if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper {
|
||||
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 100, height: 100), resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)))
|
||||
return wallpaperDatas(account: account, accountManager: accountManager, fileReference: .standalone(media: file.file), representations: convertedRepresentations, alwaysShowThumbnailFirst: false, thumbnail: false, onlyFullSize: true, autoFetchFullSize: true, synchronousLoad: false)
|
||||
|> mapToSignal { _, fullSizeData, complete -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
|
||||
|> mapToSignal { _, fullSizeData, complete -> Signal<(PresentationTheme?, WallpaperImage?, Data?), NoError> in
|
||||
guard complete, let fullSizeData = fullSizeData else {
|
||||
return .complete()
|
||||
}
|
||||
@ -1176,10 +1168,10 @@ public func themeImage(account: Account, accountManager: AccountManager, source:
|
||||
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
|
||||
|
||||
if wallpaper.wallpaper.isPattern, !file.settings.colors.isEmpty, let intensity = file.settings.intensity {
|
||||
return accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperRepresentation(colors: file.settings.colors, intensity: intensity, rotation: file.settings.rotation), complete: true, fetch: true)
|
||||
return accountManager.mediaBox.resourceData(file.file.resource)
|
||||
|> mapToSignal { data in
|
||||
if data.complete, let imageData = try? Data(contentsOf: URL(fileURLWithPath: data.path)), let image = UIImage(data: imageData) {
|
||||
return .single((theme, image, thumbnailData))
|
||||
if data.complete, let imageData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
||||
return .single((theme, .pattern(data: imageData, colors: file.settings.colors, intensity: intensity), thumbnailData))
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
@ -1188,13 +1180,13 @@ public func themeImage(account: Account, accountManager: AccountManager, source:
|
||||
return accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true)
|
||||
|> mapToSignal { data in
|
||||
if data.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: data.path)), let image = UIImage(data: data) {
|
||||
return .single((theme, image, thumbnailData))
|
||||
return .single((theme, .image(image), thumbnailData))
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
} else if let image = UIImage(data: fullSizeData) {
|
||||
return .single((theme, image, thumbnailData))
|
||||
return .single((theme, .image(image), thumbnailData))
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
@ -1262,8 +1254,27 @@ public func themeImage(account: Account, accountManager: AccountManager, source:
|
||||
if let theme = theme {
|
||||
context.withFlippedContext { c in
|
||||
c.setBlendMode(.normal)
|
||||
|
||||
drawThemeImage(context: c, theme: theme, wallpaperImage: wallpaperImage, size: arguments.drawingSize)
|
||||
|
||||
switch wallpaperImage {
|
||||
case let .image(image):
|
||||
drawThemeImage(context: c, theme: theme, wallpaperImage: image, size: arguments.drawingSize)
|
||||
case let .pattern(data, colors, intensity):
|
||||
let wallpaperImage = generateImage(arguments.drawingSize, rotatedContext: { size, context in
|
||||
drawWallpaperGradientImage(colors.map(UIColor.init(rgb:)), context: context, size: size)
|
||||
if let unpackedData = TGGUnzipData(data, 2 * 1024 * 1024), let image = drawSvgImage(unpackedData, arguments.drawingSize, .clear, .black) {
|
||||
context.setBlendMode(.softLight)
|
||||
context.setAlpha(abs(CGFloat(intensity)) / 100.0)
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: arguments.drawingSize))
|
||||
} else if let image = UIImage(data: data) {
|
||||
context.setBlendMode(.softLight)
|
||||
context.setAlpha(abs(CGFloat(intensity)) / 100.0)
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: arguments.drawingSize))
|
||||
}
|
||||
})
|
||||
drawThemeImage(context: c, theme: theme, wallpaperImage: wallpaperImage, size: arguments.drawingSize)
|
||||
case .none:
|
||||
drawThemeImage(context: c, theme: theme, wallpaperImage: nil, size: arguments.drawingSize)
|
||||
}
|
||||
|
||||
c.setStrokeColor(theme.rootController.navigationBar.separatorColor.cgColor)
|
||||
c.setLineWidth(2.0)
|
||||
@ -1486,10 +1497,7 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
|
||||
if intensity < 0 {
|
||||
return .single(((.black, nil, []), incomingColor, outgoingColor, nil, rotation))
|
||||
} else {
|
||||
return accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperRepresentation(colors: file.settings.colors, intensity: intensity, rotation: file.settings.rotation), complete: true, fetch: true)
|
||||
|> mapToSignal { _ in
|
||||
return .single((effectiveBackgroundColor, incomingColor, outgoingColor, nil, rotation))
|
||||
}
|
||||
return .single((effectiveBackgroundColor, incomingColor, outgoingColor, nil, rotation))
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit c567dad74ffcea9df820809b2cdef90f544d68ca
|
||||
Subproject commit 7fdc010d9e71a0c39d3f63d421d1bef762b6a034
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "7.8",
|
||||
"app": "7.8.1",
|
||||
"bazel": "4.0.0",
|
||||
"xcode": "12.4"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user