diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 5898cbb4ee..28fe4808db 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -11800,9 +11800,12 @@ Sorry for the inconvenience."; "SendInviteLink.TitleUpgradeToPremium" = "Upgrade to Premium"; "SendInviteLink.TextContactsAndPremiumOneUser" = "**%@** accepts invitations to groups from contacts and **Premium** users."; +"SendInviteLink.ChannelTextContactsAndPremiumOneUser" = "**%@** accepts invitations to channels from contacts and **Premium** users."; "SendInviteLink.TextContactsAndPremiumMultipleUsers_1" = "{user_list}, and **%d** more person only accept invitations to groups from contacts and **Premium** users."; "SendInviteLink.TextContactsAndPremiumMultipleUsers_any" = "{user_list}, and **%d** more people only accept invitations to groups from contacts and **Premium** users."; +"SendInviteLink.ChannelTextContactsAndPremiumMultipleUsers_1" = "{user_list}, and **%d** more person only accept invitations to channels from contacts and **Premium** users."; +"SendInviteLink.ChannelTextContactsAndPremiumMultipleUsers_any" = "{user_list}, and **%d** more people only accept invitations to channels from contacts and **Premium** users."; "SendInviteLink.SubscribeToPremiumButton" = "Subscribe to Telegram Premium"; "SendInviteLink.PremiumOrSendSectionSeparator" = "or"; diff --git a/submodules/ContactListUI/Sources/ContactContextMenus.swift b/submodules/ContactListUI/Sources/ContactContextMenus.swift index 216be65305..8e8815dc86 100644 --- a/submodules/ContactListUI/Sources/ContactContextMenus.swift +++ b/submodules/ContactListUI/Sources/ContactContextMenus.swift @@ -188,10 +188,12 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con let presentationData = context.sharedContext.currentPresentationData.with { $0 } let text: String switch error { - case .limitExceeded: - text = presentationData.strings.TwoStepAuth_FloodError - default: - text = presentationData.strings.Login_UnknownError + case .limitExceeded: + text = presentationData.strings.TwoStepAuth_FloodError + case .premiumRequired: + text = presentationData.strings.Conversation_SendMessageErrorNonPremiumForbidden(peer.compactDisplayTitle).string + default: + text = presentationData.strings.Login_UnknownError } contactsController.present(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) } diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift index 588c242c38..42a9faa2f3 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift @@ -1510,8 +1510,19 @@ public func channelAdminController(context: AccountContext, updatedPresentationD } updateRightsDisposable.set((context.engine.peers.addGroupAdmin(peerId: peerId, adminId: adminId) |> deliverOnMainQueue).start(error: { error in - if case let .addMemberError(error) = error, case .privacy = error, let admin = adminPeer { - presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + if case let .addMemberError(error) = error, case let .privacy(privacy) = error, let admin = adminPeer { + if let failedPeer = privacy?.forbiddenPeers.first { + let _ = (context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.ExportedInvitation(id: group.id) + ) + |> deliverOnMainQueue).startStandalone(next: { exportedInvitation in + let _ = exportedInvitation + let inviteScreen = SendInviteLinkScreen(context: context, peer: .legacyGroup(group), link: exportedInvitation?.link, peers: [failedPeer]) + pushControllerImpl?(inviteScreen) + }) + } else { + presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + } } else if case .adminsTooMuch = error { presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Group_ErrorAdminsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift index 49341c10bf..cbc787a359 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift @@ -518,7 +518,7 @@ public func channelMembersController(context: AccountContext, updatedPresentatio ) |> deliverOnMainQueue).start(next: { chatPeer, exportedInvitation, members in let disabledIds = members?.compactMap({$0.peer.id}) ?? [] - let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: [], filters: [.excludeSelf, .disable(disabledIds)], onlyWriteable: true)) + let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: [], filters: [.excludeSelf, .disable(disabledIds)], onlyWriteable: true, isGroupInvitation: true)) addMembersDisposable.set(( contactsController.result diff --git a/submodules/PremiumUI/Sources/CreateGiveawayController.swift b/submodules/PremiumUI/Sources/CreateGiveawayController.swift index 846d11ad8f..9976989cf2 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayController.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayController.swift @@ -854,7 +854,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio let expiryDate = calendar.date(byAdding: .day, value: 3, to: calendar.date(from: components)!)! let expiryTime = Int32(expiryDate.timeIntervalSince1970) - let minDate = currentTime + 60 * 30 + let minDate = currentTime + 60 * 1 let maxDate = currentTime + context.userLimits.maxGiveawayPeriodSeconds let initialState: CreateGiveawayControllerState = CreateGiveawayControllerState(mode: .giveaway, subscriptions: initialSubscriptions, time: expiryTime) @@ -1099,7 +1099,9 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio let quantity: Int32 switch state.mode { case .giveaway: - purpose = .giveaway(boostPeer: peerId, additionalPeerIds: state.channels.filter { $0 != peerId }, countries: state.countries, onlyNewSubscribers: state.onlyNewEligible, showWinners: state.showWinners, prizeDescription: state.prizeDescription.isEmpty ? nil : state.prizeDescription, randomId: Int64.random(in: .min ..< .max), untilDate: state.time, currency: currency, amount: amount) + let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + let untilDate = max(state.time, currentTime + 60) + purpose = .giveaway(boostPeer: peerId, additionalPeerIds: state.channels.filter { $0 != peerId }, countries: state.countries, onlyNewSubscribers: state.onlyNewEligible, showWinners: state.showWinners, prizeDescription: state.prizeDescription.isEmpty ? nil : state.prizeDescription, randomId: Int64.random(in: .min ..< .max), untilDate: untilDate, currency: currency, amount: amount) quantity = selectedProduct.giftOption.storeQuantity case .gift: purpose = .giftCode(peerIds: state.peers, boostPeer: peerId, currency: currency, amount: amount) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift index 83ad6be77b..1ac7a60ab0 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift @@ -230,7 +230,7 @@ private class AdMessagesHistoryContextImpl { self.sponsorInfo = try container.decodeIfPresent(String.self, forKey: .sponsorInfo) self.additionalInfo = try container.decodeIfPresent(String.self, forKey: .additionalInfo) - self.canReport = try container.decodeIfPresent(Bool.self, forKey: .displayAvatar) ?? false + self.canReport = try container.decodeIfPresent(Bool.self, forKey: .canReport) ?? false } public func encode(to encoder: Encoder) throws { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift index eddd975006..dfbda21313 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift @@ -53,18 +53,18 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) { if let group = peer as? TelegramGroup { return account.network.request(Api.functions.messages.addChatUser(chatId: group.id.id._internalGetInt64Value(), userId: inputUser, fwdLimit: 100)) - |> mapError { error -> AddGroupMemberError in + |> `catch` { error -> Signal in switch error.errorDescription { case "USERS_TOO_MUCH": - return .groupFull + return .fail(.groupFull) case "USER_PRIVACY_RESTRICTED": - return .privacy(nil) + return .fail(.privacy(nil)) case "USER_CHANNELS_TOO_MUCH": - return .tooManyChannels + return .fail(.tooManyChannels) case "USER_NOT_MUTUAL_CONTACT": - return .notMutualContact + return .fail(.privacy(nil)) default: - return .generic + return .fail(.generic) } } |> mapToSignal { result -> Signal in diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBusinessHoursItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBusinessHoursItem.swift index 87b007469a..c12ce928a7 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBusinessHoursItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenBusinessHoursItem.swift @@ -399,8 +399,25 @@ private final class PeerInfoScreenBusinessHoursItemNode: PeerInfoScreenItemNode containerSize: CGSize(width: width - sideInset - dayRightInset, height: 100.0) ) - var timezoneSwitchButtonSize: CGSize? + var hasTimezoneDependentEntries = false if item.businessHours.timezoneId != self.currentTimezone.identifier { + var currentCalendar = Calendar(identifier: .gregorian) + currentCalendar.timeZone = TimeZone(identifier: item.businessHours.timezoneId) ?? TimeZone.current + + let timezoneOffsetMinutes = (self.currentTimezone.secondsFromGMT() - currentCalendar.timeZone.secondsFromGMT()) / 60 + + for i in 0 ..< businessDays.count { + let businessHoursTextLocal = dayBusinessHoursText(presentationData: presentationData, day: businessDays[i], offsetMinutes: 0) + let businessHoursTextOffset = dayBusinessHoursText(presentationData: presentationData, day: businessDays[i], offsetMinutes: timezoneOffsetMinutes) + if businessHoursTextOffset != businessHoursTextLocal { + hasTimezoneDependentEntries = true + break + } + } + } + + var timezoneSwitchButtonSize: CGSize? + if hasTimezoneDependentEntries { let timezoneSwitchButton: ComponentView if let current = self.timezoneSwitchButton { timezoneSwitchButton = current diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoMembers.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoMembers.swift index 7b8ac46a98..801d58db58 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoMembers.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoMembers.swift @@ -309,7 +309,8 @@ private final class PeerInfoMembersContextImpl { guard let strongSelf = self else { return } - if let _ = strongSelf.removingMemberIds.removeValue(forKey: memberId) { + if let disposable = strongSelf.removingMemberIds.removeValue(forKey: memberId) { + disposable.dispose() strongSelf.pushState() } } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 69a9adc75c..f24dd49473 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -6535,10 +6535,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } let text: String switch error { - case .limitExceeded: - text = strongSelf.presentationData.strings.TwoStepAuth_FloodError - default: - text = strongSelf.presentationData.strings.Login_UnknownError + case .limitExceeded: + text = strongSelf.presentationData.strings.TwoStepAuth_FloodError + case .premiumRequired: + text = strongSelf.presentationData.strings.Conversation_SendMessageErrorNonPremiumForbidden(displayTitle).string + default: + text = strongSelf.presentationData.strings.Login_UnknownError } strongSelf.controller?.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) })) diff --git a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift index b4c33abae9..b75ef97dde 100644 --- a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift +++ b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift @@ -22,17 +22,20 @@ private final class SendInviteLinkScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext + let peer: EnginePeer let link: String? let peers: [TelegramForbiddenInvitePeer] let peerPresences: [EnginePeer.Id: EnginePeer.Presence] init( context: AccountContext, + peer: EnginePeer, link: String?, peers: [TelegramForbiddenInvitePeer], peerPresences: [EnginePeer.Id: EnginePeer.Presence] ) { self.context = context + self.peer = peer self.link = link self.peers = peers self.peerPresences = peerPresences @@ -412,7 +415,11 @@ private final class SendInviteLinkScreenComponent: Component { let text: String if premiumRestrictedUsers.count == 1 { - text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string + if case let .channel(channel) = component.peer, case .broadcast = channel.info { + text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string + } else { + text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string + } } else { let extraCount = premiumRestrictedUsers.count - 3 @@ -439,9 +446,17 @@ private final class SendInviteLinkScreenComponent: Component { } if extraCount >= 1 { - text = environment.strings.SendInviteLink_TextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) + if case let .channel(channel) = component.peer, case .broadcast = channel.info { + text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) + } else { + text = environment.strings.SendInviteLink_TextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) + } } else { - text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(peersText).string + if case let .channel(channel) = component.peer, case .broadcast = channel.info { + text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumOneUser(peersText).string + } else { + text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(peersText).string + } } } @@ -1066,7 +1081,7 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer { self.link = link self.peers = peers - super.init(context: context, component: SendInviteLinkScreenComponent(context: context, link: link, peers: peers, peerPresences: [:]), navigationBarAppearance: .none) + super.init(context: context, component: SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: [:]), navigationBarAppearance: .none) self.statusBar.statusBarStyle = .Ignore self.navigationPresentation = .flatModal @@ -1085,7 +1100,7 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer { parsedPresences[id] = presence } } - self.updateComponent(component: AnyComponent(SendInviteLinkScreenComponent(context: context, link: link, peers: peers, peerPresences: parsedPresences)), transition: .immediate) + self.updateComponent(component: AnyComponent(SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: parsedPresences)), transition: .immediate) }) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 0c5f28a39a..9ea3450b07 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -7637,7 +7637,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }) if let editMessage = interfaceState.editMessage, let message = combinedInitialData.initialData?.associatedMessages[editMessage.messageId] { - updated = updatedChatEditInterfaceMessageState(state: updated, message: message) + let (updatedState, updatedPreviewQueryState) = updatedChatEditInterfaceMessageState(context: strongSelf.context, state: updated, message: message) + updated = updatedState + strongSelf.editingUrlPreviewQueryState = updatedPreviewQueryState } updated = updated.updatedSlowmodeState(slowmodeState) return updated @@ -8972,7 +8974,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return interfaceState.withUpdatedEditMessage(ChatEditMessageState(messageId: messageId, inputState: ChatTextInputState(inputText: inputText), disableUrlPreviews: disableUrlPreviews, inputTextMaxLength: inputTextMaxLength)) } - updated = updatedChatEditInterfaceMessageState(state: updated, message: message) + let (updatedState, updatedPreviewQueryState) = updatedChatEditInterfaceMessageState(context: strongSelf.context, state: updated, message: message) + updated = updatedState + strongSelf.editingUrlPreviewQueryState = updatedPreviewQueryState + updated = updated.updatedInputMode({ _ in return .text }) diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index d6e369d8b2..769b7768d1 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -419,7 +419,7 @@ func messageMediaEditingOptions(message: Message) -> MessageMediaEditingOptions return options } -func updatedChatEditInterfaceMessageState(state: ChatPresentationInterfaceState, message: Message) -> ChatPresentationInterfaceState { +func updatedChatEditInterfaceMessageState(context: AccountContext, state: ChatPresentationInterfaceState, message: Message) -> (ChatPresentationInterfaceState, (UrlPreviewState?, Disposable)?) { var updated = state for media in message.media { if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { @@ -451,7 +451,16 @@ func updatedChatEditInterfaceMessageState(state: ChatPresentationInterfaceState, content = .media(mediaOptions: messageMediaEditingOptions(message: message)) } updated = updated.updatedEditMessageState(ChatEditInterfaceMessageState(content: content, mediaReference: nil)) - return updated + + var previewState: (UrlPreviewState?, Disposable)? + if let (updatedEditingUrlPreviewState, _) = urlPreviewStateForInputText(updated.interfaceState.editMessage?.inputState.inputText, context: context, currentQuery: nil, forPeerId: state.chatLocation.peerId) { + previewState = (updatedEditingUrlPreviewState, EmptyDisposable) + } + + return ( + updated, + previewState + ) } func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, messages: [Message], controllerInteraction: ChatControllerInteraction?, selectAll: Bool, interfaceInteraction: ChatPanelInterfaceInteraction?, readStats: MessageReadStats? = nil, messageNode: ChatMessageItemView? = nil) -> Signal {