[WIP] Post story from profile

This commit is contained in:
Ali 2023-09-18 18:59:34 +02:00
parent abb693587f
commit 1c960c816f
8 changed files with 164 additions and 23 deletions

View File

@ -796,7 +796,7 @@ public struct StoryCameraTransitionInCoordinator {
public protocol TelegramRootControllerInterface: NavigationController {
@discardableResult
func openStoryCamera(transitionIn: StoryCameraTransitionIn?, transitionedIn: @escaping () -> Void, transitionOut: @escaping (Stories.PendingTarget?, Bool) -> StoryCameraTransitionOut?) -> StoryCameraTransitionInCoordinator?
func openStoryCamera(customTarget: EnginePeer.Id?, transitionIn: StoryCameraTransitionIn?, transitionedIn: @escaping () -> Void, transitionOut: @escaping (Stories.PendingTarget?, Bool) -> StoryCameraTransitionOut?) -> StoryCameraTransitionInCoordinator?
func getContactsController() -> ViewController?
func getChatsController() -> ViewController?

View File

@ -2710,7 +2710,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
let coordinator = rootController.openStoryCamera(transitionIn: cameraTransitionIn, transitionedIn: {}, transitionOut: self.storyCameraTransitionOut())
let coordinator = rootController.openStoryCamera(customTarget: nil, transitionIn: cameraTransitionIn, transitionedIn: {}, transitionOut: self.storyCameraTransitionOut())
coordinator?.animateIn()
}
}
@ -5684,7 +5684,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
if let current = self.storyCameraTransitionInCoordinator {
coordinator = current
} else {
coordinator = rootController.openStoryCamera(transitionIn: nil, transitionedIn: {}, transitionOut: { [weak self] target, _ in
coordinator = rootController.openStoryCamera(customTarget: nil, transitionIn: nil, transitionedIn: {}, transitionOut: { [weak self] target, _ in
guard let self, let target else {
return nil
}

View File

@ -294,6 +294,7 @@ public enum PresentationResourceKey: Int32 {
case uploadToneIcon
case storyViewListLikeIcon
case navigationPostStoryIcon
}
public enum ChatExpiredStoryIndicatorType: Hashable {

View File

@ -169,4 +169,10 @@ public struct PresentationResourcesRootController {
})?.stretchableImage(withLeftCapWidth: Int(inset) + 15, topCapHeight: 8 * 2 + 15)
})
}
public static func navigationPostStoryIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPostStoryIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
}

View File

@ -203,6 +203,7 @@ final class PeerInfoScreenData {
let threadData: MessageHistoryThreadData?
let appConfiguration: AppConfiguration?
let isPowerSavingEnabled: Bool?
let accountIsPremium: Bool
let _isContact: Bool
var forceIsContact: Bool = false
@ -236,7 +237,8 @@ final class PeerInfoScreenData {
requestsContext: PeerInvitationImportersContext?,
threadData: MessageHistoryThreadData?,
appConfiguration: AppConfiguration?,
isPowerSavingEnabled: Bool?
isPowerSavingEnabled: Bool?,
accountIsPremium: Bool
) {
self.peer = peer
self.chatPeer = chatPeer
@ -259,6 +261,7 @@ final class PeerInfoScreenData {
self.threadData = threadData
self.appConfiguration = appConfiguration
self.isPowerSavingEnabled = isPowerSavingEnabled
self.accountIsPremium = accountIsPremium
}
}
@ -599,7 +602,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
requestsContext: nil,
threadData: nil,
appConfiguration: appConfiguration,
isPowerSavingEnabled: isPowerSavingEnabled
isPowerSavingEnabled: isPowerSavingEnabled,
accountIsPremium: peer?.isPremium ?? false
)
}
}
@ -632,7 +636,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
requestsContext: nil,
threadData: nil,
appConfiguration: nil,
isPowerSavingEnabled: nil
isPowerSavingEnabled: nil,
accountIsPremium: false
))
case let .user(userPeerId, secretChatId, kind):
let groupsInCommon: GroupsInCommonContext?
@ -741,15 +746,22 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
|> distinctUntilChanged
let accountIsPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|> map { peer -> Bool in
return peer?.isPremium ?? false
}
|> distinctUntilChanged
return combineLatest(
context.account.viewTracker.peerView(peerId, updateData: true),
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
secretChatKeyFingerprint,
status,
hasStories
hasStories,
accountIsPremium
)
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories -> PeerInfoScreenData in
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, accountIsPremium -> PeerInfoScreenData in
var availablePanes = availablePanes
if let hasStories {
@ -787,7 +799,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
requestsContext: nil,
threadData: nil,
appConfiguration: nil,
isPowerSavingEnabled: nil
isPowerSavingEnabled: nil,
accountIsPremium: accountIsPremium
)
}
case .channel:
@ -820,6 +833,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
|> distinctUntilChanged
let accountIsPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|> map { peer -> Bool in
return peer?.isPremium ?? false
}
|> distinctUntilChanged
return combineLatest(
context.account.viewTracker.peerView(peerId, updateData: true),
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
@ -829,9 +848,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
invitationsStatePromise.get(),
requestsContextPromise.get(),
requestsStatePromise.get(),
hasStories
hasStories,
accountIsPremium
)
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories -> PeerInfoScreenData in
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium -> PeerInfoScreenData in
var availablePanes = availablePanes
if let hasStories {
if hasStories {
@ -887,7 +907,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
requestsContext: currentRequestsContext,
threadData: nil,
appConfiguration: nil,
isPowerSavingEnabled: nil
isPowerSavingEnabled: nil,
accountIsPremium: accountIsPremium
)
}
case let .group(groupId):
@ -1006,6 +1027,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
threadData = .single(nil)
}
let accountIsPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|> map { peer -> Bool in
return peer?.isPremium ?? false
}
|> distinctUntilChanged
return combineLatest(queue: .mainQueue(),
context.account.viewTracker.peerView(groupId, updateData: true),
peerInfoAvailableMediaPanes(context: context, peerId: groupId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
@ -1017,9 +1044,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
requestsContextPromise.get(),
requestsStatePromise.get(),
threadData,
context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]),
accountIsPremium
)
|> mapToSignal { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData, preferencesView -> Signal<PeerInfoScreenData, NoError> in
|> mapToSignal { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData, preferencesView, accountIsPremium -> Signal<PeerInfoScreenData, NoError> in
var discussionPeer: Peer?
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
discussionPeer = peer
@ -1091,7 +1119,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
requestsContext: currentRequestsContext,
threadData: threadData,
appConfiguration: appConfiguration,
isPowerSavingEnabled: nil
isPowerSavingEnabled: nil,
accountIsPremium: accountIsPremium
))
}
}

