Reduce Motion option to disable animations of chats/contacts/calls lists and chat bubbles

Fixed crash on profile photo removal
Fixed several auto-download issues
Fixed network usage calculation for videos
Fixed several UI issues
This commit is contained in:
Ilya Laktyushin 2018-10-06 00:52:13 +03:00
parent 606e607de4
commit ab5881de15
92 changed files with 3114 additions and 2738 deletions

View File

@ -37,6 +37,7 @@
09874E582107A4C300E190B8 /* VimeoEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09874E3A21075BF400E190B8 /* VimeoEmbedImplementation.swift */; };
09874E592107BD4100E190B8 /* GenericEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09874E4021075C1700E190B8 /* GenericEmbedImplementation.swift */; };
09AE3823214C110900850BFD /* LegacySecureIdScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */; };
09C3466D2167D63A00B76780 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C3466C2167D63A00B76780 /* Accessibility.swift */; };
09C500242142BA6400EF253E /* ItemListWebsiteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */; };
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
D007019C2029E8F2006B9E34 /* LegqacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.swift */; };
@ -1057,6 +1058,7 @@
09874E4221075C3000E190B8 /* VKEmbedImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VKEmbedImplementation.swift; sourceTree = "<group>"; };
09874E4421075C3F00E190B8 /* StreamableEmbedImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamableEmbedImplementation.swift; sourceTree = "<group>"; };
09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySecureIdScanController.swift; sourceTree = "<group>"; };
09C3466C2167D63A00B76780 /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = "<group>"; };
09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListWebsiteItem.swift; sourceTree = "<group>"; };
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = "<group>"; };
D00219051DDD1C9E00BE708A /* ImageContainingNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageContainingNode.swift; sourceTree = "<group>"; };
@ -4312,6 +4314,7 @@
D044A0F220BDA05800326FAC /* ThrottledValue.swift */,
D0EC55A2210231D600D1992C /* SearchPeerMembers.swift */,
D0192D45210F4F940005FA10 /* FixSearchableListNodeScrolling.swift */,
09C3466C2167D63A00B76780 /* Accessibility.swift */,
);
name = Utils;
sourceTree = "<group>";
@ -4917,6 +4920,7 @@
D0EC6D2D1EB9F58800EBF1C3 /* TapLongTapOrDoubleTapGestureRecognizer.swift in Sources */,
D0AF7C461ED84BC500CD8E0F /* LanguageSelectionController.swift in Sources */,
D0B69C3C20EBD8C8003632C7 /* CheckDeviceAccess.swift in Sources */,
09C3466D2167D63A00B76780 /* Accessibility.swift in Sources */,
D0FA08C020483F9600DD23FC /* ExtractVideoData.swift in Sources */,
D0BE30492061C0F500FBE6D8 /* SecureIdAuthHeaderNode.swift in Sources */,
D0EC6D2E1EB9F58800EBF1C3 /* ImageNode.swift in Sources */,

View File

@ -0,0 +1,49 @@
import SwiftSignalKit
import UIKit
func currentReduceMotionEnabled() -> Bool {
return UIAccessibility.isReduceMotionEnabled
}
func reduceMotionEnabled() -> Signal<Bool, NoError> {
return Signal { subscriber in
subscriber.putNext(UIAccessibility.isReduceMotionEnabled)
let observer = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIAccessibilityReduceMotionStatusDidChange, object: nil, queue: .main, using: { _ in
subscriber.putNext(UIAccessibility.isReduceMotionEnabled)
})
return ActionDisposable {
Queue.mainQueue().async {
NotificationCenter.default.removeObserver(observer)
}
}
} |> runOn(Queue.mainQueue())
}
func boldTextEnabled() -> Signal<Bool, NoError> {
return Signal { subscriber in
subscriber.putNext(UIAccessibility.isBoldTextEnabled)
let observer = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIAccessibilityBoldTextStatusDidChange, object: nil, queue: .main, using: { _ in
subscriber.putNext(UIAccessibility.isBoldTextEnabled)
})
return ActionDisposable {
Queue.mainQueue().async {
NotificationCenter.default.removeObserver(observer)
}
}
} |> runOn(Queue.mainQueue())
}
private func checkButtonShapes() -> Bool {
let button = UIButton()
button.setTitle("title", for: .normal)
if let attributes = button.titleLabel?.attributedText?.attributes(at: 0, effectiveRange: nil), let _ = attributes[NSAttributedStringKey.underlineStyle] {
return true
} else {
return false
}
}

View File

@ -10,7 +10,7 @@ import CoreTelephony
public final class AuthorizationSequenceController: NavigationController {
static func navigationBarTheme(_ theme: AuthorizationTheme) -> NavigationBarTheme {
return NavigationBarTheme(buttonColor: theme.accentColor, primaryTextColor: .black, backgroundColor: .clear, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
return NavigationBarTheme(buttonColor: theme.accentColor, disabledButtonColor: UIColor(rgb: 0xd0d0d0), primaryTextColor: .black, backgroundColor: .clear, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
}
private var account: UnauthorizedAccount

View File

@ -186,7 +186,7 @@ final class AuthorizationSequenceCountrySelectionController: ViewController {
self.strings = strings
self.displayCodes = displayCodes
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(buttonColor: theme.searchBar.accent, primaryTextColor: theme.searchBar.primaryText, backgroundColor: theme.searchBar.background, separatorColor: theme.searchBar.separator, badgeBackgroundColor: theme.searchBar.accent, badgeStrokeColor: .clear, badgeTextColor: theme.searchBar.background), strings: NavigationBarStrings(presentationStrings: strings)))
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(buttonColor: theme.searchBar.accent, disabledButtonColor: UIColor(rgb: 0xd0d0d0), primaryTextColor: theme.searchBar.primaryText, backgroundColor: theme.searchBar.background, separatorColor: theme.searchBar.separator, badgeBackgroundColor: theme.searchBar.accent, badgeStrokeColor: .clear, badgeTextColor: theme.searchBar.background), strings: NavigationBarStrings(presentationStrings: strings)))
self.statusBar.statusBarStyle = theme.statusBar.style

View File

@ -470,7 +470,7 @@ func autodownloadMediaCategoryController(account: Account, category: AutomaticDo
case .cellular:
settings.peers.channels.voiceMessage.cellular = !settings.peers.channels.voiceMessage.cellular
case .wifi:
settings.peers.channels.voiceMessage.wifi = !settings.peers.channels.file.wifi
settings.peers.channels.voiceMessage.wifi = !settings.peers.channels.voiceMessage.wifi
}
}
case .videoMessage:
@ -501,7 +501,7 @@ func autodownloadMediaCategoryController(account: Account, category: AutomaticDo
case .cellular:
settings.peers.channels.videoMessage.cellular = !settings.peers.channels.videoMessage.cellular
case .wifi:
settings.peers.channels.videoMessage.wifi = !settings.peers.channels.file.wifi
settings.peers.channels.videoMessage.wifi = !settings.peers.channels.videoMessage.wifi
}
}
}

View File

@ -25,6 +25,8 @@ final class CallControllerNode: ASDisplayNode {
private let buttonsNode: CallControllerButtonsNode
private var keyPreviewNode: CallControllerKeyPreviewNode?
private var debugNode: CallDebugNode?
private var keyTextData: (Data, String)?
private let keyButtonNode: HighlightableButtonNode
@ -433,16 +435,47 @@ final class CallControllerNode: ASDisplayNode {
}
}
final private class CallControllerDebugNode: ASDisplayNode {
final private class CallDebugNode: ASDisplayNode {
private let disposable = MetaDisposable()
private let dimNode: ASDisplayNode
private let textNode: ASTextNode
override init() {
super.init()
self.dimNode = ASDisplayNode()
self.dimNode.isLayerBacked = true
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.8)
self.textNode = ASTextNode()
self.textNode.isUserInteractionEnabled = false
super.init()
}
deinit {
disposable.dispose()
}
override func didLoad() {
super.didLoad()
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
self.view.addGestureRecognizer(tapRecognizer)
}
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
}
override func layout() {
super.layout()
let size = self.bounds.size
self.dimNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width))
//let labelSize = labelNode.measure(CGSize(width: , height: 100.0))
//textNode.frame = CGRect(origin: CGPoint(x: floor(size.width, y: 81.0), size: labelSize)
}
}

View File

@ -121,7 +121,7 @@ public final class CallListController: ViewController {
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
if self.isNodeLoaded {
self.controllerNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat)
self.controllerNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, disableAnimations: self.presentationData.disableAnimations)
}
}

View File

