mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
Various UI fixes
This commit is contained in:
parent
9bf4297c60
commit
ebc595a62f
22
Images.xcassets/Settings/MenuIcons/EditProfile.imageset/Contents.json
vendored
Normal file
22
Images.xcassets/Settings/MenuIcons/EditProfile.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "EditProfile@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "EditProfile@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Images.xcassets/Settings/MenuIcons/EditProfile.imageset/EditProfile@2x.png
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/EditProfile.imageset/EditProfile@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 666 B |
BIN
Images.xcassets/Settings/MenuIcons/EditProfile.imageset/EditProfile@3x.png
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/EditProfile.imageset/EditProfile@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 954 B |
@ -71,6 +71,7 @@ func faqSearchableItems(context: AccountContext) -> Signal<[SettingsSearchableIt
|
|||||||
return cachedFaqInstantPage(context: context)
|
return cachedFaqInstantPage(context: context)
|
||||||
|> map { resolvedUrl -> [SettingsSearchableItem] in
|
|> map { resolvedUrl -> [SettingsSearchableItem] in
|
||||||
var results: [SettingsSearchableItem] = []
|
var results: [SettingsSearchableItem] = []
|
||||||
|
var nextIndex: Int = 1
|
||||||
if case let .instantView(webPage, _) = resolvedUrl {
|
if case let .instantView(webPage, _) = resolvedUrl {
|
||||||
if case let .Loaded(content) = webPage.content, let instantPage = content.instantPage {
|
if case let .Loaded(content) = webPage.content, let instantPage = content.instantPage {
|
||||||
var processingQuestions = false
|
var processingQuestions = false
|
||||||
@ -83,14 +84,15 @@ func faqSearchableItems(context: AccountContext) -> Signal<[SettingsSearchableIt
|
|||||||
if results.isEmpty {
|
if results.isEmpty {
|
||||||
processingQuestions = true
|
processingQuestions = true
|
||||||
}
|
}
|
||||||
case let .anchor(anchor):
|
// case let .anchor(anchor):
|
||||||
currentAnchor = anchor
|
// currentAnchor = anchor
|
||||||
case let .header(text):
|
// case let .header(text):
|
||||||
if let anchor = currentAnchor {
|
// if let anchor = currentAnchor {
|
||||||
results.append(SettingsSearchableItem(id: .faq(results.count + 1), title: text.plainText, alternate: [], icon: .faq, breadcrumbs: [strings.SettingsSearch_FAQ], present: { context, _, present in
|
// results.append(SettingsSearchableItem(id: .faq(nextIndex), title: text.plainText, alternate: [], icon: .faq, breadcrumbs: [strings.SettingsSearch_FAQ], present: { context, _, present in
|
||||||
present(.push, InstantPageController(context: context, webPage: webPage, sourcePeerType: .channel, anchor: anchor))
|
// present(.push, InstantPageController(context: context, webPage: webPage, sourcePeerType: .channel, anchor: anchor))
|
||||||
}))
|
// }))
|
||||||
}
|
// nextIndex += 1
|
||||||
|
// }
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -107,9 +109,20 @@ func faqSearchableItems(context: AccountContext) -> Signal<[SettingsSearchableIt
|
|||||||
for item in items {
|
for item in items {
|
||||||
if case let .text(itemText, _) = item, case let .url(text, url, _) = itemText {
|
if case let .text(itemText, _) = item, case let .url(text, url, _) = itemText {
|
||||||
let (_, anchor) = extractAnchor(string: url)
|
let (_, anchor) = extractAnchor(string: url)
|
||||||
results.append(SettingsSearchableItem(id: .faq(results.count + 1), title: text.plainText, alternate: [], icon: .faq, breadcrumbs: [strings.SettingsSearch_FAQ, currentSection], present: { context, _, present in
|
var index = nextIndex
|
||||||
|
if anchor?.contains("delete-my-account") ?? false {
|
||||||
|
index = 0
|
||||||
|
} else {
|
||||||
|
nextIndex += 1
|
||||||
|
}
|
||||||
|
let item = SettingsSearchableItem(id: .faq(index), title: text.plainText, alternate: [], icon: .faq, breadcrumbs: [strings.SettingsSearch_FAQ, currentSection], present: { context, _, present in
|
||||||
present(.push, InstantPageController(context: context, webPage: webPage, sourcePeerType: .channel, anchor: anchor))
|
present(.push, InstantPageController(context: context, webPage: webPage, sourcePeerType: .channel, anchor: anchor))
|
||||||
}))
|
})
|
||||||
|
if index == 0 {
|
||||||
|
results.insert(item, at: 0)
|
||||||
|
} else {
|
||||||
|
results.append(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -352,7 +352,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
durationNode.defaultDuration = telegramFile.duration.flatMap(Double.init)
|
durationNode.defaultDuration = telegramFile.duration.flatMap(Double.init)
|
||||||
|
|
||||||
let streamVideo = automaticDownload && isMediaStreamable(message: item.message, media: telegramFile)
|
let streamVideo = automaticDownload && isMediaStreamable(message: item.message, media: telegramFile) && telegramFile.id?.namespace != Namespaces.Media.LocalFile
|
||||||
if let videoNode = strongSelf.videoNode {
|
if let videoNode = strongSelf.videoNode {
|
||||||
videoNode.layer.allowsGroupOpacity = true
|
videoNode.layer.allowsGroupOpacity = true
|
||||||
videoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.5, delay: 0.2, removeOnCompletion: false, completion: { [weak videoNode] _ in
|
videoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.5, delay: 0.2, removeOnCompletion: false, completion: { [weak videoNode] _ in
|
||||||
@ -500,6 +500,15 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isBuffering: Bool?
|
||||||
|
if let message = self.item?.message, let media = self.media, let size = media.size, (isMediaStreamable(message: message, media: media) || size <= 256 * 1024) && (self.automaticDownload ?? false) {
|
||||||
|
if let playerStatus = self.playerStatus, case .buffering = playerStatus.status {
|
||||||
|
isBuffering = true
|
||||||
|
} else {
|
||||||
|
isBuffering = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var progressRequired = false
|
var progressRequired = false
|
||||||
if case let .fetchStatus(fetchStatus) = status.mediaStatus {
|
if case let .fetchStatus(fetchStatus) = status.mediaStatus {
|
||||||
if case .Local = fetchStatus {
|
if case .Local = fetchStatus {
|
||||||
@ -511,6 +520,8 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
progressRequired = true
|
progressRequired = true
|
||||||
}
|
}
|
||||||
|
} else if isBuffering ?? false {
|
||||||
|
progressRequired = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if progressRequired {
|
if progressRequired {
|
||||||
@ -530,15 +541,6 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isBuffering: Bool?
|
|
||||||
if let message = self.item?.message, let media = self.media, let size = media.size, (isMediaStreamable(message: message, media: media) || size <= 256 * 1024) && (self.automaticDownload ?? false) {
|
|
||||||
if let playerStatus = self.playerStatus, case .buffering = playerStatus.status {
|
|
||||||
isBuffering = true
|
|
||||||
} else {
|
|
||||||
isBuffering = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var state: RadialStatusNodeState
|
var state: RadialStatusNodeState
|
||||||
switch status.mediaStatus {
|
switch status.mediaStatus {
|
||||||
case var .fetchStatus(fetchStatus):
|
case var .fetchStatus(fetchStatus):
|
||||||
@ -550,7 +552,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
case let .Fetching(_, progress):
|
case let .Fetching(_, progress):
|
||||||
if let isBuffering = isBuffering {
|
if let isBuffering = isBuffering {
|
||||||
if isBuffering {
|
if isBuffering {
|
||||||
state = .progress(color: bubbleTheme.mediaOverlayControlForegroundColor, lineWidth: nil, value: nil, cancelEnabled: false)
|
state = .progress(color: bubbleTheme.mediaOverlayControlForegroundColor, lineWidth: nil, value: nil, cancelEnabled: true)
|
||||||
} else {
|
} else {
|
||||||
state = .none
|
state = .none
|
||||||
}
|
}
|
||||||
@ -573,7 +575,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if isBuffering ?? false {
|
if isBuffering ?? false {
|
||||||
state = .progress(color: bubbleTheme.mediaOverlayControlForegroundColor, lineWidth: nil, value: nil, cancelEnabled: false)
|
state = .progress(color: bubbleTheme.mediaOverlayControlForegroundColor, lineWidth: nil, value: nil, cancelEnabled: true)
|
||||||
} else {
|
} else {
|
||||||
state = .none
|
state = .none
|
||||||
}
|
}
|
||||||
|
|||||||
@ -178,8 +178,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
let point = recognizer.location(in: self.imageNode.view)
|
let point = recognizer.location(in: self.imageNode.view)
|
||||||
if let fetchStatus = self.fetchStatus, case .Local = fetchStatus {
|
if let fetchStatus = self.fetchStatus, case .Local = fetchStatus {
|
||||||
var videoContentMatch = true
|
var videoContentMatch = true
|
||||||
if let content = self.videoContent, case let .message(id, _, _) = content.nativeId {
|
if let content = self.videoContent, case let .message(id, _, mediaId) = content.nativeId {
|
||||||
videoContentMatch = self.message?.id == id
|
videoContentMatch = self.message?.id == id && self.media?.id == mediaId
|
||||||
}
|
}
|
||||||
self.activateLocalContent((self.automaticPlayback ?? false) && videoContentMatch ? .automaticPlayback : .default)
|
self.activateLocalContent((self.automaticPlayback ?? false) && videoContentMatch ? .automaticPlayback : .default)
|
||||||
} else {
|
} else {
|
||||||
@ -698,26 +698,20 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
} else if let image = media as? TelegramMediaWebFile {
|
} else if let image = media as? TelegramMediaWebFile {
|
||||||
strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, image: image).start())
|
strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: context.account, image: image).start())
|
||||||
} else if let file = media as? TelegramMediaFile {
|
} else if let file = media as? TelegramMediaFile {
|
||||||
if automaticPlayback || !file.isAnimated {
|
let fetchSignal = messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: false)
|
||||||
let fetchSignal = messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: false)
|
let visibilityAwareFetchSignal = strongSelf.visibilityPromise.get()
|
||||||
if !file.isAnimated {
|
|> mapToSignal { visibility -> Signal<Void, NoError> in
|
||||||
let visibilityAwareFetchSignal = strongSelf.visibilityPromise.get()
|
switch visibility {
|
||||||
|> mapToSignal { visibility -> Signal<Void, NoError> in
|
case .visible:
|
||||||
switch visibility {
|
return fetchSignal
|
||||||
case .visible:
|
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||||
return fetchSignal
|
return .complete()
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
|
||||||
return .complete()
|
|
||||||
}
|
|
||||||
case .none:
|
|
||||||
return .complete()
|
|
||||||
}
|
}
|
||||||
|
case .none:
|
||||||
|
return .complete()
|
||||||
}
|
}
|
||||||
strongSelf.fetchDisposable.set(visibilityAwareFetchSignal.start())
|
|
||||||
} else {
|
|
||||||
strongSelf.fetchDisposable.set(fetchSignal.start())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
strongSelf.fetchDisposable.set(visibilityAwareFetchSignal.start())
|
||||||
}
|
}
|
||||||
} else if case .prefetch = automaticDownload, message.id.namespace != Namespaces.Message.SecretIncoming {
|
} else if case .prefetch = automaticDownload, message.id.namespace != Namespaces.Message.SecretIncoming {
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
@ -927,7 +921,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
if wideLayout {
|
if wideLayout {
|
||||||
if let size = file.size {
|
if let size = file.size {
|
||||||
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: decimalSeparator)) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: decimalSeparator))"
|
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: decimalSeparator)) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: decimalSeparator))"
|
||||||
if file.isAnimated && !automaticDownload {
|
if file.isAnimated && (!automaticDownload || !automaticPlayback) {
|
||||||
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: "GIF " + sizeString, size: nil, muted: false, active: false)
|
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: "GIF " + sizeString, size: nil, muted: false, active: false)
|
||||||
}
|
}
|
||||||
else if let duration = file.duration, !message.flags.contains(.Unsent) {
|
else if let duration = file.duration, !message.flags.contains(.Unsent) {
|
||||||
@ -1031,7 +1025,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
case .Remote:
|
case .Remote:
|
||||||
state = .download(bubbleTheme.mediaOverlayControlForegroundColor)
|
state = .download(bubbleTheme.mediaOverlayControlForegroundColor)
|
||||||
if let file = self.media as? TelegramMediaFile {
|
if let file = self.media as? TelegramMediaFile {
|
||||||
if file.isAnimated && !automaticDownload {
|
if file.isAnimated && (!automaticDownload || !automaticPlayback) {
|
||||||
let string = "GIF " + dataSizeString(file.size ?? 0, decimalSeparator: decimalSeparator)
|
let string = "GIF " + dataSizeString(file.size ?? 0, decimalSeparator: decimalSeparator)
|
||||||
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: string, size: nil, muted: false, active: false)
|
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: string, size: nil, muted: false, active: false)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -400,22 +400,22 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
|||||||
let peerView = context.account.viewTracker.peerView(context.account.peerId)
|
let peerView = context.account.viewTracker.peerView(context.account.peerId)
|
||||||
|
|
||||||
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), peerView)
|
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), peerView)
|
||||||
|> map { presentationData, state, view -> (ItemListControllerState, (ItemListNodeState<SettingsEntry>, SettingsEntry.ItemGenerationArguments)) in
|
|> map { presentationData, state, view -> (ItemListControllerState, (ItemListNodeState<SettingsEntry>, SettingsEntry.ItemGenerationArguments)) in
|
||||||
let rightNavigationButton: ItemListNavigationButton
|
let rightNavigationButton: ItemListNavigationButton
|
||||||
if state.updatingName != nil || state.updatingBioText {
|
if state.updatingName != nil || state.updatingBioText {
|
||||||
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
|
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
|
||||||
} else {
|
} else {
|
||||||
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
|
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
|
||||||
arguments.saveEditingState()
|
arguments.saveEditingState()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.EditProfile_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.EditProfile_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||||
let listState = ItemListNodeState(entries: editSettingsEntries(presentationData: presentationData, state: state, view: view, canAddAccounts: canAddAccounts), style: .blocks, ensureVisibleItemTag: focusOnItemTag)
|
let listState = ItemListNodeState(entries: editSettingsEntries(presentationData: presentationData, state: state, view: view, canAddAccounts: canAddAccounts), style: .blocks, ensureVisibleItemTag: focusOnItemTag)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
} |> afterDisposed {
|
} |> afterDisposed {
|
||||||
actionsDisposable.dispose()
|
actionsDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal, tabBarItem: nil)
|
let controller = ItemListController(context: context, state: signal, tabBarItem: nil)
|
||||||
@ -527,12 +527,12 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
|||||||
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
||||||
}) |> deliverOnMainQueue).start(next: { result in
|
}) |> deliverOnMainQueue).start(next: { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .complete:
|
case .complete:
|
||||||
updateState {
|
updateState {
|
||||||
$0.withUpdatedUpdatingAvatar(nil)
|
$0.withUpdatedUpdatingAvatar(nil)
|
||||||
}
|
}
|
||||||
case .progress:
|
case .progress:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -267,7 +267,7 @@ final class GridMessageItemNode: GridItemNode {
|
|||||||
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString))
|
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString))
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false)
|
strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -338,23 +338,29 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
shouldUpdateVisibleItems = true
|
shouldUpdateVisibleItems = true
|
||||||
self.updateNavigationBar()
|
self.updateNavigationBar()
|
||||||
}
|
}
|
||||||
|
var didSetScrollOffset = false
|
||||||
if resetOffset {
|
if resetOffset {
|
||||||
var contentOffset = CGPoint(x: 0.0, y: -self.scrollNode.view.contentInset.top)
|
var contentOffset = CGPoint(x: 0.0, y: -self.scrollNode.view.contentInset.top)
|
||||||
if let state = self.initialState {
|
if let state = self.initialState {
|
||||||
self.setupScrollOffsetOnLayout = false
|
didSetScrollOffset = true
|
||||||
contentOffset = CGPoint(x: 0.0, y: CGFloat(state.contentOffset))
|
contentOffset = CGPoint(x: 0.0, y: CGFloat(state.contentOffset))
|
||||||
}
|
}
|
||||||
else if let anchor = self.initialAnchor, !anchor.isEmpty {
|
else if let anchor = self.initialAnchor, !anchor.isEmpty {
|
||||||
if let items = self.currentLayout?.items {
|
if let items = self.currentLayout?.items {
|
||||||
self.setupScrollOffsetOnLayout = false
|
didSetScrollOffset = true
|
||||||
if let (item, lineOffset, _, _) = self.findAnchorItem(anchor, items: items) {
|
if let (item, lineOffset, _, _) = self.findAnchorItem(anchor, items: items) {
|
||||||
contentOffset = CGPoint(x: 0.0, y: item.frame.minY + lineOffset - self.scrollNode.view.contentInset.top)
|
contentOffset = CGPoint(x: 0.0, y: item.frame.minY + lineOffset - self.scrollNode.view.contentInset.top)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.setupScrollOffsetOnLayout = false
|
didSetScrollOffset = true
|
||||||
}
|
}
|
||||||
self.scrollNode.view.contentOffset = contentOffset
|
self.scrollNode.view.contentOffset = contentOffset
|
||||||
|
if didSetScrollOffset {
|
||||||
|
self.previousContentOffset = contentOffset
|
||||||
|
self.updateNavigationBar()
|
||||||
|
self.setupScrollOffsetOnLayout = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if shouldUpdateVisibleItems {
|
if shouldUpdateVisibleItems {
|
||||||
self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds)
|
self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds)
|
||||||
@ -668,7 +674,9 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let delta: CGFloat
|
let delta: CGFloat
|
||||||
if let previousContentOffset = self.previousContentOffset {
|
if self.setupScrollOffsetOnLayout {
|
||||||
|
delta = 0.0
|
||||||
|
} else if let previousContentOffset = self.previousContentOffset {
|
||||||
delta = contentOffset.y - previousContentOffset.y
|
delta = contentOffset.y - previousContentOffset.y
|
||||||
} else {
|
} else {
|
||||||
delta = 0.0
|
delta = 0.0
|
||||||
@ -700,6 +708,10 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
navigationBarFrame.size.height = max(minBarHeight, min(maxBarHeight, navigationBarFrame.size.height))
|
navigationBarFrame.size.height = max(minBarHeight, min(maxBarHeight, navigationBarFrame.size.height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.setupScrollOffsetOnLayout {
|
||||||
|
navigationBarFrame.size.height = maxBarHeight
|
||||||
|
}
|
||||||
|
|
||||||
let transitionFactor = (navigationBarFrame.size.height - minBarHeight) / (maxBarHeight - minBarHeight)
|
let transitionFactor = (navigationBarFrame.size.height - minBarHeight) / (maxBarHeight - minBarHeight)
|
||||||
|
|
||||||
if containerLayout.safeInsets.top.isZero {
|
if containerLayout.safeInsets.top.isZero {
|
||||||
|
|||||||
@ -92,7 +92,7 @@ class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
private var item: ItemListActionItem?
|
private var item: ItemListActionItem?
|
||||||
|
|
||||||
var tag: ItemListItemTag? {
|
var tag: ItemListItemTag? {
|
||||||
return self.item?.tag
|
return self.item?.tag as? ItemListItemTag
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
|||||||
@ -5,14 +5,6 @@ import Postbox
|
|||||||
import TelegramCore
|
import TelegramCore
|
||||||
import LegacyComponents
|
import LegacyComponents
|
||||||
|
|
||||||
private final class LogoutOptionsItemIcons {
|
|
||||||
static let addAccount = UIImage(bundleImageName: "Settings/MenuIcons/AddAccount")?.precomposed()
|
|
||||||
static let setPasscode = UIImage(bundleImageName: "Settings/MenuIcons/SetPasscode")?.precomposed()
|
|
||||||
static let clearCache = UIImage(bundleImageName: "Settings/MenuIcons/ClearCache")?.precomposed()
|
|
||||||
static let changePhoneNumber = UIImage(bundleImageName: "Settings/MenuIcons/ChangePhoneNumber")?.precomposed()
|
|
||||||
static let contactSupport = UIImage(bundleImageName: "Settings/MenuIcons/Support")?.precomposed()
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct LogoutOptionsItemArguments {
|
private struct LogoutOptionsItemArguments {
|
||||||
let addAccount: () -> Void
|
let addAccount: () -> Void
|
||||||
let setPasscode: () -> Void
|
let setPasscode: () -> Void
|
||||||
@ -76,23 +68,23 @@ private enum LogoutOptionsEntry: ItemListNodeEntry, Equatable {
|
|||||||
case let .alternativeHeader(theme, title):
|
case let .alternativeHeader(theme, title):
|
||||||
return ItemListSectionHeaderItem(theme: theme, text: title, sectionId: self.section)
|
return ItemListSectionHeaderItem(theme: theme, text: title, sectionId: self.section)
|
||||||
case let .addAccount(theme, title, text):
|
case let .addAccount(theme, title, text):
|
||||||
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.addAccount, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
return ItemListDisclosureItem(theme: theme, icon: PresentationResourcesSettings.addAccount, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
arguments.addAccount()
|
arguments.addAccount()
|
||||||
})
|
})
|
||||||
case let .setPasscode(theme, title, text):
|
case let .setPasscode(theme, title, text):
|
||||||
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.setPasscode, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
return ItemListDisclosureItem(theme: theme, icon: PresentationResourcesSettings.setPasscode, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
arguments.setPasscode()
|
arguments.setPasscode()
|
||||||
})
|
})
|
||||||
case let .clearCache(theme, title, text):
|
case let .clearCache(theme, title, text):
|
||||||
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.clearCache, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
return ItemListDisclosureItem(theme: theme, icon: PresentationResourcesSettings.clearCache, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
arguments.clearCache()
|
arguments.clearCache()
|
||||||
})
|
})
|
||||||
case let .changePhoneNumber(theme, title, text):
|
case let .changePhoneNumber(theme, title, text):
|
||||||
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.changePhoneNumber, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
return ItemListDisclosureItem(theme: theme, icon: PresentationResourcesSettings.changePhoneNumber, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
arguments.changePhoneNumber()
|
arguments.changePhoneNumber()
|
||||||
})
|
})
|
||||||
case let .contactSupport(theme, title, text):
|
case let .contactSupport(theme, title, text):
|
||||||
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.contactSupport, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
return ItemListDisclosureItem(theme: theme, icon: PresentationResourcesSettings.support, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
arguments.contactSupport()
|
arguments.contactSupport()
|
||||||
})
|
})
|
||||||
case let .logout(theme, title):
|
case let .logout(theme, title):
|
||||||
|
|||||||
@ -312,7 +312,6 @@ private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaRef
|
|||||||
|> mapToSignal { maybeData -> Signal<(Data?, (Data, String)?, Bool), NoError> in
|
|> mapToSignal { maybeData -> Signal<(Data?, (Data, String)?, Bool), NoError> in
|
||||||
if maybeData.complete {
|
if maybeData.complete {
|
||||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||||
|
|
||||||
return .single((nil, loadedData == nil ? nil : (loadedData!, maybeData.path), true))
|
return .single((nil, loadedData == nil ? nil : (loadedData!, maybeData.path), true))
|
||||||
} else {
|
} else {
|
||||||
let thumbnail: Signal<Data?, NoError>
|
let thumbnail: Signal<Data?, NoError>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import Display
|
import Display
|
||||||
|
|
||||||
struct PresentationResourcesSettings {
|
struct PresentationResourcesSettings {
|
||||||
|
static let editProfile = UIImage(bundleImageName: "Settings/MenuIcons/EditProfile")?.precomposed()
|
||||||
static let proxy = UIImage(bundleImageName: "Settings/MenuIcons/Proxy")?.precomposed()
|
static let proxy = UIImage(bundleImageName: "Settings/MenuIcons/Proxy")?.precomposed()
|
||||||
static let savedMessages = UIImage(bundleImageName: "Settings/MenuIcons/SavedMessages")?.precomposed()
|
static let savedMessages = UIImage(bundleImageName: "Settings/MenuIcons/SavedMessages")?.precomposed()
|
||||||
static let recentCalls = UIImage(bundleImageName: "Settings/MenuIcons/RecentCalls")?.precomposed()
|
static let recentCalls = UIImage(bundleImageName: "Settings/MenuIcons/RecentCalls")?.precomposed()
|
||||||
@ -18,4 +19,9 @@ struct PresentationResourcesSettings {
|
|||||||
|
|
||||||
static let support = UIImage(bundleImageName: "Settings/MenuIcons/Support")?.precomposed()
|
static let support = UIImage(bundleImageName: "Settings/MenuIcons/Support")?.precomposed()
|
||||||
static let faq = UIImage(bundleImageName: "Settings/MenuIcons/Faq")?.precomposed()
|
static let faq = UIImage(bundleImageName: "Settings/MenuIcons/Faq")?.precomposed()
|
||||||
|
|
||||||
|
static let addAccount = UIImage(bundleImageName: "Settings/MenuIcons/AddAccount")?.precomposed()
|
||||||
|
static let setPasscode = UIImage(bundleImageName: "Settings/MenuIcons/SetPasscode")?.precomposed()
|
||||||
|
static let clearCache = UIImage(bundleImageName: "Settings/MenuIcons/ClearCache")?.precomposed()
|
||||||
|
static let changePhoneNumber = UIImage(bundleImageName: "Settings/MenuIcons/ChangePhoneNumber")?.precomposed()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -598,7 +598,6 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
|
|||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
|
|
||||||
let updateSettingsDisposable = MetaDisposable()
|
let updateSettingsDisposable = MetaDisposable()
|
||||||
actionsDisposable.add(updateSettingsDisposable)
|
|
||||||
|
|
||||||
let arguments = SelectivePrivacySettingsControllerArguments(context: context, updateType: { type in
|
let arguments = SelectivePrivacySettingsControllerArguments(context: context, updateType: { type in
|
||||||
updateState {
|
updateState {
|
||||||
@ -721,71 +720,81 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
|
|||||||
actionsDisposable.dispose()
|
actionsDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
|
||||||
controller.didDisappear = { [weak controller] _ in
|
let update: (Bool) -> Void = { save in
|
||||||
if let controller = controller, controller.navigationController?.viewControllers.firstIndex(of: controller) == nil {
|
var wasSaving = false
|
||||||
var wasSaving = false
|
var settings: SelectivePrivacySettings?
|
||||||
var settings: SelectivePrivacySettings?
|
var callP2PSettings: SelectivePrivacySettings?
|
||||||
var callP2PSettings: SelectivePrivacySettings?
|
var callDataSaving: VoiceCallDataSaving?
|
||||||
var callDataSaving: VoiceCallDataSaving?
|
var callIntegrationEnabled: Bool?
|
||||||
var callIntegrationEnabled: Bool?
|
updateState { state in
|
||||||
updateState { state in
|
wasSaving = state.saving
|
||||||
wasSaving = state.saving
|
callDataSaving = state.callDataSaving
|
||||||
callDataSaving = state.callDataSaving
|
callIntegrationEnabled = state.callIntegrationEnabled
|
||||||
callIntegrationEnabled = state.callIntegrationEnabled
|
switch state.setting {
|
||||||
switch state.setting {
|
case .everybody:
|
||||||
case .everybody:
|
settings = SelectivePrivacySettings.enableEveryone(disableFor: state.disableFor)
|
||||||
settings = SelectivePrivacySettings.enableEveryone(disableFor: state.disableFor)
|
case .contacts:
|
||||||
case .contacts:
|
settings = SelectivePrivacySettings.enableContacts(enableFor: state.enableFor, disableFor: state.disableFor)
|
||||||
settings = SelectivePrivacySettings.enableContacts(enableFor: state.enableFor, disableFor: state.disableFor)
|
case .nobody:
|
||||||
case .nobody:
|
settings = SelectivePrivacySettings.disableEveryone(enableFor: state.enableFor)
|
||||||
settings = SelectivePrivacySettings.disableEveryone(enableFor: state.enableFor)
|
|
||||||
}
|
|
||||||
|
|
||||||
if case .voiceCalls = kind, let callP2PMode = state.callP2PMode, let disableFor = state.callP2PDisableFor, let enableFor = state.callP2PEnableFor {
|
|
||||||
switch callP2PMode {
|
|
||||||
case .everybody:
|
|
||||||
callP2PSettings = SelectivePrivacySettings.enableEveryone(disableFor: disableFor)
|
|
||||||
case .contacts:
|
|
||||||
callP2PSettings = SelectivePrivacySettings.enableContacts(enableFor: enableFor, disableFor: disableFor)
|
|
||||||
case .nobody:
|
|
||||||
callP2PSettings = SelectivePrivacySettings.disableEveryone(enableFor: enableFor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.withUpdatedSaving(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let settings = settings, !wasSaving {
|
if case .voiceCalls = kind, let callP2PMode = state.callP2PMode, let disableFor = state.callP2PDisableFor, let enableFor = state.callP2PEnableFor {
|
||||||
let type: UpdateSelectiveAccountPrivacySettingsType
|
switch callP2PMode {
|
||||||
switch kind {
|
case .everybody:
|
||||||
case .presence:
|
callP2PSettings = SelectivePrivacySettings.enableEveryone(disableFor: disableFor)
|
||||||
type = .presence
|
case .contacts:
|
||||||
case .groupInvitations:
|
callP2PSettings = SelectivePrivacySettings.enableContacts(enableFor: enableFor, disableFor: disableFor)
|
||||||
type = .groupInvitations
|
case .nobody:
|
||||||
case .voiceCalls:
|
callP2PSettings = SelectivePrivacySettings.disableEveryone(enableFor: enableFor)
|
||||||
type = .voiceCalls
|
|
||||||
case .profilePhoto:
|
|
||||||
type = .profilePhoto
|
|
||||||
case .forwards:
|
|
||||||
type = .forwards
|
|
||||||
}
|
|
||||||
|
|
||||||
let updateSettingsSignal = updateSelectiveAccountPrivacySettings(account: context.account, type: type, settings: settings)
|
|
||||||
var updateCallP2PSettingsSignal: Signal<Void, NoError> = Signal.complete()
|
|
||||||
if let callP2PSettings = callP2PSettings {
|
|
||||||
updateCallP2PSettingsSignal = updateSelectiveAccountPrivacySettings(account: context.account, type: .voiceCallsP2P, settings: callP2PSettings)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSettingsDisposable.set((combineLatest(updateSettingsSignal, updateCallP2PSettingsSignal) |> deliverOnMainQueue).start(completed: {
|
|
||||||
}))
|
|
||||||
|
|
||||||
if case .voiceCalls = kind, let dataSaving = callDataSaving, let callP2PSettings = callP2PSettings, let systemIntegrationEnabled = callIntegrationEnabled {
|
|
||||||
updated(settings, (callP2PSettings, VoiceCallSettings(dataSaving: dataSaving, enableSystemIntegration: systemIntegrationEnabled)))
|
|
||||||
} else {
|
|
||||||
updated(settings, nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return state.withUpdatedSaving(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let settings = settings, !wasSaving {
|
||||||
|
let type: UpdateSelectiveAccountPrivacySettingsType
|
||||||
|
switch kind {
|
||||||
|
case .presence:
|
||||||
|
type = .presence
|
||||||
|
case .groupInvitations:
|
||||||
|
type = .groupInvitations
|
||||||
|
case .voiceCalls:
|
||||||
|
type = .voiceCalls
|
||||||
|
case .profilePhoto:
|
||||||
|
type = .profilePhoto
|
||||||
|
case .forwards:
|
||||||
|
type = .forwards
|
||||||
|
}
|
||||||
|
|
||||||
|
let updateSettingsSignal = updateSelectiveAccountPrivacySettings(account: context.account, type: type, settings: settings)
|
||||||
|
var updateCallP2PSettingsSignal: Signal<Void, NoError> = Signal.complete()
|
||||||
|
if let callP2PSettings = callP2PSettings {
|
||||||
|
updateCallP2PSettingsSignal = updateSelectiveAccountPrivacySettings(account: context.account, type: .voiceCallsP2P, settings: callP2PSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSettingsDisposable.set((combineLatest(updateSettingsSignal, updateCallP2PSettingsSignal) |> deliverOnMainQueue).start(completed: {
|
||||||
|
}))
|
||||||
|
|
||||||
|
if case .voiceCalls = kind, let dataSaving = callDataSaving, let callP2PSettings = callP2PSettings, let systemIntegrationEnabled = callIntegrationEnabled {
|
||||||
|
updated(settings, (callP2PSettings, VoiceCallSettings(dataSaving: dataSaving, enableSystemIntegration: systemIntegrationEnabled)))
|
||||||
|
} else {
|
||||||
|
updated(settings, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = ItemListController(context: context, state: signal)
|
||||||
|
controller.willDisappear = { [weak controller] _ in
|
||||||
|
if let controller = controller, controller.navigationController?.viewControllers.firstIndex(of: controller) == nil {
|
||||||
|
update(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.didDisappear = { [weak controller] _ in
|
||||||
|
if let controller = controller, controller.navigationController?.viewControllers.firstIndex(of: controller) == nil {
|
||||||
|
update(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1078,7 +1078,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
|||||||
presentControllerImpl?(v, a)
|
presentControllerImpl?(v, a)
|
||||||
}, pushController: { v in
|
}, pushController: { v in
|
||||||
pushControllerImpl?(v)
|
pushControllerImpl?(v)
|
||||||
}, getNavigationController: getNavigationControllerImpl)
|
}, getNavigationController: getNavigationControllerImpl, exceptionsList: notifyExceptions.get())
|
||||||
|
|
||||||
let (hasPassport, hasWatchApp) = hasPassportAndWatch
|
let (hasPassport, hasWatchApp) = hasPassportAndWatch
|
||||||
let listState = ItemListNodeState(entries: settingsEntries(account: context.account, presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, notifyExceptions: preferencesAndExceptions.1, notificationsAuthorizationStatus: preferencesAndExceptions.2, notificationsWarningSuppressed: preferencesAndExceptions.3, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, hasPassport: hasPassport, hasWatchApp: hasWatchApp, accountsAndPeers: accountsAndPeers.1, inAppNotificationSettings: inAppNotificationSettings), style: .blocks, searchItem: searchItem, initialScrollToItem: ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up))
|
let listState = ItemListNodeState(entries: settingsEntries(account: context.account, presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, notifyExceptions: preferencesAndExceptions.1, notificationsAuthorizationStatus: preferencesAndExceptions.2, notificationsWarningSuppressed: preferencesAndExceptions.3, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, hasPassport: hasPassport, hasWatchApp: hasWatchApp, accountsAndPeers: accountsAndPeers.1, inAppNotificationSettings: inAppNotificationSettings), style: .blocks, searchItem: searchItem, initialScrollToItem: ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up))
|
||||||
|
|||||||
@ -19,6 +19,8 @@ extension NavigationBarSearchContentNode: ItemListControllerSearchNavigationCont
|
|||||||
extension SettingsSearchableItemIcon {
|
extension SettingsSearchableItemIcon {
|
||||||
func image() -> UIImage? {
|
func image() -> UIImage? {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .profile:
|
||||||
|
return PresentationResourcesSettings.editProfile
|
||||||
case .proxy:
|
case .proxy:
|
||||||
return PresentationResourcesSettings.proxy
|
return PresentationResourcesSettings.proxy
|
||||||
case .savedMessages:
|
case .savedMessages:
|
||||||
@ -58,12 +60,13 @@ final class SettingsSearchItem: ItemListControllerSearch {
|
|||||||
let presentController: (ViewController, Any?) -> Void
|
let presentController: (ViewController, Any?) -> Void
|
||||||
let pushController: (ViewController) -> Void
|
let pushController: (ViewController) -> Void
|
||||||
let getNavigationController: (() -> NavigationController?)?
|
let getNavigationController: (() -> NavigationController?)?
|
||||||
|
let exceptionsList: Signal<NotificationExceptionsList?, NoError>
|
||||||
|
|
||||||
private var updateActivity: ((Bool) -> Void)?
|
private var updateActivity: ((Bool) -> Void)?
|
||||||
private var activity: ValuePromise<Bool> = ValuePromise(ignoreRepeated: false)
|
private var activity: ValuePromise<Bool> = ValuePromise(ignoreRepeated: false)
|
||||||
private let activityDisposable = MetaDisposable()
|
private let activityDisposable = MetaDisposable()
|
||||||
|
|
||||||
init(context: AccountContext, theme: PresentationTheme, placeholder: String, activated: Bool, updateActivated: @escaping (Bool) -> Void, presentController: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, getNavigationController: (() -> NavigationController?)?) {
|
init(context: AccountContext, theme: PresentationTheme, placeholder: String, activated: Bool, updateActivated: @escaping (Bool) -> Void, presentController: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, getNavigationController: (() -> NavigationController?)?, exceptionsList: Signal<NotificationExceptionsList?, NoError>) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.placeholder = placeholder
|
self.placeholder = placeholder
|
||||||
@ -72,6 +75,7 @@ final class SettingsSearchItem: ItemListControllerSearch {
|
|||||||
self.presentController = presentController
|
self.presentController = presentController
|
||||||
self.pushController = pushController
|
self.pushController = pushController
|
||||||
self.getNavigationController = getNavigationController
|
self.getNavigationController = getNavigationController
|
||||||
|
self.exceptionsList = exceptionsList
|
||||||
self.activityDisposable.set((activity.get() |> mapToSignal { value -> Signal<Bool, NoError> in
|
self.activityDisposable.set((activity.get() |> mapToSignal { value -> Signal<Bool, NoError> in
|
||||||
if value {
|
if value {
|
||||||
return .single(value) |> delay(0.2, queue: Queue.mainQueue())
|
return .single(value) |> delay(0.2, queue: Queue.mainQueue())
|
||||||
@ -135,7 +139,7 @@ final class SettingsSearchItem: ItemListControllerSearch {
|
|||||||
pushController(c)
|
pushController(c)
|
||||||
}, presentController: { c, a in
|
}, presentController: { c, a in
|
||||||
presentController(c, a)
|
presentController(c, a)
|
||||||
}, getNavigationController: self.getNavigationController)
|
}, getNavigationController: self.getNavigationController, exceptionsList: self.exceptionsList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,7 +221,7 @@ private final class SettingsSearchContainerNode: SearchDisplayControllerContentN
|
|||||||
|
|
||||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings)>
|
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings)>
|
||||||
|
|
||||||
init(context: AccountContext, listState: LocalizationListState, openResult: @escaping (SettingsSearchableItem) -> Void) {
|
init(context: AccountContext, openResult: @escaping (SettingsSearchableItem) -> Void, exceptionsList: Signal<NotificationExceptionsList?, NoError>) {
|
||||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
|
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
|
||||||
@ -235,14 +239,20 @@ private final class SettingsSearchContainerNode: SearchDisplayControllerContentN
|
|||||||
self.addSubnode(self.dimNode)
|
self.addSubnode(self.dimNode)
|
||||||
self.addSubnode(self.listNode)
|
self.addSubnode(self.listNode)
|
||||||
|
|
||||||
let queryAndFoundItems = combineLatest(settingsSearchableItems(context: context), faqSearchableItems(context: context))
|
let queryAndFoundItems = combineLatest(settingsSearchableItems(context: context, exceptionsList: exceptionsList), faqSearchableItems(context: context))
|
||||||
|> mapToSignal { searchableItems, faqSearchableItems -> Signal<(String, [SettingsSearchableItem])?, NoError> in
|
|> mapToSignal { searchableItems, faqSearchableItems -> Signal<(String, [SettingsSearchableItem])?, NoError> in
|
||||||
return self.searchQuery.get()
|
return self.searchQuery.get()
|
||||||
|> mapToSignal { query -> Signal<(String, [SettingsSearchableItem])?, NoError> in
|
|> mapToSignal { query -> Signal<(String, [SettingsSearchableItem])?, NoError> in
|
||||||
if let query = query, !query.isEmpty {
|
if let query = query, !query.isEmpty {
|
||||||
let result = searchSettingsItems(items: searchableItems, query: query)
|
let results = searchSettingsItems(items: searchableItems, query: query)
|
||||||
let faqResults = searchSettingsItems(items: faqSearchableItems, query: query)
|
let faqResults = searchSettingsItems(items: faqSearchableItems, query: query)
|
||||||
return .single((query, result + faqResults))
|
let finalResults: [SettingsSearchableItem]
|
||||||
|
if faqResults.first?.id == .faq(0) {
|
||||||
|
finalResults = faqResults + results
|
||||||
|
} else {
|
||||||
|
finalResults = results + faqResults
|
||||||
|
}
|
||||||
|
return .single((query, finalResults))
|
||||||
} else {
|
} else {
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
@ -404,16 +414,18 @@ private final class SettingsSearchItemNode: ItemListControllerSearchNode {
|
|||||||
let pushController: (ViewController) -> Void
|
let pushController: (ViewController) -> Void
|
||||||
let presentController: (ViewController, Any?) -> Void
|
let presentController: (ViewController, Any?) -> Void
|
||||||
let getNavigationController: (() -> NavigationController?)?
|
let getNavigationController: (() -> NavigationController?)?
|
||||||
|
let exceptionsList: Signal<NotificationExceptionsList?, NoError>
|
||||||
|
|
||||||
var cancel: () -> Void
|
var cancel: () -> Void
|
||||||
|
|
||||||
init(context: AccountContext, cancel: @escaping () -> Void, updateActivity: @escaping(Bool) -> Void, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, Any?) -> Void, getNavigationController: (() -> NavigationController?)?) {
|
init(context: AccountContext, cancel: @escaping () -> Void, updateActivity: @escaping(Bool) -> Void, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, Any?) -> Void, getNavigationController: (() -> NavigationController?)?, exceptionsList: Signal<NotificationExceptionsList?, NoError>) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self.cancel = cancel
|
||||||
self.pushController = pushController
|
self.pushController = pushController
|
||||||
self.presentController = presentController
|
self.presentController = presentController
|
||||||
self.getNavigationController = getNavigationController
|
self.getNavigationController = getNavigationController
|
||||||
self.cancel = cancel
|
self.exceptionsList = exceptionsList
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
@ -428,7 +440,7 @@ private final class SettingsSearchItemNode: ItemListControllerSearchNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: SettingsSearchContainerNode(context: self.context, listState: LocalizationListState.defaultSettings, openResult: { [weak self] result in
|
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: SettingsSearchContainerNode(context: self.context, openResult: { [weak self] result in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
result.present(strongSelf.context, strongSelf.getNavigationController?(), { [weak self] mode, controller in
|
result.present(strongSelf.context, strongSelf.getNavigationController?(), { [weak self] mode, controller in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -445,7 +457,7 @@ private final class SettingsSearchItemNode: ItemListControllerSearchNode {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}), cancel: { [weak self] in
|
}, exceptionsList: self.exceptionsList), cancel: { [weak self] in
|
||||||
self?.cancel()
|
self?.cancel()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import TelegramCore
|
|||||||
private let maximumNumberOfAccounts = 3
|
private let maximumNumberOfAccounts = 3
|
||||||
|
|
||||||
enum SettingsSearchableItemIcon {
|
enum SettingsSearchableItemIcon {
|
||||||
|
case profile
|
||||||
case proxy
|
case proxy
|
||||||
case savedMessages
|
case savedMessages
|
||||||
case calls
|
case calls
|
||||||
@ -55,7 +56,7 @@ struct SettingsSearchableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func profileSearchableItems(context: AccountContext, canAddAccount: Bool) -> [SettingsSearchableItem] {
|
private func profileSearchableItems(context: AccountContext, canAddAccount: Bool) -> [SettingsSearchableItem] {
|
||||||
let icon: SettingsSearchableItemIcon = .calls
|
let icon: SettingsSearchableItemIcon = .profile
|
||||||
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
||||||
|
|
||||||
let presentProfileSettings: (AccountContext, @escaping (SettingsSearchableItemPresentation, ViewController) -> Void, EditSettingsEntryTag?) -> Void = { context, present, itemTag in
|
let presentProfileSettings: (AccountContext, @escaping (SettingsSearchableItemPresentation, ViewController) -> Void, EditSettingsEntryTag?) -> Void = { context, present, itemTag in
|
||||||
@ -87,7 +88,7 @@ private func profileSearchableItems(context: AccountContext, canAddAccount: Bool
|
|||||||
}))
|
}))
|
||||||
if canAddAccount {
|
if canAddAccount {
|
||||||
items.append(SettingsSearchableItem(id: .profile(4), title: strings.Settings_AddAccount, alternate: [], icon: icon, breadcrumbs: [strings.EditProfile_Title], present: { context, _, present in
|
items.append(SettingsSearchableItem(id: .profile(4), title: strings.Settings_AddAccount, alternate: [], icon: icon, breadcrumbs: [strings.EditProfile_Title], present: { context, _, present in
|
||||||
let isTestingEnvironment = context.account.testingEnvironment
|
let isTestingEnvironment = context.account.testingEnvironment
|
||||||
context.sharedContext.beginNewAuth(testingEnvironment: isTestingEnvironment)
|
context.sharedContext.beginNewAuth(testingEnvironment: isTestingEnvironment)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -155,12 +156,12 @@ private func stickerSearchableItems(context: AccountContext) -> [SettingsSearcha
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private func notificationSearchableItems(context: AccountContext, notifyExceptions: Signal<NotificationExceptionsList?, NoError>) -> [SettingsSearchableItem] {
|
private func notificationSearchableItems(context: AccountContext, exceptionsList: NotificationExceptionsList?) -> [SettingsSearchableItem] {
|
||||||
let icon: SettingsSearchableItemIcon = .notifications
|
let icon: SettingsSearchableItemIcon = .notifications
|
||||||
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
||||||
|
|
||||||
let presentNotificationSettings: (AccountContext, (SettingsSearchableItemPresentation, ViewController) -> Void, NotificationsAndSoundsEntryTag?) -> Void = { context, present, itemTag in
|
let presentNotificationSettings: (AccountContext, (SettingsSearchableItemPresentation, ViewController) -> Void, NotificationsAndSoundsEntryTag?) -> Void = { context, present, itemTag in
|
||||||
present(.push, notificationsAndSoundsController(context: context, exceptionsList: nil, focusOnItemTag: itemTag))
|
present(.push, notificationsAndSoundsController(context: context, exceptionsList: exceptionsList, focusOnItemTag: itemTag))
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -475,7 +476,7 @@ private func appearanceSearchableItems(context: AccountContext) -> [SettingsSear
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
func settingsSearchableItems(context: AccountContext) -> Signal<[SettingsSearchableItem], NoError> {
|
func settingsSearchableItems(context: AccountContext, exceptionsList: Signal<NotificationExceptionsList?, NoError>) -> Signal<[SettingsSearchableItem], NoError> {
|
||||||
let watchAppInstalled = (context.watchManager?.watchAppInstalled ?? .single(false))
|
let watchAppInstalled = (context.watchManager?.watchAppInstalled ?? .single(false))
|
||||||
|> take(1)
|
|> take(1)
|
||||||
let canAddAccount = activeAccountsAndPeers(context: context)
|
let canAddAccount = activeAccountsAndPeers(context: context)
|
||||||
@ -483,8 +484,8 @@ func settingsSearchableItems(context: AccountContext) -> Signal<[SettingsSearcha
|
|||||||
|> map { accountsAndPeers -> Bool in
|
|> map { accountsAndPeers -> Bool in
|
||||||
return accountsAndPeers.1.count + 1 < maximumNumberOfAccounts
|
return accountsAndPeers.1.count + 1 < maximumNumberOfAccounts
|
||||||
}
|
}
|
||||||
return combineLatest(watchAppInstalled, canAddAccount)
|
return combineLatest(watchAppInstalled, canAddAccount, exceptionsList)
|
||||||
|> map { watchAppInstalled, canAddAccount in
|
|> map { watchAppInstalled, canAddAccount, exceptionsList in
|
||||||
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
||||||
|
|
||||||
var allItems: [SettingsSearchableItem] = []
|
var allItems: [SettingsSearchableItem] = []
|
||||||
@ -503,7 +504,7 @@ func settingsSearchableItems(context: AccountContext) -> Signal<[SettingsSearcha
|
|||||||
let stickerItems = stickerSearchableItems(context: context)
|
let stickerItems = stickerSearchableItems(context: context)
|
||||||
allItems.append(contentsOf: stickerItems)
|
allItems.append(contentsOf: stickerItems)
|
||||||
|
|
||||||
let notificationItems = notificationSearchableItems(context: context, notifyExceptions: .complete())
|
let notificationItems = notificationSearchableItems(context: context, exceptionsList: exceptionsList)
|
||||||
allItems.append(contentsOf: notificationItems)
|
allItems.append(contentsOf: notificationItems)
|
||||||
|
|
||||||
let privacyItems = privacySearchableItems(context: context)
|
let privacyItems = privacySearchableItems(context: context)
|
||||||
@ -535,13 +536,25 @@ func settingsSearchableItems(context: AccountContext) -> Signal<[SettingsSearcha
|
|||||||
})
|
})
|
||||||
allItems.append(passport)
|
allItems.append(passport)
|
||||||
|
|
||||||
let support = SettingsSearchableItem(id: .support(0), title: strings.Settings_Support, alternate: ["Support"], icon: .support, breadcrumbs: [], present: { context, _, present in
|
let support = SettingsSearchableItem(id: .support(0), title: strings.Settings_Support, alternate: [], icon: .support, breadcrumbs: [], present: { context, _, present in
|
||||||
//return .push(ChatController(context: context, chatLocation: .peer(context.account.peerId)))
|
let _ = (supportPeerId(account: context.account)
|
||||||
|
|> deliverOnMainQueue).start(next: { peerId in
|
||||||
|
if let peerId = peerId {
|
||||||
|
present(.push, ChatController(context: context, chatLocation: .peer(peerId)))
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
allItems.append(support)
|
allItems.append(support)
|
||||||
|
|
||||||
let faq = SettingsSearchableItem(id: .faq(0), title: strings.Settings_FAQ, alternate: [], icon: .faq, breadcrumbs: [], present: { context, _, present in
|
let faq = SettingsSearchableItem(id: .faq(0), title: strings.Settings_FAQ, alternate: [], icon: .faq, breadcrumbs: [], present: { context, navigationController, present in
|
||||||
//return .push(ChatController(context: context, chatLocation: .peer(context.account.peerId)))
|
|
||||||
|
let _ = (cachedFaqInstantPage(context: context)
|
||||||
|
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
||||||
|
openResolvedUrl(resolvedUrl, context: context, navigationController: navigationController, openPeer: { peer, navigation in
|
||||||
|
}, present: { controller, arguments in
|
||||||
|
present(.push, controller)
|
||||||
|
}, dismissInput: {})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
allItems.append(faq)
|
allItems.append(faq)
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ private final class SoftwareVideoThumbnailLayerNullAction: NSObject, CAAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class SoftwareVideoThumbnailLayer: CALayer {
|
final class SoftwareVideoThumbnailLayer: CALayer {
|
||||||
var disposable: Disposable?
|
var disposable = MetaDisposable()
|
||||||
|
|
||||||
var ready: (() -> Void)? {
|
var ready: (() -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
@ -28,8 +28,7 @@ final class SoftwareVideoThumbnailLayer: CALayer {
|
|||||||
self.masksToBounds = true
|
self.masksToBounds = true
|
||||||
|
|
||||||
if let dimensions = fileReference.media.dimensions {
|
if let dimensions = fileReference.media.dimensions {
|
||||||
self.disposable = (mediaGridMessageVideo(postbox: account.postbox, videoReference: fileReference)
|
self.disposable.set((mediaGridMessageVideo(postbox: account.postbox, videoReference: fileReference)).start(next: { [weak self] transform in
|
||||||
|> deliverOn(Queue.concurrentDefaultQueue())).start(next: { [weak self] transform in
|
|
||||||
var boundingSize = dimensions.aspectFilled(CGSize(width: 93.0, height: 93.0))
|
var boundingSize = dimensions.aspectFilled(CGSize(width: 93.0, height: 93.0))
|
||||||
let imageSize = boundingSize
|
let imageSize = boundingSize
|
||||||
boundingSize.width = min(200.0, boundingSize.width)
|
boundingSize.width = min(200.0, boundingSize.width)
|
||||||
@ -42,7 +41,7 @@ final class SoftwareVideoThumbnailLayer: CALayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ final class SoftwareVideoThumbnailLayer: CALayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.disposable?.dispose()
|
self.disposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func action(forKey event: String) -> CAAction? {
|
override func action(forKey event: String) -> CAAction? {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user