mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Invite Links Fixes
This commit is contained in:
parent
426e8724dc
commit
935f931034
@ -5883,8 +5883,11 @@ Sorry for the inconvenience.";
|
||||
"InviteLink.InviteLink" = "Invite Link";
|
||||
"InviteLink.CreatedBy" = "Link Created By";
|
||||
|
||||
"InviteLink.DeleteLinkAlert.Text" = "Are you sure you want to delete this link? It will be completely gone.";
|
||||
"InviteLink.DeleteLinkAlert.Action" = "Delete";
|
||||
|
||||
"InviteLink.DeleteAllRevokedLinksAlert.Text" = "This will delete all revoked links.";
|
||||
"InviteLink.DeleteAllRevokedLinksAlert.Action" = "Delete";
|
||||
"InviteLink.DeleteAllRevokedLinksAlert.Action" = "Delete All";
|
||||
|
||||
"InviteLink.ExpiresIn" = "expires in %@";
|
||||
|
||||
|
@ -1212,8 +1212,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
strongSelf.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
switch controller.content {
|
||||
case let .archivedChat(archivedChat):
|
||||
if peerIds.contains(PeerId(archivedChat.peerId)) {
|
||||
case let .archivedChat(peerId, _, _, _):
|
||||
if peerIds.contains(PeerId(peerId)) {
|
||||
controller.dismiss()
|
||||
}
|
||||
default:
|
||||
|
@ -158,7 +158,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
return ChatListSearchItem(theme: theme, placeholder: strings.Contacts_SearchLabel, activate: {
|
||||
interaction.activateSearch()
|
||||
})
|
||||
case let .sort(theme, strings, sortOrder):
|
||||
case let .sort(_, strings, sortOrder):
|
||||
var text = strings.Contacts_SortedByName
|
||||
if case .presence = sortOrder {
|
||||
text = strings.Contacts_SortedByPresence
|
||||
@ -166,17 +166,17 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: text, icon: .inline(dropDownIcon, .right), highlight: .alpha, header: nil, action: {
|
||||
interaction.openSortMenu()
|
||||
})
|
||||
case let .permissionInfo(theme, title, text, suppressed):
|
||||
case let .permissionInfo(_, title, text, suppressed):
|
||||
return InfoListItem(presentationData: ItemListPresentationData(presentationData), title: title, text: .plain(text), style: .plain, closeAction: suppressed ? nil : {
|
||||
interaction.suppressWarning()
|
||||
})
|
||||
case let .permissionEnable(theme, text):
|
||||
case let .permissionEnable(_, text):
|
||||
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: text, icon: .none, header: nil, action: {
|
||||
interaction.authorize()
|
||||
})
|
||||
case let .option(_, option, header, theme, _):
|
||||
case let .option(_, option, header, _, _):
|
||||
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, icon: option.icon, clearHighlightAutomatically: false, header: header, action: option.action)
|
||||
case let .peer(_, peer, presence, header, selection, theme, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, enabled):
|
||||
case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, enabled):
|
||||
var status: ContactsPeerItemStatus
|
||||
let itemPeer: ContactsPeerItemPeer
|
||||
var isContextActionEnabled = false
|
||||
@ -928,9 +928,9 @@ public final class ContactListNode: ASDisplayNode {
|
||||
|> mapToSignal { presentation in
|
||||
var generateSections = false
|
||||
var includeChatList = false
|
||||
if case let .natural(natural) = presentation {
|
||||
if case let .natural(_, includeChatListValue) = presentation {
|
||||
generateSections = true
|
||||
includeChatList = natural.includeChatList
|
||||
includeChatList = includeChatListValue
|
||||
}
|
||||
|
||||
if case let .search(query, searchChatList, searchDeviceContacts, searchGroups, searchChannels, globalSearch) = presentation {
|
||||
|
@ -1225,7 +1225,7 @@ public class GalleryController: ViewController, StandalonePresentableController
|
||||
self.centralItemNavigationStyle.set(centralItemNode.navigationStyle())
|
||||
self.centralItemFooterContentNode.set(centralItemNode.footerContent())
|
||||
|
||||
if let (media, _) = mediaForMessage(message: message) {
|
||||
if let _ = mediaForMessage(message: message) {
|
||||
centralItemNode.activateAsInitial()
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
||||
})
|
||||
case let .usageCustomPicker(theme, value, focused):
|
||||
let text = value.flatMap { String($0) } ?? (focused ? "" : presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsersUnlimited)
|
||||
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(string: presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsers, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .number, alignment: .right, tag: nil, sectionId: self.section, textUpdated: { updatedText in
|
||||
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(string: presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsers, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .number, alignment: .right, selectAllOnFocus: true, tag: nil, sectionId: self.section, textUpdated: { updatedText in
|
||||
guard !updatedText.isEmpty else {
|
||||
return
|
||||
}
|
||||
@ -300,9 +300,10 @@ private struct InviteLinkEditControllerState: Equatable {
|
||||
var time: InviteLinkTimeLimit
|
||||
var pickingTimeLimit = false
|
||||
var pickingUsageLimit = false
|
||||
var updating = false
|
||||
}
|
||||
|
||||
public func inviteLinkEditController(context: AccountContext, peerId: PeerId, invite: ExportedInvitation?, completion: (() -> Void)? = nil) -> ViewController {
|
||||
public func inviteLinkEditController(context: AccountContext, peerId: PeerId, invite: ExportedInvitation?, completion: ((ExportedInvitation?) -> Void)? = nil) -> ViewController {
|
||||
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||
let actionsDisposable = DisposableSet()
|
||||
|
||||
@ -359,8 +360,17 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
||||
dismissAction()
|
||||
dismissImpl?()
|
||||
|
||||
let _ = (revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
completion?()
|
||||
let _ = (revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link)
|
||||
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|
||||
|> deliverOnMainQueue).start(next: { invite in
|
||||
completion?(invite)
|
||||
}, error: { _ in
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.updating = false
|
||||
return updatedState
|
||||
}
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
})
|
||||
})
|
||||
]),
|
||||
@ -369,6 +379,7 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
||||
presentControllerImpl?(controller, nil)
|
||||
})
|
||||
|
||||
let previousState = Atomic<InviteLinkEditControllerState?>(value: nil)
|
||||
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get())
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
@ -376,7 +387,13 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
||||
dismissImpl?()
|
||||
})
|
||||
|
||||
let rightNavigationButton = ItemListNavigationButton(content: .text(invite == nil ? presentationData.strings.Common_Create : presentationData.strings.Common_Save), style: .bold, enabled: true, action: {
|
||||
let rightNavigationButton = ItemListNavigationButton(content: .text(invite == nil ? presentationData.strings.Common_Create : presentationData.strings.Common_Save), style: state.updating ? .activity : .bold, enabled: true, action: {
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.updating = true
|
||||
return updatedState
|
||||
}
|
||||
|
||||
let expireDate: Int32?
|
||||
if case let .custom(value) = state.time {
|
||||
expireDate = value
|
||||
@ -390,21 +407,43 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
||||
let usageLimit = state.usage.value
|
||||
if invite == nil {
|
||||
let _ = (createPeerExportedInvitation(account: context.account, peerId: peerId, expireDate: expireDate, usageLimit: usageLimit)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
completion?()
|
||||
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|
||||
|> deliverOnMainQueue).start(next: { invite in
|
||||
completion?(invite)
|
||||
dismissImpl?()
|
||||
}, error: { _ in
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.updating = false
|
||||
return updatedState
|
||||
}
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
})
|
||||
} else if let invite = invite {
|
||||
let _ = (editPeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link, expireDate: expireDate, usageLimit: usageLimit)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
completion?()
|
||||
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|
||||
|> deliverOnMainQueue).start(next: { invite in
|
||||
completion?(invite)
|
||||
dismissImpl?()
|
||||
}, error: { _ in
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.updating = false
|
||||
return updatedState
|
||||
}
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
let previousState = previousState.swap(state)
|
||||
var animateChanges = false
|
||||
if let previousState = previousState, previousState.pickingTimeLimit != state.pickingTimeLimit {
|
||||
animateChanges = true
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(invite == nil ? presentationData.strings.InviteLink_Create_Title : presentationData.strings.InviteLink_Create_EditTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkEditControllerEntries(invite: invite, state: state, presentationData: presentationData), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkEditControllerEntries(invite: invite, state: state, presentationData: presentationData), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: animateChanges)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
@ -309,19 +309,14 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
|
||||
var getControllerImpl: (() -> ViewController?)?
|
||||
|
||||
let invitesPromise = Promise<ExportedInvitations?>()
|
||||
invitesPromise.set(.single(nil)
|
||||
|> then(peerExportedInvitations(account: context.account, peerId: peerId, revoked: false)))
|
||||
|
||||
let revokedInvitesPromise = Promise<ExportedInvitations?>()
|
||||
revokedInvitesPromise.set(.single(nil)
|
||||
|> then(peerExportedInvitations(account: context.account, peerId: peerId, revoked: true)))
|
||||
let invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: false)
|
||||
let revokedInvitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: true, forceUpdate: true)
|
||||
|
||||
let arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in
|
||||
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
}, openMainLink: { invite in
|
||||
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, importersContext: nil)
|
||||
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, invitationsContext: nil, importersContext: nil)
|
||||
pushControllerImpl?(controller)
|
||||
}, copyLink: { invite in
|
||||
UIPasteboard.general.string = invite.link
|
||||
@ -390,7 +385,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
updatedState.revokingPrivateLink = false
|
||||
return updatedState
|
||||
}
|
||||
invitesPromise.set(peerExportedInvitations(account: context.account, peerId: peerId, revoked: false))
|
||||
|
||||
invitesContext.reload()
|
||||
revokedInvitesContext.reload()
|
||||
}))
|
||||
}
|
||||
})
|
||||
@ -403,14 +400,16 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||
presentInGlobalOverlayImpl?(contextController)
|
||||
}, createLink: {
|
||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: nil, completion: {
|
||||
invitesPromise.set(peerExportedInvitations(account: context.account, peerId: peerId, revoked: false))
|
||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: nil, completion: { invite in
|
||||
if let invite = invite {
|
||||
invitesContext.add(invite)
|
||||
}
|
||||
})
|
||||
controller.navigationPresentation = .modal
|
||||
pushControllerImpl?(controller)
|
||||
}, openLink: { invite in
|
||||
if let invite = invite {
|
||||
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, importersContext: nil)
|
||||
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, invitationsContext: invitesContext, importersContext: nil)
|
||||
pushControllerImpl?(controller)
|
||||
}
|
||||
}, linkContextAction: { invite, node, gesture in
|
||||
@ -446,8 +445,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: invite, completion: {
|
||||
invitesPromise.set(peerExportedInvitations(account: context.account, peerId: peerId, revoked: false))
|
||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: invite, completion: { invite in
|
||||
if let invite = invite {
|
||||
if invite.isRevoked {
|
||||
invitesContext.remove(invite)
|
||||
revokedInvitesContext.add(invite)
|
||||
} else {
|
||||
invitesContext.update(invite)
|
||||
}
|
||||
}
|
||||
})
|
||||
controller.navigationPresentation = .modal
|
||||
pushControllerImpl?(controller)
|
||||
@ -466,13 +472,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
}
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeAlert_Text),
|
||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||
ActionSheetTextItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Text),
|
||||
ActionSheetButtonItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Action, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
revokeLinkDisposable.set((deletePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
|
||||
}))
|
||||
|
||||
revokedInvitesContext.remove(invite)
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
@ -498,6 +506,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
revokeLinkDisposable.set((revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
|
||||
}))
|
||||
|
||||
invitesContext.remove(invite)
|
||||
revokedInvitesContext.add(invite)
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
@ -521,8 +532,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
dismissAction()
|
||||
|
||||
deleteAllRevokedLinksDisposable.set((deleteAllRevokedPeerExportedInvitations(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||
|
||||
}))
|
||||
|
||||
revokedInvitesContext.clear()
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
@ -552,11 +564,11 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
||||
importersState.set(context.state |> map(Optional.init))
|
||||
}
|
||||
|
||||
let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesPromise.get(), revokedInvitesPromise.get())
|
||||
let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state)
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, view, importersContext, importers, invites, revokedInvites -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.InviteLink_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkListControllerEntries(presentationData: presentationData, view: view, invites: invites?.list, revokedInvites: revokedInvites?.list, mainPeers: importers?.importers.compactMap { $0.peer.peer } ?? []), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkListControllerEntries(presentationData: presentationData, view: view, invites: invites.invitations, revokedInvites: revokedInvites.invitations, mainPeers: importers?.importers.compactMap { $0.peer.peer } ?? []), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
@ -342,7 +342,6 @@ public final class InviteLinkQRCodeController: ViewController {
|
||||
self.containerLayout = (layout, navigationBarHeight)
|
||||
|
||||
var insets = layout.insets(options: [.statusBar, .input])
|
||||
let cleanInsets = layout.insets(options: [.statusBar])
|
||||
insets.top = max(10.0, insets.top)
|
||||
|
||||
let makeImageLayout = self.qrImageNode.asyncLayout()
|
||||
|
@ -118,7 +118,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
||||
return false
|
||||
}
|
||||
case let .importer(lhsIndex, lhsTheme, lhsDateTimeFormat, lhsPeer, lhsDate, lhsLoading):
|
||||
if case let .importer(rhsIndex, rhsTheme, rhsDateTimeFormat, rhsPeer, rhsDate, rhsLoading) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, arePeersEqual(lhsPeer, rhsPeer), lhsDate == rhsDate {
|
||||
if case let .importer(rhsIndex, rhsTheme, rhsDateTimeFormat, rhsPeer, rhsDate, rhsLoading) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, arePeersEqual(lhsPeer, rhsPeer), lhsDate == rhsDate, lhsLoading == rhsLoading {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -192,7 +192,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
||||
let dateString = stringForFullDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: dateTimeFormat)
|
||||
return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: interaction.context, peer: peer, height: .generic, nameStyle: .distinctBold, presence: nil, text: .text(dateString, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: 0, action: {
|
||||
interaction.openPeer(peer.id)
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, hasTopStripe: false, noInsets: true, tag: nil, shimmering: ItemListPeerItemShimmering(alternationIndex: 0))
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, hasTopStripe: false, noInsets: true, tag: nil, shimmering: loading ? ItemListPeerItemShimmering(alternationIndex: 0) : nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,14 +217,16 @@ public final class InviteLinkViewController: ViewController {
|
||||
private let context: AccountContext
|
||||
private let peerId: PeerId
|
||||
private let invite: ExportedInvitation
|
||||
private let invitationsContext: PeerExportedInvitationsContext?
|
||||
private let importersContext: PeerInvitationImportersContext?
|
||||
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, peerId: PeerId, invite: ExportedInvitation, importersContext: PeerInvitationImportersContext?) {
|
||||
public init(context: AccountContext, peerId: PeerId, invite: ExportedInvitation, invitationsContext: PeerExportedInvitationsContext?, importersContext: PeerInvitationImportersContext?) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.invite = invite
|
||||
self.invitationsContext = invitationsContext
|
||||
self.importersContext = importersContext
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
@ -539,8 +541,17 @@ public final class InviteLinkViewController: ViewController {
|
||||
let navigationController = self.controller?.navigationController as? NavigationController
|
||||
self.controller?.dismiss()
|
||||
|
||||
let invitationsContext = self.controller?.invitationsContext
|
||||
if let navigationController = navigationController {
|
||||
let controller = inviteLinkEditController(context: self.context, peerId: self.peerId, invite: self.invite)
|
||||
let controller = inviteLinkEditController(context: self.context, peerId: self.peerId, invite: self.invite, completion: { [weak self] invite in
|
||||
if let invite = invite {
|
||||
if invite.isRevoked {
|
||||
invitationsContext?.remove(invite)
|
||||
} else {
|
||||
invitationsContext?.update(invite)
|
||||
}
|
||||
}
|
||||
})
|
||||
controller.navigationPresentation = .modal
|
||||
navigationController.pushViewController(controller)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let datePicker: UIDatePicker
|
||||
private var datePicker: UIDatePicker?
|
||||
|
||||
private var item: ItemListDatePickerItem?
|
||||
|
||||
@ -98,25 +98,31 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode {
|
||||
self.bottomStripeNode = ASDisplayNode()
|
||||
self.bottomStripeNode.isLayerBacked = true
|
||||
|
||||
self.datePicker = UIDatePicker()
|
||||
self.datePicker.minimumDate = Date()
|
||||
self.datePicker.datePickerMode = .dateAndTime
|
||||
if #available(iOS 14.0, *) {
|
||||
self.datePicker.preferredDatePickerStyle = .inline
|
||||
}
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.datePicker.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
|
||||
}
|
||||
|
||||
public override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.view.addSubview(self.datePicker)
|
||||
let datePicker = UIDatePicker()
|
||||
datePicker.minimumDate = Date()
|
||||
datePicker.datePickerMode = .dateAndTime
|
||||
if #available(iOS 14.0, *) {
|
||||
datePicker.preferredDatePickerStyle = .inline
|
||||
}
|
||||
|
||||
datePicker.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
|
||||
|
||||
self.view.addSubview(datePicker)
|
||||
self.datePicker = datePicker
|
||||
}
|
||||
|
||||
@objc private func datePickerUpdated() {
|
||||
self.item?.updated?(Int32(self.datePicker.date.timeIntervalSince1970))
|
||||
guard let datePicker = self.datePicker else {
|
||||
return
|
||||
}
|
||||
self.item?.updated?(Int32(datePicker.date.timeIntervalSince1970))
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ item: ItemListDatePickerItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
@ -162,8 +168,8 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode {
|
||||
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||
}
|
||||
|
||||
strongSelf.datePicker.date = item.date.flatMap { Date(timeIntervalSince1970: TimeInterval($0)) } ?? Date()
|
||||
strongSelf.datePicker.frame = CGRect(origin: CGPoint(x: 16.0, y: 3.0), size: CGSize(width: contentSize.width - 32.0, height: contentSize.height))
|
||||
strongSelf.datePicker?.date = item.date.flatMap { Date(timeIntervalSince1970: TimeInterval($0)) } ?? Date()
|
||||
strongSelf.datePicker?.frame = CGRect(origin: CGPoint(x: 16.0, y: 3.0), size: CGSize(width: contentSize.width - 32.0, height: contentSize.height))
|
||||
|
||||
switch item.style {
|
||||
case .plain:
|
||||
|
@ -130,7 +130,6 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
|
||||
let itemSeparatorColor: UIColor
|
||||
|
||||
let leftInset = 16.0 + params.leftInset
|
||||
let rightInset = 16.0 + params.rightInset
|
||||
|
||||
var height: CGFloat
|
||||
let count = item.invites?.count ?? 0
|
||||
|
@ -46,6 +46,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
||||
let clearType: ItemListSingleLineInputClearType
|
||||
let maxLength: Int
|
||||
let enabled: Bool
|
||||
let selectAllOnFocus: Bool
|
||||
public let sectionId: ItemListSectionId
|
||||
let action: () -> Void
|
||||
let textUpdated: (String) -> Void
|
||||
@ -55,7 +56,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
||||
let cleared: (() -> Void)?
|
||||
public let tag: ItemListItemTag?
|
||||
|
||||
public init(presentationData: ItemListPresentationData, title: NSAttributedString, text: String, placeholder: String, type: ItemListSingleLineInputItemType = .regular(capitalization: true, autocorrection: true), returnKeyType: UIReturnKeyType = .`default`, alignment: ItemListSingleLineInputAlignment = .default, spacing: CGFloat = 0.0, clearType: ItemListSingleLineInputClearType = .none, maxLength: Int = 0, enabled: Bool = true, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, processPaste: ((String) -> String)? = nil, updatedFocus: ((Bool) -> Void)? = nil, action: @escaping () -> Void, cleared: (() -> Void)? = nil) {
|
||||
public init(presentationData: ItemListPresentationData, title: NSAttributedString, text: String, placeholder: String, type: ItemListSingleLineInputItemType = .regular(capitalization: true, autocorrection: true), returnKeyType: UIReturnKeyType = .`default`, alignment: ItemListSingleLineInputAlignment = .default, spacing: CGFloat = 0.0, clearType: ItemListSingleLineInputClearType = .none, maxLength: Int = 0, enabled: Bool = true, selectAllOnFocus: Bool = false, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, processPaste: ((String) -> String)? = nil, updatedFocus: ((Bool) -> Void)? = nil, action: @escaping () -> Void, cleared: (() -> Void)? = nil) {
|
||||
self.presentationData = presentationData
|
||||
self.title = title
|
||||
self.text = text
|
||||
@ -67,6 +68,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
||||
self.clearType = clearType
|
||||
self.maxLength = maxLength
|
||||
self.enabled = enabled
|
||||
self.selectAllOnFocus = selectAllOnFocus
|
||||
self.tag = tag
|
||||
self.sectionId = sectionId
|
||||
self.textUpdated = textUpdated
|
||||
@ -494,6 +496,13 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
||||
|
||||
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
self.item?.updatedFocus?(true)
|
||||
if self.item?.selectAllOnFocus == true {
|
||||
DispatchQueue.main.async {
|
||||
let startPosition = self.textNode.textField.beginningOfDocument
|
||||
let endPosition = self.textNode.textField.endOfDocument
|
||||
self.textNode.textField.selectedTextRange = self.textNode.textField.textRange(from: startPosition, to: endPosition)
|
||||
}
|
||||
}
|
||||
self.updateClearButtonVisibility()
|
||||
}
|
||||
|
||||
|
@ -368,7 +368,7 @@ private enum ChannelAdminEntry: ItemListNodeEntry {
|
||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! ChannelAdminControllerArguments
|
||||
switch self {
|
||||
case let .info(_, strings, dateTimeFormat, peer, presence):
|
||||
case let .info(_, _, dateTimeFormat, peer, presence):
|
||||
return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, cachedData: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in
|
||||
}, avatarTapped: {
|
||||
})
|
||||
|
@ -182,17 +182,17 @@ private enum ChannelMembersEntry: ItemListNodeEntry {
|
||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! ChannelMembersControllerArguments
|
||||
switch self {
|
||||
case let .addMember(theme, text):
|
||||
case let .addMember(_, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.addMember()
|
||||
})
|
||||
case let .inviteLink(theme, text):
|
||||
case let .inviteLink(_, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.inviteViaLink()
|
||||
})
|
||||
case let .addMemberInfo(theme, text):
|
||||
case let .addMemberInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .peerItem(_, theme, strings, dateTimeFormat, nameDisplayOrder, participant, editing, enabled):
|
||||
case let .peerItem(_, _, strings, dateTimeFormat, nameDisplayOrder, participant, editing, enabled):
|
||||
let text: ItemListPeerItemText
|
||||
if let user = participant.peer as? TelegramUser, let _ = user.botInfo {
|
||||
text = .text(strings.Bot_GenericBotStatus, .secondary)
|
||||
@ -465,6 +465,7 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) ->
|
||||
}
|
||||
}, inviteViaLink: {
|
||||
if let controller = getControllerImpl?() {
|
||||
dismissInputImpl?()
|
||||
presentControllerImpl?(InviteLinkInviteController(context: context, peerId: peerId, parentNavigationController: controller.navigationController as? NavigationController), nil)
|
||||
}
|
||||
})
|
||||
|
@ -79,7 +79,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
case publicLinkAvailability(PresentationTheme, String, Bool)
|
||||
case editablePublicLink(PresentationTheme, PresentationStrings, String, String)
|
||||
case privateLinkHeader(PresentationTheme, String)
|
||||
case privateLink(PresentationTheme, ExportedInvitation?)
|
||||
case privateLink(PresentationTheme, ExportedInvitation?, Bool)
|
||||
case privateLinkInfo(PresentationTheme, String)
|
||||
case privateLinkManage(PresentationTheme, String)
|
||||
case privateLinkManageInfo(PresentationTheme, String)
|
||||
@ -184,8 +184,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .privateLink(lhsTheme, lhsInvite):
|
||||
if case let .privateLink(rhsTheme, rhsInvite) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite {
|
||||
case let .privateLink(lhsTheme, lhsInvite, lhsDisplayImporters):
|
||||
if case let .privateLink(rhsTheme, rhsInvite, rhsDisplayImporters) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite, lhsDisplayImporters == rhsDisplayImporters {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -292,8 +292,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
return ItemListActivityTextItem(displayActivity: value, presentationData: presentationData, text: attr, sectionId: self.section)
|
||||
case let .privateLinkHeader(_, title):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||
case let .privateLink(_, invite):
|
||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: [], displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||
case let .privateLink(_, invite, displayImporters):
|
||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: [], displayButton: true, displayImporters: displayImporters, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||
if let invite = invite {
|
||||
arguments.copyLink(invite)
|
||||
}
|
||||
@ -602,7 +602,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
case .privateChannel:
|
||||
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite))
|
||||
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
|
||||
if isGroup {
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||
} else {
|
||||
@ -621,7 +621,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
case .privateLink:
|
||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite))
|
||||
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
|
||||
switch mode {
|
||||
case .initialSetup:
|
||||
@ -720,7 +720,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
case .privateChannel:
|
||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite))
|
||||
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||
switch mode {
|
||||
case .initialSetup:
|
||||
@ -1059,7 +1059,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
|
||||
return state.withUpdatedUpdatingAddressName(false)
|
||||
}
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
|
||||
}, completed: {
|
||||
updateState { state in
|
||||
return state.withUpdatedUpdatingAddressName(false)
|
||||
|
@ -3,20 +3,24 @@ import Postbox
|
||||
public final class CachedStickerQueryResult: PostboxCoding {
|
||||
public let items: [TelegramMediaFile]
|
||||
public let hash: Int32
|
||||
public let timestamp: Int32
|
||||
|
||||
public init(items: [TelegramMediaFile], hash: Int32) {
|
||||
public init(items: [TelegramMediaFile], hash: Int32, timestamp: Int32) {
|
||||
self.items = items
|
||||
self.hash = hash
|
||||
self.timestamp = timestamp
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.items = decoder.decodeObjectArrayForKey("it").map { $0 as! TelegramMediaFile }
|
||||
self.hash = decoder.decodeInt32ForKey("h", orElse: 0)
|
||||
self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeObjectArray(self.items, forKey: "it")
|
||||
encoder.encodeInt32(self.hash, forKey: "h")
|
||||
encoder.encodeInt32(self.timestamp, forKey: "t")
|
||||
}
|
||||
|
||||
public static func cacheKey(_ query: String) -> ValueBoxKey {
|
||||
|
@ -74,6 +74,7 @@ public struct Namespaces {
|
||||
public static let cachedContextResults: Int8 = 10
|
||||
public static let proximityNotificationStoredState: Int8 = 11
|
||||
public static let cachedPeerInvitationImporters: Int8 = 12
|
||||
public static let cachedPeerExportedInvitations: Int8 = 13
|
||||
}
|
||||
|
||||
public struct UnorderedItemList {
|
||||
|
@ -170,6 +170,8 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(ValidationMessageAttribute.self, f: { ValidationMessageAttribute(decoder: $0) })
|
||||
declareEncodable(EmojiSearchQueryMessageAttribute.self, f: { EmojiSearchQueryMessageAttribute(decoder: $0) })
|
||||
declareEncodable(CachedPeerInvitationImporters.self, f: { CachedPeerInvitationImporters(decoder: $0) })
|
||||
declareEncodable(CachedPeerExportedInvitations.self, f: { CachedPeerExportedInvitations(decoder: $0) })
|
||||
declareEncodable(ExportedInvitation.self, f: { ExportedInvitation(decoder: $0) })
|
||||
|
||||
return
|
||||
}()
|
||||
|
@ -57,8 +57,12 @@ public func revokePersistentPeerExportedInvitation(account: Account, peerId: Pee
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func createPeerExportedInvitation(account: Account, peerId: PeerId, expireDate: Int32?, usageLimit: Int32?) -> Signal<ExportedInvitation?, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in
|
||||
public enum CreatePeerExportedInvitationError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func createPeerExportedInvitation(account: Account, peerId: PeerId, expireDate: Int32?, usageLimit: Int32?) -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> {
|
||||
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
var flags: Int32 = 0
|
||||
if let _ = expireDate {
|
||||
@ -68,7 +72,7 @@ public func createPeerExportedInvitation(account: Account, peerId: PeerId, expir
|
||||
flags |= (1 << 1)
|
||||
}
|
||||
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: expireDate, usageLimit: usageLimit))
|
||||
|> retryRequest
|
||||
|> mapError { _ in return CreatePeerExportedInvitationError.generic }
|
||||
|> map { result -> ExportedInvitation? in
|
||||
if let invitation = ExportedInvitation(apiExportedInvite: result) {
|
||||
return invitation
|
||||
@ -79,7 +83,9 @@ public func createPeerExportedInvitation(account: Account, peerId: PeerId, expir
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
|> castError(CreatePeerExportedInvitationError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
public struct ExportedInvitations : Equatable {
|
||||
@ -258,9 +264,10 @@ final class CachedPeerExportedInvitations: PostboxCoding {
|
||||
let canLoadMore: Bool
|
||||
let count: Int32
|
||||
|
||||
public static func key(peerId: PeerId) -> ValueBoxKey {
|
||||
public static func key(peerId: PeerId, revoked: Bool) -> ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 8 + 4)
|
||||
key.setInt64(0, value: peerId.toInt64())
|
||||
key.setInt32(8, value: revoked ? 1 : 0)
|
||||
return key
|
||||
}
|
||||
|
||||
@ -287,26 +294,32 @@ private final class PeerExportedInvitationsContextImpl {
|
||||
private let queue: Queue
|
||||
private let account: Account
|
||||
private let peerId: PeerId
|
||||
private let revoked: Bool
|
||||
private var forceUpdate: Bool
|
||||
private let disposable = MetaDisposable()
|
||||
private let updateDisposable = MetaDisposable()
|
||||
private var isLoadingMore: Bool = false
|
||||
private var hasLoadedOnce: Bool = false
|
||||
private var canLoadMore: Bool = true
|
||||
private var loadedFromCache: Bool = false
|
||||
private var results: [ExportedInvitation] = []
|
||||
private var count: Int32
|
||||
private var populateCache: Bool = true
|
||||
|
||||
let state = Promise<PeerExportedInvitationsState>()
|
||||
|
||||
init(queue: Queue, account: Account, peerId: PeerId) {
|
||||
init(queue: Queue, account: Account, peerId: PeerId, revoked: Bool, forceUpdate: Bool) {
|
||||
self.queue = queue
|
||||
self.account = account
|
||||
self.peerId = peerId
|
||||
self.revoked = revoked
|
||||
self.forceUpdate = forceUpdate
|
||||
|
||||
self.count = 0
|
||||
|
||||
self.isLoadingMore = true
|
||||
self.disposable.set((account.postbox.transaction { transaction -> CachedPeerExportedInvitations? in
|
||||
return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerExportedInvitations.key(peerId: peerId))) as? CachedPeerExportedInvitations
|
||||
return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked))) as? CachedPeerExportedInvitations
|
||||
}
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] cachedResult in
|
||||
guard let strongSelf = self else {
|
||||
@ -318,6 +331,7 @@ private final class PeerExportedInvitationsContextImpl {
|
||||
strongSelf.count = cachedResult.count
|
||||
strongSelf.hasLoadedOnce = true
|
||||
strongSelf.canLoadMore = cachedResult.canLoadMore
|
||||
strongSelf.loadedFromCache = true
|
||||
}
|
||||
strongSelf.loadMore()
|
||||
}))
|
||||
@ -327,6 +341,12 @@ private final class PeerExportedInvitationsContextImpl {
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.updateDisposable.dispose()
|
||||
}
|
||||
|
||||
func reload() {
|
||||
self.forceUpdate = true
|
||||
self.loadMore()
|
||||
}
|
||||
|
||||
func loadMore() {
|
||||
@ -336,16 +356,33 @@ private final class PeerExportedInvitationsContextImpl {
|
||||
self.isLoadingMore = true
|
||||
let account = self.account
|
||||
let peerId = self.peerId
|
||||
let lastResult = self.results.last
|
||||
let revoked = self.revoked
|
||||
var lastResult = self.results.last
|
||||
|
||||
if self.forceUpdate {
|
||||
self.forceUpdate = false
|
||||
lastResult = nil
|
||||
}
|
||||
if !self.forceUpdate && self.loadedFromCache {
|
||||
self.populateCache = false
|
||||
self.loadedFromCache = false
|
||||
}
|
||||
let populateCache = self.populateCache
|
||||
|
||||
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<([ExportedInvitation], Int32), NoError> in
|
||||
if let inputPeer = inputPeer {
|
||||
let offsetLink = lastResult?.link
|
||||
|
||||
let signal = account.network.request(Api.functions.messages.getExportedChatInvites(flags: 0, peer: inputPeer, adminId: nil, offsetLink: offsetLink, limit: lastResult == nil ? 50 : 100))
|
||||
var flags: Int32 = 0
|
||||
if let _ = offsetLink {
|
||||
flags |= (1 << 2)
|
||||
}
|
||||
if revoked {
|
||||
flags |= (1 << 3)
|
||||
}
|
||||
let signal = account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: nil, offsetLink: offsetLink, limit: lastResult == nil ? 50 : 100))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
|
||||
return .single(nil)
|
||||
@ -366,7 +403,7 @@ private final class PeerExportedInvitationsContextImpl {
|
||||
})
|
||||
let invitations: [ExportedInvitation] = invites.compactMap { ExportedInvitation(apiExportedInvite: $0) }
|
||||
if populateCache {
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerExportedInvitations.key(peerId: peerId)), entry: CachedPeerExportedInvitations(invitations: invitations, canLoadMore: count >= 50, count: count), collectionSpec: cachedPeerExportedInvitationsCollectionSpec)
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: CachedPeerExportedInvitations(invitations: invitations, canLoadMore: count >= 50, count: count), collectionSpec: cachedPeerExportedInvitationsCollectionSpec)
|
||||
}
|
||||
return (invitations, count)
|
||||
}
|
||||
@ -401,10 +438,63 @@ private final class PeerExportedInvitationsContextImpl {
|
||||
strongSelf.count = Int32(strongSelf.results.count)
|
||||
}
|
||||
strongSelf.updateState()
|
||||
|
||||
if strongSelf.forceUpdate {
|
||||
strongSelf.loadMore()
|
||||
}
|
||||
}))
|
||||
self.updateState()
|
||||
}
|
||||
|
||||
public func add(_ invite: ExportedInvitation) {
|
||||
var results = self.results
|
||||
results.removeAll(where: { $0.link == invite.link})
|
||||
results.insert(invite, at: 0)
|
||||
self.results = results
|
||||
self.updateState()
|
||||
self.updateCache()
|
||||
}
|
||||
|
||||
public func update(_ invite: ExportedInvitation) {
|
||||
var results = self.results
|
||||
if let index = self.results.firstIndex(where: { $0.link == invite.link }) {
|
||||
results[index] = invite
|
||||
}
|
||||
self.results = results
|
||||
self.updateState()
|
||||
self.updateCache()
|
||||
}
|
||||
|
||||
public func remove(_ invite: ExportedInvitation) {
|
||||
var results = self.results
|
||||
results.removeAll(where: { $0.link == invite.link})
|
||||
self.results = results
|
||||
self.updateState()
|
||||
self.updateCache()
|
||||
}
|
||||
|
||||
public func clear() {
|
||||
self.results = []
|
||||
self.count = 0
|
||||
self.updateState()
|
||||
self.updateCache()
|
||||
}
|
||||
|
||||
private func updateCache() {
|
||||
guard self.hasLoadedOnce && !self.isLoadingMore else {
|
||||
return
|
||||
}
|
||||
|
||||
let peerId = self.peerId
|
||||
let revoked = self.revoked
|
||||
let invitations = Array(self.results.prefix(50))
|
||||
let canLoadMore = self.canLoadMore
|
||||
let count = self.count
|
||||
self.updateDisposable.set(self.account.postbox.transaction({ transaction in
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: CachedPeerExportedInvitations(invitations: invitations, canLoadMore: canLoadMore, count: count), collectionSpec: cachedPeerExportedInvitationsCollectionSpec)
|
||||
}).start())
|
||||
}
|
||||
|
||||
private func updateState() {
|
||||
self.state.set(.single(PeerExportedInvitationsState(invitations: self.results, isLoadingMore: self.isLoadingMore, hasLoadedOnce: self.hasLoadedOnce, canLoadMore: self.canLoadMore, count: self.count)))
|
||||
}
|
||||
@ -426,18 +516,48 @@ public final class PeerExportedInvitationsContext {
|
||||
}
|
||||
}
|
||||
|
||||
public init(account: Account, peerId: PeerId, invite: ExportedInvitation) {
|
||||
public init(account: Account, peerId: PeerId, revoked: Bool, forceUpdate: Bool) {
|
||||
let queue = self.queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return PeerExportedInvitationsContextImpl(queue: queue, account: account, peerId: peerId)
|
||||
return PeerExportedInvitationsContextImpl(queue: queue, account: account, peerId: peerId, revoked: revoked, forceUpdate: forceUpdate)
|
||||
})
|
||||
}
|
||||
|
||||
public func reload() {
|
||||
self.impl.with { impl in
|
||||
impl.reload()
|
||||
}
|
||||
}
|
||||
|
||||
public func loadMore() {
|
||||
self.impl.with { impl in
|
||||
impl.loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
public func add(_ invite: ExportedInvitation) {
|
||||
self.impl.with { impl in
|
||||
impl.add(invite)
|
||||
}
|
||||
}
|
||||
|
||||
public func update(_ invite: ExportedInvitation) {
|
||||
self.impl.with { impl in
|
||||
impl.update(invite)
|
||||
}
|
||||
}
|
||||
|
||||
public func remove(_ invite: ExportedInvitation) {
|
||||
self.impl.with { impl in
|
||||
impl.remove(invite)
|
||||
}
|
||||
}
|
||||
|
||||
public func clear() {
|
||||
self.impl.with { impl in
|
||||
impl.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -521,6 +641,7 @@ private final class PeerInvitationImportersContextImpl {
|
||||
private var isLoadingMore: Bool = false
|
||||
private var hasLoadedOnce: Bool = false
|
||||
private var canLoadMore: Bool = true
|
||||
private var loadedFromCache = false
|
||||
private var results: [PeerInvitationImportersState.Importer] = []
|
||||
private var count: Int32
|
||||
private var populateCache: Bool = true
|
||||
@ -562,6 +683,7 @@ private final class PeerInvitationImportersContextImpl {
|
||||
strongSelf.results = cachedPeers
|
||||
strongSelf.hasLoadedOnce = true
|
||||
strongSelf.canLoadMore = canLoadMore
|
||||
strongSelf.loadedFromCache = true
|
||||
}
|
||||
strongSelf.loadMore()
|
||||
}))
|
||||
@ -581,8 +703,14 @@ private final class PeerInvitationImportersContextImpl {
|
||||
let account = self.account
|
||||
let peerId = self.peerId
|
||||
let link = self.link
|
||||
let lastResult = self.results.last
|
||||
let populateCache = self.populateCache
|
||||
|
||||
var lastResult = self.results.last
|
||||
if self.loadedFromCache {
|
||||
self.loadedFromCache = false
|
||||
lastResult = nil
|
||||
}
|
||||
|
||||
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|
@ -5,6 +5,26 @@ import SwiftSignalKit
|
||||
|
||||
import SyncCore
|
||||
|
||||
private struct SearchStickersConfiguration {
|
||||
static var defaultValue: SearchStickersConfiguration {
|
||||
return SearchStickersConfiguration(cacheTimeout: 86400)
|
||||
}
|
||||
|
||||
public let cacheTimeout: Int32
|
||||
|
||||
fileprivate init(cacheTimeout: Int32) {
|
||||
self.cacheTimeout = cacheTimeout
|
||||
}
|
||||
|
||||
static func with(appConfiguration: AppConfiguration) -> SearchStickersConfiguration {
|
||||
if let data = appConfiguration.data, let value = data["stickers_emoji_cache_time"] as? Int32 {
|
||||
return SearchStickersConfiguration(cacheTimeout: value)
|
||||
} else {
|
||||
return .defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class FoundStickerItem: Equatable {
|
||||
public let file: TelegramMediaFile
|
||||
public let stringRepresentations: [String]
|
||||
@ -140,7 +160,15 @@ public func searchStickers(account: Account, query: String, scope: SearchSticker
|
||||
result.append(contentsOf: installedItems)
|
||||
}
|
||||
|
||||
let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query))) as? CachedStickerQueryResult
|
||||
var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query))) as? CachedStickerQueryResult
|
||||
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue
|
||||
let searchStickersConfiguration = SearchStickersConfiguration.with(appConfiguration: appConfiguration)
|
||||
|
||||
if let currentCached = cached, currentTime > currentCached.timestamp + searchStickersConfiguration.cacheTimeout {
|
||||
cached = nil
|
||||
}
|
||||
|
||||
return (result, cached)
|
||||
} |> mapToSignal { localItems, cached -> Signal<[FoundStickerItem], NoError> in
|
||||
@ -199,7 +227,8 @@ public func searchStickers(account: Account, query: String, scope: SearchSticker
|
||||
result.append(contentsOf: animatedItems)
|
||||
result.append(contentsOf: items)
|
||||
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: CachedStickerQueryResult(items: files, hash: hash), collectionSpec: collectionSpec)
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime), collectionSpec: collectionSpec)
|
||||
|
||||
return result
|
||||
case .stickersNotModified:
|
||||
|
@ -6,6 +6,7 @@ import SyncCore
|
||||
|
||||
public enum ServerProvidedSuggestion: String {
|
||||
case autoarchivePopular = "AUTOARCHIVE_POPULAR"
|
||||
case newcomerTicks = "NEWCOMER_TICKS"
|
||||
}
|
||||
|
||||
public func getServerProvidedSuggestions(postbox: Postbox) -> Signal<[ServerProvidedSuggestion], NoError> {
|
||||
@ -22,12 +23,7 @@ public func getServerProvidedSuggestions(postbox: Postbox) -> Signal<[ServerProv
|
||||
return []
|
||||
}
|
||||
return list.compactMap { item -> ServerProvidedSuggestion? in
|
||||
switch item {
|
||||
case "AUTOARCHIVE_POPULAR":
|
||||
return .autoarchivePopular
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return ServerProvidedSuggestion(rawValue: item)
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
@ -205,10 +205,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
|
||||
|
||||
let peerStatusSettings = PeerStatusSettings(apiSettings: userFull.settings)
|
||||
|
||||
var hasScheduledMessages = false
|
||||
if (userFull.flags & 1 << 12) != 0 {
|
||||
hasScheduledMessages = true
|
||||
}
|
||||
let hasScheduledMessages = (userFull.flags & 1 << 12) != 0
|
||||
|
||||
return previous.withUpdatedAbout(userFull.about).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFull.commonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages)
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -305,6 +305,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
private var applicationInForegroundDisposable: Disposable?
|
||||
private var applicationInFocusDisposable: Disposable?
|
||||
|
||||
private let checksTooltipDisposable = MetaDisposable()
|
||||
private var shouldDisplayChecksTooltip = false
|
||||
|
||||
private var checkedPeerChatServiceActions = false
|
||||
|
||||
private var willAppear = false
|
||||
@ -3424,6 +3427,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.peekTimerDisposable.dispose()
|
||||
self.hasActiveGroupCallDisposable?.dispose()
|
||||
self.createVoiceChatDisposable.dispose()
|
||||
self.checksTooltipDisposable.dispose()
|
||||
}
|
||||
|
||||
public func updatePresentationMode(_ mode: ChatControllerPresentationMode) {
|
||||
@ -4761,7 +4765,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
|
||||
let editingMessage = strongSelf.editingMessage
|
||||
let text = trimChatInputText(convertMarkdownToAttributes(editMessage.inputState.inputText))
|
||||
let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text))
|
||||
var entitiesAttribute: TextEntitiesMessageAttribute?
|
||||
@ -6236,7 +6239,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.openScheduledMessages()
|
||||
}
|
||||
|
||||
// strongSelf.displayChecksTooltip()
|
||||
if strongSelf.shouldDisplayChecksTooltip {
|
||||
strongSelf.displayChecksTooltip()
|
||||
strongSelf.shouldDisplayChecksTooltip = false
|
||||
strongSelf.checksTooltipDisposable.set(dismissServerProvidedSuggestion(account: strongSelf.context.account, suggestion: .newcomerTicks).start())
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
@ -6482,7 +6489,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return false
|
||||
}
|
||||
|
||||
if !strongSelf.context.sharedContext.currentMediaInputSettings.with { $0.enableRaiseToSpeak } {
|
||||
if !strongSelf.context.sharedContext.currentMediaInputSettings.with({ $0.enableRaiseToSpeak }) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -6707,6 +6714,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
}
|
||||
|
||||
self.checksTooltipDisposable.set((getServerProvidedSuggestions(postbox: self.context.account.postbox)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] values in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !values.contains(.newcomerTicks) {
|
||||
return
|
||||
}
|
||||
strongSelf.shouldDisplayChecksTooltip = true
|
||||
}))
|
||||
|
||||
if self.scheduledActivateInput {
|
||||
self.scheduledActivateInput = false
|
||||
|
||||
@ -7481,7 +7499,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller] result in
|
||||
controller?.dismiss()
|
||||
|
||||
guard let strongSelf = self, case let .result(stats) = result, var categories = stats.media[peer.id] else {
|
||||
guard let strongSelf = self, case let .result(stats) = result, let categories = stats.media[peer.id] else {
|
||||
return
|
||||
}
|
||||
let presentationData = strongSelf.presentationData
|
||||
@ -7682,16 +7700,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
private func editMessageMediaWithMessages(_ messages: [EnqueueMessage]) {
|
||||
if let message = messages.first, case let .message(desc) = message, let mediaReference = desc.mediaReference {
|
||||
if let message = messages.first, case let .message(text, _, maybeMediaReference, _, _) = message, let mediaReference = maybeMediaReference {
|
||||
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
|
||||
var state = state
|
||||
if let editMessageState = state.editMessageState, case let .media(options) = editMessageState.content, !options.isEmpty {
|
||||
state = state.updatedEditMessageState(ChatEditInterfaceMessageState(content: editMessageState.content, mediaReference: mediaReference))
|
||||
}
|
||||
if !desc.text.isEmpty {
|
||||
if !text.isEmpty {
|
||||
state = state.updatedInterfaceState { state in
|
||||
if let editMessage = state.editMessage {
|
||||
return state.withUpdatedEditMessage(editMessage.withUpdatedInputState(ChatTextInputState(inputText: NSAttributedString(string: desc.text))))
|
||||
return state.withUpdatedEditMessage(editMessage.withUpdatedInputState(ChatTextInputState(inputText: NSAttributedString(string: text))))
|
||||
}
|
||||
return state
|
||||
}
|
||||
@ -9338,7 +9356,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let complete = results.completed
|
||||
var navigateIndex: MessageIndex?
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { current in
|
||||
if let data = current.search {
|
||||
@ -10111,8 +10128,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
case let .withBotStartPayload(botStart):
|
||||
self.effectiveNavigationController?.pushViewController(ChatControllerImpl(context: self.context, chatLocation: .peer(peerId), botStart: botStart))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -10532,7 +10547,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
private func openUrl(_ url: String, concealed: Bool, message: Message? = nil) {
|
||||
self.commitPurposefulAction()
|
||||
|
||||
self.presentVoiceMessageDiscardAlert(action: {
|
||||
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
||||
if self.context.sharedContext.immediateExperimentalUISettings.playlistPlayback {
|
||||
if url.hasSuffix(".m3u8") {
|
||||
let navigationController = self.navigationController as? NavigationController
|
||||
|
@ -159,6 +159,7 @@ final class PeerInfoScreenData {
|
||||
let members: PeerInfoMembersData?
|
||||
let encryptionKeyFingerprint: SecretChatKeyFingerprint?
|
||||
let globalSettings: TelegramGlobalSettings?
|
||||
let invitations: PeerExportedInvitationsState?
|
||||
|
||||
init(
|
||||
peer: Peer?,
|
||||
@ -172,7 +173,8 @@ final class PeerInfoScreenData {
|
||||
linkedDiscussionPeer: Peer?,
|
||||
members: PeerInfoMembersData?,
|
||||
encryptionKeyFingerprint: SecretChatKeyFingerprint?,
|
||||
globalSettings: TelegramGlobalSettings?
|
||||
globalSettings: TelegramGlobalSettings?,
|
||||
invitations: PeerExportedInvitationsState?
|
||||
) {
|
||||
self.peer = peer
|
||||
self.cachedData = cachedData
|
||||
@ -186,6 +188,7 @@ final class PeerInfoScreenData {
|
||||
self.members = members
|
||||
self.encryptionKeyFingerprint = encryptionKeyFingerprint
|
||||
self.globalSettings = globalSettings
|
||||
self.invitations = invitations
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,7 +445,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: PeerId, account
|
||||
linkedDiscussionPeer: nil,
|
||||
members: nil,
|
||||
encryptionKeyFingerprint: nil,
|
||||
globalSettings: globalSettings
|
||||
globalSettings: globalSettings,
|
||||
invitations: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -464,7 +468,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
linkedDiscussionPeer: nil,
|
||||
members: nil,
|
||||
encryptionKeyFingerprint: nil,
|
||||
globalSettings: nil
|
||||
globalSettings: nil,
|
||||
invitations: nil
|
||||
))
|
||||
case let .user(userPeerId, secretChatId, kind):
|
||||
let groupsInCommon: GroupsInCommonContext?
|
||||
@ -603,7 +608,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
linkedDiscussionPeer: nil,
|
||||
members: nil,
|
||||
encryptionKeyFingerprint: encryptionKeyFingerprint,
|
||||
globalSettings: nil
|
||||
globalSettings: nil,
|
||||
invitations: nil
|
||||
)
|
||||
}
|
||||
case .channel:
|
||||
@ -623,13 +629,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
||||
var combinedKeys: [PostboxViewKey] = []
|
||||
combinedKeys.append(globalNotificationsKey)
|
||||
|
||||
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
||||
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
||||
|
||||
return combineLatest(
|
||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
||||
context.account.postbox.combinedView(keys: combinedKeys),
|
||||
status
|
||||
status,
|
||||
invitationsContextPromise.get(),
|
||||
invitationsStatePromise.get()
|
||||
)
|
||||
|> map { peerView, availablePanes, combinedView, status -> PeerInfoScreenData in
|
||||
|> map { peerView, availablePanes, combinedView, status, currentInvitationsContext, invitations -> PeerInfoScreenData in
|
||||
var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings
|
||||
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
||||
if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings {
|
||||
@ -642,6 +654,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
discussionPeer = peer
|
||||
}
|
||||
|
||||
if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)), currentInvitationsContext == nil {
|
||||
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
|
||||
invitationsContextPromise.set(.single(invitationsContext))
|
||||
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
|
||||
}
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[peerId],
|
||||
cachedData: peerView.cachedData,
|
||||
@ -654,7 +672,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
linkedDiscussionPeer: discussionPeer,
|
||||
members: nil,
|
||||
encryptionKeyFingerprint: nil,
|
||||
globalSettings: nil
|
||||
globalSettings: nil,
|
||||
invitations: invitations
|
||||
)
|
||||
}
|
||||
case let .group(groupId):
|
||||
@ -751,14 +770,20 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
||||
var combinedKeys: [PostboxViewKey] = []
|
||||
combinedKeys.append(globalNotificationsKey)
|
||||
|
||||
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
||||
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
||||
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
context.account.viewTracker.peerView(groupId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: groupId),
|
||||
context.account.postbox.combinedView(keys: combinedKeys),
|
||||
status,
|
||||
membersData
|
||||
membersData,
|
||||
invitationsContextPromise.get(),
|
||||
invitationsStatePromise.get()
|
||||
)
|
||||
|> map { peerView, availablePanes, combinedView, status, membersData -> PeerInfoScreenData in
|
||||
|> map { peerView, availablePanes, combinedView, status, membersData, currentInvitationsContext, invitations -> PeerInfoScreenData in
|
||||
var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings
|
||||
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
||||
if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings {
|
||||
@ -780,6 +805,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
}
|
||||
}
|
||||
|
||||
if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role, currentInvitationsContext == nil {
|
||||
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
|
||||
invitationsContextPromise.set(.single(invitationsContext))
|
||||
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
|
||||
}
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[groupId],
|
||||
cachedData: peerView.cachedData,
|
||||
@ -792,7 +823,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
linkedDiscussionPeer: discussionPeer,
|
||||
members: membersData,
|
||||
encryptionKeyFingerprint: nil,
|
||||
globalSettings: nil
|
||||
globalSettings: nil,
|
||||
invitations: invitations
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1255,7 +1255,14 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
interaction.editingOpenPublicLinkSetup()
|
||||
}))
|
||||
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(""), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
invitesText = "\(count)"
|
||||
} else {
|
||||
invitesText = ""
|
||||
}
|
||||
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
||||
interaction.editingOpenInviteLinksSetup()
|
||||
}))
|
||||
|
||||
@ -1330,7 +1337,14 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
}
|
||||
}
|
||||
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(""), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
invitesText = "\(count)"
|
||||
} else {
|
||||
invitesText = ""
|
||||
}
|
||||
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
|
||||
interaction.editingOpenInviteLinksSetup()
|
||||
}))
|
||||
|
||||
@ -4544,6 +4558,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.view.endEditing(true)
|
||||
let mode: ChannelVisibilityControllerMode
|
||||
if groupPeer.addressName != nil {
|
||||
let visibilityController = channelVisibilityController(context: strongSelf.context, peerId: groupPeer.id, mode: .generic, upgradedToSupergroup: { _, f in f() }, onDismissRemoveController: contactsController)
|
||||
|
@ -91,8 +91,8 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager {
|
||||
}
|
||||
|
||||
let resolvedWallpaper: Signal<TelegramWallpaper?, NoError>
|
||||
if case let .file(file) = presentationTheme.chat.defaultWallpaper, file.id == 0 {
|
||||
resolvedWallpaper = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
||||
if case let .file(id, _, _, _, _, _, slug, _, settings) = presentationTheme.chat.defaultWallpaper, id == 0 {
|
||||
resolvedWallpaper = cachedWallpaper(account: account, slug: slug, settings: settings)
|
||||
|> map { wallpaper in
|
||||
return wallpaper?.wallpaper
|
||||
}
|
||||
@ -102,15 +102,15 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager {
|
||||
|
||||
return resolvedWallpaper
|
||||
|> mapToSignal { wallpaper -> Signal<(PresentationThemeReference, PresentationTheme?), NoError> in
|
||||
if let wallpaper = wallpaper, case let .file(file) = wallpaper {
|
||||
if let wallpaper = wallpaper, case let .file(_, _, _, _, _, _, slug, file, _) = wallpaper {
|
||||
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 100, height: 100), resource: file.file.resource, progressiveSizes: []), reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)))
|
||||
return wallpaperDatas(account: account, accountManager: accountManager, fileReference: .standalone(media: file.file), representations: convertedRepresentations, alwaysShowThumbnailFirst: false, thumbnail: false, onlyFullSize: true, autoFetchFullSize: true, synchronousLoad: false)
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 100, height: 100), resource: file.resource, progressiveSizes: []), reference: .wallpaper(wallpaper: .slug(slug), resource: file.resource)))
|
||||
return wallpaperDatas(account: account, accountManager: accountManager, fileReference: .standalone(media: file), representations: convertedRepresentations, alwaysShowThumbnailFirst: false, thumbnail: false, onlyFullSize: true, autoFetchFullSize: true, synchronousLoad: false)
|
||||
|> mapToSignal { _, fullSizeData, complete -> Signal<(PresentationThemeReference, PresentationTheme?), NoError> in
|
||||
guard complete, let fullSizeData = fullSizeData else {
|
||||
return .complete()
|
||||
}
|
||||
accountManager.mediaBox.storeResourceData(file.file.resource.id, data: fullSizeData, synchronous: true)
|
||||
accountManager.mediaBox.storeResourceData(file.resource.id, data: fullSizeData, synchronous: true)
|
||||
return .single((.cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: wallpaper, creatorAccountId: theme.isCreator ? account.id : nil)), presentationTheme))
|
||||
}
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user