Various fixes

This commit is contained in:
Ilya Laktyushin 2024-07-20 16:59:08 +04:00
parent 29a1d4ed2f
commit fed488a806
7 changed files with 172 additions and 104 deletions

View File

@ -12542,3 +12542,7 @@ Sorry for the inconvenience.";
"WebBrowser.LinkForwardTooltip.TwoChats.One" = "Link forwarded to **%@** and **%@**";
"WebBrowser.LinkForwardTooltip.ManyChats.One" = "Link forwarded to **%@** and %@ others";
"WebBrowser.LinkForwardTooltip.SavedMessages.One" = "Link forwarded to **Saved Messages**";
"Stars.Intro.StarsSent_1" = "%@ Star sent.";
"Stars.Intro.StarsSent_any" = "%@ Stars sent.";
"Stars.Intro.StarsSent.ViewChat" = "View Chat";

View File

@ -614,102 +614,6 @@ public enum ContactListActionItemIcon : Equatable {
}
}
public struct ContactListAdditionalOption: Equatable {
public let title: String
public let icon: ContactListActionItemIcon
public let action: () -> Void
public let clearHighlightAutomatically: Bool
public init(title: String, icon: ContactListActionItemIcon, action: @escaping () -> Void, clearHighlightAutomatically: Bool = false) {
self.title = title
self.icon = icon
self.action = action
self.clearHighlightAutomatically = clearHighlightAutomatically
}
public static func ==(lhs: ContactListAdditionalOption, rhs: ContactListAdditionalOption) -> Bool {
return lhs.title == rhs.title && lhs.icon == rhs.icon
}
}
public enum ContactListPeerId: Hashable {
case peer(PeerId)
case deviceContact(DeviceContactStableId)
}
public enum ContactListAction: Equatable {
case generic
case voiceCall
case videoCall
case more
}
public enum ContactListPeer: Equatable {
case peer(peer: Peer, isGlobal: Bool, participantCount: Int32?)
case deviceContact(DeviceContactStableId, DeviceContactBasicData)
public var id: ContactListPeerId {
switch self {
case let .peer(peer, _, _):
return .peer(peer.id)
case let .deviceContact(id, _):
return .deviceContact(id)
}
}
public var indexName: PeerIndexNameRepresentation {
switch self {
case let .peer(peer, _, _):
return peer.indexName
case let .deviceContact(_, contact):
return .personName(first: contact.firstName, last: contact.lastName, addressNames: [], phoneNumber: "")
}
}
public static func ==(lhs: ContactListPeer, rhs: ContactListPeer) -> Bool {
switch lhs {
case let .peer(lhsPeer, lhsIsGlobal, lhsParticipantCount):
if case let .peer(rhsPeer, rhsIsGlobal, rhsParticipantCount) = rhs, lhsPeer.isEqual(rhsPeer), lhsIsGlobal == rhsIsGlobal, lhsParticipantCount == rhsParticipantCount {
return true
} else {
return false
}
case let .deviceContact(id, contact):
if case .deviceContact(id, contact) = rhs {
return true
} else {
return false
}
}
}
}
public final class ContactSelectionControllerParams {
public let context: AccountContext
public let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
public let autoDismiss: Bool
public let title: (PresentationStrings) -> String
public let options: [ContactListAdditionalOption]
public let displayDeviceContacts: Bool
public let displayCallIcons: Bool
public let multipleSelection: Bool
public let requirePhoneNumbers: Bool
public let confirmation: (ContactListPeer) -> Signal<Bool, NoError>
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, autoDismiss: Bool = true, title: @escaping (PresentationStrings) -> String, options: [ContactListAdditionalOption] = [], displayDeviceContacts: Bool = false, displayCallIcons: Bool = false, multipleSelection: Bool = false, requirePhoneNumbers: Bool = false, confirmation: @escaping (ContactListPeer) -> Signal<Bool, NoError> = { _ in .single(true) }) {
self.context = context
self.updatedPresentationData = updatedPresentationData
self.autoDismiss = autoDismiss
self.title = title
self.options = options
self.displayDeviceContacts = displayDeviceContacts
self.displayCallIcons = displayCallIcons
self.multipleSelection = multipleSelection
self.requirePhoneNumbers = requirePhoneNumbers
self.confirmation = confirmation
}
}
public enum ChatListSearchFilter: Equatable {
case chats
case topics

View File

@ -1,6 +1,9 @@
import Foundation
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
public protocol ContactSelectionController: ViewController {
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?, NSAttributedString?, ChatSendMessageActionSheetController.SendParameters?)?, NoError> { get }
@ -10,3 +13,106 @@ public protocol ContactSelectionController: ViewController {
func dismissSearch()
}
public enum ContactSelectionControllerMode {
case generic
case starsGifting(birthdays: [EnginePeer.Id: TelegramBirthday]?, hasActions: Bool)
}
public struct ContactListAdditionalOption: Equatable {
public let title: String
public let icon: ContactListActionItemIcon
public let action: () -> Void
public let clearHighlightAutomatically: Bool
public init(title: String, icon: ContactListActionItemIcon, action: @escaping () -> Void, clearHighlightAutomatically: Bool = false) {
self.title = title
self.icon = icon
self.action = action
self.clearHighlightAutomatically = clearHighlightAutomatically
}
public static func ==(lhs: ContactListAdditionalOption, rhs: ContactListAdditionalOption) -> Bool {
return lhs.title == rhs.title && lhs.icon == rhs.icon
}
}
public enum ContactListPeerId: Hashable {
case peer(PeerId)
case deviceContact(DeviceContactStableId)
}
public enum ContactListAction: Equatable {
case generic
case voiceCall
case videoCall
case more
}
public enum ContactListPeer: Equatable {
case peer(peer: Peer, isGlobal: Bool, participantCount: Int32?)
case deviceContact(DeviceContactStableId, DeviceContactBasicData)
public var id: ContactListPeerId {
switch self {
case let .peer(peer, _, _):
return .peer(peer.id)
case let .deviceContact(id, _):
return .deviceContact(id)
}
}
public var indexName: PeerIndexNameRepresentation {
switch self {
case let .peer(peer, _, _):
return peer.indexName
case let .deviceContact(_, contact):
return .personName(first: contact.firstName, last: contact.lastName, addressNames: [], phoneNumber: "")
}
}
public static func ==(lhs: ContactListPeer, rhs: ContactListPeer) -> Bool {
switch lhs {
case let .peer(lhsPeer, lhsIsGlobal, lhsParticipantCount):
if case let .peer(rhsPeer, rhsIsGlobal, rhsParticipantCount) = rhs, lhsPeer.isEqual(rhsPeer), lhsIsGlobal == rhsIsGlobal, lhsParticipantCount == rhsParticipantCount {
return true
} else {
return false
}
case let .deviceContact(id, contact):
if case .deviceContact(id, contact) = rhs {
return true
} else {
return false
}
}
}
}
public final class ContactSelectionControllerParams {
public let context: AccountContext
public let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
public let mode: ContactSelectionControllerMode
public let autoDismiss: Bool
public let title: (PresentationStrings) -> String
public let options: Signal<[ContactListAdditionalOption], NoError>
public let displayDeviceContacts: Bool
public let displayCallIcons: Bool
public let multipleSelection: Bool
public let requirePhoneNumbers: Bool
public let confirmation: (ContactListPeer) -> Signal<Bool, NoError>
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: ContactSelectionControllerMode = .generic, autoDismiss: Bool = true, title: @escaping (PresentationStrings) -> String, options: Signal<[ContactListAdditionalOption], NoError> = .single([]), displayDeviceContacts: Bool = false, displayCallIcons: Bool = false, multipleSelection: Bool = false, requirePhoneNumbers: Bool = false, confirmation: @escaping (ContactListPeer) -> Signal<Bool, NoError> = { _ in .single(true) }) {
self.context = context
self.updatedPresentationData = updatedPresentationData
self.mode = mode
self.autoDismiss = autoDismiss
self.title = title
self.options = options
self.displayDeviceContacts = displayDeviceContacts
self.displayCallIcons = displayCallIcons
self.multipleSelection = multipleSelection
self.requirePhoneNumbers = requirePhoneNumbers
self.confirmation = confirmation
}
}

