This commit is contained in:
Ali 2023-08-10 19:10:03 +04:00
parent c9772c5fd7
commit 28bd7511a6
6 changed files with 438 additions and 291 deletions

View File

@ -178,6 +178,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case storiesDualCameraTooltip = 44 case storiesDualCameraTooltip = 44
case displayChatListArchiveTooltip = 45 case displayChatListArchiveTooltip = 45
case displayStoryReactionTooltip = 46 case displayStoryReactionTooltip = 46
case storyStealthModeReplyCount = 47
var key: ValueBoxKey { var key: ValueBoxKey {
let v = ValueBoxKey(length: 4) let v = ValueBoxKey(length: 4)
@ -419,6 +420,10 @@ private struct ApplicationSpecificNoticeKeys {
static func displayStoryReactionTooltip() -> NoticeEntryKey { static func displayStoryReactionTooltip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.displayStoryReactionTooltip.key) return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.displayStoryReactionTooltip.key)
} }
static func storyStealthModeReplyCount() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.storyStealthModeReplyCount.key)
}
} }
public struct ApplicationSpecificNotice { public struct ApplicationSpecificNotice {
@ -1580,4 +1585,30 @@ public struct ApplicationSpecificNotice {
} }
|> ignoreValues |> ignoreValues
} }
public static func storyStealthModeReplyCount(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int, NoError> {
return accountManager.noticeEntry(key: ApplicationSpecificNoticeKeys.storyStealthModeReplyCount())
|> map { view -> Int in
if let value = view.value?.get(ApplicationSpecificCounterNotice.self) {
return Int(value.value)
} else {
return 0
}
}
|> take(1)
}
public static func incrementStoryStealthModeReplyCount(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Never, NoError> {
return accountManager.transaction { transaction -> Void in
var value: Int32 = 0
if let item = transaction.getNotice(ApplicationSpecificNoticeKeys.storyStealthModeReplyCount())?.get(ApplicationSpecificCounterNotice.self) {
value = item.value
}
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value + 1)) {
transaction.setNotice(ApplicationSpecificNoticeKeys.storyStealthModeReplyCount(), entry)
}
}
|> ignoreValues
}
} }

View File

@ -90,7 +90,7 @@ public final class OptionButtonComponent: Component {
self.component = component self.component = component
let size = CGSize(width: 52.0, height: 28.0) let size = CGSize(width: 53.0, height: 28.0)
if previousComponent?.colors.background != component.colors.background { if previousComponent?.colors.background != component.colors.background {
self.backgroundView.image = generateStretchableFilledCircleImage(diameter: size.height, color: component.colors.background) self.backgroundView.image = generateStretchableFilledCircleImage(diameter: size.height, color: component.colors.background)
@ -121,8 +121,8 @@ public final class OptionButtonComponent: Component {
} }
if let iconSize = self.iconView.image?.size, let arrowSize = self.arrowView.image?.size { if let iconSize = self.iconView.image?.size, let arrowSize = self.arrowView.image?.size {
transition.setFrame(view: self.iconView, frame: CGRect(origin: CGPoint(x: 3.0, y: floor((size.height - iconSize.height) * 0.5)), size: iconSize)) transition.setFrame(view: self.iconView, frame: CGRect(origin: CGPoint(x: 4.0, y: floor((size.height - iconSize.height) * 0.5)), size: iconSize))
transition.setFrame(view: self.arrowView, frame: CGRect(origin: CGPoint(x: size.width - 8.0 - arrowSize.width, y: floor((size.height - arrowSize.height) * 0.5)), size: arrowSize)) transition.setFrame(view: self.arrowView, frame: CGRect(origin: CGPoint(x: size.width - 8.0 - arrowSize.width, y: 1.0 + floor((size.height - arrowSize.height) * 0.5)), size: arrowSize))
} }
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: size)) transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: size))

View File

