mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Stories
This commit is contained in:
parent
db65538d1f
commit
160b8186ff
@ -1458,7 +1458,7 @@ public class CameraScreen: ViewController {
|
||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
||||
|
||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "Enable Dual Camera Mode", location: .point(location, .top), displayDuration: .manual, inset: 16.0, shouldDismissOnTouch: { _ in
|
||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "Enable Dual Camera Mode", location: .point(location, .top), displayDuration: .manual(false), inset: 16.0, shouldDismissOnTouch: { _ in
|
||||
return .ignore
|
||||
})
|
||||
self.controller?.present(tooltipController, in: .current)
|
||||
|
@ -2341,7 +2341,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
||||
|
||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "You can set who can view this story.", location: .point(location, .top), displayDuration: .manual, inset: 16.0, shouldDismissOnTouch: { _ in
|
||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "You can set who can view this story.", location: .point(location, .top), displayDuration: .manual(false), inset: 16.0, shouldDismissOnTouch: { _ in
|
||||
return .ignore
|
||||
})
|
||||
self.controller?.present(tooltipController, in: .current)
|
||||
|
@ -240,10 +240,10 @@ private final class BannerComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
final class SaveProgressScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
public final class SaveProgressScreenComponent: Component {
|
||||
public typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
enum Content: Equatable {
|
||||
public enum Content: Equatable {
|
||||
enum ContentType: Equatable {
|
||||
case progress
|
||||
case completion
|
||||
@ -262,11 +262,11 @@ final class SaveProgressScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
let context: AccountContext
|
||||
let content: Content
|
||||
let cancel: () -> Void
|
||||
public let context: AccountContext
|
||||
public let content: Content
|
||||
public let cancel: () -> Void
|
||||
|
||||
init(
|
||||
public init(
|
||||
context: AccountContext,
|
||||
content: Content,
|
||||
cancel: @escaping () -> Void
|
||||
@ -276,7 +276,7 @@ final class SaveProgressScreenComponent: Component {
|
||||
self.cancel = cancel
|
||||
}
|
||||
|
||||
static func ==(lhs: SaveProgressScreenComponent, rhs: SaveProgressScreenComponent) -> Bool {
|
||||
public static func ==(lhs: SaveProgressScreenComponent, rhs: SaveProgressScreenComponent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
@ -374,7 +374,7 @@ final class SaveProgressScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
public func makeView() -> View {
|
||||
return View()
|
||||
}
|
||||
|
||||
@ -385,7 +385,7 @@ final class SaveProgressScreenComponent: Component {
|
||||
|
||||
private let storyDimensions = CGSize(width: 1080.0, height: 1920.0)
|
||||
|
||||
final class SaveProgressScreen: ViewController {
|
||||
public final class SaveProgressScreen: ViewController {
|
||||
fileprivate final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
|
||||
private weak var controller: SaveProgressScreen?
|
||||
private let context: AccountContext
|
||||
@ -501,7 +501,7 @@ final class SaveProgressScreen: ViewController {
|
||||
}
|
||||
|
||||
fileprivate let context: AccountContext
|
||||
var content: SaveProgressScreenComponent.Content {
|
||||
public var content: SaveProgressScreenComponent.Content {
|
||||
didSet {
|
||||
if let layout = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, transition: .animated(duration: 0.25, curve: .easeInOut))
|
||||
@ -514,7 +514,7 @@ final class SaveProgressScreen: ViewController {
|
||||
|
||||
public var cancelled: () -> Void = {}
|
||||
|
||||
init(context: AccountContext, content: SaveProgressScreenComponent.Content) {
|
||||
public init(context: AccountContext, content: SaveProgressScreenComponent.Content) {
|
||||
self.context = context
|
||||
self.content = content
|
||||
|
||||
@ -527,11 +527,11 @@ final class SaveProgressScreen: ViewController {
|
||||
self.maybeSetupDismissTimer()
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func loadDisplayNode() {
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = Node(controller: self)
|
||||
|
||||
super.displayNodeDidLoad()
|
||||
@ -567,7 +567,7 @@ final class SaveProgressScreen: ViewController {
|
||||
}
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = layout
|
||||
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
@ -67,6 +67,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/PeerReportScreen",
|
||||
"//submodules/LocalMediaResources",
|
||||
"//submodules/SaveToCameraRoll",
|
||||
"//submodules/Components/BundleIconComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -28,6 +28,7 @@ import TextFieldComponent
|
||||
import TextFormat
|
||||
import LocalMediaResources
|
||||
import SaveToCameraRoll
|
||||
import BundleIconComponent
|
||||
|
||||
public final class StoryItemSetContainerComponent: Component {
|
||||
public final class ExternalState {
|
||||
@ -251,6 +252,8 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
var centerInfoItem: InfoItem?
|
||||
var rightInfoItem: InfoItem?
|
||||
|
||||
var closeFriendIcon: ComponentView<Empty>?
|
||||
|
||||
var captionItem: CaptionItem?
|
||||
|
||||
let inputBackground = ComponentView<Empty>()
|
||||
@ -580,6 +583,9 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
if self.sendMessageContext.shareController != nil {
|
||||
return true
|
||||
}
|
||||
if self.sendMessageContext.tooltipScreen != nil {
|
||||
return true
|
||||
}
|
||||
if let navigationController = component.controller()?.navigationController as? NavigationController {
|
||||
let topViewController = navigationController.topViewController
|
||||
if !(topViewController is StoryContainerScreen) && !(topViewController is MediaEditorScreen) {
|
||||
@ -1619,10 +1625,22 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
), nil)
|
||||
}
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: "Save image", icon: { theme in
|
||||
|
||||
let saveText: String
|
||||
if case .file = component.slice.item.storyItem.media {
|
||||
saveText = "Save Video"
|
||||
} else {
|
||||
saveText = "Save Image"
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: saveText, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, a in
|
||||
}, action: { [weak self] _, a in
|
||||
a(.default)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.requestSave()
|
||||
})))
|
||||
|
||||
if component.slice.item.storyItem.isPublic && (component.slice.peer.addressName != nil || !component.slice.peer._asPeer().usernames.isEmpty) {
|
||||
@ -1863,6 +1881,66 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
if component.slice.item.storyItem.isCloseFriends {
|
||||
let closeFriendIcon: ComponentView<Empty>
|
||||
var closeFriendIconTransition = transition
|
||||
if let current = self.closeFriendIcon {
|
||||
closeFriendIcon = current
|
||||
} else {
|
||||
closeFriendIconTransition = .immediate
|
||||
closeFriendIcon = ComponentView()
|
||||
self.closeFriendIcon = closeFriendIcon
|
||||
}
|
||||
let closeFriendIconSize = closeFriendIcon.update(
|
||||
transition: closeFriendIconTransition,
|
||||
component: AnyComponent(PlainButtonComponent(
|
||||
content: AnyComponent(BundleIconComponent(
|
||||
name: "Stories/CloseStoryIcon",
|
||||
tintColor: nil,
|
||||
maxSize: nil
|
||||
)),
|
||||
effectAlignment: .center,
|
||||
action: { [weak self] in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
guard let closeFriendIconView = self.closeFriendIcon?.view else {
|
||||
return
|
||||
}
|
||||
let tooltipScreen = TooltipScreen(
|
||||
account: component.context.account,
|
||||
sharedContext: component.context.sharedContext,
|
||||
text: "You are seeing this story because you have\nbeen added to \(component.slice.peer.compactDisplayTitle)'s list of close friends.", style: .default, location: TooltipScreen.Location.point(closeFriendIconView.convert(closeFriendIconView.bounds, to: self).offsetBy(dx: 1.0, dy: 6.0), .top), displayDuration: .manual(true), shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
}
|
||||
)
|
||||
tooltipScreen.willBecomeDismissed = { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sendMessageContext.tooltipScreen = nil
|
||||
self.updateIsProgressPaused()
|
||||
}
|
||||
self.sendMessageContext.tooltipScreen = tooltipScreen
|
||||
self.updateIsProgressPaused()
|
||||
component.controller()?.present(tooltipScreen, in: .current)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 44.0, height: 44.0)
|
||||
)
|
||||
let closeFriendIconFrame = CGRect(origin: CGPoint(x: contentFrame.width - 6.0 - 52.0 - closeFriendIconSize.width, y: 21.0), size: closeFriendIconSize)
|
||||
if let closeFriendIconView = closeFriendIcon.view {
|
||||
if closeFriendIconView.superview == nil {
|
||||
self.contentContainerView.addSubview(closeFriendIconView)
|
||||
closeFriendIconTransition.setFrame(view: closeFriendIconView, frame: closeFriendIconFrame)
|
||||
}
|
||||
}
|
||||
} else if let closeFriendIcon = self.closeFriendIcon {
|
||||
self.closeFriendIcon = nil
|
||||
closeFriendIcon.view?.removeFromSuperview()
|
||||
}
|
||||
|
||||
let gradientHeight: CGFloat = 74.0
|
||||
transition.setFrame(layer: self.topContentGradientLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: contentFrame.width, height: gradientHeight)))
|
||||
transition.setAlpha(layer: self.topContentGradientLayer, alpha: (component.hideUI || self.displayViewList || self.isEditingStory) ? 0.0 : 1.0)
|
||||
@ -2682,6 +2760,35 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
private func requestSave() {
|
||||
guard let component = self.component, let peerReference = PeerReference(component.slice.peer._asPeer()) else {
|
||||
return
|
||||
}
|
||||
|
||||
let saveScreen = SaveProgressScreen(context: component.context, content: .progress("Saving", 0.0))
|
||||
component.controller()?.present(saveScreen, in: .current)
|
||||
|
||||
let disposable = (saveToCameraRoll(context: component.context, postbox: component.context.account.postbox, userLocation: .other, mediaReference: .story(peer: peerReference, id: component.slice.item.storyItem.id, media: component.slice.item.storyItem.media._asMedia()))
|
||||
|> deliverOnMainQueue).start(next: { [weak saveScreen] progress in
|
||||
guard let saveScreen else {
|
||||
return
|
||||
}
|
||||
saveScreen.content = .progress("Saving", progress)
|
||||
}, completed: { [weak saveScreen] in
|
||||
guard let saveScreen else {
|
||||
return
|
||||
}
|
||||
saveScreen.content = .completion("Saved")
|
||||
Queue.mainQueue().after(3.0, { [weak saveScreen] in
|
||||
saveScreen?.dismiss()
|
||||
})
|
||||
})
|
||||
|
||||
saveScreen.cancelled = {
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func makeView() -> View {
|
||||
|
@ -48,6 +48,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
|
||||
weak var attachmentController: AttachmentController?
|
||||
weak var shareController: ShareController?
|
||||
weak var tooltipScreen: ViewController?
|
||||
|
||||
var currentInputMode: InputMode = .text
|
||||
private var needsInputActivation = false
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Stories/CloseStoryIcon.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Stories/CloseStoryIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "StoryCloseIcon.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
10
submodules/TelegramUI/Images.xcassets/Stories/CloseStoryIcon.imageset/StoryCloseIcon.svg
vendored
Normal file
10
submodules/TelegramUI/Images.xcassets/Stories/CloseStoryIcon.imageset/StoryCloseIcon.svg
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="22" height="22" rx="11" fill="url(#paint0_linear_0_3)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.8351 15.3336C11.1171 15.1638 11.4698 15.1638 11.7519 15.3336L14.5953 17.045C15.2688 17.4504 16.0983 16.8463 15.9193 16.081L15.1664 12.8627C15.0911 12.5408 15.2007 12.2037 15.4508 11.9876L17.9565 9.82292C18.5521 9.30844 18.2346 8.3309 17.4504 8.26456L14.1484 7.9852C13.8202 7.95742 13.5342 7.75036 13.4053 7.44716L12.1115 4.40309C11.8049 3.68149 10.7821 3.68149 10.4754 4.40309L9.18166 7.44716C9.05279 7.75036 8.7668 7.95742 8.43852 7.9852L5.13659 8.26456C4.3524 8.3309 4.0349 9.30844 4.63043 9.82292L7.13613 11.9876C7.3863 12.2037 7.49586 12.5408 7.42056 12.8627L6.6677 16.081C6.48866 16.8463 7.31817 17.4504 7.99161 17.045L10.8351 15.3336Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_0_3" x1="18.3333" y1="2.93333" x2="3.3" y2="18.7" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7CD636"/>
|
||||
<stop offset="1" stop-color="#26B470"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,9 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
@ -583,7 +583,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
if self.containerNode.frame.contains(point) {
|
||||
self.requestDismiss()
|
||||
return self.view
|
||||
} else {
|
||||
} else if case .manual(false) = self.displayDuration {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -710,7 +710,7 @@ public final class TooltipScreen: ViewController {
|
||||
case `default`
|
||||
case custom(Double)
|
||||
case infinite
|
||||
case manual
|
||||
case manual(Bool)
|
||||
}
|
||||
|
||||
public enum Style {
|
||||
|
Loading…
x
Reference in New Issue
Block a user