mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit 'fdf8fef76c'
This commit is contained in:
commit
6d42458fe7
12 changed files with 282 additions and 158 deletions
|
|
@ -5,8 +5,8 @@
|
|||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "When you choose to share your Live Location with friends in a chat, Telegram needs background access to your location to keep them updated for the duration of the live sharing.";
|
||||
"NSLocationAlwaysUsageDescription" = "When you choose to share your live location with friends in a chat, Telegram needs background access to your location to keep them updated for the duration of the live sharing. You also need this to send locations from an Apple Watch.";
|
||||
"NSCameraUsageDescription" = "We need this so that you can take and share photos and videos, as well as make video calls.";
|
||||
"NSPhotoLibraryUsageDescription" = "We need this so that you can share photos and videos from your photo library.";
|
||||
"NSPhotoLibraryAddUsageDescription" = "We need this so that you can save photos and videos to your photo library.";
|
||||
"NSPhotoLibraryUsageDescription" = "We need this so that you can share photos and videos from your photo library and save the ones you capture.";
|
||||
"NSPhotoLibraryAddUsageDescription" = "We need this so that you can save photos and videos to your photo library and save the ones you capture.";
|
||||
"NSMicrophoneUsageDescription" = "We need this so that you can record and share voice messages and videos with sound.";
|
||||
"NSSiriUsageDescription" = "You can use Siri to send messages.";
|
||||
"NSFaceIDUsageDescription" = "You can use Face ID to unlock the app.";
|
||||
|
|
|
|||
|
|
@ -1376,7 +1376,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||
func makeBotPreviewEditorScreen(context: AccountContext, source: Any?, target: Stories.PendingTarget, transitionArguments: (UIView, CGRect, UIImage?)?, transitionOut: @escaping () -> BotPreviewEditorTransitionOut?, externalState: MediaEditorTransitionOutExternalState, completion: @escaping (MediaEditorScreenResult, @escaping (@escaping () -> Void) -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController
|
||||
func makeStickerEditorScreen(context: AccountContext, source: Any?, intro: Bool, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController
|
||||
func makeStickerMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController
|
||||
func makeAvatarMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, canDelete: Bool, performDelete: @escaping () -> Void, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController
|
||||
func makeAvatarMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, canDelete: Bool, performDelete: @escaping () -> Void, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> (ViewController?, Any?)
|
||||
func makeStoryMediaPickerScreen(context: AccountContext, isDark: Bool, forCollage: Bool, selectionLimit: Int?, getSourceRect: @escaping () -> CGRect, completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, multipleCompletion: @escaping ([Any], Bool) -> Void, dismissed: @escaping () -> Void, groupsPresented: @escaping () -> Void) -> ViewController
|
||||
func makeStickerPickerScreen(context: AccountContext, inputData: Promise<StickerPickerInput>, completion: @escaping (FileMediaReference) -> Void) -> ViewController
|
||||
func makeProxySettingsController(sharedContext: SharedAccountContext, account: UnauthorizedAccount) -> ViewController
|
||||
|
|
@ -1678,7 +1678,7 @@ public struct StarsSubscriptionConfiguration {
|
|||
return StarsSubscriptionConfiguration(
|
||||
maxFee: 2500,
|
||||
usdWithdrawRate: 1200,
|
||||
tonUsdRate: 0,
|
||||
tonUsdRate: 1.0,
|
||||
paidMessageMaxAmount: 10000,
|
||||
paidMessageCommissionPermille: 850,
|
||||
paidMessagesAvailable: false,
|
||||
|
|
@ -1698,7 +1698,7 @@ public struct StarsSubscriptionConfiguration {
|
|||
|
||||
public let maxFee: Int64
|
||||
public let usdWithdrawRate: Int64
|
||||
public let tonUsdRate: Int64
|
||||
public let tonUsdRate: Double
|
||||
public let paidMessageMaxAmount: Int64
|
||||
public let paidMessageCommissionPermille: Int32
|
||||
public let paidMessagesAvailable: Bool
|
||||
|
|
@ -1717,7 +1717,7 @@ public struct StarsSubscriptionConfiguration {
|
|||
fileprivate init(
|
||||
maxFee: Int64,
|
||||
usdWithdrawRate: Int64,
|
||||
tonUsdRate: Int64,
|
||||
tonUsdRate: Double,
|
||||
paidMessageMaxAmount: Int64,
|
||||
paidMessageCommissionPermille: Int32,
|
||||
paidMessagesAvailable: Bool,
|
||||
|
|
@ -1756,7 +1756,7 @@ public struct StarsSubscriptionConfiguration {
|
|||
if let data = appConfiguration.data {
|
||||
let maxFee = (data["stars_subscription_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.maxFee
|
||||
let usdWithdrawRate = (data["stars_usd_withdraw_rate_x1000"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.usdWithdrawRate
|
||||
let tonUsdRate = (data["ton_usd_rate"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.tonUsdRate
|
||||
let tonUsdRate = (data["ton_usd_rate"] as? Double) ?? StarsSubscriptionConfiguration.defaultValue.tonUsdRate
|
||||
let paidMessageMaxAmount = (data["stars_paid_message_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageMaxAmount
|
||||
let paidMessageCommissionPermille = (data["stars_paid_message_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageCommissionPermille
|
||||
let paidMessagesAvailable = (data["stars_paid_messages_available"] as? Bool) ?? StarsSubscriptionConfiguration.defaultValue.paidMessagesAvailable
|
||||
|
|
|
|||
|
|
@ -3777,126 +3777,188 @@ public func avatarMediaPickerController(
|
|||
performDelete: @escaping () -> Void,
|
||||
completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void,
|
||||
dismissed: @escaping () -> Void
|
||||
) -> ViewController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
|
||||
let updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>) = (presentationData, .single(presentationData))
|
||||
let controller = AttachmentController(
|
||||
context: context,
|
||||
updatedPresentationData: updatedPresentationData,
|
||||
style: .glass,
|
||||
chatLocation: nil,
|
||||
buttons: [.standalone],
|
||||
initialButton: .standalone,
|
||||
fromMenu: false,
|
||||
hasTextInput: false,
|
||||
makeEntityInputView: {
|
||||
return nil
|
||||
})
|
||||
controller.forceSourceRect = true
|
||||
controller.getSourceRect = getSourceRect
|
||||
controller.requestController = { [weak controller] _, present in
|
||||
var mainButtonState: AttachmentMainButtonState?
|
||||
|
||||
if canDelete {
|
||||
mainButtonState = AttachmentMainButtonState(text: presentationData.strings.MediaPicker_RemovePhoto, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false)
|
||||
) -> (controller: ViewController?, holder: Any?) {
|
||||
if #available(iOS 14.0, *), PHPhotoLibrary.authorizationStatus(for: .readWrite) != .authorized {
|
||||
final class PickerDelegate: NSObject, PHPickerViewControllerDelegate {
|
||||
var completion: ((Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void)?
|
||||
|
||||
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
||||
picker.dismiss(animated: true)
|
||||
|
||||
for item in results {
|
||||
if item.itemProvider.canLoadObject(ofClass: UIImage.self) {
|
||||
item.itemProvider.loadObject(ofClass: UIImage.self) { image, error in
|
||||
if let uiImage = image as? UIImage {
|
||||
Queue.mainQueue().async {
|
||||
self.completion?(uiImage, nil, CGRect(), nil, false, { _ in return nil }, {})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mediaPickerController = MediaPickerScreenImpl(
|
||||
let holder = PickerDelegate()
|
||||
holder.completion = completion
|
||||
|
||||
let openMediaPicker = {
|
||||
var configuration = PHPickerConfiguration(photoLibrary: .shared())
|
||||
configuration.filter = .images
|
||||
configuration.selectionLimit = 1
|
||||
|
||||
let picker = PHPickerViewController(configuration: configuration)
|
||||
picker.delegate = holder
|
||||
(context.sharedContext.mainWindow?.viewController as? NavigationController)?.topViewController?.present(picker, animated: true, completion: nil)
|
||||
}
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = ActionSheetController(presentationData: presentationData)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
|
||||
var items: [ActionSheetButtonItem] = [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Settings_SetNewProfilePhotoOrVideo, color: .accent, action: {
|
||||
dismissAction()
|
||||
openMediaPicker()
|
||||
}),
|
||||
ActionSheetButtonItem(title: presentationData.strings.ProfilePhoto_SetEmoji, color: .accent, action: {
|
||||
dismissAction()
|
||||
completion(nil, nil, CGRect(), nil, false, { _ in return nil }, {})
|
||||
})
|
||||
]
|
||||
if canDelete {
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.MediaPicker_RemovePhoto, color: .destructive, action: {
|
||||
dismissAction()
|
||||
performDelete()
|
||||
}))
|
||||
}
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
return (controller, holder)
|
||||
} else {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
|
||||
let updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>) = (presentationData, .single(presentationData))
|
||||
let controller = AttachmentController(
|
||||
context: context,
|
||||
updatedPresentationData: updatedPresentationData,
|
||||
style: .glass,
|
||||
peer: nil,
|
||||
threadTitle: nil,
|
||||
chatLocation: nil,
|
||||
bannedSendPhotos: nil,
|
||||
bannedSendVideos: nil,
|
||||
subject: .assets(nil, .createAvatar),
|
||||
mainButtonState: mainButtonState,
|
||||
mainButtonAction: { [weak controller] in
|
||||
controller?.dismiss(animated: true)
|
||||
performDelete()
|
||||
}
|
||||
)
|
||||
mediaPickerController.customSelection = { controller, result in
|
||||
if let result = result as? PHAsset {
|
||||
controller.updateHiddenMediaId(result.localIdentifier)
|
||||
if let transitionView = controller.transitionView(for: result.localIdentifier, snapshot: false) {
|
||||
let transitionOut: (Bool?) -> (UIView, CGRect)? = { isNew in
|
||||
if let isNew {
|
||||
if isNew {
|
||||
controller.updateHiddenMediaId(nil)
|
||||
if let transitionView = controller.defaultTransitionView() {
|
||||
return (transitionView, transitionView.bounds)
|
||||
}
|
||||
} else if let transitionView = controller.transitionView(for: result.localIdentifier, snapshot: false) {
|
||||
return (transitionView, transitionView.bounds)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
completion(result, transitionView, transitionView.bounds, controller.transitionImage(for: result.localIdentifier), false, transitionOut, { [weak controller] in
|
||||
controller?.updateHiddenMediaId(nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
mediaPickerController.openAvatarEditor = { [weak controller] in
|
||||
completion(nil, nil, .zero, nil, false, { _ in return nil }, {
|
||||
buttons: [.standalone],
|
||||
initialButton: .standalone,
|
||||
fromMenu: false,
|
||||
hasTextInput: false,
|
||||
makeEntityInputView: {
|
||||
return nil
|
||||
})
|
||||
controller?.dismiss(animated: true)
|
||||
}
|
||||
mediaPickerController.openCamera = { [weak controller] cameraHolder in
|
||||
let _ = controller
|
||||
guard let cameraHolder = cameraHolder as? CameraHolder else {
|
||||
return
|
||||
controller.forceSourceRect = true
|
||||
controller.getSourceRect = getSourceRect
|
||||
controller.requestController = { [weak controller] _, present in
|
||||
var mainButtonState: AttachmentMainButtonState?
|
||||
|
||||
if canDelete {
|
||||
mainButtonState = AttachmentMainButtonState(text: presentationData.strings.MediaPicker_RemovePhoto, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false)
|
||||
}
|
||||
|
||||
var returnToCameraImpl: (() -> Void)?
|
||||
|
||||
let cameraScreen = context.sharedContext.makeCameraScreen(
|
||||
let mediaPickerController = MediaPickerScreenImpl(
|
||||
context: context,
|
||||
mode: .avatar,
|
||||
cameraHolder: cameraHolder,
|
||||
transitionIn: CameraScreenTransitionIn(
|
||||
sourceView: cameraHolder.parentView,
|
||||
sourceRect: cameraHolder.parentView.bounds,
|
||||
sourceCornerRadius: 0.0,
|
||||
useFillAnimation: false
|
||||
),
|
||||
transitionOut: { _ in
|
||||
return CameraScreenTransitionOut(
|
||||
destinationView: cameraHolder.parentView,
|
||||
destinationRect: cameraHolder.parentView.bounds,
|
||||
destinationCornerRadius: 0.0
|
||||
)
|
||||
},
|
||||
completion: { result, commit in
|
||||
completion(result, nil, .zero, nil, true, { _ in return nil }, {
|
||||
returnToCameraImpl?()
|
||||
})
|
||||
},
|
||||
transitionedOut: { [weak cameraHolder] in
|
||||
if let cameraHolder {
|
||||
cameraHolder.restore()
|
||||
}
|
||||
updatedPresentationData: updatedPresentationData,
|
||||
style: .glass,
|
||||
peer: nil,
|
||||
threadTitle: nil,
|
||||
chatLocation: nil,
|
||||
bannedSendPhotos: nil,
|
||||
bannedSendVideos: nil,
|
||||
subject: .assets(nil, .createAvatar),
|
||||
mainButtonState: mainButtonState,
|
||||
mainButtonAction: { [weak controller] in
|
||||
controller?.dismiss(animated: true)
|
||||
performDelete()
|
||||
}
|
||||
)
|
||||
controller?.push(cameraScreen)
|
||||
|
||||
returnToCameraImpl = { [weak cameraScreen] in
|
||||
if let cameraScreen = cameraScreen as? CameraScreen {
|
||||
cameraScreen.returnFromEditor()
|
||||
mediaPickerController.customSelection = { controller, result in
|
||||
if let result = result as? PHAsset {
|
||||
controller.updateHiddenMediaId(result.localIdentifier)
|
||||
if let transitionView = controller.transitionView(for: result.localIdentifier, snapshot: false) {
|
||||
let transitionOut: (Bool?) -> (UIView, CGRect)? = { isNew in
|
||||
if let isNew {
|
||||
if isNew {
|
||||
controller.updateHiddenMediaId(nil)
|
||||
if let transitionView = controller.defaultTransitionView() {
|
||||
return (transitionView, transitionView.bounds)
|
||||
}
|
||||
} else if let transitionView = controller.transitionView(for: result.localIdentifier, snapshot: false) {
|
||||
return (transitionView, transitionView.bounds)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
completion(result, transitionView, transitionView.bounds, controller.transitionImage(for: result.localIdentifier), false, transitionOut, { [weak controller] in
|
||||
controller?.updateHiddenMediaId(nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
mediaPickerController.openAvatarEditor = { [weak controller] in
|
||||
completion(nil, nil, .zero, nil, false, { _ in return nil }, {
|
||||
})
|
||||
controller?.dismiss(animated: true)
|
||||
}
|
||||
mediaPickerController.openCamera = { [weak controller] cameraHolder in
|
||||
let _ = controller
|
||||
guard let cameraHolder = cameraHolder as? CameraHolder else {
|
||||
return
|
||||
}
|
||||
|
||||
var returnToCameraImpl: (() -> Void)?
|
||||
|
||||
let cameraScreen = context.sharedContext.makeCameraScreen(
|
||||
context: context,
|
||||
mode: .avatar,
|
||||
cameraHolder: cameraHolder,
|
||||
transitionIn: CameraScreenTransitionIn(
|
||||
sourceView: cameraHolder.parentView,
|
||||
sourceRect: cameraHolder.parentView.bounds,
|
||||
sourceCornerRadius: 0.0,
|
||||
useFillAnimation: false
|
||||
),
|
||||
transitionOut: { _ in
|
||||
return CameraScreenTransitionOut(
|
||||
destinationView: cameraHolder.parentView,
|
||||
destinationRect: cameraHolder.parentView.bounds,
|
||||
destinationCornerRadius: 0.0
|
||||
)
|
||||
},
|
||||
completion: { result, commit in
|
||||
completion(result, nil, .zero, nil, true, { _ in return nil }, {
|
||||
returnToCameraImpl?()
|
||||
})
|
||||
},
|
||||
transitionedOut: { [weak cameraHolder] in
|
||||
if let cameraHolder {
|
||||
cameraHolder.restore()
|
||||
}
|
||||
}
|
||||
)
|
||||
controller?.push(cameraScreen)
|
||||
|
||||
returnToCameraImpl = { [weak cameraScreen] in
|
||||
if let cameraScreen = cameraScreen as? CameraScreen {
|
||||
cameraScreen.returnFromEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
present(mediaPickerController, mediaPickerController.mediaPickerContext)
|
||||
}
|
||||
present(mediaPickerController, mediaPickerController.mediaPickerContext)
|
||||
controller.willDismiss = {
|
||||
dismissed()
|
||||
}
|
||||
controller.navigationPresentation = .flatModal
|
||||
controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
return (controller, nil)
|
||||
}
|
||||
controller.willDismiss = {
|
||||
dismissed()
|
||||
}
|
||||
controller.navigationPresentation = .flatModal
|
||||
controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
return controller
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1578,7 +1578,8 @@ func _internal_upgradeStarGift(account: Account, formId: Int64?, reference: Star
|
|||
prepaidUpgradeHash: nil,
|
||||
upgradeSeparate: false,
|
||||
dropOriginalDetailsStars: dropOriginalDetailsStars,
|
||||
number: nil
|
||||
number: nil,
|
||||
isRefunded: false
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -2533,6 +2534,7 @@ public final class ProfileGiftsContext {
|
|||
case upgradeSeparate
|
||||
case dropOriginalDetailsStars
|
||||
case number
|
||||
case isRefunded
|
||||
}
|
||||
|
||||
public let gift: TelegramCore.StarGift
|
||||
|
|
@ -2556,7 +2558,8 @@ public final class ProfileGiftsContext {
|
|||
public let upgradeSeparate: Bool
|
||||
public let dropOriginalDetailsStars: Int64?
|
||||
public let number: Int32?
|
||||
|
||||
public let isRefunded: Bool
|
||||
|
||||
fileprivate let _fromPeerId: EnginePeer.Id?
|
||||
|
||||
public enum DecodingError: Error {
|
||||
|
|
@ -2584,7 +2587,8 @@ public final class ProfileGiftsContext {
|
|||
prepaidUpgradeHash: String?,
|
||||
upgradeSeparate: Bool,
|
||||
dropOriginalDetailsStars: Int64?,
|
||||
number: Int32?
|
||||
number: Int32?,
|
||||
isRefunded: Bool
|
||||
) {
|
||||
self.gift = gift
|
||||
self.reference = reference
|
||||
|
|
@ -2608,6 +2612,7 @@ public final class ProfileGiftsContext {
|
|||
self.upgradeSeparate = upgradeSeparate
|
||||
self.dropOriginalDetailsStars = dropOriginalDetailsStars
|
||||
self.number = number
|
||||
self.isRefunded = isRefunded
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
|
|
@ -2641,6 +2646,7 @@ public final class ProfileGiftsContext {
|
|||
self.upgradeSeparate = try container.decodeIfPresent(Bool.self, forKey: .upgradeSeparate) ?? false
|
||||
self.dropOriginalDetailsStars = try container.decodeIfPresent(Int64.self, forKey: .dropOriginalDetailsStars)
|
||||
self.number = try container.decodeIfPresent(Int32.self, forKey: .number)
|
||||
self.isRefunded = try container.decodeIfPresent(Bool.self, forKey: .isRefunded) ?? false
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
|
|
@ -2667,6 +2673,8 @@ public final class ProfileGiftsContext {
|
|||
try container.encode(self.upgradeSeparate, forKey: .upgradeSeparate)
|
||||
try container.encodeIfPresent(self.dropOriginalDetailsStars, forKey: .dropOriginalDetailsStars)
|
||||
try container.encodeIfPresent(self.number, forKey: .number)
|
||||
try container.encode(self.isRefunded, forKey: .isRefunded)
|
||||
|
||||
}
|
||||
|
||||
public func withGift(_ gift: TelegramCore.StarGift) -> StarGift {
|
||||
|
|
@ -2691,7 +2699,8 @@ public final class ProfileGiftsContext {
|
|||
prepaidUpgradeHash: self.prepaidUpgradeHash,
|
||||
upgradeSeparate: self.upgradeSeparate,
|
||||
dropOriginalDetailsStars: self.dropOriginalDetailsStars,
|
||||
number: self.number
|
||||
number: self.number,
|
||||
isRefunded: self.isRefunded
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -2717,7 +2726,8 @@ public final class ProfileGiftsContext {
|
|||
prepaidUpgradeHash: self.prepaidUpgradeHash,
|
||||
upgradeSeparate: self.upgradeSeparate,
|
||||
dropOriginalDetailsStars: self.dropOriginalDetailsStars,
|
||||
number: self.number
|
||||
number: self.number,
|
||||
isRefunded: self.isRefunded
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -2743,7 +2753,8 @@ public final class ProfileGiftsContext {
|
|||
prepaidUpgradeHash: self.prepaidUpgradeHash,
|
||||
upgradeSeparate: self.upgradeSeparate,
|
||||
dropOriginalDetailsStars: self.dropOriginalDetailsStars,
|
||||
number: self.number
|
||||
number: self.number,
|
||||
isRefunded: self.isRefunded
|
||||
)
|
||||
}
|
||||
fileprivate func withFromPeer(_ fromPeer: EnginePeer?) -> StarGift {
|
||||
|
|
@ -2768,7 +2779,8 @@ public final class ProfileGiftsContext {
|
|||
prepaidUpgradeHash: self.prepaidUpgradeHash,
|
||||
upgradeSeparate: self.upgradeSeparate,
|
||||
dropOriginalDetailsStars: self.dropOriginalDetailsStars,
|
||||
number: self.number
|
||||
number: self.number,
|
||||
isRefunded: self.isRefunded
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -2794,7 +2806,8 @@ public final class ProfileGiftsContext {
|
|||
prepaidUpgradeHash: self.prepaidUpgradeHash,
|
||||
upgradeSeparate: self.upgradeSeparate,
|
||||
dropOriginalDetailsStars: self.dropOriginalDetailsStars,
|
||||
number: self.number
|
||||
number: self.number,
|
||||
isRefunded: self.isRefunded
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3063,6 +3076,7 @@ extension ProfileGiftsContext.State.StarGift {
|
|||
self.upgradeSeparate = (flags & (1 << 17)) != 0
|
||||
self.dropOriginalDetailsStars = dropOriginalDetailsStars
|
||||
self.number = number
|
||||
self.isRefunded = (flags & (1 << 9)) != 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1644,7 +1644,7 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot
|
|||
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails, .starGiftAuctionBid:
|
||||
receiptMessageId = nil
|
||||
}
|
||||
} else if case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, _, peerId, _, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars, _, _) = action.action, case let .Id(messageId) = message.id {
|
||||
} else if case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, isRefunded, _, peerId, _, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars, _, _) = action.action, case let .Id(messageId) = message.id {
|
||||
let reference: StarGiftReference
|
||||
if let peerId, let savedId {
|
||||
reference = .peer(peerId: peerId, id: savedId)
|
||||
|
|
@ -1672,7 +1672,8 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot
|
|||
prepaidUpgradeHash: nil,
|
||||
upgradeSeparate: false,
|
||||
dropOriginalDetailsStars: dropOriginalDetailsStars,
|
||||
number: nil
|
||||
number: nil,
|
||||
isRefunded: isRefunded
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1663,7 +1663,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||
case .stars:
|
||||
priceString = strings.Notification_StarsGiftOffer_OfferYou_Stars(Int32(clamping: amount.amount.value))
|
||||
case .ton:
|
||||
priceString = "\(amount.amount) TON"
|
||||
priceString = formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat) + " TON"
|
||||
}
|
||||
|
||||
attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGiftOffer_OfferYou(peerName, priceString, giftTitle)._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||
|
|
@ -1673,7 +1673,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||
case .stars:
|
||||
priceString = strings.Notification_StarsGiftOffer_Offer_Stars(Int32(clamping: amount.amount.value))
|
||||
case .ton:
|
||||
priceString = "\(amount.amount) TON"
|
||||
priceString = formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat) + " TON"
|
||||
}
|
||||
|
||||
attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGiftOffer_Offer(peerName, priceString, giftTitle)._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||
|
|
@ -1696,7 +1696,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||
case .stars:
|
||||
priceString = strings.Notification_StarsGiftOffer_ExpiredYou_Stars(Int32(clamping: amount.amount.value))
|
||||
case .ton:
|
||||
priceString = "\(amount.amount) TON"
|
||||
priceString = formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat) + " TON"
|
||||
}
|
||||
|
||||
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: peerIds)
|
||||
|
|
@ -1709,7 +1709,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||
case .stars:
|
||||
priceString = strings.Notification_StarsGiftOffer_Expired_Stars(Int32(clamping: amount.amount.value))
|
||||
case .ton:
|
||||
priceString = "\(amount.amount) TON"
|
||||
priceString = formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat) + " TON"
|
||||
}
|
||||
|
||||
let timeString = "[TODO]"
|
||||
|
|
@ -1730,7 +1730,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||
case .stars:
|
||||
priceString = strings.Notification_StarsGiftOffer_Rejected_Stars(Int32(clamping: amount.amount.value))
|
||||
case .ton:
|
||||
priceString = "\(amount.amount) TON"
|
||||
priceString = formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat) + " TON"
|
||||
}
|
||||
|
||||
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: peerIds)
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ public class ChatMessageGiftOfferBubbleContentNode: ChatMessageBubbleContentNode
|
|||
case .stars:
|
||||
priceString = item.presentationData.strings.Notification_StarGiftOffer_Offer_Stars(Int32(clamping: amount.amount.value))
|
||||
case .ton:
|
||||
priceString = "\(amount.amount) TON"
|
||||
priceString = formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat) + " TON"
|
||||
}
|
||||
|
||||
let peerName = item.message.peers[item.message.id.peerId].flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ public func giftOfferAlertController(
|
|||
case .stars:
|
||||
priceString = strings.Chat_GiftPurchaseOffer_AcceptConfirmation_Text_Stars(Int32(clamping: amount.amount.value))
|
||||
case .ton:
|
||||
priceString = "\(amount.amount) TON"
|
||||
priceString = formatTonAmountText(amount.amount.value, dateTimeFormat: presentationData.dateTimeFormat) + " TON"
|
||||
}
|
||||
|
||||
let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
|
|
@ -507,6 +507,7 @@ public func giftOfferAlertController(
|
|||
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: buttonText, action: { [weak contentNode] in
|
||||
contentNode?.inProgress = true
|
||||
commit()
|
||||
dismissImpl?(true)
|
||||
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
})]
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import ChatThemeScreen
|
|||
import ProfileLevelRatingBarComponent
|
||||
import AnimatedTextComponent
|
||||
import InfoParagraphComponent
|
||||
import ChatMessagePaymentAlertController
|
||||
|
||||
private final class GiftViewSheetContent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
|
@ -2337,6 +2338,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
guard let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, case let .peerId(ownerPeerId) = uniqueGift.owner, let controller = self.getController() else {
|
||||
return
|
||||
}
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: ownerPeerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
guard let self, let peer else {
|
||||
|
|
@ -2346,13 +2348,41 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.commitGiftBuyOffer(peer: peer, price: amount, duration: duration)
|
||||
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars(id: peer.id))
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller] sendPaidMessageStars in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let action: (Int64?) -> Void = { allowPaidStars in
|
||||
self.commitGiftBuyOffer(peer: peer, price: amount, duration: duration, allowPaidStars: allowPaidStars)
|
||||
}
|
||||
if let sendPaidMessageStars, sendPaidMessageStars.value > 0 {
|
||||
let alertController = chatMessagePaymentAlertController(
|
||||
context: nil,
|
||||
presentationData: presentationData,
|
||||
updatedPresentationData: nil,
|
||||
peers: [EngineRenderedPeer(peer: peer)],
|
||||
count: 1,
|
||||
amount: sendPaidMessageStars,
|
||||
totalAmount: nil,
|
||||
hasCheck: false,
|
||||
navigationController: controller?.navigationController as? NavigationController,
|
||||
completion: { _ in
|
||||
action(sendPaidMessageStars.value)
|
||||
}
|
||||
)
|
||||
controller?.present(alertController, in: .window(.root))
|
||||
} else {
|
||||
action(nil)
|
||||
}
|
||||
})
|
||||
}))
|
||||
controller.push(buyController)
|
||||
})
|
||||
}
|
||||
|
||||
func commitGiftBuyOffer(peer: EnginePeer, price: CurrencyAmount, duration: Int32) {
|
||||
func commitGiftBuyOffer(peer: EnginePeer, price: CurrencyAmount, duration: Int32, allowPaidStars: Int64?) {
|
||||
guard let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
|
||||
return
|
||||
}
|
||||
|
|
@ -2362,7 +2392,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.upgradeDisposable = (context.engine.payments.sendStarGiftOffer(peerId: peer.id, slug: uniqueGift.slug, amount: price, duration: duration, allowPaidStars: nil)
|
||||
self.upgradeDisposable = (context.engine.payments.sendStarGiftOffer(peerId: peer.id, slug: uniqueGift.slug, amount: price, duration: duration, allowPaidStars: allowPaidStars)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
}, completed: { [weak self, weak starsContext] in
|
||||
guard let self else {
|
||||
|
|
@ -2383,11 +2413,15 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
guard let self, let controller = self.getController() else {
|
||||
return
|
||||
}
|
||||
var finalStars = price.amount.value
|
||||
if let allowPaidStars {
|
||||
finalStars += allowPaidStars
|
||||
}
|
||||
let purchaseController = context.sharedContext.makeStarsPurchaseScreen(
|
||||
context: context,
|
||||
starsContext: starsContext,
|
||||
options: options ?? [],
|
||||
purpose: .starGiftOffer(requiredStars: price.amount.value),
|
||||
purpose: .starGiftOffer(requiredStars: finalStars),
|
||||
targetPeerId: nil,
|
||||
customTheme: nil,
|
||||
completion: { [weak self, weak starsContext] stars in
|
||||
|
|
@ -2411,7 +2445,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
self.inProgress = false
|
||||
self.updated()
|
||||
|
||||
self.commitGiftBuyOffer(peer: peer, price: price, duration: duration)
|
||||
self.commitGiftBuyOffer(peer: peer, price: price, duration: duration, allowPaidStars: allowPaidStars)
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13498,6 +13498,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||
|
||||
private var tabBarItemDisposable: Disposable?
|
||||
|
||||
var avatarPickerHolder: Any?
|
||||
|
||||
var controllerNode: PeerInfoScreenNode {
|
||||
return self.displayNode as! PeerInfoScreenNode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,9 +103,14 @@ extension PeerInfoScreenImpl {
|
|||
let parentController = (self.context.sharedContext.mainWindow?.viewController as? NavigationController)?.topViewController as? ViewController
|
||||
|
||||
var dismissImpl: (() -> Void)?
|
||||
let mainController = self.context.sharedContext.makeAvatarMediaPickerScreen(context: self.context, getSourceRect: { return nil }, canDelete: hasDeleteButton, performDelete: { [weak self] in
|
||||
let (mainController, pickerHolder) = self.context.sharedContext.makeAvatarMediaPickerScreen(context: self.context, getSourceRect: { return nil }, canDelete: hasDeleteButton, performDelete: { [weak self] in
|
||||
self?.openAvatarRemoval(mode: mode, peer: peer, item: item)
|
||||
}, completion: { result, transitionView, transitionRect, transitionImage, fromCamera, transitionOut, cancelled in
|
||||
}, completion: { [weak self] result, transitionView, transitionRect, transitionImage, fromCamera, transitionOut, cancelled in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.avatarPickerHolder = nil
|
||||
|
||||
var resultImage: UIImage?
|
||||
let uploadStatusPromise = Promise<PeerInfoAvatarUploadStatus>(.progress(0.0))
|
||||
|
||||
|
|
@ -155,7 +160,6 @@ extension PeerInfoScreenImpl {
|
|||
commit()
|
||||
}
|
||||
parentController?.push(controller)
|
||||
//isFromEditor = true
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -232,31 +236,37 @@ extension PeerInfoScreenImpl {
|
|||
self.parentController?.pushViewController(editorController)
|
||||
}
|
||||
}, dismissed: {
|
||||
|
||||
})
|
||||
dismissImpl = { [weak self, weak mainController] in
|
||||
if let mainController, let navigationController = mainController.navigationController {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
viewControllers = viewControllers.filter { c in
|
||||
return !(c is CameraScreen) && c !== mainController
|
||||
self.avatarPickerHolder = pickerHolder
|
||||
if let mainController {
|
||||
dismissImpl = { [weak self, weak mainController] in
|
||||
if let mainController, let navigationController = mainController.navigationController {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
viewControllers = viewControllers.filter { c in
|
||||
return !(c is CameraScreen) && c !== mainController
|
||||
}
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
}
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
}
|
||||
if let self, let navigationController = self.parentController, let mainController {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
viewControllers = viewControllers.filter { c in
|
||||
return !(c is CameraScreen) && c !== mainController
|
||||
if let self, let navigationController = self.parentController, let mainController {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
viewControllers = viewControllers.filter { c in
|
||||
return !(c is CameraScreen) && c !== mainController
|
||||
}
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
}
|
||||
|
||||
}
|
||||
if mainController is ActionSheetController {
|
||||
self.present(mainController, in: .window(.root))
|
||||
} else {
|
||||
mainController.navigationPresentation = .flatModal
|
||||
mainController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
if self.navigationController != nil {
|
||||
self.push(mainController)
|
||||
} else {
|
||||
self.parentController?.pushViewController(mainController)
|
||||
}
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
}
|
||||
|
||||
}
|
||||
mainController.navigationPresentation = .flatModal
|
||||
mainController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
if self.navigationController != nil {
|
||||
self.push(mainController)
|
||||
} else {
|
||||
self.parentController?.pushViewController(mainController)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3713,7 +3713,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
return stickerMediaPickerController(context: context, getSourceRect: getSourceRect, completion: completion, dismissed: dismissed)
|
||||
}
|
||||
|
||||
public func makeAvatarMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, canDelete: Bool, performDelete: @escaping () -> Void, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController {
|
||||
public func makeAvatarMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, canDelete: Bool, performDelete: @escaping () -> Void, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> (ViewController?, Any?) {
|
||||
return avatarMediaPickerController(context: context, getSourceRect: getSourceRect, canDelete: canDelete, performDelete: performDelete, completion: completion, dismissed: dismissed)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue