mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
10d5fdcac3
commit
c5081979f0
@ -14293,3 +14293,6 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Gift.Resale.Unavailable.Title" = "Resell Gift";
|
"Gift.Resale.Unavailable.Title" = "Resell Gift";
|
||||||
"Gift.Resale.Unavailable.Text" = "Sorry, you can't list this gift yet.\n\Reselling will be available on %@.";
|
"Gift.Resale.Unavailable.Text" = "Sorry, you can't list this gift yet.\n\Reselling will be available on %@.";
|
||||||
|
|
||||||
|
"Gift.Transfer.Unavailable.Title" = "Transfer Gift";
|
||||||
|
"Gift.Transfer.Unavailable.Text" = "Sorry, you can't transfer this gift yet.\n\Transferring will be available on %@.";
|
||||||
|
@ -101,6 +101,7 @@ public enum PremiumLimitSubject {
|
|||||||
case membershipInSharedFolders
|
case membershipInSharedFolders
|
||||||
case channels
|
case channels
|
||||||
case expiringStories
|
case expiringStories
|
||||||
|
case multiStories
|
||||||
case storiesWeekly
|
case storiesWeekly
|
||||||
case storiesMonthly
|
case storiesMonthly
|
||||||
case storiesChannelBoost(peer: EnginePeer, isCurrent: Bool, level: Int32, currentLevelBoosts: Int32, nextLevelBoosts: Int32?, link: String?, myBoostCount: Int32, canBoostAgain: Bool)
|
case storiesChannelBoost(peer: EnginePeer, isCurrent: Bool, level: Int32, currentLevelBoosts: Int32, nextLevelBoosts: Int32?, link: String?, myBoostCount: Int32, canBoostAgain: Bool)
|
||||||
|
@ -388,10 +388,10 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
|
|
||||||
self.itemsDisposable = (updatedState
|
self.itemsDisposable = (updatedState
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||||
guard let strongSelf = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.updateState(state)
|
self.updateState(state)
|
||||||
})
|
})
|
||||||
|
|
||||||
self.gridNode.scrollingInitiated = { [weak self] in
|
self.gridNode.scrollingInitiated = { [weak self] in
|
||||||
@ -404,15 +404,16 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
|
|
||||||
self.hiddenMediaDisposable = (self.hiddenMediaId.get()
|
self.hiddenMediaDisposable = (self.hiddenMediaId.get()
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] id in
|
|> deliverOnMainQueue).start(next: { [weak self] id in
|
||||||
if let strongSelf = self {
|
guard let self else {
|
||||||
strongSelf.controller?.interaction?.hiddenMediaId = id
|
return
|
||||||
strongSelf.gridNode.forEachItemNode { itemNode in
|
|
||||||
if let itemNode = itemNode as? MediaPickerGridItemNode {
|
|
||||||
itemNode.updateHiddenMedia()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strongSelf.selectionNode?.updateHiddenMedia()
|
|
||||||
}
|
}
|
||||||
|
self.controller?.interaction?.hiddenMediaId = id
|
||||||
|
self.gridNode.forEachItemNode { itemNode in
|
||||||
|
if let itemNode = itemNode as? MediaPickerGridItemNode {
|
||||||
|
itemNode.updateHiddenMedia()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.selectionNode?.updateHiddenMedia()
|
||||||
})
|
})
|
||||||
|
|
||||||
if let selectionState = self.controller?.interaction?.selectionState {
|
if let selectionState = self.controller?.interaction?.selectionState {
|
||||||
@ -431,8 +432,8 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
|
|
||||||
self.selectionChangedDisposable = (selectionChangedSignal(selectionState: selectionState)
|
self.selectionChangedDisposable = (selectionChangedSignal(selectionState: selectionState)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] animated in
|
|> deliverOnMainQueue).start(next: { [weak self] animated in
|
||||||
if let strongSelf = self {
|
if let self {
|
||||||
strongSelf.updateSelectionState(animated: animated)
|
self.updateSelectionState(animated: animated)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -451,8 +452,8 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
|
|
||||||
self.itemsDimensionsUpdatedDisposable = (itemsDimensionsUpdatedSignal(editingState: editingState)
|
self.itemsDimensionsUpdatedDisposable = (itemsDimensionsUpdatedSignal(editingState: editingState)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||||
if let strongSelf = self {
|
if let self {
|
||||||
strongSelf.updateSelectionState()
|
self.updateSelectionState()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -536,8 +537,8 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
self?.gridNode.scrollView.isScrollEnabled = isEnabled
|
self?.gridNode.scrollView.isScrollEnabled = isEnabled
|
||||||
}
|
}
|
||||||
selectionGesture.itemAt = { [weak self] point in
|
selectionGesture.itemAt = { [weak self] point in
|
||||||
if let strongSelf = self, let itemNode = strongSelf.gridNode.itemNodeAtPoint(point) as? MediaPickerGridItemNode, let selectableItem = itemNode.selectableItem {
|
if let self, let itemNode = self.gridNode.itemNodeAtPoint(point) as? MediaPickerGridItemNode, let selectableItem = itemNode.selectableItem {
|
||||||
return (selectableItem, strongSelf.controller?.interaction?.selectionState?.isIdentifierSelected(selectableItem.uniqueIdentifier) ?? false)
|
return (selectableItem, self.controller?.interaction?.selectionState?.isIdentifierSelected(selectableItem.uniqueIdentifier) ?? false)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -2004,8 +2005,11 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
var hasSelect = false
|
var hasSelect = false
|
||||||
if forCollage {
|
if forCollage {
|
||||||
hasSelect = true
|
hasSelect = true
|
||||||
} else if case .story = mode, selectionContext.selectionLimit > 1 {
|
} else if case .story = mode {
|
||||||
hasSelect = true
|
if selectionContext.selectionLimit == 1 && context.isPremium {
|
||||||
|
} else {
|
||||||
|
hasSelect = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasSelect {
|
if hasSelect {
|
||||||
@ -2584,6 +2588,34 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func selectPressed() {
|
@objc private func selectPressed() {
|
||||||
|
let context = self.context
|
||||||
|
if let selectionState = self.interaction?.selectionState, selectionState.selectionLimit == 1, !context.isPremium {
|
||||||
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
|
let controller = context.sharedContext.makePremiumLimitController(
|
||||||
|
context: self.context,
|
||||||
|
subject: .multiStories,
|
||||||
|
count: 1,
|
||||||
|
forceDark: true,
|
||||||
|
cancel: {},
|
||||||
|
action: {
|
||||||
|
let controller = context.sharedContext.makePremiumIntroController(
|
||||||
|
context: context,
|
||||||
|
source: .stories,
|
||||||
|
forceDark: true,
|
||||||
|
dismissed: nil
|
||||||
|
)
|
||||||
|
replaceImpl?(controller)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
replaceImpl = { [weak controller] c in
|
||||||
|
controller?.replace(with: c)
|
||||||
|
}
|
||||||
|
self.requestDismiss {
|
||||||
|
self.parentController()?.push(controller)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
self.navigationItem.setRightBarButton(nil, animated: true)
|
self.navigationItem.setRightBarButton(nil, animated: true)
|
||||||
self.explicitMultipleSelection = true
|
self.explicitMultipleSelection = true
|
||||||
|
|
||||||
@ -2724,11 +2756,10 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
loop: true
|
loop: true
|
||||||
), action: { [weak self] _, f in
|
), action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
guard let strongSelf = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState {
|
||||||
if let selectionContext = strongSelf.interaction?.selectionState, let editingContext = strongSelf.interaction?.editingState {
|
|
||||||
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
||||||
editingContext.setSpoiler(hasGeneric, for: item)
|
editingContext.setSpoiler(hasGeneric, for: item)
|
||||||
}
|
}
|
||||||
@ -2754,10 +2785,10 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = self.context.sharedContext.makeStarsAmountScreen(context: self.context, initialValue: price, completion: { [weak self] amount in
|
let controller = self.context.sharedContext.makeStarsAmountScreen(context: self.context, initialValue: price, completion: { [weak self] amount in
|
||||||
guard let strongSelf = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let selectionContext = strongSelf.interaction?.selectionState, let editingContext = strongSelf.interaction?.editingState {
|
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState {
|
||||||
selectionContext.selectionLimit = 10
|
selectionContext.selectionLimit = 10
|
||||||
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
||||||
editingContext.setPrice(NSNumber(value: amount), for: item)
|
editingContext.setPrice(NSNumber(value: amount), for: item)
|
||||||
|
@ -1101,6 +1101,30 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
badgePosition = max(0.32, CGFloat(component.count) / CGFloat(premiumLimit))
|
badgePosition = max(0.32, CGFloat(component.count) / CGFloat(premiumLimit))
|
||||||
badgeGraphPosition = badgePosition
|
badgeGraphPosition = badgePosition
|
||||||
|
|
||||||
|
if isPremiumDisabled {
|
||||||
|
badgeText = "\(limit)"
|
||||||
|
let numberString = strings.Premium_MaxExpiringStoriesNoPremiumTextNumberFormat(Int32(limit))
|
||||||
|
string = strings.Premium_MaxExpiringStoriesNoPremiumTextFormat(numberString).string
|
||||||
|
}
|
||||||
|
buttonAnimationName = nil
|
||||||
|
case .multiStories:
|
||||||
|
let limit = state.limits.maxExpiringStoriesCount
|
||||||
|
let premiumLimit = state.premiumLimits.maxExpiringStoriesCount
|
||||||
|
iconName = "Premium/Stories"
|
||||||
|
badgeText = "\(limit)"
|
||||||
|
if component.count >= premiumLimit {
|
||||||
|
let limitNumberString = strings.Premium_MaxExpiringStoriesFinalTextNumberFormat(Int32(premiumLimit))
|
||||||
|
string = strings.Premium_MaxExpiringStoriesFinalTextFormat(limitNumberString).string
|
||||||
|
} else {
|
||||||
|
let limitNumberString = strings.Premium_MaxExpiringStoriesTextNumberFormat(Int32(limit))
|
||||||
|
let premiumLimitNumberString = strings.Premium_MaxExpiringStoriesTextPremiumNumberFormat(Int32(premiumLimit))
|
||||||
|
string = strings.Premium_MaxExpiringStoriesTextFormat(limitNumberString, premiumLimitNumberString).string
|
||||||
|
}
|
||||||
|
defaultValue = ""
|
||||||
|
premiumValue = component.count >= premiumLimit ? "" : "\(premiumLimit)"
|
||||||
|
badgePosition = max(0.32, CGFloat(component.count) / CGFloat(premiumLimit))
|
||||||
|
badgeGraphPosition = badgePosition
|
||||||
|
|
||||||
if isPremiumDisabled {
|
if isPremiumDisabled {
|
||||||
badgeText = "\(limit)"
|
badgeText = "\(limit)"
|
||||||
let numberString = strings.Premium_MaxExpiringStoriesNoPremiumTextNumberFormat(Int32(limit))
|
let numberString = strings.Premium_MaxExpiringStoriesNoPremiumTextNumberFormat(Int32(limit))
|
||||||
@ -1210,7 +1234,6 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
remaining = nextLevelBoosts - component.count
|
remaining = nextLevelBoosts - component.count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if let _ = link {
|
if let _ = link {
|
||||||
if let remaining {
|
if let remaining {
|
||||||
let storiesString = strings.ChannelBoost_StoriesPerDay(level + 1)
|
let storiesString = strings.ChannelBoost_StoriesPerDay(level + 1)
|
||||||
@ -1813,6 +1836,7 @@ public class PremiumLimitScreen: ViewControllerComponentContainer {
|
|||||||
case membershipInSharedFolders
|
case membershipInSharedFolders
|
||||||
case channels
|
case channels
|
||||||
case expiringStories
|
case expiringStories
|
||||||
|
case multiStories
|
||||||
case storiesWeekly
|
case storiesWeekly
|
||||||
case storiesMonthly
|
case storiesMonthly
|
||||||
|
|
||||||
|
@ -484,6 +484,13 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
|||||||
case peerId(EnginePeer.Id)
|
case peerId(EnginePeer.Id)
|
||||||
case name(String)
|
case name(String)
|
||||||
case address(String)
|
case address(String)
|
||||||
|
|
||||||
|
public var peerId: EnginePeer.Id? {
|
||||||
|
if case let .peerId(peerId) = self {
|
||||||
|
return peerId
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DecodingError: Error {
|
public enum DecodingError: Error {
|
||||||
|
@ -3253,6 +3253,24 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
guard let self, let arguments = self.subject.arguments, let navigationController = self.navigationController as? NavigationController, case let .unique(gift) = arguments.gift, let reference = arguments.reference, let transferStars = arguments.transferStars else {
|
guard let self, let arguments = self.subject.arguments, let navigationController = self.navigationController as? NavigationController, case let .unique(gift) = arguments.gift, let reference = arguments.reference, let transferStars = arguments.transferStars else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
|
if let canTransferDate = arguments.canTransferDate, currentTime < canTransferDate {
|
||||||
|
let dateString = stringForFullDate(timestamp: canTransferDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
||||||
|
let controller = textAlertController(
|
||||||
|
context: self.context,
|
||||||
|
title: presentationData.strings.Gift_Transfer_Unavailable_Title,
|
||||||
|
text: presentationData.strings.Gift_Transfer_Unavailable_Text(dateString).string,
|
||||||
|
actions: [
|
||||||
|
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})
|
||||||
|
],
|
||||||
|
parseMarkdown: true
|
||||||
|
)
|
||||||
|
self.present(controller, in: .window(.root))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let _ = (context.account.stateManager.contactBirthdays
|
let _ = (context.account.stateManager.contactBirthdays
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { birthdays in
|
|> deliverOnMainQueue).start(next: { birthdays in
|
||||||
@ -3477,8 +3495,33 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let _ = ((updateResellStars?(price) ?? context.engine.payments.updateStarGiftResalePrice(reference: reference, price: price))
|
let _ = ((updateResellStars?(price) ?? context.engine.payments.updateStarGiftResalePrice(reference: reference, price: price))
|
||||||
|> deliverOnMainQueue).startStandalone(error: { error in
|
|> deliverOnMainQueue).startStandalone(error: { [weak self] error in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let title: String?
|
||||||
|
let text: String
|
||||||
|
switch error {
|
||||||
|
case .generic:
|
||||||
|
title = nil
|
||||||
|
text = presentationData.strings.Gift_Send_ErrorUnknown
|
||||||
|
case let .starGiftResellTooEarly(canResaleDate):
|
||||||
|
let dateString = stringForFullDate(timestamp: canResaleDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
||||||
|
title = presentationData.strings.Gift_Resale_Unavailable_Title
|
||||||
|
text = presentationData.strings.Gift_Resale_Unavailable_Text(dateString).string
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = textAlertController(
|
||||||
|
context: self.context,
|
||||||
|
title: title,
|
||||||
|
text: text,
|
||||||
|
actions: [
|
||||||
|
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})
|
||||||
|
],
|
||||||
|
parseMarkdown: true
|
||||||
|
)
|
||||||
|
self.present(controller, in: .window(.root))
|
||||||
}, completed: { [weak self] in
|
}, completed: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -3597,13 +3640,15 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if case let .unique(gift) = arguments.gift, let resellStars = gift.resellStars, resellStars > 0 {
|
if case let .unique(gift) = arguments.gift, let resellStars = gift.resellStars, resellStars > 0 {
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_ChangePrice, icon: { theme in
|
if arguments.reference != nil || gift.owner.peerId == context.account.peerId {
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PriceTag"), color: theme.contextMenu.primaryColor)
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_ChangePrice, icon: { theme in
|
||||||
}, action: { c, _ in
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PriceTag"), color: theme.contextMenu.primaryColor)
|
||||||
c?.dismiss(completion: nil)
|
}, action: { c, _ in
|
||||||
|
c?.dismiss(completion: nil)
|
||||||
resellGiftImpl?(true)
|
|
||||||
})))
|
resellGiftImpl?(true)
|
||||||
|
})))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_CopyLink, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_CopyLink, icon: { theme in
|
||||||
|
@ -12,6 +12,7 @@ swift_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//submodules/Display",
|
"//submodules/Display",
|
||||||
"//submodules/ComponentFlow",
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -2,9 +2,10 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
private let animationDuration: TimeInterval = 12.0
|
private let animationSpeed: TimeInterval = 50.0
|
||||||
private let animationDelay: TimeInterval = 2.0
|
private let animationDelay: TimeInterval = 2.5
|
||||||
private let spacing: CGFloat = 20.0
|
private let spacing: CGFloat = 20.0
|
||||||
|
|
||||||
public final class MarqueeComponent: Component {
|
public final class MarqueeComponent: Component {
|
||||||
@ -43,6 +44,8 @@ public final class MarqueeComponent: Component {
|
|||||||
private let gradientMaskLayer = SimpleGradientLayer()
|
private let gradientMaskLayer = SimpleGradientLayer()
|
||||||
private var isAnimating = false
|
private var isAnimating = false
|
||||||
private var isOverflowing = false
|
private var isOverflowing = false
|
||||||
|
|
||||||
|
private var component: MarqueeComponent?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
@ -60,6 +63,9 @@ public final class MarqueeComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func update(component: MarqueeComponent, availableSize: CGSize) -> CGSize {
|
public func update(component: MarqueeComponent, availableSize: CGSize) -> CGSize {
|
||||||
|
let previousComponent = self.component
|
||||||
|
self.component = component
|
||||||
|
|
||||||
let attributedText = component.attributedText
|
let attributedText = component.attributedText
|
||||||
if let measureState = self.measureState {
|
if let measureState = self.measureState {
|
||||||
if measureState.attributedText.isEqual(to: attributedText) && measureState.availableSize == availableSize {
|
if measureState.attributedText.isEqual(to: attributedText) && measureState.availableSize == availableSize {
|
||||||
@ -88,7 +94,7 @@ public final class MarqueeComponent: Component {
|
|||||||
if isOverflowing {
|
if isOverflowing {
|
||||||
self.setupMarqueeTextLayers(textImage: image.cgImage!, textWidth: boundingRect.width, containerWidth: availableSize.width)
|
self.setupMarqueeTextLayers(textImage: image.cgImage!, textWidth: boundingRect.width, containerWidth: availableSize.width)
|
||||||
self.setupGradientMask(size: CGSize(width: availableSize.width, height: boundingRect.height))
|
self.setupGradientMask(size: CGSize(width: availableSize.width, height: boundingRect.height))
|
||||||
self.startAnimation()
|
self.startAnimation(force: previousComponent?.attributedText != attributedText)
|
||||||
} else {
|
} else {
|
||||||
self.stopAnimation()
|
self.stopAnimation()
|
||||||
self.textLayer.frame = CGRect(origin: CGPoint(x: innerPadding, y: 0.0), size: boundingRect.size)
|
self.textLayer.frame = CGRect(origin: CGPoint(x: innerPadding, y: 0.0), size: boundingRect.size)
|
||||||
@ -137,17 +143,26 @@ public final class MarqueeComponent: Component {
|
|||||||
self.layer.mask = self.gradientMaskLayer
|
self.layer.mask = self.gradientMaskLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startAnimation() {
|
private func startAnimation(force: Bool = false) {
|
||||||
guard !self.isAnimating else {
|
guard !self.isAnimating || force else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.isAnimating = true
|
self.isAnimating = true
|
||||||
|
|
||||||
self.containerLayer.removeAllAnimations()
|
self.containerLayer.removeAllAnimations()
|
||||||
|
|
||||||
self.containerLayer.animateBoundsOriginXAdditive(from: 0.0, to: self.textLayer.frame.width + spacing, duration: animationDuration, delay: animationDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, completion: { _ in
|
let distance = self.textLayer.frame.width + spacing
|
||||||
self.isAnimating = false
|
let duration = distance / animationSpeed
|
||||||
self.startAnimation()
|
Queue.mainQueue().after(animationDelay, {
|
||||||
|
guard self.isAnimating else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.containerLayer.animateBoundsOriginXAdditive(from: 0.0, to: distance, duration: duration, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, completion: { finished in
|
||||||
|
if finished {
|
||||||
|
self.isAnimating = false
|
||||||
|
self.startAnimation()
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +62,10 @@ public final class StarsBalanceOverlayComponent: Component {
|
|||||||
self.balanceDisposable?.dispose()
|
self.balanceDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var didTap = false
|
||||||
@objc private func tapped() {
|
@objc private func tapped() {
|
||||||
if let component = self.component {
|
if let component = self.component, !self.didTap {
|
||||||
|
self.didTap = true
|
||||||
component.action()
|
component.action()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2803,6 +2803,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
mappedSubject = .channels
|
mappedSubject = .channels
|
||||||
case .expiringStories:
|
case .expiringStories:
|
||||||
mappedSubject = .expiringStories
|
mappedSubject = .expiringStories
|
||||||
|
case .multiStories:
|
||||||
|
mappedSubject = .multiStories
|
||||||
case .storiesWeekly:
|
case .storiesWeekly:
|
||||||
mappedSubject = .storiesWeekly
|
mappedSubject = .storiesWeekly
|
||||||
case .storiesMonthly:
|
case .storiesMonthly:
|
||||||
|
@ -179,9 +179,7 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id)
|
|||||||
if baseLang.hasSuffix(rawSuffix) {
|
if baseLang.hasSuffix(rawSuffix) {
|
||||||
baseLang = String(baseLang.dropLast(rawSuffix.count))
|
baseLang = String(baseLang.dropLast(rawSuffix.count))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|
||||||
|> map { sharedData -> TranslationSettings in
|
|> map { sharedData -> TranslationSettings in
|
||||||
|
Loading…
x
Reference in New Issue
Block a user