Various improvements

This commit is contained in:
Ilya Laktyushin 2025-11-04 01:04:57 +04:00
parent 2f3cf25666
commit 8897deff91
29 changed files with 484 additions and 321 deletions

View file

@ -909,8 +909,52 @@ public class MediaEditorTransitionOutExternalState {
}
}
public protocol CameraScreen: ViewController {
public enum CameraScreenMode {
case story
case sticker
case avatar
}
public final class CameraScreenTransitionIn {
public weak var sourceView: UIView?
public let sourceRect: CGRect
public let sourceCornerRadius: CGFloat
public let useFillAnimation: Bool
public init(
sourceView: UIView,
sourceRect: CGRect,
sourceCornerRadius: CGFloat,
useFillAnimation: Bool
) {
self.sourceView = sourceView
self.sourceRect = sourceRect
self.sourceCornerRadius = sourceCornerRadius
self.useFillAnimation = useFillAnimation
}
}
public final class CameraScreenTransitionOut {
public weak var destinationView: UIView?
public let destinationRect: CGRect
public let destinationCornerRadius: CGFloat
public let completion: (() -> Void)?
public init(
destinationView: UIView,
destinationRect: CGRect,
destinationCornerRadius: CGFloat,
completion: (() -> Void)? = nil
) {
self.destinationView = destinationView
self.destinationRect = destinationRect
self.destinationCornerRadius = destinationCornerRadius
self.completion = completion
}
}
public protocol CameraScreen: ViewController {
func returnFromEditor()
}
public protocol MediaEditorScreen: ViewController {
@ -1330,6 +1374,8 @@ public protocol SharedAccountContext: AnyObject {
func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], loadedStickerPacks: [LoadedStickerPack], actionTitle: String?, isEditing: Bool, expandIfNeeded: Bool, parentNavigationController: NavigationController?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, actionPerformed: ((Bool) -> Void)?) -> ViewController
func makeCameraScreen(context: AccountContext, mode: CameraScreenMode, cameraHolder: Any?, transitionIn: CameraScreenTransitionIn?, transitionOut: @escaping (Bool) -> CameraScreenTransitionOut?, completion: @escaping (Any, @escaping () -> Void) -> Void, transitionedOut: (() -> Void)?) -> ViewController
func makeMediaPickerScreen(context: AccountContext, hasSearch: Bool, completion: @escaping (Any) -> Void) -> ViewController
func makeStoryMediaEditorScreen(context: AccountContext, source: Any?, text: String?, link: (url: String, name: String?)?, remainingCount: Int32, completion: @escaping ([MediaEditorScreenResult], MediaEditorTransitionOutExternalState, @escaping (@escaping () -> Void) -> Void) -> Void) -> ViewController

View file

@ -19,6 +19,7 @@ public final class SolidRoundedButtonComponent: Component {
public let height: CGFloat
public let cornerRadius: CGFloat
public let gloss: Bool
public let glass: Bool
public let isEnabled: Bool
public let iconName: String?
public let animationName: String?
@ -39,6 +40,7 @@ public final class SolidRoundedButtonComponent: Component {
height: CGFloat = 48.0,
cornerRadius: CGFloat = 24.0,
gloss: Bool = false,
glass: Bool = false,
isEnabled: Bool = true,
iconName: String? = nil,
animationName: String? = nil,
@ -58,6 +60,7 @@ public final class SolidRoundedButtonComponent: Component {
self.height = height
self.cornerRadius = cornerRadius
self.gloss = gloss
self.glass = glass
self.isEnabled = isEnabled
self.iconName = iconName
self.animationName = animationName
@ -101,6 +104,9 @@ public final class SolidRoundedButtonComponent: Component {
if lhs.gloss != rhs.gloss {
return false
}
if lhs.glass != rhs.glass {
return false
}
if lhs.isEnabled != rhs.isEnabled {
return false
}

View file

@ -610,7 +610,12 @@ public final class DatePickerNode: ASDisplayNode {
}
self.theme = theme
self.backgroundColor = self.theme.backgroundColor
self.backgroundColor = theme.backgroundColor
self.datePickerBackgroundNode.backgroundColor = theme.backgroundColor
self.monthPickerBackgroundNode.backgroundColor = theme.backgroundColor
self.timePickerBackgroundNode.backgroundColor = theme.backgroundColor
self.monthArrowNode.image = generateSmallArrowImage(color: theme.accentColor)
self.previousButtonNode.setImage(generateNavigationArrowImage(color: theme.accentColor, mirror: true), for: .normal)
self.nextButtonNode.setImage(generateNavigationArrowImage(color: theme.accentColor, mirror: false), for: .normal)

View file

@ -169,7 +169,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
case let .mainLinkHeader(text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .mainLink(link, isGenerating):
return ItemListFolderInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: link, count: 0, peers: [], displayButton: true, enableButton: !isGenerating, buttonTitle: presentationData.strings.FolderLinkScreen_LinkActionCopy, secondaryButtonTitle: link != nil ? presentationData.strings.FolderLinkScreen_LinkActionShare : nil, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
return ItemListFolderInviteLinkItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, invite: link, count: 0, peers: [], displayButton: true, enableButton: !isGenerating, buttonTitle: presentationData.strings.FolderLinkScreen_LinkActionCopy, secondaryButtonTitle: link != nil ? presentationData.strings.FolderLinkScreen_LinkActionShare : nil, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
if let link {
arguments.copyLink(link.link)
}
@ -197,6 +197,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
case let .peer(_, peer, isSelected, disabledReasonText):
return ItemListPeerItem(
presentationData: presentationData,
systemStyle: .glass,
dateTimeFormat: PresentationDateTimeFormat(),
nameDisplayOrder: presentationData.nameDisplayOrder,
context: arguments.context,

View file

@ -292,7 +292,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
case let .titleHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .title(_, placeholder, value):
return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, title: NSAttributedString(), text: value, placeholder: placeholder, maxLength: 32, sectionId: self.section, textUpdated: { value in
return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(), text: value, placeholder: placeholder, maxLength: 32, sectionId: self.section, textUpdated: { value in
arguments.updateState { state in
var updatedState = state
updatedState.title = value
@ -302,7 +302,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
case let .titleInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .subscriptionFeeToggle(_, text, value, enabled):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enabled: enabled, sectionId: self.section, style: .blocks, updated: { value in
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: text, value: value, enabled: enabled, sectionId: self.section, style: .blocks, updated: { value in
arguments.updateState { state in
var updatedState = state
updatedState.subscriptionEnabled = value
@ -325,7 +325,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
title.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: NSRange(range, in: title.string))
title.addAttribute(.baselineOffset, value: -1.0, range: NSRange(range, in: title.string))
}
return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, title: title, text: value.flatMap { "\($0)" } ?? "", placeholder: placeholder, label: label, type: .number, spacing: 3.0, enabled: enabled, tag: InviteLinksEditEntryTag.subscriptionFee, sectionId: self.section, textUpdated: { text in
return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, title: title, text: value.flatMap { "\($0)" } ?? "", placeholder: placeholder, label: label, type: .number, spacing: 3.0, enabled: enabled, tag: InviteLinksEditEntryTag.subscriptionFee, sectionId: self.section, textUpdated: { text in
arguments.updateState { state in
var updatedState = state
if var value = Int64(text).flatMap({ StarsAmount(value: $0, nanos: 0) }) {
@ -343,7 +343,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
case let .subscriptionFeeInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
case let .requestApproval(_, text, value, enabled):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enabled: enabled, sectionId: self.section, style: .blocks, updated: { value in
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: text, value: value, enabled: enabled, sectionId: self.section, style: .blocks, updated: { value in
arguments.updateState { state in
var updatedState = state
updatedState.requestApproval = value
@ -373,7 +373,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
} else {
text = presentationData.strings.InviteLink_Create_TimeLimitExpiryDateNever
}
return ItemListDisclosureItem(presentationData: presentationData, title: presentationData.strings.InviteLink_Create_TimeLimitExpiryDate, enabled: enabled, label: text, labelStyle: active ? .coloredText(theme.list.itemAccentColor) : .text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: {
return ItemListDisclosureItem(presentationData: presentationData, systemStyle: .glass, title: presentationData.strings.InviteLink_Create_TimeLimitExpiryDate, enabled: enabled, label: text, labelStyle: active ? .coloredText(theme.list.itemAccentColor) : .text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: {
arguments.dismissInput()
arguments.updateState { state in
var updatedState = state
@ -437,7 +437,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
} else {
text = focused ? "" : presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsersUnlimited
}
return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, title: NSAttributedString(string: presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsers, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .number, alignment: .right, enabled: enabled, selectAllOnFocus: true, secondaryStyle: !customValue, tag: InviteLinksEditEntryTag.usage, sectionId: self.section, textUpdated: { updatedText in
return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsers, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .number, alignment: .right, enabled: enabled, selectAllOnFocus: true, secondaryStyle: !customValue, tag: InviteLinksEditEntryTag.usage, sectionId: self.section, textUpdated: { updatedText in
arguments.updateState { state in
var updatedState = state
if updatedText.isEmpty {
@ -472,7 +472,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
case let .usageInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .revoke(_, text):
return ItemListActionItem(presentationData: presentationData, title: text, kind: .destructive, alignment: .center, sectionId: self.section, style: .blocks, action: {
return ItemListActionItem(presentationData: presentationData, systemStyle: .glass, title: text, kind: .destructive, alignment: .center, sectionId: self.section, style: .blocks, action: {
arguments.revoke()
}, tag: nil)
}

View file

@ -28,6 +28,7 @@ private func actionButtonImage(color: UIColor) -> UIImage? {
public class ItemListFolderInviteLinkItem: ListViewItem, ItemListItem {
let context: AccountContext
let presentationData: ItemListPresentationData
let systemStyle: ItemListSystemStyle
let invite: ExportedChatFolderLink?
let count: Int32
let peers: [EnginePeer]
@ -49,6 +50,7 @@ public class ItemListFolderInviteLinkItem: ListViewItem, ItemListItem {
public init(
context: AccountContext,
presentationData: ItemListPresentationData,
systemStyle: ItemListSystemStyle = .legacy,
invite: ExportedChatFolderLink?,
count: Int32,
peers: [EnginePeer],
@ -69,6 +71,7 @@ public class ItemListFolderInviteLinkItem: ListViewItem, ItemListItem {
) {
self.context = context
self.presentationData = presentationData
self.systemStyle = systemStyle
self.invite = invite
self.count = count
self.peers = peers
@ -339,7 +342,7 @@ public class ItemListFolderInviteLinkItemNode: ListViewItemNode, ItemListItemNod
let verticalInset: CGFloat = 16.0
let fieldHeight: CGFloat = 52.0
let fieldSpacing: CGFloat = 16.0
let buttonHeight: CGFloat = 50.0
let buttonHeight: CGFloat = 52.0
var height = verticalInset * 2.0 + fieldHeight + fieldSpacing + buttonHeight + 54.0
@ -379,7 +382,7 @@ public class ItemListFolderInviteLinkItemNode: ListViewItemNode, ItemListItemNod
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
strongSelf.fieldNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: item.presentationData.theme.list.itemInputField.backgroundColor)
strongSelf.fieldNode.image = generateStretchableFilledCircleImage(diameter: 26.0, color: item.presentationData.theme.list.itemInputField.backgroundColor)
strongSelf.addressButtonIconNode.image = actionButtonImage(color: item.presentationData.theme.list.itemInputField.controlColor)
}
@ -436,7 +439,7 @@ public class ItemListFolderInviteLinkItemNode: ListViewItemNode, ItemListItemNod
strongSelf.bottomStripeNode.isHidden = hasCorners
}
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : nil
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
@ -454,7 +457,7 @@ public class ItemListFolderInviteLinkItemNode: ListViewItemNode, ItemListItemNod
strongSelf.addressButtonNode.frame = strongSelf.containerNode.bounds
strongSelf.referenceContainerNode.frame = strongSelf.containerNode.bounds
strongSelf.addressButtonIconNode.frame = strongSelf.containerNode.bounds
let shareButtonNode: SolidRoundedButtonNode
if let currentShareButtonNode = strongSelf.shareButtonNode {
shareButtonNode = currentShareButtonNode
@ -465,7 +468,7 @@ public class ItemListFolderInviteLinkItemNode: ListViewItemNode, ItemListItemNod
} else {
buttonTheme = SolidRoundedButtonTheme(theme: item.presentationData.theme)
}
shareButtonNode = SolidRoundedButtonNode(theme: buttonTheme, height: 50.0, cornerRadius: 11.0)
shareButtonNode = SolidRoundedButtonNode(theme: buttonTheme, glass: item.systemStyle == .glass, height: buttonHeight, cornerRadius: buttonHeight * 0.5)
shareButtonNode.pressed = { [weak self] in
self?.item?.shareAction?()
}
@ -485,7 +488,7 @@ public class ItemListFolderInviteLinkItemNode: ListViewItemNode, ItemListItemNod
} else {
buttonTheme = SolidRoundedButtonTheme(theme: item.presentationData.theme)
}
secondaryButtonNode = SolidRoundedButtonNode(theme: buttonTheme, height: 50.0, cornerRadius: 11.0)
secondaryButtonNode = SolidRoundedButtonNode(theme: buttonTheme, glass: item.systemStyle == .glass, height: buttonHeight, cornerRadius: buttonHeight * 0.5)
secondaryButtonNode.pressed = { [weak self] in
self?.item?.secondaryAction?()
}

View file

@ -2649,18 +2649,20 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
transition.updateTransformScale(node: self.moreButtonNode.iconNode, scale: moreIsVisible ? 1.0 : 0.1)
}
if case .assets(_, .story) = self.subject, self.selectionCount > 0 {
let text = self.presentationData.strings.MediaPicker_CreateStory(self.selectionCount)
self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: text, badge: nil, font: .bold, background: .color(self.presentationData.theme.actionSheet.controlAccentColor), textColor: self.presentationData.theme.list.itemCheckColors.foregroundColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, position: .top)))
if self.selectionCount > 1 && self.selectionCount <= 6 {
self.secondaryButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.MediaPicker_CombineIntoCollage, badge: nil, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, iconName: "Media Editor/Collage", smallSpacing: true, position: .bottom)))
if case .assets(_, .story) = self.subject {
if self.selectionCount > 0 {
let text = self.presentationData.strings.MediaPicker_CreateStory(self.selectionCount)
self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: text, badge: nil, font: .bold, background: .color(self.presentationData.theme.actionSheet.controlAccentColor), textColor: self.presentationData.theme.list.itemCheckColors.foregroundColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, position: .top)))
if self.selectionCount > 1 && self.selectionCount <= 6 {
self.secondaryButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.MediaPicker_CombineIntoCollage, badge: nil, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, iconName: "Media Editor/Collage", smallSpacing: true, position: .bottom)))
} else {
self.secondaryButtonStatePromise.set(.single(nil))
}
} else {
self.mainButtonStatePromise.set(.single(nil))
self.secondaryButtonStatePromise.set(.single(nil))
}
} else {
self.mainButtonStatePromise.set(.single(nil))
self.secondaryButtonStatePromise.set(.single(nil))
}
}
@ -3716,46 +3718,47 @@ public func stickerMediaPickerController(
}
mediaPickerController.openCamera = { [weak controller] cameraHolder in
let _ = controller
// guard let cameraHolder = cameraHolder as? CameraHolder else {
// return
// }
//
// var returnToCameraImpl: (() -> Void)?
// let cameraScreen = CameraScreenImpl(
// context: context,
// mode: .sticker,
// holder: cameraHolder,
// transitionIn: CameraScreenImpl.TransitionIn(
// sourceView: cameraHolder.parentView,
// sourceRect: cameraHolder.parentView.bounds,
// sourceCornerRadius: 0.0,
// useFillAnimation: false
// ),
// transitionOut: { _ in
// return CameraScreenImpl.TransitionOut(
// destinationView: cameraHolder.parentView,
// destinationRect: cameraHolder.parentView.bounds,
// destinationCornerRadius: 0.0
// )
// },
// completion: { result, _, _, commit in
// completion(result, nil, .zero, nil, true, { _ in return nil }, {
// returnToCameraImpl?()
// })
// }
// )
// cameraScreen.transitionedOut = { [weak cameraHolder] in
// if let cameraHolder {
// cameraHolder.restore()
// }
// }
// controller?.push(cameraScreen)
//
// returnToCameraImpl = { [weak cameraScreen] in
// if let cameraScreen {
// cameraScreen.returnFromEditor()
// }
// }
guard let cameraHolder = cameraHolder as? CameraHolder else {
return
}
var returnToCameraImpl: (() -> Void)?
let cameraScreen = context.sharedContext.makeCameraScreen(
context: context,
mode: .sticker,
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)
}
@ -3844,46 +3847,47 @@ public func avatarMediaPickerController(
}
mediaPickerController.openCamera = { [weak controller] cameraHolder in
let _ = controller
// guard let cameraHolder = cameraHolder as? CameraHolder else {
// return
// }
//
// var returnToCameraImpl: (() -> Void)?
// let cameraScreen = CameraScreenImpl(
// context: context,
// mode: .avatar,
// holder: cameraHolder,
// transitionIn: CameraScreenImpl.TransitionIn(
// sourceView: cameraHolder.parentView,
// sourceRect: cameraHolder.parentView.bounds,
// sourceCornerRadius: 0.0,
// useFillAnimation: false
// ),
// transitionOut: { _ in
// return CameraScreenImpl.TransitionOut(
// destinationView: cameraHolder.parentView,
// destinationRect: cameraHolder.parentView.bounds,
// destinationCornerRadius: 0.0
// )
// },
// completion: { result, _, _, commit in
// completion(result, nil, .zero, nil, true, { _ in return nil }, {
// returnToCameraImpl?()
// })
// }
// )
// cameraScreen.transitionedOut = { [weak cameraHolder] in
// if let cameraHolder {
// cameraHolder.restore()
// }
// }
// controller?.push(cameraScreen)
//
// returnToCameraImpl = { [weak cameraScreen] in
// if let cameraScreen {
// cameraScreen.returnFromEditor()
// }
// }
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)
}

View file

@ -121,6 +121,7 @@ swift_library(
"//submodules/TelegramUI/Components/ScrollComponent",
"//submodules/TelegramUI/Components/Premium/PremiumStarComponent",
"//submodules/TelegramUI/Components/Premium/PremiumCoinComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
],
visibility = [
"//visibility:public",

View file

@ -17,6 +17,7 @@ import SolidRoundedButtonComponent
import BlurredBackgroundComponent
import Markdown
import TelegramUIPreferences
import GlassBarButtonComponent
public final class PremiumGradientBackgroundComponent: Component {
public let colors: [UIColor]
@ -519,7 +520,6 @@ private final class DemoSheetContent: CombinedComponent {
final class State: ComponentState {
private let context: AccountContext
var cachedCloseImage: UIImage?
var isPremium: Bool?
var reactions: [AvailableReactions.Reaction]?
@ -682,7 +682,7 @@ private final class DemoSheetContent: CombinedComponent {
}
static var body: Body {
let closeButton = Child(Button.self)
let closeButton = Child(GlassBarButtonComponent.self)
let background = Child(PremiumGradientBackgroundComponent.self)
let pager = Child(DemoPagerComponent.self)
let button = Child(SolidRoundedButtonComponent.self)
@ -695,9 +695,7 @@ private final class DemoSheetContent: CombinedComponent {
let strings = environment.strings
let state = context.state
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
let background = background.update(
component: PremiumGradientBackgroundComponent(colors: [
UIColor(rgb: 0x0077ff),
@ -711,15 +709,7 @@ private final class DemoSheetContent: CombinedComponent {
context.add(background
.position(CGPoint(x: context.availableSize.width / 2.0, y: background.size.height / 2.0))
)
let closeImage: UIImage
if let image = state.cachedCloseImage {
closeImage = image
} else {
closeImage = generateCloseButtonImage(backgroundColor: .clear, foregroundColor: UIColor(rgb: 0xffffff))!
state.cachedCloseImage = closeImage
}
var isStandalone = false
if case .other = component.source {
isStandalone = true
@ -1140,38 +1130,30 @@ private final class DemoSheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: pager.size.height / 2.0))
)
}
let closeButton = closeButton.update(
component: Button(
content: AnyComponent(ZStack([
AnyComponentWithIdentity(
id: "background",
component: AnyComponent(
BlurredBackgroundComponent(
color: UIColor(rgb: 0x888888, alpha: 0.1)
)
)
),
AnyComponentWithIdentity(
id: "icon",
component: AnyComponent(
Image(image: closeImage)
)
),
])),
action: { [weak component] in
component?.dismiss()
component: GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: theme.overallDarkAppearance,
state: .glass,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { _ in
component.dismiss()
}
),
availableSize: CGSize(width: 30.0, height: 30.0),
availableSize: CGSize(width: 40.0, height: 40.0),
transition: .immediate
)
context.add(closeButton
.position(CGPoint(x: context.availableSize.width - environment.safeInsets.left - closeButton.size.width, y: 28.0))
.clipsToBounds(true)
.cornerRadius(15.0)
.position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0))
)
var measuredTextHeight: CGFloat?
var text: String
switch component.subject {
@ -1309,6 +1291,7 @@ private final class DemoSheetContent: CombinedComponent {
}
}
let bottomInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0)
let button = button.update(
component: SolidRoundedButtonComponent(
title: buttonText,
@ -1324,9 +1307,10 @@ private final class DemoSheetContent: CombinedComponent {
),
font: .bold,
fontSize: 17.0,
height: 50.0,
cornerRadius: 11.0,
height: 52.0,
cornerRadius: 26.0,
gloss: state.isPremium != true,
glass: true,
animationName: isStandalone ? buttonAnimationName : nil,
iconPosition: .right,
iconSpacing: 4.0,
@ -1340,7 +1324,7 @@ private final class DemoSheetContent: CombinedComponent {
}
}
),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
availableSize: CGSize(width: context.availableSize.width - bottomInsets.left - bottomInsets.right, height: 52.0),
transition: context.transition
)
@ -1358,19 +1342,12 @@ private final class DemoSheetContent: CombinedComponent {
}
}
let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight + 20.0), size: button.size)
let buttonFrame = CGRect(origin: CGPoint(x: bottomInsets.left, y: contentHeight + 20.0), size: button.size)
context.add(button
.position(CGPoint(x: buttonFrame.midX, y: buttonFrame.midY))
)
let bottomPanelPadding: CGFloat = 12.0
let bottomInset: CGFloat
if case .regular = environment.metrics.widthClass {
bottomInset = bottomPanelPadding
} else {
bottomInset = environment.safeInsets.bottom > 0.0 ? environment.safeInsets.bottom + 5.0 : bottomPanelPadding
}
return CGSize(width: context.availableSize.width, height: buttonFrame.maxY + bottomInset)
return CGSize(width: context.availableSize.width, height: buttonFrame.maxY + bottomInsets.bottom)
}
}
}
@ -1428,6 +1405,7 @@ private final class DemoSheetComponent: CombinedComponent {
})
}
)),
style: .glass,
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
followContentSizeChanges: context.component.source == .other,
animateOut: animateOut

View file

@ -20,6 +20,7 @@ import AvatarNode
import TextFormat
import RoundedRectWithTailPath
import PremiumPeerShortcutComponent
import GlassBarButtonComponent
func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
@ -177,7 +178,7 @@ public class PremiumLimitDisplayComponent: Component {
override init(frame: CGRect) {
self.container = UIView()
self.container.clipsToBounds = true
self.container.layer.cornerRadius = 6.0
self.container.layer.cornerRadius = 15.0
self.inactiveBackground = SimpleLayer()
@ -783,7 +784,6 @@ private final class LimitSheetContent: CombinedComponent {
var myBoostCount: Int32 = 0
var cachedCloseImage: (UIImage, PresentationTheme)?
var cachedChevronImage: (UIImage, PresentationTheme)?
init(context: AccountContext, subject: PremiumLimitScreen.Subject) {
@ -819,7 +819,7 @@ private final class LimitSheetContent: CombinedComponent {
}
static var body: Body {
let closeButton = Child(Button.self)
let closeButton = Child(GlassBarButtonComponent.self)
let title = Child(MultilineTextComponent.self)
let text = Child(BalancedTextComponent.self)
let alternateText = Child(List<Empty>.self)
@ -854,27 +854,29 @@ private final class LimitSheetContent: CombinedComponent {
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
let textSideInset: CGFloat = 32.0 + environment.safeInsets.left
let closeImage: UIImage
if let (image, theme) = state.cachedCloseImage, theme === environment.theme {
closeImage = image
} else {
closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: theme.actionSheet.inputClearButtonColor)!
state.cachedCloseImage = (closeImage, theme)
}
let closeButton = closeButton.update(
component: Button(
content: AnyComponent(Image(image: closeImage)),
action: { [weak component] in
component?.dismiss()
component?.cancel()
component: GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { _ in
component.dismiss()
component.cancel()
}
),
availableSize: CGSize(width: 30.0, height: 30.0),
availableSize: CGSize(width: 40.0, height: 40.0),
transition: .immediate
)
context.add(closeButton
.position(CGPoint(x: context.availableSize.width - environment.safeInsets.left - closeButton.size.width, y: 28.0))
.position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0))
)
var boostUpdated = false
@ -1394,17 +1396,6 @@ private final class LimitSheetContent: CombinedComponent {
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
transition: .immediate
)
// alternateTextChild = alternateText.update(
// component: BalancedTextComponent(
// text: .markdown(text: string, attributes: markdownAttributes),
// horizontalAlignment: .center,
// maximumNumberOfLines: 0,
// lineSpacing: 0.1
// ),
// availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
// transition: .immediate
// )
} else {
textChild = text.update(
component: BalancedTextComponent(
@ -1456,6 +1447,8 @@ private final class LimitSheetContent: CombinedComponent {
}
let isIncreaseButton = !reachedMaximumLimit && !isPremiumDisabled
let bottomInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0)
let button = button.update(
component: SolidRoundedButtonComponent(
title: actionButtonText ?? (isIncreaseButton ? strings.Premium_IncreaseLimit : strings.Common_OK),
@ -1466,9 +1459,10 @@ private final class LimitSheetContent: CombinedComponent {
),
font: .bold,
fontSize: 17.0,
height: 50.0,
cornerRadius: 10.0,
height: 52.0,
cornerRadius: 26.0,
gloss: isIncreaseButton && actionButtonHasGloss,
glass: true,
iconName: buttonIconName,
animationName: isIncreaseButton ? buttonAnimationName : nil,
iconPosition: buttonIconName != nil ? .left : .right,
@ -1482,7 +1476,7 @@ private final class LimitSheetContent: CombinedComponent {
}
}
),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
availableSize: CGSize(width: context.availableSize.width - bottomInsets.left - bottomInsets.right, height: 52.0),
transition: context.transition
)
@ -1501,20 +1495,20 @@ private final class LimitSheetContent: CombinedComponent {
),
font: .regular,
fontSize: 17.0,
height: 50.0,
cornerRadius: 10.0,
height: 52.0,
cornerRadius: 26.0,
action: {
if component.action() {
component.dismiss()
}
}
),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
availableSize: CGSize(width: context.availableSize.width - bottomInsets.left - bottomInsets.right, height: 52.0),
transition: context.transition
)
buttonOffset += 66.0
let linkFrame = CGRect(origin: CGPoint(x: sideInset, y: textOffset + (textChild?.size ?? .zero).height + 24.0), size: linkButton.size)
let linkFrame = CGRect(origin: CGPoint(x: bottomInsets.left, y: textOffset + (textChild?.size ?? .zero).height + 24.0), size: linkButton.size)
context.add(linkButton
.position(CGPoint(x: linkFrame.midX, y: linkFrame.midY))
)
@ -1525,7 +1519,7 @@ private final class LimitSheetContent: CombinedComponent {
}
context.add(title
.position(CGPoint(x: context.availableSize.width / 2.0, y: 28.0))
.position(CGPoint(x: context.availableSize.width / 2.0, y: 36.0))
)
var textSize: CGSize
@ -1594,7 +1588,7 @@ private final class LimitSheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: limit.size.height / 2.0 + 44.0 + topOffset))
)
let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: textOffset + ceil(textSize.height / 2.0) + buttonOffset + 24.0), size: button.size)
let buttonFrame = CGRect(origin: CGPoint(x: bottomInsets.left, y: textOffset + ceil(textSize.height / 2.0) + buttonOffset + 24.0), size: button.size)
context.add(button
.position(CGPoint(x: buttonFrame.midX, y: buttonFrame.midY))
)
@ -1760,6 +1754,7 @@ private final class LimitSheetComponent: CombinedComponent {
openStats: context.component.openStats,
openGift: context.component.openGift
)),
style: .glass,
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
followContentSizeChanges: true,
externalState: sheetExternalState,

View file

@ -18,6 +18,8 @@ public enum ServerProvidedSuggestion: Equatable {
case gracePremium
case starsSubscriptionLowBalance
case setupPhoto
case setupLoginEmail
case setupLoginEmailBlocking
case link(id: String, url: String, title: ServerSuggestionInfo.Item.Text, subtitle: ServerSuggestionInfo.Item.Text)
init?(string: String) {
@ -50,6 +52,10 @@ public enum ServerProvidedSuggestion: Equatable {
self = .starsSubscriptionLowBalance
case "USERPIC_SETUP":
self = .setupPhoto
case "SETUP_LOGIN_EMAIL":
self = .setupLoginEmail
case "SETUP_LOGIN_EMAIL_NOSKIP":
self = .setupLoginEmailBlocking
default:
return nil
}
@ -85,6 +91,10 @@ public enum ServerProvidedSuggestion: Equatable {
return "STARS_SUBSCRIPTION_LOW_BALANCE"
case .setupPhoto:
return "USERPIC_SETUP"
case .setupLoginEmail:
return "SETUP_LOGIN_EMAIL"
case .setupLoginEmailBlocking:
return "SETUP_LOGIN_EMAIL_NOSKIP"
case let .link(id, _, _, _):
return id
}

View file

@ -19,6 +19,7 @@ swift_library(
"//submodules/Components/ViewControllerComponent",
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/Components/MultilineTextComponent",
"//submodules/Components/BundleIconComponent",
"//submodules/TelegramPresentationData",
"//submodules/AccountContext",
"//submodules/AppBundle",
@ -30,6 +31,7 @@ swift_library(
"//submodules/TelegramUI/Components/ListSectionComponent",
"//submodules/TelegramUI/Components/ListActionItemComponent",
"//submodules/TelegramUI/Components/PlainButtonComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
],
visibility = [
"//visibility:public",

View file

@ -159,7 +159,7 @@ final class AdminUserActionsPeerComponent: Component {
let contextInset: CGFloat = 0.0
let height: CGFloat = 44.0
let height: CGFloat = 52.0
let verticalInset: CGFloat = 1.0
let leftInset: CGFloat = 30.0 + component.sideInset
var rightInset: CGFloat = contextInset * 2.0 + 8.0 + component.sideInset

View file

@ -18,6 +18,8 @@ import TelegramStringFormatting
import ListSectionComponent
import ListActionItemComponent
import PlainButtonComponent
import GlassBarButtonComponent
import BundleIconComponent
private enum ActionTypeSection: Hashable, CaseIterable {
case members
@ -486,19 +488,28 @@ private final class RecentActionsSettingsSheetComponent: Component {
let leftButtonSize = self.leftButton.update(
transition: transition,
component: AnyComponent(Button(
content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: environment.theme.list.itemAccentColor)),
action: { [weak self] in
component: AnyComponent(GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: environment.theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: environment.theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { [weak self] _ in
guard let self, let controller = self.environment?.controller() else {
return
}
controller.dismiss()
}
).minSize(CGSize(width: 44.0, height: 56.0))),
)),
environment: {},
containerSize: CGSize(width: 120.0, height: 100.0)
containerSize: CGSize(width: 40.0, height: 40.0)
)
let leftButtonFrame = CGRect(origin: CGPoint(x: 16.0 + environment.safeInsets.left, y: 0.0), size: leftButtonSize)
let leftButtonFrame = CGRect(origin: CGPoint(x: 16.0 + environment.safeInsets.left, y: 16.0), size: leftButtonSize)
if let leftButtonView = self.leftButton.view {
if leftButtonView.superview == nil {
self.navigationBarContainer.addSubview(leftButtonView)
@ -582,6 +593,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
return AnyComponentWithIdentity(id: sectionId, component: AnyComponent(ListActionItemComponent(
theme: environment.theme,
style: .glass,
title: itemTitle,
leftIcon: .check(ListActionItemComponent.LeftIcon.Check(
isSelected: selectedCount == totalCount,
@ -661,6 +673,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
subItems.append(AnyComponentWithIdentity(id: actionType, component: AnyComponent(ListActionItemComponent(
theme: environment.theme,
style: .glass,
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
@ -702,7 +715,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
environment: {},
containerSize: CGSize(width: availableSize.width - leftButtonFrame.maxX * 2.0, height: 100.0)
)
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: floor((54.0 - titleSize.height) * 0.5)), size: titleSize)
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: floor((72.0 - titleSize.height) * 0.5)), size: titleSize)
if let titleView = title.view {
if titleView.superview == nil {
self.navigationBarContainer.addSubview(titleView)
@ -728,6 +741,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
transition: optionsSectionTransition,
component: AnyComponent(ListSectionComponent(
theme: environment.theme,
style: .glass,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: environment.strings.Channel_AdminLogFilter_FilterActionsTypeTitle,
@ -796,6 +810,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
}
adminsSectionItems.append(AnyComponentWithIdentity(id: adminsSectionItems.count, component: AnyComponent(ListActionItemComponent(
theme: environment.theme,
style: .glass,
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
@ -828,6 +843,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
transition: transition,
component: AnyComponent(ListSectionComponent(
theme: environment.theme,
style: .glass,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: environment.strings.Channel_AdminLogFilter_FilterActionsAdminsTitle,
@ -854,10 +870,12 @@ private final class RecentActionsSettingsSheetComponent: Component {
contentHeight += 30.0
let bottomInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0)
let actionButtonSize = self.actionButton.update(
transition: transition,
component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: environment.theme.list.itemCheckColors.fillColor,
foreground: environment.theme.list.itemCheckColors.foregroundColor,
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)
@ -883,10 +901,10 @@ private final class RecentActionsSettingsSheetComponent: Component {
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0)
containerSize: CGSize(width: availableSize.width - bottomInsets.left - bottomInsets.right, height: 52.0)
)
let bottomPanelHeight = 8.0 + environment.safeInsets.bottom + actionButtonSize.height
let actionButtonFrame = CGRect(origin: CGPoint(x: sideInset, y: availableSize.height - bottomPanelHeight), size: actionButtonSize)
let bottomPanelHeight = actionButtonSize.height + bottomInsets.bottom
let actionButtonFrame = CGRect(origin: CGPoint(x: bottomInsets.left, y: availableSize.height - bottomPanelHeight), size: actionButtonSize)
if let actionButtonView = actionButton.view {
if actionButtonView.superview == nil {
self.addSubview(actionButtonView)

View file

@ -226,11 +226,11 @@ final class AvatarEditorScreenComponent: Component {
self.backgroundContainerView = UIView()
self.backgroundContainerView.clipsToBounds = true
self.backgroundContainerView.layer.cornerRadius = 10.0
self.backgroundContainerView.layer.cornerRadius = 26.0
self.keyboardContainerView = UIView()
self.keyboardContainerView.clipsToBounds = true
self.keyboardContainerView.layer.cornerRadius = 10.0
self.keyboardContainerView.layer.cornerRadius = 26.0
self.panelBackgroundView = BlurredBackgroundView(color: .white)
self.panelHostView = PagerExternalTopPanelContainer()
@ -1317,11 +1317,13 @@ final class AvatarEditorScreenComponent: Component {
))))
}
let bottomInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0)
let buttonSize = self.buttonView.update(
transition: transition,
component: AnyComponent(
ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: theme.list.itemCheckColors.fillColor,
foreground: theme.list.itemCheckColors.foregroundColor,
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
@ -1337,13 +1339,13 @@ final class AvatarEditorScreenComponent: Component {
)
),
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0)
containerSize: CGSize(width: availableSize.width - bottomInsets.left - bottomInsets.right, height: 52.0)
)
if let buttonView = self.buttonView.view {
if buttonView.superview == nil {
self.addSubview(buttonView)
}
transition.setFrame(view: buttonView, frame: CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: buttonSize))
transition.setFrame(view: buttonView, frame: CGRect(origin: CGPoint(x: bottomInsets.left, y: contentHeight), size: buttonSize))
}
let bottomPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight - 4.0), size: CGSize(width: availableSize.width, height: availableSize.height - contentHeight + 4.0))

View file

@ -106,7 +106,7 @@ final class BackgroundColorComponent: Component {
var validIds: [AnyHashable] = []
for i in 0 ..< values.count {
let position: CGFloat = sideInset + (spacing + itemSize.width) * CGFloat(i)
let itemFrame = CGRect(origin: CGPoint(x: position, y: 10.0), size: itemSize)
let itemFrame = CGRect(origin: CGPoint(x: position, y: 11.0), size: itemSize)
var isVisible = false
if visibleBounds.intersects(itemFrame) {
isVisible = true
@ -171,7 +171,7 @@ final class BackgroundColorComponent: Component {
self.component = component
self.state = state
let height: CGFloat = 50.0
let height: CGFloat = 52.0
let size = CGSize(width: availableSize.width, height: height)
let scrollFrame = CGRect(origin: .zero, size: size)

View file

@ -617,7 +617,7 @@ public final class ButtonComponent: Component {
})
}
if component.background.style == .glass {
if component.background.style == .glass, component.background.color.alpha > 0.9 {
let chromeView: UIImageView
var chromeTransition = transition
if let current = self.chromeView {

View file

@ -21,11 +21,20 @@ private let calendar = Calendar(identifier: .gregorian)
private final class ChatScheduleTimeSheetContentComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
public class ExternalState {
public fileprivate(set) var repeatValueFrame: CGRect
public init() {
self.repeatValueFrame = .zero
}
}
let context: AccountContext
let mode: ChatScheduleTimeScreen.Mode
let currentTime: Int32?
let currentRepeatPeriod: Int32?
let minimalTime: Int32?
let externalState: ExternalState
let dismiss: () -> Void
init(
@ -34,6 +43,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
currentTime: Int32?,
currentRepeatPeriod: Int32?,
minimalTime: Int32?,
externalState: ExternalState,
dismiss: @escaping () -> Void
) {
self.context = context
@ -41,6 +51,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
self.currentTime = currentTime
self.currentRepeatPeriod = currentRepeatPeriod
self.minimalTime = minimalTime
self.externalState = externalState
self.dismiss = dismiss
}
@ -133,14 +144,18 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
defer {
self.isUpdating = false
}
let environment = environment[EnvironmentType.self].value
let themeUpdated = self.environment?.theme != environment.theme
self.environment = environment
if self.component == nil {
self.updateMinimumDate(currentTime: component.currentTime, minimalTime: component.minimalTime)
self.repeatPeriod = component.currentRepeatPeriod
}
self.component = component
self.state = state
@ -210,6 +225,10 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
let datePicker: DatePickerNode
if let current = self.datePicker {
datePicker = current
if themeUpdated {
datePicker.updateTheme(DatePickerTheme(theme: environment.theme))
}
} else {
datePicker = DatePickerNode(
theme: DatePickerTheme(theme: environment.theme),
@ -588,6 +607,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
theme: environment.theme,
sourceFrame: repeatValueFrame,
component: AnyComponent(RepeatMenuComponent(
theme: environment.theme,
value: self.repeatPeriod,
valueUpdated: { [weak self] value in
guard let self, let component = self.component, let environment = self.environment else {
@ -602,13 +622,13 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
content: .premiumPaywall(
title: "Premium Required",
text: "Subscribe to **Telegram Premium** to schedule repeating messages.",
customUndoText: nil,
customUndoText: "Add",
timeout: nil,
linkAction: nil
),
elevatedLayout: true,
elevatedLayout: false,
action: { [weak environment] action in
if case .info = action {
if case .undo = action {
var replaceImpl: ((ViewController) -> Void)?
let controller = component.context.sharedContext.makePremiumDemoController(context: component.context, subject: .colors, forceDark: false, action: {
let controller = component.context.sharedContext.makePremiumIntroController(context: component.context, source: .nameColor, forceDark: false, dismissed: nil)
@ -656,30 +676,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
})
}
// if let controller = environment.controller(), !controller.automaticallyControlPresentationContextLayout {
// let sideInset: CGFloat = 0.0
// let bottomInset: CGFloat = max(environment.safeInsets.bottom, contentHeight)
//// if case .regular = environment.metrics.widthClass {
//// sideInset = floor((context.availableSize.width - 430.0) / 2.0) - 12.0
//// bottomInset = (context.availableSize.height - sheetExternalState.contentHeight) / 2.0 + sheetExternalState.contentHeight
//// }
//
// let layout = ContainerViewLayout(
// size: availableSize,
// metrics: environment.metrics,
// deviceMetrics: environment.deviceMetrics,
// intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomInset, right: 0.0),
// safeInsets: UIEdgeInsets(top: 0.0, left: max(sideInset, environment.safeInsets.left), bottom: 0.0, right: max(sideInset, environment.safeInsets.right)),
// additionalInsets: .zero,
// statusBarHeight: environment.statusBarHeight,
// inputHeight: nil,
// inputHeightIsInteractivellyChanging: false,
// inVoiceOver: false
// )
// controller.presentationContext.containerLayoutUpdated(layout, transition: transition.containedViewLayoutTransition)
// }
component.externalState.repeatValueFrame = repeatValueFrame
return contentSize
}
@ -739,6 +736,8 @@ private final class ChatScheduleTimeScreenComponent: Component {
final class View: UIView {
private let sheet = ComponentView<(ViewControllerComponentContainer.Environment, SheetComponentEnvironment)>()
private let sheetAnimateOut = ActionSlot<Action<Void>>()
private let sheetExternalState = SheetComponent<EnvironmentType>.ExternalState()
private let contentExternalState = ChatScheduleTimeSheetContentComponent.ExternalState()
private var component: ChatScheduleTimeScreenComponent?
private var environment: EnvironmentType?
@ -782,6 +781,7 @@ private final class ChatScheduleTimeScreenComponent: Component {
currentTime: component.currentTime,
currentRepeatPeriod: component.currentRepeatPeriod,
minimalTime: component.minimalTime,
externalState: self.contentExternalState,
dismiss: { [weak self] in
guard let self else {
return
@ -796,6 +796,7 @@ private final class ChatScheduleTimeScreenComponent: Component {
style: .glass,
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
followContentSizeChanges: true,
externalState: self.sheetExternalState,
animateOut: self.sheetAnimateOut
)),
environment: {
@ -811,6 +812,25 @@ private final class ChatScheduleTimeScreenComponent: Component {
transition.setFrame(view: sheetView, frame: CGRect(origin: CGPoint(), size: availableSize))
}
if let controller = environment.controller(), !controller.automaticallyControlPresentationContextLayout {
let sideInset: CGFloat = 20.0
let bottomInset: CGFloat = self.sheetExternalState.contentHeight - self.contentExternalState.repeatValueFrame.minY + 14.0
let layout = ContainerViewLayout(
size: availableSize,
metrics: environment.metrics,
deviceMetrics: environment.deviceMetrics,
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomInset, right: 0.0),
safeInsets: UIEdgeInsets(top: 0.0, left: max(sideInset, environment.safeInsets.left), bottom: 0.0, right: max(sideInset, environment.safeInsets.right)),
additionalInsets: .zero,
statusBarHeight: environment.statusBarHeight,
inputHeight: nil,
inputHeightIsInteractivellyChanging: false,
inVoiceOver: false
)
controller.presentationContext.containerLayoutUpdated(layout, transition: transition.containedViewLayoutTransition)
}
return availableSize
}
}
@ -860,7 +880,7 @@ public class ChatScheduleTimeScreen: ViewControllerComponentContainer {
self.navigationPresentation = .flatModal
self.blocksBackgroundWhenInOverlay = true
//self.automaticallyControlPresentationContextLayout = false
self.automaticallyControlPresentationContextLayout = false
}
required public init(coder aDecoder: NSCoder) {
@ -1148,18 +1168,24 @@ private final class MenuComponent: Component {
}
private final class RepeatMenuComponent: Component {
let theme: PresentationTheme
let value: Int32?
let valueUpdated: (Int32?) -> Void
init(
theme: PresentationTheme,
value: Int32?,
valueUpdated: @escaping (Int32?) -> Void
) {
self.theme = theme
self.value = value
self.valueUpdated = valueUpdated
}
public static func ==(lhs: RepeatMenuComponent, rhs: RepeatMenuComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.value != rhs.value {
return false
}
@ -1205,14 +1231,16 @@ private final class RepeatMenuComponent: Component {
let sideInset: CGFloat = 18.0
let itemInset: CGFloat = 60.0
self.checkIcon.tintColor = .black
let textColor = component.theme.contextMenu.primaryColor
self.checkIcon.tintColor = textColor
let neverSize = self.never.update(
transition: transition,
component: AnyComponent(
PlainButtonComponent(
content: AnyComponent(
Text(text: "Never", font: Font.regular(17.0), color: .black)
Text(text: "Never", font: Font.regular(17.0), color: textColor)
),
action: { [weak self] in
guard let self else {
@ -1277,7 +1305,7 @@ private final class RepeatMenuComponent: Component {
component: AnyComponent(
PlainButtonComponent(
content: AnyComponent(
Text(text: repeatString, font: Font.regular(17.0), color: .black)
Text(text: repeatString, font: Font.regular(17.0), color: textColor)
),
action: { [weak self] in
guard let self else {
@ -1311,7 +1339,7 @@ private final class RepeatMenuComponent: Component {
let size = CGSize(width: itemInset + maxWidth + 40.0, height: originY)
self.separator.backgroundColor = UIColor(rgb: 0xdddddd).cgColor
self.separator.backgroundColor = textColor.withMultipliedAlpha(0.6).cgColor
self.separator.frame = CGRect(origin: CGPoint(x: sideInset, y: 62.0), size: CGSize(width: size.width - sideInset * 2.0, height: UIScreenPixel))
return size

View file

@ -374,8 +374,8 @@ private class MessagePriceItemNode: ListViewItemNode {
let centralLeftText = item.value == 0 ? item.strings.Stars_SendMessage_PriceFree : item.strings.Privacy_Messages_Stars(Int32(clamping: item.value))
strongSelf.centerLeftTextNode.attributedText = NSAttributedString(string: centralLeftText, font: textFont, textColor: item.openSetCustom != nil ? item.theme.list.itemAccentColor : item.theme.list.itemPrimaryTextColor)
strongSelf.centerRightTextNode.attributedText = NSAttributedString(string: item.price, font: smallTextFont, textColor: item.openSetCustom != nil ? item.theme.list.itemAccentColor.withMultipliedAlpha(0.5) : item.theme.list.itemSecondaryTextColor)
strongSelf.centerLeftTextNode.attributedText = NSAttributedString(string: centralLeftText, font: textFont, textColor: item.openSetCustom != nil && item.isEnabled ? item.theme.list.itemAccentColor : item.theme.list.itemPrimaryTextColor)
strongSelf.centerRightTextNode.attributedText = NSAttributedString(string: item.price, font: smallTextFont, textColor: item.openSetCustom != nil && item.isEnabled ? item.theme.list.itemAccentColor.withMultipliedAlpha(0.5) : item.theme.list.itemSecondaryTextColor)
let leftTextSize = strongSelf.leftTextNode.updateLayout(CGSize(width: 100.0, height: 100.0))
let rightTextSize = strongSelf.rightTextNode.updateLayout(CGSize(width: 100.0, height: 100.0))
@ -402,7 +402,7 @@ private class MessagePriceItemNode: ListViewItemNode {
}
strongSelf.centerTextButtonBackground.tintColor = item.theme.list.itemAccentColor.withMultipliedAlpha(0.1)
if item.openSetCustom != nil {
if item.openSetCustom != nil && item.isEnabled {
strongSelf.centerTextButtonNode.isEnabled = true
strongSelf.centerTextButtonBackground.isHidden = false
} else {
@ -446,12 +446,13 @@ private class MessagePriceItemNode: ListViewItemNode {
}
let sideInset: CGFloat = 16.0
let buttonSize = CGSize(width: params.width - params.leftInset - params.rightInset - sideInset * 2.0, height: 50.0)
let buttonSize = CGSize(width: params.width - params.leftInset - params.rightInset - sideInset * 2.0, height: 52.0)
let _ = strongSelf.button.update(
transition: .immediate,
component: AnyComponent(
ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: item.theme.list.itemCheckColors.fillColor,
foreground: item.theme.list.itemCheckColors.foregroundColor,
pressedColor: item.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)

View file

@ -302,6 +302,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
var switchSectionItems: [AnyComponentWithIdentity<Empty>] = []
switchSectionItems.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
theme: environment.theme,
style: .glass,
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
@ -326,6 +327,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
transition: transition,
component: AnyComponent(ListSectionComponent(
theme: environment.theme,
style: .glass,
header: nil,
footer: nil,
items: switchSectionItems
@ -394,6 +396,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
transition: transition,
component: AnyComponent(ListSectionComponent(
theme: environment.theme,
style: .glass,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: environment.strings.ChannelMessages_PriceSectionTitle,

View file

@ -19,6 +19,7 @@ swift_library(
"//submodules/Components/ViewControllerComponent",
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/Components/MultilineTextComponent",
"//submodules/Components/BundleIconComponent",
"//submodules/TelegramPresentationData",
"//submodules/AccountContext",
"//submodules/AppBundle",
@ -26,6 +27,7 @@ swift_library(
"//submodules/PresentationDataUtils",
"//submodules/TelegramUI/Components/ButtonComponent",
"//submodules/TelegramUI/Components/PlainButtonComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
],
visibility = [
"//visibility:public",

View file

@ -139,7 +139,7 @@ public final class BirthdayPickerContentComponent: Component {
let sideInset: CGFloat = 16.0
var contentHeight: CGFloat = 0.0
var contentHeight: CGFloat = 8.0
let titleString = NSMutableAttributedString()
let titleRawString: String

View file

@ -4,10 +4,12 @@ import Display
import ComponentFlow
import SwiftSignalKit
import ViewControllerComponent
import TelegramCore
import AccountContext
import SheetComponent
import ButtonComponent
import TelegramCore
import GlassBarButtonComponent
import BundleIconComponent
private final class BirthdayPickerSheetContentComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -116,18 +118,29 @@ private final class BirthdayPickerSheetContentComponent: Component {
let cancelSize = self.cancel.update(
transition: transition,
component: AnyComponent(Button(
content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: environment.theme.list.itemAccentColor)),
action: { [weak self] in
if let self, let component = self.component {
component.dismiss()
component: AnyComponent(
GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: environment.theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: environment.theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { [weak self] _ in
if let self, let component = self.component {
component.dismiss()
}
}
}
).minSize(CGSize(width: 32.0, height: 32.0))),
)
),
environment: {},
containerSize: CGSize(width: availableSize.width, height: 32.0)
containerSize: CGSize(width: 40.0, height: 40.0)
)
let cancelFrame = CGRect(origin: CGPoint(x: sideInset, y: 13.0), size: cancelSize)
let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize)
if let cancelView = self.cancel.view {
if cancelView.superview == nil {
self.addSubview(cancelView)
@ -145,10 +158,12 @@ private final class BirthdayPickerSheetContentComponent: Component {
buttonTitle = environment.strings.SuggestBirthdate_Accept_Action
}
let bottomInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0)
let buttonSize = self.button.update(
transition: transition,
component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: environment.theme.list.itemCheckColors.fillColor,
foreground: environment.theme.list.itemCheckColors.foregroundColor,
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
@ -166,9 +181,9 @@ private final class BirthdayPickerSheetContentComponent: Component {
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0)
containerSize: CGSize(width: availableSize.width - bottomInsets.left - bottomInsets.right, height: 52.0)
)
let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: buttonSize)
let buttonFrame = CGRect(origin: CGPoint(x: bottomInsets.left, y: contentHeight), size: buttonSize)
if let buttonView = self.button.view {
if buttonView.superview == nil {
self.addSubview(buttonView)
@ -176,13 +191,8 @@ private final class BirthdayPickerSheetContentComponent: Component {
transition.setFrame(view: buttonView, frame: buttonFrame)
}
contentHeight += buttonSize.height
if environment.safeInsets.bottom.isZero {
contentHeight += 16.0
} else {
contentHeight += environment.safeInsets.bottom + 14.0
}
contentHeight += bottomInsets.bottom
return CGSize(width: availableSize.width, height: contentHeight)
}
}
@ -321,6 +331,7 @@ private final class BirthdayPickerScreenComponent: Component {
controller.requestLayout(forceUpdate: true, transition: transition)
}
)),
style: .glass,
backgroundColor: .color(environment.theme.list.plainBackgroundColor),
followContentSizeChanges: true,
isScrollEnabled: false,

View file

@ -777,7 +777,7 @@ final class StarsStatisticsScreenComponent: Component {
let panelTransition = transition
if !panelItems.isEmpty {
let panelContainerInset: CGFloat = self.listIsExpanded ? 0.0 : 16.0
let panelContainerCornerRadius: CGFloat = self.listIsExpanded ? 0.0 : 11.0
let panelContainerCornerRadius: CGFloat = self.listIsExpanded ? 0.0 : 26.0
let panelContainerSize = self.panelContainer.update(
transition: panelTransition,

View file

@ -640,7 +640,7 @@ final class StarsTransactionsPanelContainerComponent: Component {
transition.setFrame(view: self.topPanelBackgroundView, frame: CGRect(origin: .zero, size: topPanelFrame.size))
transition.setFrame(view: self.topPanelMergedBackgroundView, frame: CGRect(origin: .zero, size: topPanelFrame.size))
transition.setCornerRadius(layer: self.topPanelClippingView.layer, cornerRadius: component.insets.left > 0.0 ? 11.0 : 0.0)
transition.setCornerRadius(layer: self.topPanelClippingView.layer, cornerRadius: component.insets.left > 0.0 ? 26.0 : 0.0)
transition.setFrame(layer: self.panelsBackgroundLayer, frame: CGRect(origin: CGPoint(x: component.insets.left, y: topPanelFrame.maxY), size: CGSize(width: containerWidth, height: availableSize.height - topPanelFrame.maxY)))

View file

@ -1134,7 +1134,7 @@ final class StarsTransactionsScreenComponent: Component {
if !panelItems.isEmpty {
let panelContainerInset: CGFloat = self.listIsExpanded ? 0.0 : 16.0
let panelContainerCornerRadius: CGFloat = self.listIsExpanded ? 0.0 : 11.0
let panelContainerCornerRadius: CGFloat = self.listIsExpanded ? 0.0 : 26.0
let panelContainerSize = self.panelContainer.update(
transition: panelTransition,

View file

@ -20,6 +20,7 @@ swift_library(
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/Components/MultilineTextComponent",
"//submodules/Components/BalancedTextComponent",
"//submodules/Components/BundleIconComponent",
"//submodules/TelegramPresentationData",
"//submodules/AccountContext",
"//submodules/AppBundle",
@ -29,6 +30,7 @@ swift_library(
"//submodules/Components/SheetComponent",
"//submodules/UndoUI",
"//submodules/TelegramUI/Components/ButtonComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/TelegramUI/Components/ListSectionComponent",
"//submodules/TelegramUI/Components/ListActionItemComponent",
"//submodules/TelegramUI/Components/Stars/StarsImageComponent",

View file

@ -21,6 +21,8 @@ import StarsImageComponent
import ConfettiEffect
import PremiumPeerShortcutComponent
import StarsBalanceOverlayComponent
import GlassBarButtonComponent
import TelegramStringFormatting
private final class SheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -68,7 +70,6 @@ private final class SheetContent: CombinedComponent {
}
final class State: ComponentState {
var cachedCloseImage: (UIImage, PresentationTheme)?
var cachedStarImage: (UIImage, PresentationTheme)?
private let context: AccountContext
@ -263,7 +264,7 @@ private final class SheetContent: CombinedComponent {
static var body: Body {
let background = Child(RoundedRectangle.self)
let star = Child(StarsImageComponent.self)
let closeButton = Child(Button.self)
let closeButton = Child(GlassBarButtonComponent.self)
let title = Child(Text.self)
let peerShortcut = Child(PremiumPeerShortcutComponent.self)
@ -337,26 +338,30 @@ private final class SheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: star.size.height / 2.0 - 27.0))
)
let closeImage: UIImage
if let (image, cacheTheme) = state.cachedCloseImage, theme === cacheTheme {
closeImage = image
} else {
closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: theme.actionSheet.inputClearButtonColor)!
state.cachedCloseImage = (closeImage, theme)
}
let closeButton = closeButton.update(
component: Button(
content: AnyComponent(Image(image: closeImage)),
action: {
component: GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { _ in
component.dismiss()
}
),
availableSize: CGSize(width: 30.0, height: 30.0),
availableSize: CGSize(width: 40.0, height: 40.0),
transition: .immediate
)
context.add(closeButton
.position(CGPoint(x: context.availableSize.width - closeButton.size.width, y: 28.0))
.position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0))
)
let constrainedTitleWidth = context.availableSize.width - 16.0 * 2.0
@ -501,13 +506,15 @@ private final class SheetContent: CombinedComponent {
availableSize: context.availableSize,
transition: .immediate
)
let smallLabelFont = Font.regular(11.0)
let labelFont = Font.semibold(14.0)
let formattedBalance = formatStarsAmountText(state.balance ?? StarsAmount.zero, dateTimeFormat: environment.dateTimeFormat)
let balanceText = tonAmountAttributedString(formattedBalance, integralFont: labelFont, fractionalFont: smallLabelFont, color: textColor, decimalSeparator: environment.dateTimeFormat.decimalSeparator)
let balanceValue = balanceValue.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(
string: presentationStringsFormattedNumber(state.balance ?? StarsAmount.zero, environment.dateTimeFormat.groupingSeparator),
font: Font.semibold(16.0),
textColor: textColor
)),
text: .plain(balanceText),
maximumNumberOfLines: 1
),
availableSize: context.availableSize,
@ -519,15 +526,15 @@ private final class SheetContent: CombinedComponent {
transition: .immediate
)
let topBalanceOriginY = 11.0
let topBalanceOriginY = 19.0
context.add(balanceTitle
.position(CGPoint(x: 16.0 + environment.safeInsets.left + balanceTitle.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height / 2.0))
.position(CGPoint(x: context.availableSize.width - 16.0 - environment.safeInsets.left - balanceTitle.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height / 2.0))
)
context.add(balanceIcon
.position(CGPoint(x: 16.0 + environment.safeInsets.left + balanceIcon.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0 + 1.0 + UIScreenPixel))
.position(CGPoint(x: context.availableSize.width - 16.0 - environment.safeInsets.left - balanceIcon.size.width / 2.0 - balanceValue.size.width - 3.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0 + 1.0 + UIScreenPixel))
)
context.add(balanceValue
.position(CGPoint(x: 16.0 + environment.safeInsets.left + balanceIcon.size.width + 3.0 + balanceValue.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0 + 2.0 - UIScreenPixel))
.position(CGPoint(x: context.availableSize.width - 16.0 - environment.safeInsets.left - balanceValue.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0))
)
if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme {
@ -557,13 +564,15 @@ private final class SheetContent: CombinedComponent {
let botTitle = state.botPeer?.compactDisplayTitle ?? ""
let invoice = component.invoice
let isMedia = !component.extendedMedia.isEmpty
let buttonSideInset: CGFloat = 30.0
let button = button.update(
component: ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: theme.list.itemCheckColors.fillColor,
foreground: theme.list.itemCheckColors.foregroundColor,
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9),
cornerRadius: 10.0
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)
),
content: AnyComponentWithIdentity(
id: AnyHashable(0),
@ -650,7 +659,7 @@ private final class SheetContent: CombinedComponent {
})
}
),
availableSize: CGSize(width: context.availableSize.width - 16.0 * 2.0, height: 50),
availableSize: CGSize(width: context.availableSize.width - buttonSideInset * 2.0, height: 52),
transition: .immediate
)
context.add(button
@ -703,7 +712,11 @@ private final class SheetContent: CombinedComponent {
)
contentSize.height += info.size.height
contentSize.height += 48.0
var bottomInset: CGFloat = environment.safeInsets.bottom
if bottomInset < 5.0 {
bottomInset = 8.0
}
contentSize.height += 4.0 + bottomInset
return contentSize
}
@ -779,6 +792,7 @@ private final class StarsTransferSheetComponent: CombinedComponent {
})
}
)),
style: .glass,
backgroundColor: .color(environment.theme.list.modalBlocksBackgroundColor),
followContentSizeChanges: true,
clipsContent: true,
@ -886,24 +900,3 @@ public final class StarsTransferScreen: ViewControllerComponentContainer {
}
}
}
private func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(backgroundColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setLineWidth(2.0)
context.setLineCap(.round)
context.setStrokeColor(foregroundColor.cgColor)
context.move(to: CGPoint(x: 10.0, y: 10.0))
context.addLine(to: CGPoint(x: 20.0, y: 20.0))
context.strokePath()
context.move(to: CGPoint(x: 20.0, y: 10.0))
context.addLine(to: CGPoint(x: 10.0, y: 20.0))
context.strokePath()
})
}

View file

@ -62,6 +62,7 @@ import MediaEditorScreen
import BusinessIntroSetupScreen
import TelegramNotices
import BotSettingsScreen
import Camera
import CameraScreen
import BirthdayPickerScreen
import StarsTransactionsScreen
@ -3647,6 +3648,57 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return editorController
}
public func makeCameraScreen(context: AccountContext, mode: CameraScreenMode, cameraHolder: Any?, transitionIn: CameraScreenTransitionIn?, transitionOut: @escaping (Bool) -> CameraScreenTransitionOut?, completion: @escaping (Any, @escaping () -> Void) -> Void, transitionedOut: (() -> Void)?) -> ViewController {
let mappedTransitionIn = transitionIn.flatMap {
if let sourceView = $0.sourceView {
return CameraScreenImpl.TransitionIn(
sourceView: sourceView,
sourceRect: $0.sourceRect,
sourceCornerRadius: $0.sourceCornerRadius,
useFillAnimation: $0.useFillAnimation
)
} else {
return nil
}
}
let mappedMode: CameraScreenImpl.Mode
switch mode {
case .sticker:
mappedMode = .sticker
case .avatar:
mappedMode = .avatar
case .story:
mappedMode = .story
}
let controller = CameraScreenImpl(
context: context,
mode: mappedMode,
holder: cameraHolder as? CameraHolder,
transitionIn: mappedTransitionIn,
transitionOut: { value in
return transitionOut(value).flatMap {
if let destinationView = $0.destinationView {
return CameraScreenImpl.TransitionOut(
destinationView: destinationView,
destinationRect: $0.destinationRect,
destinationCornerRadius: $0.destinationCornerRadius,
completion: $0.completion
)
} else {
return nil
}
}
},
completion: { result, _, _, commit in
completion(result, commit)
}
)
if let transitionedOut {
controller.transitionedOut = transitionedOut
}
return controller
}
public func makeMediaPickerScreen(context: AccountContext, hasSearch: Bool, completion: @escaping (Any) -> Void) -> ViewController {
return mediaPickerController(context: context, hasSearch: hasSearch, completion: completion)
}