mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 01:10:09 +00:00
Add bot preview mode for media editor
This commit is contained in:
parent
da25e4292c
commit
d8d68722ae
@ -12535,3 +12535,5 @@ Sorry for the inconvenience.";
|
|||||||
"Stars.Transaction.FragmentUnknown_URL" = "https://fragment.com/stars";
|
"Stars.Transaction.FragmentUnknown_URL" = "https://fragment.com/stars";
|
||||||
"Conversation.StatusBotSubscribers_1" = "1 user";
|
"Conversation.StatusBotSubscribers_1" = "1 user";
|
||||||
"Conversation.StatusBotSubscribers_any" = "%d users";
|
"Conversation.StatusBotSubscribers_any" = "%d users";
|
||||||
|
|
||||||
|
"Story.Editor.Add" = "Add";
|
||||||
|
|||||||
@ -1051,10 +1051,12 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
|
|
||||||
func makeMediaPickerScreen(context: AccountContext, hasSearch: Bool, completion: @escaping (Any) -> Void) -> ViewController
|
func makeMediaPickerScreen(context: AccountContext, hasSearch: Bool, completion: @escaping (Any) -> Void) -> ViewController
|
||||||
|
|
||||||
|
func makeBotPreviewEditorScreen(context: AccountContext, source: Any?, target: Stories.PendingTarget, transitionArguments: (UIView, CGRect, UIImage?)?, externalState: MediaEditorTransitionOutExternalState, completion: @escaping (MediaEditorScreenResult, @escaping (@escaping () -> Void) -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController
|
||||||
|
|
||||||
func makeStickerEditorScreen(context: AccountContext, source: Any?, intro: Bool, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController
|
func makeStickerEditorScreen(context: AccountContext, source: Any?, intro: Bool, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController
|
||||||
|
|
||||||
func makeStickerMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController
|
func makeStickerMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController
|
||||||
func makeStoryMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect, completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void, groupsPresented: @escaping () -> Void) -> ViewController
|
func makeStoryMediaPickerScreen(context: AccountContext, isDark: Bool, getSourceRect: @escaping () -> CGRect, completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void, groupsPresented: @escaping () -> Void) -> ViewController
|
||||||
|
|
||||||
func makeStickerPickerScreen(context: AccountContext, inputData: Promise<StickerPickerInput>, completion: @escaping (FileMediaReference) -> Void) -> ViewController
|
func makeStickerPickerScreen(context: AccountContext, inputData: Promise<StickerPickerInput>, completion: @escaping (FileMediaReference) -> Void) -> ViewController
|
||||||
|
|
||||||
|
|||||||
@ -2982,12 +2982,16 @@ public func mediaPickerController(
|
|||||||
|
|
||||||
public func storyMediaPickerController(
|
public func storyMediaPickerController(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
|
isDark: Bool,
|
||||||
getSourceRect: @escaping () -> CGRect,
|
getSourceRect: @escaping () -> CGRect,
|
||||||
completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void,
|
completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void,
|
||||||
dismissed: @escaping () -> Void,
|
dismissed: @escaping () -> Void,
|
||||||
groupsPresented: @escaping () -> Void
|
groupsPresented: @escaping () -> Void
|
||||||
) -> ViewController {
|
) -> ViewController {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: defaultDarkColorPresentationTheme)
|
var presentationData = context.sharedContext.currentPresentationData.with({ $0 })
|
||||||
|
if isDark {
|
||||||
|
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||||
|
}
|
||||||
let updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>) = (presentationData, .single(presentationData))
|
let updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>) = (presentationData, .single(presentationData))
|
||||||
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: {
|
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -2979,7 +2979,7 @@ public class CameraScreen: ViewController {
|
|||||||
if let current = self.galleryController {
|
if let current = self.galleryController {
|
||||||
controller = current
|
controller = current
|
||||||
} else {
|
} else {
|
||||||
controller = self.context.sharedContext.makeStoryMediaPickerScreen(context: self.context, getSourceRect: { [weak self] in
|
controller = self.context.sharedContext.makeStoryMediaPickerScreen(context: self.context, isDark: true, getSourceRect: { [weak self] in
|
||||||
if let self {
|
if let self {
|
||||||
if let galleryButton = self.node.componentHost.findTaggedView(tag: galleryButtonTag) {
|
if let galleryButton = self.node.componentHost.findTaggedView(tag: galleryButtonTag) {
|
||||||
return galleryButton.convert(galleryButton.bounds, to: self.view).offsetBy(dx: 0.0, dy: -15.0)
|
return galleryButton.convert(galleryButton.bounds, to: self.view).offsetBy(dx: 0.0, dy: -15.0)
|
||||||
|
|||||||
@ -818,7 +818,7 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var doneButtonTitle: String?
|
var doneButtonTitle: String?
|
||||||
var doneButtonIcon: UIImage
|
var doneButtonIcon: UIImage?
|
||||||
switch controller.mode {
|
switch controller.mode {
|
||||||
case .storyEditor:
|
case .storyEditor:
|
||||||
doneButtonTitle = isEditingStory ? environment.strings.Story_Editor_Done.uppercased() : environment.strings.Story_Editor_Next.uppercased()
|
doneButtonTitle = isEditingStory ? environment.strings.Story_Editor_Done.uppercased() : environment.strings.Story_Editor_Next.uppercased()
|
||||||
@ -826,6 +826,10 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
case .stickerEditor:
|
case .stickerEditor:
|
||||||
doneButtonTitle = nil
|
doneButtonTitle = nil
|
||||||
doneButtonIcon = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/Apply"), color: .white)!
|
doneButtonIcon = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/Apply"), color: .white)!
|
||||||
|
case .botPreview:
|
||||||
|
//TODO:localize
|
||||||
|
doneButtonTitle = environment.strings.Story_Editor_Add
|
||||||
|
doneButtonIcon = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let doneButtonSize = self.doneButton.update(
|
let doneButtonSize = self.doneButton.update(
|
||||||
@ -859,6 +863,8 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
case .stickerEditor:
|
case .stickerEditor:
|
||||||
controller.requestStickerCompletion(animated: true)
|
controller.requestStickerCompletion(animated: true)
|
||||||
|
case .botPreview:
|
||||||
|
controller.requestStoryCompletion(animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
@ -2415,6 +2421,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
|
|
||||||
case storyEditor
|
case storyEditor
|
||||||
case stickerEditor(mode: StickerEditorMode)
|
case stickerEditor(mode: StickerEditorMode)
|
||||||
|
case botPreview
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TransitionIn {
|
public enum TransitionIn {
|
||||||
@ -2870,7 +2877,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
let mediaEntity = DrawingMediaEntity(size: fittedSize)
|
let mediaEntity = DrawingMediaEntity(size: fittedSize)
|
||||||
mediaEntity.position = CGPoint(x: storyDimensions.width / 2.0, y: storyDimensions.height / 2.0)
|
mediaEntity.position = CGPoint(x: storyDimensions.width / 2.0, y: storyDimensions.height / 2.0)
|
||||||
switch controller.mode {
|
switch controller.mode {
|
||||||
case .storyEditor:
|
case .storyEditor, .botPreview:
|
||||||
if fittedSize.height > fittedSize.width {
|
if fittedSize.height > fittedSize.width {
|
||||||
mediaEntity.scale = max(storyDimensions.width / fittedSize.width, storyDimensions.height / fittedSize.height)
|
mediaEntity.scale = max(storyDimensions.width / fittedSize.width, storyDimensions.height / fittedSize.height)
|
||||||
} else {
|
} else {
|
||||||
@ -3623,7 +3630,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
transitionInView.contentMode = .scaleAspectFill
|
transitionInView.contentMode = .scaleAspectFill
|
||||||
var initialScale: CGFloat
|
var initialScale: CGFloat
|
||||||
switch controller.mode {
|
switch controller.mode {
|
||||||
case .storyEditor:
|
case .storyEditor, .botPreview:
|
||||||
if image.size.height > image.size.width {
|
if image.size.height > image.size.width {
|
||||||
initialScale = max(self.previewContainerView.bounds.width / image.size.width, self.previewContainerView.bounds.height / image.size.height)
|
initialScale = max(self.previewContainerView.bounds.width / image.size.width, self.previewContainerView.bounds.height / image.size.height)
|
||||||
} else {
|
} else {
|
||||||
@ -4779,12 +4786,17 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
mediaEditor.maybePauseVideo()
|
mediaEditor.maybePauseVideo()
|
||||||
|
|
||||||
var hasInteractiveStickers = true
|
var hasInteractiveStickers = true
|
||||||
if let controller = self.controller, case .stickerEditor = controller.mode {
|
if let controller = self.controller {
|
||||||
hasInteractiveStickers = false
|
switch controller.mode {
|
||||||
|
case .stickerEditor, .botPreview:
|
||||||
|
hasInteractiveStickers = false
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var weatherSignal: Signal<StickerPickerScreen.Weather, NoError>
|
var weatherSignal: Signal<StickerPickerScreen.Weather, NoError>
|
||||||
if "".isEmpty {
|
if hasInteractiveStickers {
|
||||||
let weatherPromise: Promise<StickerPickerScreen.Weather>
|
let weatherPromise: Promise<StickerPickerScreen.Weather>
|
||||||
if let current = self.weatherPromise {
|
if let current = self.weatherPromise {
|
||||||
weatherPromise = current
|
weatherPromise = current
|
||||||
@ -6096,7 +6108,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
save = presentationData.strings.Story_Editor_DraftKeepMedia
|
save = presentationData.strings.Story_Editor_DraftKeepMedia
|
||||||
}
|
}
|
||||||
text = presentationData.strings.Story_Editor_DraftDiscaedText
|
text = presentationData.strings.Story_Editor_DraftDiscaedText
|
||||||
case .stickerEditor:
|
case .stickerEditor, .botPreview:
|
||||||
title = presentationData.strings.Story_Editor_DraftDiscardMedia
|
title = presentationData.strings.Story_Editor_DraftDiscardMedia
|
||||||
text = presentationData.strings.Story_Editor_DiscardText
|
text = presentationData.strings.Story_Editor_DiscardText
|
||||||
}
|
}
|
||||||
@ -7435,12 +7447,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
|
|
||||||
private final class DoneButtonContentComponent: CombinedComponent {
|
private final class DoneButtonContentComponent: CombinedComponent {
|
||||||
let backgroundColor: UIColor
|
let backgroundColor: UIColor
|
||||||
let icon: UIImage
|
let icon: UIImage?
|
||||||
let title: String?
|
let title: String?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
backgroundColor: UIColor,
|
backgroundColor: UIColor,
|
||||||
icon: UIImage,
|
icon: UIImage?,
|
||||||
title: String?
|
title: String?
|
||||||
) {
|
) {
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
@ -7464,12 +7476,14 @@ private final class DoneButtonContentComponent: CombinedComponent {
|
|||||||
let text = Child(Text.self)
|
let text = Child(Text.self)
|
||||||
|
|
||||||
return { context in
|
return { context in
|
||||||
let iconSize = context.component.icon.size
|
var iconChild: _UpdatedChildComponent?
|
||||||
let icon = icon.update(
|
if let iconImage = context.component.icon {
|
||||||
component: Image(image: context.component.icon, tintColor: .white, size: iconSize),
|
iconChild = icon.update(
|
||||||
availableSize: CGSize(width: 180.0, height: 100.0),
|
component: Image(image: iconImage, tintColor: .white, size: iconImage.size),
|
||||||
transition: .immediate
|
availableSize: CGSize(width: 180.0, height: 100.0),
|
||||||
)
|
transition: .immediate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let backgroundHeight: CGFloat = 33.0
|
let backgroundHeight: CGFloat = 33.0
|
||||||
var backgroundSize = CGSize(width: backgroundHeight, height: backgroundHeight)
|
var backgroundSize = CGSize(width: backgroundHeight, height: backgroundHeight)
|
||||||
@ -7489,7 +7503,10 @@ private final class DoneButtonContentComponent: CombinedComponent {
|
|||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
|
|
||||||
let updatedBackgroundWidth = backgroundSize.width + textSpacing + title!.size.width
|
var updatedBackgroundWidth = backgroundSize.width + title!.size.width
|
||||||
|
if let _ = iconChild {
|
||||||
|
updatedBackgroundWidth += textSpacing
|
||||||
|
}
|
||||||
if updatedBackgroundWidth < 126.0 {
|
if updatedBackgroundWidth < 126.0 {
|
||||||
backgroundSize.width = updatedBackgroundWidth
|
backgroundSize.width = updatedBackgroundWidth
|
||||||
} else {
|
} else {
|
||||||
@ -7509,16 +7526,22 @@ private final class DoneButtonContentComponent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if let title {
|
if let title {
|
||||||
|
var titlePosition = backgroundSize.width / 2.0
|
||||||
|
if let _ = iconChild {
|
||||||
|
titlePosition = title.size.width / 2.0 + 15.0
|
||||||
|
}
|
||||||
context.add(title
|
context.add(title
|
||||||
.position(CGPoint(x: title.size.width / 2.0 + 15.0, y: backgroundHeight / 2.0))
|
.position(CGPoint(x: titlePosition, y: backgroundHeight / 2.0))
|
||||||
.opacity(hideTitle ? 0.0 : 1.0)
|
.opacity(hideTitle ? 0.0 : 1.0)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
context.add(icon
|
if let iconChild {
|
||||||
.position(CGPoint(x: background.size.width - 16.0, y: backgroundSize.height / 2.0))
|
context.add(iconChild
|
||||||
)
|
.position(CGPoint(x: background.size.width - 16.0, y: backgroundSize.height / 2.0))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return backgroundSize
|
return backgroundSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,9 +58,10 @@ func getWeather(context: AccountContext) -> Signal<StickerPickerScreen.Weather,
|
|||||||
return getWeatherData(context: context, location: location)
|
return getWeatherData(context: context, location: location)
|
||||||
|> mapToSignal { weather in
|
|> mapToSignal { weather in
|
||||||
if let weather {
|
if let weather {
|
||||||
if let match = context.animatedEmojiStickersValue[weather.emoji.strippedEmoji]?.first {
|
let effectiveEmoji = emojiFor(for: weather.emoji.strippedEmoji, date: Date(), location: location)
|
||||||
|
if let match = context.animatedEmojiStickersValue[effectiveEmoji]?.first {
|
||||||
return .single(.loaded(StickerPickerScreen.Weather.LoadedWeather(
|
return .single(.loaded(StickerPickerScreen.Weather.LoadedWeather(
|
||||||
emoji: weather.emoji.strippedEmoji,
|
emoji: effectiveEmoji,
|
||||||
emojiFile: match.file,
|
emojiFile: match.file,
|
||||||
temperature: weather.temperature
|
temperature: weather.temperature
|
||||||
)))
|
)))
|
||||||
@ -97,3 +98,123 @@ private struct WeatherBotConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let J1970: Double = 2440588.0
|
||||||
|
private let moonEmojis = ["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘", "🌑"]
|
||||||
|
|
||||||
|
private func emojiFor(for emoji: String, date: Date, location: CLLocationCoordinate2D) -> String {
|
||||||
|
var emoji = emoji
|
||||||
|
if !"".isEmpty, ["☀️", "🌤️"].contains(emoji) && !isDay(latitude: location.latitude, longitude: location.longitude, dateTime: date) {
|
||||||
|
emoji = moonPhaseEmoji(for: date)
|
||||||
|
}
|
||||||
|
return emoji
|
||||||
|
}
|
||||||
|
|
||||||
|
private func moonPhaseEmoji(for date: Date) -> String {
|
||||||
|
let julianDate = toJulianDate(date: date)
|
||||||
|
|
||||||
|
let referenceNewMoon: Double = 2451550.1
|
||||||
|
let synodicMonth: Double = 29.53058867
|
||||||
|
|
||||||
|
let daysSinceNewMoon = julianDate - referenceNewMoon
|
||||||
|
let newMoons = daysSinceNewMoon / synodicMonth
|
||||||
|
let currentMoonPhase = (newMoons - floor(newMoons)) * synodicMonth
|
||||||
|
|
||||||
|
switch currentMoonPhase {
|
||||||
|
case 0..<1.84566:
|
||||||
|
return moonEmojis[0]
|
||||||
|
case 1.84566..<5.53699:
|
||||||
|
return moonEmojis[1]
|
||||||
|
case 5.53699..<9.22831:
|
||||||
|
return moonEmojis[2]
|
||||||
|
case 9.22831..<12.91963:
|
||||||
|
return moonEmojis[3]
|
||||||
|
case 12.91963..<16.61096:
|
||||||
|
return moonEmojis[4]
|
||||||
|
case 16.61096..<20.30228:
|
||||||
|
return moonEmojis[5]
|
||||||
|
case 20.30228..<23.99361:
|
||||||
|
return moonEmojis[6]
|
||||||
|
case 23.99361..<27.68493:
|
||||||
|
return moonEmojis[7]
|
||||||
|
default:
|
||||||
|
return moonEmojis[8]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func isDay(latitude: Double, longitude: Double, dateTime: Date) -> Bool {
|
||||||
|
let calendar = Calendar.current
|
||||||
|
let date = calendar.startOfDay(for: dateTime)
|
||||||
|
let time = dateTime.timeIntervalSince(date)
|
||||||
|
|
||||||
|
let sunrise = calculateSunrise(latitude: latitude, longitude: longitude, date: date)
|
||||||
|
let sunset = calculateSunset(latitude: latitude, longitude: longitude, date: date)
|
||||||
|
|
||||||
|
return time >= sunrise * 3600 && time <= sunset * 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculateSunrise(latitude: Double, longitude: Double, date: Date) -> Double {
|
||||||
|
return calculateSunTime(latitude: latitude, longitude: longitude, date: date, isSunrise: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculateSunset(latitude: Double, longitude: Double, date: Date) -> Double {
|
||||||
|
return calculateSunTime(latitude: latitude, longitude: longitude, date: date, isSunrise: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculateSunTime(latitude: Double, longitude: Double, date: Date, isSunrise: Bool) -> Double {
|
||||||
|
let calendar = Calendar.current
|
||||||
|
let dayOfYear = calendar.ordinality(of: .day, in: .year, for: date)!
|
||||||
|
let zenith = 90.833
|
||||||
|
|
||||||
|
let D2R = Double.pi / 180.0
|
||||||
|
let R2D = 180.0 / Double.pi
|
||||||
|
|
||||||
|
let lngHour = longitude / 15.0
|
||||||
|
let t = Double(dayOfYear) + ((isSunrise ? 6.0 : 18.0) - lngHour) / 24.0
|
||||||
|
|
||||||
|
let M = (0.9856 * t) - 3.289
|
||||||
|
var L = M + (1.916 * sin(M * D2R)) + (0.020 * sin(2 * M * D2R)) + 282.634
|
||||||
|
|
||||||
|
if L > 360.0 {
|
||||||
|
L -= 360.0
|
||||||
|
} else if L < 0.0 {
|
||||||
|
L += 360.0
|
||||||
|
}
|
||||||
|
|
||||||
|
var RA = R2D * atan(0.91764 * tan(L * D2R))
|
||||||
|
if RA > 360.0 {
|
||||||
|
RA -= 360.0
|
||||||
|
} else if RA < 0.0 {
|
||||||
|
RA += 360.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let Lquadrant = (floor(L / 90.0)) * 90.0
|
||||||
|
let RAquadrant = (floor(RA / 90.0)) * 90.0
|
||||||
|
RA += (Lquadrant - RAquadrant)
|
||||||
|
RA /= 15.0
|
||||||
|
|
||||||
|
let sinDec = 0.39782 * sin(L * D2R)
|
||||||
|
let cosDec = cos(asin(sinDec))
|
||||||
|
|
||||||
|
let cosH = (cos(zenith * D2R) - (sinDec * sin(latitude * D2R))) / (cosDec * cos(latitude * D2R))
|
||||||
|
if cosH > 1.0 || cosH < -1.0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
var H = isSunrise ? (360.0 - R2D * acos(cosH)) : R2D * acos(cosH)
|
||||||
|
H /= 15.0
|
||||||
|
|
||||||
|
let T = H + RA - (0.06571 * t) - 6.622
|
||||||
|
var UT = T - lngHour
|
||||||
|
|
||||||
|
if UT > 24.0 {
|
||||||
|
UT -= 24.0
|
||||||
|
} else if UT < 0.0 {
|
||||||
|
UT += 24.0
|
||||||
|
}
|
||||||
|
return UT
|
||||||
|
}
|
||||||
|
|
||||||
|
private func toJulianDate(date: Date) -> Double {
|
||||||
|
return date.timeIntervalSince1970 / 86400.0 + J1970 - 0.5
|
||||||
|
}
|
||||||
|
|||||||
@ -9781,6 +9781,36 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
self.controller?.push(controller)
|
self.controller?.push(controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func openBotPreviewEditor(target: Stories.PendingTarget, source: Any, transitionIn: (UIView, CGRect, UIImage?)?) {
|
||||||
|
let context = self.context
|
||||||
|
|
||||||
|
let externalState = MediaEditorTransitionOutExternalState(
|
||||||
|
storyTarget: target,
|
||||||
|
isForcedTarget: false,
|
||||||
|
isPeerArchived: false,
|
||||||
|
transitionOut: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
let controller = context.sharedContext.makeBotPreviewEditorScreen(
|
||||||
|
context: context,
|
||||||
|
source: source,
|
||||||
|
target: target,
|
||||||
|
transitionArguments: transitionIn,
|
||||||
|
externalState: externalState,
|
||||||
|
completion: { result, commit in
|
||||||
|
if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
||||||
|
var viewControllers = rootController.viewControllers
|
||||||
|
viewControllers = viewControllers.filter { !($0 is AttachmentController)}
|
||||||
|
rootController.setViewControllers(viewControllers, animated: false)
|
||||||
|
|
||||||
|
rootController.proceedWithStoryUpload(target: target, result: result, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cancelled: {}
|
||||||
|
)
|
||||||
|
self.controller?.push(controller)
|
||||||
|
}
|
||||||
|
|
||||||
private func openPostStory(sourceFrame: CGRect?) {
|
private func openPostStory(sourceFrame: CGRect?) {
|
||||||
self.postingAvailabilityDisposable?.dispose()
|
self.postingAvailabilityDisposable?.dispose()
|
||||||
|
|
||||||
@ -9788,12 +9818,20 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
if !botInfo.flags.contains(.canEdit) {
|
if !botInfo.flags.contains(.canEdit) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let cameraTransitionIn: StoryCameraTransitionIn? = nil
|
let controller = self.context.sharedContext.makeStoryMediaPickerScreen(
|
||||||
|
context: self.context,
|
||||||
if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
isDark: false,
|
||||||
let coordinator = rootController.openStoryCamera(customTarget: .botPreview(self.peerId), transitionIn: cameraTransitionIn, transitionedIn: {}, transitionOut: self.storyCameraTransitionOut())
|
getSourceRect: { return .zero },
|
||||||
coordinator?.animateIn()
|
completion: { [weak self] result, transitionView, transitionRect, transitionImage, transitionOut, dismissed in
|
||||||
}
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.openBotPreviewEditor(target: .botPreview(self.peerId), source: result, transitionIn: (transitionView, transitionRect, transitionImage))
|
||||||
|
},
|
||||||
|
dismissed: {},
|
||||||
|
groupsPresented: {}
|
||||||
|
)
|
||||||
|
self.controller?.push(controller)
|
||||||
} else {
|
} else {
|
||||||
let canPostStatus: Signal<StoriesUploadAvailability, NoError>
|
let canPostStatus: Signal<StoriesUploadAvailability, NoError>
|
||||||
canPostStatus = self.context.engine.messages.checkStoriesUploadAvailability(target: .peer(self.peerId))
|
canPostStatus = self.context.engine.messages.checkStoriesUploadAvailability(target: .peer(self.peerId))
|
||||||
|
|||||||
@ -2533,6 +2533,46 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func makeBotPreviewEditorScreen(context: AccountContext, source: Any?, target: Stories.PendingTarget, transitionArguments: (UIView, CGRect, UIImage?)?, externalState: MediaEditorTransitionOutExternalState, completion: @escaping (MediaEditorScreenResult, @escaping (@escaping () -> Void) -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController {
|
||||||
|
let subject: Signal<MediaEditorScreen.Subject?, NoError>
|
||||||
|
if let asset = source as? PHAsset {
|
||||||
|
subject = .single(.asset(asset))
|
||||||
|
} else if let image = source as? UIImage {
|
||||||
|
subject = .single(.image(image, PixelDimensions(image.size), nil, .bottomRight))
|
||||||
|
} else {
|
||||||
|
subject = .single(.empty(PixelDimensions(width: 1080, height: 1920)))
|
||||||
|
}
|
||||||
|
let editorController = MediaEditorScreen(
|
||||||
|
context: context,
|
||||||
|
mode: .botPreview,
|
||||||
|
subject: subject,
|
||||||
|
customTarget: nil,
|
||||||
|
transitionIn: transitionArguments.flatMap { .gallery(
|
||||||
|
MediaEditorScreen.TransitionIn.GalleryTransitionIn(
|
||||||
|
sourceView: $0.0,
|
||||||
|
sourceRect: $0.1,
|
||||||
|
sourceImage: $0.2
|
||||||
|
)
|
||||||
|
) },
|
||||||
|
transitionOut: { finished, isNew in
|
||||||
|
if !finished, let transitionArguments {
|
||||||
|
return MediaEditorScreen.TransitionOut(
|
||||||
|
destinationView: transitionArguments.0,
|
||||||
|
destinationRect: transitionArguments.0.bounds,
|
||||||
|
destinationCornerRadius: 0.0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, completion: { result, commit in
|
||||||
|
completion(result, commit)
|
||||||
|
} as (MediaEditorScreen.Result, @escaping (@escaping () -> Void) -> Void) -> Void
|
||||||
|
)
|
||||||
|
editorController.cancelled = { _ in
|
||||||
|
cancelled()
|
||||||
|
}
|
||||||
|
return editorController
|
||||||
|
}
|
||||||
|
|
||||||
public func makeStickerEditorScreen(context: AccountContext, source: Any?, intro: Bool, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController {
|
public func makeStickerEditorScreen(context: AccountContext, source: Any?, intro: Bool, transitionArguments: (UIView, CGRect, UIImage?)?, completion: @escaping (TelegramMediaFile, [String], @escaping () -> Void) -> Void, cancelled: @escaping () -> Void) -> ViewController {
|
||||||
let subject: Signal<MediaEditorScreen.Subject?, NoError>
|
let subject: Signal<MediaEditorScreen.Subject?, NoError>
|
||||||
var mode: MediaEditorScreen.Mode.StickerEditorMode
|
var mode: MediaEditorScreen.Mode.StickerEditorMode
|
||||||
@ -2605,8 +2645,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return mediaPickerController(context: context, hasSearch: hasSearch, completion: completion)
|
return mediaPickerController(context: context, hasSearch: hasSearch, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeStoryMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect, completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void, groupsPresented: @escaping () -> Void) -> ViewController {
|
public func makeStoryMediaPickerScreen(context: AccountContext, isDark: Bool, getSourceRect: @escaping () -> CGRect, completion: @escaping (Any, UIView, CGRect, UIImage?, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void, groupsPresented: @escaping () -> Void) -> ViewController {
|
||||||
return storyMediaPickerController(context: context, getSourceRect: getSourceRect, completion: completion, dismissed: dismissed, groupsPresented: groupsPresented)
|
return storyMediaPickerController(context: context, isDark: isDark, getSourceRect: getSourceRect, completion: completion, dismissed: dismissed, groupsPresented: groupsPresented)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeStickerMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController {
|
public func makeStickerMediaPickerScreen(context: AccountContext, getSourceRect: @escaping () -> CGRect?, completion: @escaping (Any?, UIView?, CGRect, UIImage?, Bool, @escaping (Bool?) -> (UIView, CGRect)?, @escaping () -> Void) -> Void, dismissed: @escaping () -> Void) -> ViewController {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user