Various improvements

This commit is contained in:
Ilya Laktyushin 2023-07-15 02:38:57 +02:00
parent 2e6bc7f69d
commit ae60c2be8b
10 changed files with 113 additions and 21 deletions

View File

@ -589,6 +589,7 @@ public final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate
self.textView.layer.shadowOpacity = 0.0 self.textView.layer.shadowOpacity = 0.0
self.textView.layer.shadowRadius = 0.0 self.textView.layer.shadowRadius = 0.0
} }
self.textView.textAlignment = self.textEntity.alignment.alignment
self.updateText(keepSelectedRange: afterAppendingEmoji) self.updateText(keepSelectedRange: afterAppendingEmoji)

View File

@ -18,6 +18,7 @@ public struct UserLimitsConfiguration: Equatable {
public let maxSharedFolderInviteLinks: Int32 public let maxSharedFolderInviteLinks: Int32
public let maxSharedFolderJoin: Int32 public let maxSharedFolderJoin: Int32
public let maxStoryCaptionLength: Int32 public let maxStoryCaptionLength: Int32
public let maxExpiringStoriesCount: Int32
public static var defaultValue: UserLimitsConfiguration { public static var defaultValue: UserLimitsConfiguration {
return UserLimitsConfiguration( return UserLimitsConfiguration(
@ -36,7 +37,8 @@ public struct UserLimitsConfiguration: Equatable {
maxReactionsPerMessage: 1, maxReactionsPerMessage: 1,
maxSharedFolderInviteLinks: 3, maxSharedFolderInviteLinks: 3,
maxSharedFolderJoin: 2, maxSharedFolderJoin: 2,
maxStoryCaptionLength: 1024 maxStoryCaptionLength: 1024,
maxExpiringStoriesCount: 100
) )
} }
@ -56,7 +58,8 @@ public struct UserLimitsConfiguration: Equatable {
maxReactionsPerMessage: Int32, maxReactionsPerMessage: Int32,
maxSharedFolderInviteLinks: Int32, maxSharedFolderInviteLinks: Int32,
maxSharedFolderJoin: Int32, maxSharedFolderJoin: Int32,
maxStoryCaptionLength: Int32 maxStoryCaptionLength: Int32,
maxExpiringStoriesCount: Int32
) { ) {
self.maxPinnedChatCount = maxPinnedChatCount self.maxPinnedChatCount = maxPinnedChatCount
self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount
@ -74,6 +77,7 @@ public struct UserLimitsConfiguration: Equatable {
self.maxSharedFolderInviteLinks = maxSharedFolderInviteLinks self.maxSharedFolderInviteLinks = maxSharedFolderInviteLinks
self.maxSharedFolderJoin = maxSharedFolderJoin self.maxSharedFolderJoin = maxSharedFolderJoin
self.maxStoryCaptionLength = maxStoryCaptionLength self.maxStoryCaptionLength = maxStoryCaptionLength
self.maxExpiringStoriesCount = maxExpiringStoriesCount
} }
} }
@ -114,5 +118,6 @@ extension UserLimitsConfiguration {
self.maxSharedFolderInviteLinks = getValue("chatlist_invites_limit", orElse: isPremium ? 100 : 3) self.maxSharedFolderInviteLinks = getValue("chatlist_invites_limit", orElse: isPremium ? 100 : 3)
self.maxSharedFolderJoin = getValue("chatlists_joined_limit", orElse: isPremium ? 100 : 2) self.maxSharedFolderJoin = getValue("chatlists_joined_limit", orElse: isPremium ? 100 : 2)
self.maxStoryCaptionLength = getGeneralValue("story_caption_length_limit", orElse: defaultValue.maxStoryCaptionLength) self.maxStoryCaptionLength = getGeneralValue("story_caption_length_limit", orElse: defaultValue.maxStoryCaptionLength)
self.maxExpiringStoriesCount = getGeneralValue("story_expiring_limit", orElse: defaultValue.maxExpiringStoriesCount)
} }
} }

View File

