mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '6c0d9ee7b698e281ce68b91f0fdc9d96e0325800'
This commit is contained in:
commit
536df22d0f
@ -5097,3 +5097,10 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Wallet.AccessDenied.Title" = "Please Allow Access";
|
||||
"Wallet.AccessDenied.Camera" = "TON Wallet needs access to your camera to take photos and videos.\n\nPlease go to Settings > Privacy > Camera and set TON Wallet to ON.";
|
||||
"Wallet.AccessDenied.Settings" = "Settings";
|
||||
|
||||
"GroupInfo.ShowMoreMembers_0" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_1" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_2" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_3_10" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_many" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_any" = "%@ more";
|
||||
|
@ -40,6 +40,8 @@ import AppBundle
|
||||
import Markdown
|
||||
import LocalizedPeerData
|
||||
|
||||
private let maxParticipantsDisplayedCount: Int32 = 50
|
||||
|
||||
private final class GroupInfoArguments {
|
||||
let context: AccountContext
|
||||
|
||||
@ -71,8 +73,9 @@ private final class GroupInfoArguments {
|
||||
let openLocation: (PeerGeoLocation) -> Void
|
||||
let changeLocation: () -> Void
|
||||
let displayLocationContextMenu: (String) -> Void
|
||||
let expandParticipants: () -> Void
|
||||
|
||||
init(context: AccountContext, avatarAndNameInfoContext: ItemListAvatarAndNameInfoItemContext, tapAvatarAction: @escaping () -> Void, changeProfilePhoto: @escaping () -> Void, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, ViewControllerPresentationArguments) -> Void, changeNotificationMuteSettings: @escaping () -> Void, openPreHistory: @escaping () -> Void, openSharedMedia: @escaping () -> Void, openAdministrators: @escaping () -> Void, openPermissions: @escaping () -> Void, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updateEditingDescriptionText: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, addMember: @escaping () -> Void, promotePeer: @escaping (RenderedChannelParticipant) -> Void, restrictPeer: @escaping (RenderedChannelParticipant) -> Void, removePeer: @escaping (PeerId) -> Void, leave: @escaping () -> Void, displayUsernameShareMenu: @escaping (String) -> Void, displayUsernameContextMenu: @escaping (String) -> Void, displayAboutContextMenu: @escaping (String) -> Void, aboutLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void, openStickerPackSetup: @escaping () -> Void, openGroupTypeSetup: @escaping () -> Void, openLinkedChannelSetup: @escaping () -> Void, openLocation: @escaping (PeerGeoLocation) -> Void, changeLocation: @escaping () -> Void, displayLocationContextMenu: @escaping (String) -> Void) {
|
||||
init(context: AccountContext, avatarAndNameInfoContext: ItemListAvatarAndNameInfoItemContext, tapAvatarAction: @escaping () -> Void, changeProfilePhoto: @escaping () -> Void, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, ViewControllerPresentationArguments) -> Void, changeNotificationMuteSettings: @escaping () -> Void, openPreHistory: @escaping () -> Void, openSharedMedia: @escaping () -> Void, openAdministrators: @escaping () -> Void, openPermissions: @escaping () -> Void, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updateEditingDescriptionText: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, addMember: @escaping () -> Void, promotePeer: @escaping (RenderedChannelParticipant) -> Void, restrictPeer: @escaping (RenderedChannelParticipant) -> Void, removePeer: @escaping (PeerId) -> Void, leave: @escaping () -> Void, displayUsernameShareMenu: @escaping (String) -> Void, displayUsernameContextMenu: @escaping (String) -> Void, displayAboutContextMenu: @escaping (String) -> Void, aboutLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void, openStickerPackSetup: @escaping () -> Void, openGroupTypeSetup: @escaping () -> Void, openLinkedChannelSetup: @escaping () -> Void, openLocation: @escaping (PeerGeoLocation) -> Void, changeLocation: @escaping () -> Void, displayLocationContextMenu: @escaping (String) -> Void, expandParticipants: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.avatarAndNameInfoContext = avatarAndNameInfoContext
|
||||
self.tapAvatarAction = tapAvatarAction
|
||||
@ -102,6 +105,7 @@ private final class GroupInfoArguments {
|
||||
self.openLocation = openLocation
|
||||
self.changeLocation = changeLocation
|
||||
self.displayLocationContextMenu = displayLocationContextMenu
|
||||
self.expandParticipants = expandParticipants
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,6 +193,7 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
case permissions(PresentationTheme, String, String)
|
||||
case addMember(PresentationTheme, String, editing: Bool)
|
||||
case member(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, index: Int, peerId: PeerId, peer: Peer, participant: RenderedChannelParticipant?, presence: PeerPresence?, memberStatus: GroupInfoMemberStatus, editing: ItemListPeerItemEditing, revealActions: [ParticipantRevealAction], enabled: Bool, selectable: Bool)
|
||||
case expand(PresentationTheme, String)
|
||||
case leave(PresentationTheme, String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
@ -203,7 +208,7 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
return GroupInfoSection.sharedMediaAndNotifications.rawValue
|
||||
case .permissions, .administrators:
|
||||
return GroupInfoSection.memberManagement.rawValue
|
||||
case .addMember, .member:
|
||||
case .addMember, .member, .expand:
|
||||
return GroupInfoSection.members.rawValue
|
||||
case .leave:
|
||||
return GroupInfoSection.leave.rawValue
|
||||
@ -213,40 +218,40 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
static func ==(lhs: GroupInfoEntry, rhs: GroupInfoEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsCachedData, lhsState, lhsUpdatingAvatar):
|
||||
if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs {
|
||||
if lhsTheme !== rhsTheme {
|
||||
return false
|
||||
}
|
||||
if lhsStrings !== rhsStrings {
|
||||
return false
|
||||
}
|
||||
if lhsDateTimeFormat != rhsDateTimeFormat {
|
||||
return false
|
||||
}
|
||||
if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer {
|
||||
if !lhsPeer.isEqual(rhsPeer) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsPeer == nil) != (rhsPeer != nil) {
|
||||
return false
|
||||
}
|
||||
if let lhsCachedData = lhsCachedData, let rhsCachedData = rhsCachedData {
|
||||
if !lhsCachedData.isEqual(to: rhsCachedData) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsCachedData != nil) != (rhsCachedData != nil) {
|
||||
return false
|
||||
}
|
||||
if lhsState != rhsState {
|
||||
return false
|
||||
}
|
||||
if lhsUpdatingAvatar != rhsUpdatingAvatar {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs {
|
||||
if lhsTheme !== rhsTheme {
|
||||
return false
|
||||
}
|
||||
if lhsStrings !== rhsStrings {
|
||||
return false
|
||||
}
|
||||
if lhsDateTimeFormat != rhsDateTimeFormat {
|
||||
return false
|
||||
}
|
||||
if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer {
|
||||
if !lhsPeer.isEqual(rhsPeer) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsPeer == nil) != (rhsPeer != nil) {
|
||||
return false
|
||||
}
|
||||
if let lhsCachedData = lhsCachedData, let rhsCachedData = rhsCachedData {
|
||||
if !lhsCachedData.isEqual(to: rhsCachedData) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsCachedData != nil) != (rhsCachedData != nil) {
|
||||
return false
|
||||
}
|
||||
if lhsState != rhsState {
|
||||
return false
|
||||
}
|
||||
if lhsUpdatingAvatar != rhsUpdatingAvatar {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .setGroupPhoto(lhsTheme, lhsText):
|
||||
if case let .setGroupPhoto(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
@ -419,6 +424,12 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .expand(lhsTheme, lhsText):
|
||||
if case let .expand(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,8 +480,10 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
return 16
|
||||
case let .member(_, _, _, _, index, _, _, _, _, _, _, _, _, _):
|
||||
return 20 + index
|
||||
case .leave:
|
||||
case .expand:
|
||||
return 200000 + 1
|
||||
case .leave:
|
||||
return 200000 + 2
|
||||
}
|
||||
}
|
||||
|
||||
@ -592,6 +605,10 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
}, removePeer: { peerId in
|
||||
arguments.removePeer(peerId)
|
||||
})
|
||||
case let .expand(theme, title):
|
||||
return ItemListPeerActionItem(theme: theme, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: {
|
||||
arguments.expandParticipants()
|
||||
})
|
||||
case let .leave(theme, title):
|
||||
return ItemListActionItem(theme: theme, title: title, kind: .destructive, alignment: .center, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.leave()
|
||||
@ -627,6 +644,7 @@ private struct GroupInfoState: Equatable {
|
||||
let editingState: GroupInfoEditingState?
|
||||
let updatingName: ItemListAvatarAndNameInfoItemName?
|
||||
let peerIdWithRevealedOptions: PeerId?
|
||||
let expandedParticipants: Bool
|
||||
|
||||
let temporaryParticipants: [TemporaryParticipant]
|
||||
let successfullyAddedParticipantIds: Set<PeerId>
|
||||
@ -649,6 +667,9 @@ private struct GroupInfoState: Equatable {
|
||||
if lhs.peerIdWithRevealedOptions != rhs.peerIdWithRevealedOptions {
|
||||
return false
|
||||
}
|
||||
if lhs.expandedParticipants != rhs.expandedParticipants {
|
||||
return false
|
||||
}
|
||||
if lhs.temporaryParticipants != rhs.temporaryParticipants {
|
||||
return false
|
||||
}
|
||||
@ -668,39 +689,43 @@ private struct GroupInfoState: Equatable {
|
||||
}
|
||||
|
||||
func withUpdatedUpdatingAvatar(_ updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedEditingState(_ editingState: GroupInfoEditingState?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedUpdatingName(_ updatingName: ItemListAvatarAndNameInfoItemName?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedExpandedParticipants(_ expandedParticipants: Bool) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedTemporaryParticipants(_ temporaryParticipants: [TemporaryParticipant]) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedSuccessfullyAddedParticipantIds(_ successfullyAddedParticipantIds: Set<PeerId>) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedRemovingParticipantIds(_ removingParticipantIds: Set<PeerId>) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedSavingData(_ savingData: Bool) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedSearchingMembers(_ searchingMembers: Bool) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: searchingMembers)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1157,8 +1182,11 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
sortedParticipants = updatedParticipants
|
||||
}
|
||||
|
||||
for i in 0 ..< sortedParticipants.count {
|
||||
let participant = sortedParticipants[i]
|
||||
var expand = state.expandedParticipants
|
||||
let participants = expand ? sortedParticipants : Array(sortedParticipants.prefix(Int(maxParticipantsDisplayedCount)))
|
||||
|
||||
for i in 0 ..< participants.count {
|
||||
let participant = participants[i]
|
||||
let memberStatus: GroupInfoMemberStatus
|
||||
switch participant.participant {
|
||||
case let .creator(_, rank):
|
||||
@ -1220,6 +1248,10 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
|
||||
entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, index: i, peerId: participant.peer.id, peer: participant.peer, participant: participant, presence: participant.presences[participant.peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: !peerActions.isEmpty, editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == participant.peer.id), revealActions: peerActions, enabled: true, selectable: participant.peer.id != account.peerId))
|
||||
}
|
||||
|
||||
if !expand && memberCount > maxParticipantsDisplayedCount {
|
||||
entries.append(GroupInfoEntry.expand(presentationData.theme, presentationData.strings.GroupInfo_ShowMoreMembers(Int32(memberCount - maxParticipantsDisplayedCount))))
|
||||
}
|
||||
}
|
||||
|
||||
if let group = view.peers[view.peerId] as? TelegramGroup {
|
||||
@ -1288,8 +1320,8 @@ private func valuesRequiringUpdate(state: GroupInfoState, view: PeerView) -> (ti
|
||||
}
|
||||
|
||||
public func groupInfoController(context: AccountContext, peerId originalPeerId: PeerId, membersLoaded: @escaping () -> Void = {}) -> ViewController {
|
||||
let statePromise = ValuePromise(GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false))
|
||||
let statePromise = ValuePromise(GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, expandedParticipants: false, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, expandedParticipants: false, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false))
|
||||
let updateState: ((GroupInfoState) -> GroupInfoState) -> Void = { f in
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
@ -2077,6 +2109,10 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
||||
})
|
||||
}, displayLocationContextMenu: { text in
|
||||
displayCopyContextMenuImpl?(text, .location)
|
||||
}, expandParticipants: {
|
||||
updateState {
|
||||
$0.withUpdatedExpandedParticipants(true)
|
||||
}
|
||||
})
|
||||
|
||||
let loadMoreControl = Atomic<(PeerId, PeerChannelMemberCategoryControl)?>(value: nil)
|
||||
|
@ -933,6 +933,9 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
|
||||
}
|
||||
|
||||
let controller = ItemListController(context: context, state: signal)
|
||||
if isModal {
|
||||
controller.navigationPresentation = .modal
|
||||
}
|
||||
presentControllerImpl = { [weak controller] c, contextType, a in
|
||||
controller?.present(c, in: contextType, with: a)
|
||||
}
|
||||
|
@ -584,7 +584,13 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
moreImpl?()
|
||||
})
|
||||
|
||||
let defaultThemes: [PresentationThemeReference] = [.builtin(.dayClassic), .builtin(.day), .builtin(.night), .builtin(.nightAccent)]
|
||||
var defaultThemes: [PresentationThemeReference] = []
|
||||
if presentationData.autoNightModeTriggered {
|
||||
} else {
|
||||
defaultThemes.append(contentsOf: [.builtin(.dayClassic), .builtin(.day)])
|
||||
}
|
||||
defaultThemes.append(contentsOf: [.builtin(.night), .builtin(.nightAccent)])
|
||||
|
||||
let cloudThemes: [PresentationThemeReference] = cloudThemes.map { .cloud(PresentationCloudTheme(theme: $0, resolvedWallpaper: nil)) }
|
||||
|
||||
var availableThemes = defaultThemes
|
||||
@ -667,7 +673,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
chatWallpaper = resolvedWallpaper ?? presentationTheme.chat.defaultWallpaper
|
||||
}
|
||||
|
||||
return PresentationThemeSettings(chatWallpaper: chatWallpaper, theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(chatWallpaper: chatWallpaper, theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})
|
||||
})
|
||||
}).start()
|
||||
|
@ -156,7 +156,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
|
||||
scrollIndicatorColor: UIColor(white: 1.0, alpha: 0.3),
|
||||
pageIndicatorInactiveColor: mainSecondaryTextColor.withAlphaComponent(0.4),
|
||||
inputClearButtonColor: mainSecondaryColor,
|
||||
itemBarChart: PresentationThemeItemBarChart(color1: accentColor, color2: UIColor(rgb: 0x929196), color3: UIColor(rgb: 0x333333))
|
||||
itemBarChart: PresentationThemeItemBarChart(color1: accentColor, color2: mainSecondaryTextColor.withAlphaComponent(0.5), color3: accentColor.withMultiplied(hue: 1.038, saturation: 0.329, brightness: 0.33))
|
||||
)
|
||||
|
||||
let chatList = PresentationThemeChatList(
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case navigationPlayerMaximizedRateActiveIcon
|
||||
case navigationPlayerMaximizedRateInactiveIcon
|
||||
|
||||
case itemListDownArrow
|
||||
case itemListDisclosureArrow
|
||||
case itemListCheckIcon
|
||||
case itemListSecondaryCheckIcon
|
||||
|
@ -21,6 +21,12 @@ public func generateItemListPlusIcon(_ color: UIColor) -> UIImage? {
|
||||
}
|
||||
|
||||
public struct PresentationResourcesItemList {
|
||||
public static func downArrowImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListDownArrow.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Search/DownButton"), color: theme.list.itemAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func disclosureArrowImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListDisclosureArrow.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Item List/DisclosureArrow"), color: theme.list.disclosureArrowColor)
|
||||
|
@ -1983,6 +1983,10 @@ final class SharedApplicationContext {
|
||||
var carPlayOptions = options
|
||||
carPlayOptions.insert(.allowInCarPlay)
|
||||
|
||||
if #available(iOS 13.2, *) {
|
||||
carPlayOptions.insert(.allowAnnouncement)
|
||||
}
|
||||
|
||||
unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
replyLegacyMessageCategory = UNNotificationCategory(identifier: "r", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
|
@ -7805,23 +7805,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: peer, chatPeer: peer, action: .clearCacheSuggestion, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
|
||||
var presented = false
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ClearCache_FreeSpace, color: .accent, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
let controller = storageUsageController(context: strongSelf.context, isModal: true)
|
||||
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet), blockInteraction: true)
|
||||
if let strongSelf = self, !presented {
|
||||
presented = true
|
||||
strongSelf.push(storageUsageController(context: strongSelf.context, isModal: true))
|
||||
}
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
})
|
||||
])])
|
||||
self.chatDisplayNode.dismissInput()
|
||||
self.presentInGlobalOverlay(actionSheet)
|
||||
//self.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 11.0, iOS 11.0, *)
|
||||
|
@ -11,13 +11,17 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
}
|
||||
var entries: [ChatHistoryEntry] = []
|
||||
var adminRanks: [PeerId: CachedChannelAdminRank] = [:]
|
||||
var stickersEnabled = true
|
||||
if case let .peer(peerId) = location, peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
for additionalEntry in view.additionalData {
|
||||
if case let .cacheEntry(id, data) = additionalEntry {
|
||||
if id == cachedChannelAdminRanksEntryId(peerId: peerId), let data = data as? CachedChannelAdminRanks {
|
||||
adminRanks = data.ranks
|
||||
}
|
||||
break
|
||||
} else if case let .peer(_, peer) = additionalEntry, let channel = peer as? TelegramChannel {
|
||||
if let defaultBannedRights = channel.defaultBannedRights, defaultBannedRights.flags.contains(.banSendStickers) {
|
||||
stickersEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,7 +46,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
|
||||
var contentTypeHint: ChatMessageEntryContentType = .generic
|
||||
if presentationData.largeEmoji, entry.message.media.isEmpty {
|
||||
if entry.message.text.count == 1, let _ = associatedData.animatedEmojiStickers[entry.message.text.basicEmoji.0] {
|
||||
if stickersEnabled && entry.message.text.count == 1, let _ = associatedData.animatedEmojiStickers[entry.message.text.basicEmoji.0] {
|
||||
contentTypeHint = .animatedEmoji
|
||||
} else if messageIsElligibleForLargeEmoji(entry.message) {
|
||||
contentTypeHint = .largeEmoji
|
||||
|
@ -405,10 +405,15 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
||||
}
|
||||
|
||||
if viewClassName == ChatMessageBubbleItemNode.self && self.presentationData.largeEmoji && self.message.media.isEmpty {
|
||||
if self.message.text.count == 1, let _ = self.associatedData.animatedEmojiStickers[self.message.text.basicEmoji.0] {
|
||||
viewClassName = ChatMessageAnimatedStickerItemNode.self
|
||||
} else if messageIsElligibleForLargeEmoji(self.message) {
|
||||
viewClassName = ChatMessageStickerItemNode.self
|
||||
if case let .message(_, _, _, attributes) = self.content {
|
||||
switch attributes.contentTypeHint {
|
||||
case .largeEmoji:
|
||||
viewClassName = ChatMessageStickerItemNode.self
|
||||
case .animatedEmoji:
|
||||
viewClassName = ChatMessageAnimatedStickerItemNode.self
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@ -31,7 +31,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private let effectView: UIView
|
||||
|
||||
private let animationBackgroundColor: UIColor
|
||||
|
||||
|
||||
private var originalRemainingSeconds: Int
|
||||
private var remainingSeconds: Int
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
@ -261,7 +261,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
let firstLayout = self.validLayout == nil
|
||||
self.validLayout = layout
|
||||
|
||||
let leftInset: CGFloat = 50.0
|
||||
var leftInset: CGFloat = 50.0
|
||||
if let animationNode = self.animationNode, let iconSize = animationNode.preferredSize() {
|
||||
if iconSize.width > leftInset {
|
||||
leftInset = iconSize.width - 8.0
|
||||
}
|
||||
}
|
||||
let rightInset: CGFloat = 16.0
|
||||
var contentHeight: CGFloat = 20.0
|
||||
|
||||
|
Binary file not shown.
@ -61,7 +61,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
case address(WalletTheme, String, String)
|
||||
case addressInfo(WalletTheme, String)
|
||||
case commentHeader(WalletTheme, String)
|
||||
case comment(WalletTheme, String, String)
|
||||
case comment(WalletTheme, String, String, Bool)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
@ -131,8 +131,8 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .comment(lhsTheme, lhsPlaceholder, lhsText):
|
||||
if case let .comment(rhsTheme, rhsPlaceholder, rhsText) = rhs, lhsTheme === rhsTheme, lhsPlaceholder == rhsPlaceholder, lhsText == rhsText {
|
||||
case let .comment(lhsTheme, lhsPlaceholder, lhsText, lhsSendEnabled):
|
||||
if case let .comment(rhsTheme, rhsPlaceholder, rhsText, rhsSendEnabled) = rhs, lhsTheme === rhsTheme, lhsPlaceholder == rhsPlaceholder, lhsText == rhsText, lhsSendEnabled == rhsSendEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -245,7 +245,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section)
|
||||
case let .commentHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||
case let .comment(theme, placeholder, value):
|
||||
case let .comment(theme, placeholder, value, sendEnabled):
|
||||
return ItemListMultilineInputItem(theme: theme, text: value, placeholder: placeholder, maxLength: ItemListMultilineInputItemTextLimit(value: walletTextLimit, display: true, mode: .bytes), sectionId: self.section, style: .blocks, returnKeyType: .send, textUpdated: { text in
|
||||
arguments.updateText(WalletSendScreenEntryTag.comment, text)
|
||||
}, updatedFocus: { focus in
|
||||
@ -253,7 +253,9 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
arguments.scrollToBottom()
|
||||
}
|
||||
}, tag: WalletSendScreenEntryTag.comment, action: {
|
||||
arguments.proceed()
|
||||
if sendEnabled {
|
||||
arguments.proceed()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -265,7 +267,7 @@ private struct WalletSendScreenState: Equatable {
|
||||
var comment: String
|
||||
}
|
||||
|
||||
private func walletSendScreenEntries(presentationData: WalletPresentationData, balance: Int64?, state: WalletSendScreenState) -> [WalletSendScreenEntry] {
|
||||
private func walletSendScreenEntries(presentationData: WalletPresentationData, balance: Int64?, state: WalletSendScreenState, sendEnabled: Bool) -> [WalletSendScreenEntry] {
|
||||
if balance == nil {
|
||||
return []
|
||||
}
|
||||
@ -281,7 +283,7 @@ private func walletSendScreenEntries(presentationData: WalletPresentationData, b
|
||||
entries.append(.addressInfo(presentationData.theme, presentationData.strings.Wallet_Send_AddressInfo))
|
||||
|
||||
entries.append(.commentHeader(presentationData.theme, presentationData.strings.Wallet_Receive_CommentHeader))
|
||||
entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment))
|
||||
entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment, sendEnabled))
|
||||
return entries
|
||||
}
|
||||
|
||||
@ -374,6 +376,10 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
let presentationData = context.presentationData
|
||||
let state = stateValue.with { $0 }
|
||||
let amount = amountValue(state.amount)
|
||||
guard amount > 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
let commentData = state.comment.data(using: .utf8)
|
||||
let formattedAddress = String(state.address[state.address.startIndex..<state.address.index(state.address.startIndex, offsetBy: walletAddressLength / 2)] + " \n " + state.address[state.address.index(state.address.startIndex, offsetBy: walletAddressLength / 2)..<state.address.endIndex])
|
||||
let destinationAddress = state.address
|
||||
@ -571,7 +577,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Wallet_Send_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Wallet_Navigation_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: walletState?.balance, state: state), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: emptyItem, animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: walletState?.balance, state: state, sendEnabled: sendEnabled), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: emptyItem, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
@ -448,12 +448,12 @@ public final class WalletStrings: Equatable {
|
||||
public var Wallet_SecureStorageReset_Title: String { return self._s[218]! }
|
||||
public var Wallet_Receive_CommentHeader: String { return self._s[219]! }
|
||||
public var Wallet_Info_ReceiveGrams: String { return self._s[220]! }
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
}
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
|
Loading…
x
Reference in New Issue
Block a user