mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-09-30 16:09:36 +02:00
Update Ghostgram features
This commit is contained in:
1 parent
1a3303b059
commit
24a7ec39d9
902 files changed
+148295
-62348
No files matched your search
+194
@@ -0,0 +1,194 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
|
||||
final class SGStoryWarningComponent: Component {
|
||||
typealias EnvironmentType = Empty
|
||||
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let peer: EnginePeer?
|
||||
let isInStealthMode: Bool
|
||||
let action: () -> Void
|
||||
let close: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
theme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
peer: EnginePeer?,
|
||||
isInStealthMode: Bool,
|
||||
action: @escaping () -> Void,
|
||||
close: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.peer = peer
|
||||
self.isInStealthMode = isInStealthMode
|
||||
self.action = action
|
||||
self.close = close
|
||||
}
|
||||
|
||||
static func ==(lhs: SGStoryWarningComponent, rhs: SGStoryWarningComponent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
if lhs.strings !== rhs.strings {
|
||||
return false
|
||||
}
|
||||
if lhs.peer?.id != rhs.peer?.id {
|
||||
return false
|
||||
}
|
||||
if lhs.isInStealthMode != rhs.isInStealthMode {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
final class View: UIView {
|
||||
private let dimView = UIView()
|
||||
private let panelView = UIView()
|
||||
private let titleLabel = UILabel()
|
||||
private let textLabel = UILabel()
|
||||
private let continueButton = UIButton(type: .system)
|
||||
private let closeButton = UIButton(type: .system)
|
||||
|
||||
private var component: SGStoryWarningComponent?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.dimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
||||
self.addSubview(self.dimView)
|
||||
|
||||
self.panelView.layer.cornerRadius = 22.0
|
||||
self.panelView.layer.masksToBounds = true
|
||||
self.addSubview(self.panelView)
|
||||
|
||||
self.titleLabel.numberOfLines = 0
|
||||
self.titleLabel.textAlignment = .center
|
||||
self.panelView.addSubview(self.titleLabel)
|
||||
|
||||
self.textLabel.numberOfLines = 0
|
||||
self.textLabel.textAlignment = .center
|
||||
self.panelView.addSubview(self.textLabel)
|
||||
|
||||
self.continueButton.layer.cornerRadius = 11.0
|
||||
self.continueButton.layer.masksToBounds = true
|
||||
self.continueButton.titleLabel?.font = Font.semibold(17.0)
|
||||
self.continueButton.addTarget(self, action: #selector(self.continuePressed), for: .touchUpInside)
|
||||
self.panelView.addSubview(self.continueButton)
|
||||
|
||||
self.closeButton.titleLabel?.font = Font.regular(15.0)
|
||||
self.closeButton.addTarget(self, action: #selector(self.closePressed), for: .touchUpInside)
|
||||
self.panelView.addSubview(self.closeButton)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func continuePressed() {
|
||||
self.component?.action()
|
||||
}
|
||||
|
||||
@objc private func closePressed() {
|
||||
self.component?.close()
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
self.dimView.alpha = 0.0
|
||||
self.panelView.alpha = 0.0
|
||||
self.panelView.transform = CGAffineTransform(scaleX: 0.92, y: 0.92)
|
||||
UIView.animate(withDuration: 0.22, delay: 0.0, options: [.curveEaseOut]) {
|
||||
self.dimView.alpha = 1.0
|
||||
self.panelView.alpha = 1.0
|
||||
self.panelView.transform = .identity
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
UIView.animate(withDuration: 0.18, delay: 0.0, options: [.curveEaseIn], animations: {
|
||||
self.dimView.alpha = 0.0
|
||||
self.panelView.alpha = 0.0
|
||||
self.panelView.transform = CGAffineTransform(scaleX: 0.92, y: 0.92)
|
||||
}, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
func update(component: SGStoryWarningComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
|
||||
self.component = component
|
||||
|
||||
self.dimView.frame = CGRect(origin: .zero, size: availableSize)
|
||||
self.panelView.backgroundColor = component.theme.actionSheet.opaqueItemBackgroundColor
|
||||
|
||||
self.titleLabel.textColor = component.theme.actionSheet.primaryTextColor
|
||||
self.textLabel.textColor = component.theme.actionSheet.secondaryTextColor
|
||||
|
||||
let title = component.isInStealthMode ? "Stealth Mode Is Enabled" : "Story View Warning"
|
||||
let text: String
|
||||
if component.isInStealthMode {
|
||||
text = "You are about to continue viewing stories while stealth mode is active. Swiftgram story actions may differ until migration is fully finished."
|
||||
} else {
|
||||
text = "Swiftgram story-specific warning UI is running in compatibility mode in this merged build. You can continue, but verify story actions carefully."
|
||||
}
|
||||
|
||||
self.titleLabel.attributedText = NSAttributedString(
|
||||
string: title,
|
||||
font: Font.semibold(20.0),
|
||||
textColor: component.theme.actionSheet.primaryTextColor
|
||||
)
|
||||
self.textLabel.attributedText = NSAttributedString(
|
||||
string: text,
|
||||
font: Font.regular(15.0),
|
||||
textColor: component.theme.actionSheet.secondaryTextColor
|
||||
)
|
||||
|
||||
self.continueButton.backgroundColor = component.theme.list.itemCheckColors.fillColor
|
||||
self.continueButton.setTitleColor(component.theme.list.itemCheckColors.foregroundColor, for: .normal)
|
||||
self.continueButton.setTitle("Continue", for: .normal)
|
||||
|
||||
self.closeButton.setTitleColor(component.theme.list.itemAccentColor, for: .normal)
|
||||
self.closeButton.setTitle("Close", for: .normal)
|
||||
|
||||
let panelWidth = min(availableSize.width - 32.0, 360.0)
|
||||
let titleSize = self.titleLabel.sizeThatFits(CGSize(width: panelWidth - 32.0, height: CGFloat.greatestFiniteMagnitude))
|
||||
let textSize = self.textLabel.sizeThatFits(CGSize(width: panelWidth - 32.0, height: CGFloat.greatestFiniteMagnitude))
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
let closeHeight: CGFloat = 22.0
|
||||
let panelHeight = 24.0 + titleSize.height + 12.0 + textSize.height + 20.0 + buttonHeight + 12.0 + closeHeight + 20.0
|
||||
let panelFrame = CGRect(
|
||||
x: floor((availableSize.width - panelWidth) * 0.5),
|
||||
y: floor((availableSize.height - panelHeight) * 0.5),
|
||||
width: panelWidth,
|
||||
height: panelHeight
|
||||
)
|
||||
transition.setFrame(view: self.panelView, frame: panelFrame)
|
||||
|
||||
self.titleLabel.frame = CGRect(x: 16.0, y: 24.0, width: panelWidth - 32.0, height: titleSize.height)
|
||||
self.textLabel.frame = CGRect(x: 16.0, y: self.titleLabel.frame.maxY + 12.0, width: panelWidth - 32.0, height: textSize.height)
|
||||
self.continueButton.frame = CGRect(x: 16.0, y: self.textLabel.frame.maxY + 20.0, width: panelWidth - 32.0, height: buttonHeight)
|
||||
self.closeButton.frame = CGRect(x: 16.0, y: self.continueButton.frame.maxY + 12.0, width: panelWidth - 32.0, height: closeHeight)
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
return View(frame: CGRect())
|
||||
}
|
||||
|
||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, transition: transition)
|
||||
}
|
||||
}
|
||||
+78
-5
@@ -1,3 +1,7 @@
|
||||
// MARK: Swiftgram
|
||||
import TelegramUIPreferences
|
||||
import SGSimpleSettings
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
@@ -426,7 +430,12 @@ private final class StoryContainerScreenComponent: Component {
|
||||
var longPressRecognizer: StoryLongPressRecognizer?
|
||||
|
||||
private var pendingNavigationToItemId: StoryId?
|
||||
|
||||
|
||||
private let storiesWarning = ComponentView<Empty>()
|
||||
private var requestedDisplayStoriesWarning: Bool = SGSimpleSettings.shared.warnOnStoriesOpen // MARK: Swiftgram
|
||||
private var displayStoriesWarningDisposable: Disposable?
|
||||
private var isDisplayingStoriesWarning: Bool = false
|
||||
|
||||
private let interactionGuide = ComponentView<Empty>()
|
||||
private var isDisplayingInteractionGuide: Bool = false
|
||||
private var displayInteractionGuideDisposable: Disposable?
|
||||
@@ -459,7 +468,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
guard let self, let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id], let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View else {
|
||||
return []
|
||||
}
|
||||
if self.isDisplayingInteractionGuide {
|
||||
if self.isDisplayingInteractionGuide || self.isDisplayingStoriesWarning {
|
||||
return []
|
||||
}
|
||||
if let environment = self.environment, case .regular = environment.metrics.widthClass {
|
||||
@@ -592,7 +601,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
guard let self else {
|
||||
return false
|
||||
}
|
||||
if self.isDisplayingInteractionGuide {
|
||||
if self.isDisplayingInteractionGuide || self.isDisplayingStoriesWarning {
|
||||
return false
|
||||
}
|
||||
if let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
|
||||
@@ -745,6 +754,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
|
||||
deinit {
|
||||
self.contentUpdatedDisposable?.dispose()
|
||||
self.displayStoriesWarningDisposable?.dispose()
|
||||
self.volumeButtonsListenerShouldBeActiveDisposable?.dispose()
|
||||
self.headphonesDisposable?.dispose()
|
||||
self.stealthModeDisposable?.dispose()
|
||||
@@ -1073,7 +1083,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !value && !self.isDisplayingInteractionGuide {
|
||||
if !value && (!self.isDisplayingInteractionGuide || !self.isDisplayingStoriesWarning) {
|
||||
if let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id], let currentItemView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||
currentItemView.maybeDisplayReactionTooltip()
|
||||
}
|
||||
@@ -1317,6 +1327,16 @@ private final class StoryContainerScreenComponent: Component {
|
||||
}
|
||||
})
|
||||
|
||||
// MARK: Swiftgram
|
||||
self.requestedDisplayStoriesWarning = SGSimpleSettings.shared.warnOnStoriesOpen
|
||||
if self.requestedDisplayStoriesWarning {
|
||||
self.isDisplayingStoriesWarning = true
|
||||
if update {
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
update = true
|
||||
}
|
||||
|
||||
@@ -1375,6 +1395,11 @@ private final class StoryContainerScreenComponent: Component {
|
||||
if case .file = slice.item.storyItem.media {
|
||||
isVideo = true
|
||||
}
|
||||
// TODO(swiftgram): Show warning on each new peerId story
|
||||
/* if self.requestedDisplayStoriesWarning, let previousSlice = stateValue?.previousSlice, previousSlice.peer.id != slice.peer.id {
|
||||
self.isDisplayingStoriesWarning = self.requestedDisplayStoriesWarning
|
||||
update = false
|
||||
}*/
|
||||
}
|
||||
self.focusedItem.set(focusedItemId)
|
||||
self.contentWantsVolumeButtonMonitoring.set(isVideo)
|
||||
@@ -1503,7 +1528,7 @@ private final class StoryContainerScreenComponent: Component {
|
||||
if self.pendingNavigationToItemId != nil {
|
||||
isProgressPaused = true
|
||||
}
|
||||
if self.isDisplayingInteractionGuide {
|
||||
if self.isDisplayingInteractionGuide || self.isDisplayingStoriesWarning {
|
||||
isProgressPaused = true
|
||||
}
|
||||
|
||||
@@ -1968,6 +1993,54 @@ private final class StoryContainerScreenComponent: Component {
|
||||
controller.presentationContext.containerLayoutUpdated(subLayout, transition: transition.containedViewLayoutTransition)
|
||||
}
|
||||
|
||||
// MARK: Swiftgram
|
||||
if self.isDisplayingStoriesWarning {
|
||||
let _ = self.storiesWarning.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(
|
||||
SGStoryWarningComponent(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
strings: environment.strings,
|
||||
peer: component.content.stateValue?.slice?.peer,
|
||||
isInStealthMode: stealthModeTimeout != nil || SGSimpleSettings.shared.isStealthModeEnabled,
|
||||
action: { [weak self] in
|
||||
self?.isDisplayingStoriesWarning = false
|
||||
self?.state?.updated(transition: .immediate)
|
||||
if let view = self?.storiesWarning.view as? SGStoryWarningComponent.View {
|
||||
view.animateOut(completion: {
|
||||
view.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
},
|
||||
close: { [weak self] in
|
||||
self?.environment?.controller()?.dismiss()
|
||||
if let view = self?.storiesWarning.view as? SGStoryWarningComponent.View {
|
||||
view.animateOut(completion: {
|
||||
view.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: availableSize
|
||||
)
|
||||
if let view = self.storiesWarning.view as? SGStoryWarningComponent.View {
|
||||
if view.superview == nil {
|
||||
self.addSubview(view)
|
||||
|
||||
view.animateIn()
|
||||
}
|
||||
view.layer.zPosition = 1000.0
|
||||
view.frame = CGRect(origin: .zero, size: availableSize)
|
||||
}
|
||||
} else if let view = self.storiesWarning.view as? SGStoryWarningComponent.View, view.superview != nil {
|
||||
view.animateOut(completion: {
|
||||
view.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
if self.isDisplayingInteractionGuide {
|
||||
let _ = self.interactionGuide.update(
|
||||
transition: .immediate,
|
||||
|
||||
+5
-4
@@ -1,3 +1,4 @@
|
||||
import SGSimpleSettings
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
@@ -3826,7 +3827,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
|
||||
let items = ContextController.Items(content: .list(itemList))
|
||||
|
||||
let controller = ContextController(
|
||||
let controller = makeContextController(
|
||||
presentationData: presentationData,
|
||||
source: .extracted(ListContextExtractedContentSource(contentView: sourceView)),
|
||||
items: .single(items),
|
||||
@@ -6761,7 +6762,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return .single(ContextController.Items(id: 0, content: .list(items), tip: tip, tipSignal: tipSignal))
|
||||
}
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView, position: .bottom)), items: contextItems, gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView, position: .bottom)), items: contextItems, gesture: gesture)
|
||||
contextController.dismissed = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
@@ -7095,7 +7096,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return .single(ContextController.Items(id: 0, content: .list(items), tip: tip, tipSignal: tipSignal))
|
||||
}
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView, position: .bottom)), items: contextItems, gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView, position: .bottom)), items: contextItems, gesture: gesture)
|
||||
contextController.dismissed = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
@@ -7526,7 +7527,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
|
||||
let contextItems = ContextController.Items(id: 0, content: .list(items), tip: tip, tipSignal: tipSignal)
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView, position: .bottom)), items: .single(contextItems), gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView, position: .bottom)), items: .single(contextItems), gesture: gesture)
|
||||
contextController.dismissed = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
|
||||
+1
@@ -345,6 +345,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
let presentationInterfaceState = ChatPresentationInterfaceState(
|
||||
chatWallpaper: .builtin(WallpaperSettings()),
|
||||
theme: presentationData.theme,
|
||||
preferredGlassType: .default,
|
||||
strings: presentationData.strings,
|
||||
dateTimeFormat: presentationData.dateTimeFormat,
|
||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||
|
||||
Reference in new issue
Block a user