@ -52,6 +52,7 @@ public enum EngineConfiguration {
public let maxSharedFolderInviteLinks: Int32 public let maxSharedFolderInviteLinks: Int32
public let maxSharedFolderJoin: Int32 public let maxSharedFolderJoin: Int32
public let maxStoryCaptionLength: Int32 public let maxStoryCaptionLength: Int32
public let maxExpiringStoriesCount: Int32
public static var defaultValue: UserLimits { public static var defaultValue: UserLimits {
return UserLimits(UserLimitsConfiguration.defaultValue) return UserLimits(UserLimitsConfiguration.defaultValue)
@ -73,7 +74,8 @@ public enum EngineConfiguration {
maxReactionsPerMessage: Int32, maxReactionsPerMessage: Int32,
maxSharedFolderInviteLinks: Int32, maxSharedFolderInviteLinks: Int32,
maxSharedFolderJoin: Int32, maxSharedFolderJoin: Int32,
maxStoryCaptionLength: Int32 maxStoryCaptionLength: Int32,
maxExpiringStoriesCount: Int32
) { ) {
self.maxPinnedChatCount = maxPinnedChatCount self.maxPinnedChatCount = maxPinnedChatCount
self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount
@ -91,6 +93,7 @@ public enum EngineConfiguration {
self.maxSharedFolderInviteLinks = maxSharedFolderInviteLinks self.maxSharedFolderInviteLinks = maxSharedFolderInviteLinks
self.maxSharedFolderJoin = maxSharedFolderJoin self.maxSharedFolderJoin = maxSharedFolderJoin
self.maxStoryCaptionLength = maxStoryCaptionLength self.maxStoryCaptionLength = maxStoryCaptionLength
self.maxExpiringStoriesCount = maxExpiringStoriesCount
} }
} }
} }
@ -143,7 +146,8 @@ public extension EngineConfiguration.UserLimits {
maxReactionsPerMessage: userLimitsConfiguration.maxReactionsPerMessage, maxReactionsPerMessage: userLimitsConfiguration.maxReactionsPerMessage,
maxSharedFolderInviteLinks: userLimitsConfiguration.maxSharedFolderInviteLinks, maxSharedFolderInviteLinks: userLimitsConfiguration.maxSharedFolderInviteLinks,
maxSharedFolderJoin: userLimitsConfiguration.maxSharedFolderJoin, maxSharedFolderJoin: userLimitsConfiguration.maxSharedFolderJoin,
maxStoryCaptionLength: userLimitsConfiguration.maxStoryCaptionLength maxStoryCaptionLength: userLimitsConfiguration.maxStoryCaptionLength,
maxExpiringStoriesCount: userLimitsConfiguration.maxExpiringStoriesCount
) )
} }
} }

View File

@ -56,5 +56,23 @@ public extension TelegramEngine.EngineData.Item {
} }
} }
} }
public struct CloseFriends: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = Array<EnginePeer>
public init() {
}
var key: PostboxViewKey {
return .contacts(accountPeerId: nil, includePresences: false)
}
func extract(view: PostboxView) -> Result {
guard let view = view as? ContactPeersView else {
preconditionFailure()
}
return view.peers.filter { $0.isCloseFriend }.map(EnginePeer.init)
}
}
} }
} }

View File

@ -189,6 +189,15 @@ public extension Peer {
} }
} }
var isCloseFriend: Bool {
switch self {
case let user as TelegramUser:
return user.flags.contains(.isCloseFriend)
default:
return false
}
}
var isCopyProtectionEnabled: Bool { var isCopyProtectionEnabled: Bool {
switch self { switch self {
case let group as TelegramGroup: case let group as TelegramGroup:

View File

@ -3238,6 +3238,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
public var dismissed: () -> Void = { } public var dismissed: () -> Void = { }
public var willDismiss: () -> Void = { } public var willDismiss: () -> Void = { }
private var closeFriends = Promise<[EnginePeer]>()
private let hapticFeedback = HapticFeedback() private let hapticFeedback = HapticFeedback()
public init( public init(
@ -3313,6 +3315,10 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let dropInteraction = UIDropInteraction(delegate: self) let dropInteraction = UIDropInteraction(delegate: self)
self.displayNode.view.addInteraction(dropInteraction) self.displayNode.view.addInteraction(dropInteraction)
Queue.mainQueue().after(1.0) {
self.closeFriends.set(self.context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.CloseFriends()))
}
} }
func openPrivacySettings(_ privacy: MediaEditorResultPrivacy? = nil, completion: @escaping () -> Void = {}) { func openPrivacySettings(_ privacy: MediaEditorResultPrivacy? = nil, completion: @escaping () -> Void = {}) {
@ -3325,7 +3331,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let text = self.getCaption().string let text = self.getCaption().string
let mentions = generateTextEntities(text, enabledTypes: [.mention], currentEntities: []).map { (text as NSString).substring(with: NSRange(location: $0.range.lowerBound + 1, length: $0.range.upperBound - $0.range.lowerBound - 1)) } let mentions = generateTextEntities(text, enabledTypes: [.mention], currentEntities: []).map { (text as NSString).substring(with: NSRange(location: $0.range.lowerBound + 1, length: $0.range.upperBound - $0.range.lowerBound - 1)) }
let stateContext = ShareWithPeersScreen.StateContext(context: self.context, subject: .stories(editing: false), initialPeerIds: Set(privacy.privacy.additionallyIncludePeers)) let stateContext = ShareWithPeersScreen.StateContext(
context: self.context,
subject: .stories(editing: false),
initialPeerIds: Set(privacy.privacy.additionallyIncludePeers),
closeFriends: self.closeFriends.get()
)
let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in
guard let self else { guard let self else {
return return

View File

@ -1751,13 +1751,16 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer {
public final class State { public final class State {
let peers: [EnginePeer] let peers: [EnginePeer]
let presences: [EnginePeer.Id: EnginePeer.Presence] let presences: [EnginePeer.Id: EnginePeer.Presence]
let closeFriendsPeers: [EnginePeer]
fileprivate init( fileprivate init(
peers: [EnginePeer], peers: [EnginePeer],
presences: [EnginePeer.Id: EnginePeer.Presence] presences: [EnginePeer.Id: EnginePeer.Presence],
closeFriendsPeers: [EnginePeer]
) { ) {
self.peers = peers self.peers = peers
self.presences = presences self.presences = presences
self.closeFriendsPeers = closeFriendsPeers
} }
} }
@ -1787,28 +1790,33 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer {
public init( public init(
context: AccountContext, context: AccountContext,
subject: Subject = .chats, subject: Subject = .chats,
initialPeerIds: Set<EnginePeer.Id> = Set() initialPeerIds: Set<EnginePeer.Id> = Set(),
closeFriends: Signal<[EnginePeer], NoError> = .single([])
) { ) {
self.subject = subject self.subject = subject
self.initialPeerIds = initialPeerIds self.initialPeerIds = initialPeerIds
switch subject { switch subject {
case .stories: case .stories:
var signals: [Signal<EnginePeer?, NoError>] = [] var peerSignals: [Signal<EnginePeer?, NoError>] = []
if initialPeerIds.count < 3 { if initialPeerIds.count < 3 {
for peerId in initialPeerIds { for peerId in initialPeerIds {
signals.append(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))) peerSignals.append(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)))
} }
} }
self.stateDisposable = (combineLatest(signals)
|> deliverOnMainQueue).start(next: { [weak self] peers in let peers = combineLatest(peerSignals)
self.stateDisposable = combineLatest(queue: Queue.mainQueue(), peers, closeFriends)
.start(next: { [weak self] peers, closeFriends in
guard let self else { guard let self else {
return return
} }
let state = State( let state = State(
peers: peers.compactMap { $0 }, peers: peers.compactMap { $0 },
presences: [:] presences: [:],
closeFriendsPeers: closeFriends
) )
self.stateValue = state self.stateValue = state
self.stateSubject.set(.single(state)) self.stateSubject.set(.single(state))
@ -1840,7 +1848,8 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer {
let state = State( let state = State(
peers: peers, peers: peers,
presences: presences presences: presences,
closeFriendsPeers: []
) )
self.stateValue = state self.stateValue = state
self.stateSubject.set(.single(state)) self.stateSubject.set(.single(state))
@ -1894,7 +1903,8 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer {
let state = State( let state = State(
peers: peers, peers: peers,
presences: contactList.presences presences: contactList.presences,
closeFriendsPeers: []
) )
self.stateValue = state self.stateValue = state
@ -1902,8 +1912,17 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer {
self.readySubject.set(true) self.readySubject.set(true)
}) })
case let .search(query, _): case let .search(query, onlyContacts):
self.stateDisposable = (context.engine.contacts.searchLocalPeers(query: query) let signal: Signal<[EngineRenderedPeer], NoError>
if onlyContacts {
signal = context.engine.contacts.searchContacts(query: query)
|> map { result in
return result.0.map { EngineRenderedPeer(peer: $0) }
}
} else {
signal = context.engine.contacts.searchLocalPeers(query: query)
}
self.stateDisposable = (signal
|> deliverOnMainQueue).start(next: { [weak self] peers in |> deliverOnMainQueue).start(next: { [weak self] peers in
guard let self else { guard let self else {
return return
@ -1923,7 +1942,8 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer {
return false return false
} }
}, },
presences: [:] presences: [:],
closeFriendsPeers: []
) )
self.stateValue = state self.stateValue = state
self.stateSubject.set(.single(state)) self.stateSubject.set(.single(state))
@ -1999,12 +2019,20 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer {
actionTitle: contactsSubtitle actionTitle: contactsSubtitle
)) ))
var closeFriendsSubtitle = "edit list"
if let peers = stateContext.stateValue?.closeFriendsPeers, !peers.isEmpty {
if peers.count > 2 {
closeFriendsSubtitle = "\(peers.count) people"
} else {
closeFriendsSubtitle = String(peers.map { $0.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) }.joined(separator: ", "))
}
}
categoryItems.append(ShareWithPeersScreenComponent.CategoryItem( categoryItems.append(ShareWithPeersScreenComponent.CategoryItem(
id: .closeFriends, id: .closeFriends,
title: "Close Friends", title: "Close Friends",
icon: "Call/StarHighlighted", icon: "Call/StarHighlighted",
iconColor: .green, iconColor: .green,
actionTitle: "edit list" actionTitle: closeFriendsSubtitle
)) ))
var selectedContactsSubtitle = "choose" var selectedContactsSubtitle = "choose"

View File

@ -363,6 +363,7 @@ private final class StoryContainerScreenComponent: Component {
private let audioModePromise = ValuePromise<StoryContentItem.AudioMode>(.ambient, ignoreRepeated: true) private let audioModePromise = ValuePromise<StoryContentItem.AudioMode>(.ambient, ignoreRepeated: true)
private let inputMediaNodeDataPromise = Promise<ChatEntityKeyboardInputNode.InputData>() private let inputMediaNodeDataPromise = Promise<ChatEntityKeyboardInputNode.InputData>()
private let closeFriendsPromise = Promise<[EnginePeer]>()
private var availableReactions: StoryAvailableReactions? private var availableReactions: StoryAvailableReactions?
@ -1078,6 +1079,10 @@ private final class StoryContainerScreenComponent: Component {
sendGif: nil sendGif: nil
) )
) )
self.closeFriendsPromise.set(
component.context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.CloseFriends())
)
} }
var update = false var update = false
@ -1398,6 +1403,7 @@ private final class StoryContainerScreenComponent: Component {
self.state?.updated(transition: .immediate) self.state?.updated(transition: .immediate)
}, },
keyboardInputData: self.inputMediaNodeDataPromise.get(), keyboardInputData: self.inputMediaNodeDataPromise.get(),
closeFriends: self.closeFriendsPromise.get(),
sharedViewListsContext: self.sharedViewListsContext sharedViewListsContext: self.sharedViewListsContext
)), )),
environment: {}, environment: {},

