mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
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:
parent
606e607de4
commit
ab5881de15
@ -37,6 +37,7 @@
|
|||||||
09874E582107A4C300E190B8 /* VimeoEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09874E3A21075BF400E190B8 /* VimeoEmbedImplementation.swift */; };
|
09874E582107A4C300E190B8 /* VimeoEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09874E3A21075BF400E190B8 /* VimeoEmbedImplementation.swift */; };
|
||||||
09874E592107BD4100E190B8 /* GenericEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09874E4021075C1700E190B8 /* GenericEmbedImplementation.swift */; };
|
09874E592107BD4100E190B8 /* GenericEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09874E4021075C1700E190B8 /* GenericEmbedImplementation.swift */; };
|
||||||
09AE3823214C110900850BFD /* LegacySecureIdScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AE3822214C110800850BFD /* LegacySecureIdScanController.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 */; };
|
09C500242142BA6400EF253E /* ItemListWebsiteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */; };
|
||||||
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
|
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
|
||||||
D007019C2029E8F2006B9E34 /* LegqacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
D00219051DDD1C9E00BE708A /* ImageContainingNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageContainingNode.swift; sourceTree = "<group>"; };
|
||||||
@ -4312,6 +4314,7 @@
|
|||||||
D044A0F220BDA05800326FAC /* ThrottledValue.swift */,
|
D044A0F220BDA05800326FAC /* ThrottledValue.swift */,
|
||||||
D0EC55A2210231D600D1992C /* SearchPeerMembers.swift */,
|
D0EC55A2210231D600D1992C /* SearchPeerMembers.swift */,
|
||||||
D0192D45210F4F940005FA10 /* FixSearchableListNodeScrolling.swift */,
|
D0192D45210F4F940005FA10 /* FixSearchableListNodeScrolling.swift */,
|
||||||
|
09C3466C2167D63A00B76780 /* Accessibility.swift */,
|
||||||
);
|
);
|
||||||
name = Utils;
|
name = Utils;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -4917,6 +4920,7 @@
|
|||||||
D0EC6D2D1EB9F58800EBF1C3 /* TapLongTapOrDoubleTapGestureRecognizer.swift in Sources */,
|
D0EC6D2D1EB9F58800EBF1C3 /* TapLongTapOrDoubleTapGestureRecognizer.swift in Sources */,
|
||||||
D0AF7C461ED84BC500CD8E0F /* LanguageSelectionController.swift in Sources */,
|
D0AF7C461ED84BC500CD8E0F /* LanguageSelectionController.swift in Sources */,
|
||||||
D0B69C3C20EBD8C8003632C7 /* CheckDeviceAccess.swift in Sources */,
|
D0B69C3C20EBD8C8003632C7 /* CheckDeviceAccess.swift in Sources */,
|
||||||
|
09C3466D2167D63A00B76780 /* Accessibility.swift in Sources */,
|
||||||
D0FA08C020483F9600DD23FC /* ExtractVideoData.swift in Sources */,
|
D0FA08C020483F9600DD23FC /* ExtractVideoData.swift in Sources */,
|
||||||
D0BE30492061C0F500FBE6D8 /* SecureIdAuthHeaderNode.swift in Sources */,
|
D0BE30492061C0F500FBE6D8 /* SecureIdAuthHeaderNode.swift in Sources */,
|
||||||
D0EC6D2E1EB9F58800EBF1C3 /* ImageNode.swift in Sources */,
|
D0EC6D2E1EB9F58800EBF1C3 /* ImageNode.swift in Sources */,
|
||||||
|
|||||||
49
TelegramUI/Accessibility.swift
Normal file
49
TelegramUI/Accessibility.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ import CoreTelephony
|
|||||||
|
|
||||||
public final class AuthorizationSequenceController: NavigationController {
|
public final class AuthorizationSequenceController: NavigationController {
|
||||||
static func navigationBarTheme(_ theme: AuthorizationTheme) -> NavigationBarTheme {
|
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
|
private var account: UnauthorizedAccount
|
||||||
|
|||||||
@ -186,7 +186,7 @@ final class AuthorizationSequenceCountrySelectionController: ViewController {
|
|||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.displayCodes = displayCodes
|
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
|
self.statusBar.statusBarStyle = theme.statusBar.style
|
||||||
|
|
||||||
|
|||||||
@ -470,7 +470,7 @@ func autodownloadMediaCategoryController(account: Account, category: AutomaticDo
|
|||||||
case .cellular:
|
case .cellular:
|
||||||
settings.peers.channels.voiceMessage.cellular = !settings.peers.channels.voiceMessage.cellular
|
settings.peers.channels.voiceMessage.cellular = !settings.peers.channels.voiceMessage.cellular
|
||||||
case .wifi:
|
case .wifi:
|
||||||
settings.peers.channels.voiceMessage.wifi = !settings.peers.channels.file.wifi
|
settings.peers.channels.voiceMessage.wifi = !settings.peers.channels.voiceMessage.wifi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .videoMessage:
|
case .videoMessage:
|
||||||
@ -501,7 +501,7 @@ func autodownloadMediaCategoryController(account: Account, category: AutomaticDo
|
|||||||
case .cellular:
|
case .cellular:
|
||||||
settings.peers.channels.videoMessage.cellular = !settings.peers.channels.videoMessage.cellular
|
settings.peers.channels.videoMessage.cellular = !settings.peers.channels.videoMessage.cellular
|
||||||
case .wifi:
|
case .wifi:
|
||||||
settings.peers.channels.videoMessage.wifi = !settings.peers.channels.file.wifi
|
settings.peers.channels.videoMessage.wifi = !settings.peers.channels.videoMessage.wifi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,8 @@ final class CallControllerNode: ASDisplayNode {
|
|||||||
private let buttonsNode: CallControllerButtonsNode
|
private let buttonsNode: CallControllerButtonsNode
|
||||||
private var keyPreviewNode: CallControllerKeyPreviewNode?
|
private var keyPreviewNode: CallControllerKeyPreviewNode?
|
||||||
|
|
||||||
|
private var debugNode: CallDebugNode?
|
||||||
|
|
||||||
private var keyTextData: (Data, String)?
|
private var keyTextData: (Data, String)?
|
||||||
private let keyButtonNode: HighlightableButtonNode
|
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 disposable = MetaDisposable()
|
||||||
|
|
||||||
|
private let dimNode: ASDisplayNode
|
||||||
|
private let textNode: ASTextNode
|
||||||
|
|
||||||
override init() {
|
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 {
|
deinit {
|
||||||
disposable.dispose()
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -121,7 +121,7 @@ public final class CallListController: ViewController {
|
|||||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
if self.isNodeLoaded {
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,19 +69,20 @@ struct CallListNodeState: Equatable {
|
|||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
let dateTimeFormat: PresentationDateTimeFormat
|
let dateTimeFormat: PresentationDateTimeFormat
|
||||||
|
let disableAnimations: Bool
|
||||||
let editing: Bool
|
let editing: Bool
|
||||||
let messageIdWithRevealedOptions: MessageId?
|
let messageIdWithRevealedOptions: MessageId?
|
||||||
|
|
||||||
func withUpdatedPresentationData(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> CallListNodeState {
|
func withUpdatedPresentationData(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) -> CallListNodeState {
|
||||||
return CallListNodeState(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, editing: self.editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
|
return CallListNodeState(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, disableAnimations: disableAnimations, editing: self.editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedEditing(_ editing: Bool) -> CallListNodeState {
|
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 {
|
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 {
|
static func ==(lhs: CallListNodeState, rhs: CallListNodeState) -> Bool {
|
||||||
@ -198,7 +199,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||||||
self.openInfo = openInfo
|
self.openInfo = openInfo
|
||||||
self.emptyStateUpdated = emptyStateUpdated
|
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.statePromise = ValuePromise(self.currentState, ignoreRepeated: true)
|
||||||
|
|
||||||
self.listNode = ListView()
|
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) })
|
|> map({ mappedCallListNodeViewListTransition(account: account, showSettings: showSettings, nodeInteraction: nodeInteraction, transition: $0) })
|
||||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||||
}
|
}
|
||||||
@ -371,8 +372,8 @@ final class CallListControllerNode: ASDisplayNode {
|
|||||||
self.emptyStateDisposable.dispose()
|
self.emptyStateDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) {
|
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) {
|
||||||
if theme !== self.currentState.theme || strings !== self.currentState.strings {
|
if theme !== self.currentState.theme || strings !== self.currentState.strings || disableAnimations != self.currentState.disableAnimations {
|
||||||
switch self.mode {
|
switch self.mode {
|
||||||
case .tab:
|
case .tab:
|
||||||
self.backgroundColor = theme.chatList.backgroundColor
|
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.updateEmptyPlaceholder(theme: theme, strings: strings, type: self.currentLocationAndType.type, hidden: self.emptyTextNode.isHidden)
|
||||||
|
|
||||||
self.updateState {
|
self.updateState {
|
||||||
return $0.withUpdatedPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat)
|
return $0.withUpdatedPresentationData(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, disableAnimations: disableAnimations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ enum CallListNodeViewScrollPosition {
|
|||||||
case index(index: MessageIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
|
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
|
return Signal { subscriber in
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
|
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)
|
let _ = options.insert(.Synchronous)
|
||||||
case .interactiveChanges:
|
case .interactiveChanges:
|
||||||
let _ = options.insert(.AnimateAlpha)
|
let _ = options.insert(.AnimateAlpha)
|
||||||
let _ = options.insert(.AnimateInsertion)
|
if !disableAnimations {
|
||||||
|
let _ = options.insert(.AnimateInsertion)
|
||||||
|
}
|
||||||
|
|
||||||
for (index, _, _) in indicesAndItems.sorted(by: { $0.0 > $1.0 }) {
|
for (index, _, _) in indicesAndItems.sorted(by: { $0.0 > $1.0 }) {
|
||||||
let adjustedIndex = updatedCount - 1 - index
|
let adjustedIndex = updatedCount - 1 - index
|
||||||
|
|||||||
@ -98,7 +98,11 @@ final class ChangePhoneNumberController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func nextPressed() {
|
@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 {
|
if !number.isEmpty {
|
||||||
self.inProgress = true
|
self.inProgress = true
|
||||||
self.requestDisposable.set((requestChangeAccountPhoneNumberVerification(account: self.account, phoneNumber: self.controllerNode.currentNumber) |> deliverOnMainQueue).start(next: { [weak self] next in
|
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:
|
case .invalidPhoneNumber:
|
||||||
text = presentationData.strings.Login_InvalidPhoneError
|
text = presentationData.strings.Login_InvalidPhoneError
|
||||||
case .phoneNumberOccupied:
|
case .phoneNumberOccupied:
|
||||||
text = presentationData.strings.ChangePhone_ErrorOccupied(number).0
|
text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(phoneNumber)).0
|
||||||
case .generic:
|
case .generic:
|
||||||
text = presentationData.strings.Login_UnknownError
|
text = presentationData.strings.Login_UnknownError
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
|
import CoreTelephony
|
||||||
|
|
||||||
private func generateCountryButtonBackground(color: UIColor, strokeColor: UIColor) -> UIImage? {
|
private func generateCountryButtonBackground(color: UIColor, strokeColor: UIColor) -> UIImage? {
|
||||||
return generateImage(CGSize(width: 45.0, height: 44.0 + 6.0), rotatedContext: { size, context in
|
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
|
self.phoneInputNode.countryCodeUpdated = { [weak self] code in
|
||||||
if let strongSelf = self {
|
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: [])
|
strongSelf.countryButton.setTitle(countryName, with: Font.regular(17.0), with: strongSelf.presentationData.theme.list.itemPrimaryTextColor, for: [])
|
||||||
} else {
|
} else {
|
||||||
strongSelf.countryButton.setTitle(strongSelf.presentationData.strings.Login_CountryCode, with: Font.regular(17.0), with: strongSelf.presentationData.theme.list.itemPrimaryTextColor, for: [])
|
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) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
|||||||
@ -564,7 +564,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
|||||||
text = presentationData.strings.Channel_NotificationLoading
|
text = presentationData.strings.Channel_NotificationLoading
|
||||||
}
|
}
|
||||||
entries.append(.privateLink(presentationData.theme, text, link))
|
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 {
|
switch mode {
|
||||||
case .initialSetup:
|
case .initialSetup:
|
||||||
break
|
break
|
||||||
@ -867,9 +867,6 @@ public func channelVisibilityController(account: Account, peerId: PeerId, mode:
|
|||||||
invokeAction()
|
invokeAction()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch mode {
|
switch mode {
|
||||||
case .initialSetup:
|
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)
|
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))
|
return (controllerState, (listState, arguments))
|
||||||
|
|||||||
@ -13,14 +13,12 @@ private let messageFixedFont: UIFont = UIFont(name: "Menlo-Regular", size: 16.0)
|
|||||||
final class ChatBotInfoItem: ListViewItem {
|
final class ChatBotInfoItem: ListViewItem {
|
||||||
fileprivate let text: String
|
fileprivate let text: String
|
||||||
fileprivate let controllerInteraction: ChatControllerInteraction
|
fileprivate let controllerInteraction: ChatControllerInteraction
|
||||||
fileprivate let theme: ChatPresentationThemeData
|
fileprivate let presentationData: ChatPresentationData
|
||||||
fileprivate let strings: PresentationStrings
|
|
||||||
|
|
||||||
init(text: String, controllerInteraction: ChatControllerInteraction, theme: ChatPresentationThemeData, strings: PresentationStrings) {
|
init(text: String, controllerInteraction: ChatControllerInteraction, presentationData: ChatPresentationData) {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
self.theme = theme
|
self.presentationData = presentationData
|
||||||
self.strings = strings
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
|
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 theme: ChatPresentationThemeData?
|
||||||
|
|
||||||
|
private var item: ChatBotInfoItem?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.offsetContainer = ASDisplayNode()
|
self.offsetContainer = ASDisplayNode()
|
||||||
|
|
||||||
@ -106,10 +106,12 @@ final class ChatBotInfoItemNode: ListViewItemNode {
|
|||||||
let currentTextAndEntities = self.currentTextAndEntities
|
let currentTextAndEntities = self.currentTextAndEntities
|
||||||
let currentTheme = self.theme
|
let currentTheme = self.theme
|
||||||
return { [weak self] item, params in
|
return { [weak self] item, params in
|
||||||
|
self?.item = item
|
||||||
|
|
||||||
var updatedBackgroundImage: UIImage?
|
var updatedBackgroundImage: UIImage?
|
||||||
if currentTheme != item.theme {
|
if currentTheme != item.presentationData.theme {
|
||||||
let principalGraphics = PresentationResourcesChat.principalGraphics(item.theme.theme, wallpaper: !item.theme.wallpaper.isEmpty)
|
//let principalGraphics = PresentationResourcesChat.principalGraphics(item.presentationData.theme.theme, wallpaper: !item.presentationData.theme.wallpaper.isEmpty)
|
||||||
updatedBackgroundImage = PresentationResourcesChat.chatInfoItemBackgroundImage(item.theme.theme, wallpaper: !item.theme.wallpaper.isEmpty)
|
updatedBackgroundImage = PresentationResourcesChat.chatInfoItemBackgroundImage(item.presentationData.theme.theme, wallpaper: !item.presentationData.theme.wallpaper.isEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
var updatedTextAndEntities: (String, [MessageTextEntity])
|
var updatedTextAndEntities: (String, [MessageTextEntity])
|
||||||
@ -123,7 +125,7 @@ final class ChatBotInfoItemNode: ListViewItemNode {
|
|||||||
updatedTextAndEntities = (item.text, generateTextEntities(item.text, enabledTypes: .all))
|
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 horizontalEdgeInset: CGFloat = 10.0 + params.leftInset
|
||||||
let horizontalContentInset: CGFloat = 12.0
|
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())
|
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
|
return (itemLayout, { _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.theme = item.theme
|
strongSelf.theme = item.presentationData.theme
|
||||||
|
|
||||||
if let updatedBackgroundImage = updatedBackgroundImage {
|
if let updatedBackgroundImage = updatedBackgroundImage {
|
||||||
strongSelf.backgroundNode.image = updatedBackgroundImage
|
strongSelf.backgroundNode.image = updatedBackgroundImage
|
||||||
@ -238,4 +240,11 @@ final class ChatBotInfoItemNode: ListViewItemNode {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override public var wantsScrollDynamics: Bool {
|
||||||
|
if let disableAnimations = self.item?.presentationData.disableAnimations {
|
||||||
|
return !disableAnimations
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,7 +94,7 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode {
|
|||||||
|
|
||||||
let buttonSize = self.button.measure(CGSize(width: width - 80.0, height: 100.0))
|
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)
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -129,7 +129,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let panelHeight: CGFloat = 45.0
|
let panelHeight = defaultHeight(metrics: metrics)
|
||||||
|
|
||||||
let buttonSize = self.button.bounds.size
|
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)
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
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 {
|
if case .standard = mode {
|
||||||
enableMediaAccessoryPanel = true
|
mediaAccessoryPanelVisibility = .specific(size: .compact)
|
||||||
} else {
|
} else {
|
||||||
locationBroadcastPanelSource = .none
|
locationBroadcastPanelSource = .none
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin
|
|||||||
default:
|
default:
|
||||||
navigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData)
|
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)
|
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.validLayout = layout
|
||||||
|
|
||||||
|
self.chatTitleView?.layoutMetrics = layout.metrics
|
||||||
|
|
||||||
self.chatDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop in
|
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)
|
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]?) {
|
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
|
self.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(account: self.account, signals: signals!) |> deliverOnMainQueue).start(next: { [weak self] messages in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
|
|||||||
@ -298,7 +298,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .peer(peerId) = strongSelf.chatLocation {
|
if case .peer = strongSelf.chatLocation {
|
||||||
strongSelf.sendMessages(messages)
|
strongSelf.sendMessages(messages)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,11 +309,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.textInputPanelNode?.pasteImages = { [weak self] images in
|
self.textInputPanelNode?.pasteImages = { [weak self] images in
|
||||||
self?.displayPasteMenu(images)
|
self?.displayPasteMenu(images)
|
||||||
}
|
}
|
||||||
|
self.textInputPanelNode?.pasteData = { [weak self] data in
|
||||||
|
//self?.sendGifData(data)
|
||||||
|
}
|
||||||
self.textInputPanelNode?.displayAttachmentMenu = { [weak self] in
|
self.textInputPanelNode?.displayAttachmentMenu = { [weak self] in
|
||||||
self?.displayAttachmentMenu()
|
self?.displayAttachmentMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.textInputPanelNode?.updateActivity = { [weak self] in
|
self.textInputPanelNode?.updateActivity = { [weak self] in
|
||||||
self?.updateTypingActivity(true)
|
self?.updateTypingActivity(true)
|
||||||
}
|
}
|
||||||
@ -639,7 +640,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if case .standard(true) = self.chatPresentationInterfaceState.mode {
|
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 {
|
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)))
|
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?
|
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))
|
titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: panelHeight))
|
||||||
insets.top += panelHeight
|
insets.top += panelHeight
|
||||||
}
|
}
|
||||||
@ -855,8 +857,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
listInsets.left += 6.0
|
listInsets.left += 6.0
|
||||||
listInsets.right += 6.0
|
listInsets.right += 6.0
|
||||||
listInsets.top += 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 menuHeight = menuHeight {
|
||||||
if let _ = self.controllerInteraction.contextHighlightedState?.messageStableId, let (menuController, node, frame) = displayContextMenuController {
|
if let _ = self.controllerInteraction.contextHighlightedState?.messageStableId, let (menuController, node, frame) = displayContextMenuController {
|
||||||
|
|
||||||
self.controllerInteraction.presentController(menuController, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
|
self.controllerInteraction.presentController(menuController, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var bounds = strongSelf.bounds
|
var bounds = strongSelf.bounds
|
||||||
|
|||||||
@ -8,13 +8,11 @@ import TelegramCore
|
|||||||
private let messageFont = Font.medium(14.0)
|
private let messageFont = Font.medium(14.0)
|
||||||
|
|
||||||
final class ChatEmptyItem: ListViewItem {
|
final class ChatEmptyItem: ListViewItem {
|
||||||
fileprivate let theme: PresentationTheme
|
fileprivate let presentationData: ChatPresentationData
|
||||||
fileprivate let strings: PresentationStrings
|
|
||||||
fileprivate let tagMask: MessageTags?
|
fileprivate let tagMask: MessageTags?
|
||||||
|
|
||||||
init(theme: PresentationTheme, strings: PresentationStrings, tagMask: MessageTags?) {
|
init(presentationData: ChatPresentationData, tagMask: MessageTags?) {
|
||||||
self.theme = theme
|
self.presentationData = presentationData
|
||||||
self.strings = strings
|
|
||||||
self.tagMask = tagMask
|
self.tagMask = tagMask
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +69,8 @@ final class ChatEmptyItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
private var theme: PresentationTheme?
|
private var theme: PresentationTheme?
|
||||||
|
|
||||||
|
private var item: ChatEmptyItem?
|
||||||
|
|
||||||
init(rotated: Bool) {
|
init(rotated: Bool) {
|
||||||
self.rotated = rotated
|
self.rotated = rotated
|
||||||
self.offsetContainer = ASDisplayNode()
|
self.offsetContainer = ASDisplayNode()
|
||||||
@ -98,28 +98,30 @@ final class ChatEmptyItemNode: ListViewItemNode {
|
|||||||
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
||||||
let currentTheme = self.theme
|
let currentTheme = self.theme
|
||||||
return { [weak self] item, params in
|
return { [weak self] item, params in
|
||||||
|
self?.item = item
|
||||||
|
|
||||||
let width = params.width
|
let width = params.width
|
||||||
var updatedBackgroundImage: UIImage?
|
var updatedBackgroundImage: UIImage?
|
||||||
|
|
||||||
let iconImage: UIImage? = PresentationResourcesChat.chatEmptyItemIconImage(item.theme)
|
let iconImage: UIImage? = PresentationResourcesChat.chatEmptyItemIconImage(item.presentationData.theme.theme)
|
||||||
|
|
||||||
if currentTheme !== item.theme {
|
if currentTheme !== item.presentationData.theme {
|
||||||
updatedBackgroundImage = PresentationResourcesChat.chatEmptyItemBackgroundImage(item.theme)
|
updatedBackgroundImage = PresentationResourcesChat.chatEmptyItemBackgroundImage(item.presentationData.theme.theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
let attributedText: NSAttributedString
|
let attributedText: NSAttributedString
|
||||||
if let tagMask = item.tagMask {
|
if let tagMask = item.tagMask {
|
||||||
let text: String
|
let text: String
|
||||||
if tagMask == .photoOrVideo {
|
if tagMask == .photoOrVideo {
|
||||||
text = item.strings.SharedMedia_EmptyText
|
text = item.presentationData.strings.SharedMedia_EmptyText
|
||||||
} else if tagMask == .file {
|
} else if tagMask == .file {
|
||||||
text = item.strings.SharedMedia_EmptyFilesText
|
text = item.presentationData.strings.SharedMedia_EmptyFilesText
|
||||||
} else {
|
} else {
|
||||||
text = ""
|
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 {
|
} 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
|
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())
|
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
|
return (itemLayout, { _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.theme = item.theme
|
strongSelf.theme = item.presentationData.theme.theme
|
||||||
|
|
||||||
if let updatedBackgroundImage = updatedBackgroundImage {
|
if let updatedBackgroundImage = updatedBackgroundImage {
|
||||||
strongSelf.backgroundNode.image = updatedBackgroundImage
|
strongSelf.backgroundNode.image = updatedBackgroundImage
|
||||||
@ -181,4 +183,11 @@ final class ChatEmptyItemNode: ListViewItemNode {
|
|||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@ final class ChatFeedNavigationInputPanelNode: ChatInputPanelNode {
|
|||||||
|
|
||||||
let buttonSize = self.button.measure(CGSize(width: width - leftInset - rightInset - 80.0, height: 100.0))
|
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)
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
|||||||
|
|
||||||
if let maxReadIndex = view.maxReadIndex, includeUnreadEntry {
|
if let maxReadIndex = view.maxReadIndex, includeUnreadEntry {
|
||||||
var i = 0
|
var i = 0
|
||||||
let unreadEntry: ChatHistoryEntry = .UnreadEntry(maxReadIndex, presentationData.theme, presentationData.strings)
|
let unreadEntry: ChatHistoryEntry = .UnreadEntry(maxReadIndex, presentationData)
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
if entry > unreadEntry {
|
if entry > unreadEntry {
|
||||||
if i == 0, case .HoleEntry = entry {
|
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 {
|
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 {
|
} else if view.entries.isEmpty && includeEmptyEntry {
|
||||||
//entries.insert(.EmptyChatInfoEntry(presentationData.theme, presentationData.strings, view.tagMask), at: 0)
|
//entries.insert(.EmptyChatInfoEntry(presentationData.theme, presentationData.strings, view.tagMask), at: 0)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,9 +27,9 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||||||
case HoleEntry(MessageHistoryHole, PresentationTheme, PresentationStrings)
|
case HoleEntry(MessageHistoryHole, PresentationTheme, PresentationStrings)
|
||||||
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, Bool)
|
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, Bool)
|
||||||
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, Bool)], ChatPresentationData)
|
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, Bool)], ChatPresentationData)
|
||||||
case UnreadEntry(MessageIndex, ChatPresentationThemeData, PresentationStrings)
|
case UnreadEntry(MessageIndex, ChatPresentationData)
|
||||||
case ChatInfoEntry(String, ChatPresentationThemeData, PresentationStrings)
|
case ChatInfoEntry(String, ChatPresentationData)
|
||||||
case EmptyChatInfoEntry(PresentationTheme, PresentationStrings, MessageTags?)
|
case EmptyChatInfoEntry(ChatPresentationData, MessageTags?)
|
||||||
case SearchEntry(PresentationTheme, PresentationStrings)
|
case SearchEntry(PresentationTheme, PresentationStrings)
|
||||||
|
|
||||||
var stableId: UInt64 {
|
var stableId: UInt64 {
|
||||||
@ -59,7 +59,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||||||
return MessageIndex(message)
|
return MessageIndex(message)
|
||||||
case let .MessageGroupEntry(_, messages, _):
|
case let .MessageGroupEntry(_, messages, _):
|
||||||
return MessageIndex(messages[messages.count - 1].0)
|
return MessageIndex(messages[messages.count - 1].0)
|
||||||
case let .UnreadEntry(index, _, _):
|
case let .UnreadEntry(index, _):
|
||||||
return index
|
return index
|
||||||
case .ChatInfoEntry:
|
case .ChatInfoEntry:
|
||||||
return MessageIndex.absoluteLowerBound()
|
return MessageIndex.absoluteLowerBound()
|
||||||
@ -173,20 +173,20 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .UnreadEntry(lhsIndex, lhsTheme, lhsStrings):
|
case let .UnreadEntry(lhsIndex, lhsPresentationData):
|
||||||
if case let .UnreadEntry(rhsIndex, rhsTheme, rhsStrings) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings {
|
if case let .UnreadEntry(rhsIndex, rhsPresentationData) = rhs, lhsIndex == rhsIndex, lhsPresentationData === rhsPresentationData {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .ChatInfoEntry(lhsText, lhsTheme, lhsStrings):
|
case let .ChatInfoEntry(lhsText, lhsPresentationData):
|
||||||
if case let .ChatInfoEntry(rhsText, rhsTheme, rhsStrings) = rhs, lhsText == rhsText, lhsTheme == rhsTheme, lhsStrings === rhsStrings {
|
if case let .ChatInfoEntry(rhsText, rhsPresentationData) = rhs, lhsText == rhsText, lhsPresentationData === rhsPresentationData {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .EmptyChatInfoEntry(lhsTheme, lhsStrings, lhsTagMask):
|
case let .EmptyChatInfoEntry(lhsPresentationData, lhsTagMask):
|
||||||
if case let .EmptyChatInfoEntry(rhsTheme, rhsStrings, rhsTagMask) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsTagMask == rhsTagMask {
|
if case let .EmptyChatInfoEntry(rhsPresentationData, rhsTagMask) = rhs, lhsPresentationData === rhsPresentationData, lhsTagMask == rhsTagMask {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -254,7 +254,7 @@ public final class ChatHistoryGridNode: GridNode, ChatHistoryNode {
|
|||||||
|
|
||||||
|
|
||||||
self.chatPresentationDataPromise.set(account.telegramApplicationContext.presentationData |> map { presentationData in
|
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
|
self.floatingSections = true
|
||||||
|
|||||||
@ -172,12 +172,12 @@ private func mappedInsertEntries(account: Account, chatLocation: ChatLocation, a
|
|||||||
item = ListMessageHoleItem()
|
item = ListMessageHoleItem()
|
||||||
}
|
}
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
||||||
case let .UnreadEntry(_, theme, strings):
|
case let .UnreadEntry(_, presentationData):
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, theme: theme, strings: strings), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData), directionHint: entry.directionHint)
|
||||||
case let .ChatInfoEntry(text, theme, strings):
|
case let .ChatInfoEntry(text, presentationData):
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, theme: theme, strings: strings), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, presentationData: presentationData), directionHint: entry.directionHint)
|
||||||
case let .EmptyChatInfoEntry(theme, strings, tagMask):
|
case let .EmptyChatInfoEntry(presentationData, tagMask):
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(theme: theme, strings: strings, tagMask: tagMask), directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(presentationData: presentationData, tagMask: tagMask), directionHint: entry.directionHint)
|
||||||
case let .SearchEntry(theme, strings):
|
case let .SearchEntry(theme, strings):
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
||||||
controllerInteraction.openSearch()
|
controllerInteraction.openSearch()
|
||||||
@ -217,12 +217,12 @@ private func mappedUpdateEntries(account: Account, chatLocation: ChatLocation, a
|
|||||||
item = ListMessageHoleItem()
|
item = ListMessageHoleItem()
|
||||||
}
|
}
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
||||||
case let .UnreadEntry(_, theme, strings):
|
case let .UnreadEntry(_, presentationData):
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, theme: theme, strings: strings), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData), directionHint: entry.directionHint)
|
||||||
case let .ChatInfoEntry(text, theme, strings):
|
case let .ChatInfoEntry(text, presentationData):
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, theme: theme, strings: strings), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatBotInfoItem(text: text, controllerInteraction: controllerInteraction, presentationData: presentationData), directionHint: entry.directionHint)
|
||||||
case let .EmptyChatInfoEntry(theme, strings, tagMask):
|
case let .EmptyChatInfoEntry(presentationData, tagMask):
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(theme: theme, strings: strings, tagMask: tagMask), directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatEmptyItem(presentationData: presentationData, tagMask: tagMask), directionHint: entry.directionHint)
|
||||||
case let .SearchEntry(theme, strings):
|
case let .SearchEntry(theme, strings):
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
||||||
controllerInteraction.openSearch()
|
controllerInteraction.openSearch()
|
||||||
@ -261,7 +261,7 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
|
|||||||
for entry in view.additionalData {
|
for entry in view.additionalData {
|
||||||
if case let .peer(_, value) = entry {
|
if case let .peer(_, value) = entry {
|
||||||
if let channel = value as? TelegramChannel, case .group = channel.info {
|
if let channel = value as? TelegramChannel, case .group = channel.info {
|
||||||
automaticMediaDownloadPeerType = .channel
|
automaticMediaDownloadPeerType = .group
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||||||
|
|
||||||
self.currentPresentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
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()
|
super.init()
|
||||||
|
|
||||||
@ -672,19 +672,22 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||||||
let previousTheme = strongSelf.currentPresentationData.theme
|
let previousTheme = strongSelf.currentPresentationData.theme
|
||||||
let previousStrings = strongSelf.currentPresentationData.strings
|
let previousStrings = strongSelf.currentPresentationData.strings
|
||||||
let previousWallpaper = strongSelf.currentPresentationData.chatWallpaper
|
let previousWallpaper = strongSelf.currentPresentationData.chatWallpaper
|
||||||
|
let previousDisableAnimations = strongSelf.currentPresentationData.disableAnimations
|
||||||
|
|
||||||
strongSelf.currentPresentationData = presentationData
|
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 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
|
strongSelf.forEachItemHeaderNode { itemHeaderNode in
|
||||||
if let dateNode = itemHeaderNode as? ChatMessageDateHeaderNode {
|
if let dateNode = itemHeaderNode as? ChatMessageDateHeaderNode {
|
||||||
dateNode.updateThemeAndStrings(theme: themeData, strings: presentationData.strings)
|
dateNode.updatePresentationData(chatPresentationData)
|
||||||
} else if let dateNode = itemHeaderNode as? ListMessageDateHeaderNode {
|
} else if let dateNode = itemHeaderNode as? ListMessageDateHeaderNode {
|
||||||
dateNode.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings)
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -15,4 +15,12 @@ class ChatInputPanelNode: ASDisplayNode {
|
|||||||
func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func defaultHeight(metrics: LayoutMetrics) -> CGFloat {
|
||||||
|
if case .regular = metrics.widthClass, case .regular = metrics.heightClass {
|
||||||
|
return 49.0
|
||||||
|
} else {
|
||||||
|
return 45.0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,8 @@ private let tabImageUnread = tabImageNone.flatMap({ image in
|
|||||||
})
|
})
|
||||||
|
|
||||||
public class ChatListController: TelegramController, UIViewControllerPreviewingDelegate {
|
public class ChatListController: TelegramController, UIViewControllerPreviewingDelegate {
|
||||||
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
private let account: Account
|
private let account: Account
|
||||||
private let controlsHistoryPreload: Bool
|
private let controlsHistoryPreload: Bool
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
|||||||
|
|
||||||
self.titleView = NetworkStatusTitleView(theme: self.presentationData.theme)
|
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
|
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))
|
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
if self.isNodeLoaded {
|
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() {
|
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
|
self.chatListDisplayNode.navigationBar = self.navigationBar
|
||||||
|
|
||||||
@ -525,6 +527,8 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
|||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
self.validLayout = layout
|
||||||
|
|
||||||
self.chatListDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
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? {
|
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
|
let boundsSize = self.view.bounds.size
|
||||||
var contentSize = CGSize(width: boundsSize.width, height: boundsSize.height - (boundsSize.height > boundsSize.width ? 50.0 : 10.0))
|
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)) {
|
if (boundsSize.width.isEqual(to: 375.0) && boundsSize.height.isEqual(to: 812.0)) {
|
||||||
|
|||||||
@ -23,10 +23,10 @@ class ChatListControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
var themeAndStrings: (PresentationTheme, PresentationStrings, dateTimeFormat: PresentationDateTimeFormat)
|
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.account = account
|
||||||
self.groupId = groupId
|
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)
|
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.themeAndStrings = (theme, strings, dateTimeFormat)
|
||||||
|
|
||||||
self.backgroundColor = theme.chatList.backgroundColor
|
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.searchDisplayController?.updateThemeAndStrings(theme: theme, strings: strings)
|
||||||
self.chatListEmptyNode?.updateThemeAndStrings(theme: theme, strings: strings)
|
self.chatListEmptyNode?.updateThemeAndStrings(theme: theme, strings: strings)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -164,27 +164,29 @@ private enum RevealOptionKey: Int32 {
|
|||||||
|
|
||||||
private let itemHeight: CGFloat = 76.0
|
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] = []
|
var options: [ItemListRevealOption] = []
|
||||||
if let isPinned = isPinned {
|
if !isEditing {
|
||||||
if isPinned {
|
if let isPinned = 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))
|
if isPinned {
|
||||||
} else {
|
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))
|
||||||
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))
|
} 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 let isMuted = isMuted {
|
if 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))
|
||||||
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 {
|
||||||
} 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))
|
||||||
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 let hasPeerGroupId = hasPeerGroupId {
|
if hasPeerGroupId {
|
||||||
if hasPeerGroupId {
|
options.append(ItemListRevealOption(key: RevealOptionKey.ungroup.rawValue, title: "Ungroup", icon: ungroupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
|
||||||
options.append(ItemListRevealOption(key: RevealOptionKey.ungroup.rawValue, title: "Ungroup", icon: ungroupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
|
} else {
|
||||||
} else {
|
options.append(ItemListRevealOption(key: RevealOptionKey.group.rawValue, title: "Group", icon: groupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
|
||||||
options.append(ItemListRevealOption(key: RevealOptionKey.group.rawValue, title: "Group", icon: groupIcon, color: theme.list.itemAccentColor, textColor: theme.list.itemDisclosureActions.neutral2.foregroundColor))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if canDelete {
|
if canDelete {
|
||||||
@ -709,8 +711,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
isPinned = item.index.pinningIndex != nil
|
isPinned = item.index.pinningIndex != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.enableContextActions && !item.editing && !isAd {
|
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)
|
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 {
|
if itemPeer.peerId != item.account.peerId {
|
||||||
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread)
|
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread)
|
||||||
} else {
|
} else {
|
||||||
@ -723,8 +725,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
case .groupReference:
|
case .groupReference:
|
||||||
let isPinned = item.index.pinningIndex != nil
|
let isPinned = item.index.pinningIndex != nil
|
||||||
|
|
||||||
if item.enableContextActions && !item.editing {
|
if item.enableContextActions {
|
||||||
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: nil, hasPeerGroupId: nil, canDelete: false)
|
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: nil, hasPeerGroupId: nil, canDelete: false, isEditing: item.editing)
|
||||||
} else {
|
} else {
|
||||||
peerRevealOptions = []
|
peerRevealOptions = []
|
||||||
}
|
}
|
||||||
|
|||||||
@ -333,12 +333,12 @@ final class ChatListNode: ListView {
|
|||||||
var isEmptyUpdated: ((Bool) -> Void)?
|
var isEmptyUpdated: ((Bool) -> Void)?
|
||||||
private var wasEmpty: Bool?
|
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.account = account
|
||||||
self.controlsHistoryPreload = controlsHistoryPreload
|
self.controlsHistoryPreload = controlsHistoryPreload
|
||||||
self.mode = mode
|
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.statePromise = ValuePromise(self.currentState, ignoreRepeated: true)
|
||||||
|
|
||||||
self.theme = theme
|
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) })
|
|> map({ mappedChatListNodeViewListTransition(account: account, nodeInteraction: nodeInteraction, peerGroupId: groupId, mode: mode, transition: $0) })
|
||||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||||
}
|
}
|
||||||
@ -768,7 +768,7 @@ final class ChatListNode: ListView {
|
|||||||
self.activityStatusesDisposable?.dispose()
|
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 {
|
if theme !== self.currentState.presentationData.theme || strings !== self.currentState.presentationData.strings || dateTimeFormat != self.currentState.presentationData.dateTimeFormat {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
|
||||||
@ -777,7 +777,7 @@ final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.updateState {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,12 +6,14 @@ final class ChatListPresentationData {
|
|||||||
let dateTimeFormat: PresentationDateTimeFormat
|
let dateTimeFormat: PresentationDateTimeFormat
|
||||||
let nameSortOrder: PresentationPersonNameOrder
|
let nameSortOrder: PresentationPersonNameOrder
|
||||||
let nameDisplayOrder: 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.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.dateTimeFormat = dateTimeFormat
|
self.dateTimeFormat = dateTimeFormat
|
||||||
self.nameSortOrder = nameSortOrder
|
self.nameSortOrder = nameSortOrder
|
||||||
self.nameDisplayOrder = nameDisplayOrder
|
self.nameDisplayOrder = nameDisplayOrder
|
||||||
|
self.disableAnimations = disableAnimations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -507,7 +507,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
|||||||
self.openMessage = openMessage
|
self.openMessage = openMessage
|
||||||
|
|
||||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
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.recentListNode = ListView()
|
||||||
self.listNode = ListView()
|
self.listNode = ListView()
|
||||||
|
|||||||
@ -154,7 +154,7 @@ final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
|||||||
case .disabled:
|
case .disabled:
|
||||||
return .single(([], [:]))
|
return .single(([], [:]))
|
||||||
case let .peers(peers):
|
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
|
return account.postbox.unreadMessageCountsView(items: peerViews.map {.peer($0.peerId)}) |> map { values in
|
||||||
|
|
||||||
var peers:[Peer] = []
|
var peers:[Peer] = []
|
||||||
|
|||||||
@ -44,7 +44,7 @@ enum ChatListNodeViewScrollPosition {
|
|||||||
case index(index: ChatListIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
|
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
|
return Signal { subscriber in
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
|
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)
|
let _ = options.insert(.AnimateCrossfade)
|
||||||
} else {
|
} else {
|
||||||
let _ = options.insert(.AnimateAlpha)
|
let _ = options.insert(.AnimateAlpha)
|
||||||
let _ = options.insert(.AnimateInsertion)
|
if !disableAnimations {
|
||||||
|
let _ = options.insert(.AnimateInsertion)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case .reload:
|
case .reload:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -30,6 +30,8 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
|||||||
self.emptyNode = ImmediateTextNode()
|
self.emptyNode = ImmediateTextNode()
|
||||||
self.emptyNode.isLayerBacked = true
|
self.emptyNode.isLayerBacked = true
|
||||||
self.emptyNode.attributedText = NSAttributedString(string: strings.Conversation_EmptyGifPanelPlaceholder, font: Font.regular(15.0), textColor: theme.chat.inputMediaPanel.stickersSectionTextColor)
|
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()
|
super.init()
|
||||||
|
|
||||||
|
|||||||
@ -116,7 +116,7 @@ final class ChatMessageActionSheetControllerNode: ViewControllerTracingNode {
|
|||||||
self.addSubnode(self.inputDimNode)
|
self.addSubnode(self.inputDimNode)
|
||||||
self.addSubnode(self.itemsShadowNode)
|
self.addSubnode(self.itemsShadowNode)
|
||||||
self.addSubnode(self.itemsContainerNode)
|
self.addSubnode(self.itemsContainerNode)
|
||||||
|
|
||||||
for actionNode in actionNodes {
|
for actionNode in actionNodes {
|
||||||
self.itemsContainerNode.addSubnode(actionNode)
|
self.itemsContainerNode.addSubnode(actionNode)
|
||||||
actionNode.addTarget(self, action: #selector(actionPressed(_:)), forControlEvents: .touchUpInside)
|
actionNode.addTarget(self, action: #selector(actionPressed(_:)), forControlEvents: .touchUpInside)
|
||||||
@ -205,7 +205,7 @@ final class ChatMessageActionSheetControllerNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let associatedController = self.associatedController {
|
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) {
|
if let result = associatedController.view.hitTest(subpoint, with: event) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1040,7 +1040,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
|||||||
} else {
|
} else {
|
||||||
minimalContentSize = layoutConstants.bubble.minimumSize
|
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 backgroundFrame: CGRect
|
||||||
let contentOrigin: CGPoint
|
let contentOrigin: CGPoint
|
||||||
@ -1048,12 +1054,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
|||||||
switch alignment {
|
switch alignment {
|
||||||
case .none:
|
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)
|
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)
|
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:
|
case .center:
|
||||||
let availableWidth = params.width - params.leftInset - params.rightInset
|
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)
|
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)
|
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 {
|
switch item.content {
|
||||||
case let .message(message, _, _, _):
|
case let .message(message, _, _, _):
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if media is TelegramMediaAction {
|
if let action = media as? TelegramMediaAction {
|
||||||
canHaveSelection = false
|
if case .phoneCall = action.action { } else {
|
||||||
break
|
canHaveSelection = false
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
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() {
|
@objc func shareButtonPressed() {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
if item.content.firstMessage.id.peerId == item.account.peerId {
|
if item.content.firstMessage.id.peerId == item.account.peerId {
|
||||||
|
|||||||
@ -17,13 +17,12 @@ final class ChatMessageDateHeader: ListViewItemHeader {
|
|||||||
private let roundedTimestamp: Int32
|
private let roundedTimestamp: Int32
|
||||||
|
|
||||||
let id: Int64
|
let id: Int64
|
||||||
let theme: ChatPresentationThemeData
|
let presentationData: ChatPresentationData
|
||||||
let strings: PresentationStrings
|
let action: ((Int32) -> Void)?
|
||||||
let action:((Int32)->Void)?
|
|
||||||
init(timestamp: Int32, theme: ChatPresentationThemeData, strings: PresentationStrings, action:((Int32)->Void)? = nil) {
|
init(timestamp: Int32, presentationData: ChatPresentationData, action:((Int32) -> Void)? = nil) {
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
self.theme = theme
|
self.presentationData = presentationData
|
||||||
self.strings = strings
|
|
||||||
self.action = action
|
self.action = action
|
||||||
if timestamp == Int32.max {
|
if timestamp == Int32.max {
|
||||||
self.roundedTimestamp = timestamp / (granularity) * (granularity)
|
self.roundedTimestamp = timestamp / (granularity) * (granularity)
|
||||||
@ -38,7 +37,7 @@ final class ChatMessageDateHeader: ListViewItemHeader {
|
|||||||
let height: CGFloat = 34.0
|
let height: CGFloat = 34.0
|
||||||
|
|
||||||
func node() -> ListViewItemHeaderNode {
|
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
|
let stickBackgroundNode: ASImageNode
|
||||||
|
|
||||||
private let localTimestamp: Int32
|
private let localTimestamp: Int32
|
||||||
private var theme: ChatPresentationThemeData
|
private var presentationData: ChatPresentationData
|
||||||
private var strings: PresentationStrings
|
|
||||||
|
|
||||||
private var flashingOnScrolling = false
|
private var flashingOnScrolling = false
|
||||||
private var stickDistanceFactor: CGFloat = 0.0
|
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.localTimestamp = localTimestamp
|
||||||
self.theme = theme
|
|
||||||
self.strings = strings
|
|
||||||
self.action = action
|
self.action = action
|
||||||
|
|
||||||
self.labelNode = TextNode()
|
self.labelNode = TextNode()
|
||||||
@ -115,7 +113,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||||||
|
|
||||||
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
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.backgroundNode.image = graphics.dateStaticBackground
|
||||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||||
@ -139,15 +137,15 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||||||
let text: String
|
let text: String
|
||||||
if timeinfo.tm_year == timeinfoNow.tm_year {
|
if timeinfo.tm_year == timeinfoNow.tm_year {
|
||||||
if timeinfo.tm_yday == timeinfoNow.tm_yday {
|
if timeinfo.tm_yday == timeinfoNow.tm_yday {
|
||||||
text = strings.Weekday_Today
|
text = presentationData.strings.Weekday_Today
|
||||||
} else {
|
} 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 {
|
} 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 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()))
|
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() {
|
override func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
self.view.addGestureRecognizer(ListViewTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
self.view.addGestureRecognizer(ListViewTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateThemeAndStrings(theme: ChatPresentationThemeData, strings: PresentationStrings) {
|
func updatePresentationData(_ presentationData: ChatPresentationData) {
|
||||||
self.theme = theme
|
let graphics = PresentationResourcesChat.principalGraphics(presentationData.theme.theme, wallpaper: !presentationData.theme.wallpaper.isEmpty)
|
||||||
self.strings = strings
|
|
||||||
|
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(theme.theme, wallpaper: !theme.wallpaper.isEmpty)
|
|
||||||
|
|
||||||
self.backgroundNode.image = graphics.dateStaticBackground
|
self.backgroundNode.image = graphics.dateStaticBackground
|
||||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||||
@ -261,4 +255,8 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||||||
action?(self.localTimestamp)
|
action?(self.localTimestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override public var wantsScrollDynamics: Bool {
|
||||||
|
return !self.presentationData.disableAnimations
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,10 @@ import TelegramCore
|
|||||||
class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||||
private let interactiveVideoNode: ChatMessageInteractiveInstantVideoNode
|
private let interactiveVideoNode: ChatMessageInteractiveInstantVideoNode
|
||||||
|
|
||||||
|
private var selectionNode: ChatMessageSelectionNode?
|
||||||
private var swipeToReplyNode: ChatMessageSwipeToReplyNode?
|
private var swipeToReplyNode: ChatMessageSwipeToReplyNode?
|
||||||
private var swipeToReplyFeedback: HapticFeedback?
|
private var swipeToReplyFeedback: HapticFeedback?
|
||||||
|
|
||||||
private var selectionNode: ChatMessageSelectionNode?
|
|
||||||
|
|
||||||
private var appliedItem: ChatMessageItem?
|
private var appliedItem: ChatMessageItem?
|
||||||
|
|
||||||
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
private var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||||
@ -21,6 +20,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
private var replyInfoNode: ChatMessageReplyInfoNode?
|
private var replyInfoNode: ChatMessageReplyInfoNode?
|
||||||
private var replyBackgroundNode: ASImageNode?
|
private var replyBackgroundNode: ASImageNode?
|
||||||
|
|
||||||
|
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||||
|
|
||||||
private var currentSwipeToReplyTranslation: CGFloat = 0.0
|
private var currentSwipeToReplyTranslation: CGFloat = 0.0
|
||||||
|
|
||||||
override var visibility: ListViewItemNodeVisibility {
|
override var visibility: ListViewItemNodeVisibility {
|
||||||
@ -76,9 +77,12 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
|
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
|
||||||
let currentForwardBackgroundNode = self.forwardBackgroundNode
|
let currentForwardBackgroundNode = self.forwardBackgroundNode
|
||||||
|
|
||||||
|
let actionButtonsLayout = ChatMessageActionButtonsNode.asyncLayout(self.actionButtonsNode)
|
||||||
|
|
||||||
let currentItem = self.appliedItem
|
let currentItem = self.appliedItem
|
||||||
|
|
||||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||||
|
let baseWidth = params.width - params.leftInset - params.rightInset
|
||||||
let incoming = item.message.effectivelyIncoming(item.account.peerId)
|
let incoming = item.message.effectivelyIncoming(item.account.peerId)
|
||||||
|
|
||||||
let avatarInset: CGFloat
|
let avatarInset: CGFloat
|
||||||
@ -124,6 +128,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?
|
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?
|
||||||
var updatedReplyBackgroundNode: ASImageNode?
|
var updatedReplyBackgroundNode: ASImageNode?
|
||||||
var replyBackgroundImage: UIImage?
|
var replyBackgroundImage: UIImage?
|
||||||
|
var replyMarkup: ReplyMarkupMessageAttribute?
|
||||||
|
var inlineBotNameString: String?
|
||||||
|
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
|
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)
|
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)
|
replyBackgroundImage = PresentationResourcesChat.chatServiceBubbleFillImage(item.presentationData.theme.theme)
|
||||||
break
|
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)
|
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 {
|
if let strongSelf = self {
|
||||||
strongSelf.appliedItem = item
|
strongSelf.appliedItem = item
|
||||||
|
|
||||||
@ -241,6 +274,35 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
forwardInfoNode.removeFromSupernode()
|
forwardInfoNode.removeFromSupernode()
|
||||||
strongSelf.forwardInfoNode = nil
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -279,11 +279,8 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
|||||||
self.effectiveAuthorId = effectiveAuthor?.id
|
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
|
var calendar = NSCalendar.current
|
||||||
|
|
||||||
calendar.timeZone = TimeZone(abbreviation: "UTC")!
|
calendar.timeZone = TimeZone(abbreviation: "UTC")!
|
||||||
let date = Date(timeIntervalSince1970: TimeInterval(timestamp))
|
let date = Date(timeIntervalSince1970: TimeInterval(timestamp))
|
||||||
let components = calendar.dateComponents([.year, .month, .day], from: date)
|
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) {
|
if let date = calendar.date(from: components) {
|
||||||
controllerInteraction.navigateToFirstDateMessage(Int32(date.timeIntervalSince1970))
|
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 {
|
if displayAuthorInfo {
|
||||||
@ -330,7 +312,6 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.accessoryItem = accessoryItem
|
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) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
import Postbox
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
|
||||||
struct ChatMessageItemWidthFill {
|
struct ChatMessageItemWidthFill {
|
||||||
let compactInset: CGFloat
|
let compactInset: CGFloat
|
||||||
@ -190,4 +191,55 @@ public class ChatMessageItemView: ListViewItemNode {
|
|||||||
return nil
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,7 +76,8 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
textColor = titleColor
|
textColor = titleColor
|
||||||
}
|
}
|
||||||
|
|
||||||
var leftInset: CGFloat = 10.0
|
var leftInset: CGFloat = 11.0
|
||||||
|
let spacing: CGFloat = 2.0
|
||||||
|
|
||||||
var overlayIcon: UIImage?
|
var overlayIcon: UIImage?
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
|
|
||||||
var applyImage: (() -> TransformImageNode)?
|
var applyImage: (() -> TransformImageNode)?
|
||||||
if let imageDimensions = imageDimensions {
|
if let imageDimensions = imageDimensions {
|
||||||
leftInset += 36.0
|
leftInset += 32.0
|
||||||
let boundingSize = CGSize(width: 30.0, height: 30.0)
|
let boundingSize = CGSize(width: 30.0, height: 30.0)
|
||||||
var radius: CGFloat = 2.0
|
var radius: CGFloat = 2.0
|
||||||
var imageSize = imageDimensions.aspectFilled(boundingSize)
|
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 (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 (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, {
|
return (size, {
|
||||||
let node: ChatMessageReplyInfoNode
|
let node: ChatMessageReplyInfoNode
|
||||||
@ -186,8 +187,8 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
node.addSubnode(imageNode)
|
node.addSubnode(imageNode)
|
||||||
node.imageNode = 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: 4.0 + UIScreenPixel), 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))
|
imageFrame = imageNode.frame
|
||||||
|
|
||||||
if let updateImageSignal = updateImageSignal {
|
if let updateImageSignal = updateImageSignal {
|
||||||
imageNode.setSignal(updateImageSignal)
|
imageNode.setSignal(updateImageSignal)
|
||||||
@ -216,11 +217,11 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
node.overlayIconNode = nil
|
node.overlayIconNode = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: titleLayout.size)
|
titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: spacing), size: titleLayout.size)
|
||||||
textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: titleLayout.size.height), size: textLayout.size)
|
textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: titleNode.frame.maxY + spacing), size: textLayout.size)
|
||||||
|
|
||||||
node.lineNode.image = lineImage
|
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)
|
node.contentNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
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)
|
self.validLayout = (width, leftInset, rightInset, maxHeight, metrics)
|
||||||
|
|
||||||
let panelHeight: CGFloat = 45.0
|
let panelHeight = defaultHeight(metrics: metrics)
|
||||||
|
|
||||||
if self.presentationInterfaceState != interfaceState {
|
if self.presentationInterfaceState != interfaceState {
|
||||||
self.presentationInterfaceState = interfaceState
|
self.presentationInterfaceState = interfaceState
|
||||||
@ -186,6 +186,6 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,8 +124,8 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
if let strongSelf = self, let item = strongSelf.item {
|
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 {
|
if let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content, let image = content.image, let instantPage = content.instantPage {
|
||||||
var isGallery = false
|
var isGallery = false
|
||||||
switch websiteType(of: content) {
|
switch instantPageType(of: content) {
|
||||||
case .instagram, .twitter:
|
case .album:
|
||||||
let count = instantPageGalleryMedia(webpageId: webPage.webpageId, page: instantPage, galleryMedia: image).count
|
let count = instantPageGalleryMedia(webpageId: webPage.webpageId, page: instantPage, galleryMedia: image).count
|
||||||
if count > 1 {
|
if count > 1 {
|
||||||
isGallery = true
|
isGallery = true
|
||||||
@ -331,8 +331,8 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let webPage = self.webPage, case let .Loaded(content) = webPage.content, content.instantPage != nil {
|
if let webPage = self.webPage, case let .Loaded(content) = webPage.content, content.instantPage != nil {
|
||||||
switch instantPageType(of: content) {
|
switch websiteType(of: content) {
|
||||||
case .album:
|
case .instagram, .twitter:
|
||||||
return .none
|
return .none
|
||||||
default:
|
default:
|
||||||
return .instantPage
|
return .instantPage
|
||||||
|
|||||||
@ -53,17 +53,19 @@ public final class ChatPresentationData {
|
|||||||
let fontSize: PresentationFontSize
|
let fontSize: PresentationFontSize
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
let dateTimeFormat: PresentationDateTimeFormat
|
let dateTimeFormat: PresentationDateTimeFormat
|
||||||
|
let disableAnimations: Bool
|
||||||
|
|
||||||
let messageFont: UIFont
|
let messageFont: UIFont
|
||||||
let messageBoldFont: UIFont
|
let messageBoldFont: UIFont
|
||||||
let messageItalicFont: UIFont
|
let messageItalicFont: UIFont
|
||||||
let messageFixedFont: 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.theme = theme
|
||||||
self.fontSize = fontSize
|
self.fontSize = fontSize
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.dateTimeFormat = dateTimeFormat
|
self.dateTimeFormat = dateTimeFormat
|
||||||
|
self.disableAnimations = disableAnimations
|
||||||
|
|
||||||
let baseFontSize = fontSize.baseDisplaySize
|
let baseFontSize = fontSize.baseDisplaySize
|
||||||
self.messageFont = UIFont.systemFont(ofSize: baseFontSize)
|
self.messageFont = UIFont.systemFont(ofSize: baseFontSize)
|
||||||
|
|||||||
@ -26,7 +26,7 @@ final class ChatRecentActionsController: TelegramController {
|
|||||||
|
|
||||||
self.titleView = ChatRecentActionsTitleView(color: self.presentationData.theme.rootController.navigationBar.primaryTextColor)
|
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
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
|
||||||
|
|
||||||
|
|||||||
@ -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.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)
|
self.context = ChannelAdminEventLogContext(postbox: self.account.postbox, network: self.account.network, peerId: self.peer.id)
|
||||||
|
|
||||||
|
|||||||
@ -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.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)))
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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))
|
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)
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.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)))
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,8 +112,12 @@ private final class AccessoryItemIconButton: HighlightableButton {
|
|||||||
|
|
||||||
private func calclulateTextFieldMinHeight(_ presentationInterfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
private func calclulateTextFieldMinHeight(_ presentationInterfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
let baseFontSize = max(17.0, presentationInterfaceState.fontSize.baseDisplaySize)
|
let baseFontSize = max(17.0, presentationInterfaceState.fontSize.baseDisplaySize)
|
||||||
let result: CGFloat
|
var result: CGFloat
|
||||||
if baseFontSize.isEqual(to: 17.0) {
|
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
|
result = 31.0
|
||||||
} else if baseFontSize.isEqual(to: 19.0) {
|
} else if baseFontSize.isEqual(to: 19.0) {
|
||||||
result = 33.0
|
result = 33.0
|
||||||
@ -122,6 +126,11 @@ private func calclulateTextFieldMinHeight(_ presentationInterfaceState: ChatPres
|
|||||||
} else {
|
} else {
|
||||||
result = 31.0
|
result = 31.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .regular = metrics.widthClass {
|
||||||
|
result = max(33.0, result)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +187,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
var displayAttachmentMenu: () -> Void = { }
|
var displayAttachmentMenu: () -> Void = { }
|
||||||
var sendMessage: () -> Void = { }
|
var sendMessage: () -> Void = { }
|
||||||
var pasteImages: ([UIImage]) -> Void = { _ in }
|
var pasteImages: ([UIImage]) -> Void = { _ in }
|
||||||
|
var pasteData: (Data) -> Void = { _ in }
|
||||||
var updateHeight: () -> Void = { }
|
var updateHeight: () -> Void = { }
|
||||||
|
|
||||||
var updateActivity: () -> Void = { }
|
var updateActivity: () -> Void = { }
|
||||||
@ -482,7 +492,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
|
|
||||||
let updatedMaxHeight = (CGFloat(maxNumberOfLines) * 22.0 + 10.0)
|
let updatedMaxHeight = (CGFloat(maxNumberOfLines) * 22.0 + 10.0)
|
||||||
|
|
||||||
textFieldHeight = min(updatedMaxHeight, unboundTextFieldHeight)
|
textFieldHeight = max(textFieldMinHeight, min(updatedMaxHeight, unboundTextFieldHeight))
|
||||||
} else {
|
} else {
|
||||||
textFieldHeight = textFieldMinHeight
|
textFieldHeight = textFieldMinHeight
|
||||||
}
|
}
|
||||||
@ -1296,26 +1306,28 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
|
@objc func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
|
||||||
|
let pasteboard = UIPasteboard.general
|
||||||
|
|
||||||
var images: [UIImage] = []
|
var images: [UIImage] = []
|
||||||
var text: String?
|
if let gifData = pasteboard.data(forPasteboardType: "com.compuserve.gif") {
|
||||||
|
self.pasteData(gifData)
|
||||||
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 false
|
||||||
} else {
|
} 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() {
|
@objc func sendButtonPressed() {
|
||||||
|
|||||||
@ -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) {
|
var networkState: AccountNetworkState = .online(proxy: nil) {
|
||||||
didSet {
|
didSet {
|
||||||
if self.networkState != oldValue {
|
if self.networkState != oldValue {
|
||||||
if case .online = self.networkState {
|
updateNetworkStatusNode(networkState: self.networkState, metrics: self.layoutMetrics)
|
||||||
self.contentContainer.isHidden = false
|
}
|
||||||
if let networkStatusNode = self.networkStatusNode {
|
}
|
||||||
self.networkStatusNode = nil
|
}
|
||||||
networkStatusNode.removeFromSupernode()
|
|
||||||
}
|
var layoutMetrics: LayoutMetrics = LayoutMetrics() {
|
||||||
} else {
|
didSet {
|
||||||
self.contentContainer.isHidden = true
|
if self.layoutMetrics != oldValue {
|
||||||
let statusNode: ChatTitleNetworkStatusNode
|
updateNetworkStatusNode(networkState: self.networkState, metrics: self.layoutMetrics)
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,7 +103,7 @@ final class ChatUnblockInputPanelNode: ChatInputPanelNode {
|
|||||||
|
|
||||||
let buttonSize = self.button.measure(CGSize(width: width - leftInset - rightInset - 80.0, height: 100.0))
|
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)
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,15 +9,13 @@ private let titleFont = UIFont.systemFont(ofSize: 13.0)
|
|||||||
|
|
||||||
class ChatUnreadItem: ListViewItem {
|
class ChatUnreadItem: ListViewItem {
|
||||||
let index: MessageIndex
|
let index: MessageIndex
|
||||||
let theme: ChatPresentationThemeData
|
let presentationData: ChatPresentationData
|
||||||
let strings: PresentationStrings
|
|
||||||
let header: ChatMessageDateHeader
|
let header: ChatMessageDateHeader
|
||||||
|
|
||||||
init(index: MessageIndex, theme: ChatPresentationThemeData, strings: PresentationStrings) {
|
init(index: MessageIndex, presentationData: ChatPresentationData) {
|
||||||
self.index = index
|
self.index = index
|
||||||
self.theme = theme
|
self.presentationData = presentationData
|
||||||
self.strings = strings
|
self.header = ChatMessageDateHeader(timestamp: index.timestamp, presentationData: presentationData)
|
||||||
self.header = ChatMessageDateHeader(timestamp: index.timestamp, theme: theme, strings: strings)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
|
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
|
return { item, params, dateAtBottom in
|
||||||
var updatedBackgroundImage: UIImage?
|
var updatedBackgroundImage: UIImage?
|
||||||
if currentTheme != item.theme {
|
if currentTheme != item.presentationData.theme {
|
||||||
updatedBackgroundImage = PresentationResourcesChat.chatUnreadBarBackgroundImage(item.theme.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)
|
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
|
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 {
|
if let strongSelf = self {
|
||||||
strongSelf.item = item
|
strongSelf.item = item
|
||||||
strongSelf.theme = item.theme
|
strongSelf.theme = item.presentationData.theme
|
||||||
|
|
||||||
if let updatedBackgroundImage = updatedBackgroundImage {
|
if let updatedBackgroundImage = updatedBackgroundImage {
|
||||||
strongSelf.backgroundNode.image = 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)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,9 +76,17 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setStatusSignal(_ status: Signal<MediaPlayerStatus, NoError>?) {
|
func setStatusSignal(_ status: Signal<MediaPlayerStatus, NoError>?) {
|
||||||
self.scrubberNode.status = status
|
let mappedStatus: Signal<MediaPlayerStatus, NoError>?
|
||||||
self.leftTimestampNode.status = status
|
if let status = status {
|
||||||
self.rightTimestampNode.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>?) {
|
func setBufferingStatusSignal(_ status: Signal<(IndexSet, Int)?, NoError>?) {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public extension TabBarControllerTheme {
|
|||||||
public extension NavigationBarTheme {
|
public extension NavigationBarTheme {
|
||||||
public convenience init(rootControllerTheme: PresentationTheme) {
|
public convenience init(rootControllerTheme: PresentationTheme) {
|
||||||
let theme = rootControllerTheme.rootController.navigationBar
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -565,7 +565,7 @@ final class ContactListNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
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) {
|
init(account: Account, presentation: ContactListPresentation, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil) {
|
||||||
self.account = account
|
self.account = account
|
||||||
@ -576,7 +576,7 @@ final class ContactListNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
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()
|
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 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 previous = previousEntries.swap(entries)
|
||||||
let animated: Bool
|
let animated: Bool
|
||||||
if let previous = previous {
|
if let previous = previous, !themeAndStrings.5 {
|
||||||
animated = (entries.count - previous.count) < 20
|
animated = (entries.count - previous.count) < 20
|
||||||
} else {
|
} else {
|
||||||
animated = false
|
animated = false
|
||||||
@ -747,12 +747,13 @@ final class ContactListNode: ASDisplayNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let previousTheme = strongSelf.presentationData.theme
|
let previousTheme = strongSelf.presentationData.theme
|
||||||
let previousStrings = strongSelf.presentationData.strings
|
let previousStrings = strongSelf.presentationData.strings
|
||||||
|
let previousDisableAnimations = strongSelf.presentationData.disableAnimations
|
||||||
|
|
||||||
strongSelf.presentationData = presentationData
|
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.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
|
strongSelf.listNode.forEachAccessoryItemNode({ accessoryItemNode in
|
||||||
if let accessoryItemNode = accessoryItemNode as? ContactsSectionHeaderAccessoryItemNode {
|
if let accessoryItemNode = accessoryItemNode as? ContactsSectionHeaderAccessoryItemNode {
|
||||||
|
|||||||
@ -153,7 +153,7 @@ class ContactMultiselectionController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func loadDisplayNode() {
|
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._listReady.set(self.contactsNode.contactListNode.ready)
|
||||||
|
|
||||||
self.contactsNode.dismiss = { [weak self] in
|
self.contactsNode.dismiss = { [weak self] in
|
||||||
|
|||||||
@ -44,12 +44,20 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
|
|
||||||
init(account: Account, options: [ContactListAdditionalOption], filters: [ContactListFilter]) {
|
init(account: Account, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter]) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
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.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()
|
super.init()
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,7 @@ private let rootTabBar = PresentationThemeRootTabBar(
|
|||||||
|
|
||||||
private let rootNavigationBar = PresentationThemeRootNavigationBar(
|
private let rootNavigationBar = PresentationThemeRootNavigationBar(
|
||||||
buttonColor: accentColor,
|
buttonColor: accentColor,
|
||||||
|
disabledButtonColor: UIColor(rgb: 0x5b646f),
|
||||||
primaryTextColor: UIColor(rgb: 0xffffff),
|
primaryTextColor: UIColor(rgb: 0xffffff),
|
||||||
secondaryTextColor: UIColor(rgb: 0x8B9197),
|
secondaryTextColor: UIColor(rgb: 0x8B9197),
|
||||||
controlColor: UIColor(rgb: 0x8B9197),
|
controlColor: UIColor(rgb: 0x8B9197),
|
||||||
|
|||||||
@ -24,6 +24,7 @@ private let rootTabBar = PresentationThemeRootTabBar(
|
|||||||
|
|
||||||
private let rootNavigationBar = PresentationThemeRootNavigationBar(
|
private let rootNavigationBar = PresentationThemeRootNavigationBar(
|
||||||
buttonColor: accentColor,
|
buttonColor: accentColor,
|
||||||
|
disabledButtonColor: UIColor(rgb: 0x525252),
|
||||||
primaryTextColor: accentColor,
|
primaryTextColor: accentColor,
|
||||||
secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5),
|
secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5),
|
||||||
controlColor: accentColor,
|
controlColor: accentColor,
|
||||||
|
|||||||
@ -24,6 +24,7 @@ private func makeDefaultPresentationTheme(accentColor: UIColor, day: Bool) -> Pr
|
|||||||
|
|
||||||
let rootNavigationBar = PresentationThemeRootNavigationBar(
|
let rootNavigationBar = PresentationThemeRootNavigationBar(
|
||||||
buttonColor: accentColor,
|
buttonColor: accentColor,
|
||||||
|
disabledButtonColor: UIColor(rgb: 0xd0d0d0),
|
||||||
primaryTextColor: .black,
|
primaryTextColor: .black,
|
||||||
secondaryTextColor: UIColor(rgb: 0x787878),
|
secondaryTextColor: UIColor(rgb: 0x787878),
|
||||||
controlColor: UIColor(rgb: 0x7e8791),
|
controlColor: UIColor(rgb: 0x7e8791),
|
||||||
|
|||||||
@ -42,7 +42,7 @@ final class DeleteChatInputPanelNode: ChatInputPanelNode {
|
|||||||
|
|
||||||
let buttonSize = self.button.measure(CGSize(width: width - leftInset - rightInset - 10.0, height: 100.0))
|
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)
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -293,90 +293,11 @@ func editSettingsController(account: Account, currentName: ItemListAvatarAndName
|
|||||||
var avatarGalleryTransitionArguments: ((AvatarGalleryEntry) -> GalleryTransitionArguments?)?
|
var avatarGalleryTransitionArguments: ((AvatarGalleryEntry) -> GalleryTransitionArguments?)?
|
||||||
let avatarAndNameInfoContext = ItemListAvatarAndNameInfoItemContext()
|
let avatarAndNameInfoContext = ItemListAvatarAndNameInfoItemContext()
|
||||||
var updateHiddenAvatarImpl: (() -> Void)?
|
var updateHiddenAvatarImpl: (() -> Void)?
|
||||||
|
var changeProfilePhotoImpl: (() -> Void)?
|
||||||
|
|
||||||
let wallpapersPromise = Promise<[TelegramWallpaper]>()
|
let wallpapersPromise = Promise<[TelegramWallpaper]>()
|
||||||
wallpapersPromise.set(telegramWallpapers(postbox: account.postbox, network: account.network))
|
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: {
|
let arguments = EditSettingsItemArguments(account: account, accountManager: accountManager, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
|
||||||
var updating = false
|
var updating = false
|
||||||
updateState {
|
updateState {
|
||||||
@ -388,7 +309,7 @@ func editSettingsController(account: Account, currentName: ItemListAvatarAndName
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
changeProfilePhotoImpl()
|
changeProfilePhotoImpl?()
|
||||||
}, pushController: { controller in
|
}, pushController: { controller in
|
||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
}, presentController: { controller in
|
}, 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
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -231,8 +231,8 @@ enum GalleryControllerItemSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GalleryController: ViewController {
|
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 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), 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 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 {
|
private var galleryNode: GalleryControllerNode {
|
||||||
return self.displayNode as! GalleryControllerNode
|
return self.displayNode as! GalleryControllerNode
|
||||||
|
|||||||
@ -155,8 +155,6 @@ final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var removedNodes: [GalleryItemNode] = []
|
|
||||||
|
|
||||||
if !transaction.deleteItems.isEmpty || !transaction.insertItems.isEmpty {
|
if !transaction.deleteItems.isEmpty || !transaction.insertItems.isEmpty {
|
||||||
let deleteItems = transaction.deleteItems.sorted()
|
let deleteItems = transaction.deleteItems.sorted()
|
||||||
|
|
||||||
@ -164,8 +162,8 @@ final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.items.remove(at: deleteItemIndex)
|
self.items.remove(at: deleteItemIndex)
|
||||||
for i in 0 ..< self.itemNodes.count {
|
for i in 0 ..< self.itemNodes.count {
|
||||||
if self.itemNodes[i].index == deleteItemIndex {
|
if self.itemNodes[i].index == deleteItemIndex {
|
||||||
removedNodes.append(self.itemNodes[i])
|
|
||||||
self.removeVisibleItemNode(internalIndex: i)
|
self.removeVisibleItemNode(internalIndex: i)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
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 peerNotificationSettings: TelegramPeerNotificationSettings = (view.notificationSettings as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings
|
||||||
let notificationsText: String
|
let notificationsText: String
|
||||||
switch peerNotificationSettings.muteState {
|
switch peerNotificationSettings.muteState {
|
||||||
@ -751,6 +747,10 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let editingState = state.editingState {
|
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 let group = view.peers[view.peerId] as? TelegramGroup {
|
||||||
if case .creator = group.role {
|
if case .creator = group.role {
|
||||||
entries.append(.adminManagement(presentationData.theme, presentationData.strings.GroupInfo_ChatAdmins))
|
entries.append(.adminManagement(presentationData.theme, presentationData.strings.GroupInfo_ChatAdmins))
|
||||||
|
|||||||
@ -26,14 +26,14 @@ final class HashtagSearchController: TelegramController {
|
|||||||
|
|
||||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
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.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
|
||||||
|
|
||||||
self.title = query
|
self.title = query
|
||||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
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 location: SearchMessagesLocation = .general
|
||||||
let search = searchMessages(account: account, location: location, query: query)
|
let search = searchMessages(account: account, location: location, query: query)
|
||||||
|
|||||||
@ -453,7 +453,12 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
|
|||||||
statusColor = item.theme.list.itemPrimaryTextColor
|
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
|
let separatorHeight = UIScreenPixel
|
||||||
|
|
||||||
@ -660,6 +665,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
|
|||||||
inputFirstField.textColor = item.theme.list.itemPrimaryTextColor
|
inputFirstField.textColor = item.theme.list.itemPrimaryTextColor
|
||||||
inputFirstField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
|
inputFirstField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
|
||||||
inputFirstField.autocorrectionType = .no
|
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.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)
|
inputFirstField.attributedText = NSAttributedString(string: firstName, font: Font.regular(17.0), textColor: item.theme.list.itemPrimaryTextColor)
|
||||||
strongSelf.inputFirstField = inputFirstField
|
strongSelf.inputFirstField = inputFirstField
|
||||||
@ -675,6 +681,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
|
|||||||
inputSecondField.textColor = item.theme.list.itemPrimaryTextColor
|
inputSecondField.textColor = item.theme.list.itemPrimaryTextColor
|
||||||
inputSecondField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
|
inputSecondField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
|
||||||
inputSecondField.autocorrectionType = .no
|
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.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)
|
inputSecondField.attributedText = NSAttributedString(string: lastName, font: Font.regular(17.0), textColor: item.theme.list.itemPrimaryTextColor)
|
||||||
strongSelf.inputSecondField = inputSecondField
|
strongSelf.inputSecondField = inputSecondField
|
||||||
|
|||||||
@ -161,6 +161,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
@objc func revealTapGesture(_ recognizer: UITapGestureRecognizer) {
|
@objc func revealTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
if case .ended = recognizer.state {
|
if case .ended = recognizer.state {
|
||||||
self.updateRevealOffsetInternal(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
|
self.updateRevealOffsetInternal(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
|
||||||
|
self.revealOptionsInteractivelyClosed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -173,12 +173,17 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var playbackStatusValue: MediaPlayerPlaybackStatus?
|
private var playbackStatusValue: MediaPlayerPlaybackStatus?
|
||||||
private var scrubbingBeginTimestamp: Double?
|
private var scrubbingBeginTimestamp: Double?
|
||||||
private var scrubbingTimestamp: Double?
|
private var scrubbingTimestampValue: Double?
|
||||||
|
|
||||||
var playbackStatusUpdated: ((MediaPlayerPlaybackStatus?) -> Void)?
|
var playbackStatusUpdated: ((MediaPlayerPlaybackStatus?) -> Void)?
|
||||||
var playerStatusUpdated: ((MediaPlayerStatus?) -> Void)?
|
var playerStatusUpdated: ((MediaPlayerStatus?) -> Void)?
|
||||||
var seek: ((Double) -> Void)?
|
var seek: ((Double) -> Void)?
|
||||||
|
|
||||||
|
private let _scrubbingTimestamp = Promise<Double?>(nil)
|
||||||
|
var scrubbingTimestamp: Signal<Double?, NoError> {
|
||||||
|
return self._scrubbingTimestamp.get()
|
||||||
|
}
|
||||||
|
|
||||||
var ignoreSeekId: Int?
|
var ignoreSeekId: Int?
|
||||||
|
|
||||||
var enableScrubbing: Bool = true {
|
var enableScrubbing: Bool = true {
|
||||||
@ -361,7 +366,8 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
|
if let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
|
||||||
strongSelf.scrubbingBeginTimestamp = statusValue.timestamp
|
strongSelf.scrubbingBeginTimestamp = statusValue.timestamp
|
||||||
strongSelf.scrubbingTimestamp = statusValue.timestamp
|
strongSelf.scrubbingTimestampValue = statusValue.timestamp
|
||||||
|
strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue))
|
||||||
strongSelf.updateProgress()
|
strongSelf.updateProgress()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,7 +375,8 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
handleNodeContainer.updateScrubbing = { [weak self] addedFraction in
|
handleNodeContainer.updateScrubbing = { [weak self] addedFraction in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let statusValue = strongSelf.statusValue, let scrubbingBeginTimestamp = strongSelf.scrubbingBeginTimestamp, Double(0.0).isLess(than: statusValue.duration) {
|
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()
|
strongSelf.updateProgress()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,13 +384,14 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
handleNodeContainer.endScrubbing = { [weak self] apply in
|
handleNodeContainer.endScrubbing = { [weak self] apply in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.scrubbingBeginTimestamp = nil
|
strongSelf.scrubbingBeginTimestamp = nil
|
||||||
let scrubbingTimestamp = strongSelf.scrubbingTimestamp
|
let scrubbingTimestampValue = strongSelf.scrubbingTimestampValue
|
||||||
strongSelf.scrubbingTimestamp = nil
|
strongSelf.scrubbingTimestampValue = nil
|
||||||
if let scrubbingTimestamp = scrubbingTimestamp, apply {
|
strongSelf._scrubbingTimestamp.set(.single(nil))
|
||||||
|
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
|
||||||
if let statusValue = strongSelf.statusValue {
|
if let statusValue = strongSelf.statusValue {
|
||||||
strongSelf.ignoreSeekId = statusValue.seekId
|
strongSelf.ignoreSeekId = statusValue.seekId
|
||||||
}
|
}
|
||||||
strongSelf.seek?(scrubbingTimestamp)
|
strongSelf.seek?(scrubbingTimestampValue)
|
||||||
}
|
}
|
||||||
strongSelf.updateProgress()
|
strongSelf.updateProgress()
|
||||||
}
|
}
|
||||||
@ -404,7 +412,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
|
if let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
|
||||||
strongSelf.scrubbingBeginTimestamp = statusValue.timestamp
|
strongSelf.scrubbingBeginTimestamp = statusValue.timestamp
|
||||||
strongSelf.scrubbingTimestamp = statusValue.timestamp
|
strongSelf.scrubbingTimestampValue = statusValue.timestamp
|
||||||
strongSelf.updateProgress()
|
strongSelf.updateProgress()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,7 +420,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
handleNodeContainer.updateScrubbing = { [weak self] addedFraction in
|
handleNodeContainer.updateScrubbing = { [weak self] addedFraction in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let statusValue = strongSelf.statusValue, let scrubbingBeginTimestamp = strongSelf.scrubbingBeginTimestamp, Double(0.0).isLess(than: statusValue.duration) {
|
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()
|
strongSelf.updateProgress()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,10 +428,10 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
handleNodeContainer.endScrubbing = { [weak self] apply in
|
handleNodeContainer.endScrubbing = { [weak self] apply in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.scrubbingBeginTimestamp = nil
|
strongSelf.scrubbingBeginTimestamp = nil
|
||||||
let scrubbingTimestamp = strongSelf.scrubbingTimestamp
|
let scrubbingTimestampValue = strongSelf.scrubbingTimestampValue
|
||||||
strongSelf.scrubbingTimestamp = nil
|
strongSelf.scrubbingTimestampValue = nil
|
||||||
if let scrubbingTimestamp = scrubbingTimestamp, apply {
|
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
|
||||||
strongSelf.seek?(scrubbingTimestamp)
|
strongSelf.seek?(scrubbingTimestampValue)
|
||||||
}
|
}
|
||||||
strongSelf.updateProgress()
|
strongSelf.updateProgress()
|
||||||
}
|
}
|
||||||
@ -529,8 +537,8 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
if case .buffering(true, _) = statusValue.status {
|
if case .buffering(true, _) = statusValue.status {
|
||||||
initialBuffering = true
|
initialBuffering = true
|
||||||
} else if Double(0.0).isLess(than: statusValue.duration) {
|
} else if Double(0.0).isLess(than: statusValue.duration) {
|
||||||
if let scrubbingTimestamp = self.scrubbingTimestamp {
|
if let scrubbingTimestampValue = self.scrubbingTimestampValue {
|
||||||
timestampAndDuration = (max(0.0, min(scrubbingTimestamp, statusValue.duration)), statusValue.duration)
|
timestampAndDuration = (max(0.0, min(scrubbingTimestampValue, statusValue.duration)), statusValue.duration)
|
||||||
} else {
|
} else {
|
||||||
timestampAndDuration = (statusValue.timestamp, statusValue.duration)
|
timestampAndDuration = (statusValue.timestamp, statusValue.duration)
|
||||||
}
|
}
|
||||||
@ -539,7 +547,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let (timestamp, duration) = timestampAndDuration {
|
if let (timestamp, duration) = timestampAndDuration {
|
||||||
let progress = CGFloat(timestamp / duration)
|
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 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))
|
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)?
|
let timestampAndDuration: (timestamp: Double, duration: Double)?
|
||||||
if let statusValue = self.statusValue, Double(0.0).isLess(than: statusValue.duration) {
|
if let statusValue = self.statusValue, Double(0.0).isLess(than: statusValue.duration) {
|
||||||
if let scrubbingTimestamp = self.scrubbingTimestamp {
|
if let scrubbingTimestampValue = self.scrubbingTimestampValue {
|
||||||
timestampAndDuration = (max(0.0, min(scrubbingTimestamp, statusValue.duration)), statusValue.duration)
|
timestampAndDuration = (max(0.0, min(scrubbingTimestampValue, statusValue.duration)), statusValue.duration)
|
||||||
} else {
|
} else {
|
||||||
timestampAndDuration = (statusValue.timestamp, statusValue.duration)
|
timestampAndDuration = (statusValue.timestamp, statusValue.duration)
|
||||||
}
|
}
|
||||||
@ -652,7 +660,7 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let (timestamp, duration) = timestampAndDuration {
|
if let (timestamp, duration) = timestampAndDuration {
|
||||||
let progress = CGFloat(timestamp / duration)
|
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 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))
|
let toRect = CGRect(origin: backgroundFrame.origin, size: CGSize(width: backgroundFrame.size.width, height: backgroundFrame.size.height))
|
||||||
|
|
||||||
|
|||||||
@ -100,10 +100,12 @@ private func allOpenInOptions(applicationContext: TelegramApplicationContext, it
|
|||||||
let lat = location.latitude
|
let lat = location.latitude
|
||||||
let lon = location.longitude
|
let lon = location.longitude
|
||||||
|
|
||||||
if let venue = location.venue, let venueId = venue.id, let provider = venue.provider, provider == "foursquare" {
|
if !withDirections {
|
||||||
options.append(OpenInOption(application: .other(title: "Foursquare", identifier: 306934924, scheme: "foursquare"), action: {
|
if let venue = location.venue, let venueId = venue.id, let provider = venue.provider, provider == "foursquare" {
|
||||||
return .openUrl(url: "foursquare://venues/\(venueId)")
|
options.append(OpenInOption(application: .other(title: "Foursquare", identifier: 306934924, scheme: "foursquare"), action: {
|
||||||
}))
|
return .openUrl(url: "foursquare://venues/\(venueId)")
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options.append(OpenInOption(application: .maps, action: {
|
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)")
|
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 {
|
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: {
|
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)")
|
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: {
|
if !withDirections {
|
||||||
return .openUrl(url: "here-location://\(lat),\(lon)")
|
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: {
|
options.append(OpenInOption(application: .other(title: "Waze", identifier: 323229106, scheme: "waze"), action: {
|
||||||
let url = "waze://?ll=\(lat),\(lon)"
|
let url = "waze://?ll=\(lat),\(lon)"
|
||||||
|
|||||||
@ -41,10 +41,10 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec
|
|||||||
self.requestDismiss = requestDismiss
|
self.requestDismiss = requestDismiss
|
||||||
self.requestShare = requestShare
|
self.requestShare = requestShare
|
||||||
|
|
||||||
if case .reversed = initialOrder {
|
if case .regular = initialOrder {
|
||||||
self.currentIsReversed = true
|
|
||||||
} else {
|
|
||||||
self.currentIsReversed = false
|
self.currentIsReversed = false
|
||||||
|
} else {
|
||||||
|
self.currentIsReversed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var openMessageImpl: ((MessageId) -> Bool)?
|
var openMessageImpl: ((MessageId) -> Bool)?
|
||||||
@ -125,8 +125,10 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec
|
|||||||
|
|
||||||
self.controlsNode.updateOrder = { [weak self] order in
|
self.controlsNode.updateOrder = { [weak self] order in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var reversed = false
|
let reversed: Bool
|
||||||
if case .reversed = order {
|
if case .regular = order {
|
||||||
|
reversed = false
|
||||||
|
} else {
|
||||||
reversed = true
|
reversed = true
|
||||||
}
|
}
|
||||||
if reversed != strongSelf.currentIsReversed {
|
if reversed != strongSelf.currentIsReversed {
|
||||||
|
|||||||
@ -177,9 +177,9 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.addSubnode(self.separatorNode)
|
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 {
|
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 {
|
} else {
|
||||||
return MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused)
|
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
|
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 {
|
if value.order != strongSelf.currentOrder {
|
||||||
strongSelf.updateOrder?(value.order)
|
strongSelf.updateOrder?(value.order)
|
||||||
strongSelf.currentOrder = value.order
|
strongSelf.currentOrder = value.order
|
||||||
switch value.order {
|
switch value.order {
|
||||||
case .regular:
|
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:
|
case .reversed:
|
||||||
strongSelf.orderButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/OrderReverse"), color: strongSelf.theme.list.itemAccentColor)
|
strongSelf.orderButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/OrderReverse"), color: strongSelf.theme.list.itemAccentColor)
|
||||||
case .random:
|
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 {
|
if value.looping != strongSelf.currentLooping {
|
||||||
@ -239,15 +246,9 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
|||||||
|
|
||||||
switch value.looping {
|
switch value.looping {
|
||||||
case .none:
|
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)
|
strongSelf.loopingButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Repeat"), color: baseColor)
|
||||||
case .item:
|
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:
|
case .all:
|
||||||
strongSelf.loopingButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Repeat"), color: strongSelf.theme.list.itemAccentColor)
|
strongSelf.loopingButton.icon = generateTintedImage(image: UIImage(bundleImageName: "GlobalMusicPlayer/Repeat"), color: strongSelf.theme.list.itemAccentColor)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class PeerMediaCollectionController: TelegramController {
|
|||||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||||
self.interfaceState = PeerMediaCollectionInterfaceState(theme: self.presentationData.theme, strings: self.presentationData.strings)
|
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
|
self.title = self.presentationData.strings.SharedMedia_TitleAll
|
||||||
|
|
||||||
@ -515,7 +515,7 @@ public class PeerMediaCollectionController: TelegramController {
|
|||||||
|
|
||||||
self.validLayout = layout
|
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)
|
self.mediaCollectionDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -191,7 +191,11 @@ class PeerMediaCollectionControllerNode: ASDisplayNode {
|
|||||||
self.candidateHistoryNodeReadyDisposable.dispose()
|
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)
|
self.containerLayout = (layout, navigationBarHeight)
|
||||||
|
|
||||||
var vanillaInsets = layout.insets(options: [])
|
var vanillaInsets = layout.insets(options: [])
|
||||||
@ -207,19 +211,19 @@ class PeerMediaCollectionControllerNode: ASDisplayNode {
|
|||||||
if let searchDisplayController = self.searchDisplayController {
|
if let searchDisplayController = self.searchDisplayController {
|
||||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||||
if !searchDisplayController.isDeactivating {
|
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)
|
let sectionsHeight = self.sectionsNode.updateLayout(width: layout.size.width, additionalInset: additionalInset, transition: transition, interfaceState: self.mediaCollectionInterfaceState)
|
||||||
var sectionOffset: CGFloat = 0.0
|
var sectionOffset: CGFloat = 0.0
|
||||||
if navigationBarHeight.isZero {
|
if primaryNavigationBarHeight.isZero {
|
||||||
sectionOffset = -sectionsHeight
|
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)))
|
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
|
var insets = vanillaInsets
|
||||||
if !navigationBarHeight.isZero {
|
if !primaryNavigationBarHeight.isZero {
|
||||||
insets.top += sectionsHeight
|
insets.top += sectionsHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,7 +62,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
self.segmentedControl.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
self.segmentedControl.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
||||||
self.segmentedControl.selectedSegmentIndex = 0
|
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()
|
super.init()
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private func updateThemeAndStrings() {
|
private func updateThemeAndStrings() {
|
||||||
self.searchDisplayController?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
|
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) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
|||||||
@ -34,8 +34,9 @@ public final class PresentationData: Equatable {
|
|||||||
public let dateTimeFormat: PresentationDateTimeFormat
|
public let dateTimeFormat: PresentationDateTimeFormat
|
||||||
public let nameDisplayOrder: PresentationPersonNameOrder
|
public let nameDisplayOrder: PresentationPersonNameOrder
|
||||||
public let nameSortOrder: 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.strings = strings
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.chatWallpaper = chatWallpaper
|
self.chatWallpaper = chatWallpaper
|
||||||
@ -43,10 +44,11 @@ public final class PresentationData: Equatable {
|
|||||||
self.dateTimeFormat = dateTimeFormat
|
self.dateTimeFormat = dateTimeFormat
|
||||||
self.nameDisplayOrder = nameDisplayOrder
|
self.nameDisplayOrder = nameDisplayOrder
|
||||||
self.nameSortOrder = nameSortOrder
|
self.nameSortOrder = nameSortOrder
|
||||||
|
self.disableAnimations = disableAnimations
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: PresentationData, rhs: PresentationData) -> Bool {
|
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 dateTimeFormat = currentDateTimeFormat()
|
||||||
let nameDisplayOrder = currentPersonNameDisplayOrder()
|
let nameDisplayOrder = currentPersonNameDisplayOrder()
|
||||||
let nameSortOrder = currentPersonNameSortOrder()
|
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> {
|
public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData, NoError> {
|
||||||
let preferencesKey = PostboxViewKey.preferences(keys: Set([ApplicationSpecificPreferencesKeys.presentationThemeSettings, PreferencesKeys.localizationSettings]))
|
let preferencesKey = PostboxViewKey.preferences(keys: Set([ApplicationSpecificPreferencesKeys.presentationThemeSettings, PreferencesKeys.localizationSettings]))
|
||||||
return postbox.combinedView(keys: [preferencesKey])
|
return combineLatest(postbox.combinedView(keys: [preferencesKey]), reduceMotionEnabled())
|
||||||
|> mapToSignal { view -> Signal<PresentationData, NoError> in
|
|> mapToSignal { view, disableAnimations -> Signal<PresentationData, NoError> in
|
||||||
let themeSettings: PresentationThemeSettings
|
let themeSettings: PresentationThemeSettings
|
||||||
if let current = (view.views[preferencesKey] as! PreferencesView).values[ApplicationSpecificPreferencesKeys.presentationThemeSettings] as? PresentationThemeSettings {
|
if let current = (view.views[preferencesKey] as! PreferencesView).values[ApplicationSpecificPreferencesKeys.presentationThemeSettings] as? PresentationThemeSettings {
|
||||||
themeSettings = current
|
themeSettings = current
|
||||||
@ -361,7 +363,7 @@ public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData
|
|||||||
effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme)
|
effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme)
|
||||||
switch themeSettings.automaticThemeSwitchSetting.theme {
|
switch themeSettings.automaticThemeSwitchSetting.theme {
|
||||||
case .nightAccent:
|
case .nightAccent:
|
||||||
effectiveChatWallpaper = .color(0x18222D)
|
effectiveChatWallpaper = .color(0x18222d)
|
||||||
case .nightGrayscale:
|
case .nightGrayscale:
|
||||||
effectiveChatWallpaper = .color(0x000000)
|
effectiveChatWallpaper = .color(0x000000)
|
||||||
default:
|
default:
|
||||||
@ -402,7 +404,7 @@ public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData
|
|||||||
let nameDisplayOrder = currentPersonNameDisplayOrder()
|
let nameDisplayOrder = currentPersonNameDisplayOrder()
|
||||||
let nameSortOrder = currentPersonNameSortOrder()
|
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 nameSortOrder = currentPersonNameSortOrder()
|
||||||
|
|
||||||
let themeSettings = PresentationThemeSettings.defaultSettings
|
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
@ -67,6 +67,7 @@ public final class PresentationThemeRootNavigationStatusBar {
|
|||||||
|
|
||||||
public final class PresentationThemeRootNavigationBar {
|
public final class PresentationThemeRootNavigationBar {
|
||||||
public let buttonColor: UIColor
|
public let buttonColor: UIColor
|
||||||
|
public let disabledButtonColor: UIColor
|
||||||
public let primaryTextColor: UIColor
|
public let primaryTextColor: UIColor
|
||||||
public let secondaryTextColor: UIColor
|
public let secondaryTextColor: UIColor
|
||||||
public let controlColor: UIColor
|
public let controlColor: UIColor
|
||||||
@ -77,8 +78,9 @@ public final class PresentationThemeRootNavigationBar {
|
|||||||
public let badgeStrokeColor: UIColor
|
public let badgeStrokeColor: UIColor
|
||||||
public let badgeTextColor: 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.buttonColor = buttonColor
|
||||||
|
self.disabledButtonColor = disabledButtonColor
|
||||||
self.primaryTextColor = primaryTextColor
|
self.primaryTextColor = primaryTextColor
|
||||||
self.secondaryTextColor = secondaryTextColor
|
self.secondaryTextColor = secondaryTextColor
|
||||||
self.controlColor = controlColor
|
self.controlColor = controlColor
|
||||||
|
|||||||
@ -145,6 +145,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
|||||||
public var themeAccentColor: Int32?
|
public var themeAccentColor: Int32?
|
||||||
public var fontSize: PresentationFontSize
|
public var fontSize: PresentationFontSize
|
||||||
public var automaticThemeSwitchSetting: AutomaticThemeSwitchSetting
|
public var automaticThemeSwitchSetting: AutomaticThemeSwitchSetting
|
||||||
|
public var disableAnimations: Bool
|
||||||
|
|
||||||
public var relatedResources: [MediaResourceId] {
|
public var relatedResources: [MediaResourceId] {
|
||||||
switch self.chatWallpaper {
|
switch self.chatWallpaper {
|
||||||
@ -156,15 +157,16 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static var defaultSettings: PresentationThemeSettings {
|
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.chatWallpaper = chatWallpaper
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.themeAccentColor = themeAccentColor
|
self.themeAccentColor = themeAccentColor
|
||||||
self.fontSize = fontSize
|
self.fontSize = fontSize
|
||||||
self.automaticThemeSwitchSetting = automaticThemeSwitchSetting
|
self.automaticThemeSwitchSetting = automaticThemeSwitchSetting
|
||||||
|
self.disableAnimations = disableAnimations
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
@ -173,6 +175,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
|||||||
self.themeAccentColor = decoder.decodeOptionalInt32ForKey("themeAccentColor")
|
self.themeAccentColor = decoder.decodeOptionalInt32ForKey("themeAccentColor")
|
||||||
self.fontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("f", orElse: PresentationFontSize.regular.rawValue)) ?? .regular
|
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.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) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
@ -185,6 +188,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
|||||||
}
|
}
|
||||||
encoder.encodeInt32(self.fontSize.rawValue, forKey: "f")
|
encoder.encodeInt32(self.fontSize.rawValue, forKey: "f")
|
||||||
encoder.encodeObject(self.automaticThemeSwitchSetting, forKey: "automaticThemeSwitchSetting")
|
encoder.encodeObject(self.automaticThemeSwitchSetting, forKey: "automaticThemeSwitchSetting")
|
||||||
|
encoder.encodeBool(self.disableAnimations, forKey: "disableAnimations")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isEqual(to: PreferencesEntry) -> Bool {
|
public func isEqual(to: PreferencesEntry) -> Bool {
|
||||||
@ -196,7 +200,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: PresentationThemeSettings, rhs: PresentationThemeSettings) -> Bool {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,9 +51,9 @@ private func screenRecordingActive() -> Signal<Bool, NoError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func screenCaptureEvents() -> Signal<ScreenCaptureEvent, 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
|
let observer = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationUserDidTakeScreenshot, object: nil, queue: .main, using: { _ in
|
||||||
susbcriber.putNext(.still)
|
subscriber.putNext(.still)
|
||||||
})
|
})
|
||||||
|
|
||||||
var previous = false
|
var previous = false
|
||||||
@ -61,7 +61,7 @@ func screenCaptureEvents() -> Signal<ScreenCaptureEvent, NoError> {
|
|||||||
if value != previous {
|
if value != previous {
|
||||||
previous = value
|
previous = value
|
||||||
if value {
|
if value {
|
||||||
susbcriber.putNext(.video)
|
subscriber.putNext(.video)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -152,7 +152,7 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
private let iconNode: ASImageNode
|
private let iconNode: ASImageNode
|
||||||
private let textField: SearchBarTextField
|
private let textField: SearchBarTextField
|
||||||
private let clearButton: HighlightableButtonNode
|
private let clearButton: HighlightableButtonNode
|
||||||
private let cancelButton: ASButtonNode
|
private let cancelButton: HighlightableButtonNode
|
||||||
|
|
||||||
var placeholderString: NSAttributedString? {
|
var placeholderString: NSAttributedString? {
|
||||||
get {
|
get {
|
||||||
@ -262,7 +262,7 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
self.textField.keyboardAppearance = .dark
|
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.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.setAttributedTitle(NSAttributedString(string: strings.Common_Cancel, font: Font.regular(17.0), textColor: theme.accent), for: [])
|
||||||
self.cancelButton.displaysAsynchronously = false
|
self.cancelButton.displaysAsynchronously = false
|
||||||
|
|||||||
@ -64,7 +64,7 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
|
|||||||
|
|
||||||
let buttonSize = self.button.measure(CGSize(width: width - 10.0, height: 100.0))
|
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)
|
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 {
|
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
return 45.0
|
return defaultHeight(metrics: metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,14 +99,12 @@ final class SecureIdAuthController: ViewController {
|
|||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
|
||||||
|
|
||||||
self.title = self.presentationData.strings.Passport_Title
|
self.title = self.presentationData.strings.Passport_Title
|
||||||
let leftButtonTitle: String
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .form:
|
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:
|
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.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationInfoIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.infoPressed))
|
||||||
|
|
||||||
self.challengeDisposable.set((twoStepAuthData(account.network)
|
self.challengeDisposable.set((twoStepAuthData(account.network)
|
||||||
|
|||||||
@ -2873,17 +2873,23 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
|
|||||||
|
|
||||||
if let frontSideDocument = innerState.frontSideDocument {
|
if let frontSideDocument = innerState.frontSideDocument {
|
||||||
entries.append(SecureIdDocumentGalleryEntry(index: Int32(index), resource: frontSideDocument.resource, location: SecureIdDocumentGalleryEntryLocation(position: Int32(index), totalCount: totalCount), error: ""))
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
if let backSideDocument = innerState.backSideDocument {
|
if let backSideDocument = innerState.backSideDocument {
|
||||||
entries.append(SecureIdDocumentGalleryEntry(index: Int32(index), resource: backSideDocument.resource, location: SecureIdDocumentGalleryEntryLocation(position: Int32(index), totalCount: totalCount), error: ""))
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
if let selfieDocument = innerState.selfieDocument {
|
if let selfieDocument = innerState.selfieDocument {
|
||||||
entries.append(SecureIdDocumentGalleryEntry(index: Int32(index), resource: selfieDocument.resource, location: SecureIdDocumentGalleryEntryLocation(position: Int32(index), totalCount: totalCount), error: ""))
|
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
|
index += 1
|
||||||
}
|
}
|
||||||
if let _ = innerState.documents.index(where: { $0.id == document.id }) {
|
if let _ = innerState.documents.index(where: { $0.id == document.id }) {
|
||||||
|
|||||||
@ -259,11 +259,8 @@ public final class ShareController: ViewController {
|
|||||||
for entry in view.0.entries.reversed() {
|
for entry in view.0.entries.reversed() {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .MessageEntry(_, _, _, _, _, renderedPeer, _):
|
case let .MessageEntry(_, _, _, _, _, renderedPeer, _):
|
||||||
if let peer = renderedPeer.chatMainPeer, peer.id != accountPeer.id {
|
if let peer = renderedPeer.chatMainPeer, peer.id != accountPeer.id, canSendMessagesToPeer(peer) {
|
||||||
if let user = peer as? TelegramUser, (user.firstName ?? "").isEmpty, (user.lastName ?? "").isEmpty {
|
peers.append(peer)
|
||||||
} else if canSendMessagesToPeer(peer) {
|
|
||||||
peers.append(peer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -4,6 +4,12 @@ import TelegramCore
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Postbox
|
import Postbox
|
||||||
|
|
||||||
|
enum MediaAccessoryPanelVisibility {
|
||||||
|
case none
|
||||||
|
case specific(size: ContainerViewLayoutSizeClass)
|
||||||
|
case always
|
||||||
|
}
|
||||||
|
|
||||||
enum LocationBroadcastPanelSource {
|
enum LocationBroadcastPanelSource {
|
||||||
case none
|
case none
|
||||||
case summary
|
case summary
|
||||||
@ -36,7 +42,7 @@ private func presentLiveLocationController(account: Account, peerId: PeerId, con
|
|||||||
public class TelegramController: ViewController {
|
public class TelegramController: ViewController {
|
||||||
private let account: Account
|
private let account: Account
|
||||||
|
|
||||||
let enableMediaAccessoryPanel: Bool
|
let mediaAccessoryPanelVisibility: MediaAccessoryPanelVisibility
|
||||||
let locationBroadcastPanelSource: LocationBroadcastPanelSource
|
let locationBroadcastPanelSource: LocationBroadcastPanelSource
|
||||||
|
|
||||||
private var mediaStatusDisposable: Disposable?
|
private var mediaStatusDisposable: Disposable?
|
||||||
@ -70,18 +76,22 @@ public class TelegramController: ViewController {
|
|||||||
return height
|
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.account = account
|
||||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||||
self.enableMediaAccessoryPanel = enableMediaAccessoryPanel
|
self.mediaAccessoryPanelVisibility = mediaAccessoryPanelVisibility
|
||||||
self.locationBroadcastPanelSource = locationBroadcastPanelSource
|
self.locationBroadcastPanelSource = locationBroadcastPanelSource
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: navigationBarPresentationData)
|
super.init(navigationBarPresentationData: navigationBarPresentationData)
|
||||||
|
|
||||||
if enableMediaAccessoryPanel {
|
if case .none = mediaAccessoryPanelVisibility {} else {
|
||||||
self.mediaStatusDisposable = (account.telegramApplicationContext.mediaManager.globalMediaPlayerState
|
self.mediaStatusDisposable = (account.telegramApplicationContext.mediaManager.globalMediaPlayerState
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] playlistStateAndType in
|
|> 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) ||
|
if !arePlaylistItemsEqual(strongSelf.playlistStateAndType?.0, playlistStateAndType?.0.item) ||
|
||||||
strongSelf.playlistStateAndType?.1 != playlistStateAndType?.0.order || strongSelf.playlistStateAndType?.2 != playlistStateAndType?.1 {
|
strongSelf.playlistStateAndType?.1 != playlistStateAndType?.0.order || strongSelf.playlistStateAndType?.2 != playlistStateAndType?.1 {
|
||||||
var previousVoiceItem: SharedMediaPlaylistItem?
|
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 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))
|
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 {
|
if let (mediaAccessoryPanel, mediaType) = self.mediaAccessoryPanel, mediaType == type {
|
||||||
|
|||||||
@ -14,8 +14,9 @@ public class TermsOfServiceControllerTheme {
|
|||||||
public let itemSeparator: UIColor
|
public let itemSeparator: UIColor
|
||||||
public let primary: UIColor
|
public let primary: UIColor
|
||||||
public let accent: 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.statusBarStyle = statusBarStyle
|
||||||
self.navigationBackground = navigationBackground
|
self.navigationBackground = navigationBackground
|
||||||
self.navigationSeparator = navigationSeparator
|
self.navigationSeparator = navigationSeparator
|
||||||
@ -24,16 +25,17 @@ public class TermsOfServiceControllerTheme {
|
|||||||
self.itemSeparator = itemSeparator
|
self.itemSeparator = itemSeparator
|
||||||
self.primary = primary
|
self.primary = primary
|
||||||
self.accent = accent
|
self.accent = accent
|
||||||
|
self.disabled = disabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension TermsOfServiceControllerTheme {
|
public extension TermsOfServiceControllerTheme {
|
||||||
convenience init(presentationTheme: PresentationTheme) {
|
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) {
|
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 {
|
var presentationTheme: PresentationTheme {
|
||||||
@ -93,7 +95,7 @@ public class TermsOfServiceController: ViewController {
|
|||||||
self.decline = decline
|
self.decline = decline
|
||||||
self.openUrl = openUrl
|
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
|
self.statusBar.statusBarStyle = self.theme.statusBarStyle
|
||||||
|
|
||||||
|
|||||||
@ -250,10 +250,10 @@ class ThemeGalleryController: ViewController {
|
|||||||
}
|
}
|
||||||
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
|
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
|
||||||
if case .color(0x000000) = wallpaper {
|
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: {
|
}) |> deliverOnMainQueue).start(completed: {
|
||||||
self?.dismiss(forceAway: true)
|
self?.dismiss(forceAway: true)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -99,10 +99,10 @@ final class ThemeGridController: ViewController {
|
|||||||
let wallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: image.size, resource: resource)])
|
let wallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: image.size, resource: resource)])
|
||||||
let _ = (updatePresentationThemeSettingsInteractively(postbox: self.account.postbox, { current in
|
let _ = (updatePresentationThemeSettingsInteractively(postbox: self.account.postbox, { current in
|
||||||
if case .color(0x000000) = wallpaper {
|
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
|
}) |> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
let _ = (self?.navigationController as? NavigationController)?.popViewController(animated: true)
|
let _ = (self?.navigationController as? NavigationController)?.popViewController(animated: true)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -149,7 +149,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
|||||||
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
|
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: [])
|
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 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)
|
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)
|
||||||
|
|||||||
@ -11,14 +11,16 @@ private final class ThemeSettingsControllerArguments {
|
|||||||
let openWallpaperSettings: () -> Void
|
let openWallpaperSettings: () -> Void
|
||||||
let openAccentColor: (Int32) -> Void
|
let openAccentColor: (Int32) -> Void
|
||||||
let openAutoNightTheme: () -> 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.account = account
|
||||||
self.selectTheme = selectTheme
|
self.selectTheme = selectTheme
|
||||||
self.selectFontSize = selectFontSize
|
self.selectFontSize = selectFontSize
|
||||||
self.openWallpaperSettings = openWallpaperSettings
|
self.openWallpaperSettings = openWallpaperSettings
|
||||||
self.openAccentColor = openAccentColor
|
self.openAccentColor = openAccentColor
|
||||||
self.openAutoNightTheme = openAutoNightTheme
|
self.openAutoNightTheme = openAutoNightTheme
|
||||||
|
self.disableAnimations = disableAnimations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,12 +38,14 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
case wallpaper(PresentationTheme, String)
|
case wallpaper(PresentationTheme, String)
|
||||||
case accentColor(PresentationTheme, String, Int32)
|
case accentColor(PresentationTheme, String, Int32)
|
||||||
case autoNightTheme(PresentationTheme, String, String)
|
case autoNightTheme(PresentationTheme, String, String)
|
||||||
|
case animationsItem(PresentationTheme, String, Bool)
|
||||||
|
case animationsInfo(PresentationTheme, String)
|
||||||
case themeListHeader(PresentationTheme, String)
|
case themeListHeader(PresentationTheme, String)
|
||||||
case themeItem(PresentationTheme, String, Bool, Int32)
|
case themeItem(PresentationTheme, String, Bool, Int32)
|
||||||
|
|
||||||
var section: ItemListSectionId {
|
var section: ItemListSectionId {
|
||||||
switch self {
|
switch self {
|
||||||
case .chatPreviewHeader, .chatPreview, .wallpaper, .accentColor, .autoNightTheme:
|
case .chatPreviewHeader, .chatPreview, .wallpaper, .accentColor, .autoNightTheme, .animationsItem, .animationsInfo:
|
||||||
return ThemeSettingsControllerSection.chatPreview.rawValue
|
return ThemeSettingsControllerSection.chatPreview.rawValue
|
||||||
case .themeListHeader, .themeItem:
|
case .themeListHeader, .themeItem:
|
||||||
return ThemeSettingsControllerSection.themeList.rawValue
|
return ThemeSettingsControllerSection.themeList.rawValue
|
||||||
@ -66,10 +70,14 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
return 5
|
return 5
|
||||||
case .autoNightTheme:
|
case .autoNightTheme:
|
||||||
return 6
|
return 6
|
||||||
case .themeListHeader:
|
case .animationsItem:
|
||||||
return 7
|
return 7
|
||||||
|
case .animationsInfo:
|
||||||
|
return 8
|
||||||
|
case .themeListHeader:
|
||||||
|
return 9
|
||||||
case let .themeItem(_, _, _, index):
|
case let .themeItem(_, _, _, index):
|
||||||
return 8 + index
|
return 10 + index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,18 +101,30 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .accentColor(lhsTheme, lhsText, lhsColor):
|
case let .accentColor(lhsTheme, lhsText, lhsColor):
|
||||||
if case let .accentColor(rhsTheme, rhsText, rhsColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsColor == rhsColor {
|
if case let .accentColor(rhsTheme, rhsText, rhsColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsColor == rhsColor {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .autoNightTheme(lhsTheme, lhsText, lhsValue):
|
case let .autoNightTheme(lhsTheme, lhsText, lhsValue):
|
||||||
if case let .autoNightTheme(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
if case let .autoNightTheme(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
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):
|
case let .themeListHeader(lhsTheme, lhsText):
|
||||||
if case let .themeListHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
if case let .themeListHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||||
return true
|
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: {
|
return ItemListDisclosureItem(theme: theme, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
arguments.openAutoNightTheme()
|
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):
|
case let .themeListHeader(theme, text):
|
||||||
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||||
case let .themeItem(theme, title, value, index):
|
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] = []
|
var entries: [ThemeSettingsControllerEntry] = []
|
||||||
|
|
||||||
entries.append(.fontSizeHeader(presentationData.theme, strings.Appearance_TextSize))
|
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))
|
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(.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_ThemeDayClassic, theme.name == .builtin(.dayClassic), 0))
|
||||||
entries.append(.themeItem(presentationData.theme, strings.Appearance_ThemeDay, theme.name == .builtin(.day), 1))
|
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)
|
wallpaper = .color(0x18222D)
|
||||||
theme = .builtin(.nightAccent)
|
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()
|
}).start()
|
||||||
}, selectFontSize: { size in
|
}, selectFontSize: { size in
|
||||||
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current 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()
|
}).start()
|
||||||
}, openWallpaperSettings: {
|
}, openWallpaperSettings: {
|
||||||
pushControllerImpl?(ThemeGridController(account: account))
|
pushControllerImpl?(ThemeGridController(account: account))
|
||||||
@ -235,11 +266,15 @@ public func themeSettingsController(account: Account) -> ViewController {
|
|||||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||||
presentControllerImpl?(ThemeAccentColorActionSheet(theme: presentationData.theme, strings: presentationData.strings, currentValue: color, applyValue: { color in
|
presentControllerImpl?(ThemeAccentColorActionSheet(theme: presentationData.theme, strings: presentationData.strings, currentValue: color, applyValue: { color in
|
||||||
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current 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()
|
}).start()
|
||||||
}))
|
}))
|
||||||
}, openAutoNightTheme: {
|
}, openAutoNightTheme: {
|
||||||
pushControllerImpl?(themeAutoNightSettingsController(account: account))
|
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
|
let themeSettingsKey = ApplicationSpecificPreferencesKeys.presentationThemeSettings
|
||||||
@ -256,6 +291,7 @@ public func themeSettingsController(account: Account) -> ViewController {
|
|||||||
let wallpaper: TelegramWallpaper
|
let wallpaper: TelegramWallpaper
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
let dateTimeFormat: PresentationDateTimeFormat
|
let dateTimeFormat: PresentationDateTimeFormat
|
||||||
|
let disableAnimations: Bool
|
||||||
|
|
||||||
let settings = (preferences.values[themeSettingsKey] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
let settings = (preferences.values[themeSettingsKey] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
||||||
switch settings.theme {
|
switch settings.theme {
|
||||||
@ -281,9 +317,10 @@ public func themeSettingsController(account: Account) -> ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dateTimeFormat = presentationData.dateTimeFormat
|
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 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 {
|
if previousTheme.swap(theme)?.name != theme.name {
|
||||||
presentControllerImpl?(ThemeSettingsCrossfadeController())
|
presentControllerImpl?(ThemeSettingsCrossfadeController())
|
||||||
|
|||||||
@ -33,7 +33,6 @@ final class WebEmbedVideoContent: UniversalVideoContent {
|
|||||||
private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
|
private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
|
||||||
private let webpageContent: TelegramMediaWebpageLoadedContent
|
private let webpageContent: TelegramMediaWebpageLoadedContent
|
||||||
private let intrinsicDimensions: CGSize
|
private let intrinsicDimensions: CGSize
|
||||||
private let approximateDuration: Int32
|
|
||||||
|
|
||||||
private let playbackCompletedListeners = Bag<() -> Void>()
|
private let playbackCompletedListeners = Bag<() -> Void>()
|
||||||
|
|
||||||
@ -55,11 +54,6 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
|
|||||||
return self._ready.get()
|
return self._ready.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
private let _preloadCompleted = ValuePromise<Bool>()
|
|
||||||
var preloadCompleted: Signal<Bool, NoError> {
|
|
||||||
return self._preloadCompleted.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
private let imageNode: TransformImageNode
|
private let imageNode: TransformImageNode
|
||||||
private let playerNode: WebEmbedPlayerNode
|
private let playerNode: WebEmbedPlayerNode
|
||||||
|
|
||||||
@ -67,7 +61,6 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
|
|||||||
|
|
||||||
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent) {
|
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent) {
|
||||||
self.webpageContent = webpageContent
|
self.webpageContent = webpageContent
|
||||||
self.approximateDuration = Int32(webpageContent.duration ?? 0)
|
|
||||||
|
|
||||||
if let embedSize = webpageContent.embedSize {
|
if let embedSize = webpageContent.embedSize {
|
||||||
self.intrinsicDimensions = embedSize
|
self.intrinsicDimensions = embedSize
|
||||||
@ -86,8 +79,6 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
|
|||||||
self.addSubnode(self.playerNode)
|
self.addSubnode(self.playerNode)
|
||||||
self.addSubnode(self.imageNode)
|
self.addSubnode(self.imageNode)
|
||||||
|
|
||||||
self._preloadCompleted.set(true)
|
|
||||||
|
|
||||||
if let image = webpageContent.image {
|
if let image = webpageContent.image {
|
||||||
self.imageNode.setSignal(chatMessagePhoto(postbox: postbox, photoReference: .webPage(webPage: WebpageReference(webPage), media: image)))
|
self.imageNode.setSignal(chatMessagePhoto(postbox: postbox, photoReference: .webPage(webPage: WebpageReference(webPage), media: image)))
|
||||||
self.imageNode.imageUpdated = { [weak self] in
|
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))
|
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
let makeImageLayout = self.imageNode.asyncLayout()
|
if let image = webpageContent.image, let representation = image.representationForDisplayAtSize(self.intrinsicDimensions) {
|
||||||
let applyImageLayout = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets()))
|
let makeImageLayout = self.imageNode.asyncLayout()
|
||||||
applyImageLayout()
|
let applyImageLayout = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: representation.dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
|
||||||
|
applyImageLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func play() {
|
func play() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user