@ -69,19 +69,20 @@ struct CallListNodeState: Equatable {
let theme: PresentationTheme
let strings: PresentationStrings
let dateTimeFormat: PresentationDateTimeFormat
let disableAnimations: Bool
let editing: Bool
let messageIdWithRevealedOptions: MessageId?
func withUpdatedPresentationData(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> CallListNodeState {
return CallListNodeState(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, editing: self.editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
func withUpdatedPresentationData(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) -> CallListNodeState {
return CallListNodeState(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, disableAnimations: disableAnimations, editing: self.editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
}
func withUpdatedEditing(_ editing: Bool) -> CallListNodeState {
return CallListNodeState(theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, editing: editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
return CallListNodeState(theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, disableAnimations: self.disableAnimations, editing: editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
}
func withUpdatedMessageIdWithRevealedOptions(_ messageIdWithRevealedOptions: MessageId?) -> CallListNodeState {
return CallListNodeState(theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, editing: self.editing, messageIdWithRevealedOptions: messageIdWithRevealedOptions)
return CallListNodeState(theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, disableAnimations: self.disableAnimations, editing: self.editing, messageIdWithRevealedOptions: messageIdWithRevealedOptions)
}
static func ==(lhs: CallListNodeState, rhs: CallListNodeState) -> Bool {
@ -198,7 +199,7 @@ final class CallListControllerNode: ASDisplayNode {
self.openInfo = openInfo
self.emptyStateUpdated = emptyStateUpdated
self.currentState = CallListNodeState(theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, editing: false, messageIdWithRevealedOptions: nil)
self.currentState = CallListNodeState(theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, disableAnimations: presentationData.disableAnimations, editing: false, messageIdWithRevealedOptions: nil)
self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true)
self.listNode = ListView()
@ -322,7 +323,7 @@ final class CallListControllerNode: ASDisplayNode {
}
}
return preparedCallListNodeViewTransition(from: previous, to: processedView, reason: reason, account: account, scrollPosition: update.scrollPosition)
return preparedCallListNodeViewTransition(from: previous, to: processedView, reason: reason, disableAnimations: state.disableAnimations, account: account, scrollPosition: update.scrollPosition)
|> map({ mappedCallListNodeViewListTransition(account: account, showSettings: showSettings, nodeInteraction: nodeInteraction, transition: $0) })
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
}
@ -371,8 +372,8 @@ final class CallListControllerNode: ASDisplayNode {
self.emptyStateDisposable.dispose()
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) {
if theme !== self.currentState.theme || strings !== self.currentState.strings {
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) {
if theme !== self.currentState.theme || strings !== self.currentState.strings || disableAnimations != self.currentState.disableAnimations {
switch self.mode {
case .tab:
self.backgroundColor = theme.chatList.backgroundColor
@ -385,7 +386,7 @@ final class CallListControllerNode: ASDisplayNode {
self.updateEmptyPlaceholder(theme: theme, strings: strings, type: self.currentLocationAndType.type, hidden: self.emptyTextNode.isHidden)
self.updateState {
return $0.withUpdatedPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat)
return $0.withUpdatedPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, disableAnimations: disableAnimations)
}
}
}

View File

@ -45,7 +45,7 @@ enum CallListNodeViewScrollPosition {
case index(index: MessageIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
}
func preparedCallListNodeViewTransition(from fromView: CallListNodeView?, to toView: CallListNodeView, reason: CallListNodeViewTransitionReason, account: Account, scrollPosition: CallListNodeViewScrollPosition?) -> Signal<CallListNodeViewTransition, NoError> {
func preparedCallListNodeViewTransition(from fromView: CallListNodeView?, to toView: CallListNodeView, reason: CallListNodeViewTransitionReason, disableAnimations: Bool, account: Account, scrollPosition: CallListNodeViewScrollPosition?) -> Signal<CallListNodeViewTransition, NoError> {
return Signal { subscriber in
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
@ -74,7 +74,9 @@ func preparedCallListNodeViewTransition(from fromView: CallListNodeView?, to toV
let _ = options.insert(.Synchronous)
case .interactiveChanges:
let _ = options.insert(.AnimateAlpha)
let _ = options.insert(.AnimateInsertion)
if !disableAnimations {
let _ = options.insert(.AnimateInsertion)
}
for (index, _, _) in indicesAndItems.sorted(by: { $0.0 > $1.0 }) {
let adjustedIndex = updatedCount - 1 - index

View File

@ -98,7 +98,11 @@ final class ChangePhoneNumberController: ViewController {
}
@objc func nextPressed() {
let (_, number) = self.controllerNode.codeAndNumber
let (code, number) = self.controllerNode.codeAndNumber
var phoneNumber = number
if let code = code {
phoneNumber = "\(code)\(phoneNumber)"
}
if !number.isEmpty {
self.inProgress = true
self.requestDisposable.set((requestChangeAccountPhoneNumberVerification(account: self.account, phoneNumber: self.controllerNode.currentNumber) |> deliverOnMainQueue).start(next: { [weak self] next in
@ -119,7 +123,7 @@ final class ChangePhoneNumberController: ViewController {
case .invalidPhoneNumber:
text = presentationData.strings.Login_InvalidPhoneError
case .phoneNumberOccupied:
text = presentationData.strings.ChangePhone_ErrorOccupied(number).0
text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(phoneNumber)).0
case .generic:
text = presentationData.strings.Login_UnknownError
}

View File

@ -2,6 +2,7 @@ import Foundation
import AsyncDisplayKit
import Display
import TelegramCore
import CoreTelephony
private func generateCountryButtonBackground(color: UIColor, strokeColor: UIColor) -> UIImage? {
return generateImage(CGSize(width: 45.0, height: 44.0 + 6.0), rotatedContext: { size, context in
@ -149,7 +150,7 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
self.phoneInputNode.countryCodeUpdated = { [weak self] code in
if let strongSelf = self {
if let code = Int(code), let (coutnryId, countryName) = countryCodeToIdAndName[code] {
if let code = Int(code), let (_, countryName) = countryCodeToIdAndName[code] {
strongSelf.countryButton.setTitle(countryName, with: Font.regular(17.0), with: strongSelf.presentationData.theme.list.itemPrimaryTextColor, for: [])
} else {
strongSelf.countryButton.setTitle(strongSelf.presentationData.strings.Login_CountryCode, with: Font.regular(17.0), with: strongSelf.presentationData.theme.list.itemPrimaryTextColor, for: [])
@ -157,7 +158,29 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
}
}
self.phoneInputNode.number = "+1"
var countryId: String? = nil
let networkInfo = CTTelephonyNetworkInfo()
if let carrier = networkInfo.subscriberCellularProvider {
countryId = carrier.isoCountryCode
}
if countryId == nil {
countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String
}
var countryCodeAndId: (Int32, String) = (1, "US")
if let countryId = countryId {
let normalizedId = countryId.uppercased()
for (code, idAndName) in countryCodeToIdAndName {
if idAndName.0 == normalizedId {
countryCodeAndId = (Int32(code), idAndName.0.uppercased())
break
}
}
}
self.phoneInputNode.number = "+\(countryCodeAndId.0)"
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {

View File

@ -564,7 +564,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
text = presentationData.strings.Channel_NotificationLoading
}
entries.append(.privateLink(presentationData.theme, text, link))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
switch mode {
case .initialSetup:
break
@ -867,9 +867,6 @@ public func channelVisibilityController(account: Account, peerId: PeerId, mode:
invokeAction()
}
})
} else {
switch mode {
case .initialSetup:
@ -926,7 +923,13 @@ public func channelVisibilityController(account: Account, peerId: PeerId, mode:
}
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(isGroup ? presentationData.strings.GroupInfo_GroupType : presentationData.strings.Channel_TypeSetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let title: String
if case .privateLink = mode {
title = presentationData.strings.GroupInfo_InviteLink_Title
} else {
title = isGroup ? presentationData.strings.GroupInfo_GroupType : presentationData.strings.Channel_TypeSetup_Title
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(entries: channelVisibilityControllerEntries(presentationData: presentationData, mode: mode, view: view, publicChannelsToRevoke: publicChannelsToRevoke, state: state), style: .blocks, crossfadeState: crossfade, animateChanges: false)
return (controllerState, (listState, arguments))

View File

@ -13,14 +13,12 @@ private let messageFixedFont: UIFont = UIFont(name: "Menlo-Regular", size: 16.0)
final class ChatBotInfoItem: ListViewItem {
fileprivate let text: String
fileprivate let controllerInteraction: ChatControllerInteraction
fileprivate let theme: ChatPresentationThemeData
fileprivate let strings: PresentationStrings
fileprivate let presentationData: ChatPresentationData
init(text: String, controllerInteraction: ChatControllerInteraction, theme: ChatPresentationThemeData, strings: PresentationStrings) {
init(text: String, controllerInteraction: ChatControllerInteraction, presentationData: ChatPresentationData) {
self.text = text
self.controllerInteraction = controllerInteraction
self.theme = theme
self.strings = strings
self.presentationData = presentationData
}
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
@ -77,6 +75,8 @@ final class ChatBotInfoItemNode: ListViewItemNode {
private var theme: ChatPresentationThemeData?
private var item: ChatBotInfoItem?
init() {
self.offsetContainer = ASDisplayNode()
@ -106,10 +106,12 @@ final class ChatBotInfoItemNode: ListViewItemNode {
let currentTextAndEntities = self.currentTextAndEntities
let currentTheme = self.theme
return { [weak self] item, params in
self?.item = item
var updatedBackgroundImage: UIImage?
if currentTheme != item.theme {
let principalGraphics = PresentationResourcesChat.principalGraphics(item.theme.theme, wallpaper: !item.theme.wallpaper.isEmpty)
updatedBackgroundImage = PresentationResourcesChat.chatInfoItemBackgroundImage(item.theme.theme, wallpaper: !item.theme.wallpaper.isEmpty)
if currentTheme != item.presentationData.theme {
//let principalGraphics = PresentationResourcesChat.principalGraphics(item.presentationData.theme.theme, wallpaper: !item.presentationData.theme.wallpaper.isEmpty)
updatedBackgroundImage = PresentationResourcesChat.chatInfoItemBackgroundImage(item.presentationData.theme.theme, wallpaper: !item.presentationData.theme.wallpaper.isEmpty)
}
var updatedTextAndEntities: (String, [MessageTextEntity])
@ -123,7 +125,7 @@ final class ChatBotInfoItemNode: ListViewItemNode {
updatedTextAndEntities = (item.text, generateTextEntities(item.text, enabledTypes: .all))
}
let attributedText = stringWithAppliedEntities(updatedTextAndEntities.0, entities: updatedTextAndEntities.1, baseColor: item.theme.theme.chat.bubble.infoPrimaryTextColor, linkColor: item.theme.theme.chat.bubble.infoLinkTextColor, baseFont: messageFont, linkFont: messageFont, boldFont: messageBoldFont, italicFont: messageItalicFont, fixedFont: messageFixedFont)
let attributedText = stringWithAppliedEntities(updatedTextAndEntities.0, entities: updatedTextAndEntities.1, baseColor: item.presentationData.theme.theme.chat.bubble.infoPrimaryTextColor, linkColor: item.presentationData.theme.theme.chat.bubble.infoLinkTextColor, baseFont: messageFont, linkFont: messageFont, boldFont: messageBoldFont, italicFont: messageItalicFont, fixedFont: messageFixedFont)
let horizontalEdgeInset: CGFloat = 10.0 + params.leftInset
let horizontalContentInset: CGFloat = 12.0
@ -138,7 +140,7 @@ final class ChatBotInfoItemNode: ListViewItemNode {
let itemLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: textLayout.size.height + verticalItemInset * 2.0 + verticalContentInset * 2.0 + 4.0), insets: UIEdgeInsets())
return (itemLayout, { _ in
if let strongSelf = self {
strongSelf.theme = item.theme
strongSelf.theme = item.presentationData.theme
if let updatedBackgroundImage = updatedBackgroundImage {
strongSelf.backgroundNode.image = updatedBackgroundImage
@ -238,4 +240,11 @@ final class ChatBotInfoItemNode: ListViewItemNode {
break
}
}
override public var wantsScrollDynamics: Bool {
if let disableAnimations = self.item?.presentationData.disableAnimations {
return !disableAnimations
}
return true
}
}

View File

@ -94,7 +94,7 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode {
let buttonSize = self.button.measure(CGSize(width: width - 80.0, height: 100.0))
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize)
@ -105,6 +105,6 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -129,7 +129,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
}
}
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
let buttonSize = self.button.bounds.size
self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize)
@ -141,6 +141,6 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -211,9 +211,9 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, fontSize: self.presentationData.fontSize, accountPeerId: account.peerId, mode: mode, chatLocation: chatLocation)
var enableMediaAccessoryPanel = false
var mediaAccessoryPanelVisibility = MediaAccessoryPanelVisibility.none
if case .standard = mode {
enableMediaAccessoryPanel = true
mediaAccessoryPanelVisibility = .specific(size: .compact)
} else {
locationBroadcastPanelSource = .none
}
@ -224,7 +224,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin
default:
navigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData)
}
super.init(account: account, navigationBarPresentationData: navigationBarPresentationData, enableMediaAccessoryPanel: enableMediaAccessoryPanel, locationBroadcastPanelSource: locationBroadcastPanelSource)
super.init(account: account, navigationBarPresentationData: navigationBarPresentationData, mediaAccessoryPanelVisibility: mediaAccessoryPanelVisibility, locationBroadcastPanelSource: locationBroadcastPanelSource)
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
@ -2848,6 +2848,8 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin
self.validLayout = layout
self.chatTitleView?.layoutMetrics = layout.metrics
self.chatDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop in
self.chatDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop)
})
@ -3621,7 +3623,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin
}
private func enqueueMediaMessages(signals: [Any]?) {
if case let .peer(peerId) = self.chatLocation {
if case .peer = self.chatLocation {
self.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(account: self.account, signals: signals!) |> deliverOnMainQueue).start(next: { [weak self] messages in
if let strongSelf = self {
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId

View File

@ -298,7 +298,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
if case let .peer(peerId) = strongSelf.chatLocation {
if case .peer = strongSelf.chatLocation {
strongSelf.sendMessages(messages)
}
}
@ -309,11 +309,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.textInputPanelNode?.pasteImages = { [weak self] images in
self?.displayPasteMenu(images)
}
self.textInputPanelNode?.pasteData = { [weak self] data in
//self?.sendGifData(data)
}
self.textInputPanelNode?.displayAttachmentMenu = { [weak self] in
self?.displayAttachmentMenu()
}
self.textInputPanelNode?.updateActivity = { [weak self] in
self?.updateTypingActivity(true)
}
@ -639,7 +640,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
if case .standard(true) = self.chatPresentationInterfaceState.mode {
inputPanelSize = CGSize(width: layout.size.width, height: 47.0)
self.inputPanelNode = nil
inputPanelSize = CGSize(width: layout.size.width, height: 0.0)
}
if let inputMediaNode = self.inputMediaNode, inputMediaNode != self.inputNode {
@ -649,7 +651,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
transition.updateFrame(node: self.titleAccessoryPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: 56.0)))
var titleAccessoryPanelFrame: CGRect?
if let titleAccessoryPanelNode = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: panelHeight))
insets.top += panelHeight
}
@ -855,8 +857,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
listInsets.left += 6.0
listInsets.right += 6.0
listInsets.top += 6.0
containerInsets.bottom += 6.0
//listInsets.bottom += 6.0
}
}
@ -1675,7 +1675,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
if let menuHeight = menuHeight {
if let _ = self.controllerInteraction.contextHighlightedState?.messageStableId, let (menuController, node, frame) = displayContextMenuController {
self.controllerInteraction.presentController(menuController, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
if let strongSelf = self {
var bounds = strongSelf.bounds

View File

@ -8,13 +8,11 @@ import TelegramCore
private let messageFont = Font.medium(14.0)
final class ChatEmptyItem: ListViewItem {
fileprivate let theme: PresentationTheme
fileprivate let strings: PresentationStrings
fileprivate let presentationData: ChatPresentationData
fileprivate let tagMask: MessageTags?
init(theme: PresentationTheme, strings: PresentationStrings, tagMask: MessageTags?) {
self.theme = theme
self.strings = strings
init(presentationData: ChatPresentationData, tagMask: MessageTags?) {
self.presentationData = presentationData
self.tagMask = tagMask
}
@ -71,6 +69,8 @@ final class ChatEmptyItemNode: ListViewItemNode {
private var theme: PresentationTheme?
private var item: ChatEmptyItem?
init(rotated: Bool) {
self.rotated = rotated
self.offsetContainer = ASDisplayNode()
@ -98,28 +98,30 @@ final class ChatEmptyItemNode: ListViewItemNode {
let makeTextLayout = TextNode.asyncLayout(self.textNode)
let currentTheme = self.theme
return { [weak self] item, params in
self?.item = item
let width = params.width
var updatedBackgroundImage: UIImage?
let iconImage: UIImage? = PresentationResourcesChat.chatEmptyItemIconImage(item.theme)
let iconImage: UIImage? = PresentationResourcesChat.chatEmptyItemIconImage(item.presentationData.theme.theme)
if currentTheme !== item.theme {
updatedBackgroundImage = PresentationResourcesChat.chatEmptyItemBackgroundImage(item.theme)
if currentTheme !== item.presentationData.theme {
updatedBackgroundImage = PresentationResourcesChat.chatEmptyItemBackgroundImage(item.presentationData.theme.theme)
}
let attributedText: NSAttributedString
if let tagMask = item.tagMask {
let text: String
if tagMask == .photoOrVideo {
text = item.strings.SharedMedia_EmptyText
text = item.presentationData.strings.SharedMedia_EmptyText
} else if tagMask == .file {
text = item.strings.SharedMedia_EmptyFilesText
text = item.presentationData.strings.SharedMedia_EmptyFilesText
} else {
text = ""
}
attributedText = NSAttributedString(string: text, font: messageFont, textColor: item.theme.list.itemSecondaryTextColor, paragraphAlignment: .center)
attributedText = NSAttributedString(string: text, font: messageFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor, paragraphAlignment: .center)
} else {
attributedText = NSAttributedString(string: item.strings.Conversation_EmptyPlaceholder, font: messageFont, textColor: item.theme.chat.serviceMessage.serviceMessagePrimaryTextColor, paragraphAlignment: .center)
attributedText = NSAttributedString(string: item.presentationData.strings.Conversation_EmptyPlaceholder, font: messageFont, textColor: item.presentationData.theme.theme.chat.serviceMessage.serviceMessagePrimaryTextColor, paragraphAlignment: .center)
}
let horizontalEdgeInset: CGFloat = 10.0
@ -144,7 +146,7 @@ final class ChatEmptyItemNode: ListViewItemNode {
let itemLayout = ListViewItemNodeLayout(contentSize: CGSize(width: width, height: imageSize.height + imageSpacing + textLayout.size.height + verticalItemInset * 2.0 + verticalContentInset * 2.0 + 4.0), insets: UIEdgeInsets())
return (itemLayout, { _ in
if let strongSelf = self {
strongSelf.theme = item.theme
strongSelf.theme = item.presentationData.theme.theme
if let updatedBackgroundImage = updatedBackgroundImage {
strongSelf.backgroundNode.image = updatedBackgroundImage
@ -181,4 +183,11 @@ final class ChatEmptyItemNode: ListViewItemNode {
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false)
}
override public var wantsScrollDynamics: Bool {
if let disableAnimations = self.item?.presentationData.disableAnimations {
return !disableAnimations
}
return true
}
}

View File

@ -58,7 +58,7 @@ final class ChatFeedNavigationInputPanelNode: ChatInputPanelNode {
let buttonSize = self.button.measure(CGSize(width: width - leftInset - rightInset - 80.0, height: 100.0))
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize)
@ -66,7 +66,7 @@ final class ChatFeedNavigationInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -74,7 +74,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
if let maxReadIndex = view.maxReadIndex, includeUnreadEntry {
var i = 0
let unreadEntry: ChatHistoryEntry = .UnreadEntry(maxReadIndex, presentationData.theme, presentationData.strings)
let unreadEntry: ChatHistoryEntry = .UnreadEntry(maxReadIndex, presentationData)
for entry in entries {
if entry > unreadEntry {
if i == 0, case .HoleEntry = entry {
@ -97,7 +97,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
}
}
if let cachedPeerData = cachedPeerData as? CachedUserData, let botInfo = cachedPeerData.botInfo, !botInfo.description.isEmpty {
entries.insert(.ChatInfoEntry(botInfo.description, presentationData.theme, presentationData.strings), at: 0)
entries.insert(.ChatInfoEntry(botInfo.description, presentationData), at: 0)
} else if view.entries.isEmpty && includeEmptyEntry {
//entries.insert(.EmptyChatInfoEntry(presentationData.theme, presentationData.strings, view.tagMask), at: 0)
}

View File

@ -27,9 +27,9 @@ enum ChatHistoryEntry: Identifiable, Comparable {
case HoleEntry(MessageHistoryHole, PresentationTheme, PresentationStrings)
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, Bool)
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, Bool)], ChatPresentationData)
case UnreadEntry(MessageIndex, ChatPresentationThemeData, PresentationStrings)
case ChatInfoEntry(String, ChatPresentationThemeData, PresentationStrings)
case EmptyChatInfoEntry(PresentationTheme, PresentationStrings, MessageTags?)
case UnreadEntry(MessageIndex, ChatPresentationData)
case ChatInfoEntry(String, ChatPresentationData)
case EmptyChatInfoEntry(ChatPresentationData, MessageTags?)
case SearchEntry(PresentationTheme, PresentationStrings)
var stableId: UInt64 {
@ -59,7 +59,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
return MessageIndex(message)
case let .MessageGroupEntry(_, messages, _):
return MessageIndex(messages[messages.count - 1].0)
case let .UnreadEntry(index, _, _):
case let .UnreadEntry(index, _):
return index
case .ChatInfoEntry:
return MessageIndex.absoluteLowerBound()
@ -173,20 +173,20 @@ enum ChatHistoryEntry: Identifiable, Comparable {
} else {
return false
}
case let .UnreadEntry(lhsIndex, lhsTheme, lhsStrings):
if case let .UnreadEntry(rhsIndex, rhsTheme, rhsStrings) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings {
case let .UnreadEntry(lhsIndex, lhsPresentationData):
if case let .UnreadEntry(rhsIndex, rhsPresentationData) = rhs, lhsIndex == rhsIndex, lhsPresentationData === rhsPresentationData {
return true
} else {
return false
}
case let .ChatInfoEntry(lhsText, lhsTheme, lhsStrings):
if case let .ChatInfoEntry(rhsText, rhsTheme, rhsStrings) = rhs, lhsText == rhsText, lhsTheme == rhsTheme, lhsStrings === rhsStrings {
case let .ChatInfoEntry(lhsText, lhsPresentationData):
if case let .ChatInfoEntry(rhsText, rhsPresentationData) = rhs, lhsText == rhsText, lhsPresentationData === rhsPresentationData {
return true
} else {
return false
}
case let .EmptyChatInfoEntry(lhsTheme, lhsStrings, lhsTagMask):
if case let .EmptyChatInfoEntry(rhsTheme, rhsStrings, rhsTagMask) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsTagMask == rhsTagMask {
case let .EmptyChatInfoEntry(lhsPresentationData, lhsTagMask):
if case let .EmptyChatInfoEntry(rhsPresentationData, rhsTagMask) = rhs, lhsPresentationData === rhsPresentationData, lhsTagMask == rhsTagMask {
return true
} else {
return false

View File

@ -254,7 +254,7 @@ public final class ChatHistoryGridNode: GridNode, ChatHistoryNode {
self.chatPresentationDataPromise.set(account.telegramApplicationContext.presentationData |> map { presentationData in
return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, disableAnimations: presentationData.disableAnimations)
})
self.floatingSections = true

View File

@ -172,12 +172,12 @@ private func mappedInsertEntries(account: Account, chatLocation: ChatLocation, a
item = ListMessageHoleItem()
}
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .UnreadEntry(_, theme, strings):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, theme: theme, strings: strings), directionHint: entry.directionHint)
case let .ChatInfoEntry(text, theme, strings):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, theme: theme, strings: strings), directionHint: entry.directionHint)
case let .EmptyChatInfoEntry(theme, strings, tagMask):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(theme: theme, strings: strings, tagMask: tagMask), directionHint: entry.directionHint)
case let .UnreadEntry(_, presentationData):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData), directionHint: entry.directionHint)
case let .ChatInfoEntry(text, presentationData):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, presentationData: presentationData), directionHint: entry.directionHint)
case let .EmptyChatInfoEntry(presentationData, tagMask):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(presentationData: presentationData, tagMask: tagMask), directionHint: entry.directionHint)
case let .SearchEntry(theme, strings):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
controllerInteraction.openSearch()
@ -217,12 +217,12 @@ private func mappedUpdateEntries(account: Account, chatLocation: ChatLocation, a
item = ListMessageHoleItem()
}
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .UnreadEntry(_, theme, strings):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, theme: theme, strings: strings), directionHint: entry.directionHint)
case let .ChatInfoEntry(text, theme, strings):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, theme: theme, strings: strings), directionHint: entry.directionHint)
case let .EmptyChatInfoEntry(theme, strings, tagMask):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(theme: theme, strings: strings, tagMask: tagMask), directionHint: entry.directionHint)
case let .UnreadEntry(_, presentationData):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData), directionHint: entry.directionHint)
case let .ChatInfoEntry(text, presentationData):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, presentationData: presentationData), directionHint: entry.directionHint)
case let .EmptyChatInfoEntry(presentationData, tagMask):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(presentationData: presentationData, tagMask: tagMask), directionHint: entry.directionHint)
case let .SearchEntry(theme, strings):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
controllerInteraction.openSearch()
@ -261,7 +261,7 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
for entry in view.additionalData {
if case let .peer(_, value) = entry {
if let channel = value as? TelegramChannel, case .group = channel.info {
automaticMediaDownloadPeerType = .channel
automaticMediaDownloadPeerType = .group
}
break
}
@ -357,7 +357,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.currentPresentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.currentPresentationData.theme, wallpaper: self.currentPresentationData.chatWallpaper), fontSize: self.currentPresentationData.fontSize, strings: self.currentPresentationData.strings, dateTimeFormat: self.currentPresentationData.dateTimeFormat))
self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.currentPresentationData.theme, wallpaper: self.currentPresentationData.chatWallpaper), fontSize: self.currentPresentationData.fontSize, strings: self.currentPresentationData.strings, dateTimeFormat: self.currentPresentationData.dateTimeFormat, disableAnimations: self.currentPresentationData.disableAnimations))
super.init()
@ -672,19 +672,22 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
let previousTheme = strongSelf.currentPresentationData.theme
let previousStrings = strongSelf.currentPresentationData.strings
let previousWallpaper = strongSelf.currentPresentationData.chatWallpaper
let previousDisableAnimations = strongSelf.currentPresentationData.disableAnimations
strongSelf.currentPresentationData = presentationData
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings || previousWallpaper != presentationData.chatWallpaper {
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings || previousWallpaper != presentationData.chatWallpaper || previousDisableAnimations != presentationData.disableAnimations {
let themeData = ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper)
let chatPresentationData = ChatPresentationData(theme: themeData, fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, disableAnimations: presentationData.disableAnimations)
strongSelf.forEachItemHeaderNode { itemHeaderNode in
if let dateNode = itemHeaderNode as? ChatMessageDateHeaderNode {
dateNode.updateThemeAndStrings(theme: themeData, strings: presentationData.strings)
dateNode.updatePresentationData(chatPresentationData)
} else if let dateNode = itemHeaderNode as? ListMessageDateHeaderNode {
dateNode.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings)
}
}
strongSelf.chatPresentationDataPromise.set(.single(ChatPresentationData(theme: themeData, fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)))
strongSelf.chatPresentationDataPromise.set(.single(chatPresentationData))
}
}
})

View File

@ -15,4 +15,12 @@ class ChatInputPanelNode: ASDisplayNode {
func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 0.0
}
func defaultHeight(metrics: LayoutMetrics) -> CGFloat {
if case .regular = metrics.widthClass, case .regular = metrics.heightClass {
return 49.0
} else {
return 45.0
}
}
}

View File

@ -27,6 +27,8 @@ private let tabImageUnread = tabImageNone.flatMap({ image in
})
public class ChatListController: TelegramController, UIViewControllerPreviewingDelegate {
private var validLayout: ContainerViewLayout?
private let account: Account
private let controlsHistoryPreload: Bool
@ -67,7 +69,7 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
self.titleView = NetworkStatusTitleView(theme: self.presentationData.theme)
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), enableMediaAccessoryPanel: true, locationBroadcastPanelSource: .summary)
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .always, locationBroadcastPanelSource: .summary)
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
@ -270,12 +272,12 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
if self.isNodeLoaded {
self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations)
}
}
override public func loadDisplayNode() {
self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations)
self.chatListDisplayNode.navigationBar = self.navigationBar
@ -525,6 +527,8 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
self.validLayout = layout
self.chatListDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
}
@ -589,6 +593,10 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
}
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let layout = self.validLayout, case .compact = layout.metrics.widthClass else {
return nil
}
let boundsSize = self.view.bounds.size
var contentSize = CGSize(width: boundsSize.width, height: boundsSize.height - (boundsSize.height > boundsSize.width ? 50.0 : 10.0))
if (boundsSize.width.isEqual(to: 375.0) && boundsSize.height.isEqual(to: 812.0)) {

View File

@ -23,10 +23,10 @@ class ChatListControllerNode: ASDisplayNode {
var themeAndStrings: (PresentationTheme, PresentationStrings, dateTimeFormat: PresentationDateTimeFormat)
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
self.account = account
self.groupId = groupId
self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder)
self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, disableAnimations: disableAnimations)
self.themeAndStrings = (theme, strings, dateTimeFormat)
@ -61,11 +61,11 @@ class ChatListControllerNode: ASDisplayNode {
}
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
self.themeAndStrings = (theme, strings, dateTimeFormat)
self.backgroundColor = theme.chatList.backgroundColor
self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder)
self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, disableAnimations: disableAnimations)
self.searchDisplayController?.updateThemeAndStrings(theme: theme, strings: strings)
self.chatListEmptyNode?.updateThemeAndStrings(theme: theme, strings: strings)
}