View File

@ -1401,6 +1401,8 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
if self.isWhite != oldValue {
if case .qrCode = self.key, let theme = self.theme {
self.iconNode.image = self.isWhite ? generateTintedImage(image: PresentationResourcesRootController.navigationQrCodeIcon(theme), color: .white) : PresentationResourcesRootController.navigationQrCodeIcon(theme)
} else if case .postStory = self.key, let theme = self.theme {
self.iconNode.image = self.isWhite ? generateTintedImage(image: PresentationResourcesRootController.navigationPostStoryIcon(theme), color: .white) : PresentationResourcesRootController.navigationPostStoryIcon(theme)
}
self.regularTextNode.isHidden = self.isWhite
@ -1502,6 +1504,10 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
case .moreToSearch:
text = ""
accessibilityText = ""
case .postStory:
text = ""
accessibilityText = presentationData.strings.Story_Privacy_PostStory
icon = PresentationResourcesRootController.navigationPostStoryIcon(presentationData.theme)
}
self.accessibilityLabel = accessibilityText
self.containerNode.isGestureEnabled = isGestureEnabled
@ -1581,6 +1587,7 @@ enum PeerInfoHeaderNavigationButtonKey {
case more
case qrCode
case moreToSearch
case postStory
}
struct PeerInfoHeaderNavigationButtonSpec: Equatable {
@ -1725,7 +1732,10 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
}
let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData, height: size.height)
var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin
let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize)
var buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize)
if case .postStory = spec.key {
buttonFrame.origin.x -= 12.0
}
nextButtonOrigin -= buttonSize.width + 4.0
if spec.isForExpandedView {
nextExpandedButtonOrigin = nextButtonOrigin
@ -1781,7 +1791,10 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
if let buttonNode = self.rightButtonNodes[key] {
let buttonSize = buttonNode.bounds.size
var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin
let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize)
var buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize)
if case .postStory = spec.key {
buttonFrame.origin.x -= 12.0
}
nextButtonOrigin -= buttonSize.width + 4.0
if spec.isForExpandedView {
nextExpandedButtonOrigin = nextButtonOrigin

View File

@ -92,6 +92,7 @@ import StoryContainerScreen
import ChatAvatarNavigationNode
import PeerReportScreen
import WebUI
import ShareWithPeersScreen
enum PeerInfoAvatarEditingMode {
case generic
@ -2168,6 +2169,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
private var expiringStoryList: PeerExpiringStoryListContext?
private var expiringStoryListState: PeerExpiringStoryListContext.State?
private var expiringStoryListDisposable: Disposable?
private var postingAvailabilityDisposable: Disposable?
private let storiesReady = ValuePromise<Bool>(true, ignoreRepeated: true)
@ -3608,6 +3610,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
}
case .qrCode:
strongSelf.openQrCode()
case .postStory:
strongSelf.openPostStory()
case .editPhoto, .editVideo, .moreToSearch:
break
}
@ -4004,6 +4008,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
self.translationStateDisposable?.dispose()
self.copyProtectionTooltipController?.dismiss()
self.expiringStoryListDisposable?.dispose()
self.postingAvailabilityDisposable?.dispose()
}
override func didLoad() {
@ -8261,6 +8266,84 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
controller.present(ChatQrCodeScreen(context: self.context, subject: .peer(peer: peer, threadId: threadId, temporary: temporary)), in: .window(.root))
}
private func openPostStory() {
self.postingAvailabilityDisposable?.dispose()
self.postingAvailabilityDisposable = (self.context.engine.messages.checkStoriesUploadAvailability(target: .peer(self.peerId))
|> deliverOnMainQueue).start(next: { [weak self] status in
guard let self else {
return
}
switch status {
case .available:
var cameraTransitionIn: StoryCameraTransitionIn?
if let rightButton = self.headerNode.navigationButtonContainer.rightButtonNodes[.postStory] {
cameraTransitionIn = StoryCameraTransitionIn(
sourceView: rightButton.view,
sourceRect: rightButton.view.bounds,
sourceCornerRadius: rightButton.view.bounds.height * 0.5
)
}
if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
let coordinator = rootController.openStoryCamera(customTarget: self.peerId, transitionIn: cameraTransitionIn, transitionedIn: {}, transitionOut: self.storyCameraTransitionOut())
coordinator?.animateIn()
}
case .channelBoostRequired:
let _ = combineLatest(
queue: Queue.mainQueue(),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId)),
self.context.engine.peers.getChannelBoostStatus(peerId: self.peerId)
).start(next: { [weak self] peer, status in
guard let self, let peer, let status else {
return
}
let link: String
if let addressName = peer.addressName, !addressName.isEmpty {
link = "t.me/\(peer.addressName ?? "")?boost"
} else {
link = "t.me/c/\(peer.id.id._internalGetInt64Value())?boost"
}
if let navigationController = self.controller?.navigationController as? NavigationController {
if let previousController = navigationController.viewControllers.last as? ShareWithPeersScreen {
previousController.dismiss()
}
let controller = self.context.sharedContext.makePremiumLimitController(context: self.context, subject: .storiesChannelBoost(peer: peer, isCurrent: true, level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), link: link, boosted: false), count: Int32(status.boosts), forceDark: false, cancel: {}, action: {
UIPasteboard.general.string = "https://\(link)"
return true
})
navigationController.pushViewController(controller)
}
self.hapticFeedback.impact(.light)
})
default:
break
}
}).strict()
}
private func storyCameraTransitionOut() -> (Stories.PendingTarget?, Bool) -> StoryCameraTransitionOut? {
return { [weak self] target, _ in
guard let self else {
return nil
}
let _ = self
/*if let transitionView = self.headerNode.navigationButtonContainer.rightButtonNodes[.postStory]?.view {
return StoryCameraTransitionOut(
destinationView: transitionView,
destinationRect: transitionView.bounds,
destinationCornerRadius: transitionView.bounds.height * 0.5
)
}*/
return nil
}
}
fileprivate func openSettings(section: PeerInfoSettingsSection) {
let push: (ViewController) -> Void = { [weak self] c in
guard let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController else {
@ -9756,6 +9839,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
} else if peerInfoCanEdit(peer: self.data?.peer, chatLocation: self.chatLocation, threadData: self.data?.threadData, cachedData: self.data?.cachedData, isContact: self.data?.isContact) {
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
}
if let data = self.data, data.accountIsPremium, let channel = data.peer as? TelegramChannel, channel.hasPermission(.postStories) {
rightNavigationButtons.insert(PeerInfoHeaderNavigationButtonSpec(key: .postStory, isForExpandedView: false), at: 0)
}
if self.state.selectedMessageIds == nil {
if let currentPaneKey = self.paneContainerNode.currentPaneKey {
switch currentPaneKey {

View File

@ -266,7 +266,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
}
@discardableResult
public func openStoryCamera(transitionIn: StoryCameraTransitionIn?, transitionedIn: @escaping () -> Void, transitionOut: @escaping (Stories.PendingTarget?, Bool) -> StoryCameraTransitionOut?) -> StoryCameraTransitionInCoordinator? {
public func openStoryCamera(customTarget: EnginePeer.Id?, transitionIn: StoryCameraTransitionIn?, transitionedIn: @escaping () -> Void, transitionOut: @escaping (Stories.PendingTarget?, Bool) -> StoryCameraTransitionOut?) -> StoryCameraTransitionInCoordinator? {
guard let controller = self.viewControllers.last as? ViewController else {
return nil
}
@ -379,6 +379,10 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
let target: Stories.PendingTarget
let targetPeerId: EnginePeer.Id
if let customTarget {
target = .peer(customTarget)
targetPeerId = customTarget
} else {
if let sendAsPeerId = options.sendAsPeerId {
target = .peer(sendAsPeerId)
targetPeerId = sendAsPeerId
@ -386,6 +390,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
target = .myStories
targetPeerId = context.account.peerId
}
}
storyTarget = target
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: targetPeerId))