Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin
2021-10-28 23:32:22 +04:00
9 changed files with 444 additions and 158 deletions

View File

@@ -6998,8 +6998,8 @@ Sorry for the inconvenience.";
"MessageCalendar.Title" = "Calendar"; "MessageCalendar.Title" = "Calendar";
"MessageCalendar.DaysSelectedTitle_1" = "1 day selected"; "MessageCalendar.DaysSelectedTitle_1" = "1 day selected";
"MessageCalendar.DaysSelectedTitle_any" = "%@ days selected"; "MessageCalendar.DaysSelectedTitle_any" = "%@ days selected";
"MessageCalendar.DeleteConfirmation_1" = "Are you sure you want to delete all messages for the selected day?"; "MessageCalendar.DeleteAlertText_1" = "Are you sure you want to delete all messages for the selected day?";
"MessageCalendar.DeleteConfirmation_1" = "Are you sure you want to delete all messages for the selected %@ days?"; "MessageCalendar.DeleteAlertText_any" = "Are you sure you want to delete all messages for the selected %@ days?";
"SharedMedia.PhotoCount_1" = "1 photo"; "SharedMedia.PhotoCount_1" = "1 photo";
"SharedMedia.PhotoCount_any" = "%@ photos"; "SharedMedia.PhotoCount_any" = "%@ photos";

View File