View File

@ -103,6 +103,7 @@ public final class StoryItemSetContainerComponent: Component {
public let controller: () -> ViewController? public let controller: () -> ViewController?
public let toggleAmbientMode: () -> Void public let toggleAmbientMode: () -> Void
public let keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError> public let keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>
public let closeFriends: Signal<[EnginePeer], NoError>
let sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext let sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext
init( init(
@ -135,6 +136,7 @@ public final class StoryItemSetContainerComponent: Component {
controller: @escaping () -> ViewController?, controller: @escaping () -> ViewController?,
toggleAmbientMode: @escaping () -> Void, toggleAmbientMode: @escaping () -> Void,
keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>, keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>,
closeFriends: Signal<[EnginePeer], NoError>,
sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext
) { ) {
self.context = context self.context = context
@ -166,6 +168,7 @@ public final class StoryItemSetContainerComponent: Component {
self.controller = controller self.controller = controller
self.toggleAmbientMode = toggleAmbientMode self.toggleAmbientMode = toggleAmbientMode
self.keyboardInputData = keyboardInputData self.keyboardInputData = keyboardInputData
self.closeFriends = closeFriends
self.sharedViewListsContext = sharedViewListsContext self.sharedViewListsContext = sharedViewListsContext
} }
@ -3173,16 +3176,23 @@ public final class StoryItemSetContainerComponent: Component {
} }
private func openItemPrivacySettings(initialPrivacy: EngineStoryPrivacy? = nil) { private func openItemPrivacySettings(initialPrivacy: EngineStoryPrivacy? = nil) {
guard let context = self.component?.context else { guard let component = self.component else {
return return
} }
let context = component.context
let privacy = initialPrivacy ?? self.component?.slice.item.storyItem.privacy let privacy = initialPrivacy ?? self.component?.slice.item.storyItem.privacy
guard let privacy else { guard let privacy else {
return return
} }
let stateContext = ShareWithPeersScreen.StateContext(context: context, subject: .stories(editing: true), initialPeerIds: Set(privacy.additionallyIncludePeers)) let stateContext = ShareWithPeersScreen.StateContext(
context: context,
subject: .stories(editing: true),
initialPeerIds: Set(privacy.additionallyIncludePeers),
closeFriends: component.closeFriends
)
let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in
guard let self else { guard let self else {
return return

View File

@ -542,7 +542,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
animationSpacing = 8.0 animationSpacing = 8.0
} }
let containerWidth = max(100.0, min(layout.size.width, 614.0) - sideInset * 2.0) let containerWidth = max(100.0, min(layout.size.width - sideInset * 2.0, 614.0))
var actionSize: CGSize = .zero var actionSize: CGSize = .zero