Various UI fixes

This commit is contained in:
Ilya Laktyushin 2020-01-03 20:55:06 +03:00
parent 81c409e93e
commit b5b7128583
34 changed files with 3533 additions and 3289 deletions

View File

@ -5242,3 +5242,5 @@ Any member of this group will be able to see messages in the channel.";
"StickerPackActionInfo.RemovedText" = "%@ is no longer in your stickers.";
"Conversation.ContextMenuCancelEditing" = "Cancel Editing";
"Map.NoPlacesNearby" = "There are no known places nearby.\nTry a different location.";

View File

@ -304,6 +304,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
let statusFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0))
let dateFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0))
let avatarDiameter = min(40.0, floor(item.presentationData.fontSize.itemListBaseFontSize * 40.0 / 17.0))
let editingOffset: CGFloat
var editableControlSizeAndApply: (CGFloat, (CGFloat) -> ItemListEditableControlNode)?
@ -315,7 +316,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
editingOffset = 0.0
}
var leftInset: CGFloat = 86.0 + params.leftInset
var leftInset: CGFloat = 46.0 + avatarDiameter + params.leftInset
let rightInset: CGFloat = 13.0 + params.rightInset
var infoIconRightInset: CGFloat = rightInset - 1.0
@ -548,7 +549,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
})
}
transition.updateFrameAdditive(node: strongSelf.avatarNode, frame: CGRect(origin: CGPoint(x: revealOffset + leftInset - 52.0, y: floor((contentSize.height - 40.0) / 2.0)), size: CGSize(width: 40.0, height: 40.0)))
transition.updateFrameAdditive(node: strongSelf.avatarNode, frame: CGRect(origin: CGPoint(x: revealOffset + leftInset - 52.0, y: floor((contentSize.height - avatarDiameter) / 2.0)), size: CGSize(width: avatarDiameter, height: avatarDiameter)))
let _ = titleApply()
transition.updateFrameAdditive(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: revealOffset + leftInset, y: verticalInset), size: titleLayout.size))

View File

