mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Improvements
This commit is contained in:
parent
9e1fdb3c8d
commit
d192889e0e
@ -167,19 +167,34 @@ public func incomingMessagePrivacyScreen(context: AccountContext, value: Bool, u
|
||||
}
|
||||
)
|
||||
|
||||
let enableSetting: Signal<Bool, NoError> = context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId),
|
||||
TelegramEngine.EngineData.Item.Configuration.App()
|
||||
)
|
||||
|> map { accountPeer, appConfig -> Bool in
|
||||
if let accountPeer, accountPeer.isPremium {
|
||||
return true
|
||||
}
|
||||
if let data = appConfig.data, let setting = data["new_noncontact_peers_require_premium_without_ownpremium"] as? Bool {
|
||||
if setting {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let signal = combineLatest(queue: .mainQueue(),
|
||||
context.sharedContext.presentationData,
|
||||
context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)
|
||||
),
|
||||
statePromise.get()
|
||||
statePromise.get(),
|
||||
enableSetting
|
||||
)
|
||||
|> map { presentationData, accountPeer, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
|> map { presentationData, state, enableSetting -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let rightNavigationButton: ItemListNavigationButton? = nil
|
||||
|
||||
let title: ItemListControllerTitle = .text(presentationData.strings.Privacy_Messages_Title)
|
||||
|
||||
let entries: [GlobalAutoremoveEntry] = incomingMessagePrivacyScreenEntries(presentationData: presentationData, state: state, isPremium: accountPeer?.isPremium ?? false)
|
||||
let entries: [GlobalAutoremoveEntry] = incomingMessagePrivacyScreenEntries(presentationData: presentationData, state: state, isPremium: enableSetting)
|
||||
|
||||
let animateChanges = false
|
||||
|
||||
|
@ -47,6 +47,7 @@ public final class EmojiActionIconComponent: Component {
|
||||
let size = CGSize(width: 24.0, height: 24.0)
|
||||
|
||||
if let fileId = component.fileId {
|
||||
var iconSize = size
|
||||
let icon: ComponentView<Empty>
|
||||
if let current = self.icon {
|
||||
icon = current
|
||||
@ -56,6 +57,9 @@ public final class EmojiActionIconComponent: Component {
|
||||
}
|
||||
let content: EmojiStatusComponent.AnimationContent
|
||||
if let file = component.file {
|
||||
if let dimensions = file.dimensions {
|
||||
iconSize = dimensions.cgSize.aspectFitted(size)
|
||||
}
|
||||
content = .file(file: file)
|
||||
} else {
|
||||
content = .customEmoji(fileId: fileId)
|
||||
@ -68,7 +72,7 @@ public final class EmojiActionIconComponent: Component {
|
||||
animationRenderer: component.context.animationRenderer,
|
||||
content: .animation(
|
||||
content: content,
|
||||
size: size,
|
||||
size: iconSize,
|
||||
placeholderColor: .lightGray,
|
||||
themeColor: component.color,
|
||||
loopMode: .forever
|
||||
@ -77,9 +81,9 @@ public final class EmojiActionIconComponent: Component {
|
||||
action: nil
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: size
|
||||
containerSize: iconSize
|
||||
)
|
||||
let iconFrame = CGRect(origin: CGPoint(), size: size)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) * 0.5), y: floor((size.height - iconSize.height) * 0.5)), size: iconSize)
|
||||
if let iconView = icon.view {
|
||||
if iconView.superview == nil {
|
||||
self.addSubview(iconView)
|
||||
|
@ -30,6 +30,12 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
public enum EmptyLineHandling {
|
||||
case allowed
|
||||
case oneConsecutive
|
||||
case notAllowed
|
||||
}
|
||||
|
||||
public let externalState: ExternalState?
|
||||
public let context: AccountContext
|
||||
public let theme: PresentationTheme
|
||||
@ -41,7 +47,7 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
||||
public let autocorrectionType: UITextAutocorrectionType
|
||||
public let characterLimit: Int?
|
||||
public let displayCharacterLimit: Bool
|
||||
public let allowEmptyLines: Bool
|
||||
public let emptyLineHandling: EmptyLineHandling
|
||||
public let updated: ((String) -> Void)?
|
||||
public let textUpdateTransition: Transition
|
||||
public let tag: AnyObject?
|
||||
@ -58,7 +64,7 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
||||
autocorrectionType: UITextAutocorrectionType = .default,
|
||||
characterLimit: Int? = nil,
|
||||
displayCharacterLimit: Bool = false,
|
||||
allowEmptyLines: Bool = true,
|
||||
emptyLineHandling: EmptyLineHandling = .allowed,
|
||||
updated: ((String) -> Void)?,
|
||||
textUpdateTransition: Transition = .immediate,
|
||||
tag: AnyObject? = nil
|
||||
@ -74,7 +80,7 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
||||
self.autocorrectionType = autocorrectionType
|
||||
self.characterLimit = characterLimit
|
||||
self.displayCharacterLimit = displayCharacterLimit
|
||||
self.allowEmptyLines = allowEmptyLines
|
||||
self.emptyLineHandling = emptyLineHandling
|
||||
self.updated = updated
|
||||
self.textUpdateTransition = textUpdateTransition
|
||||
self.tag = tag
|
||||
@ -114,7 +120,7 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
||||
if lhs.displayCharacterLimit != rhs.displayCharacterLimit {
|
||||
return false
|
||||
}
|
||||
if lhs.allowEmptyLines != rhs.allowEmptyLines {
|
||||
if lhs.emptyLineHandling != rhs.emptyLineHandling {
|
||||
return false
|
||||
}
|
||||
if (lhs.updated == nil) != (rhs.updated == nil) {
|
||||
@ -225,6 +231,16 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
||||
self.measureTextLimitLabel = nil
|
||||
}
|
||||
|
||||
let mappedEmptyLineHandling: TextFieldComponent.EmptyLineHandling
|
||||
switch component.emptyLineHandling {
|
||||
case .allowed:
|
||||
mappedEmptyLineHandling = .allowed
|
||||
case .oneConsecutive:
|
||||
mappedEmptyLineHandling = .oneConsecutive
|
||||
case .notAllowed:
|
||||
mappedEmptyLineHandling = .notAllowed
|
||||
}
|
||||
|
||||
let textFieldSize = self.textField.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(TextFieldComponent(
|
||||
@ -242,7 +258,7 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
||||
},
|
||||
isOneLineWhenUnfocused: false,
|
||||
characterLimit: component.characterLimit,
|
||||
allowEmptyLines: component.allowEmptyLines,
|
||||
emptyLineHandling: mappedEmptyLineHandling,
|
||||
formatMenuAvailability: .none,
|
||||
lockedFormatAction: {
|
||||
},
|
||||
|
@ -321,7 +321,12 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
self.scrollContentView.addSubview(avatarsNode.view)
|
||||
}
|
||||
|
||||
let avatarPeers = component.peers.map(\.peer)
|
||||
let avatarPeers: [EnginePeer]
|
||||
if !premiumRestrictedUsers.isEmpty {
|
||||
avatarPeers = premiumRestrictedUsers.map(\.peer)
|
||||
} else {
|
||||
avatarPeers = component.peers.map(\.peer)
|
||||
}
|
||||
let avatarsContent = self.avatarsContext.update(peers: avatarPeers.count <= 3 ? avatarPeers : Array(avatarPeers.prefix(upTo: 3)), animated: false)
|
||||
let avatarsSize = avatarsNode.update(
|
||||
context: component.context,
|
||||
|
@ -767,7 +767,7 @@ final class BusinessIntroSetupScreenComponent: Component {
|
||||
autocorrectionType: .no,
|
||||
characterLimit: 32,
|
||||
displayCharacterLimit: true,
|
||||
allowEmptyLines: false,
|
||||
emptyLineHandling: .notAllowed,
|
||||
updated: { _ in
|
||||
},
|
||||
textUpdateTransition: .spring(duration: 0.4),
|
||||
@ -788,7 +788,7 @@ final class BusinessIntroSetupScreenComponent: Component {
|
||||
autocorrectionType: .no,
|
||||
characterLimit: 70,
|
||||
displayCharacterLimit: true,
|
||||
allowEmptyLines: false,
|
||||
emptyLineHandling: .notAllowed,
|
||||
updated: { _ in
|
||||
},
|
||||
textUpdateTransition: .spring(duration: 0.4),
|
||||
|
@ -406,7 +406,7 @@ final class BusinessLocationSetupScreenComponent: Component {
|
||||
autocapitalizationType: .none,
|
||||
autocorrectionType: .no,
|
||||
characterLimit: 256,
|
||||
allowEmptyLines: false,
|
||||
emptyLineHandling: .oneConsecutive,
|
||||
updated: { _ in
|
||||
},
|
||||
textUpdateTransition: .spring(duration: 0.4),
|
||||
|
@ -295,7 +295,7 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
break
|
||||
case let .result(peer):
|
||||
let previousState = self.botResolutionState?.state
|
||||
if let peer {
|
||||
if let peer, case let .user(user) = peer, user.botInfo != nil {
|
||||
self.botResolutionState?.state = .found(peer: peer, isInstalled: false)
|
||||
} else {
|
||||
self.botResolutionState?.state = .notFound
|
||||
|
@ -89,6 +89,12 @@ public final class TextFieldComponent: Component {
|
||||
case none
|
||||
}
|
||||
|
||||
public enum EmptyLineHandling {
|
||||
case allowed
|
||||
case oneConsecutive
|
||||
case notAllowed
|
||||
}
|
||||
|
||||
public let context: AccountContext
|
||||
public let theme: PresentationTheme
|
||||
public let strings: PresentationStrings
|
||||
@ -101,7 +107,7 @@ public final class TextFieldComponent: Component {
|
||||
public let resetText: NSAttributedString?
|
||||
public let isOneLineWhenUnfocused: Bool
|
||||
public let characterLimit: Int?
|
||||
public let allowEmptyLines: Bool
|
||||
public let emptyLineHandling: EmptyLineHandling
|
||||
public let formatMenuAvailability: FormatMenuAvailability
|
||||
public let lockedFormatAction: () -> Void
|
||||
public let present: (ViewController) -> Void
|
||||
@ -120,7 +126,7 @@ public final class TextFieldComponent: Component {
|
||||
resetText: NSAttributedString?,
|
||||
isOneLineWhenUnfocused: Bool,
|
||||
characterLimit: Int? = nil,
|
||||
allowEmptyLines: Bool = true,
|
||||
emptyLineHandling: EmptyLineHandling = .allowed,
|
||||
formatMenuAvailability: FormatMenuAvailability,
|
||||
lockedFormatAction: @escaping () -> Void,
|
||||
present: @escaping (ViewController) -> Void,
|
||||
@ -138,7 +144,7 @@ public final class TextFieldComponent: Component {
|
||||
self.resetText = resetText
|
||||
self.isOneLineWhenUnfocused = isOneLineWhenUnfocused
|
||||
self.characterLimit = characterLimit
|
||||
self.allowEmptyLines = allowEmptyLines
|
||||
self.emptyLineHandling = emptyLineHandling
|
||||
self.formatMenuAvailability = formatMenuAvailability
|
||||
self.lockedFormatAction = lockedFormatAction
|
||||
self.present = present
|
||||
@ -182,7 +188,7 @@ public final class TextFieldComponent: Component {
|
||||
if lhs.characterLimit != rhs.characterLimit {
|
||||
return false
|
||||
}
|
||||
if lhs.allowEmptyLines != rhs.allowEmptyLines {
|
||||
if lhs.emptyLineHandling != rhs.emptyLineHandling {
|
||||
return false
|
||||
}
|
||||
if lhs.formatMenuAvailability != rhs.formatMenuAvailability {
|
||||
@ -566,12 +572,21 @@ public final class TextFieldComponent: Component {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if !component.allowEmptyLines {
|
||||
switch component.emptyLineHandling {
|
||||
case .allowed:
|
||||
break
|
||||
case .oneConsecutive:
|
||||
let string = self.inputState.inputText.string as NSString
|
||||
let updatedString = string.replacingCharacters(in: range, with: text)
|
||||
if updatedString.range(of: "\n\n") != nil {
|
||||
return false
|
||||
}
|
||||
case .notAllowed:
|
||||
let string = self.inputState.inputText.string as NSString
|
||||
let updatedString = string.replacingCharacters(in: range, with: text)
|
||||
if updatedString.range(of: "\n") != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -17,7 +17,7 @@ extension ChatControllerImpl {
|
||||
guard let self, let itemNode else {
|
||||
return
|
||||
}
|
||||
if value >= 1 {
|
||||
if value >= 2 {
|
||||
return
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ extension ChatControllerImpl {
|
||||
let location = CGPoint(x: bounds.midX, y: bounds.minY - 11.0)
|
||||
|
||||
//TODO:localize
|
||||
let tooltipController = TooltipController(content: .text("Only you can see that this message was sent by the bot."), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, balancedTextLayout: true, timeout: 3.5, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
|
||||
let tooltipController = TooltipController(content: .text("Only you can see that this\nmessage was sent by the bot."), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, balancedTextLayout: true, timeout: 3.5, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
|
||||
self.checksTooltipController = tooltipController
|
||||
tooltipController.dismissed = { [weak self, weak tooltipController] _ in
|
||||
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.checksTooltipController === tooltipController {
|
||||
@ -57,6 +57,11 @@ extension ChatControllerImpl {
|
||||
return (self.chatDisplayNode, CGRect(origin: location, size: CGSize()))
|
||||
}))
|
||||
|
||||
#if DEBUG
|
||||
if "".isEmpty {
|
||||
return
|
||||
}
|
||||
#endif
|
||||
let _ = ApplicationSpecificNotice.incrementBusinessBotMessageTooltip(accountManager: self.context.sharedContext.accountManager).startStandalone()
|
||||
})
|
||||
}
|
||||
|
@ -675,6 +675,22 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if parsedUrl.host == "message" {
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
var parameter: String?
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
if queryItem.name == "slug" {
|
||||
parameter = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let parameter {
|
||||
convertedUrl = "https://t.me/m/\(parameter)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if parsedUrl.host == "resolve" {
|
||||
|
Loading…
x
Reference in New Issue
Block a user