mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Profile preview
This commit is contained in:
parent
db60f2c82d
commit
baca7c8661
@ -11884,3 +11884,6 @@ Sorry for the inconvenience.";
|
|||||||
"BusinessLink.ErrorExpired" = "Link Expired";
|
"BusinessLink.ErrorExpired" = "Link Expired";
|
||||||
|
|
||||||
"WebApp.AlertBiometryAccessText" = "Do you want to allow %@ to use Face ID?";
|
"WebApp.AlertBiometryAccessText" = "Do you want to allow %@ to use Face ID?";
|
||||||
|
|
||||||
|
"StoryList.SubtitleArchived_1" = "1 archived post";
|
||||||
|
"StoryList.SubtitleArchived_any" = "%d archived posts";
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
@property (nonatomic, assign) bool displayEdges;
|
@property (nonatomic, assign) bool displayEdges;
|
||||||
@property (nonatomic, assign) bool useLinesForPositions;
|
@property (nonatomic, assign) bool useLinesForPositions;
|
||||||
|
@property (nonatomic, assign) bool markPositions;
|
||||||
|
|
||||||
@property (nonatomic, readonly) bool knobStartedDragging;
|
@property (nonatomic, readonly) bool knobStartedDragging;
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f;
|
|||||||
_value = _startValue;
|
_value = _startValue;
|
||||||
_dotSize = 10.5f;
|
_dotSize = 10.5f;
|
||||||
_minimumUndottedValue = -1;
|
_minimumUndottedValue = -1;
|
||||||
|
_markPositions = true;
|
||||||
|
|
||||||
_lineSize = TGPhotoEditorSliderViewLineSize;
|
_lineSize = TGPhotoEditorSliderViewLineSize;
|
||||||
_knobPadding = TGPhotoEditorSliderViewInternalMargin;
|
_knobPadding = TGPhotoEditorSliderViewInternalMargin;
|
||||||
@ -214,6 +215,12 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f;
|
|||||||
{
|
{
|
||||||
for (NSInteger i = 0; i < self.positionsCount; i++)
|
for (NSInteger i = 0; i < self.positionsCount; i++)
|
||||||
{
|
{
|
||||||
|
if (!self.markPositions) {
|
||||||
|
if (i != 0 && i != self.positionsCount - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (self.useLinesForPositions) {
|
if (self.useLinesForPositions) {
|
||||||
CGSize lineSize = CGSizeMake(4.0, 12.0);
|
CGSize lineSize = CGSizeMake(4.0, 12.0);
|
||||||
CGRect lineRect = CGRectMake(margin - lineSize.width / 2.0f + totalLength / (self.positionsCount - 1) * i, (sideLength - lineSize.height) / 2, lineSize.width, lineSize.height);
|
CGRect lineRect = CGRectMake(margin - lineSize.width / 2.0f + totalLength / (self.positionsCount - 1) * i, (sideLength - lineSize.height) / 2, lineSize.width, lineSize.height);
|
||||||
|
@ -73,6 +73,7 @@ public struct PresentationResourcesSettings {
|
|||||||
public static let stories = renderIcon(name: "Settings/Menu/Stories")
|
public static let stories = renderIcon(name: "Settings/Menu/Stories")
|
||||||
public static let premiumGift = renderIcon(name: "Settings/Menu/Gift")
|
public static let premiumGift = renderIcon(name: "Settings/Menu/Gift")
|
||||||
public static let business = renderIcon(name: "Settings/Menu/Business", backgroundColors: [UIColor(rgb: 0xA95CE3), UIColor(rgb: 0xF16B80)])
|
public static let business = renderIcon(name: "Settings/Menu/Business", backgroundColors: [UIColor(rgb: 0xA95CE3), UIColor(rgb: 0xF16B80)])
|
||||||
|
public static let myProfile = renderIcon(name: "Settings/Menu/Profile")
|
||||||
|
|
||||||
public static let premium = generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
|
public static let premium = generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
|
||||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
|
@ -15,6 +15,7 @@ public final class EmptyStateIndicatorComponent: Component {
|
|||||||
public let title: String
|
public let title: String
|
||||||
public let text: String
|
public let text: String
|
||||||
public let actionTitle: String?
|
public let actionTitle: String?
|
||||||
|
public let fitToHeight: Bool
|
||||||
public let action: () -> Void
|
public let action: () -> Void
|
||||||
public let additionalActionTitle: String?
|
public let additionalActionTitle: String?
|
||||||
public let additionalAction: () -> Void
|
public let additionalAction: () -> Void
|
||||||
@ -22,6 +23,7 @@ public final class EmptyStateIndicatorComponent: Component {
|
|||||||
public init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
|
fitToHeight: Bool,
|
||||||
animationName: String,
|
animationName: String,
|
||||||
title: String,
|
title: String,
|
||||||
text: String,
|
text: String,
|
||||||
@ -32,6 +34,7 @@ public final class EmptyStateIndicatorComponent: Component {
|
|||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
self.fitToHeight = fitToHeight
|
||||||
self.animationName = animationName
|
self.animationName = animationName
|
||||||
self.title = title
|
self.title = title
|
||||||
self.text = text
|
self.text = text
|
||||||
@ -48,6 +51,9 @@ public final class EmptyStateIndicatorComponent: Component {
|
|||||||
if lhs.theme !== rhs.theme {
|
if lhs.theme !== rhs.theme {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.fitToHeight != rhs.fitToHeight {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.animationName != rhs.animationName {
|
if lhs.animationName != rhs.animationName {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -205,7 +211,12 @@ public final class EmptyStateIndicatorComponent: Component {
|
|||||||
totalHeight += buttonSpacing + additionalButtonSize.height
|
totalHeight += buttonSpacing + additionalButtonSize.height
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentY = floor((availableSize.height - totalHeight) * 0.5)
|
var contentY: CGFloat
|
||||||
|
if component.fitToHeight {
|
||||||
|
contentY = 0.0
|
||||||
|
} else {
|
||||||
|
contentY = floor((availableSize.height - totalHeight) * 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
if let animationView = self.animation.view {
|
if let animationView = self.animation.view {
|
||||||
if animationView.superview == nil {
|
if animationView.superview == nil {
|
||||||
@ -243,9 +254,13 @@ public final class EmptyStateIndicatorComponent: Component {
|
|||||||
contentY += additionalButtonSize.height
|
contentY += additionalButtonSize.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if component.fitToHeight {
|
||||||
|
return CGSize(width: availableSize.width, height: totalHeight)
|
||||||
|
} else {
|
||||||
return availableSize
|
return availableSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func makeView() -> View {
|
public func makeView() -> View {
|
||||||
return View(frame: CGRect())
|
return View(frame: CGRect())
|
||||||
|
@ -11,18 +11,24 @@ import SliderComponent
|
|||||||
public final class ListItemSliderSelectorComponent: Component {
|
public final class ListItemSliderSelectorComponent: Component {
|
||||||
public let theme: PresentationTheme
|
public let theme: PresentationTheme
|
||||||
public let values: [String]
|
public let values: [String]
|
||||||
|
public let markPositions: Bool
|
||||||
public let selectedIndex: Int
|
public let selectedIndex: Int
|
||||||
|
public let title: String?
|
||||||
public let selectedIndexUpdated: (Int) -> Void
|
public let selectedIndexUpdated: (Int) -> Void
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
values: [String],
|
values: [String],
|
||||||
|
markPositions: Bool,
|
||||||
selectedIndex: Int,
|
selectedIndex: Int,
|
||||||
|
title: String?,
|
||||||
selectedIndexUpdated: @escaping (Int) -> Void
|
selectedIndexUpdated: @escaping (Int) -> Void
|
||||||
) {
|
) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.values = values
|
self.values = values
|
||||||
|
self.markPositions = markPositions
|
||||||
self.selectedIndex = selectedIndex
|
self.selectedIndex = selectedIndex
|
||||||
|
self.title = title
|
||||||
self.selectedIndexUpdated = selectedIndexUpdated
|
self.selectedIndexUpdated = selectedIndexUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,14 +39,21 @@ public final class ListItemSliderSelectorComponent: Component {
|
|||||||
if lhs.values != rhs.values {
|
if lhs.values != rhs.values {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.markPositions != rhs.markPositions {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.selectedIndex != rhs.selectedIndex {
|
if lhs.selectedIndex != rhs.selectedIndex {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.title != rhs.title {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class View: UIView, ListSectionComponent.ChildView {
|
public final class View: UIView, ListSectionComponent.ChildView {
|
||||||
private var titles: [ComponentView<Empty>] = []
|
private var titles: [Int: ComponentView<Empty>] = [:]
|
||||||
|
private var mainTitle: ComponentView<Empty>?
|
||||||
private var slider = ComponentView<Empty>()
|
private var slider = ComponentView<Empty>()
|
||||||
|
|
||||||
private var component: ListItemSliderSelectorComponent?
|
private var component: ListItemSliderSelectorComponent?
|
||||||
@ -67,15 +80,24 @@ public final class ListItemSliderSelectorComponent: Component {
|
|||||||
|
|
||||||
let titleAreaWidth: CGFloat = availableSize.width - titleSideInset * 2.0
|
let titleAreaWidth: CGFloat = availableSize.width - titleSideInset * 2.0
|
||||||
|
|
||||||
|
var validIds: [Int] = []
|
||||||
for i in 0 ..< component.values.count {
|
for i in 0 ..< component.values.count {
|
||||||
|
if component.title != nil {
|
||||||
|
if i != 0 && i != component.values.count - 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validIds.append(i)
|
||||||
|
|
||||||
var titleTransition = transition
|
var titleTransition = transition
|
||||||
let title: ComponentView<Empty>
|
let title: ComponentView<Empty>
|
||||||
if self.titles.count > i {
|
if let current = self.titles[i] {
|
||||||
title = self.titles[i]
|
title = current
|
||||||
} else {
|
} else {
|
||||||
titleTransition = titleTransition.withAnimation(.none)
|
titleTransition = titleTransition.withAnimation(.none)
|
||||||
title = ComponentView()
|
title = ComponentView()
|
||||||
self.titles.append(title)
|
self.titles[i] = title
|
||||||
}
|
}
|
||||||
let titleSize = title.update(
|
let titleSize = title.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
@ -103,11 +125,48 @@ public final class ListItemSliderSelectorComponent: Component {
|
|||||||
titleTransition.setPosition(view: titleView, position: titleFrame.center)
|
titleTransition.setPosition(view: titleView, position: titleFrame.center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.titles.count > component.values.count {
|
var removeIds: [Int] = []
|
||||||
for i in component.values.count ..< self.titles.count {
|
for (id, title) in self.titles {
|
||||||
self.titles[i].view?.removeFromSuperview()
|
if !validIds.contains(id) {
|
||||||
|
removeIds.append(id)
|
||||||
|
title.view?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id in removeIds {
|
||||||
|
self.titles.removeValue(forKey: id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let title = component.title {
|
||||||
|
let mainTitle: ComponentView<Empty>
|
||||||
|
var mainTitleTransition = transition
|
||||||
|
if let current = self.mainTitle {
|
||||||
|
mainTitle = current
|
||||||
|
} else {
|
||||||
|
mainTitleTransition = mainTitleTransition.withAnimation(.none)
|
||||||
|
mainTitle = ComponentView()
|
||||||
|
self.mainTitle = mainTitle
|
||||||
|
}
|
||||||
|
let mainTitleSize = mainTitle.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(string: title, font: Font.regular(16.0), textColor: component.theme.list.itemPrimaryTextColor))
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||||
|
)
|
||||||
|
let mainTitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - mainTitleSize.width) * 0.5), y: 10.0), size: mainTitleSize)
|
||||||
|
if let mainTitleView = mainTitle.view {
|
||||||
|
if mainTitleView.superview == nil {
|
||||||
|
self.addSubview(mainTitleView)
|
||||||
|
}
|
||||||
|
mainTitleView.bounds = CGRect(origin: CGPoint(), size: mainTitleFrame.size)
|
||||||
|
mainTitleTransition.setPosition(view: mainTitleView, position: mainTitleFrame.center)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let mainTitle = self.mainTitle {
|
||||||
|
self.mainTitle = nil
|
||||||
|
mainTitle.view?.removeFromSuperview()
|
||||||
}
|
}
|
||||||
self.titles.removeLast(self.titles.count - component.values.count)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sliderSize = self.slider.update(
|
let sliderSize = self.slider.update(
|
||||||
@ -115,6 +174,7 @@ public final class ListItemSliderSelectorComponent: Component {
|
|||||||
component: AnyComponent(SliderComponent(
|
component: AnyComponent(SliderComponent(
|
||||||
valueCount: component.values.count,
|
valueCount: component.values.count,
|
||||||
value: component.selectedIndex,
|
value: component.selectedIndex,
|
||||||
|
markPositions: component.markPositions,
|
||||||
trackBackgroundColor: component.theme.list.controlSecondaryColor,
|
trackBackgroundColor: component.theme.list.controlSecondaryColor,
|
||||||
trackForegroundColor: component.theme.list.itemAccentColor,
|
trackForegroundColor: component.theme.list.itemAccentColor,
|
||||||
valueUpdated: { [weak self] value in
|
valueUpdated: { [weak self] value in
|
||||||
|
@ -33,6 +33,8 @@ swift_library(
|
|||||||
"//submodules/UndoUI",
|
"//submodules/UndoUI",
|
||||||
"//submodules/TextFormat",
|
"//submodules/TextFormat",
|
||||||
"//submodules/Components/HierarchyTrackingLayer",
|
"//submodules/Components/HierarchyTrackingLayer",
|
||||||
|
"//submodules/TelegramUI/Components/ListSectionComponent",
|
||||||
|
"//submodules/TelegramUI/Components/ListItemSliderSelectorComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -21,6 +21,8 @@ import AnimatedTextComponent
|
|||||||
import TextFormat
|
import TextFormat
|
||||||
import AudioToolbox
|
import AudioToolbox
|
||||||
import PremiumLockButtonSubtitleComponent
|
import PremiumLockButtonSubtitleComponent
|
||||||
|
import ListSectionComponent
|
||||||
|
import ListItemSliderSelectorComponent
|
||||||
|
|
||||||
final class PeerAllowedReactionsScreenComponent: Component {
|
final class PeerAllowedReactionsScreenComponent: Component {
|
||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
@ -57,6 +59,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
|||||||
private var reactionsTitleText: ComponentView<Empty>?
|
private var reactionsTitleText: ComponentView<Empty>?
|
||||||
private var reactionsInfoText: ComponentView<Empty>?
|
private var reactionsInfoText: ComponentView<Empty>?
|
||||||
private var reactionInput: ComponentView<Empty>?
|
private var reactionInput: ComponentView<Empty>?
|
||||||
|
private var reactionCountSection: ComponentView<Empty>?
|
||||||
private let actionButton = ComponentView<Empty>()
|
private let actionButton = ComponentView<Empty>()
|
||||||
|
|
||||||
private var reactionSelectionControl: ComponentView<Empty>?
|
private var reactionSelectionControl: ComponentView<Empty>?
|
||||||
@ -82,6 +85,8 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
|||||||
private var displayInput: Bool = false
|
private var displayInput: Bool = false
|
||||||
private var recenterOnCaret: Bool = false
|
private var recenterOnCaret: Bool = false
|
||||||
|
|
||||||
|
private var allowedReactionCount: Int = 11
|
||||||
|
|
||||||
private var isApplyingSettings: Bool = false
|
private var isApplyingSettings: Bool = false
|
||||||
private var applyDisposable: Disposable?
|
private var applyDisposable: Disposable?
|
||||||
|
|
||||||
@ -775,6 +780,86 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
contentHeight += reactionsInfoTextSize.height
|
contentHeight += reactionsInfoTextSize.height
|
||||||
contentHeight += 6.0
|
contentHeight += 6.0
|
||||||
|
|
||||||
|
contentHeight += 32.0
|
||||||
|
|
||||||
|
let reactionCountSection: ComponentView<Empty>
|
||||||
|
if let current = self.reactionCountSection {
|
||||||
|
reactionCountSection = current
|
||||||
|
} else {
|
||||||
|
reactionCountSection = ComponentView()
|
||||||
|
self.reactionCountSection = reactionCountSection
|
||||||
|
}
|
||||||
|
|
||||||
|
let reactionCountValueList = (1 ... 11).map { i -> String in
|
||||||
|
return "\(i)"
|
||||||
|
}
|
||||||
|
//TODO:localize
|
||||||
|
let sliderTitle: String
|
||||||
|
if self.allowedReactionCount == 1 {
|
||||||
|
sliderTitle = "1 reaction"
|
||||||
|
} else {
|
||||||
|
sliderTitle = "\(self.allowedReactionCount) reactions"
|
||||||
|
}
|
||||||
|
let reactionCountSectionSize = reactionCountSection.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(ListSectionComponent(
|
||||||
|
theme: environment.theme,
|
||||||
|
header: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: "MAXIMUM REACTIONS PER POST",
|
||||||
|
font: Font.regular(13.0),
|
||||||
|
textColor: environment.theme.list.freeTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)),
|
||||||
|
footer: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: "Limit the number of different reactions that can be added to a post, including already published posts.",
|
||||||
|
font: Font.regular(13.0),
|
||||||
|
textColor: environment.theme.list.freeTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)),
|
||||||
|
items: [
|
||||||
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemSliderSelectorComponent(
|
||||||
|
theme: environment.theme,
|
||||||
|
values: reactionCountValueList.map { item in
|
||||||
|
return item
|
||||||
|
},
|
||||||
|
markPositions: false,
|
||||||
|
selectedIndex: max(0, min(reactionCountValueList.count - 1, self.allowedReactionCount - 1)),
|
||||||
|
title: sliderTitle,
|
||||||
|
selectedIndexUpdated: { [weak self] index in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let index = max(1, min(reactionCountValueList.count, index + 1))
|
||||||
|
self.allowedReactionCount = index
|
||||||
|
self.state?.updated(transition: .immediate)
|
||||||
|
}
|
||||||
|
)))
|
||||||
|
],
|
||||||
|
displaySeparators: false
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||||
|
)
|
||||||
|
let reactionCountSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: reactionCountSectionSize)
|
||||||
|
if let reactionCountSectionView = reactionCountSection.view {
|
||||||
|
if reactionCountSectionView.superview == nil {
|
||||||
|
self.scrollView.addSubview(reactionCountSectionView)
|
||||||
|
}
|
||||||
|
if animateIn {
|
||||||
|
reactionCountSectionView.frame = reactionCountSectionFrame
|
||||||
|
if !transition.animation.isImmediate {
|
||||||
|
reactionCountSectionView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transition.setFrame(view: reactionCountSectionView, frame: reactionCountSectionFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentHeight += reactionCountSectionSize.height
|
||||||
} else {
|
} else {
|
||||||
if let reactionsTitleText = self.reactionsTitleText {
|
if let reactionsTitleText = self.reactionsTitleText {
|
||||||
self.reactionsTitleText = nil
|
self.reactionsTitleText = nil
|
||||||
@ -814,6 +899,19 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let reactionCountSection = self.reactionCountSection {
|
||||||
|
self.reactionCountSection = nil
|
||||||
|
if let reactionCountSectionView = reactionCountSection.view {
|
||||||
|
if !transition.animation.isImmediate {
|
||||||
|
reactionCountSectionView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak reactionCountSectionView] _ in
|
||||||
|
reactionCountSectionView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reactionCountSectionView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var buttonContents: [AnyComponentWithIdentity<Empty>] = []
|
var buttonContents: [AnyComponentWithIdentity<Empty>] = []
|
||||||
|
@ -8,6 +8,7 @@ import TelegramPresentationData
|
|||||||
public enum PeerInfoPaneKey: Int32 {
|
public enum PeerInfoPaneKey: Int32 {
|
||||||
case members
|
case members
|
||||||
case stories
|
case stories
|
||||||
|
case storyArchive
|
||||||
case media
|
case media
|
||||||
case savedMessagesChats
|
case savedMessagesChats
|
||||||
case savedMessages
|
case savedMessages
|
||||||
|
@ -305,6 +305,7 @@ final class PeerInfoScreenData {
|
|||||||
let linkedDiscussionPeer: Peer?
|
let linkedDiscussionPeer: Peer?
|
||||||
let members: PeerInfoMembersData?
|
let members: PeerInfoMembersData?
|
||||||
let storyListContext: PeerStoryListContext?
|
let storyListContext: PeerStoryListContext?
|
||||||
|
let storyArchiveListContext: PeerStoryListContext?
|
||||||
let encryptionKeyFingerprint: SecretChatKeyFingerprint?
|
let encryptionKeyFingerprint: SecretChatKeyFingerprint?
|
||||||
let globalSettings: TelegramGlobalSettings?
|
let globalSettings: TelegramGlobalSettings?
|
||||||
let invitations: PeerExportedInvitationsState?
|
let invitations: PeerExportedInvitationsState?
|
||||||
@ -344,6 +345,7 @@ final class PeerInfoScreenData {
|
|||||||
linkedDiscussionPeer: Peer?,
|
linkedDiscussionPeer: Peer?,
|
||||||
members: PeerInfoMembersData?,
|
members: PeerInfoMembersData?,
|
||||||
storyListContext: PeerStoryListContext?,
|
storyListContext: PeerStoryListContext?,
|
||||||
|
storyArchiveListContext: PeerStoryListContext?,
|
||||||
encryptionKeyFingerprint: SecretChatKeyFingerprint?,
|
encryptionKeyFingerprint: SecretChatKeyFingerprint?,
|
||||||
globalSettings: TelegramGlobalSettings?,
|
globalSettings: TelegramGlobalSettings?,
|
||||||
invitations: PeerExportedInvitationsState?,
|
invitations: PeerExportedInvitationsState?,
|
||||||
@ -371,6 +373,7 @@ final class PeerInfoScreenData {
|
|||||||
self.linkedDiscussionPeer = linkedDiscussionPeer
|
self.linkedDiscussionPeer = linkedDiscussionPeer
|
||||||
self.members = members
|
self.members = members
|
||||||
self.storyListContext = storyListContext
|
self.storyListContext = storyListContext
|
||||||
|
self.storyArchiveListContext = storyArchiveListContext
|
||||||
self.encryptionKeyFingerprint = encryptionKeyFingerprint
|
self.encryptionKeyFingerprint = encryptionKeyFingerprint
|
||||||
self.globalSettings = globalSettings
|
self.globalSettings = globalSettings
|
||||||
self.invitations = invitations
|
self.invitations = invitations
|
||||||
@ -403,7 +406,7 @@ private enum PeerInfoScreenInputData: Equatable {
|
|||||||
|
|
||||||
public func hasAvailablePeerInfoMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<Bool, NoError> {
|
public func hasAvailablePeerInfoMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<Bool, NoError> {
|
||||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||||
let mediaPanes = peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: .peer(id: peerId), chatLocationContextHolder: chatLocationContextHolder)
|
let mediaPanes = peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: .peer(id: peerId), isMyProfile: false, chatLocationContextHolder: chatLocationContextHolder)
|
||||||
|> map { panes -> Bool in
|
|> map { panes -> Bool in
|
||||||
if let panes {
|
if let panes {
|
||||||
return !panes.isEmpty
|
return !panes.isEmpty
|
||||||
@ -426,8 +429,11 @@ public func hasAvailablePeerInfoMediaPanes(context: AccountContext, peerId: Peer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<[PeerInfoPaneKey]?, NoError> {
|
private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, isMyProfile: Bool, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<[PeerInfoPaneKey]?, NoError> {
|
||||||
let tags: [(MessageTags, PeerInfoPaneKey)] = [
|
var tags: [(MessageTags, PeerInfoPaneKey)] = []
|
||||||
|
|
||||||
|
if !isMyProfile {
|
||||||
|
tags = [
|
||||||
(.photoOrVideo, .media),
|
(.photoOrVideo, .media),
|
||||||
(.file, .files),
|
(.file, .files),
|
||||||
(.music, .music),
|
(.music, .music),
|
||||||
@ -435,6 +441,7 @@ private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId
|
|||||||
(.webPage, .links),
|
(.webPage, .links),
|
||||||
(.gif, .gifs)
|
(.gif, .gifs)
|
||||||
]
|
]
|
||||||
|
}
|
||||||
enum PaneState {
|
enum PaneState {
|
||||||
case loading
|
case loading
|
||||||
case empty
|
case empty
|
||||||
@ -545,7 +552,7 @@ public func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId, c
|
|||||||
case .user, .channel, .group:
|
case .user, .channel, .group:
|
||||||
var signals: [Signal<Never, NoError>] = []
|
var signals: [Signal<Never, NoError>] = []
|
||||||
|
|
||||||
signals.append(context.peerChannelMemberCategoriesContextsManager.profileData(postbox: context.account.postbox, network: context.account.network, peerId: peerId, customData: peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder) |> ignoreValues) |> ignoreValues)
|
signals.append(context.peerChannelMemberCategoriesContextsManager.profileData(postbox: context.account.postbox, network: context.account.network, peerId: peerId, customData: peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, isMyProfile: false, chatLocationContextHolder: chatLocationContextHolder) |> ignoreValues) |> ignoreValues)
|
||||||
signals.append(context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: context.account.postbox, network: context.account.network, peerId: peerId, fetch: peerInfoProfilePhotos(context: context, peerId: peerId)) |> ignoreValues)
|
signals.append(context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: context.account.postbox, network: context.account.network, peerId: peerId, fetch: peerInfoProfilePhotos(context: context, peerId: peerId)) |> ignoreValues)
|
||||||
|
|
||||||
if case .user = inputData {
|
if case .user = inputData {
|
||||||
@ -843,6 +850,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
linkedDiscussionPeer: nil,
|
linkedDiscussionPeer: nil,
|
||||||
members: nil,
|
members: nil,
|
||||||
storyListContext: hasStories == true ? storyListContext : nil,
|
storyListContext: hasStories == true ? storyListContext : nil,
|
||||||
|
storyArchiveListContext: nil,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: globalSettings,
|
globalSettings: globalSettings,
|
||||||
invitations: nil,
|
invitations: nil,
|
||||||
@ -859,7 +867,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, isSettings: Bool, hintGroupInCommon: PeerId?, existingRequestsContext: PeerInvitationImportersContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<PeerInfoScreenData, NoError> {
|
func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, existingRequestsContext: PeerInvitationImportersContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<PeerInfoScreenData, NoError> {
|
||||||
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: isSettings)
|
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: isSettings)
|
||||||
|> mapToSignal { inputData -> Signal<PeerInfoScreenData, NoError> in
|
|> mapToSignal { inputData -> Signal<PeerInfoScreenData, NoError> in
|
||||||
let wasUpgradedGroup = Atomic<Bool?>(value: nil)
|
let wasUpgradedGroup = Atomic<Bool?>(value: nil)
|
||||||
@ -881,6 +889,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: nil,
|
linkedDiscussionPeer: nil,
|
||||||
members: nil,
|
members: nil,
|
||||||
storyListContext: nil,
|
storyListContext: nil,
|
||||||
|
storyArchiveListContext: nil,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: nil,
|
invitations: nil,
|
||||||
@ -896,7 +905,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
))
|
))
|
||||||
case let .user(userPeerId, secretChatId, kind):
|
case let .user(userPeerId, secretChatId, kind):
|
||||||
let groupsInCommon: GroupsInCommonContext?
|
let groupsInCommon: GroupsInCommonContext?
|
||||||
if [.user, .bot].contains(kind) {
|
if isMyProfile {
|
||||||
|
groupsInCommon = nil
|
||||||
|
} else if [.user, .bot].contains(kind) {
|
||||||
groupsInCommon = GroupsInCommonContext(account: context.account, peerId: userPeerId, hintGroupInCommon: hintGroupInCommon)
|
groupsInCommon = GroupsInCommonContext(account: context.account, peerId: userPeerId, hintGroupInCommon: hintGroupInCommon)
|
||||||
} else {
|
} else {
|
||||||
groupsInCommon = nil
|
groupsInCommon = nil
|
||||||
@ -1008,6 +1019,23 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|
|
||||||
|
let hasStoryArchive: Signal<Bool?, NoError>
|
||||||
|
var storyArchiveListContext: PeerStoryListContext?
|
||||||
|
if isMyProfile {
|
||||||
|
let storyArchiveListContextValue = PeerStoryListContext(account: context.account, peerId: peerId, isArchived: true)
|
||||||
|
storyArchiveListContext = storyArchiveListContextValue
|
||||||
|
hasStoryArchive = storyArchiveListContextValue.state
|
||||||
|
|> map { state -> Bool? in
|
||||||
|
if !state.hasCache {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return !state.items.isEmpty
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
} else {
|
||||||
|
hasStoryArchive = .single(false)
|
||||||
|
}
|
||||||
|
|
||||||
let accountIsPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
let accountIsPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||||
|> map { peer -> Bool in
|
|> map { peer -> Bool in
|
||||||
return peer?.isPremium ?? false
|
return peer?.isPremium ?? false
|
||||||
@ -1092,11 +1120,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, isMyProfile: isMyProfile, chatLocationContextHolder: chatLocationContextHolder),
|
||||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||||
secretChatKeyFingerprint,
|
secretChatKeyFingerprint,
|
||||||
status,
|
status,
|
||||||
hasStories,
|
hasStories,
|
||||||
|
hasStoryArchive,
|
||||||
accountIsPremium,
|
accountIsPremium,
|
||||||
savedMessagesPeer,
|
savedMessagesPeer,
|
||||||
hasSavedMessagesChats,
|
hasSavedMessagesChats,
|
||||||
@ -1104,10 +1133,15 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
hasSavedMessageTags,
|
hasSavedMessageTags,
|
||||||
peerInfoPersonalChannel(context: context, peerId: peerId, isSettings: false)
|
peerInfoPersonalChannel(context: context, peerId: peerId, isSettings: false)
|
||||||
)
|
)
|
||||||
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, accountIsPremium, savedMessagesPeer, hasSavedMessagesChats, hasSavedMessages, hasSavedMessageTags, personalChannel -> PeerInfoScreenData in
|
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, hasStoryArchive, accountIsPremium, savedMessagesPeer, hasSavedMessagesChats, hasSavedMessages, hasSavedMessageTags, personalChannel -> PeerInfoScreenData in
|
||||||
var availablePanes = availablePanes
|
var availablePanes = availablePanes
|
||||||
|
|
||||||
if let hasStories {
|
if isMyProfile {
|
||||||
|
availablePanes?.insert(.stories, at: 0)
|
||||||
|
if let hasStoryArchive, hasStoryArchive {
|
||||||
|
availablePanes?.insert(.storyArchive, at: 1)
|
||||||
|
}
|
||||||
|
} else if let hasStories {
|
||||||
if hasStories, peerView.peers[peerView.peerId] is TelegramUser, peerView.peerId != context.account.peerId {
|
if hasStories, peerView.peers[peerView.peerId] is TelegramUser, peerView.peerId != context.account.peerId {
|
||||||
availablePanes?.insert(.stories, at: 0)
|
availablePanes?.insert(.stories, at: 0)
|
||||||
}
|
}
|
||||||
@ -1155,6 +1189,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: nil,
|
linkedDiscussionPeer: nil,
|
||||||
members: nil,
|
members: nil,
|
||||||
storyListContext: storyListContext,
|
storyListContext: storyListContext,
|
||||||
|
storyArchiveListContext: storyArchiveListContext,
|
||||||
encryptionKeyFingerprint: encryptionKeyFingerprint,
|
encryptionKeyFingerprint: encryptionKeyFingerprint,
|
||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: nil,
|
invitations: nil,
|
||||||
@ -1244,7 +1279,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, isMyProfile: false, chatLocationContextHolder: chatLocationContextHolder),
|
||||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||||
status,
|
status,
|
||||||
invitationsContextPromise.get(),
|
invitationsContextPromise.get(),
|
||||||
@ -1325,6 +1360,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: discussionPeer,
|
linkedDiscussionPeer: discussionPeer,
|
||||||
members: nil,
|
members: nil,
|
||||||
storyListContext: storyListContext,
|
storyListContext: storyListContext,
|
||||||
|
storyArchiveListContext: nil,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: invitations,
|
invitations: invitations,
|
||||||
@ -1517,7 +1553,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
|
|
||||||
return combineLatest(queue: .mainQueue(),
|
return combineLatest(queue: .mainQueue(),
|
||||||
context.account.viewTracker.peerView(groupId, updateData: true),
|
context.account.viewTracker.peerView(groupId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: groupId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
peerInfoAvailableMediaPanes(context: context, peerId: groupId, chatLocation: chatLocation, isMyProfile: false, chatLocationContextHolder: chatLocationContextHolder),
|
||||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||||
status,
|
status,
|
||||||
membersData,
|
membersData,
|
||||||
@ -1618,6 +1654,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: discussionPeer,
|
linkedDiscussionPeer: discussionPeer,
|
||||||
members: membersData,
|
members: membersData,
|
||||||
storyListContext: storyListContext,
|
storyListContext: storyListContext,
|
||||||
|
storyArchiveListContext: nil,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: invitations,
|
invitations: invitations,
|
||||||
|
@ -88,6 +88,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
private let isOpenedFromChat: Bool
|
private let isOpenedFromChat: Bool
|
||||||
private let isSettings: Bool
|
private let isSettings: Bool
|
||||||
|
private let isMyProfile: Bool
|
||||||
private let videoCallsEnabled: Bool
|
private let videoCallsEnabled: Bool
|
||||||
private let forumTopicThreadId: Int64?
|
private let forumTopicThreadId: Int64?
|
||||||
private let chatLocation: ChatLocation
|
private let chatLocation: ChatLocation
|
||||||
@ -179,12 +180,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var validLayout: (width: CGFloat, deviceMetrics: DeviceMetrics)?
|
private var validLayout: (width: CGFloat, deviceMetrics: DeviceMetrics)?
|
||||||
|
|
||||||
init(context: AccountContext, controller: PeerInfoScreenImpl, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isMediaOnly: Bool, isSettings: Bool, forumTopicThreadId: Int64?, chatLocation: ChatLocation) {
|
init(context: AccountContext, controller: PeerInfoScreenImpl, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isMediaOnly: Bool, isSettings: Bool, isMyProfile: Bool, forumTopicThreadId: Int64?, chatLocation: ChatLocation) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.isAvatarExpanded = avatarInitiallyExpanded
|
self.isAvatarExpanded = avatarInitiallyExpanded
|
||||||
self.isOpenedFromChat = isOpenedFromChat
|
self.isOpenedFromChat = isOpenedFromChat
|
||||||
self.isSettings = isSettings
|
self.isSettings = isSettings
|
||||||
|
self.isMyProfile = isMyProfile
|
||||||
self.videoCallsEnabled = true
|
self.videoCallsEnabled = true
|
||||||
self.forumTopicThreadId = forumTopicThreadId
|
self.forumTopicThreadId = forumTopicThreadId
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
@ -522,7 +524,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
let credibilityIcon: CredibilityIcon
|
let credibilityIcon: CredibilityIcon
|
||||||
var verifiedIcon: CredibilityIcon = .none
|
var verifiedIcon: CredibilityIcon = .none
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
if peer.id == self.context.account.peerId && !self.isSettings {
|
if peer.id == self.context.account.peerId && !self.isSettings && !self.isMyProfile {
|
||||||
credibilityIcon = .none
|
credibilityIcon = .none
|
||||||
} else if peer.isFake {
|
} else if peer.isFake {
|
||||||
credibilityIcon = .fake
|
credibilityIcon = .fake
|
||||||
@ -535,7 +537,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
credibilityIcon = .emojiStatus(emojiStatus)
|
credibilityIcon = .emojiStatus(emojiStatus)
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
credibilityIcon = .verified
|
credibilityIcon = .verified
|
||||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled && (peer.id != self.context.account.peerId || self.isSettings) {
|
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled && (peer.id != self.context.account.peerId || self.isSettings || self.isMyProfile) {
|
||||||
credibilityIcon = .premium
|
credibilityIcon = .premium
|
||||||
} else {
|
} else {
|
||||||
credibilityIcon = .none
|
credibilityIcon = .none
|
||||||
@ -554,7 +556,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0
|
self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0
|
||||||
|
|
||||||
let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, isModalOverlay: isModalOverlay, peer: state.isEditing ? peer : nil, threadData: threadData, chatLocation: self.chatLocation, cachedData: cachedData, isContact: isContact, isSettings: isSettings, presentationData: presentationData, transition: transition)
|
let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, isModalOverlay: isModalOverlay, peer: state.isEditing ? peer : nil, threadData: threadData, chatLocation: self.chatLocation, cachedData: cachedData, isContact: isContact, isSettings: isSettings || isMyProfile, presentationData: presentationData, transition: transition)
|
||||||
transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight)))
|
transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight)))
|
||||||
|
|
||||||
let avatarOverlayFarme = self.editingContentNode.convert(self.editingContentNode.avatarNode.frame, to: self)
|
let avatarOverlayFarme = self.editingContentNode.convert(self.editingContentNode.avatarNode.frame, to: self)
|
||||||
@ -694,7 +696,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
let backgroundTransitionStepDistance: CGFloat = 50.0
|
let backgroundTransitionStepDistance: CGFloat = 50.0
|
||||||
var backgroundTransitionDistance: CGFloat = navigationHeight + panelWithAvatarHeight - backgroundTransitionStepDistance
|
var backgroundTransitionDistance: CGFloat = navigationHeight + panelWithAvatarHeight - backgroundTransitionStepDistance
|
||||||
if self.isSettings {
|
if self.isSettings || self.isMyProfile {
|
||||||
backgroundTransitionDistance -= 100.0
|
backgroundTransitionDistance -= 100.0
|
||||||
}
|
}
|
||||||
if isMediaOnly {
|
if isMediaOnly {
|
||||||
@ -978,15 +980,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
self.navigationBackgroundBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor
|
self.navigationBackgroundBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor
|
||||||
self.navigationSeparatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor
|
self.navigationSeparatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor
|
||||||
|
|
||||||
let navigationSeparatorAlpha: CGFloat
|
let navigationSeparatorAlpha: CGFloat = 0.0
|
||||||
if isMediaOnly {
|
|
||||||
navigationSeparatorAlpha = 0.0
|
|
||||||
} else if state.isEditing && self.isSettings {
|
|
||||||
//navigationSeparatorAlpha = min(1.0, contentOffset / (navigationHeight * 0.5))
|
|
||||||
navigationSeparatorAlpha = 0.0
|
|
||||||
} else {
|
|
||||||
navigationSeparatorAlpha = 0.0
|
|
||||||
}
|
|
||||||
transition.updateAlpha(node: self.navigationBackgroundBackgroundNode, alpha: 1.0 - navigationSeparatorAlpha)
|
transition.updateAlpha(node: self.navigationBackgroundBackgroundNode, alpha: 1.0 - navigationSeparatorAlpha)
|
||||||
transition.updateAlpha(node: self.navigationSeparatorNode, alpha: navigationSeparatorAlpha)
|
transition.updateAlpha(node: self.navigationSeparatorNode, alpha: navigationSeparatorAlpha)
|
||||||
|
|
||||||
@ -994,7 +988,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
let expandedAvatarControlsHeight: CGFloat = 61.0
|
let expandedAvatarControlsHeight: CGFloat = 61.0
|
||||||
var expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
var expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
||||||
if self.isSettings {
|
if self.isSettings || self.isMyProfile {
|
||||||
expandedAvatarListHeight = expandedAvatarListHeight + 60.0
|
expandedAvatarListHeight = expandedAvatarListHeight + 60.0
|
||||||
} else {
|
} else {
|
||||||
expandedAvatarListHeight = expandedAvatarListHeight + 98.0
|
expandedAvatarListHeight = expandedAvatarListHeight + 98.0
|
||||||
@ -1002,8 +996,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
|
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
|
||||||
|
|
||||||
let actionButtonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderActionButtons(peer: peer, isSecretChat: isSecretChat, isContact: isContact)
|
let actionButtonKeys: [PeerInfoHeaderButtonKey] = (self.isSettings || self.isMyProfile) ? [] : peerInfoHeaderActionButtons(peer: peer, isSecretChat: isSecretChat, isContact: isContact)
|
||||||
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadData?.info)
|
let buttonKeys: [PeerInfoHeaderButtonKey] = (self.isSettings || self.isMyProfile) ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadData?.info)
|
||||||
|
|
||||||
var isPremium = false
|
var isPremium = false
|
||||||
var isVerified = false
|
var isVerified = false
|
||||||
@ -1029,7 +1023,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
var title: String
|
var title: String
|
||||||
if peer.id == self.context.account.peerId && !self.isSettings {
|
if peer.id == self.context.account.peerId && !self.isSettings && !self.isMyProfile {
|
||||||
if case .replyThread = self.chatLocation {
|
if case .replyThread = self.chatLocation {
|
||||||
title = presentationData.strings.Conversation_MyNotes
|
title = presentationData.strings.Conversation_MyNotes
|
||||||
} else {
|
} else {
|
||||||
@ -1069,6 +1063,26 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white, shadowColor: titleShadowColor)
|
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white, shadowColor: titleShadowColor)
|
||||||
|
|
||||||
usernameString = ("", MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white))
|
usernameString = ("", MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white))
|
||||||
|
} else if self.isMyProfile {
|
||||||
|
let subtitleColor: UIColor
|
||||||
|
subtitleColor = .white
|
||||||
|
|
||||||
|
subtitleStringText = presentationData.strings.Presence_online
|
||||||
|
subtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(17.0), color: subtitleColor)
|
||||||
|
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white, shadowColor: titleShadowColor)
|
||||||
|
|
||||||
|
usernameString = ("", MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white))
|
||||||
|
|
||||||
|
let (maybePanelStatusData, _, _) = panelStatusData
|
||||||
|
if let panelStatusData = maybePanelStatusData {
|
||||||
|
let subtitleColor: UIColor
|
||||||
|
if panelStatusData.isActivity {
|
||||||
|
subtitleColor = UIColor.white
|
||||||
|
} else {
|
||||||
|
subtitleColor = UIColor.white
|
||||||
|
}
|
||||||
|
panelSubtitleString = (panelStatusData.text, MultiScaleTextState.Attributes(font: Font.regular(17.0), color: subtitleColor))
|
||||||
|
}
|
||||||
} else if let _ = threadData {
|
} else if let _ = threadData {
|
||||||
let subtitleColor: UIColor
|
let subtitleColor: UIColor
|
||||||
subtitleColor = UIColor.white
|
subtitleColor = UIColor.white
|
||||||
@ -1341,14 +1355,14 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
let expandedTitleScale: CGFloat = 0.8
|
let expandedTitleScale: CGFloat = 0.8
|
||||||
|
|
||||||
var bottomShadowHeight: CGFloat = 88.0
|
var bottomShadowHeight: CGFloat = 88.0
|
||||||
if !self.isSettings {
|
if !self.isSettings && !self.isMyProfile {
|
||||||
bottomShadowHeight += 100.0
|
bottomShadowHeight += 100.0
|
||||||
}
|
}
|
||||||
let bottomShadowFrame = CGRect(origin: CGPoint(x: 0.0, y: expandedAvatarHeight - bottomShadowHeight), size: CGSize(width: width, height: bottomShadowHeight))
|
let bottomShadowFrame = CGRect(origin: CGPoint(x: 0.0, y: expandedAvatarHeight - bottomShadowHeight), size: CGSize(width: width, height: bottomShadowHeight))
|
||||||
transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: bottomShadowFrame, beginWithCurrentState: true)
|
transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: bottomShadowFrame, beginWithCurrentState: true)
|
||||||
self.avatarListNode.listContainerNode.bottomShadowNode.update(size: bottomShadowFrame.size, transition: transition)
|
self.avatarListNode.listContainerNode.bottomShadowNode.update(size: bottomShadowFrame.size, transition: transition)
|
||||||
|
|
||||||
let singleTitleLockOffset: CGFloat = (peer?.id == self.context.account.peerId || subtitleSize.height.isZero) ? 8.0 : 0.0
|
let singleTitleLockOffset: CGFloat = ((peer?.id == self.context.account.peerId && !self.isMyProfile) || subtitleSize.height.isZero) ? 8.0 : 0.0
|
||||||
|
|
||||||
let titleLockOffset: CGFloat = 7.0 + singleTitleLockOffset
|
let titleLockOffset: CGFloat = 7.0 + singleTitleLockOffset
|
||||||
let titleMaxLockOffset: CGFloat = 7.0
|
let titleMaxLockOffset: CGFloat = 7.0
|
||||||
@ -1358,14 +1372,14 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
if self.isAvatarExpanded {
|
if self.isAvatarExpanded {
|
||||||
let minTitleSize = CGSize(width: titleSize.width * expandedTitleScale, height: titleSize.height * expandedTitleScale)
|
let minTitleSize = CGSize(width: titleSize.width * expandedTitleScale, height: titleSize.height * expandedTitleScale)
|
||||||
var minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize)
|
var minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize)
|
||||||
if !self.isSettings {
|
if !self.isSettings && !self.isMyProfile {
|
||||||
minTitleFrame.origin.y -= 83.0
|
minTitleFrame.origin.y -= 83.0
|
||||||
}
|
}
|
||||||
|
|
||||||
titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize)
|
titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize)
|
||||||
|
|
||||||
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
|
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
|
||||||
if case .regular = metrics.widthClass, !isSettings {
|
if case .regular = metrics.widthClass, !isSettings, !isMyProfile {
|
||||||
titleCollapseOffset -= 7.0
|
titleCollapseOffset -= 7.0
|
||||||
}
|
}
|
||||||
titleOffset = -min(titleCollapseOffset, contentOffset)
|
titleOffset = -min(titleCollapseOffset, contentOffset)
|
||||||
@ -1377,7 +1391,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 9.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize)
|
titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 9.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize)
|
||||||
|
|
||||||
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
|
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
|
||||||
if case .regular = metrics.widthClass, !isSettings {
|
if case .regular = metrics.widthClass, !isSettings, !isMyProfile {
|
||||||
titleCollapseOffset -= 7.0
|
titleCollapseOffset -= 7.0
|
||||||
}
|
}
|
||||||
titleOffset = -min(titleCollapseOffset, contentOffset)
|
titleOffset = -min(titleCollapseOffset, contentOffset)
|
||||||
@ -1408,7 +1422,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
let effectiveAreaExpansionFraction: CGFloat
|
let effectiveAreaExpansionFraction: CGFloat
|
||||||
if state.isEditing {
|
if state.isEditing {
|
||||||
effectiveAreaExpansionFraction = 0.0
|
effectiveAreaExpansionFraction = 0.0
|
||||||
} else if isSettings {
|
} else if isSettings || isMyProfile {
|
||||||
var paneAreaExpansionDelta = (self.frame.maxY - navigationHeight) - contentOffset
|
var paneAreaExpansionDelta = (self.frame.maxY - navigationHeight) - contentOffset
|
||||||
paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance))
|
paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance))
|
||||||
effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance
|
effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance
|
||||||
@ -1716,12 +1730,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
rawHeight = navigationHeight + panelWithAvatarHeight
|
rawHeight = navigationHeight + panelWithAvatarHeight
|
||||||
var expandablePart: CGFloat = panelWithAvatarHeight - contentOffset
|
var expandablePart: CGFloat = panelWithAvatarHeight - contentOffset
|
||||||
if self.isSettings {
|
if self.isSettings || self.isMyProfile {
|
||||||
expandablePart += 20.0
|
expandablePart += 20.0
|
||||||
} else {
|
} else {
|
||||||
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.peerId == self.context.account.peerId {
|
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.peerId == self.context.account.peerId {
|
||||||
expandablePart = 0.0
|
expandablePart = 0.0
|
||||||
} else if peer?.id == self.context.account.peerId {
|
} else if peer?.id == self.context.account.peerId && !self.isMyProfile {
|
||||||
expandablePart = 0.0
|
expandablePart = 0.0
|
||||||
} else {
|
} else {
|
||||||
expandablePart += 99.0
|
expandablePart += 99.0
|
||||||
@ -2140,7 +2154,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !state.isEditing {
|
if !state.isEditing {
|
||||||
if !isSettings {
|
if !isSettings && !isMyProfile {
|
||||||
if self.isAvatarExpanded {
|
if self.isAvatarExpanded {
|
||||||
resolvedHeight -= 21.0
|
resolvedHeight -= 21.0
|
||||||
} else {
|
} else {
|
||||||
|
@ -365,6 +365,7 @@ private final class PeerInfoPendingPane {
|
|||||||
hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void,
|
hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void,
|
||||||
parentController: ViewController?,
|
parentController: ViewController?,
|
||||||
openMediaCalendar: @escaping () -> Void,
|
openMediaCalendar: @escaping () -> Void,
|
||||||
|
openAddStory: @escaping () -> Void,
|
||||||
paneDidScroll: @escaping () -> Void,
|
paneDidScroll: @escaping () -> Void,
|
||||||
ensureRectVisible: @escaping (UIView, CGRect) -> Void,
|
ensureRectVisible: @escaping (UIView, CGRect) -> Void,
|
||||||
externalDataUpdated: @escaping (ContainedViewLayoutTransition) -> Void
|
externalDataUpdated: @escaping (ContainedViewLayoutTransition) -> Void
|
||||||
@ -372,8 +373,8 @@ private final class PeerInfoPendingPane {
|
|||||||
let captureProtected = data.peer?.isCopyProtectionEnabled ?? false
|
let captureProtected = data.peer?.isCopyProtectionEnabled ?? false
|
||||||
let paneNode: PeerInfoPaneNode
|
let paneNode: PeerInfoPaneNode
|
||||||
switch key {
|
switch key {
|
||||||
case .stories:
|
case .stories, .storyArchive:
|
||||||
let visualPaneNode = PeerInfoStoryPaneNode(context: context, peerId: peerId, chatLocation: chatLocation, contentType: .photoOrVideo, captureProtected: captureProtected, isSaved: false, isArchive: false, navigationController: chatControllerInteraction.navigationController, listContext: data.storyListContext)
|
let visualPaneNode = PeerInfoStoryPaneNode(context: context, peerId: peerId, chatLocation: chatLocation, contentType: .photoOrVideo, captureProtected: captureProtected, isSaved: false, isArchive: key == .storyArchive, isProfileEmbedded: true, navigationController: chatControllerInteraction.navigationController, listContext: key == .storyArchive ? data.storyArchiveListContext : data.storyListContext)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
visualPaneNode.openCurrentDate = {
|
visualPaneNode.openCurrentDate = {
|
||||||
openMediaCalendar()
|
openMediaCalendar()
|
||||||
@ -384,6 +385,9 @@ private final class PeerInfoPendingPane {
|
|||||||
visualPaneNode.ensureRectVisible = { sourceView, rect in
|
visualPaneNode.ensureRectVisible = { sourceView, rect in
|
||||||
ensureRectVisible(sourceView, rect)
|
ensureRectVisible(sourceView, rect)
|
||||||
}
|
}
|
||||||
|
visualPaneNode.emptyAction = {
|
||||||
|
openAddStory()
|
||||||
|
}
|
||||||
case .media:
|
case .media:
|
||||||
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .photoOrVideo, captureProtected: captureProtected)
|
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .photoOrVideo, captureProtected: captureProtected)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
@ -500,6 +504,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
var requestUpdate: ((ContainedViewLayoutTransition) -> Void)?
|
var requestUpdate: ((ContainedViewLayoutTransition) -> Void)?
|
||||||
|
|
||||||
var openMediaCalendar: (() -> Void)?
|
var openMediaCalendar: (() -> Void)?
|
||||||
|
var openAddStory: (() -> Void)?
|
||||||
var paneDidScroll: (() -> Void)?
|
var paneDidScroll: (() -> Void)?
|
||||||
|
|
||||||
var ensurePaneRectVisible: ((UIView, CGRect) -> Void)?
|
var ensurePaneRectVisible: ((UIView, CGRect) -> Void)?
|
||||||
@ -848,6 +853,9 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
openMediaCalendar: { [weak self] in
|
openMediaCalendar: { [weak self] in
|
||||||
self?.openMediaCalendar?()
|
self?.openMediaCalendar?()
|
||||||
},
|
},
|
||||||
|
openAddStory: { [weak self] in
|
||||||
|
self?.openAddStory?()
|
||||||
|
},
|
||||||
paneDidScroll: { [weak self] in
|
paneDidScroll: { [weak self] in
|
||||||
self?.paneDidScroll?()
|
self?.paneDidScroll?()
|
||||||
},
|
},
|
||||||
@ -1010,6 +1018,9 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
switch key {
|
switch key {
|
||||||
case .stories:
|
case .stories:
|
||||||
title = presentationData.strings.PeerInfo_PaneStories
|
title = presentationData.strings.PeerInfo_PaneStories
|
||||||
|
case .storyArchive:
|
||||||
|
//TODO:localize
|
||||||
|
title = "Archived Posts"
|
||||||
case .media:
|
case .media:
|
||||||
title = presentationData.strings.PeerInfo_PaneMedia
|
title = presentationData.strings.PeerInfo_PaneMedia
|
||||||
case .files:
|
case .files:
|
||||||
|
@ -518,6 +518,7 @@ private enum PeerInfoSettingsSection {
|
|||||||
case emojiStatus
|
case emojiStatus
|
||||||
case powerSaving
|
case powerSaving
|
||||||
case businessSetup
|
case businessSetup
|
||||||
|
case profile
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum PeerInfoReportType {
|
private enum PeerInfoReportType {
|
||||||
@ -725,6 +726,7 @@ private enum SettingsSection: Int, CaseIterable {
|
|||||||
case edit
|
case edit
|
||||||
case phone
|
case phone
|
||||||
case accounts
|
case accounts
|
||||||
|
case myProfile
|
||||||
case proxy
|
case proxy
|
||||||
case apps
|
case apps
|
||||||
case shortcuts
|
case shortcuts
|
||||||
@ -850,6 +852,11 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
items[.myProfile]!.append(PeerInfoScreenDisclosureItem(id: 0, text: "My Profile", icon: PresentationResourcesSettings.myProfile, action: {
|
||||||
|
interaction.openSettings(.profile)
|
||||||
|
}))
|
||||||
|
|
||||||
if !settings.proxySettings.servers.isEmpty {
|
if !settings.proxySettings.servers.isEmpty {
|
||||||
let proxyType: String
|
let proxyType: String
|
||||||
if settings.proxySettings.enabled, let activeServer = settings.proxySettings.activeServer {
|
if settings.proxySettings.enabled, let activeServer = settings.proxySettings.activeServer {
|
||||||
@ -892,10 +899,6 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items[.apps]!.append(PeerInfoScreenDisclosureItem(id: 0, text: presentationData.strings.Settings_MyStories, icon: PresentationResourcesSettings.stories, action: {
|
|
||||||
interaction.openSettings(.stories)
|
|
||||||
}))
|
|
||||||
|
|
||||||
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 1, text: presentationData.strings.Settings_SavedMessages, icon: PresentationResourcesSettings.savedMessages, action: {
|
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 1, text: presentationData.strings.Settings_SavedMessages, icon: PresentationResourcesSettings.savedMessages, action: {
|
||||||
interaction.openSettings(.savedMessages)
|
interaction.openSettings(.savedMessages)
|
||||||
}))
|
}))
|
||||||
@ -994,7 +997,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, isMyProfile: Bool) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||||
guard let data = data else {
|
guard let data = data else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@ -1028,7 +1031,9 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
let ItemBirthdayHelp = 12
|
let ItemBirthdayHelp = 12
|
||||||
let ItemPeerPersonalChannel = 13
|
let ItemPeerPersonalChannel = 13
|
||||||
|
|
||||||
|
if !isMyProfile {
|
||||||
items[.help]!.append(PeerInfoScreenCommentItem(id: ItemNameHelp, text: presentationData.strings.EditProfile_NameAndPhotoOrVideoHelp))
|
items[.help]!.append(PeerInfoScreenCommentItem(id: ItemNameHelp, text: presentationData.strings.EditProfile_NameAndPhotoOrVideoHelp))
|
||||||
|
}
|
||||||
|
|
||||||
if let cachedData = data.cachedData as? CachedUserData {
|
if let cachedData = data.cachedData as? CachedUserData {
|
||||||
items[.bio]!.append(PeerInfoScreenMultilineInputItem(id: ItemBio, text: state.updatingBio ?? (cachedData.about ?? ""), placeholder: presentationData.strings.UserInfo_About_Placeholder, textUpdated: { updatedText in
|
items[.bio]!.append(PeerInfoScreenMultilineInputItem(id: ItemBio, text: state.updatingBio ?? (cachedData.about ?? ""), placeholder: presentationData.strings.UserInfo_About_Placeholder, textUpdated: { updatedText in
|
||||||
@ -1056,6 +1061,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
birthDateString = presentationData.strings.Settings_Birthday_Add
|
birthDateString = presentationData.strings.Settings_Birthday_Add
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isMyProfile {
|
||||||
let isEditingBirthDate = state.isEditingBirthDate
|
let isEditingBirthDate = state.isEditingBirthDate
|
||||||
items[.birthday]!.append(PeerInfoScreenDisclosureItem(id: ItemBirthday, label: .coloredText(birthDateString, isEditingBirthDate ? .accent : .generic), text: presentationData.strings.Settings_Birthday, icon: nil, hasArrow: false, action: {
|
items[.birthday]!.append(PeerInfoScreenDisclosureItem(id: ItemBirthday, label: .coloredText(birthDateString, isEditingBirthDate ? .accent : .generic), text: presentationData.strings.Settings_Birthday, icon: nil, hasArrow: false, action: {
|
||||||
interaction.updateIsEditingBirthdate(!isEditingBirthDate)
|
interaction.updateIsEditingBirthdate(!isEditingBirthDate)
|
||||||
@ -1070,6 +1076,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var birthdayIsForContactsOnly = false
|
var birthdayIsForContactsOnly = false
|
||||||
if let birthdayPrivacy = data.globalSettings?.privacySettings?.birthday, case .enableContacts = birthdayPrivacy {
|
if let birthdayPrivacy = data.globalSettings?.privacySettings?.birthday, case .enableContacts = birthdayPrivacy {
|
||||||
birthdayIsForContactsOnly = true
|
birthdayIsForContactsOnly = true
|
||||||
@ -1077,6 +1084,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
items[.birthday]!.append(PeerInfoScreenCommentItem(id: ItemBirthdayHelp, text: birthdayIsForContactsOnly ? presentationData.strings.Settings_Birthday_ContactsHelp : presentationData.strings.Settings_Birthday_Help, linkAction: { _ in
|
items[.birthday]!.append(PeerInfoScreenCommentItem(id: ItemBirthdayHelp, text: birthdayIsForContactsOnly ? presentationData.strings.Settings_Birthday_ContactsHelp : presentationData.strings.Settings_Birthday_Help, linkAction: { _ in
|
||||||
interaction.openBirthdatePrivacy()
|
interaction.openBirthdatePrivacy()
|
||||||
}))
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
if let user = data.peer as? TelegramUser {
|
if let user = data.peer as? TelegramUser {
|
||||||
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, action: {
|
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, action: {
|
||||||
@ -1091,7 +1099,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
interaction.openSettings(.username)
|
interaction.openSettings(.username)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if let peer = data.peer as? TelegramUser {
|
if !isMyProfile, let peer = data.peer as? TelegramUser {
|
||||||
var colors: [PeerNameColors.Colors] = []
|
var colors: [PeerNameColors.Colors] = []
|
||||||
if let nameColor = peer.nameColor.flatMap({ context.peerNameColors.get($0, dark: presentationData.theme.overallDarkAppearance) }) {
|
if let nameColor = peer.nameColor.flatMap({ context.peerNameColors.get($0, dark: presentationData.theme.overallDarkAppearance) }) {
|
||||||
colors.append(nameColor)
|
colors.append(nameColor)
|
||||||
@ -1123,9 +1131,11 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isMyProfile {
|
||||||
items[.account]!.append(PeerInfoScreenActionItem(id: ItemAddAccount, text: presentationData.strings.Settings_AddAnotherAccount, alignment: .center, action: {
|
items[.account]!.append(PeerInfoScreenActionItem(id: ItemAddAccount, text: presentationData.strings.Settings_AddAnotherAccount, alignment: .center, action: {
|
||||||
interaction.openSettings(.addAccount)
|
interaction.openSettings(.addAccount)
|
||||||
}))
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
var hasPremiumAccounts = false
|
var hasPremiumAccounts = false
|
||||||
if data.peer?.isPremium == true && !context.account.testingEnvironment {
|
if data.peer?.isPremium == true && !context.account.testingEnvironment {
|
||||||
@ -1142,11 +1152,13 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isMyProfile {
|
||||||
items[.account]!.append(PeerInfoScreenCommentItem(id: ItemAddAccountHelp, text: hasPremiumAccounts ? presentationData.strings.Settings_AddAnotherAccount_PremiumHelp : presentationData.strings.Settings_AddAnotherAccount_Help))
|
items[.account]!.append(PeerInfoScreenCommentItem(id: ItemAddAccountHelp, text: hasPremiumAccounts ? presentationData.strings.Settings_AddAnotherAccount_PremiumHelp : presentationData.strings.Settings_AddAnotherAccount_Help))
|
||||||
|
|
||||||
items[.logout]!.append(PeerInfoScreenActionItem(id: ItemLogout, text: presentationData.strings.Settings_Logout, color: .destructive, alignment: .center, action: {
|
items[.logout]!.append(PeerInfoScreenActionItem(id: ItemLogout, text: presentationData.strings.Settings_Logout, color: .destructive, alignment: .center, action: {
|
||||||
interaction.openSettings(.logout)
|
interaction.openSettings(.logout)
|
||||||
}))
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
var result: [(AnyHashable, [PeerInfoScreenItem])] = []
|
var result: [(AnyHashable, [PeerInfoScreenItem])] = []
|
||||||
for section in Section.allCases {
|
for section in Section.allCases {
|
||||||
@ -2371,6 +2383,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||||
|
|
||||||
let isSettings: Bool
|
let isSettings: Bool
|
||||||
|
let isMyProfile: Bool
|
||||||
private let isMediaOnly: Bool
|
private let isMediaOnly: Bool
|
||||||
let initialExpandPanes: Bool
|
let initialExpandPanes: Bool
|
||||||
|
|
||||||
@ -2488,7 +2501,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
private var didSetReady = false
|
private var didSetReady = false
|
||||||
|
|
||||||
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, initialPaneKey: PeerInfoPaneKey?) {
|
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, initialPaneKey: PeerInfoPaneKey?) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
@ -2499,9 +2512,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
self.reactionSourceMessageId = reactionSourceMessageId
|
self.reactionSourceMessageId = reactionSourceMessageId
|
||||||
self.callMessages = callMessages
|
self.callMessages = callMessages
|
||||||
self.isSettings = isSettings
|
self.isSettings = isSettings
|
||||||
|
self.isMyProfile = isMyProfile
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
self.chatLocationContextHolder = chatLocationContextHolder
|
self.chatLocationContextHolder = chatLocationContextHolder
|
||||||
self.isMediaOnly = context.account.peerId == peerId && !isSettings
|
self.isMediaOnly = context.account.peerId == peerId && !isSettings && !isMyProfile
|
||||||
self.initialExpandPanes = initialPaneKey != nil
|
self.initialExpandPanes = initialPaneKey != nil
|
||||||
|
|
||||||
self.scrollNode = ASScrollNode()
|
self.scrollNode = ASScrollNode()
|
||||||
@ -2512,7 +2526,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
if case let .replyThread(message) = chatLocation {
|
if case let .replyThread(message) = chatLocation {
|
||||||
forumTopicThreadId = message.threadId
|
forumTopicThreadId = message.threadId
|
||||||
}
|
}
|
||||||
self.headerNode = PeerInfoHeaderNode(context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation)
|
self.headerNode = PeerInfoHeaderNode(context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, isMyProfile: isMyProfile, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation)
|
||||||
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey)
|
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
@ -3437,6 +3451,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
strongSelf.openMediaCalendar()
|
strongSelf.openMediaCalendar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.paneContainerNode.openAddStory = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.headerNode.navigationButtonContainer.performAction?(.postStory, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
self.paneContainerNode.paneDidScroll = { [weak self] in
|
self.paneContainerNode.paneDidScroll = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -4180,7 +4201,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
strongSelf.controller?.present(emojiStatusSelectionController, in: .window(.root))
|
strongSelf.controller?.present(emojiStatusSelectionController, in: .window(.root))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, hintGroupInCommon: hintGroupInCommon, existingRequestsContext: requestsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder)
|
screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: hintGroupInCommon, existingRequestsContext: requestsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder)
|
||||||
|
|
||||||
var previousTimestamp: Double?
|
var previousTimestamp: Double?
|
||||||
self.headerNode.displayPremiumIntro = { [weak self] sourceView, peerStatus, emojiStatusFileAndPack, white in
|
self.headerNode.displayPremiumIntro = { [weak self] sourceView, peerStatus, emojiStatusFileAndPack, white in
|
||||||
@ -9186,6 +9207,18 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
self.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil)
|
self.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil)
|
||||||
case .proxy:
|
case .proxy:
|
||||||
self.controller?.push(proxySettingsController(context: self.context))
|
self.controller?.push(proxySettingsController(context: self.context))
|
||||||
|
case .profile:
|
||||||
|
self.controller?.push(PeerInfoScreenImpl(
|
||||||
|
context: self.context,
|
||||||
|
updatedPresentationData: self.controller?.updatedPresentationData,
|
||||||
|
peerId: self.context.account.peerId,
|
||||||
|
avatarInitiallyExpanded: false,
|
||||||
|
isOpenedFromChat: false,
|
||||||
|
nearbyPeerDistance: nil,
|
||||||
|
reactionSourceMessageId: nil,
|
||||||
|
callMessages: [],
|
||||||
|
isMyProfile: true
|
||||||
|
))
|
||||||
case .stories:
|
case .stories:
|
||||||
push(PeerInfoStoryGridScreen(context: self.context, peerId: self.context.account.peerId, scope: .saved))
|
push(PeerInfoStoryGridScreen(context: self.context, peerId: self.context.account.peerId, scope: .saved))
|
||||||
case .savedMessages:
|
case .savedMessages:
|
||||||
@ -10503,7 +10536,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
var validEditingSections: [AnyHashable] = []
|
var validEditingSections: [AnyHashable] = []
|
||||||
let editItems = self.isSettings ? settingsEditingItems(data: self.data, state: self.state, context: self.context, presentationData: self.presentationData, interaction: self.interaction) : editingItems(data: self.data, state: self.state, chatLocation: self.chatLocation, context: self.context, presentationData: self.presentationData, interaction: self.interaction)
|
let editItems = (self.isSettings || self.isMyProfile) ? settingsEditingItems(data: self.data, state: self.state, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isMyProfile: self.isMyProfile) : editingItems(data: self.data, state: self.state, chatLocation: self.chatLocation, context: self.context, presentationData: self.presentationData, interaction: self.interaction)
|
||||||
|
|
||||||
for (sectionId, sectionItems) in editItems {
|
for (sectionId, sectionItems) in editItems {
|
||||||
var insets = UIEdgeInsets()
|
var insets = UIEdgeInsets()
|
||||||
@ -10829,6 +10862,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
if let data = self.data, !data.isPremiumRequiredForStoryPosting || data.accountIsPremium, let channel = data.peer as? TelegramChannel, channel.hasPermission(.postStories) {
|
if let data = self.data, !data.isPremiumRequiredForStoryPosting || data.accountIsPremium, let channel = data.peer as? TelegramChannel, channel.hasPermission(.postStories) {
|
||||||
rightNavigationButtons.insert(PeerInfoHeaderNavigationButtonSpec(key: .postStory, isForExpandedView: false), at: 0)
|
rightNavigationButtons.insert(PeerInfoHeaderNavigationButtonSpec(key: .postStory, isForExpandedView: false), at: 0)
|
||||||
|
} else if self.isMyProfile {
|
||||||
|
rightNavigationButtons.insert(PeerInfoHeaderNavigationButtonSpec(key: .postStory, isForExpandedView: false), at: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.state.selectedMessageIds == nil {
|
if self.state.selectedMessageIds == nil {
|
||||||
@ -11182,6 +11217,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
private let reactionSourceMessageId: MessageId?
|
private let reactionSourceMessageId: MessageId?
|
||||||
private let callMessages: [Message]
|
private let callMessages: [Message]
|
||||||
private let isSettings: Bool
|
private let isSettings: Bool
|
||||||
|
private let isMyProfile: Bool
|
||||||
private let hintGroupInCommon: PeerId?
|
private let hintGroupInCommon: PeerId?
|
||||||
private weak var requestsContext: PeerInvitationImportersContext?
|
private weak var requestsContext: PeerInvitationImportersContext?
|
||||||
private let switchToRecommendedChannels: Bool
|
private let switchToRecommendedChannels: Bool
|
||||||
@ -11241,7 +11277,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
|
|
||||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||||
|
|
||||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil, forumTopicThread: ChatReplyThreadMessage? = nil, switchToRecommendedChannels: Bool = false) {
|
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool = false, isMyProfile: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil, forumTopicThread: ChatReplyThreadMessage? = nil, switchToRecommendedChannels: Bool = false) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updatedPresentationData = updatedPresentationData
|
self.updatedPresentationData = updatedPresentationData
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
@ -11251,6 +11287,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
self.reactionSourceMessageId = reactionSourceMessageId
|
self.reactionSourceMessageId = reactionSourceMessageId
|
||||||
self.callMessages = callMessages
|
self.callMessages = callMessages
|
||||||
self.isSettings = isSettings
|
self.isSettings = isSettings
|
||||||
|
self.isMyProfile = isMyProfile
|
||||||
self.hintGroupInCommon = hintGroupInCommon
|
self.hintGroupInCommon = hintGroupInCommon
|
||||||
self.requestsContext = requestsContext
|
self.requestsContext = requestsContext
|
||||||
self.switchToRecommendedChannels = switchToRecommendedChannels
|
self.switchToRecommendedChannels = switchToRecommendedChannels
|
||||||
@ -11587,7 +11624,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, initialPaneKey: self.switchToRecommendedChannels ? .recommended : nil)
|
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, initialPaneKey: self.switchToRecommendedChannels ? .recommended : nil)
|
||||||
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
||||||
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
||||||
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
||||||
|
@ -461,6 +461,7 @@ final class PeerInfoStoryGridScreenComponent: Component {
|
|||||||
captureProtected: false,
|
captureProtected: false,
|
||||||
isSaved: true,
|
isSaved: true,
|
||||||
isArchive: component.scope == .archive,
|
isArchive: component.scope == .archive,
|
||||||
|
isProfileEmbedded: false,
|
||||||
navigationController: { [weak self] in
|
navigationController: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -189,6 +189,62 @@ private let viewCountImage: UIImage = {
|
|||||||
return image!
|
return image!
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private let privacyTypeImageScaleFactor: CGFloat = {
|
||||||
|
return 0.9
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let privacyTypeEveryoneImage: UIImage = {
|
||||||
|
let baseImage = UIImage(bundleImageName: "Stories/PrivacyEveryone")!
|
||||||
|
let imageSize = CGSize(width: floor(baseImage.size.width * privacyTypeImageScaleFactor), height: floor(baseImage.size.width * privacyTypeImageScaleFactor))
|
||||||
|
let image = generateImage(imageSize, rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
baseImage.draw(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
})
|
||||||
|
return image!
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let privacyTypeContactsImage: UIImage = {
|
||||||
|
let baseImage = UIImage(bundleImageName: "Stories/PrivacyContacts")!
|
||||||
|
let imageSize = CGSize(width: floor(baseImage.size.width * privacyTypeImageScaleFactor), height: floor(baseImage.size.width * privacyTypeImageScaleFactor))
|
||||||
|
let image = generateImage(imageSize, rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
baseImage.draw(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
})
|
||||||
|
return image!
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let privacyTypeCloseFriendsImage: UIImage = {
|
||||||
|
let baseImage = UIImage(bundleImageName: "Stories/PrivacyCloseFriends")!
|
||||||
|
let imageSize = CGSize(width: floor(baseImage.size.width * privacyTypeImageScaleFactor), height: floor(baseImage.size.width * privacyTypeImageScaleFactor))
|
||||||
|
let image = generateImage(imageSize, rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
baseImage.draw(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
})
|
||||||
|
return image!
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let privacyTypeSelectedImage: UIImage = {
|
||||||
|
let baseImage = UIImage(bundleImageName: "Stories/PrivacySelectedContacts")!
|
||||||
|
let imageSize = CGSize(width: floor(baseImage.size.width * privacyTypeImageScaleFactor), height: floor(baseImage.size.width * privacyTypeImageScaleFactor))
|
||||||
|
let image = generateImage(imageSize, rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
baseImage.draw(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
})
|
||||||
|
return image!
|
||||||
|
}()
|
||||||
|
|
||||||
private final class DurationLayer: CALayer {
|
private final class DurationLayer: CALayer {
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
@ -264,6 +320,41 @@ private final class DurationLayer: CALayer {
|
|||||||
self.contents = image?.cgImage
|
self.contents = image?.cgImage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func update(privacyType: Stories.Item.Privacy.Base, isMin: Bool) {
|
||||||
|
if isMin {
|
||||||
|
self.contents = nil
|
||||||
|
} else {
|
||||||
|
let iconImage: UIImage
|
||||||
|
switch privacyType {
|
||||||
|
case .everyone:
|
||||||
|
iconImage = privacyTypeEveryoneImage
|
||||||
|
case .contacts:
|
||||||
|
iconImage = privacyTypeContactsImage
|
||||||
|
case .closeFriends:
|
||||||
|
iconImage = privacyTypeCloseFriendsImage
|
||||||
|
case .nobody:
|
||||||
|
iconImage = privacyTypeSelectedImage
|
||||||
|
}
|
||||||
|
|
||||||
|
let sideInset: CGFloat = 0.0
|
||||||
|
let verticalInset: CGFloat = 0.0
|
||||||
|
let image = generateImage(CGSize(width: iconImage.size.width + sideInset * 2.0, height: iconImage.size.height + verticalInset * 2.0), rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setBlendMode(.normal)
|
||||||
|
|
||||||
|
context.setShadow(offset: CGSize(width: 0.0, height: 0.0), blur: 2.5, color: UIColor(rgb: 0x000000, alpha: 0.22).cgColor)
|
||||||
|
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
|
||||||
|
iconImage.draw(in: CGRect(origin: CGPoint(x: (size.width - iconImage.size.width) * 0.5, y: (size.height - iconImage.size.height) * 0.5), size: iconImage.size))
|
||||||
|
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
})
|
||||||
|
self.contents = image?.cgImage
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private protocol ItemLayer: SparseItemGridLayer {
|
private protocol ItemLayer: SparseItemGridLayer {
|
||||||
@ -276,7 +367,7 @@ private protocol ItemLayer: SparseItemGridLayer {
|
|||||||
var hasContents: Bool { get set }
|
var hasContents: Bool { get set }
|
||||||
func setSpoilerContents(_ contents: Any?)
|
func setSpoilerContents(_ contents: Any?)
|
||||||
|
|
||||||
func updateDuration(viewCount: Int32?, duration: Int32?, isMin: Bool, minFactor: CGFloat)
|
func updateDuration(viewCount: Int32?, duration: Int32?, privacy: Stories.Item.Privacy.Base?, isMin: Bool, minFactor: CGFloat)
|
||||||
func updateSelection(theme: CheckNodeTheme, isSelected: Bool?, animated: Bool)
|
func updateSelection(theme: CheckNodeTheme, isSelected: Bool?, animated: Bool)
|
||||||
func updateHasSpoiler(hasSpoiler: Bool)
|
func updateHasSpoiler(hasSpoiler: Bool)
|
||||||
|
|
||||||
@ -288,8 +379,10 @@ private final class GenericItemLayer: CALayer, ItemLayer {
|
|||||||
var item: VisualMediaItem?
|
var item: VisualMediaItem?
|
||||||
var viewCountLayer: DurationLayer?
|
var viewCountLayer: DurationLayer?
|
||||||
var durationLayer: DurationLayer?
|
var durationLayer: DurationLayer?
|
||||||
|
var privacyTypeLayer: DurationLayer?
|
||||||
var leftShadowLayer: SimpleLayer?
|
var leftShadowLayer: SimpleLayer?
|
||||||
var rightShadowLayer: SimpleLayer?
|
var rightShadowLayer: SimpleLayer?
|
||||||
|
var topRightShadowLayer: SimpleLayer?
|
||||||
var minFactor: CGFloat = 1.0
|
var minFactor: CGFloat = 1.0
|
||||||
var selectionLayer: GridMessageSelectionLayer?
|
var selectionLayer: GridMessageSelectionLayer?
|
||||||
var dustLayer: MediaDustLayer?
|
var dustLayer: MediaDustLayer?
|
||||||
@ -335,7 +428,7 @@ private final class GenericItemLayer: CALayer, ItemLayer {
|
|||||||
self.item = item
|
self.item = item
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateDuration(viewCount: Int32?, duration: Int32?, isMin: Bool, minFactor: CGFloat) {
|
func updateDuration(viewCount: Int32?, duration: Int32?, privacy: Stories.Item.Privacy.Base?, isMin: Bool, minFactor: CGFloat) {
|
||||||
self.minFactor = minFactor
|
self.minFactor = minFactor
|
||||||
|
|
||||||
if let viewCount {
|
if let viewCount {
|
||||||
@ -371,6 +464,23 @@ private final class GenericItemLayer: CALayer, ItemLayer {
|
|||||||
durationLayer.removeFromSuperlayer()
|
durationLayer.removeFromSuperlayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let privacy {
|
||||||
|
if let privacyTypeLayer = self.privacyTypeLayer {
|
||||||
|
privacyTypeLayer.update(privacyType: privacy, isMin: isMin)
|
||||||
|
} else {
|
||||||
|
let privacyTypeLayer = DurationLayer()
|
||||||
|
privacyTypeLayer.contentsGravity = .bottomRight
|
||||||
|
privacyTypeLayer.update(privacyType: privacy, isMin: isMin)
|
||||||
|
self.addSublayer(privacyTypeLayer)
|
||||||
|
privacyTypeLayer.frame = CGRect(origin: CGPoint(x: self.bounds.width - 2.0, y: 3.0), size: CGSize())
|
||||||
|
privacyTypeLayer.transform = CATransform3DMakeScale(minFactor, minFactor, 1.0)
|
||||||
|
self.privacyTypeLayer = privacyTypeLayer
|
||||||
|
}
|
||||||
|
} else if let privacyTypeLayer = self.privacyTypeLayer {
|
||||||
|
self.privacyTypeLayer = nil
|
||||||
|
privacyTypeLayer.removeFromSuperlayer()
|
||||||
|
}
|
||||||
|
|
||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
|
|
||||||
if self.viewCountLayer != nil {
|
if self.viewCountLayer != nil {
|
||||||
@ -404,6 +514,22 @@ private final class GenericItemLayer: CALayer, ItemLayer {
|
|||||||
rightShadowLayer.removeFromSuperlayer()
|
rightShadowLayer.removeFromSuperlayer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.privacyTypeLayer != nil {
|
||||||
|
if self.topRightShadowLayer == nil {
|
||||||
|
let topRightShadowLayer = SimpleLayer()
|
||||||
|
self.topRightShadowLayer = topRightShadowLayer
|
||||||
|
self.insertSublayer(topRightShadowLayer, at: 0)
|
||||||
|
topRightShadowLayer.contents = rightShadowImage.cgImage
|
||||||
|
let shadowSize = CGSize(width: min(size.width, rightShadowImage.size.width), height: min(size.height, rightShadowImage.size.height))
|
||||||
|
topRightShadowLayer.frame = CGRect(origin: CGPoint(x: size.width - shadowSize.width, y: size.height - shadowSize.height), size: shadowSize)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let topRightShadowLayer = self.topRightShadowLayer {
|
||||||
|
self.topRightShadowLayer = nil
|
||||||
|
topRightShadowLayer.removeFromSuperlayer()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSelection(theme: CheckNodeTheme, isSelected: Bool?, animated: Bool) {
|
func updateSelection(theme: CheckNodeTheme, isSelected: Bool?, animated: Bool) {
|
||||||
@ -468,6 +594,9 @@ private final class GenericItemLayer: CALayer, ItemLayer {
|
|||||||
if let durationLayer = self.durationLayer {
|
if let durationLayer = self.durationLayer {
|
||||||
durationLayer.frame = CGRect(origin: CGPoint(x: size.width - 3.0, y: size.height - 4.0), size: CGSize())
|
durationLayer.frame = CGRect(origin: CGPoint(x: size.width - 3.0, y: size.height - 4.0), size: CGSize())
|
||||||
}
|
}
|
||||||
|
if let privacyTypeLayer = self.privacyTypeLayer {
|
||||||
|
privacyTypeLayer.frame = CGRect(origin: CGPoint(x: size.width - 2.0, y: 3.0), size: CGSize())
|
||||||
|
}
|
||||||
|
|
||||||
if let leftShadowLayer = self.leftShadowLayer {
|
if let leftShadowLayer = self.leftShadowLayer {
|
||||||
let shadowSize = CGSize(width: min(size.width, leftShadowImage.size.width), height: min(size.height, leftShadowImage.size.height))
|
let shadowSize = CGSize(width: min(size.width, leftShadowImage.size.width), height: min(size.height, leftShadowImage.size.height))
|
||||||
@ -479,6 +608,11 @@ private final class GenericItemLayer: CALayer, ItemLayer {
|
|||||||
rightShadowLayer.frame = CGRect(origin: CGPoint(x: size.width - shadowSize.width, y: size.height - shadowSize.height), size: shadowSize)
|
rightShadowLayer.frame = CGRect(origin: CGPoint(x: size.width - shadowSize.width, y: size.height - shadowSize.height), size: shadowSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let topRightShadowLayer = self.topRightShadowLayer {
|
||||||
|
let shadowSize = CGSize(width: min(size.width, rightShadowImage.size.width), height: min(size.height, rightShadowImage.size.height))
|
||||||
|
topRightShadowLayer.frame = CGRect(origin: CGPoint(x: size.width - shadowSize.width, y: 0.0), size: shadowSize)
|
||||||
|
}
|
||||||
|
|
||||||
if let binding = binding as? SparseItemGridBindingImpl, let item = item as? VisualMediaItem, let previousItem = self.item, previousItem.story.media.id != item.story.media.id {
|
if let binding = binding as? SparseItemGridBindingImpl, let item = item as? VisualMediaItem, let previousItem = self.item, previousItem.story.media.id != item.story.media.id {
|
||||||
binding.bindLayers(items: [item], layers: [displayItem], size: size, insets: insets, synchronous: .none)
|
binding.bindLayers(items: [item], layers: [displayItem], size: size, insets: insets, synchronous: .none)
|
||||||
}
|
}
|
||||||
@ -489,11 +623,14 @@ private final class ItemTransitionView: UIView {
|
|||||||
private weak var itemLayer: CALayer?
|
private weak var itemLayer: CALayer?
|
||||||
private var copyDurationLayer: SimpleLayer?
|
private var copyDurationLayer: SimpleLayer?
|
||||||
private var copyViewCountLayer: SimpleLayer?
|
private var copyViewCountLayer: SimpleLayer?
|
||||||
|
private var copyPrivacyTypeLayer: SimpleLayer?
|
||||||
private var copyLeftShadowLayer: SimpleLayer?
|
private var copyLeftShadowLayer: SimpleLayer?
|
||||||
private var copyRightShadowLayer: SimpleLayer?
|
private var copyRightShadowLayer: SimpleLayer?
|
||||||
|
private var copyTopRightShadowLayer: SimpleLayer?
|
||||||
|
|
||||||
private var viewCountLayerBottomLeftPosition: CGPoint?
|
private var viewCountLayerBottomLeftPosition: CGPoint?
|
||||||
private var durationLayerBottomLeftPosition: CGPoint?
|
private var durationLayerBottomLeftPosition: CGPoint?
|
||||||
|
private var privacyTypeLayerTopRightPosition: CGPoint?
|
||||||
|
|
||||||
init(itemLayer: CALayer?) {
|
init(itemLayer: CALayer?) {
|
||||||
self.itemLayer = itemLayer
|
self.itemLayer = itemLayer
|
||||||
@ -505,13 +642,17 @@ private final class ItemTransitionView: UIView {
|
|||||||
|
|
||||||
var viewCountLayer: CALayer?
|
var viewCountLayer: CALayer?
|
||||||
var durationLayer: CALayer?
|
var durationLayer: CALayer?
|
||||||
|
var privacyTypeLayer: CALayer?
|
||||||
var leftShadowLayer: CALayer?
|
var leftShadowLayer: CALayer?
|
||||||
var rightShadowLayer: CALayer?
|
var rightShadowLayer: CALayer?
|
||||||
|
var topRightShadowLayer: CALayer?
|
||||||
if let itemLayer = itemLayer as? GenericItemLayer {
|
if let itemLayer = itemLayer as? GenericItemLayer {
|
||||||
viewCountLayer = itemLayer.viewCountLayer
|
viewCountLayer = itemLayer.viewCountLayer
|
||||||
durationLayer = itemLayer.durationLayer
|
durationLayer = itemLayer.durationLayer
|
||||||
|
privacyTypeLayer = itemLayer.privacyTypeLayer
|
||||||
leftShadowLayer = itemLayer.leftShadowLayer
|
leftShadowLayer = itemLayer.leftShadowLayer
|
||||||
rightShadowLayer = itemLayer.rightShadowLayer
|
rightShadowLayer = itemLayer.rightShadowLayer
|
||||||
|
topRightShadowLayer = itemLayer.topRightShadowLayer
|
||||||
self.layer.contents = itemLayer.contents
|
self.layer.contents = itemLayer.contents
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,6 +678,17 @@ private final class ItemTransitionView: UIView {
|
|||||||
self.copyRightShadowLayer = copyLayer
|
self.copyRightShadowLayer = copyLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let topRightShadowLayer {
|
||||||
|
let copyLayer = SimpleLayer()
|
||||||
|
copyLayer.contents = topRightShadowLayer.contents
|
||||||
|
copyLayer.contentsRect = topRightShadowLayer.contentsRect
|
||||||
|
copyLayer.contentsGravity = topRightShadowLayer.contentsGravity
|
||||||
|
copyLayer.contentsScale = topRightShadowLayer.contentsScale
|
||||||
|
copyLayer.frame = topRightShadowLayer.frame
|
||||||
|
self.layer.addSublayer(copyLayer)
|
||||||
|
self.copyTopRightShadowLayer = copyLayer
|
||||||
|
}
|
||||||
|
|
||||||
if let viewCountLayer {
|
if let viewCountLayer {
|
||||||
let copyViewCountLayer = SimpleLayer()
|
let copyViewCountLayer = SimpleLayer()
|
||||||
copyViewCountLayer.contents = viewCountLayer.contents
|
copyViewCountLayer.contents = viewCountLayer.contents
|
||||||
@ -550,6 +702,19 @@ private final class ItemTransitionView: UIView {
|
|||||||
self.viewCountLayerBottomLeftPosition = CGPoint(x: viewCountLayer.frame.minX, y: itemLayer.bounds.height - viewCountLayer.frame.maxY)
|
self.viewCountLayerBottomLeftPosition = CGPoint(x: viewCountLayer.frame.minX, y: itemLayer.bounds.height - viewCountLayer.frame.maxY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let privacyTypeLayer {
|
||||||
|
let copyPrivacyTypeLayer = SimpleLayer()
|
||||||
|
copyPrivacyTypeLayer.contents = privacyTypeLayer.contents
|
||||||
|
copyPrivacyTypeLayer.contentsRect = privacyTypeLayer.contentsRect
|
||||||
|
copyPrivacyTypeLayer.contentsGravity = privacyTypeLayer.contentsGravity
|
||||||
|
copyPrivacyTypeLayer.contentsScale = privacyTypeLayer.contentsScale
|
||||||
|
copyPrivacyTypeLayer.frame = privacyTypeLayer.frame
|
||||||
|
self.layer.addSublayer(copyPrivacyTypeLayer)
|
||||||
|
self.copyPrivacyTypeLayer = copyPrivacyTypeLayer
|
||||||
|
|
||||||
|
self.privacyTypeLayerTopRightPosition = CGPoint(x: itemLayer.bounds.width - privacyTypeLayer.frame.maxX, y: privacyTypeLayer.frame.minY)
|
||||||
|
}
|
||||||
|
|
||||||
if let durationLayer {
|
if let durationLayer {
|
||||||
let copyDurationLayer = SimpleLayer()
|
let copyDurationLayer = SimpleLayer()
|
||||||
copyDurationLayer.contents = durationLayer.contents
|
copyDurationLayer.contents = durationLayer.contents
|
||||||
@ -576,8 +741,12 @@ private final class ItemTransitionView: UIView {
|
|||||||
transition.setFrame(layer: copyDurationLayer, frame: CGRect(origin: CGPoint(x: size.width - durationLayerBottomLeftPosition.x - copyDurationLayer.bounds.width, y: size.height - durationLayerBottomLeftPosition.y - copyDurationLayer.bounds.height), size: copyDurationLayer.bounds.size))
|
transition.setFrame(layer: copyDurationLayer, frame: CGRect(origin: CGPoint(x: size.width - durationLayerBottomLeftPosition.x - copyDurationLayer.bounds.width, y: size.height - durationLayerBottomLeftPosition.y - copyDurationLayer.bounds.height), size: copyDurationLayer.bounds.size))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let copyViewCountLayer = self.copyViewCountLayer, let viewcountLayerBottomLeftPosition = self.viewCountLayerBottomLeftPosition {
|
if let copyViewCountLayer = self.copyViewCountLayer, let viewCountLayerBottomLeftPosition = self.viewCountLayerBottomLeftPosition {
|
||||||
transition.setFrame(layer: copyViewCountLayer, frame: CGRect(origin: CGPoint(x: viewcountLayerBottomLeftPosition.x, y: size.height - viewcountLayerBottomLeftPosition.y - copyViewCountLayer.bounds.height), size: copyViewCountLayer.bounds.size))
|
transition.setFrame(layer: copyViewCountLayer, frame: CGRect(origin: CGPoint(x: viewCountLayerBottomLeftPosition.x, y: size.height - viewCountLayerBottomLeftPosition.y - copyViewCountLayer.bounds.height), size: copyViewCountLayer.bounds.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let privacyTypeLayer = self.copyPrivacyTypeLayer, let privacyTypeLayerTopRightPosition = self.privacyTypeLayerTopRightPosition {
|
||||||
|
transition.setFrame(layer: privacyTypeLayer, frame: CGRect(origin: CGPoint(x: size.width - privacyTypeLayerTopRightPosition.x, y: privacyTypeLayerTopRightPosition.y), size: privacyTypeLayer.bounds.size))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let copyLeftShadowLayer = self.copyLeftShadowLayer {
|
if let copyLeftShadowLayer = self.copyLeftShadowLayer {
|
||||||
@ -587,6 +756,10 @@ private final class ItemTransitionView: UIView {
|
|||||||
if let copyRightShadowLayer = self.copyRightShadowLayer {
|
if let copyRightShadowLayer = self.copyRightShadowLayer {
|
||||||
transition.setFrame(layer: copyRightShadowLayer, frame: CGRect(origin: CGPoint(x: size.width - copyRightShadowLayer.bounds.width, y: size.height - copyRightShadowLayer.bounds.height), size: copyRightShadowLayer.bounds.size))
|
transition.setFrame(layer: copyRightShadowLayer, frame: CGRect(origin: CGPoint(x: size.width - copyRightShadowLayer.bounds.width, y: size.height - copyRightShadowLayer.bounds.height), size: copyRightShadowLayer.bounds.size))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let copyTopRightShadowLayer = self.copyTopRightShadowLayer {
|
||||||
|
transition.setFrame(layer: copyTopRightShadowLayer, frame: CGRect(origin: CGPoint(x: size.width - copyTopRightShadowLayer.bounds.width, y: 0.0), size: copyTopRightShadowLayer.bounds.size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,6 +768,7 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
|
|||||||
let chatLocation: ChatLocation
|
let chatLocation: ChatLocation
|
||||||
let directMediaImageCache: DirectMediaImageCache
|
let directMediaImageCache: DirectMediaImageCache
|
||||||
let captureProtected: Bool
|
let captureProtected: Bool
|
||||||
|
let displayPrivacy: Bool
|
||||||
var strings: PresentationStrings
|
var strings: PresentationStrings
|
||||||
var chatPresentationData: ChatPresentationData
|
var chatPresentationData: ChatPresentationData
|
||||||
var checkNodeTheme: CheckNodeTheme
|
var checkNodeTheme: CheckNodeTheme
|
||||||
@ -613,11 +787,12 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
|
|||||||
|
|
||||||
private var shimmerImages: [CGFloat: UIImage] = [:]
|
private var shimmerImages: [CGFloat: UIImage] = [:]
|
||||||
|
|
||||||
init(context: AccountContext, chatLocation: ChatLocation, directMediaImageCache: DirectMediaImageCache, captureProtected: Bool) {
|
init(context: AccountContext, chatLocation: ChatLocation, directMediaImageCache: DirectMediaImageCache, captureProtected: Bool, displayPrivacy: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
self.directMediaImageCache = directMediaImageCache
|
self.directMediaImageCache = directMediaImageCache
|
||||||
self.captureProtected = false
|
self.captureProtected = false
|
||||||
|
self.displayPrivacy = displayPrivacy
|
||||||
|
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self.strings = presentationData.strings
|
self.strings = presentationData.strings
|
||||||
@ -794,6 +969,11 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
|
|||||||
viewCount = Int32(value)
|
viewCount = Int32(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var privacyType: EngineStoryPrivacy.Base?
|
||||||
|
if self.displayPrivacy, let value = story.privacy {
|
||||||
|
privacyType = value.base
|
||||||
|
}
|
||||||
|
|
||||||
var duration: Int32?
|
var duration: Int32?
|
||||||
var isMin: Bool = false
|
var isMin: Bool = false
|
||||||
if let file = selectedMedia as? TelegramMediaFile, !file.isAnimated {
|
if let file = selectedMedia as? TelegramMediaFile, !file.isAnimated {
|
||||||
@ -802,7 +982,7 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
|
|||||||
}
|
}
|
||||||
isMin = layer.bounds.width < 80.0
|
isMin = layer.bounds.width < 80.0
|
||||||
}
|
}
|
||||||
layer.updateDuration(viewCount: viewCount, duration: duration, isMin: isMin, minFactor: min(1.0, layer.bounds.height / 74.0))
|
layer.updateDuration(viewCount: viewCount, duration: duration, privacy: privacyType, isMin: isMin, minFactor: min(1.0, layer.bounds.height / 74.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
var isSelected: Bool?
|
var isSelected: Bool?
|
||||||
@ -895,6 +1075,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
private let chatLocation: ChatLocation
|
private let chatLocation: ChatLocation
|
||||||
private let isSaved: Bool
|
private let isSaved: Bool
|
||||||
private let isArchive: Bool
|
private let isArchive: Bool
|
||||||
|
private let isProfileEmbedded: Bool
|
||||||
public private(set) var contentType: ContentType
|
public private(set) var contentType: ContentType
|
||||||
private var contentTypePromise: ValuePromise<ContentType>
|
private var contentTypePromise: ValuePromise<ContentType>
|
||||||
|
|
||||||
@ -1002,7 +1183,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
|
|
||||||
private var emptyStateView: ComponentView<Empty>?
|
private var emptyStateView: ComponentView<Empty>?
|
||||||
|
|
||||||
public init(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, contentType: ContentType, captureProtected: Bool, isSaved: Bool, isArchive: Bool, navigationController: @escaping () -> NavigationController?, listContext: PeerStoryListContext?) {
|
public init(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, contentType: ContentType, captureProtected: Bool, isSaved: Bool, isArchive: Bool, isProfileEmbedded: Bool, navigationController: @escaping () -> NavigationController?, listContext: PeerStoryListContext?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
@ -1011,6 +1192,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.navigationController = navigationController
|
self.navigationController = navigationController
|
||||||
self.isSaved = isSaved
|
self.isSaved = isSaved
|
||||||
self.isArchive = isArchive
|
self.isArchive = isArchive
|
||||||
|
self.isProfileEmbedded = isProfileEmbedded
|
||||||
|
|
||||||
self.isSelectionModeActive = isArchive
|
self.isSelectionModeActive = isArchive
|
||||||
|
|
||||||
@ -1024,7 +1206,8 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
context: context,
|
context: context,
|
||||||
chatLocation: .peer(id: peerId),
|
chatLocation: .peer(id: peerId),
|
||||||
directMediaImageCache: self.directMediaImageCache,
|
directMediaImageCache: self.directMediaImageCache,
|
||||||
captureProtected: captureProtected
|
captureProtected: captureProtected,
|
||||||
|
displayPrivacy: isProfileEmbedded && !self.isArchive
|
||||||
)
|
)
|
||||||
|
|
||||||
self.listSource = listContext ?? PeerStoryListContext(account: context.account, peerId: peerId, isArchived: self.isArchive)
|
self.listSource = listContext ?? PeerStoryListContext(account: context.account, peerId: peerId, isArchived: self.isArchive)
|
||||||
@ -1421,7 +1604,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
strongSelf.itemGrid.cancelGestures()
|
strongSelf.itemGrid.cancelGestures()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.statusPromise.set(.single(PeerInfoStatusData(text: "", isActivity: false, key: .stories)))
|
self.statusPromise.set(.single(PeerInfoStatusData(text: "", isActivity: false, key: self.isArchive ? .storyArchive : .stories)))
|
||||||
|
|
||||||
/*self.storedStateDisposable = (visualMediaStoredState(engine: context.engine, peerId: peerId, messageTag: self.stateTag)
|
/*self.storedStateDisposable = (visualMediaStoredState(engine: context.engine, peerId: peerId, messageTag: self.stateTag)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
@ -1671,11 +1854,13 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
} else {
|
} else {
|
||||||
if self.isSaved {
|
if self.isSaved {
|
||||||
title = self.presentationData.strings.StoryList_SubtitleSaved(Int32(state.totalCount))
|
title = self.presentationData.strings.StoryList_SubtitleSaved(Int32(state.totalCount))
|
||||||
|
} else if self.isArchive {
|
||||||
|
title = self.presentationData.strings.StoryList_SubtitleArchived(Int32(state.totalCount))
|
||||||
} else {
|
} else {
|
||||||
title = self.presentationData.strings.StoryList_SubtitleCount(Int32(state.totalCount))
|
title = self.presentationData.strings.StoryList_SubtitleCount(Int32(state.totalCount))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.statusPromise.set(.single(PeerInfoStatusData(text: title, isActivity: false, key: .stories)))
|
self.statusPromise.set(.single(PeerInfoStatusData(text: title, isActivity: false, key: self.isArchive ? .storyArchive : .stories)))
|
||||||
|
|
||||||
let timezoneOffset = Int32(TimeZone.current.secondsFromGMT())
|
let timezoneOffset = Int32(TimeZone.current.secondsFromGMT())
|
||||||
|
|
||||||
@ -1952,12 +2137,19 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
itemLayer.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: self.itemInteraction.selectedIds?.contains(item.story.id), animated: animated)
|
itemLayer.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: self.itemInteraction.selectedIds?.contains(item.story.id), animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
let isSelecting = self._itemInteraction?.selectedIds != nil
|
var isSelecting = false
|
||||||
|
if let selectedIds = self._itemInteraction?.selectedIds, !selectedIds.isEmpty {
|
||||||
|
isSelecting = true
|
||||||
|
}
|
||||||
self.itemGrid.pinchEnabled = !isSelecting
|
self.itemGrid.pinchEnabled = !isSelecting
|
||||||
|
|
||||||
var enableDismissGesture = true
|
var enableDismissGesture = true
|
||||||
if let items = self.items, items.items.isEmpty {
|
if self.isProfileEmbedded {
|
||||||
} else if isSelecting {
|
enableDismissGesture = true
|
||||||
|
} else if let items = self.items, items.items.isEmpty {
|
||||||
|
}
|
||||||
|
|
||||||
|
if isSelecting {
|
||||||
enableDismissGesture = false
|
enableDismissGesture = false
|
||||||
}
|
}
|
||||||
self.view.disablesInteractiveTransitionGestureRecognizer = !enableDismissGesture
|
self.view.disablesInteractiveTransitionGestureRecognizer = !enableDismissGesture
|
||||||
@ -2030,6 +2222,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
component: AnyComponent(EmptyStateIndicatorComponent(
|
component: AnyComponent(EmptyStateIndicatorComponent(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
theme: presentationData.theme,
|
theme: presentationData.theme,
|
||||||
|
fitToHeight: self.isProfileEmbedded,
|
||||||
animationName: "StoryListEmpty",
|
animationName: "StoryListEmpty",
|
||||||
title: self.isArchive ? presentationData.strings.StoryList_ArchivedEmptyState_Title : presentationData.strings.StoryList_SavedEmptyPosts_Title,
|
title: self.isArchive ? presentationData.strings.StoryList_ArchivedEmptyState_Title : presentationData.strings.StoryList_SavedEmptyPosts_Title,
|
||||||
text: self.isArchive ? presentationData.strings.StoryList_ArchivedEmptyState_Text : presentationData.strings.StoryList_SavedEmptyPosts_Text,
|
text: self.isArchive ? presentationData.strings.StoryList_ArchivedEmptyState_Text : presentationData.strings.StoryList_SavedEmptyPosts_Text,
|
||||||
@ -2040,7 +2233,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
self.emptyAction?()
|
self.emptyAction?()
|
||||||
},
|
},
|
||||||
additionalActionTitle: self.isArchive ? nil : presentationData.strings.StoryList_SavedEmptyAction,
|
additionalActionTitle: (self.isArchive || self.isProfileEmbedded) ? nil : presentationData.strings.StoryList_SavedEmptyAction,
|
||||||
additionalAction: { [weak self] in
|
additionalAction: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -2051,6 +2244,14 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: size.width, height: size.height - topInset - bottomInset)
|
containerSize: CGSize(width: size.width, height: size.height - topInset - bottomInset)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let emptyStateFrame: CGRect
|
||||||
|
if self.isProfileEmbedded {
|
||||||
|
emptyStateFrame = CGRect(origin: CGPoint(x: floor((size.width - emptyStateSize.width) * 0.5), y: max(topInset, floor((visibleHeight - topInset - bottomInset - emptyStateSize.height) * 0.5))), size: emptyStateSize)
|
||||||
|
} else {
|
||||||
|
emptyStateFrame = CGRect(origin: CGPoint(x: floor((size.width - emptyStateSize.width) * 0.5), y: topInset), size: emptyStateSize)
|
||||||
|
}
|
||||||
|
|
||||||
if let emptyStateComponentView = emptyStateView.view {
|
if let emptyStateComponentView = emptyStateView.view {
|
||||||
if emptyStateComponentView.superview == nil {
|
if emptyStateComponentView.superview == nil {
|
||||||
self.view.addSubview(emptyStateComponentView)
|
self.view.addSubview(emptyStateComponentView)
|
||||||
@ -2058,12 +2259,20 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
emptyStateComponentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
emptyStateComponentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emptyStateTransition.setFrame(view: emptyStateComponentView, frame: CGRect(origin: CGPoint(x: floor((size.width - emptyStateSize.width) * 0.5), y: topInset), size: emptyStateSize))
|
emptyStateTransition.setFrame(view: emptyStateComponentView, frame: emptyStateFrame)
|
||||||
}
|
}
|
||||||
if self.didUpdateItemsOnce {
|
|
||||||
Transition(animation: .curve(duration: 0.2, curve: .easeInOut)).setBackgroundColor(view: self.view, color: presentationData.theme.list.blocksBackgroundColor)
|
let backgroundColor: UIColor
|
||||||
|
if self.isProfileEmbedded {
|
||||||
|
backgroundColor = presentationData.theme.list.plainBackgroundColor
|
||||||
} else {
|
} else {
|
||||||
self.view.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.didUpdateItemsOnce {
|
||||||
|
Transition(animation: .curve(duration: 0.2, curve: .easeInOut)).setBackgroundColor(view: self.view, color: backgroundColor)
|
||||||
|
} else {
|
||||||
|
self.view.backgroundColor = backgroundColor
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let emptyStateView = self.emptyStateView {
|
if let emptyStateView = self.emptyStateView {
|
||||||
@ -2076,7 +2285,11 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.isProfileEmbedded {
|
||||||
|
subTransition.setBackgroundColor(view: self.view, color: presentationData.theme.list.plainBackgroundColor)
|
||||||
|
} else {
|
||||||
subTransition.setBackgroundColor(view: self.view, color: presentationData.theme.list.blocksBackgroundColor)
|
subTransition.setBackgroundColor(view: self.view, color: presentationData.theme.list.blocksBackgroundColor)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.view.backgroundColor = .clear
|
self.view.backgroundColor = .clear
|
||||||
}
|
}
|
||||||
|
@ -1463,7 +1463,9 @@ final class AutomaticBusinessMessageSetupScreenComponent: Component {
|
|||||||
values: valueList.map { item in
|
values: valueList.map { item in
|
||||||
return environment.strings.MessageTimer_Days(Int32(item))
|
return environment.strings.MessageTimer_Days(Int32(item))
|
||||||
},
|
},
|
||||||
|
markPositions: true,
|
||||||
selectedIndex: selectedInactivityIndex,
|
selectedIndex: selectedInactivityIndex,
|
||||||
|
title: nil,
|
||||||
selectedIndexUpdated: { [weak self] index in
|
selectedIndexUpdated: { [weak self] index in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
|
@ -9,6 +9,7 @@ import ComponentFlow
|
|||||||
public final class SliderComponent: Component {
|
public final class SliderComponent: Component {
|
||||||
public let valueCount: Int
|
public let valueCount: Int
|
||||||
public let value: Int
|
public let value: Int
|
||||||
|
public let markPositions: Bool
|
||||||
public let trackBackgroundColor: UIColor
|
public let trackBackgroundColor: UIColor
|
||||||
public let trackForegroundColor: UIColor
|
public let trackForegroundColor: UIColor
|
||||||
public let valueUpdated: (Int) -> Void
|
public let valueUpdated: (Int) -> Void
|
||||||
@ -17,6 +18,7 @@ public final class SliderComponent: Component {
|
|||||||
public init(
|
public init(
|
||||||
valueCount: Int,
|
valueCount: Int,
|
||||||
value: Int,
|
value: Int,
|
||||||
|
markPositions: Bool,
|
||||||
trackBackgroundColor: UIColor,
|
trackBackgroundColor: UIColor,
|
||||||
trackForegroundColor: UIColor,
|
trackForegroundColor: UIColor,
|
||||||
valueUpdated: @escaping (Int) -> Void,
|
valueUpdated: @escaping (Int) -> Void,
|
||||||
@ -24,6 +26,7 @@ public final class SliderComponent: Component {
|
|||||||
) {
|
) {
|
||||||
self.valueCount = valueCount
|
self.valueCount = valueCount
|
||||||
self.value = value
|
self.value = value
|
||||||
|
self.markPositions = markPositions
|
||||||
self.trackBackgroundColor = trackBackgroundColor
|
self.trackBackgroundColor = trackBackgroundColor
|
||||||
self.trackForegroundColor = trackForegroundColor
|
self.trackForegroundColor = trackForegroundColor
|
||||||
self.valueUpdated = valueUpdated
|
self.valueUpdated = valueUpdated
|
||||||
@ -37,6 +40,9 @@ public final class SliderComponent: Component {
|
|||||||
if lhs.value != rhs.value {
|
if lhs.value != rhs.value {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.markPositions != rhs.markPositions {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.trackBackgroundColor != rhs.trackBackgroundColor {
|
if lhs.trackBackgroundColor != rhs.trackBackgroundColor {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -97,6 +103,7 @@ public final class SliderComponent: Component {
|
|||||||
sliderView.maximumValue = CGFloat(component.valueCount - 1)
|
sliderView.maximumValue = CGFloat(component.valueCount - 1)
|
||||||
sliderView.positionsCount = component.valueCount
|
sliderView.positionsCount = component.valueCount
|
||||||
sliderView.useLinesForPositions = true
|
sliderView.useLinesForPositions = true
|
||||||
|
sliderView.markPositions = component.markPositions
|
||||||
|
|
||||||
sliderView.backgroundColor = nil
|
sliderView.backgroundColor = nil
|
||||||
sliderView.isOpaque = false
|
sliderView.isOpaque = false
|
||||||
|
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Profile.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Profile.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "profile.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
231
submodules/TelegramUI/Images.xcassets/Settings/Menu/Profile.imageset/profile.pdf
vendored
Normal file
231
submodules/TelegramUI/Images.xcassets/Settings/Menu/Profile.imageset/profile.pdf
vendored
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< /Type /XObject
|
||||||
|
/Length 2 0 R
|
||||||
|
/Group << /Type /Group
|
||||||
|
/S /Transparency
|
||||||
|
>>
|
||||||
|
/Subtype /Form
|
||||||
|
/Resources << >>
|
||||||
|
/BBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||||
|
1.000000 0.176471 0.333333 scn
|
||||||
|
0.000000 18.799999 m
|
||||||
|
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
|
||||||
|
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
|
||||||
|
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
|
||||||
|
18.799999 30.000000 l
|
||||||
|
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
|
||||||
|
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
|
||||||
|
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
|
||||||
|
30.000000 11.200001 l
|
||||||
|
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
|
||||||
|
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
|
||||||
|
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
|
||||||
|
11.200000 0.000000 l
|
||||||
|
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||||
|
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||||
|
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
|
||||||
|
0.000000 18.799999 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 5.000000 5.000000 cm
|
||||||
|
1.000000 1.000000 1.000000 scn
|
||||||
|
17.165209 3.024336 m
|
||||||
|
18.919451 4.825943 20.000000 7.286784 20.000000 10.000000 c
|
||||||
|
20.000000 15.522848 15.522847 20.000000 10.000000 20.000000 c
|
||||||
|
4.477152 20.000000 0.000000 15.522848 0.000000 10.000000 c
|
||||||
|
0.000000 7.286821 1.080519 4.826013 2.834717 3.024412 c
|
||||||
|
2.877964 3.183798 2.941688 3.345104 3.027704 3.506973 c
|
||||||
|
3.983309 5.305289 5.950467 7.156250 9.999956 7.156250 c
|
||||||
|
14.049442 7.156250 16.016598 5.305290 16.972202 3.506973 c
|
||||||
|
17.058231 3.345078 17.121962 3.183746 17.165209 3.024336 c
|
||||||
|
h
|
||||||
|
11.770506 0.156250 m
|
||||||
|
8.229494 0.156250 l
|
||||||
|
8.804153 0.053581 9.395820 0.000000 10.000000 0.000000 c
|
||||||
|
10.604180 0.000000 11.195847 0.053581 11.770506 0.156250 c
|
||||||
|
h
|
||||||
|
13.499953 12.843750 m
|
||||||
|
13.499953 10.910753 11.932950 9.343750 9.999953 9.343750 c
|
||||||
|
8.066957 9.343750 6.499953 10.910753 6.499953 12.843750 c
|
||||||
|
6.499953 14.776747 8.066957 16.343750 9.999953 16.343750 c
|
||||||
|
11.932950 16.343750 13.499953 14.776747 13.499953 12.843750 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
25.000000 15.000000 m
|
||||||
|
25.000000 9.477154 20.522846 5.000000 15.000000 5.000000 c
|
||||||
|
9.477152 5.000000 5.000000 9.477154 5.000000 15.000000 c
|
||||||
|
5.000000 20.522848 9.477152 25.000000 15.000000 25.000000 c
|
||||||
|
20.522846 25.000000 25.000000 20.522848 25.000000 15.000000 c
|
||||||
|
h
|
||||||
|
W*
|
||||||
|
n
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 5.000000 5.000000 cm
|
||||||
|
1.000000 1.000000 1.000000 scn
|
||||||
|
18.670000 10.000000 m
|
||||||
|
18.670000 5.211691 14.788309 1.330000 10.000000 1.330000 c
|
||||||
|
10.000000 -1.330000 l
|
||||||
|
16.257387 -1.330000 21.330000 3.742613 21.330000 10.000000 c
|
||||||
|
18.670000 10.000000 l
|
||||||
|
h
|
||||||
|
10.000000 1.330000 m
|
||||||
|
5.211691 1.330000 1.330000 5.211691 1.330000 10.000000 c
|
||||||
|
-1.330000 10.000000 l
|
||||||
|
-1.330000 3.742613 3.742614 -1.330000 10.000000 -1.330000 c
|
||||||
|
10.000000 1.330000 l
|
||||||
|
h
|
||||||
|
1.330000 10.000000 m
|
||||||
|
1.330000 14.788309 5.211691 18.670000 10.000000 18.670000 c
|
||||||
|
10.000000 21.330000 l
|
||||||
|
3.742614 21.330000 -1.330000 16.257385 -1.330000 10.000000 c
|
||||||
|
1.330000 10.000000 l
|
||||||
|
h
|
||||||
|
10.000000 18.670000 m
|
||||||
|
14.788309 18.670000 18.670000 14.788309 18.670000 10.000000 c
|
||||||
|
21.330000 10.000000 l
|
||||||
|
21.330000 16.257385 16.257387 21.330000 10.000000 21.330000 c
|
||||||
|
10.000000 18.670000 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
3071
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
<< /Type /XObject
|
||||||
|
/Length 4 0 R
|
||||||
|
/Group << /Type /Group
|
||||||
|
/S /Transparency
|
||||||
|
>>
|
||||||
|
/Subtype /Form
|
||||||
|
/Resources << >>
|
||||||
|
/BBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 18.799999 m
|
||||||
|
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
|
||||||
|
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
|
||||||
|
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
|
||||||
|
18.799999 30.000000 l
|
||||||
|
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
|
||||||
|
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
|
||||||
|
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
|
||||||
|
30.000000 11.200001 l
|
||||||
|
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
|
||||||
|
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
|
||||||
|
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
|
||||||
|
11.200000 0.000000 l
|
||||||
|
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||||
|
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||||
|
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
|
||||||
|
0.000000 18.799999 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
944
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /XObject << /X1 1 0 R >>
|
||||||
|
/ExtGState << /E1 << /SMask << /Type /Mask
|
||||||
|
/G 3 0 R
|
||||||
|
/S /Alpha
|
||||||
|
>>
|
||||||
|
/Type /ExtGState
|
||||||
|
>> >>
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Length 7 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
/E1 gs
|
||||||
|
/X1 Do
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
7 0 obj
|
||||||
|
46
|
||||||
|
endobj
|
||||||
|
|
||||||
|
8 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
/Resources 5 0 R
|
||||||
|
/Contents 6 0 R
|
||||||
|
/Parent 9 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
9 0 obj
|
||||||
|
<< /Kids [ 8 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
10 0 obj
|
||||||
|
<< /Pages 9 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 11
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000003329 00000 n
|
||||||
|
0000003352 00000 n
|
||||||
|
0000004544 00000 n
|
||||||
|
0000004566 00000 n
|
||||||
|
0000004864 00000 n
|
||||||
|
0000004966 00000 n
|
||||||
|
0000004987 00000 n
|
||||||
|
0000005160 00000 n
|
||||||
|
0000005234 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 10 0 R
|
||||||
|
/Size 11
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
5294
|
||||||
|
%%EOF
|
Loading…
x
Reference in New Issue
Block a user