View File

@ -164,27 +164,29 @@ private enum RevealOptionKey: Int32 {
private let itemHeight: CGFloat = 76.0
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool?, isMuted: Bool?, hasPeerGroupId: Bool?, canDelete: Bool) -> [ItemListRevealOption] {
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool?, isMuted: Bool?, hasPeerGroupId: Bool?, canDelete: Bool, isEditing: Bool) -> [ItemListRevealOption] {
var options: [ItemListRevealOption] = []
if let isPinned = isPinned {
if isPinned {
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.neutral1.fillColor, textColor: theme.list.itemDisclosureActions.neutral1.foregroundColor))
} else {
options.append(ItemListRevealOption(key: RevealOptionKey.pin.rawValue, title: strings.DialogList_Pin, icon: pinIcon, color: theme.list.itemDisclosureActions.neutral1.fillColor, textColor: theme.list.itemDisclosureActions.neutral1.foregroundColor))
if !isEditing {
if let isPinned = isPinned {
if isPinned {
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.neutral1.fillColor, textColor: theme.list.itemDisclosureActions.neutral1.foregroundColor))
} else {
options.append(ItemListRevealOption(key: RevealOptionKey.pin.rawValue, title: strings.DialogList_Pin, icon: pinIcon, color: theme.list.itemDisclosureActions.neutral1.fillColor, textColor: theme.list.itemDisclosureActions.neutral1.foregroundColor))
}
}
}
if let isMuted = isMuted {
if isMuted {
options.append(ItemListRevealOption(key: RevealOptionKey.unmute.rawValue, title: strings.Conversation_Unmute, icon: unmuteIcon, color: theme.list.itemDisclosureActions.neutral2.fillColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
} else {
options.append(ItemListRevealOption(key: RevealOptionKey.mute.rawValue, title: strings.Conversation_Mute, icon: muteIcon, color: theme.list.itemDisclosureActions.neutral2.fillColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
if let isMuted = isMuted {
if isMuted {
options.append(ItemListRevealOption(key: RevealOptionKey.unmute.rawValue, title: strings.Conversation_Unmute, icon: unmuteIcon, color: theme.list.itemDisclosureActions.neutral2.fillColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
} else {
options.append(ItemListRevealOption(key: RevealOptionKey.mute.rawValue, title: strings.Conversation_Mute, icon: muteIcon, color: theme.list.itemDisclosureActions.neutral2.fillColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
}
}
}
if let hasPeerGroupId = hasPeerGroupId {
if hasPeerGroupId {
options.append(ItemListRevealOption(key: RevealOptionKey.ungroup.rawValue, title: "Ungroup", icon: ungroupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
} else {
options.append(ItemListRevealOption(key: RevealOptionKey.group.rawValue, title: "Group", icon: groupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
if let hasPeerGroupId = hasPeerGroupId {
if hasPeerGroupId {
options.append(ItemListRevealOption(key: RevealOptionKey.ungroup.rawValue, title: "Ungroup", icon: ungroupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
} else {
options.append(ItemListRevealOption(key: RevealOptionKey.group.rawValue, title: "Group", icon: groupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
}
}
}
if canDelete {
@ -709,8 +711,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
isPinned = item.index.pinningIndex != nil
}
if item.enableContextActions && !item.editing && !isAd {
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, hasPeerGroupId: hasPeerGroupId, canDelete: true)
if item.enableContextActions && !isAd {
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, hasPeerGroupId: hasPeerGroupId, canDelete: true, isEditing: item.editing)
if itemPeer.peerId != item.account.peerId {
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread)
} else {
@ -723,8 +725,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
case .groupReference:
let isPinned = item.index.pinningIndex != nil
if item.enableContextActions && !item.editing {
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: nil, hasPeerGroupId: nil, canDelete: false)
if item.enableContextActions {
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: nil, hasPeerGroupId: nil, canDelete: false, isEditing: item.editing)
} else {
peerRevealOptions = []
}

View File

@ -333,12 +333,12 @@ final class ChatListNode: ListView {
var isEmptyUpdated: ((Bool) -> Void)?
private var wasEmpty: Bool?
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
self.account = account
self.controlsHistoryPreload = controlsHistoryPreload
self.mode = mode
self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil)
self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, disableAnimations: disableAnimations), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil)
self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true)
self.theme = theme
@ -475,7 +475,7 @@ final class ChatListNode: ListView {
}
}
return preparedChatListNodeViewTransition(from: previous, to: processedView, reason: reason, account: account, scrollPosition: updatedScrollPosition)
return preparedChatListNodeViewTransition(from: previous, to: processedView, reason: reason, disableAnimations: state.presentationData.disableAnimations, account: account, scrollPosition: updatedScrollPosition)
|> map({ mappedChatListNodeViewListTransition(account: account, nodeInteraction: nodeInteraction, peerGroupId: groupId, mode: mode, transition: $0) })
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
}
@ -768,7 +768,7 @@ final class ChatListNode: ListView {
self.activityStatusesDisposable?.dispose()
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
if theme !== self.currentState.presentationData.theme || strings !== self.currentState.presentationData.strings || dateTimeFormat != self.currentState.presentationData.dateTimeFormat {
self.theme = theme
@ -777,7 +777,7 @@ final class ChatListNode: ListView {
}
self.updateState {
return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder))
return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, disableAnimations: disableAnimations))
}
}
}

View File

@ -6,12 +6,14 @@ final class ChatListPresentationData {
let dateTimeFormat: PresentationDateTimeFormat
let nameSortOrder: PresentationPersonNameOrder
let nameDisplayOrder: PresentationPersonNameOrder
let disableAnimations: Bool
init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
self.theme = theme
self.strings = strings
self.dateTimeFormat = dateTimeFormat
self.nameSortOrder = nameSortOrder
self.nameDisplayOrder = nameDisplayOrder
self.disableAnimations = disableAnimations
}
}

View File

@ -507,7 +507,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
self.openMessage = openMessage
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder))
self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations))
self.recentListNode = ListView()
self.listNode = ListView()

View File

@ -154,7 +154,7 @@ final class ChatListSearchRecentPeersNode: ASDisplayNode {
case .disabled:
return .single(([], [:]))
case let .peers(peers):
return combineLatest(peers.map {account.postbox.peerView(id: $0.id)}) |> mapToSignal { peerViews -> Signal<([Peer], [PeerId: UnreadSearchBadge]), NoError> in
return combineLatest(peers.filter { !$0.isDeleted }.map {account.postbox.peerView(id: $0.id)}) |> mapToSignal { peerViews -> Signal<([Peer], [PeerId: UnreadSearchBadge]), NoError> in
return account.postbox.unreadMessageCountsView(items: peerViews.map {.peer($0.peerId)}) |> map { values in
var peers:[Peer] = []

View File

@ -44,7 +44,7 @@ enum ChatListNodeViewScrollPosition {
case index(index: ChatListIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
}
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, account: Account, scrollPosition: ChatListNodeViewScrollPosition?) -> Signal<ChatListNodeViewTransition, NoError> {
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, disableAnimations: Bool, account: Account, scrollPosition: ChatListNodeViewScrollPosition?) -> Signal<ChatListNodeViewTransition, NoError> {
return Signal { subscriber in
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
@ -98,7 +98,9 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV
let _ = options.insert(.AnimateCrossfade)
} else {
let _ = options.insert(.AnimateAlpha)
let _ = options.insert(.AnimateInsertion)
if !disableAnimations {
let _ = options.insert(.AnimateInsertion)
}
}
case .reload:
break

View File

@ -30,6 +30,8 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
self.emptyNode = ImmediateTextNode()
self.emptyNode.isLayerBacked = true
self.emptyNode.attributedText = NSAttributedString(string: strings.Conversation_EmptyGifPanelPlaceholder, font: Font.regular(15.0), textColor: theme.chat.inputMediaPanel.stickersSectionTextColor)
self.emptyNode.textAlignment = .center
self.emptyNode.maximumNumberOfLines = 3
super.init()

View File

@ -116,7 +116,7 @@ final class ChatMessageActionSheetControllerNode: ViewControllerTracingNode {
self.addSubnode(self.inputDimNode)
self.addSubnode(self.itemsShadowNode)
self.addSubnode(self.itemsContainerNode)
for actionNode in actionNodes {
self.itemsContainerNode.addSubnode(actionNode)
actionNode.addTarget(self, action: #selector(actionPressed(_:)), forControlEvents: .touchUpInside)
@ -205,7 +205,7 @@ final class ChatMessageActionSheetControllerNode: ViewControllerTracingNode {
}
}
if let associatedController = self.associatedController {
let subpoint = self.view.convert(point, to: associatedController.view)
let subpoint = self.view.convert(point, to: nil) // temporary fix of iPad landscape+keyboard issue. Point converts to portrait coordinate system otherwise
if let result = associatedController.view.hitTest(subpoint, with: event) {
return result
}

View File

@ -1040,7 +1040,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
} else {
minimalContentSize = layoutConstants.bubble.minimumSize
}
let layoutBubbleSize = CGSize(width: max(contentSize.width, headerSize.width) + layoutConstants.bubble.contentInsets.left + layoutConstants.bubble.contentInsets.right, height: max(minimalContentSize.height, headerSize.height + contentSize.height + layoutConstants.bubble.contentInsets.top + layoutConstants.bubble.contentInsets.bottom))
let calculatedBubbleHeight = headerSize.height + contentSize.height + layoutConstants.bubble.contentInsets.top + layoutConstants.bubble.contentInsets.bottom
let layoutBubbleSize = CGSize(width: max(contentSize.width, headerSize.width) + layoutConstants.bubble.contentInsets.left + layoutConstants.bubble.contentInsets.right, height: max(minimalContentSize.height, calculatedBubbleHeight))
var contentVerticalOffset: CGFloat = 0.0
if minimalContentSize.height > calculatedBubbleHeight + 2.0 {
contentVerticalOffset = floorToScreenPixels((minimalContentSize.height - calculatedBubbleHeight) / 2.0)
}
let backgroundFrame: CGRect
let contentOrigin: CGPoint
@ -1048,12 +1054,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
switch alignment {
case .none:
backgroundFrame = CGRect(origin: CGPoint(x: incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + avatarInset) : (params.width - params.rightInset - layoutBubbleSize.width - layoutConstants.bubble.edgeInset), y: 0.0), size: layoutBubbleSize)
contentOrigin = CGPoint(x: backgroundFrame.origin.x + (incoming ? layoutConstants.bubble.contentInsets.left : layoutConstants.bubble.contentInsets.right), y: backgroundFrame.origin.y + layoutConstants.bubble.contentInsets.top + headerSize.height)
contentOrigin = CGPoint(x: backgroundFrame.origin.x + (incoming ? layoutConstants.bubble.contentInsets.left : layoutConstants.bubble.contentInsets.right), y: backgroundFrame.origin.y + layoutConstants.bubble.contentInsets.top + headerSize.height + contentVerticalOffset)
contentUpperRightCorner = CGPoint(x: backgroundFrame.maxX - (incoming ? layoutConstants.bubble.contentInsets.right : layoutConstants.bubble.contentInsets.left), y: backgroundFrame.origin.y + layoutConstants.bubble.contentInsets.top + headerSize.height)
case .center:
let availableWidth = params.width - params.leftInset - params.rightInset
backgroundFrame = CGRect(origin: CGPoint(x: params.leftInset + floor((availableWidth - layoutBubbleSize.width) / 2.0), y: 0.0), size: layoutBubbleSize)
contentOrigin = CGPoint(x: backgroundFrame.minX + floor(layoutConstants.bubble.contentInsets.right + layoutConstants.bubble.contentInsets.left) / 2.0, y: backgroundFrame.minY + layoutConstants.bubble.contentInsets.top + headerSize.height)
contentOrigin = CGPoint(x: backgroundFrame.minX + floor(layoutConstants.bubble.contentInsets.right + layoutConstants.bubble.contentInsets.left) / 2.0, y: backgroundFrame.minY + layoutConstants.bubble.contentInsets.top + headerSize.height + contentVerticalOffset)
contentUpperRightCorner = CGPoint(x: backgroundFrame.maxX - (incoming ? layoutConstants.bubble.contentInsets.right : layoutConstants.bubble.contentInsets.left), y: backgroundFrame.origin.y + layoutConstants.bubble.contentInsets.top + headerSize.height)
}
@ -1755,9 +1761,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
switch item.content {
case let .message(message, _, _, _):
for media in message.media {
if media is TelegramMediaAction {
canHaveSelection = false
break
if let action = media as? TelegramMediaAction {
if case .phoneCall = action.action { } else {
canHaveSelection = false
break
}
}
}
default:
@ -1883,50 +1891,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
}
private func performMessageButtonAction(button: ReplyMarkupButton) {
if let item = self.item {
switch button.action {
case .text:
item.controllerInteraction.sendMessage(button.title)
case let .url(url):
item.controllerInteraction.openUrl(url, true, nil)
case .requestMap:
item.controllerInteraction.shareCurrentLocation()
case .requestPhone:
item.controllerInteraction.shareAccountContact()
case .openWebApp:
item.controllerInteraction.requestMessageActionCallback(item.message.id, nil, true)
case let .callback(data):
item.controllerInteraction.requestMessageActionCallback(item.message.id, data, false)
case let .switchInline(samePeer, query):
var botPeer: Peer?
var found = false
for attribute in item.message.attributes {
if let attribute = attribute as? InlineBotMessageAttribute {
if let peerId = attribute.peerId {
botPeer = item.message.peers[peerId]
found = true
}
}
}
if !found {
botPeer = item.message.author
}
var peerId: PeerId?
if samePeer {
peerId = item.message.id.peerId
}
if let botPeer = botPeer, let addressName = botPeer.addressName {
item.controllerInteraction.activateSwitchInline(peerId, "@\(addressName) \(query)")
}
case .payment:
item.controllerInteraction.openCheckoutOrReceipt(item.message.id)
}
}
}
@objc func shareButtonPressed() {
if let item = self.item {
if item.content.firstMessage.id.peerId == item.account.peerId {

View File

@ -17,13 +17,12 @@ final class ChatMessageDateHeader: ListViewItemHeader {
private let roundedTimestamp: Int32
let id: Int64
let theme: ChatPresentationThemeData
let strings: PresentationStrings
let action:((Int32)->Void)?
init(timestamp: Int32, theme: ChatPresentationThemeData, strings: PresentationStrings, action:((Int32)->Void)? = nil) {
let presentationData: ChatPresentationData
let action: ((Int32) -> Void)?
init(timestamp: Int32, presentationData: ChatPresentationData, action:((Int32) -> Void)? = nil) {
self.timestamp = timestamp
self.theme = theme
self.strings = strings
self.presentationData = presentationData
self.action = action
if timestamp == Int32.max {
self.roundedTimestamp = timestamp / (granularity) * (granularity)
@ -38,7 +37,7 @@ final class ChatMessageDateHeader: ListViewItemHeader {
let height: CGFloat = 34.0
func node() -> ListViewItemHeaderNode {
return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, theme: self.theme, strings: self.strings, action: self.action)
return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, presentationData: self.presentationData, action: self.action)
}
}
@ -81,17 +80,16 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
let stickBackgroundNode: ASImageNode
private let localTimestamp: Int32
private var theme: ChatPresentationThemeData
private var strings: PresentationStrings
private var presentationData: ChatPresentationData
private var flashingOnScrolling = false
private var stickDistanceFactor: CGFloat = 0.0
private var action:((Int32)->Void)? = nil
private var action:((Int32) -> Void)? = nil
init(localTimestamp: Int32, theme: ChatPresentationThemeData, strings: PresentationStrings, action:((Int32)->Void)? = nil) {
init(localTimestamp: Int32, presentationData: ChatPresentationData, action:((Int32) -> Void)? = nil) {
self.presentationData = presentationData
self.localTimestamp = localTimestamp
self.theme = theme
self.strings = strings
self.action = action
self.labelNode = TextNode()
@ -115,7 +113,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
let graphics = PresentationResourcesChat.principalGraphics(theme.theme, wallpaper: !theme.wallpaper.isEmpty)
let graphics = PresentationResourcesChat.principalGraphics(presentationData.theme.theme, wallpaper: !presentationData.theme.wallpaper.isEmpty)
self.backgroundNode.image = graphics.dateStaticBackground
self.stickBackgroundNode.image = graphics.dateFloatingBackground
@ -139,15 +137,15 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
let text: String
if timeinfo.tm_year == timeinfoNow.tm_year {
if timeinfo.tm_yday == timeinfoNow.tm_yday {
text = strings.Weekday_Today
text = presentationData.strings.Weekday_Today
} else {
text = strings.Date_ChatDateHeader(monthAtIndex(Int(timeinfo.tm_mon), strings: strings), "\(timeinfo.tm_mday)").0
text = presentationData.strings.Date_ChatDateHeader(monthAtIndex(Int(timeinfo.tm_mon), strings: presentationData.strings), "\(timeinfo.tm_mday)").0
}
} else {
text = strings.Date_ChatDateHeaderYear(monthAtIndex(Int(timeinfo.tm_mon), strings: strings), "\(timeinfo.tm_mday)", "\(1900 + timeinfo.tm_year)").0
text = presentationData.strings.Date_ChatDateHeaderYear(monthAtIndex(Int(timeinfo.tm_mon), strings: presentationData.strings), "\(timeinfo.tm_mday)", "\(1900 + timeinfo.tm_year)").0
}
let attributedString = NSAttributedString(string: text, font: titleFont, textColor: theme.theme.chat.serviceMessage.dateTextColor)
let attributedString = NSAttributedString(string: text, font: titleFont, textColor: presentationData.theme.theme.chat.serviceMessage.dateTextColor)
let labelLayout = TextNode.asyncLayout(self.labelNode)
let (size, apply) = labelLayout(TextNodeLayoutArguments(attributedString: attributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 320.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
@ -164,18 +162,14 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
}
override func didLoad() {
super.didLoad()
self.view.addGestureRecognizer(ListViewTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
func updateThemeAndStrings(theme: ChatPresentationThemeData, strings: PresentationStrings) {
self.theme = theme
self.strings = strings
let graphics = PresentationResourcesChat.principalGraphics(theme.theme, wallpaper: !theme.wallpaper.isEmpty)
func updatePresentationData(_ presentationData: ChatPresentationData) {
let graphics = PresentationResourcesChat.principalGraphics(presentationData.theme.theme, wallpaper: !presentationData.theme.wallpaper.isEmpty)
self.backgroundNode.image = graphics.dateStaticBackground
self.stickBackgroundNode.image = graphics.dateFloatingBackground
@ -261,4 +255,8 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
action?(self.localTimestamp)
}
}
override public var wantsScrollDynamics: Bool {
return !self.presentationData.disableAnimations
}
}

View File

@ -8,11 +8,10 @@ import TelegramCore
class ChatMessageInstantVideoItemNode: ChatMessageItemView {
private let interactiveVideoNode: ChatMessageInteractiveInstantVideoNode
private var selectionNode: ChatMessageSelectionNode?
private var swipeToReplyNode: ChatMessageSwipeToReplyNode?
private var swipeToReplyFeedback: HapticFeedback?
private var selectionNode: ChatMessageSelectionNode?
private var appliedItem: ChatMessageItem?
private var forwardInfoNode: ChatMessageForwardInfoNode?
@ -21,6 +20,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
private var replyInfoNode: ChatMessageReplyInfoNode?
private var replyBackgroundNode: ASImageNode?
private var actionButtonsNode: ChatMessageActionButtonsNode?
private var currentSwipeToReplyTranslation: CGFloat = 0.0
override var visibility: ListViewItemNodeVisibility {
@ -76,9 +77,12 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
let currentForwardBackgroundNode = self.forwardBackgroundNode
let actionButtonsLayout = ChatMessageActionButtonsNode.asyncLayout(self.actionButtonsNode)
let currentItem = self.appliedItem
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
let baseWidth = params.width - params.leftInset - params.rightInset
let incoming = item.message.effectivelyIncoming(item.account.peerId)
let avatarInset: CGFloat
@ -124,6 +128,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?
var updatedReplyBackgroundNode: ASImageNode?
var replyBackgroundImage: UIImage?
var replyMarkup: ReplyMarkupMessageAttribute?
var inlineBotNameString: String?
for attribute in item.message.attributes {
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
let availableWidth = max(60.0, params.width - params.leftInset - params.rightInset - videoLayout.contentSize.width - 20.0 - layoutConstants.bubble.edgeInset * 2.0 - avatarInset - layoutConstants.bubble.contentInsets.left)
@ -136,6 +143,14 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
}
replyBackgroundImage = PresentationResourcesChat.chatServiceBubbleFillImage(item.presentationData.theme.theme)
break
} else if let attribute = attribute as? InlineBotMessageAttribute {
if let peerId = attribute.peerId, let bot = item.message.peers[peerId] as? TelegramUser {
inlineBotNameString = bot.username
} else {
inlineBotNameString = attribute.title
}
} else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty {
replyMarkup = attribute
}
}
@ -173,7 +188,25 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
forwardBackgroundImage = PresentationResourcesChat.chatServiceBubbleFillImage(item.presentationData.theme.theme)
}
return (ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: videoLayout.contentSize.height), insets: layoutInsets), { [weak self] animation in
var maxContentWidth = videoLayout.contentSize.width
var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animated: Bool) -> ChatMessageActionButtonsNode))?
if let replyMarkup = replyMarkup {
let (minWidth, buttonsLayout) = actionButtonsLayout(item.account, item.presentationData.theme.theme, item.presentationData.strings, replyMarkup, item.message, maxContentWidth)
maxContentWidth = max(maxContentWidth, minWidth)
actionButtonsFinalize = buttonsLayout
}
var actionButtonsSizeAndApply: (CGSize, (Bool) -> ChatMessageActionButtonsNode)?
if let actionButtonsFinalize = actionButtonsFinalize {
actionButtonsSizeAndApply = actionButtonsFinalize(maxContentWidth)
}
var layoutSize = CGSize(width: params.width, height: videoLayout.contentSize.height)
if let actionButtonsSizeAndApply = actionButtonsSizeAndApply {
layoutSize.height += actionButtonsSizeAndApply.0.height
}
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation in
if let strongSelf = self {
strongSelf.appliedItem = item
@ -241,6 +274,35 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
forwardInfoNode.removeFromSupernode()
strongSelf.forwardInfoNode = nil
}
if let actionButtonsSizeAndApply = actionButtonsSizeAndApply {
var animated = false
if let _ = strongSelf.actionButtonsNode {
if case .System = animation {
animated = true
}
}
let actionButtonsNode = actionButtonsSizeAndApply.1(animated)
let previousFrame = actionButtonsNode.frame
let actionButtonsFrame = CGRect(origin: CGPoint(x: videoFrame.minX, y: videoFrame.maxY), size: actionButtonsSizeAndApply.0)
actionButtonsNode.frame = actionButtonsFrame
if actionButtonsNode !== strongSelf.actionButtonsNode {
strongSelf.actionButtonsNode = actionButtonsNode
actionButtonsNode.buttonPressed = { button in
if let strongSelf = self {
strongSelf.performMessageButtonAction(button: button)
}
}
strongSelf.addSubnode(actionButtonsNode)
} else {
if case let .System(duration) = animation {
actionButtonsNode.layer.animateFrame(from: previousFrame, to: actionButtonsFrame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
}
}
} else if let actionButtonsNode = strongSelf.actionButtonsNode {
actionButtonsNode.removeFromSupernode()
strongSelf.actionButtonsNode = nil
}
}
})
}

View File

@ -279,11 +279,8 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
self.effectiveAuthorId = effectiveAuthor?.id
self.header = ChatMessageDateHeader(timestamp: content.index.timestamp, theme: presentationData.theme, strings: presentationData.strings, action: { timestamp in
//
self.header = ChatMessageDateHeader(timestamp: content.index.timestamp, presentationData: presentationData, action: { timestamp in
var calendar = NSCalendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")!
let date = Date(timeIntervalSince1970: TimeInterval(timestamp))
let components = calendar.dateComponents([.year, .month, .day], from: date)
@ -291,21 +288,6 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
if let date = calendar.date(from: components) {
controllerInteraction.navigateToFirstDateMessage(Int32(date.timeIntervalSince1970))
}
/*
unsigned unitFlags = NSCalendarUnitDay| NSCalendarUnitYear | NSCalendarUnitMonth;
NSDateComponents *components = [cal components:unitFlags fromDate:date];
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = day;
comps.year = components.year;
comps.month = components.month;
return [cal dateFromComponents:comps];
*/
// item.chatInteraction?.jumpToDate(CalendarUtils.monthDay(components.day!, date: date))
})
if displayAuthorInfo {
@ -330,7 +312,6 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
}
}
self.accessoryItem = accessoryItem
}
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {

View File

@ -2,6 +2,7 @@ import Foundation
import AsyncDisplayKit
import Display
import Postbox
import TelegramCore
struct ChatMessageItemWidthFill {
let compactInset: CGFloat
@ -190,4 +191,55 @@ public class ChatMessageItemView: ListViewItemNode {
return nil
}
}
func performMessageButtonAction(button: ReplyMarkupButton) {
if let item = self.item {
switch button.action {
case .text:
item.controllerInteraction.sendMessage(button.title)
case let .url(url):
item.controllerInteraction.openUrl(url, true, nil)
case .requestMap:
item.controllerInteraction.shareCurrentLocation()
case .requestPhone:
item.controllerInteraction.shareAccountContact()
case .openWebApp:
item.controllerInteraction.requestMessageActionCallback(item.message.id, nil, true)
case let .callback(data):
item.controllerInteraction.requestMessageActionCallback(item.message.id, data, false)
case let .switchInline(samePeer, query):
var botPeer: Peer?
var found = false
for attribute in item.message.attributes {
if let attribute = attribute as? InlineBotMessageAttribute {
if let peerId = attribute.peerId {
botPeer = item.message.peers[peerId]
found = true
}
}
}
if !found {
botPeer = item.message.author
}
var peerId: PeerId?
if samePeer {
peerId = item.message.id.peerId
}
if let botPeer = botPeer, let addressName = botPeer.addressName {
item.controllerInteraction.activateSwitchInline(peerId, "@\(addressName) \(query)")
}
case .payment:
item.controllerInteraction.openCheckoutOrReceipt(item.message.id)
}
}
}
override public var wantsScrollDynamics: Bool {
if let disableAnimations = self.item?.presentationData.disableAnimations {
return !disableAnimations
}
return true
}
}

View File

@ -76,7 +76,8 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
textColor = titleColor
}
var leftInset: CGFloat = 10.0
var leftInset: CGFloat = 11.0
let spacing: CGFloat = 2.0
var overlayIcon: UIImage?
@ -112,7 +113,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
var applyImage: (() -> TransformImageNode)?
if let imageDimensions = imageDimensions {
leftInset += 36.0
leftInset += 32.0
let boundingSize = CGSize(width: 30.0, height: 30.0)
var radius: CGFloat = 2.0
var imageSize = imageDimensions.aspectFilled(boundingSize)
@ -151,7 +152,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
let (titleLayout, titleApply) = titleNodeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: titleString, font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: contrainedTextSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (textLayout, textApply) = textNodeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: textString, font: textFont, textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: contrainedTextSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let size = CGSize(width: max(titleLayout.size.width, textLayout.size.width) + leftInset, height: titleLayout.size.height + textLayout.size.height)
let size = CGSize(width: max(titleLayout.size.width, textLayout.size.width) + leftInset, height: titleLayout.size.height + textLayout.size.height + 2 * spacing)
return (size, {
let node: ChatMessageReplyInfoNode
@ -186,8 +187,8 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
node.addSubnode(imageNode)
node.imageNode = imageNode
}
imageFrame = CGRect(origin: CGPoint(x: 8.0, y: 3.0), size: CGSize(width: 30.0, height: 30.0))
imageNode.frame = CGRect(origin: CGPoint(x: 8.0, y: 3.0), size: CGSize(width: 30.0, height: 30.0))
imageNode.frame = CGRect(origin: CGPoint(x: 8.0, y: 4.0 + UIScreenPixel), size: CGSize(width: 30.0, height: 30.0))
imageFrame = imageNode.frame
if let updateImageSignal = updateImageSignal {
imageNode.setSignal(updateImageSignal)
@ -216,11 +217,11 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
node.overlayIconNode = nil
}
titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: titleLayout.size)
textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: titleLayout.size.height), size: textLayout.size)
titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: spacing), size: titleLayout.size)
textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: titleNode.frame.maxY + spacing), size: textLayout.size)
node.lineNode.image = lineImage
node.lineNode.frame = CGRect(origin: CGPoint(x: 1.0, y: 3.0), size: CGSize(width: 2.0, height: max(0.0, size.height - 4.0)))
node.lineNode.frame = CGRect(origin: CGPoint(x: 1.0, y: 3.0), size: CGSize(width: 2.0, height: max(0.0, size.height - 5.0)))
node.contentNode.frame = CGRect(origin: CGPoint(), size: size)

View File

@ -116,7 +116,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, maxHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
self.validLayout = (width, leftInset, rightInset, maxHeight, metrics)
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
if self.presentationInterfaceState != interfaceState {
self.presentationInterfaceState = interfaceState
@ -186,6 +186,6 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -124,8 +124,8 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
if let strongSelf = self, let item = strongSelf.item {
if let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content, let image = content.image, let instantPage = content.instantPage {
var isGallery = false
switch websiteType(of: content) {
case .instagram, .twitter:
switch instantPageType(of: content) {
case .album:
let count = instantPageGalleryMedia(webpageId: webPage.webpageId, page: instantPage, galleryMedia: image).count
if count > 1 {
isGallery = true
@ -331,8 +331,8 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
}
if let webPage = self.webPage, case let .Loaded(content) = webPage.content, content.instantPage != nil {
switch instantPageType(of: content) {
case .album:
switch websiteType(of: content) {
case .instagram, .twitter:
return .none
default:
return .instantPage

View File

@ -53,17 +53,19 @@ public final class ChatPresentationData {
let fontSize: PresentationFontSize
let strings: PresentationStrings
let dateTimeFormat: PresentationDateTimeFormat
let disableAnimations: Bool
let messageFont: UIFont
let messageBoldFont: UIFont
let messageItalicFont: UIFont
let messageFixedFont: UIFont
init(theme: ChatPresentationThemeData, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) {
init(theme: ChatPresentationThemeData, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) {
self.theme = theme
self.fontSize = fontSize
self.strings = strings
self.dateTimeFormat = dateTimeFormat
self.disableAnimations = disableAnimations
let baseFontSize = fontSize.baseDisplaySize
self.messageFont = UIFont.systemFont(ofSize: baseFontSize)

View File

@ -26,7 +26,7 @@ final class ChatRecentActionsController: TelegramController {
self.titleView = ChatRecentActionsTitleView(color: self.presentationData.theme.rootController.navigationBar.primaryTextColor)
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), enableMediaAccessoryPanel: true, locationBroadcastPanelSource: .none)
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none)
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style

View File

@ -97,7 +97,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.state = ChatRecentActionsControllerState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, fontSize: self.presentationData.fontSize)
self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper), fontSize: self.presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat))
self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper), fontSize: self.presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, disableAnimations: self.presentationData.disableAnimations))
self.context = ChannelAdminEventLogContext(postbox: self.account.postbox, network: self.account.network, peerId: self.peer.id)

View File

@ -131,7 +131,7 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode {
}
}
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
transition.updateFrame(node: self.deleteButton, frame: CGRect(origin: CGPoint(x: leftInset, y: -1.0), size: CGSize(width: 48.0, height: panelHeight)))
transition.updateFrame(node: self.sendButton, frame: CGRect(origin: CGPoint(x: width - rightInset - 43.0 - UIScreenPixel, y: -UIScreenPixel), size: CGSize(width: 44.0, height: panelHeight)))
@ -158,7 +158,7 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -33,7 +33,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
}
}
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
let textSize = self.textNode.updateLayout(CGSize(width: width - leftInset - rightInset - 8.0 * 2.0, height: panelHeight))
self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - textSize.width) / 2.0), y: floor((panelHeight - textSize.height) / 2.0)), size: textSize)
@ -42,6 +42,6 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -104,7 +104,12 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode {
}
}
let panelHeight: CGFloat = 45.0
let panelHeight: CGFloat
if case .regular = metrics.widthClass {
panelHeight = 49.0
} else {
panelHeight = 45.0
}
transition.updateFrame(node: self.downButton, frame: CGRect(origin: CGPoint(x: leftInset + 12.0, y: 0.0), size: CGSize(width: 40.0, height: panelHeight)))
transition.updateFrame(node: self.upButton, frame: CGRect(origin: CGPoint(x: leftInset + 12.0 + 43.0, y: 0.0), size: CGSize(width: 40.0, height: panelHeight)))
@ -154,6 +159,6 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -112,8 +112,12 @@ private final class AccessoryItemIconButton: HighlightableButton {
private func calclulateTextFieldMinHeight(_ presentationInterfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
let baseFontSize = max(17.0, presentationInterfaceState.fontSize.baseDisplaySize)
let result: CGFloat
if baseFontSize.isEqual(to: 17.0) {
var result: CGFloat
if baseFontSize.isEqual(to: 26.0) {
result = 42.0
} else if baseFontSize.isEqual(to: 23.0) {
result = 38.0
} else if baseFontSize.isEqual(to: 17.0) {
result = 31.0
} else if baseFontSize.isEqual(to: 19.0) {
result = 33.0
@ -122,6 +126,11 @@ private func calclulateTextFieldMinHeight(_ presentationInterfaceState: ChatPres
} else {
result = 31.0
}
if case .regular = metrics.widthClass {
result = max(33.0, result)
}
return result
}
@ -178,6 +187,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
var displayAttachmentMenu: () -> Void = { }
var sendMessage: () -> Void = { }
var pasteImages: ([UIImage]) -> Void = { _ in }
var pasteData: (Data) -> Void = { _ in }
var updateHeight: () -> Void = { }
var updateActivity: () -> Void = { }
@ -482,7 +492,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let updatedMaxHeight = (CGFloat(maxNumberOfLines) * 22.0 + 10.0)
textFieldHeight = min(updatedMaxHeight, unboundTextFieldHeight)
textFieldHeight = max(textFieldMinHeight, min(updatedMaxHeight, unboundTextFieldHeight))
} else {
textFieldHeight = textFieldMinHeight
}
@ -1296,26 +1306,28 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
@objc func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
let pasteboard = UIPasteboard.general
var images: [UIImage] = []
var text: String?
for item in UIPasteboard.general.items {
if let image = item[kUTTypeJPEG as String] as? UIImage {
images.append(image)
} else if let image = item[kUTTypePNG as String] as? UIImage {
images.append(image)
} else if let image = item[kUTTypeGIF as String] as? UIImage {
images.append(image)
}
}
if !images.isEmpty {
self.pasteImages(images)
if let gifData = pasteboard.data(forPasteboardType: "com.compuserve.gif") {
self.pasteData(gifData)
return false
} else {
return true
for item in UIPasteboard.general.items {
if let image = item[kUTTypeJPEG as String] as? UIImage {
images.append(image)
} else if let image = item[kUTTypePNG as String] as? UIImage {
images.append(image)
} else if let image = item[kUTTypeGIF as String] as? UIImage {
images.append(image)
}
}
if !images.isEmpty {
self.pasteImages(images)
return false
}
}
return true
}
@objc func sendButtonPressed() {

View File

@ -185,39 +185,55 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
}
}
private func updateNetworkStatusNode(networkState: AccountNetworkState, metrics: LayoutMetrics) {
var isOnline = false
if case .online = networkState {
isOnline = true
}
if isOnline || metrics.widthClass == .regular {
self.contentContainer.isHidden = false
if let networkStatusNode = self.networkStatusNode {
self.networkStatusNode = nil
networkStatusNode.removeFromSupernode()
}
} else {
self.contentContainer.isHidden = true
let statusNode: ChatTitleNetworkStatusNode
if let current = self.networkStatusNode {
statusNode = current
} else {
statusNode = ChatTitleNetworkStatusNode(theme: self.theme)
self.networkStatusNode = statusNode
self.insertSubview(statusNode.view, belowSubview: self.button.view)
}
switch self.networkState {
case .waitingForNetwork:
statusNode.title = self.strings.State_WaitingForNetwork
case .connecting:
statusNode.title = self.strings.State_Connecting
case .updating:
statusNode.title = self.strings.State_Updating
case .online:
break
}
}
self.setNeedsLayout()
}
var networkState: AccountNetworkState = .online(proxy: nil) {
didSet {
if self.networkState != oldValue {
if case .online = self.networkState {
self.contentContainer.isHidden = false
if let networkStatusNode = self.networkStatusNode {
self.networkStatusNode = nil
networkStatusNode.removeFromSupernode()
}
} else {
self.contentContainer.isHidden = true
let statusNode: ChatTitleNetworkStatusNode
if let current = self.networkStatusNode {
statusNode = current
} else {
statusNode = ChatTitleNetworkStatusNode(theme: self.theme)
self.networkStatusNode = statusNode
self.insertSubview(statusNode.view, belowSubview: self.button.view)
}
switch self.networkState {
case .waitingForNetwork:
statusNode.title = self.strings.State_WaitingForNetwork
case .connecting:
statusNode.title = self.strings.State_Connecting
case .updating:
statusNode.title = self.strings.State_Updating
case .online:
break
}
}
self.setNeedsLayout()
updateNetworkStatusNode(networkState: self.networkState, metrics: self.layoutMetrics)
}
}
}
var layoutMetrics: LayoutMetrics = LayoutMetrics() {
didSet {
if self.layoutMetrics != oldValue {
updateNetworkStatusNode(networkState: self.networkState, metrics: self.layoutMetrics)
}
}
}

View File

@ -103,7 +103,7 @@ final class ChatUnblockInputPanelNode: ChatInputPanelNode {
let buttonSize = self.button.measure(CGSize(width: width - leftInset - rightInset - 80.0, height: 100.0))
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize)
@ -114,6 +114,6 @@ final class ChatUnblockInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -9,15 +9,13 @@ private let titleFont = UIFont.systemFont(ofSize: 13.0)
class ChatUnreadItem: ListViewItem {
let index: MessageIndex
let theme: ChatPresentationThemeData
let strings: PresentationStrings
let presentationData: ChatPresentationData
let header: ChatMessageDateHeader
init(index: MessageIndex, theme: ChatPresentationThemeData, strings: PresentationStrings) {
init(index: MessageIndex, presentationData: ChatPresentationData) {
self.index = index
self.theme = theme
self.strings = strings
self.header = ChatMessageDateHeader(timestamp: index.timestamp, theme: theme, strings: strings)
self.presentationData = presentationData
self.header = ChatMessageDateHeader(timestamp: index.timestamp, presentationData: presentationData)
}
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
@ -110,18 +108,18 @@ class ChatUnreadItemNode: ListViewItemNode {
return { item, params, dateAtBottom in
var updatedBackgroundImage: UIImage?
if currentTheme != item.theme {
updatedBackgroundImage = PresentationResourcesChat.chatUnreadBarBackgroundImage(item.theme.theme)
if currentTheme != item.presentationData.theme {
updatedBackgroundImage = PresentationResourcesChat.chatUnreadBarBackgroundImage(item.presentationData.theme.theme)
}
let (size, apply) = labelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.Conversation_UnreadMessages, font: titleFont, textColor: item.theme.theme.chat.serviceMessage.unreadBarTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (size, apply) = labelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Conversation_UnreadMessages, font: titleFont, textColor: item.presentationData.theme.theme.chat.serviceMessage.unreadBarTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let backgroundSize = CGSize(width: params.width, height: 25.0)
return (ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: 25.0), insets: UIEdgeInsets(top: 6.0 + (dateAtBottom ? layoutConstants.timestampHeaderHeight : 0.0), left: 0.0, bottom: 5.0, right: 0.0)), { [weak self] in
if let strongSelf = self {
strongSelf.item = item
strongSelf.theme = item.theme
strongSelf.theme = item.presentationData.theme
if let updatedBackgroundImage = updatedBackgroundImage {
strongSelf.backgroundNode.image = updatedBackgroundImage
@ -149,4 +147,11 @@ class ChatUnreadItemNode: ListViewItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
override public var wantsScrollDynamics: Bool {
if let disableAnimations = self.item?.presentationData.disableAnimations {
return !disableAnimations
}
return true
}
}

View File

@ -76,9 +76,17 @@ final class ChatVideoGalleryItemScrubberView: UIView {
}
func setStatusSignal(_ status: Signal<MediaPlayerStatus, NoError>?) {
self.scrubberNode.status = status
self.leftTimestampNode.status = status
self.rightTimestampNode.status = status
let mappedStatus: Signal<MediaPlayerStatus, NoError>?
if let status = status {
mappedStatus = combineLatest(status, self.scrubberNode.scrubbingTimestamp) |> map { status, scrubbingTimestamp -> MediaPlayerStatus in
return MediaPlayerStatus(generationTimestamp: status.generationTimestamp, duration: status.duration, dimensions: status.dimensions, timestamp: scrubbingTimestamp ?? status.timestamp, baseRate: status.baseRate, seekId: status.seekId, status: status.status)
}
} else {
mappedStatus = nil
}
self.scrubberNode.status = mappedStatus
self.leftTimestampNode.status = mappedStatus
self.rightTimestampNode.status = mappedStatus
}
func setBufferingStatusSignal(_ status: Signal<(IndexSet, Int)?, NoError>?) {

View File

@ -11,7 +11,7 @@ public extension TabBarControllerTheme {
public extension NavigationBarTheme {
public convenience init(rootControllerTheme: PresentationTheme) {
let theme = rootControllerTheme.rootController.navigationBar
self.init(buttonColor: theme.buttonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: theme.backgroundColor, separatorColor: theme.separatorColor, badgeBackgroundColor: theme.badgeBackgroundColor, badgeStrokeColor: theme.badgeStrokeColor, badgeTextColor: theme.badgeTextColor)
self.init(buttonColor: theme.buttonColor, disabledButtonColor: theme.disabledButtonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: theme.backgroundColor, separatorColor: theme.separatorColor, badgeBackgroundColor: theme.badgeBackgroundColor, badgeStrokeColor: theme.badgeStrokeColor, badgeTextColor: theme.badgeTextColor)
}
}

View File

@ -565,7 +565,7 @@ final class ContactListNode: ASDisplayNode {
private var presentationData: PresentationData
private var presentationDataDisposable: Disposable?
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder)>
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool)>
init(account: Account, presentation: ContactListPresentation, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil) {
self.account = account
@ -576,7 +576,7 @@ final class ContactListNode: ASDisplayNode {
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.dateTimeFormat, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder))
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.dateTimeFormat, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder, self.presentationData.disableAnimations))
super.init()
@ -722,7 +722,7 @@ final class ContactListNode: ASDisplayNode {
let entries = contactListNodeEntries(accountPeer: view.accountPeer, peers: peers, presences: view.peerPresences, presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, dateTimeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds)
let previous = previousEntries.swap(entries)
let animated: Bool
if let previous = previous {
if let previous = previous, !themeAndStrings.5 {
animated = (entries.count - previous.count) < 20
} else {
animated = false
@ -747,12 +747,13 @@ final class ContactListNode: ASDisplayNode {
if let strongSelf = self {
let previousTheme = strongSelf.presentationData.theme
let previousStrings = strongSelf.presentationData.strings
let previousDisableAnimations = strongSelf.presentationData.disableAnimations
strongSelf.presentationData = presentationData
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings || previousDisableAnimations != presentationData.disableAnimations {
strongSelf.backgroundColor = presentationData.theme.chatList.backgroundColor
strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder)))
strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, presentationData.disableAnimations)))
strongSelf.listNode.forEachAccessoryItemNode({ accessoryItemNode in
if let accessoryItemNode = accessoryItemNode as? ContactsSectionHeaderAccessoryItemNode {

View File

@ -153,7 +153,7 @@ class ContactMultiselectionController: ViewController {
}
override func loadDisplayNode() {
self.displayNode = ContactMultiselectionControllerNode(account: self.account, options: self.options, filters: filters)
self.displayNode = ContactMultiselectionControllerNode(account: self.account, mode: self.mode, options: self.options, filters: filters)
self._listReady.set(self.contactsNode.contactListNode.ready)
self.contactsNode.dismiss = { [weak self] in

View File

@ -44,12 +44,20 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
private var presentationData: PresentationData
private var presentationDataDisposable: Disposable?
init(account: Account, options: [ContactListAdditionalOption], filters: [ContactListFilter]) {
init(account: Account, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter]) {
self.account = account
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
let placeholder: String
switch mode {
case .peerSelection:
placeholder = self.presentationData.strings.Contacts_SearchLabel
default:
placeholder = self.presentationData.strings.Compose_TokenListPlaceholder
}
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: false, options: options), filters: filters, selectionState: ContactListNodeGroupSelectionState())
self.tokenListNode = EditableTokenListNode(theme: EditableTokenListNodeTheme(backgroundColor: self.presentationData.theme.rootController.navigationBar.backgroundColor, separatorColor: self.presentationData.theme.rootController.navigationBar.separatorColor, placeholderTextColor: self.presentationData.theme.list.itemPlaceholderTextColor, primaryTextColor: self.presentationData.theme.list.itemPrimaryTextColor, selectedTextColor: self.presentationData.theme.list.itemAccentColor, keyboardColor: self.presentationData.theme.chatList.searchBarKeyboardColor), placeholder: self.presentationData.strings.Compose_TokenListPlaceholder)
self.tokenListNode = EditableTokenListNode(theme: EditableTokenListNodeTheme(backgroundColor: self.presentationData.theme.rootController.navigationBar.backgroundColor, separatorColor: self.presentationData.theme.rootController.navigationBar.separatorColor, placeholderTextColor: self.presentationData.theme.list.itemPlaceholderTextColor, primaryTextColor: self.presentationData.theme.list.itemPrimaryTextColor, selectedTextColor: self.presentationData.theme.list.itemAccentColor, keyboardColor: self.presentationData.theme.chatList.searchBarKeyboardColor), placeholder: placeholder)
super.init()

View File

@ -24,6 +24,7 @@ private let rootTabBar = PresentationThemeRootTabBar(
private let rootNavigationBar = PresentationThemeRootNavigationBar(
buttonColor: accentColor,
disabledButtonColor: UIColor(rgb: 0x5b646f),
primaryTextColor: UIColor(rgb: 0xffffff),
secondaryTextColor: UIColor(rgb: 0x8B9197),
controlColor: UIColor(rgb: 0x8B9197),

View File

@ -24,6 +24,7 @@ private let rootTabBar = PresentationThemeRootTabBar(
private let rootNavigationBar = PresentationThemeRootNavigationBar(
buttonColor: accentColor,
disabledButtonColor: UIColor(rgb: 0x525252),
primaryTextColor: accentColor,
secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5),
controlColor: accentColor,

View File

@ -24,6 +24,7 @@ private func makeDefaultPresentationTheme(accentColor: UIColor, day: Bool) -> Pr
let rootNavigationBar = PresentationThemeRootNavigationBar(
buttonColor: accentColor,
disabledButtonColor: UIColor(rgb: 0xd0d0d0),
primaryTextColor: .black,
secondaryTextColor: UIColor(rgb: 0x787878),
controlColor: UIColor(rgb: 0x7e8791),

View File

@ -42,7 +42,7 @@ final class DeleteChatInputPanelNode: ChatInputPanelNode {
let buttonSize = self.button.measure(CGSize(width: width - leftInset - rightInset - 10.0, height: 100.0))
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize)
@ -50,6 +50,6 @@ final class DeleteChatInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -293,90 +293,11 @@ func editSettingsController(account: Account, currentName: ItemListAvatarAndName
var avatarGalleryTransitionArguments: ((AvatarGalleryEntry) -> GalleryTransitionArguments?)?
let avatarAndNameInfoContext = ItemListAvatarAndNameInfoItemContext()
var updateHiddenAvatarImpl: (() -> Void)?
var changeProfilePhotoImpl: (() -> Void)?
let wallpapersPromise = Promise<[TelegramWallpaper]>()
wallpapersPromise.set(telegramWallpapers(postbox: account.postbox, network: account.network))
let changeProfilePhotoImpl: () -> Void = {
let _ = (account.postbox.transaction { transaction -> Peer? in
return transaction.getPeer(account.peerId)
} |> deliverOnMainQueue).start(next: { peer in
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
legacyController.statusBar.statusBarStyle = .Ignore
let emptyController = LegacyEmptyController(context: legacyController.context)!
let navigationController = makeLegacyNavigationController(rootController: emptyController)
navigationController.setNavigationBarHidden(true, animated: false)
navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0)
legacyController.bind(controller: navigationController)
presentControllerImpl?(legacyController, nil)
var hasPhotos = false
if let peer = peer, !peer.profileImageRepresentations.isEmpty {
hasPhotos = true
}
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasDeleteButton: hasPhotos, personalPhoto: true, saveEditedPhotos: false, saveCapturedMedia: false)!
let _ = currentAvatarMixin.swap(mixin)
mixin.didFinishWithImage = { image in
if let image = image {
if let data = UIImageJPEGRepresentation(image, 0.6) {
let resource = LocalFileMediaResource(fileId: arc4random64())
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
let representation = TelegramMediaImageRepresentation(dimensions: CGSize(width: 640.0, height: 640.0), resource: resource)
updateState {
$0.withUpdatedUpdatingAvatar(.image(representation))
}
updateAvatarDisposable.set((updateAccountPhoto(account: account, resource: resource) |> deliverOnMainQueue).start(next: { result in
switch result {
case .complete:
updateState {
$0.withUpdatedUpdatingAvatar(nil)
}
case .progress:
break
}
}))
}
}
}
mixin.didFinishWithDelete = {
let _ = currentAvatarMixin.swap(nil)
updateState {
if let profileImage = peer?.smallProfileImage {
return $0.withUpdatedUpdatingAvatar(.image(profileImage))
} else {
return $0.withUpdatedUpdatingAvatar(.none)
}
}
updateAvatarDisposable.set((updateAccountPhoto(account: account, resource: nil) |> deliverOnMainQueue).start(next: { result in
switch result {
case .complete:
updateState {
$0.withUpdatedUpdatingAvatar(nil)
}
case .progress:
break
}
}))
}
mixin.didDismiss = { [weak legacyController] in
let _ = currentAvatarMixin.swap(nil)
legacyController?.dismiss()
}
let menuController = mixin.present()
if let menuController = menuController {
menuController.customRemoveFromParentViewController = { [weak legacyController] in
legacyController?.dismiss()
}
}
})
}
let arguments = EditSettingsItemArguments(account: account, accountManager: accountManager, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
var updating = false
updateState {
@ -388,7 +309,7 @@ func editSettingsController(account: Account, currentName: ItemListAvatarAndName
return
}
changeProfilePhotoImpl()
changeProfilePhotoImpl?()
}, pushController: { controller in
pushControllerImpl?(controller)
}, presentController: { controller in
@ -500,6 +421,88 @@ func editSettingsController(account: Account, currentName: ItemListAvatarAndName
}
}
}
changeProfilePhotoImpl = { [weak controller] in
let _ = (account.postbox.transaction { transaction -> Peer? in
return transaction.getPeer(account.peerId)
} |> deliverOnMainQueue).start(next: { peer in
controller?.view.endEditing(true)
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
legacyController.statusBar.statusBarStyle = .Ignore
let emptyController = LegacyEmptyController(context: legacyController.context)!
let navigationController = makeLegacyNavigationController(rootController: emptyController)
navigationController.setNavigationBarHidden(true, animated: false)
navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0)
legacyController.bind(controller: navigationController)
presentControllerImpl?(legacyController, nil)
var hasPhotos = false
if let peer = peer, !peer.profileImageRepresentations.isEmpty {
hasPhotos = true
}
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasDeleteButton: hasPhotos, personalPhoto: true, saveEditedPhotos: false, saveCapturedMedia: false)!
let _ = currentAvatarMixin.swap(mixin)
mixin.didFinishWithImage = { image in
if let image = image {
if let data = UIImageJPEGRepresentation(image, 0.6) {
let resource = LocalFileMediaResource(fileId: arc4random64())
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
let representation = TelegramMediaImageRepresentation(dimensions: CGSize(width: 640.0, height: 640.0), resource: resource)
updateState {
$0.withUpdatedUpdatingAvatar(.image(representation))
}
updateAvatarDisposable.set((updateAccountPhoto(account: account, resource: resource) |> deliverOnMainQueue).start(next: { result in
switch result {
case .complete:
updateState {
$0.withUpdatedUpdatingAvatar(nil)
}
case .progress:
break
}
}))
}
}
}
mixin.didFinishWithDelete = {
let _ = currentAvatarMixin.swap(nil)
updateState {
if let profileImage = peer?.smallProfileImage {
return $0.withUpdatedUpdatingAvatar(.image(profileImage))
} else {
return $0.withUpdatedUpdatingAvatar(.none)
}
}
updateAvatarDisposable.set((updateAccountPhoto(account: account, resource: nil) |> deliverOnMainQueue).start(next: { result in
switch result {
case .complete:
updateState {
$0.withUpdatedUpdatingAvatar(nil)
}
case .progress:
break
}
}))
}
mixin.didDismiss = { [weak legacyController] in
let _ = currentAvatarMixin.swap(nil)
legacyController?.dismiss()
}
let menuController = mixin.present()
if let menuController = menuController {
menuController.customRemoveFromParentViewController = { [weak legacyController] in
legacyController?.dismiss()
}
}
})
}
return controller
}

View File

@ -231,8 +231,8 @@ enum GalleryControllerItemSource {
}
class GalleryController: ViewController {
static let darkNavigationTheme = NavigationBarTheme(buttonColor: .white, primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
static let lightNavigationTheme = NavigationBarTheme(buttonColor: UIColor(rgb: 0x007ee5), primaryTextColor: .black, backgroundColor: UIColor(red: 0.968626451, green: 0.968626451, blue: 0.968626451, alpha: 1.0), separatorColor: UIColor(red: 0.6953125, green: 0.6953125, blue: 0.6953125, alpha: 1.0), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
static let darkNavigationTheme = NavigationBarTheme(buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
static let lightNavigationTheme = NavigationBarTheme(buttonColor: UIColor(rgb: 0x007ee5), disabledButtonColor: UIColor(rgb: 0xd0d0d0), primaryTextColor: .black, backgroundColor: UIColor(red: 0.968626451, green: 0.968626451, blue: 0.968626451, alpha: 1.0), separatorColor: UIColor(red: 0.6953125, green: 0.6953125, blue: 0.6953125, alpha: 1.0), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
private var galleryNode: GalleryControllerNode {
return self.displayNode as! GalleryControllerNode

View File

@ -155,8 +155,6 @@ final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
var removedNodes: [GalleryItemNode] = []
if !transaction.deleteItems.isEmpty || !transaction.insertItems.isEmpty {
let deleteItems = transaction.deleteItems.sorted()
@ -164,8 +162,8 @@ final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
self.items.remove(at: deleteItemIndex)
for i in 0 ..< self.itemNodes.count {
if self.itemNodes[i].index == deleteItemIndex {
removedNodes.append(self.itemNodes[i])
self.removeVisibleItemNode(internalIndex: i)
break
}
}
}

View File

@ -735,10 +735,6 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: peer, cachedData: view.cachedData, state: infoState, updatingAvatar: state.updatingAvatar))
}
if canEditGroupInfo {
entries.append(GroupInfoEntry.setGroupPhoto(presentationData.theme, presentationData.strings.GroupInfo_SetGroupPhoto))
}
let peerNotificationSettings: TelegramPeerNotificationSettings = (view.notificationSettings as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings
let notificationsText: String
switch peerNotificationSettings.muteState {
@ -751,6 +747,10 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
}
if let editingState = state.editingState {
if canEditGroupInfo {
entries.append(GroupInfoEntry.setGroupPhoto(presentationData.theme, presentationData.strings.GroupInfo_SetGroupPhoto))
}
if let group = view.peers[view.peerId] as? TelegramGroup {
if case .creator = group.role {
entries.append(.adminManagement(presentationData.theme, presentationData.strings.GroupInfo_ChatAdmins))

View File

@ -26,14 +26,14 @@ final class HashtagSearchController: TelegramController {
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), enableMediaAccessoryPanel: true, locationBroadcastPanelSource: .none)
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none)
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
self.title = query
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations)
let location: SearchMessagesLocation = .general
let search = searchMessages(account: account, location: location, query: query)

View File

@ -453,7 +453,12 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
statusColor = item.theme.list.itemPrimaryTextColor
}
let (statusNodeLayout, statusNodeApply) = layoutStatusNode(TextNodeLayoutArguments(attributedString: NSAttributedString(string: statusText, font: statusFont, textColor: statusColor), backgroundColor: nil, maximumNumberOfLines: 3, truncationType: .end, constrainedSize: CGSize(width: baseWidth - 20, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
var availableStatusWidth = baseWidth - 20
if item.call != nil {
availableStatusWidth -= 44.0
}
let (statusNodeLayout, statusNodeApply) = layoutStatusNode(TextNodeLayoutArguments(attributedString: NSAttributedString(string: statusText, font: statusFont, textColor: statusColor), backgroundColor: nil, maximumNumberOfLines: 3, truncationType: .end, constrainedSize: CGSize(width: availableStatusWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let separatorHeight = UIScreenPixel
@ -660,6 +665,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
inputFirstField.textColor = item.theme.list.itemPrimaryTextColor
inputFirstField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
inputFirstField.autocorrectionType = .no
inputFirstField.returnKeyType = .next
inputFirstField.attributedPlaceholder = NSAttributedString(string: item.strings.UserInfo_FirstNamePlaceholder, font: Font.regular(17.0), textColor: item.theme.list.itemPlaceholderTextColor)
inputFirstField.attributedText = NSAttributedString(string: firstName, font: Font.regular(17.0), textColor: item.theme.list.itemPrimaryTextColor)
strongSelf.inputFirstField = inputFirstField
@ -675,6 +681,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
inputSecondField.textColor = item.theme.list.itemPrimaryTextColor
inputSecondField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
inputSecondField.autocorrectionType = .no
inputSecondField.returnKeyType = .done
inputSecondField.attributedPlaceholder = NSAttributedString(string: item.strings.UserInfo_LastNamePlaceholder, font: Font.regular(17.0), textColor: item.theme.list.itemPlaceholderTextColor)
inputSecondField.attributedText = NSAttributedString(string: lastName, font: Font.regular(17.0), textColor: item.theme.list.itemPrimaryTextColor)
strongSelf.inputSecondField = inputSecondField

View File

@ -161,6 +161,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
@objc func revealTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.updateRevealOffsetInternal(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
self.revealOptionsInteractivelyClosed()
}
}

View File

@ -173,12 +173,17 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
private var playbackStatusValue: MediaPlayerPlaybackStatus?
private var scrubbingBeginTimestamp: Double?
private var scrubbingTimestamp: Double?
private var scrubbingTimestampValue: Double?
var playbackStatusUpdated: ((MediaPlayerPlaybackStatus?) -> Void)?
var playerStatusUpdated: ((MediaPlayerStatus?) -> Void)?
var seek: ((Double) -> Void)?
private let _scrubbingTimestamp = Promise<Double?>(nil)
var scrubbingTimestamp: Signal<Double?, NoError> {
return self._scrubbingTimestamp.get()
}
var ignoreSeekId: Int?
var enableScrubbing: Bool = true {
@ -361,7 +366,8 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
if let strongSelf = self {
if let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
strongSelf.scrubbingBeginTimestamp = statusValue.timestamp
strongSelf.scrubbingTimestamp = statusValue.timestamp
strongSelf.scrubbingTimestampValue = statusValue.timestamp
strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue))
strongSelf.updateProgress()
}
}
@ -369,7 +375,8 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
handleNodeContainer.updateScrubbing = { [weak self] addedFraction in
if let strongSelf = self {
if let statusValue = strongSelf.statusValue, let scrubbingBeginTimestamp = strongSelf.scrubbingBeginTimestamp, Double(0.0).isLess(than: statusValue.duration) {
strongSelf.scrubbingTimestamp = scrubbingBeginTimestamp + statusValue.duration * Double(addedFraction)
strongSelf.scrubbingTimestampValue = max(0.0, min(statusValue.duration, scrubbingBeginTimestamp + statusValue.duration * Double(addedFraction)))
strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue))
strongSelf.updateProgress()
}
}
@ -377,13 +384,14 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
handleNodeContainer.endScrubbing = { [weak self] apply in
if let strongSelf = self {
strongSelf.scrubbingBeginTimestamp = nil
let scrubbingTimestamp = strongSelf.scrubbingTimestamp
strongSelf.scrubbingTimestamp = nil
if let scrubbingTimestamp = scrubbingTimestamp, apply {
let scrubbingTimestampValue = strongSelf.scrubbingTimestampValue
strongSelf.scrubbingTimestampValue = nil
strongSelf._scrubbingTimestamp.set(.single(nil))
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
if let statusValue = strongSelf.statusValue {
strongSelf.ignoreSeekId = statusValue.seekId
}
strongSelf.seek?(scrubbingTimestamp)
strongSelf.seek?(scrubbingTimestampValue)
}
strongSelf.updateProgress()
}
@ -404,7 +412,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
if let strongSelf = self {
if let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
strongSelf.scrubbingBeginTimestamp = statusValue.timestamp
strongSelf.scrubbingTimestamp = statusValue.timestamp
strongSelf.scrubbingTimestampValue = statusValue.timestamp
strongSelf.updateProgress()
}
}
@ -412,7 +420,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
handleNodeContainer.updateScrubbing = { [weak self] addedFraction in
if let strongSelf = self {
if let statusValue = strongSelf.statusValue, let scrubbingBeginTimestamp = strongSelf.scrubbingBeginTimestamp, Double(0.0).isLess(than: statusValue.duration) {
strongSelf.scrubbingTimestamp = scrubbingBeginTimestamp + statusValue.duration * Double(addedFraction)
strongSelf.scrubbingTimestampValue = scrubbingBeginTimestamp + statusValue.duration * Double(addedFraction)
strongSelf.updateProgress()
}
}
@ -420,10 +428,10 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
handleNodeContainer.endScrubbing = { [weak self] apply in
if let strongSelf = self {
strongSelf.scrubbingBeginTimestamp = nil
let scrubbingTimestamp = strongSelf.scrubbingTimestamp
strongSelf.scrubbingTimestamp = nil
if let scrubbingTimestamp = scrubbingTimestamp, apply {
strongSelf.seek?(scrubbingTimestamp)
let scrubbingTimestampValue = strongSelf.scrubbingTimestampValue
strongSelf.scrubbingTimestampValue = nil
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
strongSelf.seek?(scrubbingTimestampValue)
}
strongSelf.updateProgress()
}
@ -529,8 +537,8 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
if case .buffering(true, _) = statusValue.status {
initialBuffering = true
} else if Double(0.0).isLess(than: statusValue.duration) {
if let scrubbingTimestamp = self.scrubbingTimestamp {
timestampAndDuration = (max(0.0, min(scrubbingTimestamp, statusValue.duration)), statusValue.duration)
if let scrubbingTimestampValue = self.scrubbingTimestampValue {
timestampAndDuration = (max(0.0, min(scrubbingTimestampValue, statusValue.duration)), statusValue.duration)
} else {
timestampAndDuration = (statusValue.timestamp, statusValue.duration)
}
@ -539,7 +547,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
if let (timestamp, duration) = timestampAndDuration {
let progress = CGFloat(timestamp / duration)
if let _ = scrubbingTimestamp {
if let _ = scrubbingTimestampValue {
let fromRect = CGRect(origin: backgroundFrame.origin, size: CGSize(width: 0.0, height: backgroundFrame.size.height))
let toRect = CGRect(origin: backgroundFrame.origin, size: CGSize(width: backgroundFrame.size.width, height: backgroundFrame.size.height))
@ -641,8 +649,8 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
let timestampAndDuration: (timestamp: Double, duration: Double)?
if let statusValue = self.statusValue, Double(0.0).isLess(than: statusValue.duration) {
if let scrubbingTimestamp = self.scrubbingTimestamp {
timestampAndDuration = (max(0.0, min(scrubbingTimestamp, statusValue.duration)), statusValue.duration)
if let scrubbingTimestampValue = self.scrubbingTimestampValue {
timestampAndDuration = (max(0.0, min(scrubbingTimestampValue, statusValue.duration)), statusValue.duration)
} else {
timestampAndDuration = (statusValue.timestamp, statusValue.duration)
}
@ -652,7 +660,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
if let (timestamp, duration) = timestampAndDuration {
let progress = CGFloat(timestamp / duration)
if let _ = scrubbingTimestamp {
if let _ = scrubbingTimestampValue {
let fromRect = CGRect(origin: backgroundFrame.origin, size: CGSize(width: 0.0, height: backgroundFrame.size.height))
let toRect = CGRect(origin: backgroundFrame.origin, size: CGSize(width: backgroundFrame.size.width, height: backgroundFrame.size.height))

View File

@ -100,10 +100,12 @@ private func allOpenInOptions(applicationContext: TelegramApplicationContext, it
let lat = location.latitude
let lon = location.longitude
if let venue = location.venue, let venueId = venue.id, let provider = venue.provider, provider == "foursquare" {
options.append(OpenInOption(application: .other(title: "Foursquare", identifier: 306934924, scheme: "foursquare"), action: {
return .openUrl(url: "foursquare://venues/\(venueId)")
}))
if !withDirections {
if let venue = location.venue, let venueId = venue.id, let provider = venue.provider, provider == "foursquare" {
options.append(OpenInOption(application: .other(title: "Foursquare", identifier: 306934924, scheme: "foursquare"), action: {
return .openUrl(url: "foursquare://venues/\(venueId)")
}))
}
}
options.append(OpenInOption(application: .maps, action: {
@ -147,31 +149,33 @@ private func allOpenInOptions(applicationContext: TelegramApplicationContext, it
return .openUrl(url: "lyft://ridetype?id=lyft&destination[latitude]=\(lat)&destination[longitude]=\(lon)")
}))
options.append(OpenInOption(application: .other(title: "Citymapper", identifier: 469463298, scheme: "citymapper"), action: {
let endName: String
let endAddress: String
if let title = location.venue?.title.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), title.count > 0 {
endName = title
} else {
endName = ""
}
if let address = location.venue?.address?.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), address.count > 0 {
endAddress = address
} else {
endAddress = ""
}
return .openUrl(url: "citymapper://directions?endcoord=\(lat),\(lon)&endname=\(endName)&endaddress=\(endAddress)")
}))
if withDirections {
options.append(OpenInOption(application: .other(title: "Citymapper", identifier: 469463298, scheme: "citymapper"), action: {
let endName: String
let endAddress: String
if let title = location.venue?.title.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), title.count > 0 {
endName = title
} else {
endName = ""
}
if let address = location.venue?.address?.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), address.count > 0 {
endAddress = address
} else {
endAddress = ""
}
return .openUrl(url: "citymapper://directions?endcoord=\(lat),\(lon)&endname=\(endName)&endaddress=\(endAddress)")
}))
options.append(OpenInOption(application: .other(title: "Yandex.Navi", identifier: 474500851, scheme: "yandexnavi"), action: {
return .openUrl(url: "yandexnavi://build_route_on_map?lat_to=\(lat)&lon_to=\(lon)")
}))
}
options.append(OpenInOption(application: .other(title: "HERE Maps", identifier: 955837609, scheme: "here-location"), action: {
return .openUrl(url: "here-location://\(lat),\(lon)")
}))
if !withDirections {
options.append(OpenInOption(application: .other(title: "HERE Maps", identifier: 955837609, scheme: "here-location"), action: {
return .openUrl(url: "here-location://\(lat),\(lon)")
}))
}
options.append(OpenInOption(application: .other(title: "Waze", identifier: 323229106, scheme: "waze"), action: {
let url = "waze://?ll=\(lat),\(lon)"

View File

@ -41,10 +41,10 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec
self.requestDismiss = requestDismiss
self.requestShare = requestShare
if case .reversed = initialOrder {
self.currentIsReversed = true
} else {
if case .regular = initialOrder {
self.currentIsReversed = false
} else {
self.currentIsReversed = true
}
var openMessageImpl: ((MessageId) -> Bool)?
@ -125,8 +125,10 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec
self.controlsNode.updateOrder = { [weak self] order in
if let strongSelf = self {
var reversed = false
if case .reversed = order {
let reversed: Bool
if case .regular = order {
reversed = false
} else {
reversed = true
}
if reversed != strongSelf.currentIsReversed {

View File

@ -177,9 +177,9 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
self.addSubnode(self.separatorNode)
let mappedStatus = status |> map { value -> MediaPlayerStatus in
let mappedStatus = combineLatest(status, self.scrubberNode.scrubbingTimestamp) |> map { value, scrubbingTimestamp -> MediaPlayerStatus in
if let value = value {
return value.status
return MediaPlayerStatus(generationTimestamp: value.status.generationTimestamp, duration: value.status.duration, dimensions: value.status.dimensions, timestamp: scrubbingTimestamp ?? value.status.timestamp, baseRate: value.status.baseRate, seekId: value.status.seekId, status: value.status.status)
} else {
return MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused)
}
@ -222,16 +222,23 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
displayData = value.item.displayData
let baseColor: UIColor
if strongSelf.theme.list.itemPrimaryTextColor.isEqual(strongSelf.theme.list.itemAccentColor) {
baseColor = strongSelf.theme.list.controlSecondaryColor
} else {
baseColor = strongSelf.theme.list.itemPrimaryTextColor
}
if value.order != strongSelf.currentOrder {
strongSelf.updateOrder?(value.order)
strongSelf.currentOrder = value.order
switch value.order {
case .regular:
strongSelf.orderButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/OrderReverse"), color: strongSelf.theme.list.itemPrimaryTextColor)
strongSelf.orderButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/OrderReverse"), color: baseColor)
case .reversed:
strongSelf.orderButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/OrderReverse"), color: strongSelf.theme.list.itemAccentColor)
case .random:
strongSelf.orderButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/OrderRandom"), color: strongSelf.theme.list.itemPrimaryTextColor)
strongSelf.orderButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/OrderRandom"), color: strongSelf.theme.list.itemAccentColor)
}
}
if value.looping != strongSelf.currentLooping {
@ -239,15 +246,9 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
switch value.looping {
case .none:
let baseColor: UIColor
if strongSelf.theme.list.itemPrimaryTextColor.isEqual(strongSelf.theme.list.itemAccentColor) {
baseColor = strongSelf.theme.list.controlSecondaryColor
} else {
baseColor = strongSelf.theme.list.itemPrimaryTextColor
}
strongSelf.loopingButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Repeat"), color: baseColor)
case .item:
strongSelf.loopingButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/RepeatOne"), color: strongSelf.theme.list.itemPrimaryTextColor)
strongSelf.loopingButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/RepeatOne"), color: strongSelf.theme.list.itemAccentColor)
case .all:
strongSelf.loopingButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Repeat"), color: strongSelf.theme.list.itemAccentColor)
}

View File

@ -47,7 +47,7 @@ public class PeerMediaCollectionController: TelegramController {
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
self.interfaceState = PeerMediaCollectionInterfaceState(theme: self.presentationData.theme, strings: self.presentationData.strings)
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(self.presentationData.theme.rootController.navigationBar.backgroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)), enableMediaAccessoryPanel: true, locationBroadcastPanelSource: .none)
super.init(account: account, navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(self.presentationData.theme.rootController.navigationBar.backgroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none)
self.title = self.presentationData.strings.SharedMedia_TitleAll
@ -515,7 +515,7 @@ public class PeerMediaCollectionController: TelegramController {
self.validLayout = layout
self.mediaCollectionDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets in
self.mediaCollectionDisplayNode.containerLayoutUpdated(layout, navigationBarHeightAndPrimaryHeight: (self.navigationHeight, self.primaryNavigationHeight), transition: transition, listViewTransaction: { updateSizeAndInsets in
self.mediaCollectionDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets)
})
}

View File

@ -191,7 +191,11 @@ class PeerMediaCollectionControllerNode: ASDisplayNode {
self.candidateHistoryNodeReadyDisposable.dispose()
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, listViewTransaction: (ListViewUpdateSizeAndInsets) -> Void) {
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeightAndPrimaryHeight: (CGFloat, CGFloat), transition: ContainedViewLayoutTransition, listViewTransaction: (ListViewUpdateSizeAndInsets) -> Void) {
let navigationBarHeight = navigationBarHeightAndPrimaryHeight.0
let primaryNavigationBarHeight = navigationBarHeightAndPrimaryHeight.1
let navigationBarHeightDelta = (navigationBarHeight - primaryNavigationBarHeight)
self.containerLayout = (layout, navigationBarHeight)
var vanillaInsets = layout.insets(options: [])
@ -207,19 +211,19 @@ class PeerMediaCollectionControllerNode: ASDisplayNode {
if let searchDisplayController = self.searchDisplayController {
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
if !searchDisplayController.isDeactivating {
vanillaInsets.top += layout.statusBarHeight ?? 0.0
vanillaInsets.top += (layout.statusBarHeight ?? 0.0) - navigationBarHeightDelta
}
}
let sectionsHeight = self.sectionsNode.updateLayout(width: layout.size.width, additionalInset: additionalInset, transition: transition, interfaceState: self.mediaCollectionInterfaceState)
var sectionOffset: CGFloat = 0.0
if navigationBarHeight.isZero {
sectionOffset = -sectionsHeight
if primaryNavigationBarHeight.isZero {
sectionOffset = -sectionsHeight - navigationBarHeightDelta
}
transition.updateFrame(node: self.sectionsNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight + sectionOffset), size: CGSize(width: layout.size.width, height: sectionsHeight)))
var insets = vanillaInsets
if !navigationBarHeight.isZero {
if !primaryNavigationBarHeight.isZero {
insets.top += sectionsHeight
}

View File

@ -62,7 +62,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
self.segmentedControl.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
self.segmentedControl.selectedSegmentIndex = 0
self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder)
self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
super.init()
@ -107,7 +107,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
private func updateThemeAndStrings() {
self.searchDisplayController?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations)
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {

View File

@ -34,8 +34,9 @@ public final class PresentationData: Equatable {
public let dateTimeFormat: PresentationDateTimeFormat
public let nameDisplayOrder: PresentationPersonNameOrder
public let nameSortOrder: PresentationPersonNameOrder
public let disableAnimations: Bool
public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder) {
public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
self.strings = strings
self.theme = theme
self.chatWallpaper = chatWallpaper
@ -43,10 +44,11 @@ public final class PresentationData: Equatable {
self.dateTimeFormat = dateTimeFormat
self.nameDisplayOrder = nameDisplayOrder
self.nameSortOrder = nameSortOrder
self.disableAnimations = disableAnimations
}
public static func ==(lhs: PresentationData, rhs: PresentationData) -> Bool {
return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.chatWallpaper == rhs.chatWallpaper && lhs.fontSize == rhs.fontSize && lhs.dateTimeFormat == rhs.dateTimeFormat
return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.chatWallpaper == rhs.chatWallpaper && lhs.fontSize == rhs.fontSize && lhs.dateTimeFormat == rhs.dateTimeFormat && lhs.disableAnimations == rhs.disableAnimations
}
}
@ -271,7 +273,7 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal<Initi
let dateTimeFormat = currentDateTimeFormat()
let nameDisplayOrder = currentPersonNameDisplayOrder()
let nameSortOrder = currentPersonNameSortOrder()
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder), automaticMediaDownloadSettings: automaticMediaDownloadSettings, loggingSettings: loggingSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: currentReduceMotionEnabled() || themeSettings.disableAnimations), automaticMediaDownloadSettings: automaticMediaDownloadSettings, loggingSettings: loggingSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
}
}
@ -342,8 +344,8 @@ private func automaticThemeShouldSwitch(_ settings: AutomaticThemeSwitchSetting,
public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData, NoError> {
let preferencesKey = PostboxViewKey.preferences(keys: Set([ApplicationSpecificPreferencesKeys.presentationThemeSettings, PreferencesKeys.localizationSettings]))
return postbox.combinedView(keys: [preferencesKey])
|> mapToSignal { view -> Signal<PresentationData, NoError> in
return combineLatest(postbox.combinedView(keys: [preferencesKey]), reduceMotionEnabled())
|> mapToSignal { view, disableAnimations -> Signal<PresentationData, NoError> in
let themeSettings: PresentationThemeSettings
if let current = (view.views[preferencesKey] as! PreferencesView).values[ApplicationSpecificPreferencesKeys.presentationThemeSettings] as? PresentationThemeSettings {
themeSettings = current
@ -361,7 +363,7 @@ public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData
effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme)
switch themeSettings.automaticThemeSwitchSetting.theme {
case .nightAccent:
effectiveChatWallpaper = .color(0x18222D)
effectiveChatWallpaper = .color(0x18222d)
case .nightGrayscale:
effectiveChatWallpaper = .color(0x000000)
default:
@ -402,7 +404,7 @@ public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData
let nameDisplayOrder = currentPersonNameDisplayOrder()
let nameSortOrder = currentPersonNameSortOrder()
return PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder)
return PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: disableAnimations || themeSettings.disableAnimations)
}
}
}
@ -413,5 +415,5 @@ public func defaultPresentationData() -> PresentationData {
let nameSortOrder = currentPersonNameSortOrder()
let themeSettings = PresentationThemeSettings.defaultSettings
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder)
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations)
}

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,7 @@ public final class PresentationThemeRootNavigationStatusBar {
public final class PresentationThemeRootNavigationBar {
public let buttonColor: UIColor
public let disabledButtonColor: UIColor
public let primaryTextColor: UIColor
public let secondaryTextColor: UIColor
public let controlColor: UIColor
@ -77,8 +78,9 @@ public final class PresentationThemeRootNavigationBar {
public let badgeStrokeColor: UIColor
public let badgeTextColor: UIColor
public init(buttonColor: UIColor, primaryTextColor: UIColor, secondaryTextColor: UIColor, controlColor: UIColor, accentTextColor: UIColor, backgroundColor: UIColor, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor) {
public init(buttonColor: UIColor, disabledButtonColor: UIColor, primaryTextColor: UIColor, secondaryTextColor: UIColor, controlColor: UIColor, accentTextColor: UIColor, backgroundColor: UIColor, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor) {
self.buttonColor = buttonColor
self.disabledButtonColor = disabledButtonColor
self.primaryTextColor = primaryTextColor
self.secondaryTextColor = secondaryTextColor
self.controlColor = controlColor

View File

@ -145,6 +145,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
public var themeAccentColor: Int32?
public var fontSize: PresentationFontSize
public var automaticThemeSwitchSetting: AutomaticThemeSwitchSetting
public var disableAnimations: Bool
public var relatedResources: [MediaResourceId] {
switch self.chatWallpaper {
@ -156,15 +157,16 @@ public struct PresentationThemeSettings: PreferencesEntry {
}
public static var defaultSettings: PresentationThemeSettings {
return PresentationThemeSettings(chatWallpaper: .builtin, theme: .builtin(.dayClassic), themeAccentColor: nil, fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .none, theme: .nightAccent))
return PresentationThemeSettings(chatWallpaper: .builtin, theme: .builtin(.dayClassic), themeAccentColor: nil, fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .none, theme: .nightAccent), disableAnimations: false)
}
public init(chatWallpaper: TelegramWallpaper, theme: PresentationThemeReference, themeAccentColor: Int32?, fontSize: PresentationFontSize, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting) {
public init(chatWallpaper: TelegramWallpaper, theme: PresentationThemeReference, themeAccentColor: Int32?, fontSize: PresentationFontSize, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting, disableAnimations: Bool) {
self.chatWallpaper = chatWallpaper
self.theme = theme
self.themeAccentColor = themeAccentColor
self.fontSize = fontSize
self.automaticThemeSwitchSetting = automaticThemeSwitchSetting
self.disableAnimations = disableAnimations
}
public init(decoder: PostboxDecoder) {
@ -173,6 +175,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
self.themeAccentColor = decoder.decodeOptionalInt32ForKey("themeAccentColor")
self.fontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("f", orElse: PresentationFontSize.regular.rawValue)) ?? .regular
self.automaticThemeSwitchSetting = (decoder.decodeObjectForKey("automaticThemeSwitchSetting", decoder: { AutomaticThemeSwitchSetting(decoder: $0) }) as? AutomaticThemeSwitchSetting) ?? AutomaticThemeSwitchSetting(trigger: .none, theme: .nightAccent)
self.disableAnimations = decoder.decodeBoolForKey("disableAnimations", orElse: false)
}
public func encode(_ encoder: PostboxEncoder) {
@ -185,6 +188,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
}
encoder.encodeInt32(self.fontSize.rawValue, forKey: "f")
encoder.encodeObject(self.automaticThemeSwitchSetting, forKey: "automaticThemeSwitchSetting")
encoder.encodeBool(self.disableAnimations, forKey: "disableAnimations")
}
public func isEqual(to: PreferencesEntry) -> Bool {
@ -196,7 +200,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
}
public static func ==(lhs: PresentationThemeSettings, rhs: PresentationThemeSettings) -> Bool {
return lhs.chatWallpaper == rhs.chatWallpaper && lhs.theme == rhs.theme && lhs.themeAccentColor == rhs.themeAccentColor && lhs.fontSize == rhs.fontSize && lhs.automaticThemeSwitchSetting == rhs.automaticThemeSwitchSetting
return lhs.chatWallpaper == rhs.chatWallpaper && lhs.theme == rhs.theme && lhs.themeAccentColor == rhs.themeAccentColor && lhs.fontSize == rhs.fontSize && lhs.automaticThemeSwitchSetting == rhs.automaticThemeSwitchSetting && lhs.disableAnimations == rhs.disableAnimations
}
}

View File

@ -51,9 +51,9 @@ private func screenRecordingActive() -> Signal<Bool, NoError> {
}
func screenCaptureEvents() -> Signal<ScreenCaptureEvent, NoError> {
return Signal { susbcriber in
return Signal { subscriber in
let observer = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationUserDidTakeScreenshot, object: nil, queue: .main, using: { _ in
susbcriber.putNext(.still)
subscriber.putNext(.still)
})
var previous = false
@ -61,7 +61,7 @@ func screenCaptureEvents() -> Signal<ScreenCaptureEvent, NoError> {
if value != previous {
previous = value
if value {
susbcriber.putNext(.video)
subscriber.putNext(.video)
}
}
})

View File

@ -152,7 +152,7 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
private let iconNode: ASImageNode
private let textField: SearchBarTextField
private let clearButton: HighlightableButtonNode
private let cancelButton: ASButtonNode
private let cancelButton: HighlightableButtonNode
var placeholderString: NSAttributedString? {
get {
@ -262,7 +262,7 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
self.textField.keyboardAppearance = .dark
}
self.cancelButton = ASButtonNode()
self.cancelButton = HighlightableButtonNode()
self.cancelButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
self.cancelButton.setAttributedTitle(NSAttributedString(string: strings.Common_Cancel, font: Font.regular(17.0), textColor: theme.accent), for: [])
self.cancelButton.displaysAsynchronously = false

View File

@ -64,7 +64,7 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
let buttonSize = self.button.measure(CGSize(width: width - 10.0, height: 100.0))
let panelHeight: CGFloat = 45.0
let panelHeight = defaultHeight(metrics: metrics)
self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize)
@ -72,6 +72,6 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
}
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 45.0
return defaultHeight(metrics: metrics)
}
}

View File

@ -99,14 +99,12 @@ final class SecureIdAuthController: ViewController {
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
self.title = self.presentationData.strings.Passport_Title
let leftButtonTitle: String
switch mode {
case .form:
leftButtonTitle = self.presentationData.strings.Common_Cancel
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
case .list:
leftButtonTitle = self.presentationData.strings.Common_Done
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.cancelPressed))
}
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: leftButtonTitle, style: .plain, target: self, action: #selector(self.cancelPressed))
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationInfoIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.infoPressed))
self.challengeDisposable.set((twoStepAuthData(account.network)

View File

@ -2873,17 +2873,23 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
if let frontSideDocument = innerState.frontSideDocument {
entries.append(SecureIdDocumentGalleryEntry(index: Int32(index), resource: frontSideDocument.resource, location: SecureIdDocumentGalleryEntryLocation(position: Int32(index), totalCount: totalCount), error: ""))
centralIndex = index
if document.id == frontSideDocument.id {
centralIndex = index
}
index += 1
}
if let backSideDocument = innerState.backSideDocument {
entries.append(SecureIdDocumentGalleryEntry(index: Int32(index), resource: backSideDocument.resource, location: SecureIdDocumentGalleryEntryLocation(position: Int32(index), totalCount: totalCount), error: ""))
centralIndex = index
if document.id == backSideDocument.id {
centralIndex = index
}
index += 1
}
if let selfieDocument = innerState.selfieDocument {
entries.append(SecureIdDocumentGalleryEntry(index: Int32(index), resource: selfieDocument.resource, location: SecureIdDocumentGalleryEntryLocation(position: Int32(index), totalCount: totalCount), error: ""))
centralIndex = index
if document.id == selfieDocument.id {
centralIndex = index
}
index += 1
}
if let _ = innerState.documents.index(where: { $0.id == document.id }) {

View File

@ -259,11 +259,8 @@ public final class ShareController: ViewController {
for entry in view.0.entries.reversed() {
switch entry {
case let .MessageEntry(_, _, _, _, _, renderedPeer, _):
if let peer = renderedPeer.chatMainPeer, peer.id != accountPeer.id {
if let user = peer as? TelegramUser, (user.firstName ?? "").isEmpty, (user.lastName ?? "").isEmpty {
} else if canSendMessagesToPeer(peer) {
peers.append(peer)
}
if let peer = renderedPeer.chatMainPeer, peer.id != accountPeer.id, canSendMessagesToPeer(peer) {
peers.append(peer)
}
default:
break

View File

@ -4,6 +4,12 @@ import TelegramCore
import SwiftSignalKit
import Postbox
enum MediaAccessoryPanelVisibility {
case none
case specific(size: ContainerViewLayoutSizeClass)
case always
}
enum LocationBroadcastPanelSource {
case none
case summary
@ -36,7 +42,7 @@ private func presentLiveLocationController(account: Account, peerId: PeerId, con
public class TelegramController: ViewController {
private let account: Account
let enableMediaAccessoryPanel: Bool
let mediaAccessoryPanelVisibility: MediaAccessoryPanelVisibility
let locationBroadcastPanelSource: LocationBroadcastPanelSource
private var mediaStatusDisposable: Disposable?
@ -70,18 +76,22 @@ public class TelegramController: ViewController {
return height
}
init(account: Account, navigationBarPresentationData: NavigationBarPresentationData?, enableMediaAccessoryPanel: Bool, locationBroadcastPanelSource: LocationBroadcastPanelSource) {
public var primaryNavigationHeight: CGFloat {
return super.navigationHeight
}
init(account: Account, navigationBarPresentationData: NavigationBarPresentationData?, mediaAccessoryPanelVisibility: MediaAccessoryPanelVisibility, locationBroadcastPanelSource: LocationBroadcastPanelSource) {
self.account = account
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
self.enableMediaAccessoryPanel = enableMediaAccessoryPanel
self.mediaAccessoryPanelVisibility = mediaAccessoryPanelVisibility
self.locationBroadcastPanelSource = locationBroadcastPanelSource
super.init(navigationBarPresentationData: navigationBarPresentationData)
if enableMediaAccessoryPanel {
if case .none = mediaAccessoryPanelVisibility {} else {
self.mediaStatusDisposable = (account.telegramApplicationContext.mediaManager.globalMediaPlayerState
|> deliverOnMainQueue).start(next: { [weak self] playlistStateAndType in
if let strongSelf = self, strongSelf.enableMediaAccessoryPanel {
if let strongSelf = self {
if !arePlaylistItemsEqual(strongSelf.playlistStateAndType?.0, playlistStateAndType?.0.item) ||
strongSelf.playlistStateAndType?.1 != playlistStateAndType?.0.order || strongSelf.playlistStateAndType?.2 != playlistStateAndType?.1 {
var previousVoiceItem: SharedMediaPlaylistItem?
@ -352,7 +362,17 @@ public class TelegramController: ViewController {
}
}
if let (item, _, type) = self.playlistStateAndType {
let mediaAccessoryPanelHidden: Bool
switch self.mediaAccessoryPanelVisibility {
case .always:
mediaAccessoryPanelHidden = false
case .none:
mediaAccessoryPanelHidden = true
case let .specific(size):
mediaAccessoryPanelHidden = size != layout.metrics.widthClass
}
if let (item, _, type) = self.playlistStateAndType, !mediaAccessoryPanelHidden {
let panelHeight = MediaNavigationAccessoryHeaderNode.minimizedHeight
let panelFrame = CGRect(origin: CGPoint(x: 0.0, y: navigationHeight.isZero ? -panelHeight : (navigationHeight + additionalHeight + UIScreenPixel)), size: CGSize(width: layout.size.width, height: panelHeight))
if let (mediaAccessoryPanel, mediaType) = self.mediaAccessoryPanel, mediaType == type {

View File

@ -14,8 +14,9 @@ public class TermsOfServiceControllerTheme {
public let itemSeparator: UIColor
public let primary: UIColor
public let accent: UIColor
public let disabled: UIColor
public init(statusBarStyle: StatusBarStyle, navigationBackground: UIColor, navigationSeparator: UIColor, listBackground: UIColor, itemBackground: UIColor, itemSeparator: UIColor, primary: UIColor, accent: UIColor) {
public init(statusBarStyle: StatusBarStyle, navigationBackground: UIColor, navigationSeparator: UIColor, listBackground: UIColor, itemBackground: UIColor, itemSeparator: UIColor, primary: UIColor, accent: UIColor, disabled: UIColor) {
self.statusBarStyle = statusBarStyle
self.navigationBackground = navigationBackground
self.navigationSeparator = navigationSeparator
@ -24,16 +25,17 @@ public class TermsOfServiceControllerTheme {
self.itemSeparator = itemSeparator
self.primary = primary
self.accent = accent
self.disabled = disabled
}
}
public extension TermsOfServiceControllerTheme {
convenience init(presentationTheme: PresentationTheme) {
self.init(statusBarStyle: presentationTheme.rootController.statusBar.style.style, navigationBackground: presentationTheme.rootController.navigationBar.backgroundColor, navigationSeparator: presentationTheme.rootController.navigationBar.separatorColor, listBackground: presentationTheme.list.blocksBackgroundColor, itemBackground: presentationTheme.list.itemBlocksBackgroundColor, itemSeparator: presentationTheme.list.itemBlocksSeparatorColor, primary: presentationTheme.list.itemPrimaryTextColor, accent: presentationTheme.list.itemAccentColor)
self.init(statusBarStyle: presentationTheme.rootController.statusBar.style.style, navigationBackground: presentationTheme.rootController.navigationBar.backgroundColor, navigationSeparator: presentationTheme.rootController.navigationBar.separatorColor, listBackground: presentationTheme.list.blocksBackgroundColor, itemBackground: presentationTheme.list.itemBlocksBackgroundColor, itemSeparator: presentationTheme.list.itemBlocksSeparatorColor, primary: presentationTheme.list.itemPrimaryTextColor, accent: presentationTheme.list.itemAccentColor, disabled: presentationTheme.rootController.navigationBar.disabledButtonColor)
}
convenience init(authTheme: AuthorizationTheme) {
self.init(statusBarStyle: authTheme.statusBarStyle, navigationBackground: authTheme.navigationBarBackgroundColor, navigationSeparator: authTheme.navigationBarSeparatorColor, listBackground: authTheme.listBackgroundColor, itemBackground: authTheme.backgroundColor, itemSeparator: authTheme.separatorColor, primary: authTheme.primaryColor, accent: authTheme.accentColor)
self.init(statusBarStyle: authTheme.statusBarStyle, navigationBackground: authTheme.navigationBarBackgroundColor, navigationSeparator: authTheme.navigationBarSeparatorColor, listBackground: authTheme.listBackgroundColor, itemBackground: authTheme.backgroundColor, itemSeparator: authTheme.separatorColor, primary: authTheme.primaryColor, accent: authTheme.accentColor, disabled: authTheme.accentColor)
}
var presentationTheme: PresentationTheme {
@ -93,7 +95,7 @@ public class TermsOfServiceController: ViewController {
self.decline = decline
self.openUrl = openUrl
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(buttonColor: self.theme.accent, primaryTextColor: self.theme.primary, backgroundColor: self.theme.navigationBackground, separatorColor: self.theme.navigationSeparator, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear), strings: NavigationBarStrings(back: strings.Common_Back, close: strings.Common_Close)))
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(buttonColor: self.theme.accent, disabledButtonColor: self.theme.disabled, primaryTextColor: self.theme.primary, backgroundColor: self.theme.navigationBackground, separatorColor: self.theme.navigationSeparator, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear), strings: NavigationBarStrings(back: strings.Common_Back, close: strings.Common_Close)))
self.statusBar.statusBarStyle = self.theme.statusBarStyle

View File

@ -250,10 +250,10 @@ class ThemeGalleryController: ViewController {
}
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
if case .color(0x000000) = wallpaper {
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: .regular, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting)
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: .regular, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting)
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}) |> deliverOnMainQueue).start(completed: {
self?.dismiss(forceAway: true)
})

View File

@ -99,10 +99,10 @@ final class ThemeGridController: ViewController {
let wallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: image.size, resource: resource)])
let _ = (updatePresentationThemeSettingsInteractively(postbox: self.account.postbox, { current in
if case .color(0x000000) = wallpaper {
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting)
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting)
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}) |> deliverOnMainQueue).start(completed: { [weak self] in
let _ = (self?.navigationController as? NavigationController)?.popViewController(animated: true)
})

View File

@ -149,7 +149,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: item.strings.Appearance_PreviewReplyText, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: item.componentTheme, wallpaper: item.wallpaper), fontSize: item.fontSize, strings: item.strings, dateTimeFormat: item.dateTimeFormat)
let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: item.componentTheme, wallpaper: item.wallpaper), fontSize: item.fontSize, strings: item.strings, dateTimeFormat: item.dateTimeFormat, disableAnimations: false)
let item2: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, account: item.account, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true)
let item1: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, account: item.account, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: TelegramUser(id: item.account.peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), text: item.strings.Appearance_PreviewOutgoingText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true)

View File

@ -11,14 +11,16 @@ private final class ThemeSettingsControllerArguments {
let openWallpaperSettings: () -> Void
let openAccentColor: (Int32) -> Void
let openAutoNightTheme: () -> Void
let disableAnimations: (Bool) -> Void
init(account: Account, selectTheme: @escaping (Int32) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, openAccentColor: @escaping (Int32) -> Void, openAutoNightTheme: @escaping () -> Void) {
init(account: Account, selectTheme: @escaping (Int32) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, openAccentColor: @escaping (Int32) -> Void, openAutoNightTheme: @escaping () -> Void, disableAnimations: @escaping (Bool) -> Void) {
self.account = account
self.selectTheme = selectTheme
self.selectFontSize = selectFontSize
self.openWallpaperSettings = openWallpaperSettings
self.openAccentColor = openAccentColor
self.openAutoNightTheme = openAutoNightTheme
self.disableAnimations = disableAnimations
}
}
@ -36,12 +38,14 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
case wallpaper(PresentationTheme, String)
case accentColor(PresentationTheme, String, Int32)
case autoNightTheme(PresentationTheme, String, String)
case animationsItem(PresentationTheme, String, Bool)
case animationsInfo(PresentationTheme, String)
case themeListHeader(PresentationTheme, String)
case themeItem(PresentationTheme, String, Bool, Int32)
var section: ItemListSectionId {
switch self {
case .chatPreviewHeader, .chatPreview, .wallpaper, .accentColor, .autoNightTheme:
case .chatPreviewHeader, .chatPreview, .wallpaper, .accentColor, .autoNightTheme, .animationsItem, .animationsInfo:
return ThemeSettingsControllerSection.chatPreview.rawValue
case .themeListHeader, .themeItem:
return ThemeSettingsControllerSection.themeList.rawValue
@ -66,10 +70,14 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
return 5
case .autoNightTheme:
return 6
case .themeListHeader:
case .animationsItem:
return 7
case .animationsInfo:
return 8
case .themeListHeader:
return 9
case let .themeItem(_, _, _, index):
return 8 + index
return 10 + index
}
}
@ -93,18 +101,30 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
} else {
return false
}
case let .accentColor(lhsTheme, lhsText, lhsColor):
if case let .accentColor(rhsTheme, rhsText, rhsColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsColor == rhsColor {
return true
} else {
return false
}
case let .autoNightTheme(lhsTheme, lhsText, lhsValue):
if case let .autoNightTheme(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .accentColor(lhsTheme, lhsText, lhsColor):
if case let .accentColor(rhsTheme, rhsText, rhsColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsColor == rhsColor {
return true
} else {
return false
}
case let .autoNightTheme(lhsTheme, lhsText, lhsValue):
if case let .autoNightTheme(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .animationsItem(lhsTheme, lhsTitle, lhsValue):
if case let .animationsItem(rhsTheme, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue {
return true
} else {
return false
}
case let .animationsInfo(lhsTheme, lhsText):
if case let .animationsInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .themeListHeader(lhsTheme, lhsText):
if case let .themeListHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
@ -160,6 +180,12 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
return ItemListDisclosureItem(theme: theme, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
arguments.openAutoNightTheme()
})
case let .animationsItem(theme, title, value):
return ItemListSwitchItem(theme: theme, title: title, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.disableAnimations(value)
})
case let .animationsInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .themeListHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .themeItem(theme, title, value, index):
@ -170,7 +196,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
}
}
private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeAccentColor: Int32?, autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat) -> [ThemeSettingsControllerEntry] {
private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeAccentColor: Int32?, autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) -> [ThemeSettingsControllerEntry] {
var entries: [ThemeSettingsControllerEntry] = []
entries.append(.fontSizeHeader(presentationData.theme, strings.Appearance_TextSize))
@ -193,6 +219,11 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
}
entries.append(.autoNightTheme(presentationData.theme, strings.Appearance_AutoNightTheme, title))
}
if !UIAccessibility.isReduceMotionEnabled {
entries.append(.animationsItem(presentationData.theme, strings.Appearance_ReduceMotion, disableAnimations))
entries.append(.animationsInfo(presentationData.theme, strings.Appearance_ReduceMotionInfo))
}
entries.append(.themeListHeader(presentationData.theme, strings.Appearance_ColorTheme))
entries.append(.themeItem(presentationData.theme, strings.Appearance_ThemeDayClassic, theme.name == .builtin(.dayClassic), 0))
entries.append(.themeItem(presentationData.theme, strings.Appearance_ThemeDay, theme.name == .builtin(.day), 1))
@ -223,11 +254,11 @@ public func themeSettingsController(account: Account) -> ViewController {
wallpaper = .color(0x18222D)
theme = .builtin(.nightAccent)
}
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting)
return PresentationThemeSettings(chatWallpaper: wallpaper, theme: theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}).start()
}, selectFontSize: { size in
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: size, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting)
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: size, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}).start()
}, openWallpaperSettings: {
pushControllerImpl?(ThemeGridController(account: account))
@ -235,11 +266,15 @@ public func themeSettingsController(account: Account) -> ViewController {
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
presentControllerImpl?(ThemeAccentColorActionSheet(theme: presentationData.theme, strings: presentationData.strings, currentValue: color, applyValue: { color in
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeAccentColor: color, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting)
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeAccentColor: color, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}).start()
}))
}, openAutoNightTheme: {
pushControllerImpl?(themeAutoNightSettingsController(account: account))
}, disableAnimations: { disabled in
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: disabled)
}).start()
})
let themeSettingsKey = ApplicationSpecificPreferencesKeys.presentationThemeSettings
@ -256,6 +291,7 @@ public func themeSettingsController(account: Account) -> ViewController {
let wallpaper: TelegramWallpaper
let strings: PresentationStrings
let dateTimeFormat: PresentationDateTimeFormat
let disableAnimations: Bool
let settings = (preferences.values[themeSettingsKey] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
switch settings.theme {
@ -281,9 +317,10 @@ public func themeSettingsController(account: Account) -> ViewController {
}
dateTimeFormat = presentationData.dateTimeFormat
disableAnimations = settings.disableAnimations
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: strings.Common_Back))
let listState = ItemListNodeState(entries: themeSettingsControllerEntries(presentationData: presentationData, theme: theme, themeAccentColor: settings.themeAccentColor, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat), style: .blocks, animateChanges: false)
let listState = ItemListNodeState(entries: themeSettingsControllerEntries(presentationData: presentationData, theme: theme, themeAccentColor: settings.themeAccentColor, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat, disableAnimations: disableAnimations), style: .blocks, animateChanges: false)
if previousTheme.swap(theme)?.name != theme.name {
presentControllerImpl?(ThemeSettingsCrossfadeController())

View File

@ -33,7 +33,6 @@ final class WebEmbedVideoContent: UniversalVideoContent {
private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
private let webpageContent: TelegramMediaWebpageLoadedContent
private let intrinsicDimensions: CGSize
private let approximateDuration: Int32
private let playbackCompletedListeners = Bag<() -> Void>()
@ -55,11 +54,6 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
return self._ready.get()
}
private let _preloadCompleted = ValuePromise<Bool>()
var preloadCompleted: Signal<Bool, NoError> {
return self._preloadCompleted.get()
}
private let imageNode: TransformImageNode
private let playerNode: WebEmbedPlayerNode
@ -67,7 +61,6 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent) {
self.webpageContent = webpageContent
self.approximateDuration = Int32(webpageContent.duration ?? 0)
if let embedSize = webpageContent.embedSize {
self.intrinsicDimensions = embedSize
@ -86,8 +79,6 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
self.addSubnode(self.playerNode)
self.addSubnode(self.imageNode)
self._preloadCompleted.set(true)
if let image = webpageContent.image {
self.imageNode.setSignal(chatMessagePhoto(postbox: postbox, photoReference: .webPage(webPage: WebpageReference(webPage), media: image)))
self.imageNode.imageUpdated = { [weak self] in
@ -116,9 +107,11 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(), size: size))
let makeImageLayout = self.imageNode.asyncLayout()
let applyImageLayout = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets()))
applyImageLayout()
if let image = webpageContent.image, let representation = image.representationForDisplayAtSize(self.intrinsicDimensions) {
let makeImageLayout = self.imageNode.asyncLayout()
let applyImageLayout = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: representation.dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
applyImageLayout()
}
}
func play() {