@@ -1399,7 +1399,7 @@ public final class CalendarMessageScreen: ViewController {
} }
if let _ = info.canClearForMyself ?? info.canClearForEveryone { if let _ = info.canClearForMyself ?? info.canClearForEveryone {
items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.MessageCalendar_DeleteConfirmation(Int32(selectedCount)))) items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.MessageCalendar_DeleteAlertText(Int32(selectedCount))))
if let canClearForEveryone = info.canClearForEveryone { if let canClearForEveryone = info.canClearForEveryone {
let text: String let text: String

View File

@@ -107,7 +107,13 @@ public final class GridMessageSelectionLayer: CALayer {
} }
public func updateLayout(size: CGSize) { public func updateLayout(size: CGSize) {
let checkSize = CGSize(width: 28.0, height: 28.0) let checkWidth: CGFloat
if size.width <= 60.0 {
checkWidth = 22.0
} else {
checkWidth = 28.0
}
let checkSize = CGSize(width: checkWidth, height: checkWidth)
let previousSize = self.checkLayer.bounds.size let previousSize = self.checkLayer.bounds.size
self.checkLayer.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width - 2.0, y: 2.0), size: checkSize) self.checkLayer.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width - 2.0, y: 2.0), size: checkSize)
if self.checkLayer.bounds.size != previousSize { if self.checkLayer.bounds.size != previousSize {

View File

@@ -64,21 +64,33 @@ private enum RecentSessionsEntryStableId: Hashable {
case devicesInfo case devicesInfo
} }
private struct SortIndex: Comparable {
var section: Int
var item: Int
static func <(lhs: SortIndex, rhs: SortIndex) -> Bool {
if lhs.section != rhs.section {
return lhs.section < rhs.section
}
return lhs.item < rhs.item
}
}
private enum RecentSessionsEntry: ItemListNodeEntry { private enum RecentSessionsEntry: ItemListNodeEntry {
case currentSessionHeader(PresentationTheme, String) case currentSessionHeader(SortIndex, String)
case currentSession(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, RecentAccountSession) case currentSession(SortIndex, PresentationStrings, PresentationDateTimeFormat, RecentAccountSession)
case terminateOtherSessions(PresentationTheme, String) case terminateOtherSessions(SortIndex, String)
case terminateAllWebSessions(PresentationTheme, String) case terminateAllWebSessions(SortIndex, String)
case currentAddDevice(PresentationTheme, String) case currentAddDevice(SortIndex, String)
case currentSessionInfo(PresentationTheme, String) case currentSessionInfo(SortIndex, String)
case pendingSessionsHeader(PresentationTheme, String) case pendingSessionsHeader(SortIndex, String)
case pendingSession(index: Int32, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool) case pendingSession(index: Int32, sortIndex: SortIndex, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool)
case pendingSessionsInfo(PresentationTheme, String) case pendingSessionsInfo(SortIndex, String)
case otherSessionsHeader(PresentationTheme, String) case otherSessionsHeader(SortIndex, String)
case addDevice(PresentationTheme, String) case addDevice(SortIndex, String)
case session(index: Int32, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool) case session(index: Int32, sortIndex: SortIndex, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool)
case website(index: Int32, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool) case website(index: Int32, sortIndex: SortIndex, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool)
case devicesInfo(PresentationTheme, String) case devicesInfo(SortIndex, String)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
@@ -102,7 +114,7 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
case .terminateAllWebSessions: case .terminateAllWebSessions:
return .index(3) return .index(3)
case .currentAddDevice: case .currentAddDevice:
return .index(3) return .index(4)
case .currentSessionInfo: case .currentSessionInfo:
return .index(5) return .index(5)
case .pendingSessionsHeader: case .pendingSessionsHeader:
@@ -124,88 +136,121 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
} }
} }
var sortIndex: SortIndex {
switch self {
case let .currentSessionHeader(index, _):
return index
case let .currentSession(index, _, _, _):
return index
case let .terminateOtherSessions(index, _):
return index
case let .terminateAllWebSessions(index, _):
return index
case let .currentAddDevice(index, _):
return index
case let .currentSessionInfo(index, _):
return index
case let .pendingSessionsHeader(index, _):
return index
case let .pendingSession(_, index, _, _, _, _, _, _):
return index
case let .pendingSessionsInfo(index, _):
return index
case let .otherSessionsHeader(index, _):
return index
case let .addDevice(index, _):
return index
case let .session(_, index, _, _, _, _, _, _):
return index
case let .website(_, index, _, _, _, _, _, _, _, _):
return index
case let .devicesInfo(index, _):
return index
}
}
static func ==(lhs: RecentSessionsEntry, rhs: RecentSessionsEntry) -> Bool { static func ==(lhs: RecentSessionsEntry, rhs: RecentSessionsEntry) -> Bool {
switch lhs { switch lhs {
case let .currentSessionHeader(lhsTheme, lhsText): case let .currentSessionHeader(lhsSortIndex, lhsText):
if case let .currentSessionHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .currentSessionHeader(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .terminateOtherSessions(lhsTheme, lhsText): case let .terminateOtherSessions(lhsSortIndex, lhsText):
if case let .terminateOtherSessions(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .terminateOtherSessions(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .terminateAllWebSessions(lhsTheme, lhsText): case let .terminateAllWebSessions(lhsSortIndex, lhsText):
if case let .terminateAllWebSessions(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .terminateAllWebSessions(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .currentAddDevice(lhsTheme, lhsText): case let .currentAddDevice(lhsSortIndex, lhsText):
if case let .currentAddDevice(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .currentAddDevice(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .currentSessionInfo(lhsTheme, lhsText): case let .currentSessionInfo(lhsSortIndex, lhsText):
if case let .currentSessionInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .currentSessionInfo(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .pendingSessionsHeader(lhsTheme, lhsText): case let .pendingSessionsHeader(lhsSortIndex, lhsText):
if case let .pendingSessionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .pendingSessionsHeader(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .pendingSession(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed): case let .pendingSession(lhsIndex, lhsSortIndex, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed):
if case let .pendingSession(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed { if case let .pendingSession(rhsIndex, rhsSortIndex, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsSortIndex == rhsSortIndex, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
return true return true
} else { } else {
return false return false
} }
case let .pendingSessionsInfo(lhsTheme, lhsText): case let .pendingSessionsInfo(lhsSortIndex, lhsText):
if case let .pendingSessionsInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .pendingSessionsInfo(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .otherSessionsHeader(lhsTheme, lhsText): case let .otherSessionsHeader(lhsSortIndex, lhsText):
if case let .otherSessionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .otherSessionsHeader(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .addDevice(lhsTheme, lhsText): case let .addDevice(lhsSortIndex, lhsText):
if case let .addDevice(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .addDevice(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .currentSession(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession): case let .currentSession(lhsSortIndex, lhsStrings, lhsDateTimeFormat, lhsSession):
if case let .currentSession(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession { if case let .currentSession(rhsSortIndex, rhsStrings, rhsDateTimeFormat, rhsSession) = rhs, lhsSortIndex == rhsSortIndex, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession {
return true return true
} else { } else {
return false return false
} }
case let .session(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed): case let .session(lhsIndex, lhsSortIndex, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed):
if case let .session(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed { if case let .session(rhsIndex, rhsSortIndex, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsSortIndex == rhsSortIndex, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
return true return true
} else { } else {
return false return false
} }
case let .website(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsNameOrder, lhsWebsite, lhsPeer, lhsEnabled, lhsEditing, lhsRevealed): case let .website(lhsIndex, lhsSortIndex, lhsStrings, lhsDateTimeFormat, lhsNameOrder, lhsWebsite, lhsPeer, lhsEnabled, lhsEditing, lhsRevealed):
if case let .website(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsNameOrder, rhsWebsite, rhsPeer, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameOrder == rhsNameOrder, lhsWebsite == rhsWebsite, arePeersEqual(lhsPeer, rhsPeer), lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed { if case let .website(rhsIndex, rhsSortIndex, rhsStrings, rhsDateTimeFormat, rhsNameOrder, rhsWebsite, rhsPeer, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsSortIndex == rhsSortIndex, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameOrder == rhsNameOrder, lhsWebsite == rhsWebsite, arePeersEqual(lhsPeer, rhsPeer), lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
return true return true
} else { } else {
return false return false
} }
case let .devicesInfo(lhsTheme, lhsText): case let .devicesInfo(lhsSortIndex, lhsText):
if case let .devicesInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .devicesInfo(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
return true return true
} else { } else {
return false return false
@@ -214,59 +259,7 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
} }
static func <(lhs: RecentSessionsEntry, rhs: RecentSessionsEntry) -> Bool { static func <(lhs: RecentSessionsEntry, rhs: RecentSessionsEntry) -> Bool {
switch lhs.stableId { return lhs.sortIndex < rhs.sortIndex
case let .index(lhsIndex):
if case let .index(rhsIndex) = rhs.stableId {
return lhsIndex <= rhsIndex
} else {
if case .pendingSession = rhs, lhsIndex > 5 {
return false
} else {
return true
}
}
case .session:
switch lhs {
case let .session(lhsIndex, _, _, _, _, _, _, _):
if case let .session(rhsIndex, _, _, _, _, _, _, _) = rhs {
return lhsIndex <= rhsIndex
} else if case .devicesInfo = rhs.stableId {
return true
} else {
return false
}
case let .pendingSession(lhsIndex, _, _, _, _, _, _, _):
if case let .pendingSession(rhsIndex, _, _, _, _, _, _, _) = rhs {
return lhsIndex <= rhsIndex
} else if case .session = rhs {
return true
} else if case .devicesInfo = rhs.stableId {
return true
} else {
if case let .index(rhsIndex) = rhs.stableId {
return rhsIndex == 6
} else {
return false
}
}
case let .website(lhsIndex, _, _, _, _, _, _, _, _, _):
if case let .website(rhsIndex, _, _, _, _, _, _, _, _, _) = rhs {
return lhsIndex <= rhsIndex
} else if case .devicesInfo = rhs.stableId {
return true
} else {
return false
}
default:
preconditionFailure()
}
case .devicesInfo:
if case .devicesInfo = rhs.stableId {
return false
} else {
return false
}
}
} }
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
@@ -280,16 +273,16 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
}, action: { }, action: {
arguments.openSession(session) arguments.openSession(session)
}) })
case let .terminateOtherSessions(theme, text): case let .terminateOtherSessions(_, text):
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.blockDestructiveIcon(theme), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.blockDestructiveIcon(presentationData.theme), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: {
arguments.terminateOtherSessions() arguments.terminateOtherSessions()
}) })
case let .terminateAllWebSessions(theme, text): case let .terminateAllWebSessions(_, text):
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.blockDestructiveIcon(theme), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.blockDestructiveIcon(presentationData.theme), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: {
arguments.terminateAllWebSessions() arguments.terminateAllWebSessions()
}) })
case let .currentAddDevice(theme, text): case let .currentAddDevice(_, text):
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addDeviceIcon(theme), title: text, sectionId: self.section, height: .generic, color: .accent, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addDeviceIcon(presentationData.theme), title: text, sectionId: self.section, height: .generic, color: .accent, editing: false, action: {
arguments.addDevice() arguments.addDevice()
}) })
case let .currentSessionInfo(_, text): case let .currentSessionInfo(_, text):
@@ -313,8 +306,8 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .otherSessionsHeader(_, text): case let .otherSessionsHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .addDevice(theme, text): case let .addDevice(_, text):
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addDeviceIcon(theme), title: text, sectionId: self.section, height: .generic, color: .accent, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addDeviceIcon(presentationData.theme), title: text, sectionId: self.section, height: .generic, color: .accent, editing: false, action: {
arguments.addDevice() arguments.addDevice()
}) })
case let .session(_, _, _, dateTimeFormat, session, enabled, editing, revealed): case let .session(_, _, _, dateTimeFormat, session, enabled, editing, revealed):
@@ -403,41 +396,41 @@ private func recentSessionsControllerEntries(presentationData: PresentationData,
if !sessionsState.sessions.isEmpty { if !sessionsState.sessions.isEmpty {
var existingSessionIds = Set<Int64>() var existingSessionIds = Set<Int64>()
entries.append(.currentSessionHeader(presentationData.theme, presentationData.strings.AuthSessions_CurrentSession)) entries.append(.currentSessionHeader(SortIndex(section: 0, item: 0), presentationData.strings.AuthSessions_CurrentSession))
if let index = sessionsState.sessions.firstIndex(where: { $0.hash == 0 }) { if let index = sessionsState.sessions.firstIndex(where: { $0.hash == 0 }) {
existingSessionIds.insert(sessionsState.sessions[index].hash) existingSessionIds.insert(sessionsState.sessions[index].hash)
entries.append(.currentSession(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, sessionsState.sessions[index])) entries.append(.currentSession(SortIndex(section: 0, item: 1), presentationData.strings, presentationData.dateTimeFormat, sessionsState.sessions[index]))
} }
var hasAddDevice = false var hasAddDevice = false
if sessionsState.sessions.count > 1 || enableQRLogin { if sessionsState.sessions.count > 1 || enableQRLogin {
if sessionsState.sessions.count > 1 { if sessionsState.sessions.count > 1 {
entries.append(.terminateOtherSessions(presentationData.theme, presentationData.strings.AuthSessions_TerminateOtherSessions)) entries.append(.terminateOtherSessions(SortIndex(section: 0, item: 2), presentationData.strings.AuthSessions_TerminateOtherSessions))
entries.append(.currentSessionInfo(presentationData.theme, presentationData.strings.AuthSessions_TerminateOtherSessionsHelp)) entries.append(.currentSessionInfo(SortIndex(section: 0, item: 3), presentationData.strings.AuthSessions_TerminateOtherSessionsHelp))
} else if enableQRLogin { } else if enableQRLogin {
hasAddDevice = true hasAddDevice = true
entries.append(.currentAddDevice(presentationData.theme, presentationData.strings.AuthSessions_AddDevice)) entries.append(.currentAddDevice(SortIndex(section: 0, item: 4), presentationData.strings.AuthSessions_AddDevice))
entries.append(.currentSessionInfo(presentationData.theme, presentationData.strings.AuthSessions_OtherDevices)) entries.append(.currentSessionInfo(SortIndex(section: 0, item: 5), presentationData.strings.AuthSessions_OtherDevices))
} }
let filteredPendingSessions: [RecentAccountSession] = sessionsState.sessions.filter({ $0.flags.contains(.passwordPending) }) let filteredPendingSessions: [RecentAccountSession] = sessionsState.sessions.filter({ $0.flags.contains(.passwordPending) })
if !filteredPendingSessions.isEmpty { if !filteredPendingSessions.isEmpty {
entries.append(.pendingSessionsHeader(presentationData.theme, presentationData.strings.AuthSessions_IncompleteAttempts)) entries.append(.pendingSessionsHeader(SortIndex(section: 0, item: 6), presentationData.strings.AuthSessions_IncompleteAttempts))
for i in 0 ..< filteredPendingSessions.count { for i in 0 ..< filteredPendingSessions.count {
if !existingSessionIds.contains(filteredPendingSessions[i].hash) { if !existingSessionIds.contains(filteredPendingSessions[i].hash) {
existingSessionIds.insert(filteredPendingSessions[i].hash) existingSessionIds.insert(filteredPendingSessions[i].hash)
entries.append(.pendingSession(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, session: filteredPendingSessions[i], enabled: state.removingSessionId != filteredPendingSessions[i].hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == filteredPendingSessions[i].hash)) entries.append(.pendingSession(index: Int32(i), sortIndex: SortIndex(section: 1, item: i), strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, session: filteredPendingSessions[i], enabled: state.removingSessionId != filteredPendingSessions[i].hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == filteredPendingSessions[i].hash))
} }
} }
entries.append(.pendingSessionsInfo(presentationData.theme, presentationData.strings.AuthSessions_IncompleteAttemptsInfo)) entries.append(.pendingSessionsInfo(SortIndex(section: 2, item: 0), presentationData.strings.AuthSessions_IncompleteAttemptsInfo))
} }
if sessionsState.sessions.count > 1 { if sessionsState.sessions.count > 1 {
entries.append(.otherSessionsHeader(presentationData.theme, presentationData.strings.AuthSessions_OtherSessions)) entries.append(.otherSessionsHeader(SortIndex(section: 3, item: 0), presentationData.strings.AuthSessions_OtherSessions))
} }
if enableQRLogin && !hasAddDevice { if enableQRLogin && !hasAddDevice {
entries.append(.addDevice(presentationData.theme, presentationData.strings.AuthSessions_AddDevice)) entries.append(.addDevice(SortIndex(section: 3, item: 1), presentationData.strings.AuthSessions_AddDevice))
} }
let filteredSessions: [RecentAccountSession] = sessionsState.sessions.sorted(by: { lhs, rhs in let filteredSessions: [RecentAccountSession] = sessionsState.sessions.sorted(by: { lhs, rhs in
@@ -447,12 +440,12 @@ private func recentSessionsControllerEntries(presentationData: PresentationData,
for i in 0 ..< filteredSessions.count { for i in 0 ..< filteredSessions.count {
if !existingSessionIds.contains(filteredSessions[i].hash) { if !existingSessionIds.contains(filteredSessions[i].hash) {
existingSessionIds.insert(filteredSessions[i].hash) existingSessionIds.insert(filteredSessions[i].hash)
entries.append(.session(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, session: filteredSessions[i], enabled: state.removingSessionId != filteredSessions[i].hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == filteredSessions[i].hash)) entries.append(.session(index: Int32(i), sortIndex: SortIndex(section: 4, item: i), strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, session: filteredSessions[i], enabled: state.removingSessionId != filteredSessions[i].hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == filteredSessions[i].hash))
} }
} }
if enableQRLogin && !hasAddDevice { if enableQRLogin && !hasAddDevice {
entries.append(.devicesInfo(presentationData.theme, presentationData.strings.AuthSessions_OtherDevices)) entries.append(.devicesInfo(SortIndex(section: 5, item: 0), presentationData.strings.AuthSessions_OtherDevices))
} }
} }
} }
@@ -466,10 +459,10 @@ private func recentSessionsControllerEntries(presentationData: PresentationData,
if let websites = websites, let peers = peers { if let websites = websites, let peers = peers {
var existingSessionIds = Set<Int64>() var existingSessionIds = Set<Int64>()
if websites.count > 0 { if websites.count > 0 {
entries.append(.terminateAllWebSessions(presentationData.theme, presentationData.strings.AuthSessions_LogOutApplications)) entries.append(.terminateAllWebSessions(SortIndex(section: 0, item: 0), presentationData.strings.AuthSessions_LogOutApplications))
entries.append(.currentSessionInfo(presentationData.theme, presentationData.strings.AuthSessions_LogOutApplicationsHelp)) entries.append(.currentSessionInfo(SortIndex(section: 0, item: 1), presentationData.strings.AuthSessions_LogOutApplicationsHelp))
entries.append(.otherSessionsHeader(presentationData.theme, presentationData.strings.AuthSessions_LoggedInWithTelegram)) entries.append(.otherSessionsHeader(SortIndex(section: 0, item: 2), presentationData.strings.AuthSessions_LoggedInWithTelegram))
let filteredWebsites: [WebAuthorization] = websites.sorted(by: { lhs, rhs in let filteredWebsites: [WebAuthorization] = websites.sorted(by: { lhs, rhs in
return lhs.dateActive > rhs.dateActive return lhs.dateActive > rhs.dateActive
@@ -479,7 +472,7 @@ private func recentSessionsControllerEntries(presentationData: PresentationData,
let website = websites[i] let website = websites[i]
if !existingSessionIds.contains(website.hash) { if !existingSessionIds.contains(website.hash) {
existingSessionIds.insert(website.hash) existingSessionIds.insert(website.hash)
entries.append(.website(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, website: website, peer: peers[website.botId], enabled: state.removingSessionId != website.hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == website.hash)) entries.append(.website(index: Int32(i), sortIndex: SortIndex(section: 1, item: i), strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, website: website, peer: peers[website.botId], enabled: state.removingSessionId != website.hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == website.hash))
} }
} }
} }

View File

@@ -809,6 +809,10 @@ public final class SparseItemGrid: ASDisplayNode {
self.decelerationAnimator?.isPaused = false self.decelerationAnimator?.isPaused = false
} }
func updateShimmerColors() {
self.updateVisibleItems(resetScrolling: false, synchronous: .none, restoreScrollPosition: nil)
}
private func updateVisibleItems(resetScrolling: Bool, synchronous: SparseItemGrid.Synchronous, restoreScrollPosition: (y: CGFloat, index: Int)?) { private func updateVisibleItems(resetScrolling: Bool, synchronous: SparseItemGrid.Synchronous, restoreScrollPosition: (y: CGFloat, index: Int)?) {
guard let layout = self.layout, let items = self.items else { guard let layout = self.layout, let items = self.items else {
return return
@@ -1695,4 +1699,12 @@ public final class SparseItemGrid: ASDisplayNode {
public func transferVelocity(_ velocity: CGFloat) { public func transferVelocity(_ velocity: CGFloat) {
self.currentViewport?.transferVelocity(velocity) self.currentViewport?.transferVelocity(velocity)
} }
public func updatePresentationData(theme: PresentationTheme) {
self.theme = theme
if let currentViewport = self.currentViewport {
currentViewport.updateShimmerColors()
}
}
} }

View File

@@ -131,6 +131,129 @@ public final class LottieAnimationComponent: Component {
} }
} }
private final class ScrollingTooltipAnimationComponent: Component {
public init() {
}
public static func ==(lhs: ScrollingTooltipAnimationComponent, rhs: ScrollingTooltipAnimationComponent) -> Bool {
return true
}
public final class View: UIView {
private var progress: CGFloat = 0.0
private var previousTarget: CGFloat = 0.0
private var animator: DisplayLinkAnimator?
init() {
super.init(frame: CGRect())
self.isOpaque = false
self.backgroundColor = nil
self.previousTarget = CGFloat.random(in: 0.0 ... 1.0)
self.startNextAnimation()
}
required init?(coder aDecoder: NSCoder) {
preconditionFailure()
}
func startNextAnimation() {
self.animator?.invalidate()
let previous = self.previousTarget
let target = CGFloat.random(in: 0.0 ... 1.0)
self.previousTarget = target
let animator = DisplayLinkAnimator(duration: 1.0, from: previous, to: target, update: { [weak self] value in
guard let strongSelf = self else {
return
}
strongSelf.progress = listViewAnimationCurveEaseInOut(value)
strongSelf.setNeedsDisplay()
}, completion: { [weak self] in
Queue.mainQueue().after(0.3, {
guard let strongSelf = self else {
return
}
strongSelf.startNextAnimation()
})
})
self.animator = animator
}
func update(component: ScrollingTooltipAnimationComponent, availableSize: CGSize, environment: Environment<Empty>, transition: Transition) -> CGSize {
return CGSize(width: 32.0, height: 32.0)
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let progressValue = self.progress
let itemSize: CGFloat = 12.0
let itemSpacing: CGFloat = 1.0
let listItemCount: CGFloat = 100.0
let listHeight: CGFloat = itemSize * listItemCount + itemSpacing * (listItemCount - 1)
context.setFillColor(UIColor(white: 1.0, alpha: 0.3).cgColor)
let offset: CGFloat = progressValue * listHeight
var minVisibleItemIndex: Int = Int(floor(offset / (itemSize + itemSpacing)))
while true {
let itemY: CGFloat = CGFloat(minVisibleItemIndex) * (itemSize + itemSpacing) - offset
if itemY >= self.bounds.height {
break
}
for i in 0 ..< 2 {
UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: CGFloat(i) * (itemSize + itemSpacing), y: itemY), size: CGSize(width: itemSize, height: itemSize)), cornerRadius: 2.0).fill()
}
minVisibleItemIndex += 1
}
let gradientFraction: CGFloat = 10.0 / self.bounds.height
let colorsArray: [CGColor] = ([
UIColor(white: 1.0, alpha: 1.0),
UIColor(white: 1.0, alpha: 0.0),
UIColor(white: 1.0, alpha: 0.0),
UIColor(white: 1.0, alpha: 1.0)
] as [UIColor]).map(\.cgColor)
var locations: [CGFloat] = [0.0, gradientFraction, 1.0 - gradientFraction, 1.0]
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
context.setBlendMode(.destinationOut)
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: self.bounds.height), options: [])
context.setBlendMode(.normal)
context.setFillColor(UIColor.white.cgColor)
let indicatorHeight: CGFloat = 10.0
let indicatorMinY: CGFloat = 0.0
let indicatorMaxY: CGFloat = self.bounds.height - indicatorHeight
let indicatorX: CGFloat = (itemSize + itemSpacing) * 2.0
let indicatorY = indicatorMinY * (1.0 - progress) + indicatorMaxY * progress
UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: indicatorX, y: indicatorY), size: CGSize(width: 3.0, height: indicatorHeight)), cornerRadius: 1.5).fill()
UIBezierPath(roundedRect: CGRect(x: indicatorX - 4.0 - 19.0, y: indicatorY + (indicatorHeight - 8.0) / 2.0, width: 19.0, height: 8.0), cornerRadius: 4.0).fill()
}
}
public func makeView() -> View {
return View()
}
public func update(view: View, availableSize: CGSize, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, environment: environment, transition: transition)
}
}
public final class TooltipComponent: Component { public final class TooltipComponent: Component {
public let icon: AnyComponent<Empty>? public let icon: AnyComponent<Empty>?
public let content: AnyComponent<Empty> public let content: AnyComponent<Empty>
@@ -942,9 +1065,12 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
displayTooltip.completed() displayTooltip.completed()
//#if DEBUG
//#else
Queue.mainQueue().after(2.0, { [weak self] in Queue.mainQueue().after(2.0, { [weak self] in
self?.dismissLineTooltip() self?.dismissLineTooltip()
}) })
//#endif
} }
private func updateLineTooltip(containerSize: CGSize) { private func updateLineTooltip(containerSize: CGSize) {
@@ -958,9 +1084,7 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
transition: .immediate, transition: .immediate,
component: AnyComponent(TooltipComponent( component: AnyComponent(TooltipComponent(
icon: displayTooltip.animation.flatMap { animation in icon: displayTooltip.animation.flatMap { animation in
AnyComponent(LottieAnimationComponent( AnyComponent(ScrollingTooltipAnimationComponent())
name: animation
))
}, },
content: AnyComponent(MultilineText( content: AnyComponent(MultilineText(
text: displayTooltip.text, text: displayTooltip.text,

View File

@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "playsmall.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,73 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.283813 cm
1.000000 1.000000 1.000000 scn
1.533992 9.134618 m
0.868123 9.555166 0.000000 9.076683 0.000000 8.289128 c
0.000000 0.717780 l
0.000000 -0.069775 0.868124 -0.548255 1.533993 -0.127707 c
7.527976 3.657967 l
8.149319 4.050394 8.149319 4.956517 7.527976 5.348944 c
1.533992 9.134618 l
h
f*
n
Q
endstream
endobj
3 0 obj
379
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 7.994019 9.574585 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Type /Catalog
/Pages 5 0 R
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000000469 00000 n
0000000491 00000 n
0000000662 00000 n
0000000736 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
795
%%EOF

View File

@@ -21,6 +21,7 @@ import ComponentFlow
import TelegramNotices import TelegramNotices
import TelegramUIPreferences import TelegramUIPreferences
import CheckNode import CheckNode
import AppBundle
private final class FrameSequenceThumbnailNode: ASDisplayNode { private final class FrameSequenceThumbnailNode: ASDisplayNode {
private let context: AccountContext private let context: AccountContext
@@ -711,6 +712,19 @@ private struct Month: Equatable {
} }
private let durationFont = Font.regular(12.0) private let durationFont = Font.regular(12.0)
private let minDurationImage: UIImage = {
let image = generateImage(CGSize(width: 20.0, height: 20.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor(white: 0.0, alpha: 0.5).cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
if let image = UIImage(bundleImageName: "Chat/GridPlayIcon") {
UIGraphicsPushContext(context)
image.draw(in: CGRect(origin: CGPoint(x: (size.width - image.size.width) / 2.0, y: (size.height - image.size.height) / 2.0), size: image.size))
UIGraphicsPopContext()
}
})
return image!
}()
private final class DurationLayer: CALayer { private final class DurationLayer: CALayer {
override init() { override init() {
@@ -728,7 +742,10 @@ private final class DurationLayer: CALayer {
return nullAction return nullAction
} }
func update(duration: Int32) { func update(duration: Int32, isMin: Bool) {
if isMin {
self.contents = minDurationImage.cgImage
} else {
let string = NSAttributedString(string: stringForDuration(duration), font: durationFont, textColor: .white) let string = NSAttributedString(string: stringForDuration(duration), font: durationFont, textColor: .white)
let bounds = string.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil) let bounds = string.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
let textSize = CGSize(width: ceil(bounds.width), height: ceil(bounds.height)) let textSize = CGSize(width: ceil(bounds.width), height: ceil(bounds.height))
@@ -750,11 +767,13 @@ private final class DurationLayer: CALayer {
}) })
self.contents = image?.cgImage self.contents = image?.cgImage
} }
}
} }
private final class ItemLayer: CALayer, SparseItemGridLayer { private final class ItemLayer: CALayer, SparseItemGridLayer {
var item: VisualMediaItem? var item: VisualMediaItem?
var durationLayer: DurationLayer? var durationLayer: DurationLayer?
var minFactor: CGFloat = 1.0
var selectionLayer: GridMessageSelectionLayer? var selectionLayer: GridMessageSelectionLayer?
var disposable: Disposable? var disposable: Disposable?
@@ -782,15 +801,18 @@ private final class ItemLayer: CALayer, SparseItemGridLayer {
self.item = item self.item = item
} }
func updateDuration(duration: Int32?) { func updateDuration(duration: Int32?, isMin: Bool, minFactor: CGFloat) {
self.minFactor = minFactor
if let duration = duration { if let duration = duration {
if let durationLayer = self.durationLayer { if let durationLayer = self.durationLayer {
durationLayer.update(duration: duration) durationLayer.update(duration: duration, isMin: isMin)
} else { } else {
let durationLayer = DurationLayer() let durationLayer = DurationLayer()
durationLayer.update(duration: duration) durationLayer.update(duration: duration, isMin: isMin)
self.addSublayer(durationLayer) self.addSublayer(durationLayer)
durationLayer.frame = CGRect(origin: CGPoint(x: self.bounds.width - 3.0, y: self.bounds.height - 3.0), size: CGSize()) durationLayer.frame = CGRect(origin: CGPoint(x: self.bounds.width - 3.0, y: self.bounds.height - 3.0), size: CGSize())
durationLayer.transform = CATransform3DMakeScale(minFactor, minFactor, 1.0)
} }
} else if let durationLayer = self.durationLayer { } else if let durationLayer = self.durationLayer {
self.durationLayer = nil self.durationLayer = nil
@@ -836,9 +858,9 @@ private final class ItemLayer: CALayer, SparseItemGridLayer {
} }
func update(size: CGSize) { func update(size: CGSize) {
if let durationLayer = self.durationLayer { /*if let durationLayer = self.durationLayer {
durationLayer.frame = CGRect(origin: CGPoint(x: size.width - 3.0, y: size.height - 3.0), size: CGSize()) durationLayer.frame = CGRect(origin: CGPoint(x: size.width - 3.0, y: size.height - 3.0), size: CGSize())
} }*/
} }
} }
@@ -1001,12 +1023,12 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
let context: AccountContext let context: AccountContext
let chatLocation: ChatLocation let chatLocation: ChatLocation
let directMediaImageCache: DirectMediaImageCache let directMediaImageCache: DirectMediaImageCache
let strings: PresentationStrings var strings: PresentationStrings
let useListItems: Bool let useListItems: Bool
let listItemInteraction: ListMessageItemInteraction let listItemInteraction: ListMessageItemInteraction
let chatControllerInteraction: ChatControllerInteraction let chatControllerInteraction: ChatControllerInteraction
let chatPresentationData: ChatPresentationData var chatPresentationData: ChatPresentationData
let checkNodeTheme: CheckNodeTheme var checkNodeTheme: CheckNodeTheme
var loadHoleImpl: ((SparseItemGrid.HoleAnchor, SparseItemGrid.HoleLocation) -> Signal<Never, NoError>)? var loadHoleImpl: ((SparseItemGrid.HoleAnchor, SparseItemGrid.HoleLocation) -> Signal<Never, NoError>)?
var onTapImpl: ((VisualMediaItem) -> Void)? var onTapImpl: ((VisualMediaItem) -> Void)?
@@ -1036,6 +1058,15 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
self.checkNodeTheme = CheckNodeTheme(theme: presentationData.theme, style: .overlay, hasInset: true) self.checkNodeTheme = CheckNodeTheme(theme: presentationData.theme, style: .overlay, hasInset: true)
} }
func updatePresentationData(presentationData: PresentationData) {
self.strings = presentationData.strings
let themeData = ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper)
self.chatPresentationData = ChatPresentationData(theme: themeData, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners, animatedEmojiScale: 1.0)
self.checkNodeTheme = CheckNodeTheme(theme: presentationData.theme, style: .overlay, hasInset: true)
}
func getListShimmerImage(height: CGFloat) -> UIImage { func getListShimmerImage(height: CGFloat) -> UIImage {
if let image = self.shimmerImages[height] { if let image = self.shimmerImages[height] {
return image return image
@@ -1278,10 +1309,12 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
} }
var duration: Int32? var duration: Int32?
if layer.bounds.width > 80.0, let file = selectedMedia as? TelegramMediaFile, !file.isAnimated { var isMin: Bool = false
if let file = selectedMedia as? TelegramMediaFile, !file.isAnimated {
duration = file.duration duration = file.duration
isMin = layer.bounds.width < 80.0
} }
layer.updateDuration(duration: duration) layer.updateDuration(duration: duration, isMin: isMin, minFactor: min(1.0, layer.bounds.height / 74.0))
} }
if let selectionState = self.chatControllerInteraction.selectionState { if let selectionState = self.chatControllerInteraction.selectionState {
@@ -1455,6 +1488,9 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
private weak var currentGestureItem: SparseItemGridDisplayItem? private weak var currentGestureItem: SparseItemGridDisplayItem?
private var presentationData: PresentationData
private var presentationDataDisposable: Disposable?
init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, contentType: ContentType) { init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, contentType: ContentType) {
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
@@ -1463,8 +1499,10 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
self.contentTypePromise = ValuePromise<ContentType>(contentType) self.contentTypePromise = ValuePromise<ContentType>(contentType)
self.stateTag = tagMaskForType(contentType) self.stateTag = tagMaskForType(contentType)
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
self.contextGestureContainerNode = ContextControllerSourceNode() self.contextGestureContainerNode = ContextControllerSourceNode()
self.itemGrid = SparseItemGrid(theme: self.context.sharedContext.currentPresentationData.with({ $0 }).theme) self.itemGrid = SparseItemGrid(theme: self.presentationData.theme)
self.directMediaImageCache = DirectMediaImageCache(account: context.account) self.directMediaImageCache = DirectMediaImageCache(account: context.account)
let useListItems: Bool let useListItems: Bool
@@ -1926,12 +1964,40 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
} }
} }
})) }))
self.presentationDataDisposable = (self.context.sharedContext.presentationData
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
guard let strongSelf = self else {
return
}
strongSelf.itemGridBinding.updatePresentationData(presentationData: presentationData)
strongSelf.itemGrid.updatePresentationData(theme: presentationData.theme)
strongSelf.itemGrid.forEachVisibleItem { item in
guard let itemView = item.view as? ItemView else {
return
}
if let item = itemView.item {
itemView.bind(
item: item,
presentationData: strongSelf.itemGridBinding.chatPresentationData,
context: strongSelf.itemGridBinding.context,
chatLocation: strongSelf.itemGridBinding.chatLocation,
interaction: strongSelf.itemGridBinding.listItemInteraction,
isSelected: strongSelf.chatControllerInteraction.selectionState?.selectedIds.contains(item.message.id),
size: itemView.bounds.size
)
}
}
})
} }
deinit { deinit {
self.listDisposable.dispose() self.listDisposable.dispose()
self.hiddenMediaDisposable?.dispose() self.hiddenMediaDisposable?.dispose()
self.animationTimer?.invalidate() self.animationTimer?.invalidate()
self.presentationDataDisposable?.dispose()
} }
func loadHole(anchor: SparseItemGrid.HoleAnchor, at location: SparseItemGrid.HoleLocation) -> Signal<Never, NoError> { func loadHole(anchor: SparseItemGrid.HoleAnchor, at location: SparseItemGrid.HoleLocation) -> Signal<Never, NoError> {