Merge commit '6c0d9ee7b698e281ce68b91f0fdc9d96e0325800'

This commit is contained in:
Ali 2019-11-08 17:55:01 +04:00
commit 536df22d0f
17 changed files with 4047 additions and 3960 deletions

View File

@ -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";

View File

@ -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)

View File

@ -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)
}

View File

@ -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()

View File

@ -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(

View File

@ -31,6 +31,7 @@ public enum PresentationResourceKey: Int32 {
case navigationPlayerMaximizedRateActiveIcon
case navigationPlayerMaximizedRateInactiveIcon
case itemListDownArrow
case itemListDisclosureArrow
case itemListCheckIcon
case itemListSecondaryCheckIcon

View File

@ -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)

View File

@ -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)

View File

@ -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, *)

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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

View File

@ -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))
}

View File

@ -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)