Various fixes

This commit is contained in:
Ilya Laktyushin 2024-07-21 00:29:07 +04:00
parent dfc5077946
commit b4415c251b
9 changed files with 306 additions and 278 deletions

View File

@ -12546,3 +12546,9 @@ Sorry for the inconvenience.";
"Stars.Intro.StarsSent_1" = "%@ Star sent.";
"Stars.Intro.StarsSent_any" = "%@ Stars sent.";
"Stars.Intro.StarsSent.ViewChat" = "View Chat";
"Stars.Gift.Received.Title" = "Received Gift";
"Stars.Gift.Received.Text" = "Use Stars to unlock content and services on Telegram. [See Examples >]()";
"Stars.Gift.Sent.Title" = "Sent Gift";
"Stars.Gift.Sent.Text" = "With Stars, %@ will be able to unlock content and services on Telegram. [See Examples >]()";

View File

@ -2274,7 +2274,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
safeInset += layout.safeInsets.right + 16.0
}
let navigationHeight = navigationLayout(layout: layout).navigationFrame.height
self.selectedButtonNode.frame = CGRect(origin: CGPoint(x: self.view.bounds.width - 54.0 - selectedSize.width - safeInset, y: floorToScreenPixels((navigationHeight - selectedSize.height) / 2.0) + UIScreenPixel), size: selectedSize)
self.selectedButtonNode.frame = CGRect(origin: CGPoint(x: self.view.bounds.width - 54.0 - selectedSize.width - safeInset, y: floorToScreenPixels((navigationHeight - selectedSize.height) / 2.0) + 1.0), size: selectedSize)
let isSelectionButtonVisible = count > 0 && self.controllerNode.currentDisplayMode == .all
transition.updateAlpha(node: self.selectedButtonNode, alpha: isSelectionButtonVisible ? 1.0 : 0.0)
@ -2677,7 +2677,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
safeInset += layout.safeInsets.right + 16.0
}
let navigationHeight = navigationLayout(layout: layout).navigationFrame.height
self.selectedButtonNode.frame = CGRect(origin: CGPoint(x: self.view.bounds.width - 54.0 - self.selectedButtonNode.frame.width - safeInset, y: floorToScreenPixels((navigationHeight - self.selectedButtonNode.frame.height) / 2.0) + UIScreenPixel), size: self.selectedButtonNode.frame.size)
self.selectedButtonNode.frame = CGRect(origin: CGPoint(x: self.view.bounds.width - 54.0 - self.selectedButtonNode.frame.width - safeInset, y: floorToScreenPixels((navigationHeight - self.selectedButtonNode.frame.height) / 2.0) + 1.0), size: self.selectedButtonNode.frame.size)
}
public var mediaPickerContext: AttachmentMediaPickerContext? {

View File

@ -2720,7 +2720,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
if url.hasPrefix("https://apps.apple.com/account/subscriptions") {
controller.context.sharedContext.applicationBindings.openSubscriptions()
} else if url.hasPrefix("https://") || url.hasPrefix("tg://") {
controller.context.sharedContext.openExternalUrl(context: controller.context, urlContext: .generic, url: url, forceExternal: !url.hasPrefix("tg://") && !url.contains("?start="), presentationData: controller.context.sharedContext.currentPresentationData.with({$0}), navigationController: navigationController, dismissInput: {})
controller.context.sharedContext.openExternalUrl(context: controller.context, urlContext: .generic, url: url, forceExternal: false, presentationData: controller.context.sharedContext.currentPresentationData.with({$0}), navigationController: navigationController, dismissInput: {})
} else {
let context = controller.context
let signal: Signal<ResolvedUrl, NoError>?

View File

@ -1198,6 +1198,7 @@ final class MediaEditorScreenComponent: Component {
let displayTopButtons = !(self.inputPanelExternalState.isEditing || isEditingTextEntity || component.isDisplayingTool != nil)
var inputPanelSize: CGSize = .zero
if case .storyEditor = controller.mode {
let nextInputMode: MessageInputPanelComponent.InputMode
switch self.currentInputMode {
@ -1217,7 +1218,7 @@ final class MediaEditorScreenComponent: Component {
}
self.inputPanel.parentState = state
let inputPanelSize = self.inputPanel.update(
inputPanelSize = self.inputPanel.update(
transition: transition,
component: AnyComponent(MessageInputPanelComponent(
externalState: self.inputPanelExternalState,
@ -1429,192 +1430,7 @@ final class MediaEditorScreenComponent: Component {
transition.setFrame(view: inputPanelView, frame: inputPanelFrame)
transition.setAlpha(view: inputPanelView, alpha: isEditingTextEntity || component.isDisplayingTool != nil || component.isDismissing || component.isInteractingWithEntities ? 0.0 : 1.0)
}
if let playerState = state.playerState {
let scrubberInset: CGFloat = 9.0
let minDuration: Double
let maxDuration: Double
if playerState.isAudioOnly {
minDuration = 5.0
maxDuration = 15.0
} else {
minDuration = 1.0
maxDuration = storyMaxVideoDuration
}
let previousTrackCount = self.currentVisibleTracks?.count
let visibleTracks = playerState.tracks.filter { $0.visibleInTimeline }.map { MediaScrubberComponent.Track($0) }
self.currentVisibleTracks = visibleTracks
var scrubberTransition = transition
if let previousTrackCount, previousTrackCount != visibleTracks.count {
scrubberTransition = .easeInOut(duration: 0.2)
}
let isAudioOnly = playerState.isAudioOnly
let hasMainVideoTrack = playerState.tracks.contains(where: { $0.id == 0 })
let scrubber: ComponentView<Empty>
if let current = self.scrubber {
scrubber = current
} else {
scrubber = ComponentView<Empty>()
self.scrubber = scrubber
}
let scrubberSize = scrubber.update(
transition: scrubberTransition,
component: AnyComponent(MediaScrubberComponent(
context: component.context,
style: .editor,
theme: environment.theme,
generationTimestamp: playerState.generationTimestamp,
position: playerState.position,
minDuration: minDuration,
maxDuration: maxDuration,
isPlaying: playerState.isPlaying,
tracks: visibleTracks,
positionUpdated: { [weak mediaEditor] position, apply in
if let mediaEditor {
mediaEditor.seek(position, andPlay: apply)
}
},
trackTrimUpdated: { [weak mediaEditor] trackId, start, end, updatedEnd, apply in
guard let mediaEditor else {
return
}
let trimRange = start..<end
if trackId == 2 {
mediaEditor.setAudioTrackTrimRange(trimRange, apply: apply)
if isAudioOnly {
let offset = (mediaEditor.values.audioTrackOffset ?? 0.0)
if apply {
mediaEditor.seek(offset + start, andPlay: true)
} else {
mediaEditor.seek(offset + start, andPlay: false)
mediaEditor.stop()
}
} else {
if apply {
mediaEditor.play()
} else {
mediaEditor.stop()
}
}
} else if trackId == 1 {
mediaEditor.setAdditionalVideoTrimRange(trimRange, apply: apply)
if hasMainVideoTrack {
if apply {
mediaEditor.play()
} else {
mediaEditor.stop()
}
} else {
if apply {
mediaEditor.seek(start, andPlay: true)
} else {
mediaEditor.seek(updatedEnd ? end : start, andPlay: false)
}
}
} else {
mediaEditor.setVideoTrimRange(trimRange, apply: apply)
if apply {
mediaEditor.seek(start, andPlay: true)
} else {
mediaEditor.seek(updatedEnd ? end : start, andPlay: false)
}
}
},
trackOffsetUpdated: { trackId, offset, apply in
guard let mediaEditor else {
return
}
if trackId == 2 {
mediaEditor.setAudioTrackOffset(offset, apply: apply)
if isAudioOnly {
let offset = (mediaEditor.values.audioTrackOffset ?? 0.0)
let start = (mediaEditor.values.audioTrackTrimRange?.lowerBound ?? 0.0)
if apply {
mediaEditor.seek(offset + start, andPlay: true)
} else {
mediaEditor.seek(offset + start, andPlay: false)
mediaEditor.stop()
}
} else {
if apply {
let audioStart = mediaEditor.values.audioTrackTrimRange?.lowerBound ?? 0.0
let audioOffset = min(0.0, mediaEditor.values.audioTrackOffset ?? 0.0)
var start = -audioOffset + audioStart
if let duration = mediaEditor.duration {
let lowerBound = mediaEditor.values.videoTrimRange?.lowerBound ?? 0.0
let upperBound = mediaEditor.values.videoTrimRange?.upperBound ?? duration
if start >= upperBound {
start = lowerBound
} else if start < lowerBound {
start = lowerBound
}
}
mediaEditor.seek(start, andPlay: true)
mediaEditor.play()
} else {
mediaEditor.stop()
}
}
} else if trackId == 1 {
mediaEditor.setAdditionalVideoOffset(offset, apply: apply)
}
},
trackLongPressed: { [weak controller] trackId, sourceView in
guard let controller else {
return
}
controller.node.presentTrackOptions(trackId: trackId, sourceView: sourceView)
}
)),
environment: {},
containerSize: CGSize(width: previewSize.width - scrubberInset * 2.0, height: availableSize.height)
)
let scrubberFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - scrubberSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - scrubberSize.height + controlsBottomInset - inputPanelSize.height + 3.0), size: scrubberSize)
if let scrubberView = scrubber.view {
var animateIn = false
if scrubberView.superview == nil {
animateIn = true
if let inputPanelBackgroundView = self.inputPanelBackground.view, inputPanelBackgroundView.superview != nil {
self.insertSubview(scrubberView, belowSubview: inputPanelBackgroundView)
} else {
self.addSubview(scrubberView)
}
}
if animateIn {
scrubberView.frame = scrubberFrame
} else {
scrubberTransition.setFrame(view: scrubberView, frame: scrubberFrame)
}
if !self.animatingButtons && !(!hasMainVideoTrack && animateIn) {
transition.setAlpha(view: scrubberView, alpha: component.isDisplayingTool != nil || component.isDismissing || component.isInteractingWithEntities || isEditingCaption || isRecordingAdditionalVideo || isEditingTextEntity ? 0.0 : 1.0)
} else if animateIn {
scrubberView.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
scrubberView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
scrubberView.layer.animateScale(from: 0.6, to: 1.0, duration: 0.2)
}
}
} else {
if let scrubber = self.scrubber {
self.scrubber = nil
if let scrubberView = scrubber.view {
scrubberView.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 44.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
scrubberView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
scrubberView.removeFromSuperview()
})
scrubberView.layer.animateScale(from: 1.0, to: 0.6, duration: 0.2, removeOnCompletion: false)
}
}
}
let saveContentComponent: AnyComponentWithIdentity<Empty>
if component.hasAppeared {
saveContentComponent = AnyComponentWithIdentity(
@ -1971,8 +1787,199 @@ final class MediaEditorScreenComponent: Component {
transition.setScale(view: switchCameraButtonView, scale: isRecordingAdditionalVideo ? 1.0 : 0.01)
transition.setAlpha(view: switchCameraButtonView, alpha: isRecordingAdditionalVideo ? 1.0 : 0.0)
}
} else {
inputPanelSize = CGSize(width: 0.0, height: 12.0)
}
if case .stickerEditor = controller.mode {
} else {
if let playerState = state.playerState {
let scrubberInset: CGFloat = 9.0
let minDuration: Double
let maxDuration: Double
if playerState.isAudioOnly {
minDuration = 5.0
maxDuration = 15.0
} else {
minDuration = 1.0
maxDuration = storyMaxVideoDuration
}
let previousTrackCount = self.currentVisibleTracks?.count
let visibleTracks = playerState.tracks.filter { $0.visibleInTimeline }.map { MediaScrubberComponent.Track($0) }
self.currentVisibleTracks = visibleTracks
var scrubberTransition = transition
if let previousTrackCount, previousTrackCount != visibleTracks.count {
scrubberTransition = .easeInOut(duration: 0.2)
}
let isAudioOnly = playerState.isAudioOnly
let hasMainVideoTrack = playerState.tracks.contains(where: { $0.id == 0 })
let scrubber: ComponentView<Empty>
if let current = self.scrubber {
scrubber = current
} else {
scrubber = ComponentView<Empty>()
self.scrubber = scrubber
}
let scrubberSize = scrubber.update(
transition: scrubberTransition,
component: AnyComponent(MediaScrubberComponent(
context: component.context,
style: .editor,
theme: environment.theme,
generationTimestamp: playerState.generationTimestamp,
position: playerState.position,
minDuration: minDuration,
maxDuration: maxDuration,
isPlaying: playerState.isPlaying,
tracks: visibleTracks,
positionUpdated: { [weak mediaEditor] position, apply in
if let mediaEditor {
mediaEditor.seek(position, andPlay: apply)
}
},
trackTrimUpdated: { [weak mediaEditor] trackId, start, end, updatedEnd, apply in
guard let mediaEditor else {
return
}
let trimRange = start..<end
if trackId == 2 {
mediaEditor.setAudioTrackTrimRange(trimRange, apply: apply)
if isAudioOnly {
let offset = (mediaEditor.values.audioTrackOffset ?? 0.0)
if apply {
mediaEditor.seek(offset + start, andPlay: true)
} else {
mediaEditor.seek(offset + start, andPlay: false)
mediaEditor.stop()
}
} else {
if apply {
mediaEditor.play()
} else {
mediaEditor.stop()
}
}
} else if trackId == 1 {
mediaEditor.setAdditionalVideoTrimRange(trimRange, apply: apply)
if hasMainVideoTrack {
if apply {
mediaEditor.play()
} else {
mediaEditor.stop()
}
} else {
if apply {
mediaEditor.seek(start, andPlay: true)
} else {
mediaEditor.seek(updatedEnd ? end : start, andPlay: false)
}
}
} else {
mediaEditor.setVideoTrimRange(trimRange, apply: apply)
if apply {
mediaEditor.seek(start, andPlay: true)
} else {
mediaEditor.seek(updatedEnd ? end : start, andPlay: false)
}
}
},
trackOffsetUpdated: { trackId, offset, apply in
guard let mediaEditor else {
return
}
if trackId == 2 {
mediaEditor.setAudioTrackOffset(offset, apply: apply)
if isAudioOnly {
let offset = (mediaEditor.values.audioTrackOffset ?? 0.0)
let start = (mediaEditor.values.audioTrackTrimRange?.lowerBound ?? 0.0)
if apply {
mediaEditor.seek(offset + start, andPlay: true)
} else {
mediaEditor.seek(offset + start, andPlay: false)
mediaEditor.stop()
}
} else {
if apply {
let audioStart = mediaEditor.values.audioTrackTrimRange?.lowerBound ?? 0.0
let audioOffset = min(0.0, mediaEditor.values.audioTrackOffset ?? 0.0)
var start = -audioOffset + audioStart
if let duration = mediaEditor.duration {
let lowerBound = mediaEditor.values.videoTrimRange?.lowerBound ?? 0.0
let upperBound = mediaEditor.values.videoTrimRange?.upperBound ?? duration
if start >= upperBound {
start = lowerBound
} else if start < lowerBound {
start = lowerBound
}
}
mediaEditor.seek(start, andPlay: true)
mediaEditor.play()
} else {
mediaEditor.stop()
}
}
} else if trackId == 1 {
mediaEditor.setAdditionalVideoOffset(offset, apply: apply)
}
},
trackLongPressed: { [weak controller] trackId, sourceView in
guard let controller else {
return
}
controller.node.presentTrackOptions(trackId: trackId, sourceView: sourceView)
}
)),
environment: {},
containerSize: CGSize(width: previewSize.width - scrubberInset * 2.0, height: availableSize.height)
)
let scrubberFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - scrubberSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - scrubberSize.height + controlsBottomInset - inputPanelSize.height + 3.0), size: scrubberSize)
if let scrubberView = scrubber.view {
var animateIn = false
if scrubberView.superview == nil {
animateIn = true
if let inputPanelBackgroundView = self.inputPanelBackground.view, inputPanelBackgroundView.superview != nil {
self.insertSubview(scrubberView, belowSubview: inputPanelBackgroundView)
} else {
self.addSubview(scrubberView)
}
}
if animateIn {
scrubberView.frame = scrubberFrame
} else {
scrubberTransition.setFrame(view: scrubberView, frame: scrubberFrame)
}
if !self.animatingButtons && !(!hasMainVideoTrack && animateIn) {
transition.setAlpha(view: scrubberView, alpha: component.isDisplayingTool != nil || component.isDismissing || component.isInteractingWithEntities || isEditingCaption || isRecordingAdditionalVideo || isEditingTextEntity ? 0.0 : 1.0)
} else if animateIn {
scrubberView.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
scrubberView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
scrubberView.layer.animateScale(from: 0.6, to: 1.0, duration: 0.2)
}
}
} else {
if let scrubber = self.scrubber {
self.scrubber = nil
if let scrubberView = scrubber.view {
scrubberView.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 44.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
scrubberView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
scrubberView.removeFromSuperview()
})
scrubberView.layer.animateScale(from: 1.0, to: 0.6, duration: 0.2, removeOnCompletion: false)
}
}
}
}
if case .stickerEditor = controller.mode {
var stickerButtonsHidden = buttonsAreHidden
if let displayingTool = component.isDisplayingTool, [.cutoutErase, .cutoutRestore].contains(displayingTool) {

View File

@ -5,6 +5,7 @@ import TelegramCore
import StickerPickerScreen
import AccountContext
import DeviceLocationManager
import DeviceAccess
struct StoryWeather {
let emoji: String
@ -50,33 +51,44 @@ func getWeather(context: AccountContext) -> Signal<StickerPickerScreen.Weather,
guard let locationManager = context.sharedContext.locationManager else {
return .single(.none)
}
return .single(.fetching)
|> then(
currentLocationManagerCoordinate(manager: locationManager, timeout: 5.0)
|> mapToSignal { location in
if let location {
return getWeatherData(context: context, location: location)
|> mapToSignal { weather in
if let weather {
let effectiveEmoji = emojiFor(for: weather.emoji.strippedEmoji, date: Date(), location: location)
if let match = context.animatedEmojiStickersValue[effectiveEmoji]?.first {
return .single(.loaded(StickerPickerScreen.Weather.LoadedWeather(
emoji: effectiveEmoji,
emojiFile: match.file,
temperature: weather.temperature
)))
} else {
return .single(.none)
return DeviceAccess.authorizationStatus(subject: .location(.send))
|> mapToSignal { status in
switch status {
case .notDetermined:
return .single(.notDetermined)
case .denied, .restricted, .unreachable:
return .single(.notAllowed)
case .allowed:
return .single(.fetching)
|> then(
currentLocationManagerCoordinate(manager: locationManager, timeout: 5.0)
|> mapToSignal { location in
if let location {
return getWeatherData(context: context, location: location)
|> mapToSignal { weather in
if let weather {
let effectiveEmoji = emojiFor(for: weather.emoji.strippedEmoji, date: Date(), location: location)
if let match = context.animatedEmojiStickersValue[effectiveEmoji]?.first {
return .single(.loaded(StickerPickerScreen.Weather.LoadedWeather(
emoji: effectiveEmoji,
emojiFile: match.file,
temperature: weather.temperature
)))
} else {
return .single(.none)
}
} else {
return .single(.none)
}
}
} else {
return .single(.none)
}
}
} else {
return .single(.none)
}
)
}
)
}
}
private struct WeatherBotConfiguration {

View File

@ -200,8 +200,8 @@ private final class StarsTransactionSheetContent: CombinedComponent {
switch subject {
case let .transaction(transaction, parentPeer):
if transaction.flags.contains(.isGift) {
titleText = "Received Gift"
descriptionText = "Use Stars to unlock content and services on Telegram. [See Examples >]()"
titleText = strings.Stars_Gift_Received_Title
descriptionText = strings.Stars_Gift_Received_Text
count = transaction.count
countOnTop = true
transactionId = transaction.id
@ -218,7 +218,6 @@ private final class StarsTransactionSheetContent: CombinedComponent {
photo = nil
isRefund = false
isGift = true
delayedCloseOnOpenPeer = false
} else {
switch transaction.peer {
case let .peer(peer):
@ -320,9 +319,9 @@ private final class StarsTransactionSheetContent: CombinedComponent {
delayedCloseOnOpenPeer = false
case let .gift(message):
let incoming = message.flags.contains(.Incoming)
titleText = incoming ? "Received Gift" : "Sent Gift"
titleText = incoming ? strings.Stars_Gift_Received_Title : strings.Stars_Gift_Sent_Title
let peerName = state.peerMap[message.id.peerId]?.compactDisplayTitle ?? ""
descriptionText = incoming ? "Use Stars to unlock content and services on Telegram. [See Examples >]()" : "With Stars, \(peerName) will be able to unlock content and services on Telegram. [See Examples >]()"
descriptionText = incoming ? strings.Stars_Gift_Received_Text : strings.Stars_Gift_Sent_Text(peerName).string
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction, case let .giftStars(_, _, countValue, _, _, _) = action.action {
count = countValue
if !incoming {
@ -346,7 +345,6 @@ private final class StarsTransactionSheetContent: CombinedComponent {
photo = nil
isRefund = false
isGift = true
delayedCloseOnOpenPeer = false
}
if let spaceRegex {
let nsRange = NSRange(descriptionText.startIndex..., in: descriptionText)
@ -484,10 +482,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
)
),
action: {
if toPeer.id.namespace == Namespaces.Peer.CloudUser && toPeer.id.id._internalGetInt64Value() == 777000 {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_Transaction_FragmentUnknown_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
} else if delayedCloseOnOpenPeer {
if delayedCloseOnOpenPeer {
component.openPeer(toPeer)
Queue.mainQueue().after(1.0, {
component.cancel(false)
@ -607,8 +602,11 @@ private final class StarsTransactionSheetContent: CombinedComponent {
}
},
tapAction: { attributes, _ in
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_Transaction_Terms_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
if let controller = controller() as? StarsTransactionScreen, let navigationController = controller.navigationController as? NavigationController {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_Transaction_Terms_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
component.cancel(true)
}
}
),
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),

View File

@ -466,8 +466,10 @@ final class StarsStatisticsScreenComponent: Component {
return nil
}
},
tapAction: { attributes, _ in
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_BotRevenue_Withdraw_Info_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
tapAction: { [weak self] attributes, _ in
if let controller = self?.controller?() as? StarsStatisticsScreen, let navigationController = controller.navigationController as? NavigationController {
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_BotRevenue_Withdraw_Info_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
}
}
)),
items: [AnyComponentWithIdentity(id: 0, component: AnyComponent(

View File

@ -66,6 +66,8 @@ private final class SheetContent: CombinedComponent {
let component = context.component
let state = context.state
let controller = environment.controller
let theme = environment.theme.withModalBlocksBackground()
let strings = environment.strings
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
@ -229,7 +231,9 @@ private final class SheetContent: CombinedComponent {
}
},
tapAction: { attributes, _ in
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_PaidContent_AmountInfo_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
if let controller = controller() as? StarsWithdrawScreen, let navigationController = controller.navigationController as? NavigationController {
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_PaidContent_AmountInfo_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
}
}
))
case let .reaction(starsToTop):
@ -307,7 +311,6 @@ private final class SheetContent: CombinedComponent {
buttonAttributedString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: buttonAttributedString.string))
}
let controller = environment.controller
let button = button.update(
component: ButtonComponent(
background: ButtonComponent.Background(

View File

@ -2065,6 +2065,8 @@ public class StickerPickerScreen: ViewController {
}
case none
case notDetermined
case notAllowed
case fetching
case loaded(StickerPickerScreen.Weather.LoadedWeather)
}
@ -2722,66 +2724,64 @@ final class StoryStickersContentView: UIView, EmojiCustomContentView {
} else {
maxHorizontalItems = 3
let weatherButtonContent: AnyComponent<Empty>
switch self.weather {
case .notAllowed, .notDetermined:
weatherButtonContent = AnyComponent(
InteractiveStickerButtonContent(
context: self.context,
theme: theme,
title: stringForTemperature(24),
iconName: "☀️",
iconFile: self.context.animatedEmojiStickersValue["☀️"]?.first?.file,
useOpaqueTheme: useOpaqueTheme,
tintContainerView: self.tintContainerView
)
)
case let .loaded(weather):
items.append(
AnyComponentWithIdentity(
id: "weather",
component: AnyComponent(
CameraButton(
content: AnyComponentWithIdentity(
id: "weather",
component: AnyComponent(
InteractiveStickerButtonContent(
context: self.context,
theme: theme,
title: stringForTemperature(weather.temperature),
iconName: weather.emoji,
iconFile: weather.emojiFile,
useOpaqueTheme: useOpaqueTheme,
tintContainerView: self.tintContainerView
)
)
),
action: { [weak self] in
if let self {
self.weatherAction()
}
})
)
weatherButtonContent = AnyComponent(
InteractiveStickerButtonContent(
context: self.context,
theme: theme,
title: stringForTemperature(weather.temperature),
iconName: weather.emoji,
iconFile: weather.emojiFile,
useOpaqueTheme: useOpaqueTheme,
tintContainerView: self.tintContainerView
)
)
case .fetching:
items.append(
AnyComponentWithIdentity(
id: "weather",
component: AnyComponent(
CameraButton(
content: AnyComponentWithIdentity(
id: "weather",
component: AnyComponent(
InteractiveStickerButtonContent(
context: self.context,
theme: theme,
title: nil,
iconName: nil,
useOpaqueTheme: useOpaqueTheme,
tintContainerView: self.tintContainerView
)
)
),
action: { [weak self] in
if let self {
self.weatherAction()
}
})
)
weatherButtonContent = AnyComponent(
InteractiveStickerButtonContent(
context: self.context,
theme: theme,
title: nil,
iconName: nil,
useOpaqueTheme: useOpaqueTheme,
tintContainerView: self.tintContainerView
)
)
default:
fatalError()
}
items.append(
AnyComponentWithIdentity(
id: "weather",
component: AnyComponent(
CameraButton(
content: AnyComponentWithIdentity(
id: "weather",
component: weatherButtonContent
),
action: { [weak self] in
if let self {
self.weatherAction()
}
})
)
)
)
}
items.append(