View File

@ -857,8 +857,13 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
return
}
if let navigationController = self.navigationController as? NavigationController {
var controllers = navigationController.viewControllers
controllers = controllers.filter { !($0 is ContactSelectionController) }
navigationController.setViewControllers(controllers, animated: true)
}
Queue.mainQueue().after(2.0) {
//TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let resultController = UndoOverlayController(
presentationData: presentationData,
@ -867,8 +872,8 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
scale: 0.066,
colors: [:],
title: nil,
text: "\(stars) Stars sent.",
customUndoText: "View Chat",
text: presentationData.strings.Stars_Intro_StarsSent(Int32(stars)),
customUndoText: presentationData.strings.Stars_Intro_StarsSent_ViewChat,
timeout: nil
),
elevatedLayout: false,

View File

@ -17,6 +17,7 @@ import ChatSendMessageActionUI
class ContactSelectionControllerImpl: ViewController, ContactSelectionController, PresentableController, AttachmentContainable {
private let context: AccountContext
private let mode: ContactSelectionControllerMode
private let autoDismiss: Bool
fileprivate var contactsNode: ContactSelectionControllerNode {
@ -35,7 +36,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
private let index: PeerNameIndex = .lastNameFirst
private let titleProducer: (PresentationStrings) -> String
private let options: [ContactListAdditionalOption]
private let options: Signal<[ContactListAdditionalOption], NoError>
private let displayDeviceContacts: Bool
private let displayCallIcons: Bool
private let multipleSelection: Bool
@ -94,6 +95,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
init(_ params: ContactSelectionControllerParams) {
self.context = params.context
self.mode = params.mode
self.autoDismiss = params.autoDismiss
self.titleProducer = params.title
self.options = params.options
@ -207,7 +209,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
}
override func loadDisplayNode() {
self.displayNode = ContactSelectionControllerNode(context: self.context, presentationData: self.presentationData, options: self.options, displayDeviceContacts: self.displayDeviceContacts, displayCallIcons: self.displayCallIcons, multipleSelection: self.multipleSelection, requirePhoneNumbers: self.requirePhoneNumbers)
self.displayNode = ContactSelectionControllerNode(context: self.context, mode: self.mode, presentationData: self.presentationData, options: self.options, displayDeviceContacts: self.displayDeviceContacts, displayCallIcons: self.displayCallIcons, multipleSelection: self.multipleSelection, requirePhoneNumbers: self.requirePhoneNumbers)
self._ready.set(self.contactsNode.contactListNode.ready)
self.contactsNode.navigationBar = self.navigationBar

View File

@ -55,7 +55,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
var searchContainerNode: ContactsSearchContainerNode?
init(context: AccountContext, presentationData: PresentationData, options: [ContactListAdditionalOption], displayDeviceContacts: Bool, displayCallIcons: Bool, multipleSelection: Bool, requirePhoneNumbers: Bool) {
init(context: AccountContext, mode: ContactSelectionControllerMode, presentationData: PresentationData, options: Signal<[ContactListAdditionalOption], NoError>, displayDeviceContacts: Bool, displayCallIcons: Bool, multipleSelection: Bool, requirePhoneNumbers: Bool) {
self.context = context
self.presentationData = presentationData
self.displayDeviceContacts = displayDeviceContacts
@ -67,8 +67,50 @@ final class ContactSelectionControllerNode: ASDisplayNode {
}
self.filters = filters
let displayTopPeers: ContactListPresentation.TopPeers
if case let .starsGifting(birthdays, hasActions) = mode {
if let birthdays {
let today = Calendar(identifier: .gregorian).component(.day, from: Date())
var sections: [(String, [EnginePeer.Id], Bool)] = []
var todayPeers: [EnginePeer.Id] = []
var yesterdayPeers: [EnginePeer.Id] = []
var tomorrowPeers: [EnginePeer.Id] = []
for (peerId, birthday) in birthdays {
if birthday.day == today {
todayPeers.append(peerId)
} else if birthday.day == today - 1 || birthday.day > today + 5 {
yesterdayPeers.append(peerId)
} else if birthday.day == today + 1 || birthday.day < today + 5 {
tomorrowPeers.append(peerId)
}
}
if !todayPeers.isEmpty {
sections.append((presentationData.strings.Premium_Gift_ContactSelection_BirthdayToday, todayPeers, hasActions))
}
if !yesterdayPeers.isEmpty {
sections.append((presentationData.strings.Premium_Gift_ContactSelection_BirthdayYesterday, yesterdayPeers, hasActions))
}
if !tomorrowPeers.isEmpty {
sections.append((presentationData.strings.Premium_Gift_ContactSelection_BirthdayTomorrow, tomorrowPeers, hasActions))
}
displayTopPeers = .custom(sections)
} else {
displayTopPeers = .recent
}
} else {
displayTopPeers = .none
}
let presentation: Signal<ContactListPresentation, NoError> = options
|> map { options in
return .natural(options: options, includeChatList: false, topPeers: displayTopPeers)
}
var contextActionImpl: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
self.contactListNode = ContactListNode(context: context, updatedPresentationData: (presentationData, self.presentationDataPromise.get()), presentation: .single(.natural(options: options, includeChatList: false, topPeers: .none)), filters: filters, onlyWriteable: false, isGroupInvitation: false, displayCallIcons: displayCallIcons, contextAction: multipleSelection ? { peer, node, gesture, _, _ in
self.contactListNode = ContactListNode(context: context, updatedPresentationData: (presentationData, self.presentationDataPromise.get()), presentation: presentation, filters: filters, onlyWriteable: false, isGroupInvitation: false, displayCallIcons: displayCallIcons, contextAction: multipleSelection ? { peer, node, gesture, _, _ in
contextActionImpl?(peer, node, gesture, nil)
} : nil, multipleSelection: multipleSelection)

View File

@ -2192,6 +2192,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
var reachedLimitImpl: ((Int32) -> Void)?
var presentBirthdayPickerImpl: (() -> Void)?
let mode: ContactMultiselectionControllerMode
var starsMode: ContactSelectionControllerMode = .generic
var currentBirthdays: [EnginePeer.Id: TelegramBirthday]?
if case let .chatList(birthdays) = source, let birthdays, !birthdays.isEmpty {
mode = .premiumGifting(birthdays: birthdays, selectToday: true, hasActions: true)
@ -2201,6 +2202,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
currentBirthdays = birthdays
} else if case let .stars(birthdays) = source {
mode = .premiumGifting(birthdays: birthdays, selectToday: false, hasActions: false)
starsMode = .starsGifting(birthdays: birthdays, hasActions: false)
currentBirthdays = birthdays
} else {
mode = .premiumGifting(birthdays: nil, selectToday: false, hasActions: true)
@ -2237,7 +2239,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
options.set(context.engine.payments.starsGiftOptions(peerId: nil))
let contactsController = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(
context: context,
title: { strings in return strings.Stars_Purchase_GiftStars }
mode: starsMode,
autoDismiss: false,
title: { strings in return strings.Stars_Purchase_GiftStars },
options: contactOptions
))
let _ = (contactsController.result
|> deliverOnMainQueue).start(next: { result in