@ -107,6 +107,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
private let hideNetworkActivityStatus: Bool
public let groupId: PeerGroupId
public let previewing: Bool
let openMessageFromSearchDisposable: MetaDisposable = MetaDisposable()
@ -150,6 +151,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
self.hideNetworkActivityStatus = hideNetworkActivityStatus
self.groupId = groupId
self.previewing = previewing
self.presentationData = (context.sharedContext.currentPresentationData.with { $0 })
self.presentationDataValue.set(.single(self.presentationData))
@ -369,11 +371,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
}
})
if !previewing {
self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: self.presentationData.strings.DialogList_SearchLabel, activate: { [weak self] in
self?.activateSearch()
})
self.searchContentNode?.updateExpansionProgress(0.0)
self.navigationBar?.setContentNode(self.searchContentNode, animated: false)
}
if enableDebugActions {
self.tabBarItemDebugTapAction = {
@ -443,7 +447,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
}
override public func loadDisplayNode() {
self.displayNode = ChatListControllerNode(context: self.context, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, controller: self)
self.displayNode = ChatListControllerNode(context: self.context, groupId: self.groupId, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, controller: self)
self.chatListDisplayNode.navigationBar = self.navigationBar

View File

@ -72,12 +72,12 @@ final class ChatListControllerNode: ASDisplayNode {
let debugListView = ListView()
init(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, presentationData: PresentationData, controller: ChatListControllerImpl) {
init(context: AccountContext, groupId: PeerGroupId, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, controller: ChatListControllerImpl) {
self.context = context
self.groupId = groupId
self.presentationData = presentationData
self.chatListNode = ChatListNode(context: context, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
self.chatListNode = ChatListNode(context: context, groupId: groupId, previewing: previewing, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
self.controller = controller

View File

@ -1183,6 +1183,17 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
self.dimNode.backgroundColor = self.filter.contains(.excludeRecent) ? UIColor.black.withAlphaComponent(0.5) : theme.chatList.backgroundColor
self.recentListNode.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
self.listNode.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
self.listNode.forEachItemHeaderNode({ itemHeaderNode in
if let itemHeaderNode = itemHeaderNode as? ChatListSearchItemHeaderNode {
itemHeaderNode.updateTheme(theme: theme)
}
})
self.recentListNode.forEachItemHeaderNode({ itemHeaderNode in
if let itemHeaderNode = itemHeaderNode as? ChatListSearchItemHeaderNode {
itemHeaderNode.updateTheme(theme: theme)
}
})
}
private func updateState(_ f: (ChatListSearchContainerNodeState) -> ChatListSearchContainerNodeState) {

View File

@ -379,7 +379,7 @@ public final class ChatListNode: ListView {
private var hapticFeedback: HapticFeedback?
public init(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
public init(context: AccountContext, groupId: PeerGroupId, previewing: Bool, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
self.context = context
self.groupId = groupId
self.controlsHistoryPreload = controlsHistoryPreload
@ -708,7 +708,7 @@ public final class ChatListNode: ListView {
searchMode = true
}
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, peerGroupId: groupId, mode: mode, transition: $0) })
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
}
@ -1262,8 +1262,7 @@ public final class ChatListNode: ListView {
if view.laterIndex == nil {
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
} else {
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
, scrollPosition: .top(0.0), animated: true)
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound, scrollPosition: .top(0.0), animated: true)
self.setChatListLocation(location)
}
} else {

View File

@ -48,7 +48,7 @@ enum ChatListNodeViewScrollPosition {
case index(index: ChatListIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
}
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, disableAnimations: Bool, account: Account, scrollPosition: ChatListNodeViewScrollPosition?, searchMode: Bool) -> Signal<ChatListNodeViewTransition, NoError> {
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, previewing: Bool, disableAnimations: Bool, account: Account, scrollPosition: ChatListNodeViewScrollPosition?, searchMode: Bool) -> Signal<ChatListNodeViewTransition, NoError> {
return Signal { subscriber in
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
@ -174,7 +174,7 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV
fromEmptyView = true
}
if !searchMode && fromEmptyView && scrollToItem == nil && toView.filteredEntries.count >= 1 {
if !previewing && !searchMode && fromEmptyView && scrollToItem == nil && toView.filteredEntries.count >= 1 {
scrollToItem = ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up)
}

View File

@ -420,11 +420,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
} else {
let throttledSignal = videoNode.status
|> mapToThrottled { next -> Signal<MediaPlayerStatus?, NoError> in
return .single(next) |> then(.complete() |> delay(4.0, queue: Queue.concurrentDefaultQueue()))
return .single(next) |> then(.complete() |> delay(2.0, queue: Queue.concurrentDefaultQueue()))
}
self.mediaPlaybackStateDisposable.set(throttledSignal.start(next: { status in
if let status = status, status.duration > 60.0 * 20.0 {
if let status = status, status.duration >= 60.0 * 20.0 {
var timestamp: Double?
if status.timestamp > 5.0 && status.timestamp < status.duration - 5.0 {
timestamp = status.timestamp

View File

@ -258,6 +258,9 @@
if (![[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault alertDismissCompletion:nil])
return;
if ([_context currentlyInSplitView])
return;
if ([TGCameraController useLegacyCamera])
{
[self _displayLegacyCamera];

View File

@ -111,8 +111,12 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, editMediaO
carouselItemView = carouselItem
carouselItem.suggestionContext = legacySuggestionContext(context: context, peerId: peer.id)
carouselItem.recipientName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
carouselItem.cameraPressed = { [weak controller] cameraView in
carouselItem.cameraPressed = { [weak controller, weak parentController] cameraView in
if let controller = controller {
if let parentController = parentController, parentController.context.currentlyInSplitView() {
return
}
DeviceAccess.authorizeAccess(to: .camera, presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
if value {
openCamera(cameraView, controller)

View File

@ -22,6 +22,7 @@ private struct LocationPickerTransaction {
let insertions: [ListViewInsertItem]
let updates: [ListViewUpdateItem]
let isLoading: Bool
let isEmpty: Bool
let crossFade: Bool
}
@ -166,14 +167,14 @@ private enum LocationPickerEntry: Comparable, Identifiable {
}
}
private func preparedTransition(from fromEntries: [LocationPickerEntry], to toEntries: [LocationPickerEntry], isLoading: Bool, crossFade: Bool, account: Account, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> LocationPickerTransaction {
private func preparedTransition(from fromEntries: [LocationPickerEntry], to toEntries: [LocationPickerEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, account: Account, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> LocationPickerTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) }
return LocationPickerTransaction(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, crossFade: crossFade)
return LocationPickerTransaction(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade)
}
enum LocationPickerLocation: Equatable {
@ -246,6 +247,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
private let interaction: LocationPickerInteraction
private let listNode: ListView
private let emptyResultsTextNode: ImmediateTextNode
private let headerNode: LocationMapHeaderNode
private let activityIndicator: ActivityIndicator
private let shadeNode: ASDisplayNode
@ -281,6 +283,11 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
self.listNode.verticalScrollIndicatorColor = UIColor(white: 0.0, alpha: 0.3)
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
self.emptyResultsTextNode = ImmediateTextNode()
self.emptyResultsTextNode.maximumNumberOfLines = 0
self.emptyResultsTextNode.textAlignment = .center
self.emptyResultsTextNode.isHidden = true
self.headerNode = LocationMapHeaderNode(presentationData: presentationData, toggleMapModeSelection: interaction.toggleMapModeSelection, goToUserLocation: interaction.goToUserLocation, showPlacesInThisArea: interaction.showPlacesInThisArea)
self.headerNode.mapNode.isRotateEnabled = false
@ -302,6 +309,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
self.addSubnode(self.headerNode)
self.addSubnode(self.optionsNode)
self.listNode.addSubnode(self.activityIndicator)
self.listNode.addSubnode(self.emptyResultsTextNode)
self.shadeNode.addSubnode(self.innerShadeNode)
self.addSubnode(self.shadeNode)
@ -506,7 +514,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
crossFade = true
}
let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: displayedVenues == nil, crossFade: crossFade, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction)
let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: displayedVenues == nil, isEmpty: displayedVenues?.isEmpty ?? false, crossFade: crossFade, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction)
strongSelf.enqueueTransition(transition)
var displayingPlacesButton = false
@ -725,6 +733,11 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.activityIndicator.isHidden = !transition.isLoading
strongSelf.emptyResultsTextNode.isHidden = transition.isLoading || !transition.isEmpty
strongSelf.emptyResultsTextNode.attributedText = NSAttributedString(string: strongSelf.presentationData.strings.Map_NoPlacesNearby, font: Font.regular(15.0), textColor: strongSelf.presentationData.theme.list.freeTextColor)
strongSelf.layoutActivityIndicator(transition: .immediate)
}
})
}
@ -779,6 +792,10 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
let indicatorSize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0))
let actionsInset: CGFloat = 148.0
transition.updateFrame(node: self.activityIndicator, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - indicatorSize.width) / 2.0), y: headerHeight + actionsInset + floor((layout.size.height - headerHeight - actionsInset - indicatorSize.height - layout.intrinsicInsets.bottom) / 2.0)), size: indicatorSize))
let padding: CGFloat = 16.0
let emptyTextSize = self.emptyResultsTextNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - padding * 2.0, height: CGFloat.greatestFiniteMagnitude))
transition.updateFrame(node: self.emptyResultsTextNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - emptyTextSize.width) / 2.0), y: headerHeight + actionsInset + floor((layout.size.height - headerHeight - actionsInset - emptyTextSize.height - layout.intrinsicInsets.bottom) / 2.0)), size: emptyTextSize))
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {

View File

@ -68,6 +68,9 @@ private final class MediaPlayerTimeTextNodeParameters: NSObject {
public final class MediaPlayerTimeTextNode: ASDisplayNode {
public var alignment: NSTextAlignment = .left
public var mode: MediaPlayerTimeTextNodeMode = .normal
public var keepPreviousValueOnEmptyState = false
public var textColor: UIColor {
didSet {
self.updateTimestamp()
@ -151,6 +154,10 @@ public final class MediaPlayerTimeTextNode: ASDisplayNode {
}
func updateTimestamp() {
if ((self.statusValue?.duration ?? 0.0) < 0.1) && self.state.seconds != nil && self.keepPreviousValueOnEmptyState {
return
}
if let statusValue = self.statusValue, Double(0.0).isLess(than: statusValue.duration) {
let timestampSeconds: Double
if !statusValue.generationTimestamp.isZero {

View File

@ -353,7 +353,7 @@ private func stringForSelectiveSettings(strings: PresentationStrings, settings:
}
}
private func privacyAndSecurityControllerEntries(presentationData: PresentationData, state: PrivacyAndSecurityControllerState, privacySettings: AccountPrivacySettings?, accessChallengeData: PostboxAccessChallengeData, blockedPeerCount: Int?, activeWebsitesCount: Int, twoStepAuthData: TwoStepVerificationAccessConfiguration?) -> [PrivacyAndSecurityEntry] {
private func privacyAndSecurityControllerEntries(presentationData: PresentationData, state: PrivacyAndSecurityControllerState, privacySettings: AccountPrivacySettings?, accessChallengeData: PostboxAccessChallengeData, blockedPeerCount: Int?, activeWebsitesCount: Int, hasTwoStepAuth: Bool?, twoStepAuthData: TwoStepVerificationAccessConfiguration?) -> [PrivacyAndSecurityEntry] {
var entries: [PrivacyAndSecurityEntry] = []
entries.append(.blockedPeers(presentationData.theme, presentationData.strings.Settings_BlockedUsers, blockedPeerCount == nil ? "" : (blockedPeerCount == 0 ? presentationData.strings.PrivacySettings_BlockedPeersEmpty : "\(blockedPeerCount!)")))
@ -380,13 +380,8 @@ private func privacyAndSecurityControllerEntries(presentationData: PresentationD
entries.append(.passcode(presentationData.theme, presentationData.strings.PrivacySettings_Passcode, false, passcodeValue))
}
var twoStepAuthString = ""
if let twoStepAuthData = twoStepAuthData {
switch twoStepAuthData {
case .set:
twoStepAuthString = presentationData.strings.PrivacySettings_PasscodeOn
case .notSet:
twoStepAuthString = presentationData.strings.PrivacySettings_PasscodeOff
}
if let hasTwoStepAuth = hasTwoStepAuth {
twoStepAuthString = hasTwoStepAuth ? presentationData.strings.PrivacySettings_PasscodeOn : presentationData.strings.PrivacySettings_PasscodeOff
}
entries.append(.twoStepVerification(presentationData.theme, presentationData.strings.PrivacySettings_TwoStepAuth, twoStepAuthString, twoStepAuthData))
@ -429,7 +424,7 @@ private func privacyAndSecurityControllerEntries(presentationData: PresentationD
return entries
}
public func privacyAndSecurityController(context: AccountContext, initialSettings: AccountPrivacySettings? = nil, updatedSettings: ((AccountPrivacySettings?) -> Void)? = nil, focusOnItemTag: PrivacyAndSecurityEntryTag? = nil, activeSessionsContext: ActiveSessionsContext? = nil, webSessionsContext: WebSessionsContext? = nil, blockedPeersContext: BlockedPeersContext? = nil) -> ViewController {
public func privacyAndSecurityController(context: AccountContext, initialSettings: AccountPrivacySettings? = nil, updatedSettings: ((AccountPrivacySettings?) -> Void)? = nil, updatedBlockedPeers: ((BlockedPeersContext?) -> Void)? = nil, updatedHasTwoStepAuth: ((Bool) -> Void)? = nil, focusOnItemTag: PrivacyAndSecurityEntryTag? = nil, activeSessionsContext: ActiveSessionsContext? = nil, webSessionsContext: WebSessionsContext? = nil, blockedPeersContext: BlockedPeersContext? = nil, hasTwoStepAuth: Bool? = nil) -> ViewController {
let statePromise = ValuePromise(PrivacyAndSecurityControllerState(), ignoreRepeated: true)
let stateValue = Atomic(value: PrivacyAndSecurityControllerState())
let updateState: ((PrivacyAndSecurityControllerState) -> PrivacyAndSecurityControllerState) -> Void = { f in
@ -455,12 +450,35 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
let activeSessionsContext = activeSessionsContext ?? ActiveSessionsContext(account: context.account)
let webSessionsContext = webSessionsContext ?? WebSessionsContext(account: context.account)
let blockedPeersState = Promise<BlockedPeersContextState>()
blockedPeersState.set(blockedPeersContext.state)
webSessionsContext.loadMore()
let updateTwoStepAuthDisposable = MetaDisposable()
actionsDisposable.add(updateTwoStepAuthDisposable)
let twoStepAuthDataValue = Promise<TwoStepVerificationAccessConfiguration?>(nil)
let hasTwoStepAuthDataValue = twoStepAuthDataValue.get()
|> map { data -> Bool? in
if let data = data {
if case .set = data {
return true
} else {
return false
}
} else {
return nil
}
}
let twoStepAuth = Promise<Bool?>()
if let hasTwoStepAuth = hasTwoStepAuth {
twoStepAuth.set(.single(hasTwoStepAuth) |> then(hasTwoStepAuthDataValue))
} else {
twoStepAuth.set(hasTwoStepAuthDataValue)
}
let updateHasTwoStepAuth: () -> Void = {
let signal = twoStepVerificationConfiguration(account: context.account)
|> map { value -> TwoStepVerificationAccessConfiguration? in
@ -744,8 +762,13 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
updatedSettings?(settings)
}))
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), privacySettingsPromise.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.secretChatLinkPreviewsKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]), recentPeers(account: context.account), blockedPeersContext.state, webSessionsContext.state, context.sharedContext.accountManager.accessChallengeData(), twoStepAuthDataValue.get())
|> map { presentationData, state, privacySettings, noticeView, sharedData, recentPeers, blockedPeersState, activeWebsitesState, accessChallengeData, twoStepAuthData -> (ItemListControllerState, (ItemListNodeState, Any)) in
actionsDisposable.add((blockedPeersState.get()
|> deliverOnMainQueue).start(next: { _ in
updatedBlockedPeers?(blockedPeersContext)
}))
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), privacySettingsPromise.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.secretChatLinkPreviewsKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]), recentPeers(account: context.account), blockedPeersState.get(), webSessionsContext.state, context.sharedContext.accountManager.accessChallengeData(), combineLatest(twoStepAuth.get(), twoStepAuthDataValue.get()))
|> map { presentationData, state, privacySettings, noticeView, sharedData, recentPeers, blockedPeersState, activeWebsitesState, accessChallengeData, twoStepAuth -> (ItemListControllerState, (ItemListNodeState, Any)) in
var rightNavigationButton: ItemListNavigationButton?
if privacySettings == nil || state.updatingAccountTimeoutValue != nil {
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
@ -753,7 +776,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.PrivacySettings_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: privacyAndSecurityControllerEntries(presentationData: presentationData, state: state, privacySettings: privacySettings, accessChallengeData: accessChallengeData.data, blockedPeerCount: blockedPeersState.totalCount, activeWebsitesCount: activeWebsitesState.sessions.count, twoStepAuthData: twoStepAuthData), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: privacyAndSecurityControllerEntries(presentationData: presentationData, state: state, privacySettings: privacySettings, accessChallengeData: accessChallengeData.data, blockedPeerCount: blockedPeersState.totalCount, activeWebsitesCount: activeWebsitesState.sessions.count, hasTwoStepAuth: twoStepAuth.0, twoStepAuthData: twoStepAuth.1), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
return (controllerState, (listState, arguments))
}

View File

@ -875,6 +875,9 @@ public func settingsController(context: AccountContext, accountManager: AccountM
let activeSessionsContextAndCount = Promise<(ActiveSessionsContext, Int, WebSessionsContext)>()
activeSessionsContextAndCount.set(activeSessionsContextAndCountSignal)
let blockedPeers = Promise<BlockedPeersContext?>(nil)
let hasTwoStepAuthPromise = Promise<Bool?>(nil)
let arguments = SettingsItemArguments(sharedContext: context.sharedContext, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
var updating = false
updateState {
@ -932,12 +935,17 @@ public func settingsController(context: AccountContext, accountManager: AccountM
let _ = (contextValue.get()
|> deliverOnMainQueue
|> take(1)).start(next: { context in
let _ = (activeSessionsContextAndCount.get()
let _ = (combineLatest(activeSessionsContextAndCount.get(), blockedPeers.get(), hasTwoStepAuthPromise.get())
|> deliverOnMainQueue
|> take(1)).start(next: { activeSessionsContext, _, webSessionsContext in
|> take(1)).start(next: { sessions, blockedPeersContext, hasTwoStepAuth in
let (activeSessionsContext, _, webSessionsContext) = sessions
pushControllerImpl?(privacyAndSecurityController(context: context, initialSettings: privacySettingsValue, updatedSettings: { settings in
privacySettings.set(.single(settings))
}, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext))
}, updatedBlockedPeers: { blockedPeersContext in
blockedPeers.set(.single(blockedPeersContext))
}, updatedHasTwoStepAuth: { hasTwoStepAuthValue in
hasTwoStepAuthPromise.set(.single(hasTwoStepAuthValue))
}, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, blockedPeersContext: blockedPeersContext))
})
})
}, openDataAndStorage: {

View File

@ -260,10 +260,6 @@ final class ThemeAccentColorController: ViewController {
if case let .result(resultTheme) = next {
let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start()
return updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
// if let resource = resultTheme.file?.resource, let data = themeData {
// context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
// }
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: wallpaper))
var updatedTheme = current.theme
@ -293,10 +289,6 @@ final class ThemeAccentColorController: ViewController {
if case let .result(resultTheme) = next {
let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start()
return updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
// if let resource = resultTheme.file?.resource, let data = themeData {
// context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
// }
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: wallpaper))
var updatedTheme = current.theme

View File

@ -12,7 +12,7 @@ var dayClassicColorPresets: [PresentationThemeAccentColor] = [
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0xffff5fa9, bubbleColors: (0xfffff4d7, nil), wallpaper: patternWallpaper(slug: "51nnTjx8mFIBAAAAaFGJsMIvWkk", topColor: 0xfff6b594, bottomColor: 0xffebf6cd, intensity: 46, rotation: 45)),
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xff5a9e29, bubbleColors: (0xfffff8df, 0xffdcf8c6), wallpaper: patternWallpaper(slug: "R3j69wKskFIBAAAAoUdXWCKMzCM", topColor: 0xffede6dd, bottomColor: 0xffffd59e, intensity: 50, rotation: nil)),
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0xff7e5fe5, bubbleColors: (0xfff5e2ff, nil), wallpaper: patternWallpaper(slug: "nQcFYJe1mFIBAAAAcI95wtIK0fk", topColor: 0xfffcccf4, bottomColor: 0xffae85f0, intensity: 54, rotation: nil)),
PresentationThemeAccentColor(index: 107, baseColor: .preset, accentColor: 0xff2cb9ed, bubbleColors: (0xffadf7b5, 0xfffcff8b), wallpaper: patternWallpaper(slug: "nQcFYJe1mFIBAAAAcI95wtIK0fk", topColor: 0xff1a2d1a, bottomColor: 0xff5f6f54, intensity: 50, rotation: 225)),
PresentationThemeAccentColor(index: 107, baseColor: .preset, accentColor: 0xff2cb9ed, bubbleColors: (0xffadf7b5, 0xfffcff8b), wallpaper: patternWallpaper(slug: "CJNyxPMgSVAEAAAAvW9sMwc51cw", topColor: 0xff1a2d1a, bottomColor: 0xff5f6f54, intensity: 50, rotation: 225)),
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xff199972, bubbleColors: (0xfffffec7, nil), wallpaper: patternWallpaper(slug: "fqv01SQemVIBAAAApND8LDRUhRU", topColor: 0xffc1e7cb, bottomColor: nil, intensity: 50, rotation: nil)),
PresentationThemeAccentColor(index: 105, baseColor: .preset, accentColor: 0x0ff09eee, bubbleColors: (0xff94fff9, 0xffccffc7), wallpaper: patternWallpaper(slug: "p-pXcflrmFIBAAAAvXYQk-mCwZU", topColor: 0xffffbca6, bottomColor: 0xffff63bd, intensity: 57, rotation: 225))
]

View File

@ -19,15 +19,15 @@ private enum ThemeSettingsColorEntryId: Hashable {
}
private enum ThemeSettingsColorEntry: Comparable, Identifiable {
case color(Int, PresentationThemeReference, PresentationThemeAccentColor?, Bool)
case theme(Int, PresentationThemeReference, PresentationThemeReference, Bool)
case color(Int, PresentationTheme, PresentationThemeReference, PresentationThemeAccentColor?, Bool)
case theme(Int, PresentationTheme, PresentationThemeReference, PresentationThemeReference, Bool)
case picker
var stableId: ThemeSettingsColorEntryId {
switch self {
case let .color(index, themeReference, accentColor, _):
case let .color(index, _, themeReference, accentColor, _):
return .color(themeReference.index &+ Int64(accentColor?.index ?? 0))
case let .theme(_, _, theme, _):
case let .theme(_, _, _, theme, _):
return .theme(theme.index)
case .picker:
return .picker
@ -36,14 +36,14 @@ private enum ThemeSettingsColorEntry: Comparable, Identifiable {
static func ==(lhs: ThemeSettingsColorEntry, rhs: ThemeSettingsColorEntry) -> Bool {
switch lhs {
case let .color(lhsIndex, lhsThemeReference, lhsAccentColor, lhsSelected):
if case let .color(rhsIndex, rhsThemeReference, rhsAccentColor, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsThemeReference.index == rhsThemeReference.index, lhsAccentColor == rhsAccentColor, lhsSelected == rhsSelected {
case let .color(lhsIndex, lhsCurrentTheme, lhsThemeReference, lhsAccentColor, lhsSelected):
if case let .color(rhsIndex, rhsCurrentTheme, rhsThemeReference, rhsAccentColor, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsCurrentTheme === rhsCurrentTheme, lhsThemeReference.index == rhsThemeReference.index, lhsAccentColor == rhsAccentColor, lhsSelected == rhsSelected {
return true
} else {
return false
}
case let .theme(lhsIndex, lhsBaseThemeReference, lhsTheme, lhsSelected):
if case let .theme(rhsIndex, rhsBaseThemeReference, rhsTheme, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsBaseThemeReference.index == rhsBaseThemeReference.index, lhsTheme == rhsTheme, lhsSelected == rhsSelected {
case let .theme(lhsIndex, lhsCurrentTheme, lhsBaseThemeReference, lhsTheme, lhsSelected):
if case let .theme(rhsIndex, rhsCurrentTheme, rhsBaseThemeReference, rhsTheme, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsCurrentTheme === rhsCurrentTheme, lhsBaseThemeReference.index == rhsBaseThemeReference.index, lhsTheme == rhsTheme, lhsSelected == rhsSelected {
return true
} else {
return false
@ -61,11 +61,11 @@ private enum ThemeSettingsColorEntry: Comparable, Identifiable {
switch lhs {
case .picker:
return true
case let .color(lhsIndex, _, _, _), let .theme(lhsIndex, _, _, _):
case let .color(lhsIndex, _, _, _, _), let .theme(lhsIndex, _, _, _, _):
switch rhs {
case let .color(rhsIndex, _, _, _):
case let .color(rhsIndex, _, _, _, _):
return lhsIndex < rhsIndex
case let .theme(rhsIndex, _, _, _):
case let .theme(rhsIndex, _, _, _, _):
return lhsIndex < rhsIndex
case .picker:
return false
@ -75,10 +75,10 @@ private enum ThemeSettingsColorEntry: Comparable, Identifiable {
func item(action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?, openColorPicker: @escaping (Bool) -> Void) -> ListViewItem {
switch self {
case let .color(_, themeReference, accentColor, selected):
return ThemeSettingsAccentColorIconItem(themeReference: themeReference, color: accentColor.flatMap { .accentColor($0) }, selected: selected, action: action, contextAction: contextAction)
case let .theme(_, baseThemeReference, theme, selected):
return ThemeSettingsAccentColorIconItem(themeReference: baseThemeReference, color: .theme(theme), selected: selected, action: action, contextAction: contextAction)
case let .color(_, currentTheme, themeReference, accentColor, selected):
return ThemeSettingsAccentColorIconItem(themeReference: themeReference, theme: currentTheme, color: accentColor.flatMap { .accentColor($0) }, selected: selected, action: action, contextAction: contextAction)
case let .theme(_, currentTheme, baseThemeReference, theme, selected):
return ThemeSettingsAccentColorIconItem(themeReference: baseThemeReference, theme: currentTheme, color: .theme(theme), selected: selected, action: action, contextAction: contextAction)
case .picker:
return ThemeSettingsAccentColorPickerItem(action: openColorPicker)
}
@ -165,13 +165,15 @@ enum ThemeSettingsColorOption: Equatable {
private class ThemeSettingsAccentColorIconItem: ListViewItem {
let themeReference: PresentationThemeReference
let theme: PresentationTheme
let color: ThemeSettingsColorOption?
let selected: Bool
let action: (ThemeSettingsColorOption?, Bool) -> Void
let contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?
public init(themeReference: PresentationThemeReference, color: ThemeSettingsColorOption?, selected: Bool, action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?) {
public init(themeReference: PresentationThemeReference, theme: PresentationTheme, color: ThemeSettingsColorOption?, selected: Bool, action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?) {
self.themeReference = themeReference
self.theme = theme
self.color = color
self.selected = selected
self.action = action
@ -369,13 +371,13 @@ private final class ThemeSettingsAccentColorIconItemNode : ListViewItemNode {
strokeColor = fillColor
}
// if strokeColor.distance(to: theme.list.itemBlocksBackgroundColor) < 200 {
// if strokeColor.distance(to: UIColor.white) < 200 {
// strokeColor = UIColor(rgb: 0x999999)
// } else {
// strokeColor = theme.list.controlSecondaryColor
// }
// }
if let color = strokeColor, color.distance(to: item.theme.list.itemBlocksBackgroundColor) < 200 {
if color.distance(to: UIColor.white) < 200 {
strokeColor = UIColor(rgb: 0x999999)
} else {
strokeColor = item.theme.list.controlSecondaryColor
}
}
var topColor: UIColor?
var bottomColor: UIColor?
@ -874,7 +876,7 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
switch color {
case .default:
let selected = item.currentColor == nil
entries.append(.color(index, item.generalThemeReference, nil, selected))
entries.append(.color(index, item.theme, item.generalThemeReference, nil, selected))
case let .color(color):
var selected = false
if let currentColor = item.currentColor, case let .accentColor(accentColor) = currentColor {
@ -888,22 +890,22 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
}
switch accentColor {
case let .accentColor(color):
entries.append(.color(index, item.generalThemeReference, color, selected))
entries.append(.color(index, item.theme, item.generalThemeReference, color, selected))
case let .theme(theme):
entries.append(.theme(index, item.generalThemeReference, theme, selected))
entries.append(.theme(index, item.theme, item.generalThemeReference, theme, selected))
}
case let .preset(color), let .custom(color):
var selected = false
if let currentColor = item.currentColor {
selected = currentColor.index == Int64(color.index)
}
entries.append(.color(index, item.themeReference, color, selected))
entries.append(.color(index, item.theme, item.themeReference, color, selected))
case let .theme(theme):
var selected = false
if let currentColor = item.currentColor {
selected = currentColor.index == theme.index
}
entries.append(.theme(index, item.generalThemeReference, theme, selected))
entries.append(.theme(index, item.theme, item.generalThemeReference, theme, selected))
}
index += 1
}

View File

@ -143,7 +143,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in
var updatedBackgroundSignal: Signal<(UIImage?, Bool)?, NoError>?
if currentItem?.wallpaper != item.wallpaper {
updatedBackgroundSignal = chatControllerBackgroundImageSignal(wallpaper: item.wallpaper, mediaBox: item.context.account.postbox.mediaBox)
updatedBackgroundSignal = chatControllerBackgroundImageSignal(wallpaper: item.wallpaper, mediaBox: item.context.sharedContext.accountManager.mediaBox)
}
let insets: UIEdgeInsets

View File

@ -1208,9 +1208,14 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
let _ = (context.account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: false, fetch: true)
|> filter({ $0.complete })).start(next: { data in
if data.complete, let path = context.account.postbox.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
if data.complete, let path = context.account.postbox.mediaBox.completedResourcePath(resource) {
if let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: maybeData, synchronous: true)
}
if let maybeData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: .mappedRead) {
context.sharedContext.accountManager.mediaBox.storeCachedResourceRepresentation(resource, representation: representation, data: maybeData)
}
}
})
return .single(wallpaper)
@ -1263,12 +1268,6 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
} else {
themeSpecificChatWallpapers[index] = presetWallpaper
}
// if let wallpaper = current.themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: accentColor)], wallpaper.isColorOrGradient || wallpaper.isPattern || wallpaper.isBuiltin {
// themeSpecificChatWallpapers[currentTheme.index] = nil
// if let accentColor = accentColor {
// themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: accentColor)] = nil
// }
// }
}
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)

View File

@ -637,7 +637,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
@objc private func togglePattern() {
let value = !self.patternButtonNode.isSelected
self.patternButtonNode.setSelected(value, animated: true)
self.patternButtonNode.setSelected(value, animated: false)
self.requestPatternPanel?(value)
}

View File

@ -8,10 +8,166 @@ import SyncCore
import TelegramPresentationData
import LegacyComponents
import AccountContext
import MergeLists
private let itemSize = CGSize(width: 88.0, height: 88.0)
private let inset: CGFloat = 12.0
private struct WallpaperPatternEntry: Comparable, Identifiable {
let index: Int
let wallpaper: TelegramWallpaper
let selected: Bool
var stableId: Int64 {
if case let .file(file) = self.wallpaper {
return file.id
} else {
return Int64(self.index)
}
}
static func ==(lhs: WallpaperPatternEntry, rhs: WallpaperPatternEntry) -> Bool {
if lhs.index != rhs.index {
return false
}
if lhs.wallpaper != rhs.wallpaper {
return false
}
return true
}
static func <(lhs: WallpaperPatternEntry, rhs: WallpaperPatternEntry) -> Bool {
return lhs.index < rhs.index
}
func item(context: AccountContext, action: @escaping (TelegramWallpaper) -> Void) -> ListViewItem {
return WallpaperPatternItem(context: context, wallpaper: self.wallpaper, selected: self.selected, action: action)
}
}
private class WallpaperPatternItem: ListViewItem {
let context: AccountContext
let wallpaper: TelegramWallpaper
let selected: Bool
let action: (TelegramWallpaper) -> Void
public init(context: AccountContext, wallpaper: TelegramWallpaper, selected: Bool, action: @escaping (TelegramWallpaper) -> Void) {
self.context = context
self.wallpaper = wallpaper
self.selected = selected
self.action = action
}
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
async {
let node = WallpaperPatternItemNode()
let (nodeLayout, apply) = node.asyncLayout()(self, params)
node.insets = nodeLayout.insets
node.contentSize = nodeLayout.contentSize
Queue.mainQueue().async {
completion(node, {
return (nil, { _ in
apply(false)
})
})
}
}
}
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
Queue.mainQueue().async {
assert(node() is WallpaperPatternItemNode)
if let nodeValue = node() as? WallpaperPatternItemNode {
let layout = nodeValue.asyncLayout()
async {
let (nodeLayout, apply) = layout(self, params)
Queue.mainQueue().async {
completion(nodeLayout, { _ in
apply(animation.isAnimated)
})
}
}
}
}
}
public var selectable = true
public func selected(listView: ListView) {
self.action(self.wallpaper)
}
}
private final class WallpaperPatternItemNode : ListViewItemNode {
private let wallpaperNode: SettingsThemeWallpaperNode
var item: WallpaperPatternItem?
init() {
self.wallpaperNode = SettingsThemeWallpaperNode()
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
self.addSubnode(self.wallpaperNode)
}
override func didLoad() {
super.didLoad()
self.layer.sublayerTransform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
}
func asyncLayout() -> (WallpaperPatternItem, ListViewItemLayoutParams) -> (ListViewItemNodeLayout, (Bool) -> Void) {
let currentItem = self.item
return { [weak self] item, params in
var updatedWallpaper = false
var updatedSelected = false
if currentItem?.wallpaper != item.wallpaper {
updatedWallpaper = true
}
if currentItem?.selected != item.selected {
updatedSelected = true
}
let itemLayout = ListViewItemNodeLayout(contentSize: CGSize(width: 112.0, height: 112.0), insets: UIEdgeInsets())
return (itemLayout, { animated in
if let strongSelf = self {
strongSelf.item = item
strongSelf.wallpaperNode.frame = CGRect(x: 0.0, y: 12.0, width: itemSize.width, height: itemSize.height)
}
})
}
}
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
super.animateInsertion(currentTimestamp, duration: duration, short: short)
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
super.animateRemoved(currentTimestamp, duration: duration)
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
override func animateAdded(_ currentTimestamp: Double, duration: Double) {
super.animateAdded(currentTimestamp, duration: duration)
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
}
final class WallpaperPatternPanelNode: ASDisplayNode {
private let context: AccountContext
private var theme: PresentationTheme

View File

@ -152,16 +152,18 @@ public func customizeDefaultDayTheme(theme: PresentationTheme, editing: Bool, ti
outgoingSelectionBaseColor = outgoingControlColor
outgoingCheckColor = outgoingAccent
} else {
outgoingAccentTextColor = outgoingBubbleFillColor?.withMultiplied(hue: 1.302 * hueFactor, saturation: 4.554 * saturationFactor, brightness: 0.655)
let outgoingBubbleMixedColor = lightnessColor
outgoingAccentTextColor = outgoingBubbleMixedColor.withMultiplied(hue: 1.302 * hueFactor, saturation: 4.554 * saturationFactor, brightness: 0.655)
outgoingLinkTextColor = UIColor(rgb: 0x004bad)
outgoingScamColor = UIColor(rgb: 0xff3b30)
outgoingControlColor = outgoingBubbleFillColor?.withMultiplied(hue: 1.283 * hueFactor, saturation: 3.176, brightness: 0.765)
outgoingInactiveControlColor = outgoingBubbleFillColor?.withMultiplied(hue: 1.207 * hueFactor, saturation: 1.721, brightness: 0.851)
outgoingFileTitleColor = outgoingBubbleFillColor?.withMultiplied(hue: 1.285 * hueFactor, saturation: 2.946, brightness: 0.667)
outgoingPollsProgressColor = outgoingBubbleFillColor?.withMultiplied(hue: 1.283 * hueFactor, saturation: 3.176, brightness: 0.765)
outgoingSelectionColor = outgoingBubbleFillColor?.withMultiplied(hue: 1.013 * hueFactor, saturation: 1.292, brightness: 0.871)
outgoingControlColor = outgoingBubbleMixedColor.withMultiplied(hue: 1.283 * hueFactor, saturation: 3.176, brightness: 0.765)
outgoingInactiveControlColor = outgoingBubbleMixedColor.withMultiplied(hue: 1.207 * hueFactor, saturation: 1.721, brightness: 0.851)
outgoingFileTitleColor = outgoingBubbleMixedColor.withMultiplied(hue: 1.285 * hueFactor, saturation: 2.946, brightness: 0.667)
outgoingPollsProgressColor = outgoingBubbleMixedColor.withMultiplied(hue: 1.283 * hueFactor, saturation: 3.176, brightness: 0.765)
outgoingSelectionColor = outgoingBubbleMixedColor.withMultiplied(hue: 1.013 * hueFactor, saturation: 1.292, brightness: 0.871)
outgoingSelectionBaseColor = outgoingControlColor
outgoingCheckColor = outgoingBubbleFillColor?.withMultiplied(hue: 1.344 * hueFactor, saturation: 4.554 * saturationFactor, brightness: 0.549).withAlphaComponent(0.8)
outgoingCheckColor = outgoingBubbleMixedColor.withMultiplied(hue: 1.344 * hueFactor, saturation: 4.554 * saturationFactor, brightness: 0.549).withAlphaComponent(0.8)
}
outgoingPendingActivityColor = outgoingCheckColor
@ -232,6 +234,7 @@ public func customizeDefaultDayTheme(theme: PresentationTheme, editing: Bool, ti
bar: accentColor
),
actionButtonsFillColor: serviceBackgroundColor.flatMap { chat.message.incoming.actionButtonsFillColor.withUpdated(withWallpaper: $0) },
actionButtonsStrokeColor: day ? chat.message.incoming.actionButtonsStrokeColor.withUpdated(withoutWallpaper: accentColor) : nil,
actionButtonsTextColor: day ? chat.message.incoming.actionButtonsTextColor.withUpdated(withoutWallpaper: accentColor) : nil,
textSelectionColor: accentColor?.withAlphaComponent(0.2),
textSelectionKnobColor: accentColor

View File

@ -54,7 +54,7 @@ extension TelegramWallpaper: Codable {
blur = true
}
if components.count >= 2 && components.count <= 5 && components[0].count == 6 && !optionKeys.contains(components[0]) && components[1].count == 6 && !optionKeys.contains(components[1]), let topColor = UIColor(hexString: components[0]), let bottomColor = UIColor(hexString: components[1]) {
if components.count >= 2 && components.count <= 5 && [6, 8].contains(components[0].count) && !optionKeys.contains(components[0]) && [6, 8].contains(components[1].count) && !optionKeys.contains(components[1]), let topColor = UIColor(hexString: components[0]), let bottomColor = UIColor(hexString: components[1]) {
var rotation: Int32?
if components.count > 2, components[2].count <= 3, let value = Int32(components[2]) {

View File

@ -73,7 +73,8 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, deviceMetrics: DeviceMetrics, isVisible: Bool) -> (CGFloat, CGFloat) {
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: UIScreenPixel)))
if self.theme !== interfaceState.theme {
let updatedTheme = self.theme !== interfaceState.theme
if updatedTheme {
self.theme = interfaceState.theme
self.separatorNode.backgroundColor = interfaceState.theme.chat.inputButtonPanel.panelSeparatorColor
@ -128,7 +129,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
self.buttonNodes.append(buttonNode)
}
buttonIndex += 1
if buttonNode.button != button {
if buttonNode.button != button || updatedTheme {
buttonNode.button = button
buttonNode.setAttributedTitle(NSAttributedString(string: button.title, font: Font.regular(16.0), textColor: interfaceState.theme.chat.inputButtonPanel.buttonTextColor, paragraphAlignment: .center), for: [])
}

View File

@ -1625,9 +1625,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
if let strongSelf = self {
strongSelf.chatDisplayNode.sendCurrentMessage(scheduleTime: time, completion: { [weak self] in
if let strongSelf = self, !strongSelf.presentationInterfaceState.isScheduledMessages && time != scheduleWhenOnlineTimestamp {
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) }
})
if !strongSelf.presentationInterfaceState.isScheduledMessages && time != scheduleWhenOnlineTimestamp {
strongSelf.openScheduledMessages()
}
}
})
}
})

View File

@ -2261,9 +2261,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
textInputPanelNode.text = ""
strongSelf.requestUpdateChatInterfaceState(false, true, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedComposeDisableUrlPreview(nil) })
strongSelf.ignoreUpdateHeight = false
completion()
}
})
completion()
if let forwardMessageIds = self.chatPresentationInterfaceState.interfaceState.forwardMessageIds {
for id in forwardMessageIds {

View File

@ -142,9 +142,8 @@ final class ChatMessageNotificationItemNode: NotificationItemNode {
} else {
isScheduled = true
}
} else {
self.avatarNode.setPeer(context: item.context, theme: presentationData.theme, peer: peer, overrideImage: peer.id == item.context.account.peerId ? .savedMessagesIcon : nil, emptyColor: presentationData.theme.list.mediaPlaceholderColor)
}
self.avatarNode.setPeer(context: item.context, theme: presentationData.theme, peer: peer, overrideImage: peer.id == item.context.account.peerId ? .savedMessagesIcon : nil, emptyColor: presentationData.theme.list.mediaPlaceholderColor)
}
var titleIcon: UIImage?
@ -308,9 +307,6 @@ final class ChatMessageNotificationItemNode: NotificationItemNode {
if isReminder {
title = presentationData.strings.ScheduledMessages_ReminderNotification
if let firstMessage = item.messages.first, let peer = messageMainPeer(firstMessage) {
self.avatarNode.setPeer(context: item.context, theme: presentationData.theme, peer: peer, overrideImage: .savedMessagesIcon, emptyColor: presentationData.theme.list.mediaPlaceholderColor)
}
} else if isScheduled, let currentTitle = title {
title = "📅 \(currentTitle)"
}

View File

@ -12,6 +12,7 @@ import MergeLists
import ChatListUI
import AccountContext
import ContextUI
import ChatListSearchItemHeader
private enum ChatListSearchEntryStableId: Hashable {
case messageId(MessageId)
@ -292,6 +293,12 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
let previousTheme = self.presentationData.theme
self.presentationData = presentationData
self.presentationDataPromise.set(.single(ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations)))
self.listNode.forEachItemHeaderNode({ itemHeaderNode in
if let itemHeaderNode = itemHeaderNode as? ChatListSearchItemHeaderNode {
itemHeaderNode.updateTheme(theme: presentationData.theme)
}
})
}
private func enqueueTransition(_ transition: ChatListSearchContainerTransition, firstTime: Bool) {

View File

@ -395,11 +395,11 @@ public final class MediaManagerImpl: NSObject, MediaManager {
let throttledSignal = self.globalMediaPlayerState
|> mapToThrottled { next -> Signal<(Account, SharedMediaPlayerItemPlaybackStateOrLoading, MediaManagerPlayerType)?, NoError> in
return .single(next) |> then(.complete() |> delay(4.0, queue: Queue.concurrentDefaultQueue()))
return .single(next) |> then(.complete() |> delay(2.0, queue: Queue.concurrentDefaultQueue()))
}
self.mediaPlaybackStateDisposable.set(throttledSignal.start(next: { accountStateAndType in
if let (account, stateOrLoading, type) = accountStateAndType, type == .music, case let .state(state) = stateOrLoading, state.status.duration > 60.0 * 20.0, case .playing = state.status.status {
if let (account, stateOrLoading, type) = accountStateAndType, type == .music, case let .state(state) = stateOrLoading, state.status.duration >= 60.0 * 20.0, case .playing = state.status.status {
if let item = state.item as? MessageMediaPlaylistItem {
var storedState: MediaPlaybackStoredState?
if state.status.timestamp > 5.0 && state.status.timestamp < state.status.duration - 5.0 {

View File

@ -173,10 +173,12 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
self.scrubberNode = MediaPlayerScrubbingNode(content: .standard(lineHeight: 3.0, lineCap: .round, scrubberHandle: .circle, backgroundColor: presentationData.theme.list.controlSecondaryColor, foregroundColor: presentationData.theme.list.itemAccentColor, bufferingColor: presentationData.theme.list.itemAccentColor.withAlphaComponent(0.4)))
self.leftDurationLabel = MediaPlayerTimeTextNode(textColor: presentationData.theme.list.itemSecondaryTextColor)
self.leftDurationLabel.displaysAsynchronously = false
self.leftDurationLabel.keepPreviousValueOnEmptyState = true
self.rightDurationLabel = MediaPlayerTimeTextNode(textColor: presentationData.theme.list.itemSecondaryTextColor)
self.rightDurationLabel.displaysAsynchronously = false
self.rightDurationLabel.mode = .reversed
self.rightDurationLabel.alignment = .right
self.rightDurationLabel.keepPreviousValueOnEmptyState = true
self.rateButton = HighlightableButtonNode()
self.rateButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -4.0, bottom: -8.0, right: -4.0)

View File

@ -85,7 +85,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}
self.chatListNode = ChatListNode(context: context, groupId: .root, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
self.chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
super.init()

View File

@ -1125,7 +1125,7 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
case .night:
topBackgroundColor = UIColor(rgb: 0x000000)
incomingColor = UIColor(rgb: 0x1f1f1f)
if accentColor == nil {
if accentColor == nil || accentColor?.rgb == 0xffffff {
accentColor = UIColor(rgb: 0x313131)
}
outgoingColor = bubbleColors ?? (accentColor!, accentColor!)