@ -541,7 +541,13 @@ public final class StoryItemSetContainerComponent: Component {
guard let self else { guard let self else {
return [] return []
} }
let _ = self
if self.itemsContainerView.frame.contains(point) {
if !self.isPointInsideContentArea(point: point) {
return []
}
}
return [.down] return [.down]
}) })
verticalPanRecognizer.delegate = self verticalPanRecognizer.delegate = self
@ -1029,6 +1035,14 @@ public final class StoryItemSetContainerComponent: Component {
} }
verticalPanState.startContentOffsetY = recognizer.translation(in: self).y verticalPanState.startContentOffsetY = recognizer.translation(in: self).y
} else {
if verticalPanState.fraction <= -0.15 {
if let activate = self.activateInputWhileDragging() {
recognizer.state = .cancelled
activate()
}
}
} }
self.state?.updated(transition: .immediate) self.state?.updated(transition: .immediate)
@ -1268,7 +1282,7 @@ public final class StoryItemSetContainerComponent: Component {
let currentContentScale = itemLayout.contentMinScale * itemLayout.contentScaleFraction + 1.0 * (1.0 - itemLayout.contentScaleFraction) let currentContentScale = itemLayout.contentMinScale * itemLayout.contentScaleFraction + 1.0 * (1.0 - itemLayout.contentScaleFraction)
let scaledCentralVisibleItemWidth = itemLayout.contentFrame.width * currentContentScale let scaledCentralVisibleItemWidth = itemLayout.contentFrame.width * currentContentScale
let scaledSideVisibleItemWidth = scaledCentralVisibleItemWidth - 30.0 * itemLayout.contentScaleFraction let scaledSideVisibleItemWidth = scaledCentralVisibleItemWidth - 54.0 * itemLayout.contentScaleFraction
let scaledFullItemScrollDistance = scaledCentralVisibleItemWidth * 0.5 + itemLayout.itemSpacing + scaledSideVisibleItemWidth * 0.5 let scaledFullItemScrollDistance = scaledCentralVisibleItemWidth * 0.5 + itemLayout.itemSpacing + scaledSideVisibleItemWidth * 0.5
let scaledHalfItemScrollDistance = scaledSideVisibleItemWidth * 0.5 + itemLayout.itemSpacing + scaledSideVisibleItemWidth * 0.5 let scaledHalfItemScrollDistance = scaledSideVisibleItemWidth * 0.5 + itemLayout.itemSpacing + scaledSideVisibleItemWidth * 0.5
@ -3803,6 +3817,10 @@ public final class StoryItemSetContainerComponent: Component {
self.reactionContextNode = reactionContextNode self.reactionContextNode = reactionContextNode
reactionContextNode.reactionSelected = { [weak self] updateReaction, _ in reactionContextNode.reactionSelected = { [weak self] updateReaction, _ in
guard let self else {
return
}
let action: () -> Void = { [weak self] in
guard let self, let component = self.component else { guard let self, let component = self.component else {
return return
} }
@ -3936,6 +3954,21 @@ public final class StoryItemSetContainerComponent: Component {
} }
} }
if self.displayLikeReactions {
if component.slice.item.storyItem.myReaction == updateReaction.reaction {
action()
} else {
self.sendMessageContext.performWithPossibleStealthModeConfirmation(view: self, action: {
action()
})
}
} else {
self.sendMessageContext.performWithPossibleStealthModeConfirmation(view: self, action: {
action()
})
}
}
reactionContextNode.premiumReactionsSelected = { [weak self] file in reactionContextNode.premiumReactionsSelected = { [weak self] file in
guard let self, let component = self.component else { guard let self, let component = self.component else {
return return
@ -4805,6 +4838,11 @@ public final class StoryItemSetContainerComponent: Component {
guard let component = self.component else { guard let component = self.component else {
return return
} }
let action: () -> Void = { [weak self] in
guard let self, let component = self.component else {
return
}
guard let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View else { guard let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View else {
return return
} }
@ -4860,6 +4898,15 @@ public final class StoryItemSetContainerComponent: Component {
) )
} }
if component.slice.item.storyItem.myReaction != nil {
action()
} else {
self.sendMessageContext.performWithPossibleStealthModeConfirmation(view: self, action: {
action()
})
}
}
private func performLikeOptionsAction(sourceView: UIView) { private func performLikeOptionsAction(sourceView: UIView) {
HapticFeedback().tap() HapticFeedback().tap()

View File

@ -483,14 +483,74 @@ final class StoryItemSetContainerSendMessage {
view.updateIsProgressPaused() view.updateIsProgressPaused()
} }
func performWithPossibleStealthModeConfirmation(view: StoryItemSetContainerComponent.View, action: @escaping () -> Void) {
guard let component = view.component, component.stealthModeTimeout != nil else {
action()
return
}
let _ = (combineLatest(
component.context.engine.data.get(
TelegramEngine.EngineData.Item.Configuration.StoryConfigurationState()
),
ApplicationSpecificNotice.storyStealthModeReplyCount(accountManager: component.context.sharedContext.accountManager)
)
|> deliverOnMainQueue).start(next: { [weak self, weak view] data, noticeCount in
let config = data
guard let self, let view, let component = view.component else {
return
}
let timestamp = Int32(Date().timeIntervalSince1970)
if noticeCount < 3, let activeUntilTimestamp = config.stealthModeState.actualizedNow().activeUntilTimestamp, activeUntilTimestamp > timestamp {
let theme = component.theme
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
//TODO:localize
let alertController = textAlertController(
context: component.context,
updatedPresentationData: updatedPresentationData,
title: "You are in Stealth Mode now",
text: "If you send a reply or reaction, the creator of the story will also see you in the list of viewers.",
actions: [
TextAlertAction(type: .defaultAction, title: "Cancel", action: {}),
TextAlertAction(type: .genericAction, title: "Proceed", action: {
action()
})
]
)
alertController.dismissed = { [weak self, weak view] _ in
guard let self, let view else {
return
}
self.actionSheet = nil
view.updateIsProgressPaused()
}
self.actionSheet = alertController
view.updateIsProgressPaused()
component.controller()?.presentInGlobalOverlay(alertController)
} else {
action()
}
})
}
func performSendMessageAction( func performSendMessageAction(
view: StoryItemSetContainerComponent.View, view: StoryItemSetContainerComponent.View,
silentPosting: Bool = false, silentPosting: Bool = false,
scheduleTime: Int32? = nil scheduleTime: Int32? = nil
) { ) {
self.performWithPossibleStealthModeConfirmation(view: view, action: { [weak self, weak view] in
guard let self, let view else {
return
}
guard let component = view.component else { guard let component = view.component else {
return return
} }
let focusedItem = component.slice.item let focusedItem = component.slice.item
guard let peerId = focusedItem.peerId else { guard let peerId = focusedItem.peerId else {
return return
@ -549,9 +609,14 @@ final class StoryItemSetContainerSendMessage {
} }
} }
} }
})
} }
func performSendStickerAction(view: StoryItemSetContainerComponent.View, fileReference: FileMediaReference) { func performSendStickerAction(view: StoryItemSetContainerComponent.View, fileReference: FileMediaReference) {
self.performWithPossibleStealthModeConfirmation(view: view, action: { [weak self, weak view] in
guard let self, let view else {
return
}
guard let component = view.component else { guard let component = view.component else {
return return
} }
@ -602,6 +667,7 @@ final class StoryItemSetContainerSendMessage {
view.state?.updated(transition: .spring(duration: 0.3)) view.state?.updated(transition: .spring(duration: 0.3))
} }
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring)) controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
})
} }
func performSendContextResultAction(view: StoryItemSetContainerComponent.View, results: ChatContextResultCollection, result: ChatContextResult) { func performSendContextResultAction(view: StoryItemSetContainerComponent.View, results: ChatContextResultCollection, result: ChatContextResult) {

View File

@ -1139,7 +1139,10 @@ final class StoryItemSetViewListComponent: Component {
} }
let _ = self let _ = self
sourceView?.alpha = 1.0 if let sourceView {
let transition = Transition(animation: .curve(duration: 0.25, curve: .easeInOut))
transition.setAlpha(view: sourceView, alpha: 1.0)
}
} }
controller.present(contextController, in: .window(.root)) controller.present(contextController, in: .window(.root))
} }
@ -1170,7 +1173,7 @@ final class StoryItemSetViewListComponent: Component {
component: AnyComponent(TabSelectorComponent( component: AnyComponent(TabSelectorComponent(
colors: TabSelectorComponent.Colors( colors: TabSelectorComponent.Colors(
foreground: .white, foreground: .white,
selection: UIColor(rgb: 0xffffff, alpha: 0.2) selection: UIColor(rgb: 0xffffff, alpha: 0.09)
), ),
items: [ items: [
TabSelectorComponent.Item( TabSelectorComponent.Item(
@ -1220,7 +1223,7 @@ final class StoryItemSetViewListComponent: Component {
transition: transition, transition: transition,
component: AnyComponent(OptionButtonComponent( component: AnyComponent(OptionButtonComponent(
colors: OptionButtonComponent.Colors( colors: OptionButtonComponent.Colors(
background: UIColor(rgb: 0x767680, alpha: 0.2), background: UIColor(rgb: 0xffffff, alpha: 0.09),
foreground: .white foreground: .white
), ),
icon: self.sortMode == .recentFirst ? "Chat/Context Menu/Time" : "Chat/Context Menu/Reactions", icon: self.sortMode == .recentFirst ? "Chat/Context Menu/Time" : "Chat/Context Menu/Reactions",
@ -1281,11 +1284,11 @@ final class StoryItemSetViewListComponent: Component {
if !component.hasPremium, component.storyItem.expirationTimestamp <= Int32(Date().timeIntervalSince1970) { if !component.hasPremium, component.storyItem.expirationTimestamp <= Int32(Date().timeIntervalSince1970) {
} else { } else {
if let views = component.storyItem.views { if let views = component.storyItem.views {
if views.seenCount >= 20 { if views.seenCount >= 20 || component.context.sharedContext.immediateExperimentalUISettings.storiesExperiment {
displayModeSelector = true displayModeSelector = true
displaySearchBar = true displaySearchBar = true
} }
if views.reactedCount >= 10 { if views.reactedCount >= 10 || component.context.sharedContext.immediateExperimentalUISettings.storiesExperiment {
displaySortSelector = true displaySortSelector = true
} }
} }
@ -1299,9 +1302,9 @@ final class StoryItemSetViewListComponent: Component {
if component.isSearchActive { if component.isSearchActive {
navigationHeight = navigationSearchSize.height navigationHeight = navigationSearchSize.height
} else if displaySearchBar { } else if displaySearchBar {
navigationHeight = 50.0 + navigationSearchSize.height navigationHeight = 56.0 + navigationSearchSize.height - 6.0
} else { } else {
navigationHeight = 50.0 navigationHeight = 56.0
} }
let navigationBarFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - visualHeight + 12.0), size: CGSize(width: availableSize.width, height: navigationHeight)) let navigationBarFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - visualHeight + 12.0), size: CGSize(width: availableSize.width, height: navigationHeight))
@ -1313,7 +1316,7 @@ final class StoryItemSetViewListComponent: Component {
self.navigationContainerView.addSubview(tabSelectorView) self.navigationContainerView.addSubview(tabSelectorView)
} }
tabSelectorView.isHidden = !displayModeSelector tabSelectorView.isHidden = !displayModeSelector
transition.setFrame(view: tabSelectorView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - tabSelectorSize.width) * 0.5), y: floor((50.0 - tabSelectorSize.height) * 0.5) + (component.isSearchActive ? (-50.0) : 0.0)), size: tabSelectorSize)) transition.setFrame(view: tabSelectorView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - tabSelectorSize.width) * 0.5), y: floor((56.0 - tabSelectorSize.height) * 0.5) + (component.isSearchActive ? (-56.0) : 0.0)), size: tabSelectorSize))
transition.setAlpha(view: tabSelectorView, alpha: component.isSearchActive ? 0.0 : 1.0) transition.setAlpha(view: tabSelectorView, alpha: component.isSearchActive ? 0.0 : 1.0)
} }
if let titleView = self.title.view { if let titleView = self.title.view {
@ -1322,7 +1325,7 @@ final class StoryItemSetViewListComponent: Component {
} }
titleView.isHidden = displayModeSelector titleView.isHidden = displayModeSelector
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: floor((50.0 - titleSize.height) * 0.5) + (component.isSearchActive ? (-50.0) : 0.0)), size: titleSize) let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: floor((56.0 - titleSize.height) * 0.5) + (component.isSearchActive ? (-56.0) : 0.0)), size: titleSize)
transition.setFrame(view: titleView, frame: titleFrame) transition.setFrame(view: titleView, frame: titleFrame)
transition.setAlpha(view: titleView, alpha: component.isSearchActive ? 0.0 : 1.0) transition.setAlpha(view: titleView, alpha: component.isSearchActive ? 0.0 : 1.0)
@ -1332,7 +1335,7 @@ final class StoryItemSetViewListComponent: Component {
if orderSelectorView.superview == nil { if orderSelectorView.superview == nil {
self.navigationContainerView.addSubview(orderSelectorView) self.navigationContainerView.addSubview(orderSelectorView)
} }
transition.setFrame(view: orderSelectorView, frame: CGRect(origin: CGPoint(x: availableSize.width - sideInset - orderSelectorSize.width, y: floor((50.0 - orderSelectorSize.height) * 0.5) + (component.isSearchActive ? (-50.0) : 0.0)), size: orderSelectorSize)) transition.setFrame(view: orderSelectorView, frame: CGRect(origin: CGPoint(x: availableSize.width - sideInset - orderSelectorSize.width, y: floor((56.0 - orderSelectorSize.height) * 0.5) + (component.isSearchActive ? (-56.0) : 0.0)), size: orderSelectorSize))
transition.setAlpha(view: orderSelectorView, alpha: component.isSearchActive ? 0.0 : 1.0) transition.setAlpha(view: orderSelectorView, alpha: component.isSearchActive ? 0.0 : 1.0)
orderSelectorView.isHidden = !displaySortSelector orderSelectorView.isHidden = !displaySortSelector

View File

@ -155,7 +155,7 @@ public final class TabSelectorComponent: Component {
} }
itemTransition.setPosition(view: itemTitleView, position: itemTitleFrame.origin) itemTransition.setPosition(view: itemTitleView, position: itemTitleFrame.origin)
itemTransition.setBounds(view: itemTitleView, bounds: CGRect(origin: CGPoint(), size: itemTitleFrame.size)) itemTransition.setBounds(view: itemTitleView, bounds: CGRect(origin: CGPoint(), size: itemTitleFrame.size))
itemTransition.setAlpha(view: itemTitleView, alpha: item.id == component.selectedId ? 1.0 : 0.6) itemTransition.setAlpha(view: itemTitleView, alpha: item.id == component.selectedId ? 1.0 : 0.4)
} }
} }