mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Various improvements
This commit is contained in:
@@ -59,7 +59,7 @@ class ChatSlowmodeItem: ListViewItem, ItemListItem {
|
||||
}
|
||||
}
|
||||
|
||||
private let allowedValues: [Int32] = [0, 10, 30, 60, 300, 900, 3600]
|
||||
private let allowedValues: [Int32] = [0, 5, 10, 30, 60, 300, 900, 3600]
|
||||
|
||||
class ChatSlowmodeItemNode: ListViewItemNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
|
||||
@@ -60,7 +60,7 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
case publicLinkInfo(PresentationTheme, String)
|
||||
|
||||
case additionalLinkHeader(PresentationTheme, String)
|
||||
case additionalLink(PresentationTheme, TelegramPeerUsername, Int32)
|
||||
case additionalLink(PresentationTheme, TelegramPeerUsername, Int32, Bool)
|
||||
case additionalLinkInfo(PresentationTheme, String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
@@ -84,7 +84,7 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
return .index(3)
|
||||
case .additionalLinkHeader:
|
||||
return .index(4)
|
||||
case let .additionalLink(_, username, _):
|
||||
case let .additionalLink(_, username, _, _):
|
||||
return .username(username.username)
|
||||
case .additionalLinkInfo:
|
||||
return .index(5)
|
||||
@@ -123,8 +123,8 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .additionalLink(lhsTheme, lhsAddressName, lhsIndex):
|
||||
if case let .additionalLink(rhsTheme, rhsAddressName, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsAddressName == rhsAddressName, lhsIndex == rhsIndex {
|
||||
case let .additionalLink(lhsTheme, lhsAddressName, lhsIndex, lhsCanToggleIsActive):
|
||||
if case let .additionalLink(rhsTheme, rhsAddressName, rhsIndex, rhsCanToggleIsActive) = rhs, lhsTheme === rhsTheme, lhsAddressName == rhsAddressName, lhsIndex == rhsIndex, lhsCanToggleIsActive == rhsCanToggleIsActive {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@@ -175,9 +175,9 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case let .additionalLink(_, _, lhsIndex):
|
||||
case let .additionalLink(_, _, lhsIndex, _):
|
||||
switch rhs {
|
||||
case let .additionalLink(_, _, rhsIndex):
|
||||
case let .additionalLink(_, _, rhsIndex, _):
|
||||
return lhsIndex < rhsIndex
|
||||
case .publicLinkHeader, .editablePublicLink, .publicLinkStatus, .publicLinkInfo, .additionalLinkHeader:
|
||||
return false
|
||||
@@ -232,9 +232,9 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
}, sectionId: self.section)
|
||||
case let .additionalLinkHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .additionalLink(_, link, _):
|
||||
case let .additionalLink(_, link, _, canToggleIsActive):
|
||||
return AdditionalLinkItem(presentationData: presentationData, username: link, sectionId: self.section, style: .blocks, tapAction: {
|
||||
if !link.flags.contains(.isEditable) {
|
||||
if canToggleIsActive {
|
||||
if link.isActive {
|
||||
arguments.deactivateLink(link.username)
|
||||
} else {
|
||||
@@ -348,8 +348,12 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
entries.append(.publicLinkStatus(presentationData.theme, currentUsername, status, statusText, currentUsername))
|
||||
}
|
||||
|
||||
var isBot = false
|
||||
|
||||
let otherUsernames = peer.usernames.filter { !$0.flags.contains(.isEditable) }
|
||||
if case .bot = mode {
|
||||
isBot = true
|
||||
|
||||
var infoText = presentationData.strings.Username_BotLinkHint
|
||||
if otherUsernames.isEmpty {
|
||||
infoText = presentationData.strings.Username_BotLinkHintExtended
|
||||
@@ -384,7 +388,11 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
}
|
||||
var i: Int32 = 0
|
||||
for username in usernames {
|
||||
entries.append(.additionalLink(presentationData.theme, username, i))
|
||||
var canToggleIsActive = false
|
||||
if !username.flags.contains(.isEditable) || isBot {
|
||||
canToggleIsActive = true
|
||||
}
|
||||
entries.append(.additionalLink(presentationData.theme, username, i, canToggleIsActive))
|
||||
i += 1
|
||||
}
|
||||
|
||||
@@ -613,7 +621,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup
|
||||
|
||||
controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [UsernameSetupEntry]) -> Signal<Bool, NoError> in
|
||||
let fromEntry = entries[fromIndex]
|
||||
guard case let .additionalLink(_, fromUsername, _) = fromEntry else {
|
||||
guard case let .additionalLink(_, fromUsername, _, _) = fromEntry else {
|
||||
return .single(false)
|
||||
}
|
||||
var referenceId: String?
|
||||
@@ -626,7 +634,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup
|
||||
var i = 0
|
||||
for entry in entries {
|
||||
switch entry {
|
||||
case let .additionalLink(_, link, _):
|
||||
case let .additionalLink(_, link, _, _):
|
||||
currentUsernames.append(link.username)
|
||||
if !link.isActive && maxIndex == nil {
|
||||
maxIndex = max(0, i - 1)
|
||||
@@ -639,7 +647,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup
|
||||
|
||||
if toIndex < entries.count {
|
||||
switch entries[toIndex] {
|
||||
case let .additionalLink(_, toUsername, _):
|
||||
case let .additionalLink(_, toUsername, _, _):
|
||||
if toUsername.isActive {
|
||||
referenceId = toUsername.username
|
||||
} else {
|
||||
@@ -716,7 +724,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup
|
||||
var currentUsernames: [TelegramPeerUsername] = []
|
||||
for entry in entries {
|
||||
switch entry {
|
||||
case let .additionalLink(_, username, _):
|
||||
case let .additionalLink(_, username, _, _):
|
||||
currentUsernames.append(username)
|
||||
default:
|
||||
break
|
||||
|
||||
@@ -142,10 +142,11 @@ final class VideoChatActionButtonComponent: Component {
|
||||
|
||||
let alphaTransition: ComponentTransition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.2)
|
||||
|
||||
let genericBackgroundColor = UIColor(rgb: 0x1b1d22)
|
||||
let genericBackgroundColor = UIColor(rgb: 0x2d2f38)
|
||||
|
||||
let titleText: String
|
||||
let backgroundColor: UIColor
|
||||
var tintColorKind: GlassBackgroundView.TintColor.Kind = .panel
|
||||
let iconDiameter: CGFloat
|
||||
var isEnabled: Bool = true
|
||||
switch component.content {
|
||||
@@ -208,6 +209,7 @@ final class VideoChatActionButtonComponent: Component {
|
||||
case .leave:
|
||||
titleText = component.strings.VoiceChat_Leave
|
||||
backgroundColor = UIColor(rgb: 0x330d0b)
|
||||
tintColorKind = .custom
|
||||
iconDiameter = 22.0
|
||||
}
|
||||
|
||||
@@ -282,7 +284,7 @@ final class VideoChatActionButtonComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
self.background.update(size: size, cornerRadius: size.width * 0.5, isDark: true, tintColor: .init(kind: .custom, color: backgroundColor), transition: tintTransition)
|
||||
self.background.update(size: size, cornerRadius: size.width * 0.5, isDark: true, tintColor: .init(kind: tintColorKind, color: backgroundColor), transition: tintTransition)
|
||||
transition.setFrame(view: self.background, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) * 0.5), y: size.height + 8.0), size: titleSize)
|
||||
|
||||
@@ -34,7 +34,7 @@ private func blurredAvatarImage(_ dataImage: UIImage) -> UIImage? {
|
||||
}
|
||||
|
||||
private let activityBorderImage: UIImage = {
|
||||
return generateStretchableFilledCircleImage(diameter: 20.0, color: nil, strokeColor: .white, strokeWidth: 2.0)!.withRenderingMode(.alwaysTemplate)
|
||||
return generateStretchableFilledCircleImage(diameter: 32.0, color: nil, strokeColor: .white, strokeWidth: 2.0)!.withRenderingMode(.alwaysTemplate)
|
||||
}()
|
||||
|
||||
final class VideoChatParticipantVideoComponent: Component {
|
||||
@@ -227,7 +227,7 @@ final class VideoChatParticipantVideoComponent: Component {
|
||||
self.pinchContainerNode.contentNode.view.addSubview(self.backgroundGradientView)
|
||||
|
||||
//TODO:release optimize
|
||||
self.pinchContainerNode.contentNode.view.layer.cornerRadius = 10.0
|
||||
self.pinchContainerNode.contentNode.view.layer.cornerRadius = 16.0
|
||||
self.pinchContainerNode.contentNode.view.clipsToBounds = true
|
||||
|
||||
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||
@@ -680,7 +680,7 @@ final class VideoChatParticipantVideoComponent: Component {
|
||||
|
||||
if videoDescription != nil && self.videoSpec == nil && !isEffectivelyPaused {
|
||||
if self.loadingEffectView == nil {
|
||||
let loadingEffectView = VideoChatVideoLoadingEffectView(effectAlpha: 0.1, borderAlpha: 0.2, cornerRadius: 10.0, duration: 1.0)
|
||||
let loadingEffectView = VideoChatVideoLoadingEffectView(effectAlpha: 0.1, borderAlpha: 0.2, cornerRadius: 16.0, duration: 1.0)
|
||||
self.loadingEffectView = loadingEffectView
|
||||
loadingEffectView.alpha = 0.0
|
||||
loadingEffectView.isUserInteractionEnabled = false
|
||||
|
||||
@@ -485,6 +485,14 @@ final class VideoChatScreenComponent: Component {
|
||||
if gestureRecognizer is UIPanGestureRecognizer {
|
||||
if let otherGestureRecognizer = otherGestureRecognizer as? UIPanGestureRecognizer {
|
||||
if otherGestureRecognizer.view is UIScrollView {
|
||||
if let view = otherGestureRecognizer.view {
|
||||
if let inputView = self.inputMediaNode?.view, view.isDescendant(of: inputView) {
|
||||
return false
|
||||
}
|
||||
if let reactionView = self.reactionContextNode?.view, view.isDescendant(of: reactionView) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
if let participantsView = self.participants.view as? VideoChatParticipantsComponent.View {
|
||||
@@ -2195,7 +2203,7 @@ final class VideoChatScreenComponent: Component {
|
||||
|
||||
let landscapeControlsWidth: CGFloat = 104.0
|
||||
var landscapeControlsOffsetX: CGFloat = 0.0
|
||||
//let landscapeControlsSpacing: CGFloat = 30.0
|
||||
let landscapeControlsSpacing: CGFloat = 30.0
|
||||
|
||||
var leftInset: CGFloat = max(environment.safeInsets.left, 16.0)
|
||||
|
||||
@@ -2222,6 +2230,8 @@ final class VideoChatScreenComponent: Component {
|
||||
let navigationButtonDiameter: CGFloat = 40.0
|
||||
let navigationButtonInset: CGFloat = 4.0
|
||||
|
||||
let panelColor = UIColor(rgb: 0x1f1f27)
|
||||
|
||||
let navigationLeftButtonSize = self.navigationLeftButton.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(PlainButtonComponent(
|
||||
@@ -2232,7 +2242,7 @@ final class VideoChatScreenComponent: Component {
|
||||
color: .white
|
||||
)),
|
||||
background: AnyComponent(
|
||||
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014)))
|
||||
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), isDark: false, tintColor: .init(kind: .panel, color: panelColor))
|
||||
),
|
||||
effectAlignment: .center,
|
||||
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),
|
||||
@@ -2254,7 +2264,7 @@ final class VideoChatScreenComponent: Component {
|
||||
image: closeButtonImage(dark: false)
|
||||
)),
|
||||
background: AnyComponent(
|
||||
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014)))
|
||||
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), isDark: false, tintColor: .init(kind: .panel, color: panelColor))
|
||||
),
|
||||
effectAlignment: .center,
|
||||
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),
|
||||
@@ -2646,24 +2656,28 @@ final class VideoChatScreenComponent: Component {
|
||||
|
||||
//TODO:release
|
||||
let actionButtonSize = CGSize(width: actionButtonDiameter, height: actionButtonDiameter)
|
||||
let firstActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - actionMicrophoneButtonSpacing - actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
let secondActionButtonFrame = CGRect(origin: CGPoint(x: firstActionButtonFrame.minX + 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
var firstActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - actionMicrophoneButtonSpacing - actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
var secondActionButtonFrame = CGRect(origin: CGPoint(x: firstActionButtonFrame.minX + 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
|
||||
let fourthActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
let thirdActionButtonFrame = CGRect(origin: CGPoint(x: fourthActionButtonFrame.minX - 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
|
||||
let _ = firstActionButtonFrame
|
||||
var fourthActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
var thirdActionButtonFrame = CGRect(origin: CGPoint(x: fourthActionButtonFrame.minX - 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
|
||||
|
||||
// var leftActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - actionMicrophoneButtonSpacing - actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: CGSize(width: actionButtonDiameter, height: actionButtonDiameter))
|
||||
// var rightActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: CGSize(width: actionButtonDiameter, height: actionButtonDiameter))
|
||||
|
||||
// if buttonsOnTheSide {
|
||||
// leftActionButtonFrame.origin.x = microphoneButtonFrame.minX
|
||||
// leftActionButtonFrame.origin.y = microphoneButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter
|
||||
//
|
||||
// rightActionButtonFrame.origin.x = microphoneButtonFrame.minX
|
||||
// rightActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing
|
||||
// }
|
||||
if buttonsOnTheSide {
|
||||
secondActionButtonFrame.origin.x = microphoneButtonFrame.minX
|
||||
secondActionButtonFrame.origin.y = microphoneButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter
|
||||
|
||||
firstActionButtonFrame.origin.x = microphoneButtonFrame.minX
|
||||
firstActionButtonFrame.origin.y = secondActionButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter
|
||||
|
||||
thirdActionButtonFrame.origin.x = microphoneButtonFrame.minX
|
||||
thirdActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing
|
||||
|
||||
fourthActionButtonFrame.origin.x = microphoneButtonFrame.minX
|
||||
fourthActionButtonFrame.origin.y = thirdActionButtonFrame.maxY + landscapeControlsSpacing
|
||||
}
|
||||
|
||||
let participantsSize = availableSize
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ swift_library(
|
||||
"//submodules/ActivityIndicator",
|
||||
"//submodules/ShimmerEffect",
|
||||
"//submodules/Components/BundleIconComponent",
|
||||
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
|
||||
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@@ -6,6 +6,7 @@ import AnimatedTextComponent
|
||||
import ActivityIndicator
|
||||
import BundleIconComponent
|
||||
import ShimmerEffect
|
||||
import GlassBackgroundComponent
|
||||
|
||||
public final class ButtonBadgeComponent: Component {
|
||||
let fillColor: UIColor
|
||||
@@ -338,6 +339,12 @@ public final class ButtonTextContentComponent: Component {
|
||||
|
||||
public final class ButtonComponent: Component {
|
||||
public struct Background: Equatable {
|
||||
public enum Style {
|
||||
case glass
|
||||
case legacy
|
||||
}
|
||||
|
||||
public var style: Style
|
||||
public var color: UIColor
|
||||
public var foreground: UIColor
|
||||
public var pressedColor: UIColor
|
||||
@@ -345,12 +352,14 @@ public final class ButtonComponent: Component {
|
||||
public var isShimmering: Bool
|
||||
|
||||
public init(
|
||||
style: Style = .legacy,
|
||||
color: UIColor,
|
||||
foreground: UIColor,
|
||||
pressedColor: UIColor,
|
||||
cornerRadius: CGFloat = 10.0,
|
||||
isShimmering: Bool = false
|
||||
) {
|
||||
self.style = style
|
||||
self.color = color
|
||||
self.foreground = foreground
|
||||
self.pressedColor = pressedColor
|
||||
@@ -360,6 +369,7 @@ public final class ButtonComponent: Component {
|
||||
|
||||
public func withIsShimmering(_ isShimmering: Bool) -> Background {
|
||||
return Background(
|
||||
style: self.style,
|
||||
color: self.color,
|
||||
foreground: self.foreground,
|
||||
pressedColor: self.pressedColor,
|
||||
@@ -431,6 +441,7 @@ public final class ButtonComponent: Component {
|
||||
private weak var componentState: EmptyComponentState?
|
||||
|
||||
private var shimmeringView: ButtonShimmeringView?
|
||||
private var chromeView: UIImageView?
|
||||
private var contentItem: ContentItem?
|
||||
|
||||
private var activityIndicator: ActivityIndicator?
|
||||
@@ -475,7 +486,12 @@ public final class ButtonComponent: Component {
|
||||
self.isEnabled = (component.isEnabled || component.allowActionWhenDisabled) && !component.displaysProgress
|
||||
|
||||
transition.setBackgroundColor(view: self, color: component.background.color)
|
||||
transition.setCornerRadius(layer: self.layer, cornerRadius: component.background.cornerRadius)
|
||||
|
||||
var cornerRadius: CGFloat = component.background.cornerRadius
|
||||
if case .glass = component.background.style, component.background.cornerRadius == 10.0 {
|
||||
cornerRadius = availableSize.height * 0.5
|
||||
}
|
||||
transition.setCornerRadius(layer: self.layer, cornerRadius: cornerRadius)
|
||||
|
||||
var contentAlpha: CGFloat = 1.0
|
||||
if component.displaysProgress {
|
||||
@@ -581,6 +597,33 @@ public final class ButtonComponent: Component {
|
||||
})
|
||||
}
|
||||
|
||||
if component.background.style == .glass {
|
||||
let chromeView: UIImageView
|
||||
var chromeTransition = transition
|
||||
if let current = self.chromeView {
|
||||
chromeView = current
|
||||
} else {
|
||||
chromeTransition = .immediate
|
||||
chromeView = UIImageView()
|
||||
self.chromeView = chromeView
|
||||
if let shimmeringView = self.shimmeringView {
|
||||
self.insertSubview(chromeView, aboveSubview: shimmeringView)
|
||||
} else {
|
||||
self.insertSubview(chromeView, at: 0)
|
||||
}
|
||||
|
||||
chromeView.layer.compositingFilter = "overlayBlendMode"
|
||||
chromeView.alpha = 0.8
|
||||
chromeView.image = GlassBackgroundView.generateForegroundImage(size: CGSize(width: 26.0 * 2.0, height: 26.0 * 2.0), isDark: component.background.color.lightness < 0.4, fillColor: .clear)
|
||||
}
|
||||
chromeTransition.setFrame(view: chromeView, frame: CGRect(origin: .zero, size: availableSize))
|
||||
} else if let chromeView = self.chromeView {
|
||||
self.chromeView = nil
|
||||
chromeView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { _ in
|
||||
chromeView.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,7 +834,8 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
file: arguments.parentMessage.associatedMedia[MediaId(
|
||||
namespace: Namespaces.Media.CloudFile,
|
||||
id: backgroundEmojiId
|
||||
)] as? TelegramMediaFile
|
||||
)] as? TelegramMediaFile,
|
||||
emptyCorner: giftEmojiFileId != nil
|
||||
)
|
||||
}
|
||||
var isTransparent: Bool = false
|
||||
@@ -898,16 +899,19 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
if let giftEmojiFileId {
|
||||
let giftLayerSize = CGSize(width: 20.0, height: 20.0)
|
||||
let giftLayerFrame = CGRect(origin: CGPoint(x: textFrame.minX - 16.0, y: 5.0), size: giftLayerSize)
|
||||
let giftLayerSize = CGSize(width: 18.0, height: 18.0)
|
||||
let giftLayerFrame = CGRect(origin: CGPoint(x: realSize.width - giftLayerSize.width - 4.0, y: 3.0), size: giftLayerSize)
|
||||
|
||||
let giftEmojiLayer: InlineStickerItemLayer
|
||||
if let current = node.giftEmojiLayer {
|
||||
if let current = node.giftEmojiLayer, current.file?.fileId.id == giftEmojiFileId {
|
||||
giftEmojiLayer = current
|
||||
|
||||
animation.animator.updateFrame(layer: giftEmojiLayer, frame: giftLayerFrame, completion: nil)
|
||||
} else {
|
||||
giftEmojiLayer = InlineStickerItemLayer(context: arguments.context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: giftEmojiFileId, file: nil, custom: nil, enableAnimation: true), file: nil, cache: arguments.context.animationCache, renderer: arguments.context.animationRenderer, unique: false, placeholderColor: placeholderColor, pointSize: giftLayerSize, dynamicColor: nil, loopCount: 2)
|
||||
if let giftEmojiLayer = node.giftEmojiLayer {
|
||||
node.giftEmojiLayer = nil
|
||||
giftEmojiLayer.removeFromSuperlayer()
|
||||
}
|
||||
giftEmojiLayer = InlineStickerItemLayer(context: arguments.context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: giftEmojiFileId, file: nil, custom: nil, enableAnimation: true), file: nil, cache: arguments.context.animationCache, renderer: arguments.context.animationRenderer, unique: false, placeholderColor: placeholderColor, pointSize: CGSize(width: giftLayerSize.width * 2.0, height: giftLayerSize.height * 2.0), dynamicColor: nil, loopCount: 2)
|
||||
node.giftEmojiLayer = giftEmojiLayer
|
||||
node.contentNode.layer.addSublayer(giftEmojiLayer)
|
||||
|
||||
|
||||
@@ -426,11 +426,13 @@ public final class MessageInlineBlockBackgroundView: UIView {
|
||||
public let context: AccountContext
|
||||
public let fileId: Int64
|
||||
public let file: TelegramMediaFile?
|
||||
public let emptyCorner: Bool
|
||||
|
||||
public init(context: AccountContext, fileId: Int64, file: TelegramMediaFile?) {
|
||||
public init(context: AccountContext, fileId: Int64, file: TelegramMediaFile?, emptyCorner: Bool = false) {
|
||||
self.context = context
|
||||
self.fileId = fileId
|
||||
self.file = file
|
||||
self.emptyCorner = emptyCorner
|
||||
}
|
||||
|
||||
public static func ==(lhs: Pattern, rhs: Pattern) -> Bool {
|
||||
@@ -446,7 +448,9 @@ public final class MessageInlineBlockBackgroundView: UIView {
|
||||
if lhs.file?.fileId != rhs.file?.fileId {
|
||||
return false
|
||||
}
|
||||
|
||||
if lhs.emptyCorner != rhs.emptyCorner {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -771,7 +775,12 @@ public final class MessageInlineBlockBackgroundView: UIView {
|
||||
patternContentLayer.frame = CGRect(origin: CGPoint(x: patternOrigin.x - placement.position.x / 3.0 - itemSize.width * 0.5, y: patternOrigin.y + placement.position.y / 3.0 - itemSize.height * 0.5), size: itemSize)
|
||||
var alphaFraction = abs(placement.position.x / 3.0) / min(500.0, size.width)
|
||||
alphaFraction = min(1.0, max(0.0, alphaFraction))
|
||||
patternContentLayer.opacity = 0.3 * Float(1.0 - alphaFraction) * Float(patternAlpha)
|
||||
|
||||
if maxIndex == 1 && params.pattern?.emptyCorner == true {
|
||||
patternContentLayer.opacity = 0.0
|
||||
} else {
|
||||
patternContentLayer.opacity = 0.3 * Float(1.0 - alphaFraction) * Float(patternAlpha)
|
||||
}
|
||||
|
||||
maxIndex += 1
|
||||
}
|
||||
|
||||
@@ -784,10 +784,12 @@ public extension GlassBackgroundView {
|
||||
|
||||
public final class GlassBackgroundComponent: Component {
|
||||
private let size: CGSize
|
||||
private let isDark: Bool
|
||||
private let tintColor: GlassBackgroundView.TintColor
|
||||
|
||||
public init(size: CGSize, tintColor: GlassBackgroundView.TintColor) {
|
||||
public init(size: CGSize, isDark: Bool, tintColor: GlassBackgroundView.TintColor) {
|
||||
self.size = size
|
||||
self.isDark = isDark
|
||||
self.tintColor = tintColor
|
||||
}
|
||||
|
||||
@@ -795,6 +797,9 @@ public final class GlassBackgroundComponent: Component {
|
||||
if lhs.size != rhs.size {
|
||||
return false
|
||||
}
|
||||
if lhs.isDark != rhs.isDark {
|
||||
return false
|
||||
}
|
||||
if lhs.tintColor != rhs.tintColor {
|
||||
return false
|
||||
}
|
||||
@@ -803,7 +808,7 @@ public final class GlassBackgroundComponent: Component {
|
||||
|
||||
public final class View: GlassBackgroundView {
|
||||
func update(component: GlassBackgroundComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
self.update(size: component.size, cornerRadius: component.size.height / 2.0, isDark: true, tintColor: component.tintColor, transition: transition)
|
||||
self.update(size: component.size, cornerRadius: component.size.height / 2.0, isDark: component.isDark, tintColor: component.tintColor, transition: transition)
|
||||
self.frame = CGRect(origin: .zero, size: component.size)
|
||||
|
||||
return component.size
|
||||
|
||||
@@ -8,6 +8,11 @@ import SwitchNode
|
||||
import CheckNode
|
||||
|
||||
public final class ListActionItemComponent: Component {
|
||||
public enum Style {
|
||||
case glass
|
||||
case legacy
|
||||
}
|
||||
|
||||
public enum ToggleStyle {
|
||||
case regular
|
||||
case icons
|
||||
@@ -133,6 +138,7 @@ public final class ListActionItemComponent: Component {
|
||||
}
|
||||
|
||||
public let theme: PresentationTheme
|
||||
public let style: Style
|
||||
public let background: AnyComponent<Empty>?
|
||||
public let title: AnyComponent<Empty>
|
||||
public let titleAlignment: Alignment
|
||||
@@ -146,6 +152,7 @@ public final class ListActionItemComponent: Component {
|
||||
|
||||
public init(
|
||||
theme: PresentationTheme,
|
||||
style: Style = .legacy,
|
||||
background: AnyComponent<Empty>? = nil,
|
||||
title: AnyComponent<Empty>,
|
||||
titleAlignment: Alignment = .default,
|
||||
@@ -158,6 +165,7 @@ public final class ListActionItemComponent: Component {
|
||||
updateIsHighlighted: ((UIView, Bool) -> Void)? = nil
|
||||
) {
|
||||
self.theme = theme
|
||||
self.style = style
|
||||
self.background = background
|
||||
self.title = title
|
||||
self.titleAlignment = titleAlignment
|
||||
@@ -174,6 +182,9 @@ public final class ListActionItemComponent: Component {
|
||||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
if lhs.style != rhs.style {
|
||||
return false
|
||||
}
|
||||
if lhs.background != rhs.background {
|
||||
return false
|
||||
}
|
||||
@@ -391,8 +402,19 @@ public final class ListActionItemComponent: Component {
|
||||
contentRightInset = customAccessorySizeValue.width + customAccessory.insets.left + customAccessory.insets.right
|
||||
}
|
||||
|
||||
var contentInsets = component.contentInsets
|
||||
switch component.style {
|
||||
case .glass:
|
||||
if contentInsets.top == 12.0 && contentInsets.bottom == 12.0 {
|
||||
contentInsets.top = 16.0
|
||||
contentInsets.bottom = 16.0
|
||||
}
|
||||
case .legacy:
|
||||
break
|
||||
}
|
||||
|
||||
var contentHeight: CGFloat = 0.0
|
||||
contentHeight += component.contentInsets.top
|
||||
contentHeight += contentInsets.top
|
||||
|
||||
if let leftIcon = component.leftIcon {
|
||||
switch leftIcon {
|
||||
@@ -414,11 +436,10 @@ public final class ListActionItemComponent: Component {
|
||||
contentLeftInset = floor((availableSize.width - titleSize.width) / 2.0)
|
||||
}
|
||||
|
||||
|
||||
let titleY = contentHeight
|
||||
contentHeight += titleSize.height
|
||||
|
||||
contentHeight += component.contentInsets.bottom
|
||||
contentHeight += contentInsets.bottom
|
||||
|
||||
if let iconValue = component.icon {
|
||||
if previousComponent?.icon?.component.id != iconValue.component.id, let icon = self.icon {
|
||||
|
||||
@@ -41,6 +41,7 @@ public final class ListSectionContentView: UIView {
|
||||
|
||||
public final class Configuration {
|
||||
public let theme: PresentationTheme
|
||||
public let style: ListSectionComponent.Style
|
||||
public let isModal: Bool
|
||||
public let displaySeparators: Bool
|
||||
public let extendsItemHighlightToSection: Bool
|
||||
@@ -48,12 +49,14 @@ public final class ListSectionContentView: UIView {
|
||||
|
||||
public init(
|
||||
theme: PresentationTheme,
|
||||
style: ListSectionComponent.Style = .legacy,
|
||||
isModal: Bool = false,
|
||||
displaySeparators: Bool,
|
||||
extendsItemHighlightToSection: Bool,
|
||||
background: ListSectionComponent.Background
|
||||
) {
|
||||
self.theme = theme
|
||||
self.style = style
|
||||
self.isModal = isModal
|
||||
self.displaySeparators = displaySeparators
|
||||
self.extendsItemHighlightToSection = extendsItemHighlightToSection
|
||||
@@ -152,6 +155,14 @@ public final class ListSectionContentView: UIView {
|
||||
}
|
||||
self.externalContentBackgroundView.updateColor(color: backgroundColor, transition: transition)
|
||||
|
||||
let cornerRadius: CGFloat
|
||||
switch configuration.style {
|
||||
case .glass:
|
||||
cornerRadius = 26.0
|
||||
case .legacy:
|
||||
cornerRadius = 11.0
|
||||
}
|
||||
|
||||
var innerContentHeight: CGFloat = 0.0
|
||||
var validItemIds: [AnyHashable] = []
|
||||
for index in 0 ..< readyItems.count {
|
||||
@@ -264,18 +275,18 @@ public final class ListSectionContentView: UIView {
|
||||
|
||||
let backgroundFrame: CGRect
|
||||
var backgroundAlpha: CGFloat = 1.0
|
||||
var contentCornerRadius: CGFloat = 11.0
|
||||
var contentCornerRadius: CGFloat = cornerRadius
|
||||
switch configuration.background {
|
||||
case let .none(clipped):
|
||||
backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)
|
||||
backgroundAlpha = 0.0
|
||||
self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: 11.0, maxXMinY: 11.0, minXMaxY: 11.0, maxXMaxY: 11.0), transition: transition)
|
||||
self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: cornerRadius, maxXMinY: cornerRadius, minXMaxY: cornerRadius, maxXMaxY: cornerRadius), transition: transition)
|
||||
if !clipped {
|
||||
contentCornerRadius = 0.0
|
||||
}
|
||||
case .all:
|
||||
backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)
|
||||
self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: 11.0, maxXMinY: 11.0, minXMaxY: 11.0, maxXMaxY: 11.0), transition: transition)
|
||||
self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: cornerRadius, maxXMinY: cornerRadius, minXMaxY: cornerRadius, maxXMaxY: cornerRadius), transition: transition)
|
||||
case let .range(from, corners):
|
||||
if let itemView = self.itemViews[from], itemView.frame.minY < size.height {
|
||||
backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: itemView.frame.minY), size: CGSize(width: size.width, height: size.height - itemView.frame.minY))
|
||||
@@ -306,7 +317,13 @@ public final class ListSectionComponent: Component {
|
||||
case range(from: AnyHashable, corners: DynamicCornerRadiusView.Corners)
|
||||
}
|
||||
|
||||
public enum Style {
|
||||
case glass
|
||||
case legacy
|
||||
}
|
||||
|
||||
public let theme: PresentationTheme
|
||||
public let style: Style
|
||||
public let background: Background
|
||||
public let header: AnyComponent<Empty>?
|
||||
public let footer: AnyComponent<Empty>?
|
||||
@@ -317,6 +334,7 @@ public final class ListSectionComponent: Component {
|
||||
|
||||
public init(
|
||||
theme: PresentationTheme,
|
||||
style: Style = .legacy,
|
||||
background: Background = .all,
|
||||
header: AnyComponent<Empty>?,
|
||||
footer: AnyComponent<Empty>?,
|
||||
@@ -326,6 +344,7 @@ public final class ListSectionComponent: Component {
|
||||
extendsItemHighlightToSection: Bool = false
|
||||
) {
|
||||
self.theme = theme
|
||||
self.style = style
|
||||
self.background = background
|
||||
self.header = header
|
||||
self.footer = footer
|
||||
@@ -339,6 +358,9 @@ public final class ListSectionComponent: Component {
|
||||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
if lhs.style != rhs.style {
|
||||
return false
|
||||
}
|
||||
if lhs.background != rhs.background {
|
||||
return false
|
||||
}
|
||||
@@ -464,6 +486,7 @@ public final class ListSectionComponent: Component {
|
||||
let contentResult = self.contentView.update(
|
||||
configuration: ListSectionContentView.Configuration(
|
||||
theme: component.theme,
|
||||
style: component.style,
|
||||
isModal: component.isModal,
|
||||
displaySeparators: component.displaySeparators,
|
||||
extendsItemHighlightToSection: component.extendsItemHighlightToSection,
|
||||
@@ -638,6 +661,7 @@ public final class ListSubSectionComponent: Component {
|
||||
let contentResult = self.contentView.update(
|
||||
configuration: ListSectionContentView.Configuration(
|
||||
theme: component.theme,
|
||||
style: .legacy,
|
||||
isModal: component.isModal,
|
||||
displaySeparators: component.displaySeparators,
|
||||
extendsItemHighlightToSection: false,
|
||||
|
||||
@@ -54,6 +54,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/EmojiActionIconComponent",
|
||||
"//submodules/TelegramUI/Components/TabSelectorComponent",
|
||||
"//submodules/TelegramUI/Components/PlainButtonComponent",
|
||||
"//submodules/TextFormat",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@@ -33,6 +33,8 @@ import PeerNameColorItem
|
||||
import EmojiActionIconComponent
|
||||
import TabSelectorComponent
|
||||
import WallpaperResources
|
||||
import EdgeEffect
|
||||
import TextFormat
|
||||
|
||||
private let giftListTag = GenericComponentViewTag()
|
||||
|
||||
@@ -143,8 +145,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
private let topOverscrollLayer = SimpleLayer()
|
||||
private let scrollView: ScrollView
|
||||
private let actionButton = ComponentView<Empty>()
|
||||
private let bottomPanelBackgroundView: BlurredBackgroundView
|
||||
private let bottomPanelSeparator: SimpleLayer
|
||||
private let edgeEffectView: EdgeEffectView
|
||||
|
||||
private let backButton = PeerInfoHeaderNavigationButton()
|
||||
|
||||
@@ -155,12 +156,13 @@ final class UserAppearanceScreenComponent: Component {
|
||||
}
|
||||
private var currentSection: Section = .profile
|
||||
|
||||
private let previewSection = ComponentView<Empty>()
|
||||
private let boostSection = ComponentView<Empty>()
|
||||
private let bannerSection = ComponentView<Empty>()
|
||||
private let replySection = ComponentView<Empty>()
|
||||
private let resetColorSection = ComponentView<Empty>()
|
||||
private let profilePreview = ComponentView<Empty>()
|
||||
private let profileColorSection = ComponentView<Empty>()
|
||||
private let profileResetColorSection = ComponentView<Empty>()
|
||||
private let profileGiftsSection = ComponentView<Empty>()
|
||||
|
||||
private let namePreview = ComponentView<Empty>()
|
||||
private let nameColorSection = ComponentView<Empty>()
|
||||
private let nameGiftsSection = ComponentView<Empty>()
|
||||
|
||||
private var isUpdating: Bool = false
|
||||
@@ -195,6 +197,8 @@ final class UserAppearanceScreenComponent: Component {
|
||||
|
||||
private weak var emojiStatusSelectionController: ViewController?
|
||||
|
||||
private var cachedChevronImage: (UIImage, PresentationTheme)?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.scrollView = ScrollView()
|
||||
self.scrollView.showsVerticalScrollIndicator = false
|
||||
@@ -208,8 +212,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
}
|
||||
self.scrollView.alwaysBounceVertical = true
|
||||
|
||||
self.bottomPanelBackgroundView = BlurredBackgroundView(color: .clear, enableBlur: true)
|
||||
self.bottomPanelSeparator = SimpleLayer()
|
||||
self.edgeEffectView = EdgeEffectView()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
@@ -218,8 +221,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
|
||||
self.scrollView.layer.addSublayer(self.topOverscrollLayer)
|
||||
|
||||
self.addSubview(self.bottomPanelBackgroundView)
|
||||
self.layer.addSublayer(self.bottomPanelSeparator)
|
||||
self.addSubview(self.edgeEffectView)
|
||||
|
||||
self.backButton.action = { [weak self] _, _ in
|
||||
if let self, let controller = self.environment?.controller() {
|
||||
@@ -297,16 +299,10 @@ final class UserAppearanceScreenComponent: Component {
|
||||
if self.scrolledUp != scrolledUp {
|
||||
self.scrolledUp = scrolledUp
|
||||
if !self.isUpdating {
|
||||
self.state?.updated()
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.3))
|
||||
}
|
||||
}
|
||||
|
||||
let bottomNavigationAlphaDistance: CGFloat = 16.0
|
||||
let bottomNavigationAlpha: CGFloat = max(0.0, min(1.0, (self.scrollView.contentSize.height - self.scrollView.bounds.maxY) / bottomNavigationAlphaDistance))
|
||||
|
||||
transition.setAlpha(view: self.bottomPanelBackgroundView, alpha: bottomNavigationAlpha)
|
||||
transition.setAlpha(layer: self.bottomPanelSeparator, alpha: bottomNavigationAlpha)
|
||||
|
||||
switch self.currentSection {
|
||||
case .profile:
|
||||
if let giftListView = self.profileGiftsSection.findTaggedView(tag: giftListTag) as? GiftListItemComponent.View {
|
||||
@@ -600,6 +596,9 @@ final class UserAppearanceScreenComponent: Component {
|
||||
}
|
||||
switch subject {
|
||||
case .reply:
|
||||
if case .collectible = resolvedState.nameColor {
|
||||
self.updatedPeerNameColor = .preset(.blue)
|
||||
}
|
||||
if let result {
|
||||
self.updatedPeerNameEmoji = result.fileId.id
|
||||
} else {
|
||||
@@ -681,6 +680,10 @@ final class UserAppearanceScreenComponent: Component {
|
||||
self.backgroundColor = environment.theme.list.blocksBackgroundColor
|
||||
}
|
||||
|
||||
if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme {
|
||||
self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
|
||||
}
|
||||
|
||||
if self.contentsDataDisposable == nil {
|
||||
self.contentsDataDisposable = (ContentsData.get(context: component.context)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] contentsData in
|
||||
@@ -804,7 +807,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
}
|
||||
if let intValue = value.base as? Int32 {
|
||||
self.currentSection = Section(rawValue: intValue) ?? .profile
|
||||
self.state?.updated(transition: .immediate)
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.3))
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -829,14 +832,20 @@ final class UserAppearanceScreenComponent: Component {
|
||||
|
||||
var contentHeight: CGFloat = 0.0
|
||||
|
||||
let sectionTransition = transition
|
||||
|
||||
let itemCornerRadius: CGFloat = 10.0
|
||||
let itemCornerRadius: CGFloat = 26.0
|
||||
|
||||
switch self.currentSection {
|
||||
case .profile:
|
||||
if let replySectionView = self.replySection.view, replySectionView.superview != nil {
|
||||
replySectionView.removeFromSuperview()
|
||||
var transition = transition
|
||||
if self.profilePreview.view == nil {
|
||||
transition = .immediate
|
||||
}
|
||||
|
||||
if let namePreviewView = self.namePreview.view, namePreviewView.superview != nil {
|
||||
namePreviewView.removeFromSuperview()
|
||||
}
|
||||
if let nameColorSectionView = self.nameColorSection.view, nameColorSectionView.superview != nil {
|
||||
nameColorSectionView.removeFromSuperview()
|
||||
}
|
||||
if let nameGiftsSectionView = self.nameGiftsSection.view, nameGiftsSectionView.superview != nil {
|
||||
nameGiftsSectionView.removeFromSuperview()
|
||||
@@ -850,46 +859,35 @@ final class UserAppearanceScreenComponent: Component {
|
||||
hasHeaderColor = true
|
||||
}
|
||||
|
||||
let previewSectionSize = self.previewSection.update(
|
||||
transition: sectionTransition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
background: .none(clipped: false),
|
||||
header: nil,
|
||||
footer: nil,
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor(
|
||||
itemGenerator: PeerNameColorProfilePreviewItem(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
componentTheme: environment.theme,
|
||||
strings: environment.strings,
|
||||
topInset: 0.0,
|
||||
sectionId: 0,
|
||||
peer: peer,
|
||||
subtitleString: environment.strings.Presence_online,
|
||||
files: self.cachedIconFiles,
|
||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||
showBackground: false
|
||||
),
|
||||
params: ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true)
|
||||
))),
|
||||
],
|
||||
displaySeparators: false,
|
||||
extendsItemHighlightToSection: true
|
||||
)),
|
||||
let profilePreviewSize = self.profilePreview.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(TopBottomCornersComponent(topCornerRadius: itemCornerRadius, bottomCornerRadius: !self.scrolledUp ? itemCornerRadius : 0.0, component: AnyComponent(ListItemComponentAdaptor(
|
||||
itemGenerator: PeerNameColorProfilePreviewItem(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
componentTheme: environment.theme,
|
||||
strings: environment.strings,
|
||||
topInset: 0.0,
|
||||
sectionId: 0,
|
||||
peer: peer,
|
||||
subtitleString: environment.strings.Presence_online,
|
||||
files: self.cachedIconFiles,
|
||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||
showBackground: false
|
||||
),
|
||||
params: ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true)
|
||||
)))),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0)
|
||||
)
|
||||
let previewSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: environment.navigationHeight + 12.0), size: previewSectionSize)
|
||||
if let previewSectionView = self.previewSection.view {
|
||||
if previewSectionView.superview == nil {
|
||||
self.addSubview(previewSectionView)
|
||||
let profilePreviewFrame = CGRect(origin: CGPoint(x: sideInset, y: environment.navigationHeight + 12.0), size: profilePreviewSize)
|
||||
if let profilePreviewView = self.profilePreview.view {
|
||||
if profilePreviewView.superview == nil {
|
||||
self.addSubview(profilePreviewView)
|
||||
}
|
||||
sectionTransition.setFrame(view: previewSectionView, frame: previewSectionFrame)
|
||||
transition.setFrame(view: profilePreviewView, frame: profilePreviewFrame)
|
||||
}
|
||||
contentHeight += previewSectionSize.height
|
||||
contentHeight += environment.navigationHeight + 12.0
|
||||
contentHeight += profilePreviewSize.height - 18.0
|
||||
|
||||
var profileLogoContents: [AnyComponentWithIdentity<Empty>] = []
|
||||
profileLogoContents.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
|
||||
@@ -900,15 +898,50 @@ final class UserAppearanceScreenComponent: Component {
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
))))
|
||||
let bannerSectionSize = self.bannerSection.update(
|
||||
transition: sectionTransition,
|
||||
|
||||
//TODO:localize
|
||||
let footerAttributes = MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.freeTextColor),
|
||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.freeTextColor),
|
||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemAccentColor),
|
||||
linkAttribute: { contents in
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
}
|
||||
)
|
||||
let previewFooterText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("You can also change color of your name and customize replies to you. [Change >]()", attributes: footerAttributes))
|
||||
if let range = previewFooterText.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 {
|
||||
previewFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: previewFooterText.string))
|
||||
}
|
||||
|
||||
let profileColorSectionSize = self.profileColorSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
background: .range(from: 1, corners: DynamicCornerRadiusView.Corners(minXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, maxXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, minXMaxY: itemCornerRadius, maxXMaxY: itemCornerRadius)),
|
||||
style: .glass,
|
||||
background: .range(from: 0, corners: DynamicCornerRadiusView.Corners(minXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, maxXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, minXMaxY: itemCornerRadius, maxXMaxY: itemCornerRadius)),
|
||||
header: nil,
|
||||
footer: nil,
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(previewFooterText),
|
||||
maximumNumberOfLines: 0,
|
||||
highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1),
|
||||
highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0),
|
||||
highlightAction: { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
},
|
||||
tapAction: { [weak self] _, _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.currentSection = .name
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.3))
|
||||
}
|
||||
)),
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(ListItemComponentAdaptor(
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor(
|
||||
itemGenerator: PeerNameColorItem(
|
||||
theme: environment.theme,
|
||||
colors: component.context.peerNameColors,
|
||||
@@ -928,8 +961,9 @@ final class UserAppearanceScreenComponent: Component {
|
||||
),
|
||||
params: listItemParams
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent(
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
style: .glass,
|
||||
title: AnyComponent(HStack(profileLogoContents, spacing: 6.0)),
|
||||
icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent(
|
||||
context: component.context,
|
||||
@@ -956,25 +990,27 @@ final class UserAppearanceScreenComponent: Component {
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0)
|
||||
)
|
||||
let bannerSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: bannerSectionSize)
|
||||
if let bannerSectionView = self.bannerSection.view {
|
||||
if bannerSectionView.superview == nil {
|
||||
self.scrollView.addSubview(bannerSectionView)
|
||||
let profileColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: profileColorSectionSize)
|
||||
if let profileColorSectionView = self.profileColorSection.view {
|
||||
if profileColorSectionView.superview == nil {
|
||||
self.scrollView.addSubview(profileColorSectionView)
|
||||
}
|
||||
sectionTransition.setFrame(view: bannerSectionView, frame: bannerSectionFrame)
|
||||
transition.setFrame(view: profileColorSectionView, frame: profileColorSectionFrame)
|
||||
}
|
||||
contentHeight += bannerSectionSize.height
|
||||
contentHeight += profileColorSectionSize.height
|
||||
contentHeight += sectionSpacing
|
||||
|
||||
let resetColorSectionSize = self.resetColorSection.update(
|
||||
transition: sectionTransition,
|
||||
let profileResetColorSectionSize = self.profileResetColorSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
style: .glass,
|
||||
header: nil,
|
||||
footer: nil,
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
style: .glass,
|
||||
title: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.Channel_Appearance_ResetProfileColor,
|
||||
@@ -1011,18 +1047,18 @@ final class UserAppearanceScreenComponent: Component {
|
||||
displayResetProfileColor = true
|
||||
}
|
||||
|
||||
let resetColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: resetColorSectionSize)
|
||||
if let resetColorSectionView = self.resetColorSection.view {
|
||||
if resetColorSectionView.superview == nil {
|
||||
self.scrollView.addSubview(resetColorSectionView)
|
||||
let profileResetColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: profileResetColorSectionSize)
|
||||
if let profileResetColorSectionView = self.profileResetColorSection.view {
|
||||
if profileResetColorSectionView.superview == nil {
|
||||
self.scrollView.addSubview(profileResetColorSectionView)
|
||||
}
|
||||
sectionTransition.setPosition(view: resetColorSectionView, position: resetColorSectionFrame.center)
|
||||
sectionTransition.setBounds(view: resetColorSectionView, bounds: CGRect(origin: CGPoint(), size: resetColorSectionFrame.size))
|
||||
sectionTransition.setScale(view: resetColorSectionView, scale: displayResetProfileColor ? 1.0 : 0.001)
|
||||
sectionTransition.setAlpha(view: resetColorSectionView, alpha: displayResetProfileColor ? 1.0 : 0.0)
|
||||
transition.setPosition(view: profileResetColorSectionView, position: profileResetColorSectionFrame.center)
|
||||
transition.setBounds(view: profileResetColorSectionView, bounds: CGRect(origin: CGPoint(), size: profileResetColorSectionFrame.size))
|
||||
transition.setScale(view: profileResetColorSectionView, scale: displayResetProfileColor ? 1.0 : 0.001)
|
||||
transition.setAlpha(view: profileResetColorSectionView, alpha: displayResetProfileColor ? 1.0 : 0.0)
|
||||
}
|
||||
if displayResetProfileColor {
|
||||
contentHeight += resetColorSectionSize.height
|
||||
contentHeight += profileResetColorSectionSize.height
|
||||
contentHeight += sectionSpacing
|
||||
}
|
||||
|
||||
@@ -1032,9 +1068,10 @@ final class UserAppearanceScreenComponent: Component {
|
||||
selectedGiftId = id
|
||||
}
|
||||
let giftsSectionSize = self.profileGiftsSection.update(
|
||||
transition: sectionTransition,
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
style: .glass,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.NameColor_GiftTitle,
|
||||
@@ -1106,19 +1143,24 @@ final class UserAppearanceScreenComponent: Component {
|
||||
if giftsSectionView.superview == nil {
|
||||
self.scrollView.addSubview(giftsSectionView)
|
||||
}
|
||||
sectionTransition.setFrame(view: giftsSectionView, frame: giftsSectionFrame)
|
||||
transition.setFrame(view: giftsSectionView, frame: giftsSectionFrame)
|
||||
}
|
||||
contentHeight += giftsSectionSize.height
|
||||
contentHeight += sectionSpacing
|
||||
}
|
||||
case .name:
|
||||
if let previewSectionView = self.previewSection.view, previewSectionView.superview != nil {
|
||||
previewSectionView.removeFromSuperview()
|
||||
var transition = transition
|
||||
if self.namePreview.view == nil {
|
||||
transition = .immediate
|
||||
}
|
||||
if let bannerSectionView = self.bannerSection.view, bannerSectionView.superview != nil {
|
||||
bannerSectionView.removeFromSuperview()
|
||||
|
||||
if let profilePreviewView = self.profilePreview.view, profilePreviewView.superview != nil {
|
||||
profilePreviewView.removeFromSuperview()
|
||||
}
|
||||
if let resetColorSectionView = self.resetColorSection.view, resetColorSectionView.superview != nil {
|
||||
if let profileColorSectionView = self.profileColorSection.view, profileColorSectionView.superview != nil {
|
||||
profileColorSectionView.removeFromSuperview()
|
||||
}
|
||||
if let resetColorSectionView = self.profileResetColorSection.view, resetColorSectionView.superview != nil {
|
||||
resetColorSectionView.removeFromSuperview()
|
||||
}
|
||||
if let profileGiftsSectionView = self.profileGiftsSection.view, profileGiftsSectionView.superview != nil {
|
||||
@@ -1165,10 +1207,42 @@ final class UserAppearanceScreenComponent: Component {
|
||||
replyColor = collectibleColor.mainColor(dark: environment.theme.overallDarkAppearance)
|
||||
}
|
||||
|
||||
let replySectionSize = self.replySection.update(
|
||||
transition: sectionTransition,
|
||||
let namePreviewSize = self.namePreview.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(TopBottomCornersComponent(topCornerRadius: itemCornerRadius, bottomCornerRadius: !self.scrolledUp ? itemCornerRadius : 0.0, component: AnyComponent(ListItemComponentAdaptor(
|
||||
itemGenerator: PeerNameColorChatPreviewItem(
|
||||
context: component.context,
|
||||
theme: chatPreviewTheme,
|
||||
componentTheme: chatPreviewTheme,
|
||||
strings: environment.strings,
|
||||
sectionId: 0,
|
||||
fontSize: presentationData.chatFontSize,
|
||||
chatBubbleCorners: presentationData.chatBubbleCorners,
|
||||
wallpaper: chatPreviewWallpaper,
|
||||
dateTimeFormat: environment.dateTimeFormat,
|
||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||
messageItems: [messageItem]
|
||||
),
|
||||
params: ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true)
|
||||
)))),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0)
|
||||
)
|
||||
let namePreviewFrame = CGRect(origin: CGPoint(x: sideInset, y: environment.navigationHeight + 12.0), size: namePreviewSize)
|
||||
if let namePreviewView = self.namePreview.view {
|
||||
if namePreviewView.superview == nil {
|
||||
self.addSubview(namePreviewView)
|
||||
}
|
||||
transition.setFrame(view: namePreviewView, frame: namePreviewFrame)
|
||||
}
|
||||
contentHeight += namePreviewSize.height - 18.0
|
||||
|
||||
let nameColorSectionSize = self.nameColorSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
style: .glass,
|
||||
background: .range(from: 0, corners: DynamicCornerRadiusView.Corners(minXMinY: 0.0, maxXMinY: 0.0, minXMaxY: itemCornerRadius, maxXMaxY: itemCornerRadius)),
|
||||
header: nil,
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
@@ -1180,31 +1254,18 @@ final class UserAppearanceScreenComponent: Component {
|
||||
)),
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor(
|
||||
itemGenerator: PeerNameColorChatPreviewItem(
|
||||
context: component.context,
|
||||
theme: chatPreviewTheme,
|
||||
componentTheme: chatPreviewTheme,
|
||||
strings: environment.strings,
|
||||
sectionId: 0,
|
||||
fontSize: presentationData.chatFontSize,
|
||||
chatBubbleCorners: presentationData.chatBubbleCorners,
|
||||
wallpaper: chatPreviewWallpaper,
|
||||
dateTimeFormat: environment.dateTimeFormat,
|
||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||
messageItems: [messageItem]
|
||||
),
|
||||
params: listItemParams
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(ListItemComponentAdaptor(
|
||||
itemGenerator: PeerNameColorItem(
|
||||
theme: environment.theme,
|
||||
colors: component.context.peerNameColors,
|
||||
mode: .name,
|
||||
currentColor: resolvedState.nameColor.nameColor,
|
||||
updated: { [weak self] value in
|
||||
guard let self, let value else {
|
||||
guard let self, let resolvedState = self.resolveState(), let value else {
|
||||
return
|
||||
}
|
||||
if case .collectible = resolvedState.nameColor {
|
||||
self.updatedPeerNameEmoji = .some(nil)
|
||||
}
|
||||
self.updatedPeerNameColor = .preset(value)
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
},
|
||||
@@ -1212,8 +1273,9 @@ final class UserAppearanceScreenComponent: Component {
|
||||
),
|
||||
params: listItemParams
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent(
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
style: .glass,
|
||||
title: AnyComponent(HStack(replyLogoContents, spacing: 6.0)),
|
||||
icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent(
|
||||
context: component.context,
|
||||
@@ -1236,14 +1298,14 @@ final class UserAppearanceScreenComponent: Component {
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0)
|
||||
)
|
||||
let replySectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: replySectionSize)
|
||||
if let replySectionView = self.replySection.view {
|
||||
if replySectionView.superview == nil {
|
||||
self.scrollView.addSubview(replySectionView)
|
||||
let nameColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: nameColorSectionSize)
|
||||
if let nameColorSectionView = self.nameColorSection.view {
|
||||
if nameColorSectionView.superview == nil {
|
||||
self.scrollView.addSubview(nameColorSectionView)
|
||||
}
|
||||
sectionTransition.setFrame(view: replySectionView, frame: replySectionFrame)
|
||||
transition.setFrame(view: nameColorSectionView, frame: nameColorSectionFrame)
|
||||
}
|
||||
contentHeight += replySectionSize.height
|
||||
contentHeight += nameColorSectionSize.height
|
||||
contentHeight += sectionSpacing
|
||||
|
||||
if !self.starGifts.isEmpty {
|
||||
@@ -1252,9 +1314,10 @@ final class UserAppearanceScreenComponent: Component {
|
||||
selectedGiftId = collectibleColor.collectibleId
|
||||
}
|
||||
let giftsSectionSize = self.nameGiftsSection.update(
|
||||
transition: sectionTransition,
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
style: .glass,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.NameColor_GiftTitle,
|
||||
@@ -1284,6 +1347,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
}
|
||||
|
||||
self.updatedPeerNameColor = .collectible(peerColor)
|
||||
self.updatedPeerNameEmoji = peerColor.backgroundEmojiId
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
},
|
||||
tag: giftListTag
|
||||
@@ -1300,7 +1364,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
if giftsSectionView.superview == nil {
|
||||
self.scrollView.addSubview(giftsSectionView)
|
||||
}
|
||||
sectionTransition.setFrame(view: giftsSectionView, frame: giftsSectionFrame)
|
||||
transition.setFrame(view: giftsSectionView, frame: giftsSectionFrame)
|
||||
}
|
||||
contentHeight += giftsSectionSize.height
|
||||
contentHeight += sectionSpacing
|
||||
@@ -1309,10 +1373,12 @@ final class UserAppearanceScreenComponent: Component {
|
||||
|
||||
contentHeight += bottomContentInset
|
||||
|
||||
var buttonTitle = environment.strings.Channel_Appearance_ApplyButton
|
||||
if let emojiStatus = resolvedState.emojiStatus, case .starGift = emojiStatus.content, resolvedState.changes.contains(.emojiStatus) {
|
||||
buttonTitle = environment.strings.NameColor_WearCollectible
|
||||
}
|
||||
//TODO:localize
|
||||
let buttonSideInset: CGFloat = 36.0
|
||||
let buttonTitle = "Apply Style" // environment.strings.Channel_Appearance_ApplyButton
|
||||
// if let emojiStatus = resolvedState.emojiStatus, case .starGift = emojiStatus.content, resolvedState.changes.contains(.emojiStatus) {
|
||||
// buttonTitle = environment.strings.NameColor_WearCollectible
|
||||
// }
|
||||
|
||||
var buttonContents: [AnyComponentWithIdentity<Empty>] = []
|
||||
buttonContents.append(AnyComponentWithIdentity(id: AnyHashable(buttonTitle), component: AnyComponent(
|
||||
@@ -1323,6 +1389,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
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)
|
||||
@@ -1341,7 +1408,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0)
|
||||
containerSize: CGSize(width: availableSize.width - buttonSideInset * 2.0, height: 52.0)
|
||||
)
|
||||
contentHeight += buttonSize.height
|
||||
|
||||
@@ -1350,7 +1417,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
|
||||
let buttonY = availableSize.height - bottomInset - environment.safeInsets.bottom - buttonSize.height
|
||||
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: buttonY), size: buttonSize)
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: buttonSideInset, y: buttonY), size: buttonSize)
|
||||
if let buttonView = self.actionButton.view {
|
||||
if buttonView.superview == nil {
|
||||
self.addSubview(buttonView)
|
||||
@@ -1359,26 +1426,24 @@ final class UserAppearanceScreenComponent: Component {
|
||||
transition.setAlpha(view: buttonView, alpha: 1.0)
|
||||
}
|
||||
|
||||
let bottomPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: buttonY - 8.0), size: CGSize(width: availableSize.width, height: availableSize.height - buttonY + 8.0))
|
||||
transition.setFrame(view: self.bottomPanelBackgroundView, frame: bottomPanelFrame)
|
||||
self.bottomPanelBackgroundView.updateColor(color: environment.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
|
||||
self.bottomPanelBackgroundView.update(size: bottomPanelFrame.size, transition: transition.containedViewLayoutTransition)
|
||||
|
||||
self.bottomPanelSeparator.backgroundColor = environment.theme.rootController.navigationBar.separatorColor.cgColor
|
||||
transition.setFrame(layer: self.bottomPanelSeparator, frame: CGRect(origin: CGPoint(x: bottomPanelFrame.minX, y: bottomPanelFrame.minY), size: CGSize(width: bottomPanelFrame.width, height: UIScreenPixel)))
|
||||
let edgeEffectHeight: CGFloat = availableSize.height - buttonY + 8.0
|
||||
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - edgeEffectHeight), size: CGSize(width: availableSize.width, height: edgeEffectHeight))
|
||||
transition.setFrame(view: self.edgeEffectView, frame: edgeEffectFrame)
|
||||
self.edgeEffectView.update(content: environment.theme.list.blocksBackgroundColor, isInverted: false, rect: edgeEffectFrame, edge: .bottom, edgeSize: edgeEffectFrame.height, containerSize: availableSize, transition: transition)
|
||||
|
||||
let previousBounds = self.scrollView.bounds
|
||||
let contentSize = CGSize(width: availableSize.width, height: contentHeight)
|
||||
if self.scrollView.frame != CGRect(origin: CGPoint(), size: availableSize) {
|
||||
self.scrollView.frame = CGRect(origin: CGPoint(), size: availableSize)
|
||||
let scrollViewFrame = CGRect(origin: CGPoint(x: 0.0, y: environment.navigationHeight + 30.0), size: CGSize(width: availableSize.width, height: availableSize.height - environment.navigationHeight - 30.0))
|
||||
if self.scrollView.frame != scrollViewFrame {
|
||||
self.scrollView.frame = scrollViewFrame
|
||||
}
|
||||
if self.scrollView.contentSize != contentSize {
|
||||
self.scrollView.contentSize = contentSize
|
||||
}
|
||||
let scrollInsets = UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: availableSize.height - bottomPanelFrame.minY, right: 0.0)
|
||||
if self.scrollView.verticalScrollIndicatorInsets != scrollInsets {
|
||||
self.scrollView.verticalScrollIndicatorInsets = scrollInsets
|
||||
}
|
||||
// let scrollInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: availableSize.height - bottomPanelFrame.minY, right: 0.0)
|
||||
// if self.scrollView.verticalScrollIndicatorInsets != scrollInsets {
|
||||
// self.scrollView.verticalScrollIndicatorInsets = scrollInsets
|
||||
// }
|
||||
|
||||
if !previousBounds.isEmpty, !transition.animation.isImmediate {
|
||||
let bounds = self.scrollView.bounds
|
||||
@@ -1388,7 +1453,8 @@ final class UserAppearanceScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
self.topOverscrollLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: -3000.0), size: CGSize(width: availableSize.width, height: 3000.0))
|
||||
self.topOverscrollLayer.backgroundColor = environment.theme.list.itemBlocksBackgroundColor.cgColor
|
||||
self.topOverscrollLayer.frame = CGRect(origin: CGPoint(x: sideInset, y: -1000.0), size: CGSize(width: availableSize.width - sideInset * 2.0, height: 1315.0))
|
||||
|
||||
self.updateScrolling(transition: transition)
|
||||
|
||||
@@ -1397,7 +1463,7 @@ final class UserAppearanceScreenComponent: Component {
|
||||
size: availableSize,
|
||||
metrics: environment.metrics,
|
||||
deviceMetrics: environment.deviceMetrics,
|
||||
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomPanelFrame.height, right: 0.0),
|
||||
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: edgeEffectHeight, right: 0.0),
|
||||
safeInsets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right),
|
||||
additionalInsets: .zero,
|
||||
statusBarHeight: environment.statusBarHeight,
|
||||
@@ -1494,3 +1560,79 @@ private extension PeerColor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class TopBottomCornersComponent: Component {
|
||||
private let topCornerRadius: CGFloat
|
||||
private let bottomCornerRadius: CGFloat
|
||||
private let component: AnyComponent<Empty>
|
||||
|
||||
public init(
|
||||
topCornerRadius: CGFloat,
|
||||
bottomCornerRadius: CGFloat,
|
||||
component: AnyComponent<Empty>
|
||||
) {
|
||||
self.topCornerRadius = topCornerRadius
|
||||
self.bottomCornerRadius = bottomCornerRadius
|
||||
self.component = component
|
||||
}
|
||||
|
||||
public static func == (lhs: TopBottomCornersComponent, rhs: TopBottomCornersComponent) -> Bool {
|
||||
if lhs.topCornerRadius != rhs.topCornerRadius {
|
||||
return false
|
||||
}
|
||||
if lhs.bottomCornerRadius != rhs.bottomCornerRadius {
|
||||
return false
|
||||
}
|
||||
if lhs.component != rhs.component {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public final class View: UIView {
|
||||
private let containerView: UIView
|
||||
private let hostView: ComponentHostView<Empty>
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
self.containerView = UIView()
|
||||
self.hostView = ComponentHostView<Empty>()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.containerView.clipsToBounds = true
|
||||
|
||||
self.addSubview(self.containerView)
|
||||
self.containerView.addSubview(self.hostView)
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
func update(component: TopBottomCornersComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
|
||||
let size = self.hostView.update(
|
||||
transition: transition,
|
||||
component: component.component,
|
||||
environment: {},
|
||||
containerSize: availableSize
|
||||
)
|
||||
|
||||
transition.setCornerRadius(layer: self.containerView.layer, cornerRadius: component.topCornerRadius)
|
||||
transition.setCornerRadius(layer: self.layer, cornerRadius: component.bottomCornerRadius)
|
||||
transition.setFrame(view: self.containerView, frame: CGRect(origin: .zero, size: CGSize(width: availableSize.width, height: availableSize.height + component.bottomCornerRadius)))
|
||||
|
||||
return size
|
||||
}
|
||||
}
|
||||
|
||||
public func makeView() -> View {
|
||||
return View()
|
||||
}
|
||||
|
||||
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,6 +590,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
||||
let flipButtonBackground = flipButtonBackground.update(
|
||||
component: GlassBackgroundComponent(
|
||||
size: CGSize(width: 40.0, height: 40.0),
|
||||
isDark: true,
|
||||
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
|
||||
),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
@@ -691,6 +692,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
||||
let flashButtonBackground = flashButtonBackground.update(
|
||||
component: GlassBackgroundComponent(
|
||||
size: CGSize(width: 40.0, height: 40.0),
|
||||
isDark: true,
|
||||
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
|
||||
),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
@@ -764,6 +766,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
||||
id: "background",
|
||||
component: AnyComponent(GlassBackgroundComponent(
|
||||
size: CGSize(width: 40.0, height: 40.0),
|
||||
isDark: true,
|
||||
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
|
||||
))
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user