mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
# Conflicts: # submodules/TelegramCore/Sources/InvitationLinks.swift
This commit is contained in:
commit
56ebab264e
@ -5883,8 +5883,11 @@ Sorry for the inconvenience.";
|
|||||||
"InviteLink.InviteLink" = "Invite Link";
|
"InviteLink.InviteLink" = "Invite Link";
|
||||||
"InviteLink.CreatedBy" = "Link Created By";
|
"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.Text" = "This will delete all revoked links.";
|
||||||
"InviteLink.DeleteAllRevokedLinksAlert.Action" = "Delete";
|
"InviteLink.DeleteAllRevokedLinksAlert.Action" = "Delete All";
|
||||||
|
|
||||||
"InviteLink.ExpiresIn" = "expires in %@";
|
"InviteLink.ExpiresIn" = "expires in %@";
|
||||||
|
|
||||||
@ -5892,3 +5895,5 @@ Sorry for the inconvenience.";
|
|||||||
"Conversation.ChecksTooltip.Read" = "Read";
|
"Conversation.ChecksTooltip.Read" = "Read";
|
||||||
|
|
||||||
"DialogList.MultipleTypingPair" = "%@ and %@ are typing";
|
"DialogList.MultipleTypingPair" = "%@ and %@ are typing";
|
||||||
|
|
||||||
|
"Common.Save" = "Save";
|
||||||
|
@ -1212,8 +1212,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
strongSelf.forEachController({ controller in
|
strongSelf.forEachController({ controller in
|
||||||
if let controller = controller as? UndoOverlayController {
|
if let controller = controller as? UndoOverlayController {
|
||||||
switch controller.content {
|
switch controller.content {
|
||||||
case let .archivedChat(archivedChat):
|
case let .archivedChat(peerId, _, _, _):
|
||||||
if peerIds.contains(PeerId(archivedChat.peerId)) {
|
if peerIds.contains(PeerId(peerId)) {
|
||||||
controller.dismiss()
|
controller.dismiss()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -158,7 +158,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||||||
return ChatListSearchItem(theme: theme, placeholder: strings.Contacts_SearchLabel, activate: {
|
return ChatListSearchItem(theme: theme, placeholder: strings.Contacts_SearchLabel, activate: {
|
||||||
interaction.activateSearch()
|
interaction.activateSearch()
|
||||||
})
|
})
|
||||||
case let .sort(theme, strings, sortOrder):
|
case let .sort(_, strings, sortOrder):
|
||||||
var text = strings.Contacts_SortedByName
|
var text = strings.Contacts_SortedByName
|
||||||
if case .presence = sortOrder {
|
if case .presence = sortOrder {
|
||||||
text = strings.Contacts_SortedByPresence
|
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: {
|
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: text, icon: .inline(dropDownIcon, .right), highlight: .alpha, header: nil, action: {
|
||||||
interaction.openSortMenu()
|
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 : {
|
return InfoListItem(presentationData: ItemListPresentationData(presentationData), title: title, text: .plain(text), style: .plain, closeAction: suppressed ? nil : {
|
||||||
interaction.suppressWarning()
|
interaction.suppressWarning()
|
||||||
})
|
})
|
||||||
case let .permissionEnable(theme, text):
|
case let .permissionEnable(_, text):
|
||||||
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: text, icon: .none, header: nil, action: {
|
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: text, icon: .none, header: nil, action: {
|
||||||
interaction.authorize()
|
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)
|
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
|
var status: ContactsPeerItemStatus
|
||||||
let itemPeer: ContactsPeerItemPeer
|
let itemPeer: ContactsPeerItemPeer
|
||||||
var isContextActionEnabled = false
|
var isContextActionEnabled = false
|
||||||
@ -928,9 +928,9 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
|> mapToSignal { presentation in
|
|> mapToSignal { presentation in
|
||||||
var generateSections = false
|
var generateSections = false
|
||||||
var includeChatList = false
|
var includeChatList = false
|
||||||
if case let .natural(natural) = presentation {
|
if case let .natural(_, includeChatListValue) = presentation {
|
||||||
generateSections = true
|
generateSections = true
|
||||||
includeChatList = natural.includeChatList
|
includeChatList = includeChatListValue
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .search(query, searchChatList, searchDeviceContacts, searchGroups, searchChannels, globalSearch) = presentation {
|
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.centralItemNavigationStyle.set(centralItemNode.navigationStyle())
|
||||||
self.centralItemFooterContentNode.set(centralItemNode.footerContent())
|
self.centralItemFooterContentNode.set(centralItemNode.footerContent())
|
||||||
|
|
||||||
if let (media, _) = mediaForMessage(message: message) {
|
if let _ = mediaForMessage(message: message) {
|
||||||
centralItemNode.activateAsInitial()
|
centralItemNode.activateAsInitial()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func isValidNumberOfUsers(_ number: String) -> Bool {
|
|||||||
private enum InviteLinksEditEntry: ItemListNodeEntry {
|
private enum InviteLinksEditEntry: ItemListNodeEntry {
|
||||||
case timeHeader(PresentationTheme, String)
|
case timeHeader(PresentationTheme, String)
|
||||||
case timePicker(PresentationTheme, InviteLinkTimeLimit)
|
case timePicker(PresentationTheme, InviteLinkTimeLimit)
|
||||||
case timeExpiryDate(PresentationTheme, Int32?)
|
case timeExpiryDate(PresentationTheme, Int32?, Bool)
|
||||||
case timeCustomPicker(PresentationTheme, Int32?)
|
case timeCustomPicker(PresentationTheme, Int32?)
|
||||||
case timeInfo(PresentationTheme, String)
|
case timeInfo(PresentationTheme, String)
|
||||||
|
|
||||||
@ -111,8 +111,8 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .timeExpiryDate(lhsTheme, lhsDate):
|
case let .timeExpiryDate(lhsTheme, lhsDate, lhsActive):
|
||||||
if case let .timeExpiryDate(rhsTheme, rhsDate) = rhs, lhsTheme === rhsTheme, lhsDate == rhsDate {
|
if case let .timeExpiryDate(rhsTheme, rhsDate, rhsActive) = rhs, lhsTheme === rhsTheme, lhsDate == rhsDate, lhsActive == rhsActive {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -182,14 +182,14 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
|||||||
return updatedState
|
return updatedState
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
case let .timeExpiryDate(_, value):
|
case let .timeExpiryDate(theme, value, active):
|
||||||
let text: String
|
let text: String
|
||||||
if let value = value {
|
if let value = value {
|
||||||
text = stringForFullDate(timestamp: value, strings: presentationData.strings, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .regular, dateFormat: .monthFirst, dateSeparator: ".", decimalSeparator: ".", groupingSeparator: "."))
|
text = stringForFullDate(timestamp: value, strings: presentationData.strings, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .regular, dateFormat: .monthFirst, dateSeparator: ".", decimalSeparator: ".", groupingSeparator: "."))
|
||||||
} else {
|
} else {
|
||||||
text = presentationData.strings.InviteLink_Create_TimeLimitExpiryDateNever
|
text = presentationData.strings.InviteLink_Create_TimeLimitExpiryDateNever
|
||||||
}
|
}
|
||||||
return ItemListDisclosureItem(presentationData: presentationData, title: presentationData.strings.InviteLink_Create_TimeLimitExpiryDate, label: text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: {
|
return ItemListDisclosureItem(presentationData: presentationData, title: presentationData.strings.InviteLink_Create_TimeLimitExpiryDate, label: text, labelStyle: active ? .coloredText(theme.list.itemAccentColor) : .text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: {
|
||||||
arguments.dismissInput()
|
arguments.dismissInput()
|
||||||
arguments.updateState { state in
|
arguments.updateState { state in
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
@ -223,7 +223,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
|
|||||||
})
|
})
|
||||||
case let .usageCustomPicker(theme, value, focused):
|
case let .usageCustomPicker(theme, value, focused):
|
||||||
let text = value.flatMap { String($0) } ?? (focused ? "" : presentationData.strings.InviteLink_Create_UsersLimitNumberOfUsersUnlimited)
|
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 {
|
guard !updatedText.isEmpty else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -276,7 +276,7 @@ private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state:
|
|||||||
} else if let value = state.time.value {
|
} else if let value = state.time.value {
|
||||||
time = currentTime + value
|
time = currentTime + value
|
||||||
}
|
}
|
||||||
entries.append(.timeExpiryDate(presentationData.theme, time))
|
entries.append(.timeExpiryDate(presentationData.theme, time, state.pickingTimeLimit))
|
||||||
if state.pickingTimeLimit {
|
if state.pickingTimeLimit {
|
||||||
entries.append(.timeCustomPicker(presentationData.theme, time ?? currentTime))
|
entries.append(.timeCustomPicker(presentationData.theme, time ?? currentTime))
|
||||||
}
|
}
|
||||||
@ -300,9 +300,10 @@ private struct InviteLinkEditControllerState: Equatable {
|
|||||||
var time: InviteLinkTimeLimit
|
var time: InviteLinkTimeLimit
|
||||||
var pickingTimeLimit = false
|
var pickingTimeLimit = false
|
||||||
var pickingUsageLimit = 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)?
|
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
|
|
||||||
@ -327,7 +328,7 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
|||||||
|
|
||||||
initialState = InviteLinkEditControllerState(usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, pickingTimeLimit: false, pickingUsageLimit: false)
|
initialState = InviteLinkEditControllerState(usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, pickingTimeLimit: false, pickingUsageLimit: false)
|
||||||
} else {
|
} else {
|
||||||
initialState = InviteLinkEditControllerState(usage: .medium, time: .week, pickingTimeLimit: false, pickingUsageLimit: false)
|
initialState = InviteLinkEditControllerState(usage: .unlimited, time: .unlimited, pickingTimeLimit: false, pickingUsageLimit: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||||
@ -359,8 +360,17 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
|||||||
dismissAction()
|
dismissAction()
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
|
|
||||||
let _ = (revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
let _ = (revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link)
|
||||||
completion?()
|
|> 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)
|
presentControllerImpl?(controller, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let previousState = Atomic<InviteLinkEditControllerState?>(value: nil)
|
||||||
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get())
|
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get())
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
@ -376,7 +387,13 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
|||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
})
|
})
|
||||||
|
|
||||||
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), 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?
|
let expireDate: Int32?
|
||||||
if case let .custom(value) = state.time {
|
if case let .custom(value) = state.time {
|
||||||
expireDate = value
|
expireDate = value
|
||||||
@ -390,21 +407,43 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
|
|||||||
let usageLimit = state.usage.value
|
let usageLimit = state.usage.value
|
||||||
if invite == nil {
|
if invite == nil {
|
||||||
let _ = (createPeerExportedInvitation(account: context.account, peerId: peerId, expireDate: expireDate, usageLimit: usageLimit)
|
let _ = (createPeerExportedInvitation(account: context.account, peerId: peerId, expireDate: expireDate, usageLimit: usageLimit)
|
||||||
|> deliverOnMainQueue).start(next: { result in
|
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|
||||||
completion?()
|
|> deliverOnMainQueue).start(next: { invite in
|
||||||
|
completion?(invite)
|
||||||
dismissImpl?()
|
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 {
|
} else if let invite = invite {
|
||||||
let _ = (editPeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link, expireDate: expireDate, usageLimit: usageLimit)
|
let _ = (editPeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link, expireDate: expireDate, usageLimit: usageLimit)
|
||||||
|> deliverOnMainQueue).start(next: { result in
|
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|
||||||
completion?()
|
|> deliverOnMainQueue).start(next: { invite in
|
||||||
|
completion?(invite)
|
||||||
dismissImpl?()
|
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 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))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,9 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
|||||||
case let .header(theme, title, text):
|
case let .header(theme, title, text):
|
||||||
return InviteLinkInviteHeaderItem(theme: theme, title: title, text: text)
|
return InviteLinkInviteHeaderItem(theme: theme, title: title, text: text)
|
||||||
case let .mainLink(_, invite):
|
case let .mainLink(_, invite):
|
||||||
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: 0, style: .plain, shareAction: {
|
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: 0, style: .plain, copyAction: {
|
||||||
|
interaction.copyLink(invite)
|
||||||
|
}, shareAction: {
|
||||||
interaction.shareLink(invite)
|
interaction.shareLink(invite)
|
||||||
}, contextAction: { node in
|
}, contextAction: { node in
|
||||||
interaction.mainLinkContextAction(invite, node, nil)
|
interaction.mainLinkContextAction(invite, node, nil)
|
||||||
@ -371,7 +373,7 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||||
dismissAction()
|
dismissAction()
|
||||||
|
|
||||||
self?.revokeDisposable.set((ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId, revokeExisted: true) |> deliverOnMainQueue).start(completed: {
|
self?.revokeDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||||
|
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
@ -585,11 +587,6 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
if result === self.headerNode.view {
|
if result === self.headerNode.view {
|
||||||
return self.view
|
return self.view
|
||||||
}
|
}
|
||||||
|
|
||||||
if result === self.headerNode.view {
|
|
||||||
return self.view
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.bounds.contains(point) {
|
if !self.bounds.contains(point) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -615,8 +612,6 @@ public final class InviteLinkInviteController: ViewController {
|
|||||||
case .changed:
|
case .changed:
|
||||||
var translation = recognizer.translation(in: self.contentNode.view).y
|
var translation = recognizer.translation(in: self.contentNode.view).y
|
||||||
if let currentPanOffset = self.panGestureArguments {
|
if let currentPanOffset = self.panGestureArguments {
|
||||||
|
|
||||||
|
|
||||||
if case let .known(value) = contentOffset, value <= 0.5 {
|
if case let .known(value) = contentOffset, value <= 0.5 {
|
||||||
} else {
|
} else {
|
||||||
translation = currentPanOffset
|
translation = currentPanOffset
|
||||||
|
@ -22,18 +22,20 @@ import ShareController
|
|||||||
|
|
||||||
private final class InviteLinkListControllerArguments {
|
private final class InviteLinkListControllerArguments {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let shareMainLink: (ExportedInvitation?) -> Void
|
let shareMainLink: (ExportedInvitation) -> Void
|
||||||
let openMainLink: (ExportedInvitation?) -> Void
|
let openMainLink: (ExportedInvitation) -> Void
|
||||||
|
let copyLink: (ExportedInvitation) -> Void
|
||||||
let mainLinkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
|
let mainLinkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
|
||||||
let createLink: () -> Void
|
let createLink: () -> Void
|
||||||
let openLink: (ExportedInvitation) -> Void
|
let openLink: (ExportedInvitation) -> Void
|
||||||
let linkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
|
let linkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
|
||||||
let deleteAllRevokedLinks: () -> Void
|
let deleteAllRevokedLinks: () -> Void
|
||||||
|
|
||||||
init(context: AccountContext, shareMainLink: @escaping (ExportedInvitation?) -> Void, openMainLink: @escaping (ExportedInvitation?) -> Void, mainLinkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, createLink: @escaping () -> Void, openLink: @escaping (ExportedInvitation?) -> Void, linkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, deleteAllRevokedLinks: @escaping () -> Void) {
|
init(context: AccountContext, shareMainLink: @escaping (ExportedInvitation) -> Void, openMainLink: @escaping (ExportedInvitation) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, mainLinkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, createLink: @escaping () -> Void, openLink: @escaping (ExportedInvitation?) -> Void, linkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, deleteAllRevokedLinks: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.shareMainLink = shareMainLink
|
self.shareMainLink = shareMainLink
|
||||||
self.openMainLink = openMainLink
|
self.openMainLink = openMainLink
|
||||||
|
self.copyLink = copyLink
|
||||||
self.mainLinkContextAction = mainLinkContextAction
|
self.mainLinkContextAction = mainLinkContextAction
|
||||||
self.createLink = createLink
|
self.createLink = createLink
|
||||||
self.openLink = openLink
|
self.openLink = openLink
|
||||||
@ -178,8 +180,14 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
|||||||
case let .mainLinkHeader(_, text):
|
case let .mainLinkHeader(_, text):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||||
case let .mainLink(_, invite, peers):
|
case let .mainLink(_, invite, peers):
|
||||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: peers, displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, shareAction: {
|
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: peers, displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||||
arguments.shareMainLink(invite)
|
if let invite = invite {
|
||||||
|
arguments.copyLink(invite)
|
||||||
|
}
|
||||||
|
}, shareAction: {
|
||||||
|
if let invite = invite {
|
||||||
|
arguments.shareMainLink(invite)
|
||||||
|
}
|
||||||
}, contextAction: { node in
|
}, contextAction: { node in
|
||||||
arguments.mainLinkContextAction(invite, node, nil)
|
arguments.mainLinkContextAction(invite, node, nil)
|
||||||
}, viewAction: {
|
}, viewAction: {
|
||||||
@ -299,33 +307,21 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
let deleteAllRevokedLinksDisposable = MetaDisposable()
|
let deleteAllRevokedLinksDisposable = MetaDisposable()
|
||||||
actionsDisposable.add(deleteAllRevokedLinksDisposable)
|
actionsDisposable.add(deleteAllRevokedLinksDisposable)
|
||||||
|
|
||||||
actionsDisposable.add((context.account.viewTracker.peerView(peerId) |> filter { $0.cachedData != nil } |> take(1) |> mapToSignal { view -> Signal<String?, NoError> in
|
|
||||||
return ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId)
|
|
||||||
|> mapToSignal { _ -> Signal<String?, NoError> in
|
|
||||||
return .complete()
|
|
||||||
}
|
|
||||||
}).start())
|
|
||||||
|
|
||||||
var getControllerImpl: (() -> ViewController?)?
|
var getControllerImpl: (() -> ViewController?)?
|
||||||
|
|
||||||
let invitesPromise = Promise<ExportedInvitations?>()
|
let invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: false)
|
||||||
invitesPromise.set(.single(nil)
|
let revokedInvitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: true, forceUpdate: true)
|
||||||
|> 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 arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in
|
let arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in
|
||||||
if let invite = invite {
|
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||||
let shareController = ShareController(context: context, subject: .url(invite.link))
|
presentControllerImpl?(shareController, nil)
|
||||||
presentControllerImpl?(shareController, nil)
|
|
||||||
}
|
|
||||||
}, openMainLink: { invite in
|
}, openMainLink: { invite in
|
||||||
if let invite = invite {
|
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, invitationsContext: nil, importersContext: nil)
|
||||||
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, importersContext: nil)
|
pushControllerImpl?(controller)
|
||||||
pushControllerImpl?(controller)
|
}, copyLink: { invite in
|
||||||
}
|
UIPasteboard.general.string = invite.link
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
|
||||||
}, mainLinkContextAction: { invite, node, gesture in
|
}, mainLinkContextAction: { invite, node, gesture in
|
||||||
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
|
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
|
||||||
return
|
return
|
||||||
@ -383,13 +379,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if revoke {
|
if revoke {
|
||||||
revokeLinkDisposable.set((ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId, revokeExisted: true) |> deliverOnMainQueue).start(completed: {
|
revokeLinkDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
updatedState.revokingPrivateLink = false
|
updatedState.revokingPrivateLink = false
|
||||||
return updatedState
|
return updatedState
|
||||||
}
|
}
|
||||||
invitesPromise.set(peerExportedInvitations(account: context.account, peerId: peerId, revoked: false))
|
|
||||||
|
invitesContext.reload()
|
||||||
|
revokedInvitesContext.reload()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -402,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)
|
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||||
presentInGlobalOverlayImpl?(contextController)
|
presentInGlobalOverlayImpl?(contextController)
|
||||||
}, createLink: {
|
}, createLink: {
|
||||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: nil, completion: {
|
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: nil, completion: { invite in
|
||||||
invitesPromise.set(peerExportedInvitations(account: context.account, peerId: peerId, revoked: false))
|
if let invite = invite {
|
||||||
|
invitesContext.add(invite)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
}, openLink: { invite in
|
}, openLink: { invite in
|
||||||
if let invite = invite {
|
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)
|
pushControllerImpl?(controller)
|
||||||
}
|
}
|
||||||
}, linkContextAction: { invite, node, gesture in
|
}, linkContextAction: { invite, node, gesture in
|
||||||
@ -445,8 +445,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: invite, completion: {
|
let controller = inviteLinkEditController(context: context, peerId: peerId, invite: invite, completion: { invite in
|
||||||
invitesPromise.set(peerExportedInvitations(account: context.account, peerId: peerId, revoked: false))
|
if let invite = invite {
|
||||||
|
if invite.isRevoked {
|
||||||
|
invitesContext.remove(invite)
|
||||||
|
revokedInvitesContext.add(invite)
|
||||||
|
} else {
|
||||||
|
invitesContext.update(invite)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
@ -465,13 +472,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
}
|
}
|
||||||
controller.setItemGroups([
|
controller.setItemGroups([
|
||||||
ActionSheetItemGroup(items: [
|
ActionSheetItemGroup(items: [
|
||||||
ActionSheetTextItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeAlert_Text),
|
ActionSheetTextItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Text),
|
||||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
ActionSheetButtonItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Action, color: .destructive, action: {
|
||||||
dismissAction()
|
dismissAction()
|
||||||
|
|
||||||
revokeLinkDisposable.set((deletePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
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() })])
|
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||||
@ -497,6 +506,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
revokeLinkDisposable.set((revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
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() })])
|
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||||
@ -520,8 +532,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
dismissAction()
|
dismissAction()
|
||||||
|
|
||||||
deleteAllRevokedLinksDisposable.set((deleteAllRevokedPeerExportedInvitations(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
deleteAllRevokedLinksDisposable.set((deleteAllRevokedPeerExportedInvitations(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||||
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
revokedInvitesContext.clear()
|
||||||
})
|
})
|
||||||
]),
|
]),
|
||||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||||
@ -551,11 +564,11 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|
|||||||
importersState.set(context.state |> map(Optional.init))
|
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
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, view, importersContext, importers, invites, revokedInvites -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> 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 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))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|
@ -342,7 +342,6 @@ public final class InviteLinkQRCodeController: ViewController {
|
|||||||
self.containerLayout = (layout, navigationBarHeight)
|
self.containerLayout = (layout, navigationBarHeight)
|
||||||
|
|
||||||
var insets = layout.insets(options: [.statusBar, .input])
|
var insets = layout.insets(options: [.statusBar, .input])
|
||||||
let cleanInsets = layout.insets(options: [.statusBar])
|
|
||||||
insets.top = max(10.0, insets.top)
|
insets.top = max(10.0, insets.top)
|
||||||
|
|
||||||
let makeImageLayout = self.qrImageNode.asyncLayout()
|
let makeImageLayout = self.qrImageNode.asyncLayout()
|
||||||
|
@ -24,12 +24,14 @@ import DirectionalPanGesture
|
|||||||
class InviteLinkViewInteraction {
|
class InviteLinkViewInteraction {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let openPeer: (PeerId) -> Void
|
let openPeer: (PeerId) -> Void
|
||||||
|
let copyLink: (ExportedInvitation) -> Void
|
||||||
let shareLink: (ExportedInvitation) -> Void
|
let shareLink: (ExportedInvitation) -> Void
|
||||||
let contextAction: (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void
|
let contextAction: (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void
|
||||||
|
|
||||||
init(context: AccountContext, openPeer: @escaping (PeerId) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, contextAction: @escaping (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void) {
|
init(context: AccountContext, openPeer: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, contextAction: @escaping (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.openPeer = openPeer
|
self.openPeer = openPeer
|
||||||
|
self.copyLink = copyLink
|
||||||
self.shareLink = shareLink
|
self.shareLink = shareLink
|
||||||
self.contextAction = contextAction
|
self.contextAction = contextAction
|
||||||
}
|
}
|
||||||
@ -116,7 +118,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .importer(lhsIndex, lhsTheme, lhsDateTimeFormat, lhsPeer, lhsDate, lhsLoading):
|
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
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -169,7 +171,9 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
|||||||
case let .link(_, invite):
|
case let .link(_, invite):
|
||||||
let buttonColor = color(for: invite)
|
let buttonColor = color(for: invite)
|
||||||
let availability = invitationAvailability(invite)
|
let availability = invitationAvailability(invite)
|
||||||
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: !invite.isRevoked && !availability.isZero, displayImporters: false, buttonColor: buttonColor, sectionId: 0, style: .plain, shareAction: {
|
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: !invite.isRevoked && !availability.isZero, displayImporters: false, buttonColor: buttonColor, sectionId: 0, style: .plain, copyAction: {
|
||||||
|
interaction.copyLink(invite)
|
||||||
|
}, shareAction: {
|
||||||
interaction.shareLink(invite)
|
interaction.shareLink(invite)
|
||||||
}, contextAction: { node in
|
}, contextAction: { node in
|
||||||
interaction.contextAction(invite, node, nil)
|
interaction.contextAction(invite, node, nil)
|
||||||
@ -188,7 +192,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
|
|||||||
let dateString = stringForFullDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: dateTimeFormat)
|
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: {
|
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)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,14 +217,16 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
private let invite: ExportedInvitation
|
private let invite: ExportedInvitation
|
||||||
|
private let invitationsContext: PeerExportedInvitationsContext?
|
||||||
private let importersContext: PeerInvitationImportersContext?
|
private let importersContext: PeerInvitationImportersContext?
|
||||||
|
|
||||||
private var presentationDataDisposable: Disposable?
|
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.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.invite = invite
|
self.invite = invite
|
||||||
|
self.invitationsContext = invitationsContext
|
||||||
self.importersContext = importersContext
|
self.importersContext = importersContext
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: nil)
|
super.init(navigationBarPresentationData: nil)
|
||||||
@ -383,6 +389,10 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), keepStack: .always))
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), keepStack: .always))
|
||||||
}
|
}
|
||||||
|
}, copyLink: { [weak self] invite in
|
||||||
|
UIPasteboard.general.string = invite.link
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self?.controller?.present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), in: .window(.root))
|
||||||
}, shareLink: { [weak self] invite in
|
}, shareLink: { [weak self] invite in
|
||||||
let shareController = ShareController(context: context, subject: .url(invite.link))
|
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||||
self?.controller?.present(shareController, in: .window(.root))
|
self?.controller?.present(shareController, in: .window(.root))
|
||||||
@ -531,8 +541,17 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
let navigationController = self.controller?.navigationController as? NavigationController
|
let navigationController = self.controller?.navigationController as? NavigationController
|
||||||
self.controller?.dismiss()
|
self.controller?.dismiss()
|
||||||
|
|
||||||
|
let invitationsContext = self.controller?.invitationsContext
|
||||||
if let navigationController = navigationController {
|
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
|
controller.navigationPresentation = .modal
|
||||||
navigationController.pushViewController(controller)
|
navigationController.pushViewController(controller)
|
||||||
}
|
}
|
||||||
@ -655,11 +674,6 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
if result === self.headerNode.view {
|
if result === self.headerNode.view {
|
||||||
return self.view
|
return self.view
|
||||||
}
|
}
|
||||||
|
|
||||||
if result === self.headerNode.view {
|
|
||||||
return self.view
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.bounds.contains(point) {
|
if !self.bounds.contains(point) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
private let maskNode: ASImageNode
|
private let maskNode: ASImageNode
|
||||||
|
|
||||||
private let datePicker: UIDatePicker
|
private var datePicker: UIDatePicker?
|
||||||
|
|
||||||
private var item: ItemListDatePickerItem?
|
private var item: ItemListDatePickerItem?
|
||||||
|
|
||||||
@ -98,25 +98,31 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.bottomStripeNode = ASDisplayNode()
|
self.bottomStripeNode = ASDisplayNode()
|
||||||
self.bottomStripeNode.isLayerBacked = true
|
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)
|
super.init(layerBacked: false, dynamicBounce: false)
|
||||||
|
|
||||||
self.datePicker.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func didLoad() {
|
public override func didLoad() {
|
||||||
super.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() {
|
@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) {
|
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.backgroundNode.backgroundColor = itemBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.datePicker.date = item.date.flatMap { Date(timeIntervalSince1970: TimeInterval($0)) } ?? Date()
|
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?.frame = CGRect(origin: CGPoint(x: 16.0, y: 3.0), size: CGSize(width: contentSize.width - 32.0, height: contentSize.height))
|
||||||
|
|
||||||
switch item.style {
|
switch item.style {
|
||||||
case .plain:
|
case .plain:
|
||||||
|
@ -130,7 +130,6 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
|
|||||||
let itemSeparatorColor: UIColor
|
let itemSeparatorColor: UIColor
|
||||||
|
|
||||||
let leftInset = 16.0 + params.leftInset
|
let leftInset = 16.0 + params.leftInset
|
||||||
let rightInset = 16.0 + params.rightInset
|
|
||||||
|
|
||||||
var height: CGFloat
|
var height: CGFloat
|
||||||
let count = item.invites?.count ?? 0
|
let count = item.invites?.count ?? 0
|
||||||
|
@ -35,6 +35,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
|||||||
let buttonColor: UIColor?
|
let buttonColor: UIColor?
|
||||||
public let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
|
let copyAction: (() -> Void)?
|
||||||
let shareAction: (() -> Void)?
|
let shareAction: (() -> Void)?
|
||||||
let contextAction: ((ASDisplayNode) -> Void)?
|
let contextAction: ((ASDisplayNode) -> Void)?
|
||||||
let viewAction: (() -> Void)?
|
let viewAction: (() -> Void)?
|
||||||
@ -50,6 +51,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
|||||||
buttonColor: UIColor?,
|
buttonColor: UIColor?,
|
||||||
sectionId: ItemListSectionId,
|
sectionId: ItemListSectionId,
|
||||||
style: ItemListStyle,
|
style: ItemListStyle,
|
||||||
|
copyAction: (() -> Void)?,
|
||||||
shareAction: (() -> Void)?,
|
shareAction: (() -> Void)?,
|
||||||
contextAction: ((ASDisplayNode) -> Void)?,
|
contextAction: ((ASDisplayNode) -> Void)?,
|
||||||
viewAction: (() -> Void)?,
|
viewAction: (() -> Void)?,
|
||||||
@ -64,6 +66,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
|
|||||||
self.buttonColor = buttonColor
|
self.buttonColor = buttonColor
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
self.style = style
|
self.style = style
|
||||||
|
self.copyAction = copyAction
|
||||||
self.shareAction = shareAction
|
self.shareAction = shareAction
|
||||||
self.contextAction = contextAction
|
self.contextAction = contextAction
|
||||||
self.viewAction = viewAction
|
self.viewAction = viewAction
|
||||||
@ -114,6 +117,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
|||||||
|
|
||||||
private let fieldNode: ASImageNode
|
private let fieldNode: ASImageNode
|
||||||
private let addressNode: TextNode
|
private let addressNode: TextNode
|
||||||
|
private let fieldButtonNode: HighlightTrackingButtonNode
|
||||||
private let extractedContainerNode: ContextExtractedContentContainingNode
|
private let extractedContainerNode: ContextExtractedContentContainingNode
|
||||||
private let containerNode: ContextControllerSourceNode
|
private let containerNode: ContextControllerSourceNode
|
||||||
private let addressButtonNode: HighlightTrackingButtonNode
|
private let addressButtonNode: HighlightTrackingButtonNode
|
||||||
@ -158,6 +162,8 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
|||||||
self.addressNode = TextNode()
|
self.addressNode = TextNode()
|
||||||
self.addressNode.isUserInteractionEnabled = false
|
self.addressNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.fieldButtonNode = HighlightTrackingButtonNode()
|
||||||
|
|
||||||
self.addressButtonNode = HighlightTrackingButtonNode()
|
self.addressButtonNode = HighlightTrackingButtonNode()
|
||||||
self.extractedContainerNode = ContextExtractedContentContainingNode()
|
self.extractedContainerNode = ContextExtractedContentContainingNode()
|
||||||
self.containerNode = ContextControllerSourceNode()
|
self.containerNode = ContextControllerSourceNode()
|
||||||
@ -177,6 +183,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
|||||||
|
|
||||||
self.addSubnode(self.fieldNode)
|
self.addSubnode(self.fieldNode)
|
||||||
self.addSubnode(self.addressNode)
|
self.addSubnode(self.addressNode)
|
||||||
|
self.addSubnode(self.fieldButtonNode)
|
||||||
self.addSubnode(self.avatarsNode)
|
self.addSubnode(self.avatarsNode)
|
||||||
self.addSubnode(self.invitedPeersNode)
|
self.addSubnode(self.invitedPeersNode)
|
||||||
self.addSubnode(self.avatarsButtonNode)
|
self.addSubnode(self.avatarsButtonNode)
|
||||||
@ -189,6 +196,19 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
|||||||
|
|
||||||
self.addSubnode(self.activateArea)
|
self.addSubnode(self.activateArea)
|
||||||
|
|
||||||
|
self.fieldButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.addressNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.addressNode.alpha = 0.4
|
||||||
|
} else {
|
||||||
|
strongSelf.addressNode.alpha = 1.0
|
||||||
|
strongSelf.addressNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.fieldButtonNode.addTarget(self, action: #selector(self.fieldButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
self.addressButtonNode.addTarget(self, action: #selector(self.addressButtonPressed), forControlEvents: .touchUpInside)
|
self.addressButtonNode.addTarget(self, action: #selector(self.addressButtonPressed), forControlEvents: .touchUpInside)
|
||||||
self.addressButtonNode.highligthedChanged = { [weak self] highlighted in
|
self.addressButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -224,6 +244,12 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
|||||||
self.avatarsButtonNode.addTarget(self, action: #selector(self.avatarsButtonPressed), forControlEvents: .touchUpInside)
|
self.avatarsButtonNode.addTarget(self, action: #selector(self.avatarsButtonPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func fieldButtonPressed() {
|
||||||
|
if let item = self.item {
|
||||||
|
item.copyAction?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func addressButtonPressed() {
|
@objc private func addressButtonPressed() {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
item.contextAction?(self.extractedContainerNode)
|
item.contextAction?(self.extractedContainerNode)
|
||||||
@ -393,6 +419,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
|||||||
|
|
||||||
let fieldFrame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: CGSize(width: params.width - leftInset - rightInset, height: fieldHeight))
|
let fieldFrame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: CGSize(width: params.width - leftInset - rightInset, height: fieldHeight))
|
||||||
strongSelf.fieldNode.frame = fieldFrame
|
strongSelf.fieldNode.frame = fieldFrame
|
||||||
|
strongSelf.fieldButtonNode.frame = fieldFrame
|
||||||
|
|
||||||
strongSelf.addressNode.frame = CGRect(origin: CGPoint(x: fieldFrame.minX + floorToScreenPixels((fieldFrame.width - addressLayout.size.width) / 2.0), y: fieldFrame.minY + floorToScreenPixels((fieldFrame.height - addressLayout.size.height) / 2.0) + 1.0), size: addressLayout.size)
|
strongSelf.addressNode.frame = CGRect(origin: CGPoint(x: fieldFrame.minX + floorToScreenPixels((fieldFrame.width - addressLayout.size.width) / 2.0), y: fieldFrame.minY + floorToScreenPixels((fieldFrame.height - addressLayout.size.height) / 2.0) + 1.0), size: addressLayout.size)
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ public enum ItemListDisclosureStyle {
|
|||||||
public enum ItemListDisclosureLabelStyle {
|
public enum ItemListDisclosureLabelStyle {
|
||||||
case text
|
case text
|
||||||
case detailText
|
case detailText
|
||||||
|
case coloredText(UIColor)
|
||||||
case multilineDetailText
|
case multilineDetailText
|
||||||
case badge(UIColor)
|
case badge(UIColor)
|
||||||
case color(UIColor)
|
case color(UIColor)
|
||||||
@ -277,6 +278,9 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor
|
labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor
|
||||||
labelFont = detailFont
|
labelFont = detailFont
|
||||||
labelConstrain = params.width - params.rightInset - 40.0 - leftInset
|
labelConstrain = params.width - params.rightInset - 40.0 - leftInset
|
||||||
|
case let .coloredText(color):
|
||||||
|
labelBadgeColor = color
|
||||||
|
labelFont = titleFont
|
||||||
default:
|
default:
|
||||||
labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor
|
labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor
|
||||||
labelFont = titleFont
|
labelFont = titleFont
|
||||||
|
@ -46,6 +46,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
|||||||
let clearType: ItemListSingleLineInputClearType
|
let clearType: ItemListSingleLineInputClearType
|
||||||
let maxLength: Int
|
let maxLength: Int
|
||||||
let enabled: Bool
|
let enabled: Bool
|
||||||
|
let selectAllOnFocus: Bool
|
||||||
public let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
let textUpdated: (String) -> Void
|
let textUpdated: (String) -> Void
|
||||||
@ -55,7 +56,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
|||||||
let cleared: (() -> Void)?
|
let cleared: (() -> Void)?
|
||||||
public let tag: ItemListItemTag?
|
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.presentationData = presentationData
|
||||||
self.title = title
|
self.title = title
|
||||||
self.text = text
|
self.text = text
|
||||||
@ -67,6 +68,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
|
|||||||
self.clearType = clearType
|
self.clearType = clearType
|
||||||
self.maxLength = maxLength
|
self.maxLength = maxLength
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
|
self.selectAllOnFocus = selectAllOnFocus
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
self.textUpdated = textUpdated
|
self.textUpdated = textUpdated
|
||||||
@ -494,6 +496,13 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
|||||||
|
|
||||||
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||||
self.item?.updatedFocus?(true)
|
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()
|
self.updateClearButtonVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ private enum ChannelAdminEntry: ItemListNodeEntry {
|
|||||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||||
let arguments = arguments as! ChannelAdminControllerArguments
|
let arguments = arguments as! ChannelAdminControllerArguments
|
||||||
switch self {
|
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
|
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: {
|
}, avatarTapped: {
|
||||||
})
|
})
|
||||||
|
@ -182,17 +182,17 @@ private enum ChannelMembersEntry: ItemListNodeEntry {
|
|||||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||||
let arguments = arguments as! ChannelMembersControllerArguments
|
let arguments = arguments as! ChannelMembersControllerArguments
|
||||||
switch self {
|
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: {
|
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||||
arguments.addMember()
|
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: {
|
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||||
arguments.inviteViaLink()
|
arguments.inviteViaLink()
|
||||||
})
|
})
|
||||||
case let .addMemberInfo(theme, text):
|
case let .addMemberInfo(_, text):
|
||||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
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
|
let text: ItemListPeerItemText
|
||||||
if let user = participant.peer as? TelegramUser, let _ = user.botInfo {
|
if let user = participant.peer as? TelegramUser, let _ = user.botInfo {
|
||||||
text = .text(strings.Bot_GenericBotStatus, .secondary)
|
text = .text(strings.Bot_GenericBotStatus, .secondary)
|
||||||
@ -465,6 +465,7 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) ->
|
|||||||
}
|
}
|
||||||
}, inviteViaLink: {
|
}, inviteViaLink: {
|
||||||
if let controller = getControllerImpl?() {
|
if let controller = getControllerImpl?() {
|
||||||
|
dismissInputImpl?()
|
||||||
presentControllerImpl?(InviteLinkInviteController(context: context, peerId: peerId, parentNavigationController: controller.navigationController as? NavigationController), nil)
|
presentControllerImpl?(InviteLinkInviteController(context: context, peerId: peerId, parentNavigationController: controller.navigationController as? NavigationController), nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -30,11 +30,12 @@ private final class ChannelVisibilityControllerArguments {
|
|||||||
let displayPrivateLinkMenu: (String) -> Void
|
let displayPrivateLinkMenu: (String) -> Void
|
||||||
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
|
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
|
||||||
let revokePeerId: (PeerId) -> Void
|
let revokePeerId: (PeerId) -> Void
|
||||||
let shareLink: () -> Void
|
let copyLink: (ExportedInvitation) -> Void
|
||||||
|
let shareLink: (ExportedInvitation) -> Void
|
||||||
let linkContextAction: (ASDisplayNode) -> Void
|
let linkContextAction: (ASDisplayNode) -> Void
|
||||||
let manageInviteLinks: () -> Void
|
let manageInviteLinks: () -> Void
|
||||||
|
|
||||||
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, displayPrivateLinkMenu: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, shareLink: @escaping () -> Void, linkContextAction: @escaping (ASDisplayNode) -> Void, manageInviteLinks: @escaping () -> Void) {
|
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, displayPrivateLinkMenu: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode) -> Void, manageInviteLinks: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updateCurrentType = updateCurrentType
|
self.updateCurrentType = updateCurrentType
|
||||||
self.updatePublicLinkText = updatePublicLinkText
|
self.updatePublicLinkText = updatePublicLinkText
|
||||||
@ -42,6 +43,7 @@ private final class ChannelVisibilityControllerArguments {
|
|||||||
self.displayPrivateLinkMenu = displayPrivateLinkMenu
|
self.displayPrivateLinkMenu = displayPrivateLinkMenu
|
||||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||||
self.revokePeerId = revokePeerId
|
self.revokePeerId = revokePeerId
|
||||||
|
self.copyLink = copyLink
|
||||||
self.shareLink = shareLink
|
self.shareLink = shareLink
|
||||||
self.linkContextAction = linkContextAction
|
self.linkContextAction = linkContextAction
|
||||||
self.manageInviteLinks = manageInviteLinks
|
self.manageInviteLinks = manageInviteLinks
|
||||||
@ -77,7 +79,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
case publicLinkAvailability(PresentationTheme, String, Bool)
|
case publicLinkAvailability(PresentationTheme, String, Bool)
|
||||||
case editablePublicLink(PresentationTheme, PresentationStrings, String, String)
|
case editablePublicLink(PresentationTheme, PresentationStrings, String, String)
|
||||||
case privateLinkHeader(PresentationTheme, String)
|
case privateLinkHeader(PresentationTheme, String)
|
||||||
case privateLink(PresentationTheme, ExportedInvitation?)
|
case privateLink(PresentationTheme, ExportedInvitation?, Bool)
|
||||||
case privateLinkInfo(PresentationTheme, String)
|
case privateLinkInfo(PresentationTheme, String)
|
||||||
case privateLinkManage(PresentationTheme, String)
|
case privateLinkManage(PresentationTheme, String)
|
||||||
case privateLinkManageInfo(PresentationTheme, String)
|
case privateLinkManageInfo(PresentationTheme, String)
|
||||||
@ -182,8 +184,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .privateLink(lhsTheme, lhsInvite):
|
case let .privateLink(lhsTheme, lhsInvite, lhsDisplayImporters):
|
||||||
if case let .privateLink(rhsTheme, rhsInvite) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite {
|
if case let .privateLink(rhsTheme, rhsInvite, rhsDisplayImporters) = rhs, lhsTheme === rhsTheme, lhsInvite == rhsInvite, lhsDisplayImporters == rhsDisplayImporters {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -290,9 +292,15 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
|||||||
return ItemListActivityTextItem(displayActivity: value, presentationData: presentationData, text: attr, sectionId: self.section)
|
return ItemListActivityTextItem(displayActivity: value, presentationData: presentationData, text: attr, sectionId: self.section)
|
||||||
case let .privateLinkHeader(_, title):
|
case let .privateLinkHeader(_, title):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||||
case let .privateLink(_, invite):
|
case let .privateLink(_, invite, displayImporters):
|
||||||
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: [], displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, shareAction: {
|
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: [], displayButton: true, displayImporters: displayImporters, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||||
arguments.shareLink()
|
if let invite = invite {
|
||||||
|
arguments.copyLink(invite)
|
||||||
|
}
|
||||||
|
}, shareAction: {
|
||||||
|
if let invite = invite {
|
||||||
|
arguments.shareLink(invite)
|
||||||
|
}
|
||||||
}, contextAction: { node in
|
}, contextAction: { node in
|
||||||
arguments.linkContextAction(node)
|
arguments.linkContextAction(node)
|
||||||
}, viewAction: {
|
}, viewAction: {
|
||||||
@ -594,7 +602,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
case .privateChannel:
|
case .privateChannel:
|
||||||
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
|
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
|
||||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
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 {
|
if isGroup {
|
||||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||||
} else {
|
} else {
|
||||||
@ -613,7 +621,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
case .privateLink:
|
case .privateLink:
|
||||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
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))
|
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
|
||||||
switch mode {
|
switch mode {
|
||||||
case .initialSetup:
|
case .initialSetup:
|
||||||
@ -712,7 +720,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
case .privateChannel:
|
case .privateChannel:
|
||||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_PermanentLink.uppercased()))
|
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))
|
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||||
switch mode {
|
switch mode {
|
||||||
case .initialSetup:
|
case .initialSetup:
|
||||||
@ -836,13 +844,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
|
|||||||
let revokeLinkDisposable = MetaDisposable()
|
let revokeLinkDisposable = MetaDisposable()
|
||||||
actionsDisposable.add(revokeLinkDisposable)
|
actionsDisposable.add(revokeLinkDisposable)
|
||||||
|
|
||||||
actionsDisposable.add((context.account.viewTracker.peerView(peerId) |> filter { $0.cachedData != nil } |> take(1) |> mapToSignal { view -> Signal<String?, NoError> in
|
|
||||||
return ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId)
|
|
||||||
|> mapToSignal { _ -> Signal<String?, NoError> in
|
|
||||||
return .complete()
|
|
||||||
}
|
|
||||||
}).start())
|
|
||||||
|
|
||||||
let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in
|
let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedSelectedType(type)
|
return state.withUpdatedSelectedType(type)
|
||||||
@ -898,22 +899,13 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
}, shareLink: {
|
}, copyLink: { invite in
|
||||||
let _ = (context.account.postbox.transaction { transaction -> String? in
|
UIPasteboard.general.string = invite.link
|
||||||
if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
if let cachedData = cachedData as? CachedChannelData {
|
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
|
||||||
return cachedData.exportedInvitation?.link
|
}, shareLink: { invite in
|
||||||
} else if let cachedData = cachedData as? CachedGroupData {
|
let shareController = ShareController(context: context, subject: .url(invite.link))
|
||||||
return cachedData.exportedInvitation?.link
|
presentControllerImpl?(shareController, nil)
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} |> deliverOnMainQueue).start(next: { link in
|
|
||||||
if let link = link {
|
|
||||||
let shareController = ShareController(context: context, subject: .url(link))
|
|
||||||
presentControllerImpl?(shareController, nil)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, linkContextAction: { node in
|
}, linkContextAction: { node in
|
||||||
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
|
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
|
||||||
return
|
return
|
||||||
@ -991,7 +983,7 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if revoke {
|
if revoke {
|
||||||
revokeLinkDisposable.set((ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId, revokeExisted: true) |> deliverOnMainQueue).start(completed: {
|
revokeLinkDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||||
updateState {
|
updateState {
|
||||||
$0.withUpdatedRevokingPrivateLink(false)
|
$0.withUpdatedRevokingPrivateLink(false)
|
||||||
}
|
}
|
||||||
@ -1067,7 +1059,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
|
|||||||
return state.withUpdatedUpdatingAddressName(false)
|
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)
|
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||||
|
|
||||||
}, completed: {
|
}, completed: {
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedUpdatingAddressName(false)
|
return state.withUpdatedUpdatingAddressName(false)
|
||||||
|
@ -3,20 +3,24 @@ import Postbox
|
|||||||
public final class CachedStickerQueryResult: PostboxCoding {
|
public final class CachedStickerQueryResult: PostboxCoding {
|
||||||
public let items: [TelegramMediaFile]
|
public let items: [TelegramMediaFile]
|
||||||
public let hash: Int32
|
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.items = items
|
||||||
self.hash = hash
|
self.hash = hash
|
||||||
|
self.timestamp = timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
self.items = decoder.decodeObjectArrayForKey("it").map { $0 as! TelegramMediaFile }
|
self.items = decoder.decodeObjectArrayForKey("it").map { $0 as! TelegramMediaFile }
|
||||||
self.hash = decoder.decodeInt32ForKey("h", orElse: 0)
|
self.hash = decoder.decodeInt32ForKey("h", orElse: 0)
|
||||||
|
self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
encoder.encodeObjectArray(self.items, forKey: "it")
|
encoder.encodeObjectArray(self.items, forKey: "it")
|
||||||
encoder.encodeInt32(self.hash, forKey: "h")
|
encoder.encodeInt32(self.hash, forKey: "h")
|
||||||
|
encoder.encodeInt32(self.timestamp, forKey: "t")
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func cacheKey(_ query: String) -> ValueBoxKey {
|
public static func cacheKey(_ query: String) -> ValueBoxKey {
|
||||||
|
@ -74,6 +74,7 @@ public struct Namespaces {
|
|||||||
public static let cachedContextResults: Int8 = 10
|
public static let cachedContextResults: Int8 = 10
|
||||||
public static let proximityNotificationStoredState: Int8 = 11
|
public static let proximityNotificationStoredState: Int8 = 11
|
||||||
public static let cachedPeerInvitationImporters: Int8 = 12
|
public static let cachedPeerInvitationImporters: Int8 = 12
|
||||||
|
public static let cachedPeerExportedInvitations: Int8 = 13
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct UnorderedItemList {
|
public struct UnorderedItemList {
|
||||||
|
@ -11,7 +11,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
||||||
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
||||||
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
||||||
dict[231260545] = { return Api.ChatFull.parse_chatFull($0) }
|
dict[-213431562] = { return Api.ChatFull.parse_chatFull($0) }
|
||||||
dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) }
|
dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) }
|
||||||
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
||||||
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
||||||
|
@ -2206,14 +2206,14 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
public enum ChatFull: TypeConstructorDescription {
|
public enum ChatFull: TypeConstructorDescription {
|
||||||
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?)
|
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?)
|
||||||
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?)
|
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(231260545)
|
buffer.appendInt32(-213431562)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt32(id, buffer: buffer, boxed: false)
|
serializeInt32(id, buffer: buffer, boxed: false)
|
||||||
@ -2221,7 +2221,7 @@ public extension Api {
|
|||||||
participants.serialize(buffer, true)
|
participants.serialize(buffer, true)
|
||||||
if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)}
|
||||||
notifySettings.serialize(buffer, true)
|
notifySettings.serialize(buffer, true)
|
||||||
exportedInvite.serialize(buffer, true)
|
if Int(flags) & Int(1 << 13) != 0 {exportedInvite!.serialize(buffer, true)}
|
||||||
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
||||||
buffer.appendInt32(Int32(botInfo!.count))
|
buffer.appendInt32(Int32(botInfo!.count))
|
||||||
for item in botInfo! {
|
for item in botInfo! {
|
||||||
@ -2300,9 +2300,9 @@ public extension Api {
|
|||||||
_6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
_6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
||||||
}
|
}
|
||||||
var _7: Api.ExportedChatInvite?
|
var _7: Api.ExportedChatInvite?
|
||||||
if let signature = reader.readInt32() {
|
if Int(_1!) & Int(1 << 13) != 0 {if let signature = reader.readInt32() {
|
||||||
_7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
|
_7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
|
||||||
}
|
} }
|
||||||
var _8: [Api.BotInfo]?
|
var _8: [Api.BotInfo]?
|
||||||
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
||||||
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self)
|
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self)
|
||||||
@ -2321,13 +2321,13 @@ public extension Api {
|
|||||||
let _c4 = _4 != nil
|
let _c4 = _4 != nil
|
||||||
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
|
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
|
||||||
let _c6 = _6 != nil
|
let _c6 = _6 != nil
|
||||||
let _c7 = _7 != nil
|
let _c7 = (Int(_1!) & Int(1 << 13) == 0) || _7 != nil
|
||||||
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
||||||
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
||||||
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
|
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
|
||||||
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
|
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
||||||
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7!, botInfo: _8, pinnedMsgId: _9, folderId: _10, call: _11)
|
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7, botInfo: _8, pinnedMsgId: _9, folderId: _10, call: _11)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1061,24 +1061,6 @@ public final class VoiceChatController: ViewController {
|
|||||||
strongSelf.accountPeer = accountPeer
|
strongSelf.accountPeer = accountPeer
|
||||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
|
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
|
||||||
|
|
||||||
if let peer = peerViewMainPeer(view) {
|
|
||||||
if let channel = peer as? TelegramChannel {
|
|
||||||
let addressName = channel.addressName ?? ""
|
|
||||||
if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) {
|
|
||||||
if addressName.isEmpty {
|
|
||||||
let _ = ensuredExistingPeerExportedInvitation(account: strongSelf.context.account, peerId: call.peerId).start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let group = peer as? TelegramGroup {
|
|
||||||
switch group.role {
|
|
||||||
case .creator, .admin:
|
|
||||||
let _ = ensuredExistingPeerExportedInvitation(account: strongSelf.context.account, peerId: call.peerId).start()
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strongSelf.didSetDataReady = true
|
strongSelf.didSetDataReady = true
|
||||||
strongSelf.controller?.dataReady.set(true)
|
strongSelf.controller?.dataReady.set(true)
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,8 @@ private var declaredEncodables: Void = {
|
|||||||
declareEncodable(ValidationMessageAttribute.self, f: { ValidationMessageAttribute(decoder: $0) })
|
declareEncodable(ValidationMessageAttribute.self, f: { ValidationMessageAttribute(decoder: $0) })
|
||||||
declareEncodable(EmojiSearchQueryMessageAttribute.self, f: { EmojiSearchQueryMessageAttribute(decoder: $0) })
|
declareEncodable(EmojiSearchQueryMessageAttribute.self, f: { EmojiSearchQueryMessageAttribute(decoder: $0) })
|
||||||
declareEncodable(CachedPeerInvitationImporters.self, f: { CachedPeerInvitationImporters(decoder: $0) })
|
declareEncodable(CachedPeerInvitationImporters.self, f: { CachedPeerInvitationImporters(decoder: $0) })
|
||||||
|
declareEncodable(CachedPeerExportedInvitations.self, f: { CachedPeerExportedInvitations(decoder: $0) })
|
||||||
|
declareEncodable(ExportedInvitation.self, f: { ExportedInvitation(decoder: $0) })
|
||||||
|
|
||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
|
@ -6,53 +6,45 @@ import MtProtoKit
|
|||||||
|
|
||||||
import SyncCore
|
import SyncCore
|
||||||
|
|
||||||
public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId, revokeExisted: Bool = false) -> Signal<ExportedInvitation?, NoError> {
|
public func revokePersistentPeerExportedInvitation(account: Account, peerId: PeerId) -> Signal<ExportedInvitation?, NoError> {
|
||||||
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in
|
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in
|
||||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||||
let flags: Int32 = (1 << 2)
|
let flags: Int32 = (1 << 2)
|
||||||
if let _ = peer as? TelegramChannel {
|
if let _ = peer as? TelegramChannel {
|
||||||
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil && !revokeExisted {
|
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil))
|
||||||
return .single(cachedData.exportedInvitation)
|
|> retryRequest
|
||||||
} else {
|
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
|
||||||
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil))
|
return account.postbox.transaction { transaction -> ExportedInvitation? in
|
||||||
|> retryRequest
|
if let invitation = ExportedInvitation(apiExportedInvite: result) {
|
||||||
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||||
return account.postbox.transaction { transaction -> ExportedInvitation? in
|
if let current = current as? CachedChannelData {
|
||||||
if let invitation = ExportedInvitation(apiExportedInvite: result) {
|
return current.withUpdatedExportedInvitation(invitation)
|
||||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
} else {
|
||||||
if let current = current as? CachedChannelData {
|
return CachedChannelData().withUpdatedExportedInvitation(invitation)
|
||||||
return current.withUpdatedExportedInvitation(invitation)
|
}
|
||||||
} else {
|
})
|
||||||
return CachedChannelData().withUpdatedExportedInvitation(invitation)
|
return invitation
|
||||||
}
|
} else {
|
||||||
})
|
return nil
|
||||||
return invitation
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let _ = peer as? TelegramGroup {
|
} else if let _ = peer as? TelegramGroup {
|
||||||
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil && !revokeExisted {
|
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil))
|
||||||
return .single(cachedData.exportedInvitation)
|
|> retryRequest
|
||||||
} else {
|
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
|
||||||
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil))
|
return account.postbox.transaction { transaction -> ExportedInvitation? in
|
||||||
|> retryRequest
|
if let invitation = ExportedInvitation(apiExportedInvite: result) {
|
||||||
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||||
return account.postbox.transaction { transaction -> ExportedInvitation? in
|
if let current = current as? CachedGroupData {
|
||||||
if let invitation = ExportedInvitation(apiExportedInvite: result) {
|
return current.withUpdatedExportedInvitation(invitation)
|
||||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
} else {
|
||||||
if let current = current as? CachedGroupData {
|
return current
|
||||||
return current.withUpdatedExportedInvitation(invitation)
|
}
|
||||||
} else {
|
})
|
||||||
return CachedGroupData().withUpdatedExportedInvitation(invitation)
|
return invitation
|
||||||
}
|
} else {
|
||||||
})
|
return nil
|
||||||
return invitation
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,8 +57,12 @@ public func ensuredExistingPeerExportedInvitation(account: Account, peerId: Peer
|
|||||||
} |> switchToLatest
|
} |> switchToLatest
|
||||||
}
|
}
|
||||||
|
|
||||||
public func createPeerExportedInvitation(account: Account, peerId: PeerId, expireDate: Int32?, usageLimit: Int32?) -> Signal<ExportedInvitation?, NoError> {
|
public enum CreatePeerExportedInvitationError {
|
||||||
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in
|
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) {
|
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
if let _ = expireDate {
|
if let _ = expireDate {
|
||||||
@ -76,7 +72,7 @@ public func createPeerExportedInvitation(account: Account, peerId: PeerId, expir
|
|||||||
flags |= (1 << 1)
|
flags |= (1 << 1)
|
||||||
}
|
}
|
||||||
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: expireDate, usageLimit: usageLimit))
|
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
|
|> map { result -> ExportedInvitation? in
|
||||||
if let invitation = ExportedInvitation(apiExportedInvite: result) {
|
if let invitation = ExportedInvitation(apiExportedInvite: result) {
|
||||||
return invitation
|
return invitation
|
||||||
@ -87,7 +83,9 @@ public func createPeerExportedInvitation(account: Account, peerId: PeerId, expir
|
|||||||
} else {
|
} else {
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
} |> switchToLatest
|
}
|
||||||
|
|> castError(CreatePeerExportedInvitationError.self)
|
||||||
|
|> switchToLatest
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ExportedInvitations : Equatable {
|
public struct ExportedInvitations : Equatable {
|
||||||
@ -266,9 +264,10 @@ final class CachedPeerExportedInvitations: PostboxCoding {
|
|||||||
let canLoadMore: Bool
|
let canLoadMore: Bool
|
||||||
let count: Int32
|
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)
|
let key = ValueBoxKey(length: 8 + 4)
|
||||||
key.setInt64(0, value: peerId.toInt64())
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
|
key.setInt32(8, value: revoked ? 1 : 0)
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,26 +294,32 @@ private final class PeerExportedInvitationsContextImpl {
|
|||||||
private let queue: Queue
|
private let queue: Queue
|
||||||
private let account: Account
|
private let account: Account
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
|
private let revoked: Bool
|
||||||
|
private var forceUpdate: Bool
|
||||||
private let disposable = MetaDisposable()
|
private let disposable = MetaDisposable()
|
||||||
|
private let updateDisposable = MetaDisposable()
|
||||||
private var isLoadingMore: Bool = false
|
private var isLoadingMore: Bool = false
|
||||||
private var hasLoadedOnce: Bool = false
|
private var hasLoadedOnce: Bool = false
|
||||||
private var canLoadMore: Bool = true
|
private var canLoadMore: Bool = true
|
||||||
|
private var loadedFromCache: Bool = false
|
||||||
private var results: [ExportedInvitation] = []
|
private var results: [ExportedInvitation] = []
|
||||||
private var count: Int32
|
private var count: Int32
|
||||||
private var populateCache: Bool = true
|
private var populateCache: Bool = true
|
||||||
|
|
||||||
let state = Promise<PeerExportedInvitationsState>()
|
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.queue = queue
|
||||||
self.account = account
|
self.account = account
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.revoked = revoked
|
||||||
|
self.forceUpdate = forceUpdate
|
||||||
|
|
||||||
self.count = 0
|
self.count = 0
|
||||||
|
|
||||||
self.isLoadingMore = true
|
self.isLoadingMore = true
|
||||||
self.disposable.set((account.postbox.transaction { transaction -> CachedPeerExportedInvitations? in
|
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
|
|> deliverOn(self.queue)).start(next: { [weak self] cachedResult in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -326,6 +331,7 @@ private final class PeerExportedInvitationsContextImpl {
|
|||||||
strongSelf.count = cachedResult.count
|
strongSelf.count = cachedResult.count
|
||||||
strongSelf.hasLoadedOnce = true
|
strongSelf.hasLoadedOnce = true
|
||||||
strongSelf.canLoadMore = cachedResult.canLoadMore
|
strongSelf.canLoadMore = cachedResult.canLoadMore
|
||||||
|
strongSelf.loadedFromCache = true
|
||||||
}
|
}
|
||||||
strongSelf.loadMore()
|
strongSelf.loadMore()
|
||||||
}))
|
}))
|
||||||
@ -335,6 +341,12 @@ private final class PeerExportedInvitationsContextImpl {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.disposable.dispose()
|
self.disposable.dispose()
|
||||||
|
self.updateDisposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func reload() {
|
||||||
|
self.forceUpdate = true
|
||||||
|
self.loadMore()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadMore() {
|
func loadMore() {
|
||||||
@ -344,16 +356,33 @@ private final class PeerExportedInvitationsContextImpl {
|
|||||||
self.isLoadingMore = true
|
self.isLoadingMore = true
|
||||||
let account = self.account
|
let account = self.account
|
||||||
let peerId = self.peerId
|
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
|
let populateCache = self.populateCache
|
||||||
|
|
||||||
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||||
}
|
}
|
||||||
|> mapToSignal { inputPeer -> Signal<([ExportedInvitation], Int32), NoError> in
|
|> mapToSignal { inputPeer -> Signal<([ExportedInvitation], Int32), NoError> in
|
||||||
if let inputPeer = inputPeer {
|
if let inputPeer = inputPeer {
|
||||||
let offsetLink = lastResult?.link
|
let offsetLink = lastResult?.link
|
||||||
|
var flags: Int32 = 0
|
||||||
let signal = account.network.request(Api.functions.messages.getExportedChatInvites(flags: 0, peer: inputPeer, adminId: nil, offsetLink: offsetLink, limit: lastResult == nil ? 50 : 100))
|
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)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
|
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
@ -374,7 +403,7 @@ private final class PeerExportedInvitationsContextImpl {
|
|||||||
})
|
})
|
||||||
let invitations: [ExportedInvitation] = invites.compactMap { ExportedInvitation(apiExportedInvite: $0) }
|
let invitations: [ExportedInvitation] = invites.compactMap { ExportedInvitation(apiExportedInvite: $0) }
|
||||||
if populateCache {
|
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)
|
return (invitations, count)
|
||||||
}
|
}
|
||||||
@ -409,10 +438,63 @@ private final class PeerExportedInvitationsContextImpl {
|
|||||||
strongSelf.count = Int32(strongSelf.results.count)
|
strongSelf.count = Int32(strongSelf.results.count)
|
||||||
}
|
}
|
||||||
strongSelf.updateState()
|
strongSelf.updateState()
|
||||||
|
|
||||||
|
if strongSelf.forceUpdate {
|
||||||
|
strongSelf.loadMore()
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
self.updateState()
|
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() {
|
private func updateState() {
|
||||||
self.state.set(.single(PeerExportedInvitationsState(invitations: self.results, isLoadingMore: self.isLoadingMore, hasLoadedOnce: self.hasLoadedOnce, canLoadMore: self.canLoadMore, count: self.count)))
|
self.state.set(.single(PeerExportedInvitationsState(invitations: self.results, isLoadingMore: self.isLoadingMore, hasLoadedOnce: self.hasLoadedOnce, canLoadMore: self.canLoadMore, count: self.count)))
|
||||||
}
|
}
|
||||||
@ -434,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
|
let queue = self.queue
|
||||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
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() {
|
public func loadMore() {
|
||||||
self.impl.with { impl in
|
self.impl.with { impl in
|
||||||
impl.loadMore()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -529,6 +641,7 @@ private final class PeerInvitationImportersContextImpl {
|
|||||||
private var isLoadingMore: Bool = false
|
private var isLoadingMore: Bool = false
|
||||||
private var hasLoadedOnce: Bool = false
|
private var hasLoadedOnce: Bool = false
|
||||||
private var canLoadMore: Bool = true
|
private var canLoadMore: Bool = true
|
||||||
|
private var loadedFromCache = false
|
||||||
private var results: [PeerInvitationImportersState.Importer] = []
|
private var results: [PeerInvitationImportersState.Importer] = []
|
||||||
private var count: Int32
|
private var count: Int32
|
||||||
private var populateCache: Bool = true
|
private var populateCache: Bool = true
|
||||||
@ -570,6 +683,7 @@ private final class PeerInvitationImportersContextImpl {
|
|||||||
strongSelf.results = cachedPeers
|
strongSelf.results = cachedPeers
|
||||||
strongSelf.hasLoadedOnce = true
|
strongSelf.hasLoadedOnce = true
|
||||||
strongSelf.canLoadMore = canLoadMore
|
strongSelf.canLoadMore = canLoadMore
|
||||||
|
strongSelf.loadedFromCache = true
|
||||||
}
|
}
|
||||||
strongSelf.loadMore()
|
strongSelf.loadMore()
|
||||||
}))
|
}))
|
||||||
@ -589,15 +703,21 @@ private final class PeerInvitationImportersContextImpl {
|
|||||||
let account = self.account
|
let account = self.account
|
||||||
let peerId = self.peerId
|
let peerId = self.peerId
|
||||||
let link = self.link
|
let link = self.link
|
||||||
let lastResult = self.results.last
|
|
||||||
let populateCache = self.populateCache
|
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
|
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||||
}
|
}
|
||||||
|> mapToSignal { inputPeer -> Signal<([PeerInvitationImportersState.Importer], Int32), NoError> in
|
|> mapToSignal { inputPeer -> Signal<([PeerInvitationImportersState.Importer], Int32), NoError> in
|
||||||
if let inputPeer = inputPeer {
|
if let inputPeer = inputPeer {
|
||||||
let offsetUser = lastResult?.peer.peer.flatMap { apiInputUser($0) } ?? .inputUserEmpty
|
let offsetUser = lastResult?.peer.peer.flatMap { apiInputUser($0) } ?? .inputUserEmpty
|
||||||
let offsetDate = populateCache ? 0 : lastResult?.date ?? 0
|
let offsetDate = lastResult?.date ?? 0
|
||||||
let signal = account.network.request(Api.functions.messages.getChatInviteImporters(peer: inputPeer, link: link, offsetDate: offsetDate, offsetUser: offsetUser, limit: lastResult == nil ? 10 : 50))
|
let signal = account.network.request(Api.functions.messages.getChatInviteImporters(peer: inputPeer, link: link, offsetDate: offsetDate, offsetUser: offsetUser, limit: lastResult == nil ? 10 : 50))
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<Api.messages.ChatInviteImporters?, NoError> in
|
|> `catch` { _ -> Signal<Api.messages.ChatInviteImporters?, NoError> in
|
||||||
|
@ -5,6 +5,26 @@ import SwiftSignalKit
|
|||||||
|
|
||||||
import SyncCore
|
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 final class FoundStickerItem: Equatable {
|
||||||
public let file: TelegramMediaFile
|
public let file: TelegramMediaFile
|
||||||
public let stringRepresentations: [String]
|
public let stringRepresentations: [String]
|
||||||
@ -140,7 +160,15 @@ public func searchStickers(account: Account, query: String, scope: SearchSticker
|
|||||||
result.append(contentsOf: installedItems)
|
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)
|
return (result, cached)
|
||||||
} |> mapToSignal { localItems, cached -> Signal<[FoundStickerItem], NoError> in
|
} |> 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: animatedItems)
|
||||||
result.append(contentsOf: items)
|
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
|
return result
|
||||||
case .stickersNotModified:
|
case .stickersNotModified:
|
||||||
|
@ -6,6 +6,7 @@ import SyncCore
|
|||||||
|
|
||||||
public enum ServerProvidedSuggestion: String {
|
public enum ServerProvidedSuggestion: String {
|
||||||
case autoarchivePopular = "AUTOARCHIVE_POPULAR"
|
case autoarchivePopular = "AUTOARCHIVE_POPULAR"
|
||||||
|
case newcomerTicks = "NEWCOMER_TICKS"
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getServerProvidedSuggestions(postbox: Postbox) -> Signal<[ServerProvidedSuggestion], NoError> {
|
public func getServerProvidedSuggestions(postbox: Postbox) -> Signal<[ServerProvidedSuggestion], NoError> {
|
||||||
@ -22,12 +23,7 @@ public func getServerProvidedSuggestions(postbox: Postbox) -> Signal<[ServerProv
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
return list.compactMap { item -> ServerProvidedSuggestion? in
|
return list.compactMap { item -> ServerProvidedSuggestion? in
|
||||||
switch item {
|
return ServerProvidedSuggestion(rawValue: item)
|
||||||
case "AUTOARCHIVE_POPULAR":
|
|
||||||
return .autoarchivePopular
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|
@ -205,10 +205,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
|
|||||||
|
|
||||||
let peerStatusSettings = PeerStatusSettings(apiSettings: userFull.settings)
|
let peerStatusSettings = PeerStatusSettings(apiSettings: userFull.settings)
|
||||||
|
|
||||||
var hasScheduledMessages = false
|
let hasScheduledMessages = (userFull.flags & 1 << 12) != 0
|
||||||
if (userFull.flags & 1 << 12) != 0 {
|
|
||||||
hasScheduledMessages = true
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
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)
|
||||||
}
|
}
|
||||||
@ -257,7 +254,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
|
|||||||
|
|
||||||
let photo: TelegramMediaImage? = chatFull.chatPhoto.flatMap(telegramMediaImageFromApiPhoto)
|
let photo: TelegramMediaImage? = chatFull.chatPhoto.flatMap(telegramMediaImageFromApiPhoto)
|
||||||
|
|
||||||
let exportedInvitation = ExportedInvitation(apiExportedInvite: chatFull.exportedInvite)
|
let exportedInvitation = chatFull.exportedInvite.flatMap { ExportedInvitation(apiExportedInvite: $0) }
|
||||||
let pinnedMessageId = chatFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
|
let pinnedMessageId = chatFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
|
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 applicationInForegroundDisposable: Disposable?
|
||||||
private var applicationInFocusDisposable: Disposable?
|
private var applicationInFocusDisposable: Disposable?
|
||||||
|
|
||||||
|
private let checksTooltipDisposable = MetaDisposable()
|
||||||
|
private var shouldDisplayChecksTooltip = false
|
||||||
|
|
||||||
private var checkedPeerChatServiceActions = false
|
private var checkedPeerChatServiceActions = false
|
||||||
|
|
||||||
private var willAppear = false
|
private var willAppear = false
|
||||||
@ -3424,6 +3427,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.peekTimerDisposable.dispose()
|
self.peekTimerDisposable.dispose()
|
||||||
self.hasActiveGroupCallDisposable?.dispose()
|
self.hasActiveGroupCallDisposable?.dispose()
|
||||||
self.createVoiceChatDisposable.dispose()
|
self.createVoiceChatDisposable.dispose()
|
||||||
|
self.checksTooltipDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updatePresentationMode(_ mode: ChatControllerPresentationMode) {
|
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 text = trimChatInputText(convertMarkdownToAttributes(editMessage.inputState.inputText))
|
||||||
let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text))
|
let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text))
|
||||||
var entitiesAttribute: TextEntitiesMessageAttribute?
|
var entitiesAttribute: TextEntitiesMessageAttribute?
|
||||||
@ -6236,7 +6239,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.openScheduledMessages()
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strongSelf.context.sharedContext.currentMediaInputSettings.with { $0.enableRaiseToSpeak } {
|
if !strongSelf.context.sharedContext.currentMediaInputSettings.with({ $0.enableRaiseToSpeak }) {
|
||||||
return false
|
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 {
|
if self.scheduledActivateInput {
|
||||||
self.scheduledActivateInput = false
|
self.scheduledActivateInput = false
|
||||||
|
|
||||||
@ -7481,7 +7499,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller] result in
|
|> deliverOnMainQueue).start(next: { [weak self, weak controller] result in
|
||||||
controller?.dismiss()
|
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
|
return
|
||||||
}
|
}
|
||||||
let presentationData = strongSelf.presentationData
|
let presentationData = strongSelf.presentationData
|
||||||
@ -7682,16 +7700,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func editMessageMediaWithMessages(_ messages: [EnqueueMessage]) {
|
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
|
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
|
||||||
var state = state
|
var state = state
|
||||||
if let editMessageState = state.editMessageState, case let .media(options) = editMessageState.content, !options.isEmpty {
|
if let editMessageState = state.editMessageState, case let .media(options) = editMessageState.content, !options.isEmpty {
|
||||||
state = state.updatedEditMessageState(ChatEditInterfaceMessageState(content: editMessageState.content, mediaReference: mediaReference))
|
state = state.updatedEditMessageState(ChatEditInterfaceMessageState(content: editMessageState.content, mediaReference: mediaReference))
|
||||||
}
|
}
|
||||||
if !desc.text.isEmpty {
|
if !text.isEmpty {
|
||||||
state = state.updatedInterfaceState { state in
|
state = state.updatedInterfaceState { state in
|
||||||
if let editMessage = state.editMessage {
|
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
|
return state
|
||||||
}
|
}
|
||||||
@ -9338,7 +9356,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let complete = results.completed
|
|
||||||
var navigateIndex: MessageIndex?
|
var navigateIndex: MessageIndex?
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { current in
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { current in
|
||||||
if let data = current.search {
|
if let data = current.search {
|
||||||
@ -10111,8 +10128,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
case let .withBotStartPayload(botStart):
|
case let .withBotStartPayload(botStart):
|
||||||
self.effectiveNavigationController?.pushViewController(ChatControllerImpl(context: self.context, chatLocation: .peer(peerId), botStart: botStart))
|
self.effectiveNavigationController?.pushViewController(ChatControllerImpl(context: self.context, chatLocation: .peer(peerId), botStart: botStart))
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -10532,7 +10547,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
private func openUrl(_ url: String, concealed: Bool, message: Message? = nil) {
|
private func openUrl(_ url: String, concealed: Bool, message: Message? = nil) {
|
||||||
self.commitPurposefulAction()
|
self.commitPurposefulAction()
|
||||||
|
|
||||||
self.presentVoiceMessageDiscardAlert(action: {
|
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
||||||
if self.context.sharedContext.immediateExperimentalUISettings.playlistPlayback {
|
if self.context.sharedContext.immediateExperimentalUISettings.playlistPlayback {
|
||||||
if url.hasSuffix(".m3u8") {
|
if url.hasSuffix(".m3u8") {
|
||||||
let navigationController = self.navigationController as? NavigationController
|
let navigationController = self.navigationController as? NavigationController
|
||||||
|
@ -159,6 +159,7 @@ final class PeerInfoScreenData {
|
|||||||
let members: PeerInfoMembersData?
|
let members: PeerInfoMembersData?
|
||||||
let encryptionKeyFingerprint: SecretChatKeyFingerprint?
|
let encryptionKeyFingerprint: SecretChatKeyFingerprint?
|
||||||
let globalSettings: TelegramGlobalSettings?
|
let globalSettings: TelegramGlobalSettings?
|
||||||
|
let invitations: PeerExportedInvitationsState?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
peer: Peer?,
|
peer: Peer?,
|
||||||
@ -172,7 +173,8 @@ final class PeerInfoScreenData {
|
|||||||
linkedDiscussionPeer: Peer?,
|
linkedDiscussionPeer: Peer?,
|
||||||
members: PeerInfoMembersData?,
|
members: PeerInfoMembersData?,
|
||||||
encryptionKeyFingerprint: SecretChatKeyFingerprint?,
|
encryptionKeyFingerprint: SecretChatKeyFingerprint?,
|
||||||
globalSettings: TelegramGlobalSettings?
|
globalSettings: TelegramGlobalSettings?,
|
||||||
|
invitations: PeerExportedInvitationsState?
|
||||||
) {
|
) {
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.cachedData = cachedData
|
self.cachedData = cachedData
|
||||||
@ -186,6 +188,7 @@ final class PeerInfoScreenData {
|
|||||||
self.members = members
|
self.members = members
|
||||||
self.encryptionKeyFingerprint = encryptionKeyFingerprint
|
self.encryptionKeyFingerprint = encryptionKeyFingerprint
|
||||||
self.globalSettings = globalSettings
|
self.globalSettings = globalSettings
|
||||||
|
self.invitations = invitations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +445,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: PeerId, account
|
|||||||
linkedDiscussionPeer: nil,
|
linkedDiscussionPeer: nil,
|
||||||
members: nil,
|
members: nil,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: globalSettings
|
globalSettings: globalSettings,
|
||||||
|
invitations: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,7 +468,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: nil,
|
linkedDiscussionPeer: nil,
|
||||||
members: nil,
|
members: nil,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: nil
|
globalSettings: nil,
|
||||||
|
invitations: nil
|
||||||
))
|
))
|
||||||
case let .user(userPeerId, secretChatId, kind):
|
case let .user(userPeerId, secretChatId, kind):
|
||||||
let groupsInCommon: GroupsInCommonContext?
|
let groupsInCommon: GroupsInCommonContext?
|
||||||
@ -603,7 +608,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: nil,
|
linkedDiscussionPeer: nil,
|
||||||
members: nil,
|
members: nil,
|
||||||
encryptionKeyFingerprint: encryptionKeyFingerprint,
|
encryptionKeyFingerprint: encryptionKeyFingerprint,
|
||||||
globalSettings: nil
|
globalSettings: nil,
|
||||||
|
invitations: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case .channel:
|
case .channel:
|
||||||
@ -623,13 +629,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
||||||
var combinedKeys: [PostboxViewKey] = []
|
var combinedKeys: [PostboxViewKey] = []
|
||||||
combinedKeys.append(globalNotificationsKey)
|
combinedKeys.append(globalNotificationsKey)
|
||||||
|
|
||||||
|
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
||||||
|
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
||||||
context.account.postbox.combinedView(keys: combinedKeys),
|
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
|
var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings
|
||||||
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
||||||
if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings {
|
if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings {
|
||||||
@ -642,6 +654,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
discussionPeer = peer
|
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(
|
return PeerInfoScreenData(
|
||||||
peer: peerView.peers[peerId],
|
peer: peerView.peers[peerId],
|
||||||
cachedData: peerView.cachedData,
|
cachedData: peerView.cachedData,
|
||||||
@ -654,7 +672,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: discussionPeer,
|
linkedDiscussionPeer: discussionPeer,
|
||||||
members: nil,
|
members: nil,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: nil
|
globalSettings: nil,
|
||||||
|
invitations: invitations
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case let .group(groupId):
|
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]))
|
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
||||||
var combinedKeys: [PostboxViewKey] = []
|
var combinedKeys: [PostboxViewKey] = []
|
||||||
combinedKeys.append(globalNotificationsKey)
|
combinedKeys.append(globalNotificationsKey)
|
||||||
|
|
||||||
|
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
||||||
|
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
||||||
|
|
||||||
return combineLatest(queue: .mainQueue(),
|
return combineLatest(queue: .mainQueue(),
|
||||||
context.account.viewTracker.peerView(groupId, updateData: true),
|
context.account.viewTracker.peerView(groupId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: groupId),
|
peerInfoAvailableMediaPanes(context: context, peerId: groupId),
|
||||||
context.account.postbox.combinedView(keys: combinedKeys),
|
context.account.postbox.combinedView(keys: combinedKeys),
|
||||||
status,
|
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
|
var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings
|
||||||
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
||||||
if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings {
|
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(
|
return PeerInfoScreenData(
|
||||||
peer: peerView.peers[groupId],
|
peer: peerView.peers[groupId],
|
||||||
cachedData: peerView.cachedData,
|
cachedData: peerView.cachedData,
|
||||||
@ -792,7 +823,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
linkedDiscussionPeer: discussionPeer,
|
linkedDiscussionPeer: discussionPeer,
|
||||||
members: membersData,
|
members: membersData,
|
||||||
encryptionKeyFingerprint: nil,
|
encryptionKeyFingerprint: nil,
|
||||||
globalSettings: nil
|
globalSettings: nil,
|
||||||
|
invitations: invitations
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1255,7 +1255,14 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
|||||||
interaction.editingOpenPublicLinkSetup()
|
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()
|
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()
|
interaction.editingOpenInviteLinksSetup()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -4544,6 +4558,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
strongSelf.view.endEditing(true)
|
||||||
let mode: ChannelVisibilityControllerMode
|
let mode: ChannelVisibilityControllerMode
|
||||||
if groupPeer.addressName != nil {
|
if groupPeer.addressName != nil {
|
||||||
let visibilityController = channelVisibilityController(context: strongSelf.context, peerId: groupPeer.id, mode: .generic, upgradedToSupergroup: { _, f in f() }, onDismissRemoveController: contactsController)
|
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>
|
let resolvedWallpaper: Signal<TelegramWallpaper?, NoError>
|
||||||
if case let .file(file) = presentationTheme.chat.defaultWallpaper, file.id == 0 {
|
if case let .file(id, _, _, _, _, _, slug, _, settings) = presentationTheme.chat.defaultWallpaper, id == 0 {
|
||||||
resolvedWallpaper = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
resolvedWallpaper = cachedWallpaper(account: account, slug: slug, settings: settings)
|
||||||
|> map { wallpaper in
|
|> map { wallpaper in
|
||||||
return wallpaper?.wallpaper
|
return wallpaper?.wallpaper
|
||||||
}
|
}
|
||||||
@ -102,15 +102,15 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager {
|
|||||||
|
|
||||||
return resolvedWallpaper
|
return resolvedWallpaper
|
||||||
|> mapToSignal { wallpaper -> Signal<(PresentationThemeReference, PresentationTheme?), NoError> in
|
|> 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] = []
|
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)))
|
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.file), representations: convertedRepresentations, alwaysShowThumbnailFirst: false, thumbnail: false, onlyFullSize: true, autoFetchFullSize: true, synchronousLoad: false)
|
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
|
|> mapToSignal { _, fullSizeData, complete -> Signal<(PresentationThemeReference, PresentationTheme?), NoError> in
|
||||||
guard complete, let fullSizeData = fullSizeData else {
|
guard complete, let fullSizeData = fullSizeData else {
|
||||||
return .complete()
|
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))
|
return .single((.cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: wallpaper, creatorAccountId: theme.isCreator ? account.id : nil)), presentationTheme))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user