mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Restore iOS 13 features commit
This commit is contained in:
parent
61f71dfcb2
commit
279b1304c7
@ -1,17 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11163.2" systemVersion="16A239j" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11133"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="O8c-13-3vw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<view contentMode="scaleToFill" interfaceStyle="light" id="O8c-13-3vw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<point key="canvasLocation" x="139" y="117"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
|
@ -5029,3 +5029,11 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"TwoFactorSetup.Done.Title" = "Password Set!";
|
||||
"TwoFactorSetup.Done.Text" = "Now password will be required when you log in on a new device in addition to the code you get via SMS.";
|
||||
"TwoFactorSetup.Done.Action" = "Return to Settings";
|
||||
|
||||
"AutoNightTheme.System" = "System";
|
||||
|
||||
"ChatSettings.OpenLinksIn" = "Open Links in";
|
||||
|
||||
"WebBrowser.Title" = "Web Browser";
|
||||
"WebBrowser.DefaultBrowser" = "DEFAULT WEB BROWSER";
|
||||
"WebBrowser.InAppSafari" = "In-App Safari";
|
||||
|
@ -9,8 +9,9 @@ public final class GalleryControllerActionInteraction {
|
||||
public let openHashtag: (String?, String) -> Void
|
||||
public let openBotCommand: (String) -> Void
|
||||
public let addContact: (String) -> Void
|
||||
|
||||
public init(openUrl: @escaping (String, Bool) -> Void, openUrlIn: @escaping (String) -> Void, openPeerMention: @escaping (String) -> Void, openPeer: @escaping (PeerId) -> Void, openHashtag: @escaping (String?, String) -> Void, openBotCommand: @escaping (String) -> Void, addContact: @escaping (String) -> Void) {
|
||||
public let storeMediaPlaybackState: (MessageId, Double?) -> Void
|
||||
|
||||
public init(openUrl: @escaping (String, Bool) -> Void, openUrlIn: @escaping (String) -> Void, openPeerMention: @escaping (String) -> Void, openPeer: @escaping (PeerId) -> Void, openHashtag: @escaping (String?, String) -> Void, openBotCommand: @escaping (String) -> Void, addContact: @escaping (String) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?) -> Void) {
|
||||
self.openUrl = openUrl
|
||||
self.openUrlIn = openUrlIn
|
||||
self.openPeerMention = openPeerMention
|
||||
@ -18,5 +19,6 @@ public final class GalleryControllerActionInteraction {
|
||||
self.openHashtag = openHashtag
|
||||
self.openBotCommand = openBotCommand
|
||||
self.addContact = addContact
|
||||
self.storeMediaPlaybackState = storeMediaPlaybackState
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ public func peerAvatarImageData(account: Account, peer: Peer, authorOfMessage: M
|
||||
}
|
||||
}
|
||||
|
||||
public func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), inset: CGFloat = 0.0, emptyColor: UIColor? = nil, synchronousLoad: Bool = false) -> Signal<UIImage?, NoError>? {
|
||||
public func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), round: Bool = true, inset: CGFloat = 0.0, emptyColor: UIColor? = nil, synchronousLoad: Bool = false) -> Signal<UIImage?, NoError>? {
|
||||
if let imageData = peerAvatarImageData(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation, synchronousLoad: synchronousLoad) {
|
||||
return imageData
|
||||
|> mapToSignal { data -> Signal<UIImage?, NoError> in
|
||||
@ -78,19 +78,29 @@ public func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: Messa
|
||||
context.clear(CGRect(origin: CGPoint(), size: displayDimensions))
|
||||
context.setBlendMode(.copy)
|
||||
context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
context.setBlendMode(.destinationOut)
|
||||
context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
if round {
|
||||
context.setBlendMode(.destinationOut)
|
||||
context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
}
|
||||
} else {
|
||||
if let emptyColor = emptyColor {
|
||||
context.clear(CGRect(origin: CGPoint(), size: displayDimensions))
|
||||
context.setFillColor(emptyColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
if round {
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
} else {
|
||||
context.fill(CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let emptyColor = emptyColor {
|
||||
context.clear(CGRect(origin: CGPoint(), size: displayDimensions))
|
||||
context.setFillColor(emptyColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
if round {
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
} else {
|
||||
context.fill(CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset))
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ public func childWindowHostView(parent: UIView) -> WindowHostView {
|
||||
|
||||
let hostView = WindowHostView(containerView: view, eventView: view, isRotating: {
|
||||
return false
|
||||
}, updateSupportedInterfaceOrientations: { orientations in
|
||||
}, systemUserInterfaceStyle: .single(.light), updateSupportedInterfaceOrientations: { orientations in
|
||||
}, updateDeferScreenEdgeGestures: { edges in
|
||||
}, updatePrefersOnScreenNavigationHidden: { value in
|
||||
})
|
||||
|
@ -12,6 +12,21 @@ private let defaultOrientations: UIInterfaceOrientationMask = {
|
||||
}
|
||||
}()
|
||||
|
||||
public enum WindowUserInterfaceStyle {
|
||||
case light
|
||||
case dark
|
||||
|
||||
@available(iOS 12.0, *)
|
||||
fileprivate init(style: UIUserInterfaceStyle) {
|
||||
switch style {
|
||||
case .light, .unspecified:
|
||||
self = .light
|
||||
case .dark:
|
||||
self = .dark
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class PreviewingHostViewDelegate {
|
||||
public let controllerForLocation: (UIView, CGPoint) -> (UIViewController, CGRect)?
|
||||
public let commitController: (UIViewController) -> Void
|
||||
@ -59,6 +74,11 @@ private final class WindowRootViewController: UIViewController, UIViewController
|
||||
var presentController: ((UIViewController, PresentationSurfaceLevel, Bool, (() -> Void)?) -> Void)?
|
||||
var transitionToSize: ((CGSize, Double) -> Void)?
|
||||
|
||||
private var _systemUserInterfaceStyle = ValuePromise<WindowUserInterfaceStyle>(ignoreRepeated: true)
|
||||
var systemUserInterfaceStyle: Signal<WindowUserInterfaceStyle, NoError> {
|
||||
return self._systemUserInterfaceStyle.get()
|
||||
}
|
||||
|
||||
var orientations: UIInterfaceOrientationMask = defaultOrientations {
|
||||
didSet {
|
||||
if oldValue != self.orientations {
|
||||
@ -106,6 +126,12 @@ private final class WindowRootViewController: UIViewController, UIViewController
|
||||
return orientations
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
if #available(iOS 12.0, *) {
|
||||
self._systemUserInterfaceStyle.set(WindowUserInterfaceStyle(style: self.traitCollection.userInterfaceStyle))
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
@ -118,6 +144,12 @@ private final class WindowRootViewController: UIViewController, UIViewController
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
self._systemUserInterfaceStyle.set(WindowUserInterfaceStyle(style: self.traitCollection.userInterfaceStyle))
|
||||
} else {
|
||||
self._systemUserInterfaceStyle.set(.light)
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
@ -350,7 +382,7 @@ public func nativeWindowHostView() -> (UIWindow & WindowHost, WindowHostView) {
|
||||
|
||||
let hostView = WindowHostView(containerView: rootViewController.view, eventView: window, isRotating: {
|
||||
return window.isRotating()
|
||||
}, updateSupportedInterfaceOrientations: { orientations in
|
||||
}, systemUserInterfaceStyle: rootViewController.systemUserInterfaceStyle, updateSupportedInterfaceOrientations: { orientations in
|
||||
rootViewController.orientations = orientations
|
||||
}, updateDeferScreenEdgeGestures: { edges in
|
||||
rootViewController.gestureEdges = edges
|
||||
|
@ -203,6 +203,7 @@ public final class WindowHostView {
|
||||
public let containerView: UIView
|
||||
public let eventView: UIView
|
||||
public let isRotating: () -> Bool
|
||||
public let systemUserInterfaceStyle: Signal<WindowUserInterfaceStyle, NoError>
|
||||
|
||||
let updateSupportedInterfaceOrientations: (UIInterfaceOrientationMask) -> Void
|
||||
let updateDeferScreenEdgeGestures: (UIRectEdge) -> Void
|
||||
@ -224,10 +225,11 @@ public final class WindowHostView {
|
||||
var forEachController: (((ContainableController) -> Void) -> Void)?
|
||||
var getAccessibilityElements: (() -> [Any]?)?
|
||||
|
||||
init(containerView: UIView, eventView: UIView, isRotating: @escaping () -> Bool, updateSupportedInterfaceOrientations: @escaping (UIInterfaceOrientationMask) -> Void, updateDeferScreenEdgeGestures: @escaping (UIRectEdge) -> Void, updatePrefersOnScreenNavigationHidden: @escaping (Bool) -> Void) {
|
||||
init(containerView: UIView, eventView: UIView, isRotating: @escaping () -> Bool, systemUserInterfaceStyle: Signal<WindowUserInterfaceStyle, NoError>, updateSupportedInterfaceOrientations: @escaping (UIInterfaceOrientationMask) -> Void, updateDeferScreenEdgeGestures: @escaping (UIRectEdge) -> Void, updatePrefersOnScreenNavigationHidden: @escaping (Bool) -> Void) {
|
||||
self.containerView = containerView
|
||||
self.eventView = eventView
|
||||
self.isRotating = isRotating
|
||||
self.systemUserInterfaceStyle = systemUserInterfaceStyle
|
||||
self.updateSupportedInterfaceOrientations = updateSupportedInterfaceOrientations
|
||||
self.updateDeferScreenEdgeGestures = updateDeferScreenEdgeGestures
|
||||
self.updatePrefersOnScreenNavigationHidden = updatePrefersOnScreenNavigationHidden
|
||||
@ -317,6 +319,8 @@ public class Window1 {
|
||||
}
|
||||
}
|
||||
|
||||
public let systemUserInterfaceStyle: Signal<WindowUserInterfaceStyle, NoError>
|
||||
|
||||
private var windowPanRecognizer: WindowPanRecognizer?
|
||||
private let keyboardGestureRecognizerDelegate = WindowKeyboardGestureRecognizerDelegate()
|
||||
private var keyboardGestureBeginLocation: CGPoint?
|
||||
@ -331,6 +335,7 @@ public class Window1 {
|
||||
|
||||
public init(hostView: WindowHostView, statusBarHost: StatusBarHost?) {
|
||||
self.hostView = hostView
|
||||
self.systemUserInterfaceStyle = hostView.systemUserInterfaceStyle
|
||||
|
||||
let boundsSize = self.hostView.eventView.bounds.size
|
||||
self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHost?.statusBarFrame.height ?? defaultStatusBarHeight, onScreenNavigationHeight: self.hostView.onScreenNavigationHeight)
|
||||
|
@ -140,7 +140,7 @@ private func galleryMessageCaptionText(_ message: Message) -> String {
|
||||
return message.text
|
||||
}
|
||||
|
||||
public func galleryItemForEntry(context: AccountContext, presentationData: PresentationData, entry: MessageHistoryEntry, isCentral: Bool = false, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, tempFilePath: String? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }) -> GalleryItem? {
|
||||
public func galleryItemForEntry(context: AccountContext, presentationData: PresentationData, entry: MessageHistoryEntry, isCentral: Bool = false, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, tempFilePath: String? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, storeMediaPlaybackState: @escaping (MessageId, Double?) -> Void = { _, _ in }) -> GalleryItem? {
|
||||
let message = entry.message
|
||||
let location = entry.location
|
||||
if let (media, mediaImage) = mediaForMessage(message: message) {
|
||||
@ -173,7 +173,7 @@ public func galleryItemForEntry(context: AccountContext, presentationData: Prese
|
||||
}
|
||||
|
||||
let caption = galleryCaptionStringWithAppliedEntities(text, entities: entities)
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: caption, hideControls: hideControls, fromPlayingVideo: fromPlayingVideo, landscape: landscape, timecode: timecode, playbackCompleted: playbackCompleted, performAction: performAction, openActionOptions: openActionOptions)
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: caption, hideControls: hideControls, fromPlayingVideo: fromPlayingVideo, landscape: landscape, timecode: timecode, playbackCompleted: playbackCompleted, performAction: performAction, openActionOptions: openActionOptions, storeMediaPlaybackState: storeMediaPlaybackState)
|
||||
} else {
|
||||
if let fileName = file.fileName, (fileName as NSString).pathExtension.lowercased() == "json" {
|
||||
return ChatAnimationGalleryItem(context: context, presentationData: presentationData, message: message, location: location)
|
||||
@ -212,7 +212,7 @@ public func galleryItemForEntry(context: AccountContext, presentationData: Prese
|
||||
}
|
||||
}
|
||||
if let content = content {
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, timecode: timecode, performAction: performAction, openActionOptions: openActionOptions)
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, timecode: timecode, performAction: performAction, openActionOptions: openActionOptions, storeMediaPlaybackState: storeMediaPlaybackState)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -435,7 +435,7 @@ public class GalleryController: ViewController, StandalonePresentableController
|
||||
if entry.message.stableId == strongSelf.centralEntryStableId {
|
||||
isCentral = true
|
||||
}
|
||||
if let item = galleryItemForEntry(context: context, presentationData: strongSelf.presentationData, entry: entry, isCentral: isCentral, streamVideos: streamSingleVideo, fromPlayingVideo: isCentral && fromPlayingVideo, landscape: isCentral && landscape, timecode: isCentral ? timecode : nil, performAction: strongSelf.performAction, openActionOptions: strongSelf.openActionOptions) {
|
||||
if let item = galleryItemForEntry(context: context, presentationData: strongSelf.presentationData, entry: entry, isCentral: isCentral, streamVideos: streamSingleVideo, fromPlayingVideo: isCentral && fromPlayingVideo, landscape: isCentral && landscape, timecode: isCentral ? timecode : nil, performAction: strongSelf.performAction, openActionOptions: strongSelf.openActionOptions, storeMediaPlaybackState: strongSelf.actionInteraction?.storeMediaPlaybackState ?? { _, _ in }) {
|
||||
if isCentral {
|
||||
centralItemIndex = items.count
|
||||
}
|
||||
@ -857,7 +857,7 @@ public class GalleryController: ViewController, StandalonePresentableController
|
||||
if entry.message.stableId == self.centralEntryStableId {
|
||||
isCentral = true
|
||||
}
|
||||
if let item = galleryItemForEntry(context: self.context, presentationData: self.presentationData, entry: entry, streamVideos: self.streamVideos, fromPlayingVideo: isCentral && self.fromPlayingVideo, landscape: isCentral && self.landscape, timecode: isCentral ? self.timecode : nil, performAction: self.performAction, openActionOptions: self.openActionOptions) {
|
||||
if let item = galleryItemForEntry(context: self.context, presentationData: self.presentationData, entry: entry, streamVideos: self.streamVideos, fromPlayingVideo: isCentral && self.fromPlayingVideo, landscape: isCentral && self.landscape, timecode: isCentral ? self.timecode : nil, performAction: self.performAction, openActionOptions: self.openActionOptions, storeMediaPlaybackState: self.actionInteraction?.storeMediaPlaybackState ?? { _, _ in }) {
|
||||
if isCentral {
|
||||
centralItemIndex = items.count
|
||||
}
|
||||
|
@ -34,8 +34,9 @@ public class UniversalVideoGalleryItem: GalleryItem {
|
||||
let playbackCompleted: () -> Void
|
||||
let performAction: (GalleryControllerInteractionTapAction) -> Void
|
||||
let openActionOptions: (GalleryControllerInteractionTapAction) -> Void
|
||||
|
||||
public init(context: AccountContext, presentationData: PresentationData, content: UniversalVideoContent, originData: GalleryItemOriginData?, indexData: GalleryItemIndexData?, contentInfo: UniversalVideoGalleryItemContentInfo?, caption: NSAttributedString, credit: NSAttributedString? = nil, hideControls: Bool = false, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void) {
|
||||
let storeMediaPlaybackState: (MessageId, Double?) -> Void
|
||||
|
||||
public init(context: AccountContext, presentationData: PresentationData, content: UniversalVideoContent, originData: GalleryItemOriginData?, indexData: GalleryItemIndexData?, contentInfo: UniversalVideoGalleryItemContentInfo?, caption: NSAttributedString, credit: NSAttributedString? = nil, hideControls: Bool = false, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?) -> Void) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.content = content
|
||||
@ -51,6 +52,7 @@ public class UniversalVideoGalleryItem: GalleryItem {
|
||||
self.playbackCompleted = playbackCompleted
|
||||
self.performAction = performAction
|
||||
self.openActionOptions = openActionOptions
|
||||
self.storeMediaPlaybackState = storeMediaPlaybackState
|
||||
}
|
||||
|
||||
public func node() -> GalleryItemNode {
|
||||
@ -179,7 +181,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
private var item: UniversalVideoGalleryItem?
|
||||
|
||||
private let statusDisposable = MetaDisposable()
|
||||
|
||||
private let mediaPlaybackStateDisposable = MetaDisposable()
|
||||
|
||||
private let fetchDisposable = MetaDisposable()
|
||||
private var fetchStatus: MediaResourceStatus?
|
||||
private var fetchControls: FetchControls?
|
||||
@ -304,6 +307,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
deinit {
|
||||
self.statusDisposable.dispose()
|
||||
self.mediaPlaybackStateDisposable.dispose()
|
||||
self.scrubbingFrameDisposable?.dispose()
|
||||
}
|
||||
|
||||
@ -401,6 +405,21 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
if let contentInfo = item.contentInfo, case let .message(message) = contentInfo {
|
||||
if Namespaces.Message.allScheduled.contains(message.id.namespace) {
|
||||
disablePictureInPicture = true
|
||||
} else {
|
||||
let throttledSignal = videoNode.status
|
||||
|> mapToThrottled { next -> Signal<MediaPlayerStatus?, NoError> in
|
||||
return .single(next) |> then(.complete() |> delay(4.0, queue: Queue.concurrentDefaultQueue()))
|
||||
}
|
||||
|
||||
self.mediaPlaybackStateDisposable.set(throttledSignal.start(next: { status in
|
||||
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
|
||||
}
|
||||
item.storeMediaPlaybackState(message.id, timestamp)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
var file: TelegramMediaFile?
|
||||
|
@ -113,7 +113,7 @@ public struct InstantPageGalleryEntry: Equatable {
|
||||
nativeId = .instantPage(self.pageId, file.fileId)
|
||||
}
|
||||
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: nativeId, fileReference: .webPage(webPage: WebpageReference(webPage), media: file), streamVideo: isMediaStreamable(media: file) ? .conservative : .none), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in })
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: nativeId, fileReference: .webPage(webPage: WebpageReference(webPage), media: file), streamVideo: isMediaStreamable(media: file) ? .conservative : .none), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _ in })
|
||||
} else {
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
representations.append(contentsOf: file.previewRepresentations)
|
||||
@ -125,7 +125,7 @@ public struct InstantPageGalleryEntry: Equatable {
|
||||
}
|
||||
} else if let embedWebpage = self.media.media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = embedWebpage.content {
|
||||
if let content = WebEmbedVideoContent(webPage: embedWebpage, webpageContent: webpageContent) {
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in })
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, performAction: { _ in }, openActionOptions: { _ in }, storeMediaPlaybackState: { _, _ in })
|
||||
} else {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
@ -285,10 +285,10 @@ func instantPageThemeTypeForSettingsAndTime(themeSettings: PresentationThemeSett
|
||||
|
||||
var fallback = true
|
||||
if let themeSettings = themeSettings {
|
||||
if case .none = themeSettings.automaticThemeSwitchSetting.trigger {
|
||||
if case .explicitNone = themeSettings.automaticThemeSwitchSetting.trigger {
|
||||
} else {
|
||||
fallback = false
|
||||
useDarkTheme = automaticThemeShouldSwitchNow(settings: themeSettings.automaticThemeSwitchSetting, currentTheme: themeSettings.theme)
|
||||
useDarkTheme = automaticThemeShouldSwitchNow(settings: themeSettings.automaticThemeSwitchSetting, systemUserInterfaceStyle: .light)
|
||||
}
|
||||
}
|
||||
if fallback, let time = time {
|
||||
|
@ -25,10 +25,12 @@ public enum OpenInAction {
|
||||
}
|
||||
|
||||
public final class OpenInOption {
|
||||
public let identifier: String
|
||||
public let application: OpenInApplication
|
||||
public let action: () -> OpenInAction
|
||||
|
||||
public init(application: OpenInApplication, action: @escaping () -> OpenInAction) {
|
||||
public init(identifier: String, application: OpenInApplication, action: @escaping () -> OpenInAction) {
|
||||
self.identifier = identifier
|
||||
self.application = application
|
||||
self.action = action
|
||||
}
|
||||
@ -61,11 +63,11 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
var options: [OpenInOption] = []
|
||||
switch item {
|
||||
case let .url(url):
|
||||
options.append(OpenInOption(application: .safari, action: {
|
||||
options.append(OpenInOption(identifier: "safari", application: .safari, action: {
|
||||
return .openUrl(url: url)
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Chrome", identifier: 535886823, scheme: "googlechrome", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "chrome", application: .other(title: "Chrome", identifier: 535886823, scheme: "googlechrome", store: nil), action: {
|
||||
if let url = URL(string: url), var components = URLComponents(url: url, resolvingAgainstBaseURL: true) {
|
||||
components.scheme = components.scheme == "https" ? "googlechromes" : "googlechrome"
|
||||
if let url = components.string {
|
||||
@ -75,21 +77,21 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
return .none
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Firefox", identifier: 989804926, scheme: "firefox", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "firefox", application: .other(title: "Firefox", identifier: 989804926, scheme: "firefox", store: nil), action: {
|
||||
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) {
|
||||
return .openUrl(url: "firefox://open-url?url=\(escapedUrl)")
|
||||
}
|
||||
return .none
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Firefox Focus", identifier: 1055677337, scheme: "firefox-focus", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "firefoxFocus", application: .other(title: "Firefox Focus", identifier: 1055677337, scheme: "firefox-focus", store: nil), action: {
|
||||
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) {
|
||||
return .openUrl(url: "firefox-focus://open-url?url=\(escapedUrl)")
|
||||
}
|
||||
return .none
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Opera Mini", identifier: 363729560, scheme: "opera-http", store: "es"), action: {
|
||||
options.append(OpenInOption(identifier: "operaMini", application: .other(title: "Opera Mini", identifier: 363729560, scheme: "opera-http", store: "es"), action: {
|
||||
if let url = URL(string: url), var components = URLComponents(url: url, resolvingAgainstBaseURL: true) {
|
||||
components.scheme = components.scheme == "https" ? "opera-https" : "opera-http"
|
||||
if let url = components.string {
|
||||
@ -99,7 +101,7 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
return .none
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Opera Touch", identifier: 1411869974, scheme: "touch-http", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "operaTouch", application: .other(title: "Opera Touch", identifier: 1411869974, scheme: "touch-http", store: nil), action: {
|
||||
if let url = URL(string: url), var components = URLComponents(url: url, resolvingAgainstBaseURL: true) {
|
||||
components.scheme = components.scheme == "https" ? "touch-https" : "touch-http"
|
||||
if let url = components.string {
|
||||
@ -109,14 +111,14 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
return .none
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Yandex", identifier: 483693909, scheme: "yandexbrowser-open-url", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "yandex", application: .other(title: "Yandex", identifier: 483693909, scheme: "yandexbrowser-open-url", store: nil), action: {
|
||||
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) {
|
||||
return .openUrl(url: "yandexbrowser-open-url://\(escapedUrl)")
|
||||
}
|
||||
return .none
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Microsoft Edge", identifier: 1288723196, scheme: "microsoft-edge-http", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "edge", application: .other(title: "Microsoft Edge", identifier: 1288723196, scheme: "microsoft-edge-http", store: nil), action: {
|
||||
if let url = URL(string: url), var components = URLComponents(url: url, resolvingAgainstBaseURL: true) {
|
||||
components.scheme = components.scheme == "https" ? "microsoft-edge-https" : "microsoft-edge-http"
|
||||
if let url = components.string {
|
||||
@ -126,11 +128,11 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
return .none
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "DuckDuckGo", identifier: 663592361, scheme: "ddgQuickLink", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "duckDuckGo", application: .other(title: "DuckDuckGo", identifier: 663592361, scheme: "ddgQuickLink", store: nil), action: {
|
||||
return .openUrl(url: "ddgQuickLink://\(url)")
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Alook Browser", identifier: 1261944766, scheme: "alook", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "alook", application: .other(title: "Alook Browser", identifier: 1261944766, scheme: "alook", store: nil), action: {
|
||||
return .openUrl(url: "alook://\(url)")
|
||||
}))
|
||||
|
||||
@ -140,17 +142,17 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
|
||||
if !withDirections {
|
||||
if let venue = location.venue, let venueId = venue.id, let provider = venue.provider, provider == "foursquare" {
|
||||
options.append(OpenInOption(application: .other(title: "Foursquare", identifier: 306934924, scheme: "foursquare", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "foursquare", application: .other(title: "Foursquare", identifier: 306934924, scheme: "foursquare", store: nil), action: {
|
||||
return .openUrl(url: "foursquare://venues/\(venueId)")
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
options.append(OpenInOption(application: .maps, action: {
|
||||
options.append(OpenInOption(identifier: "appleMaps", application: .maps, action: {
|
||||
return .openLocation(latitude: lat, longitude: lon, withDirections: withDirections)
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Google Maps", identifier: 585027354, scheme: "comgooglemaps-x-callback", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "googleMaps", application: .other(title: "Google Maps", identifier: 585027354, scheme: "comgooglemaps-x-callback", store: nil), action: {
|
||||
let coordinates = "\(lat),\(lon)"
|
||||
if withDirections {
|
||||
return .openUrl(url: "comgooglemaps-x-callback://?daddr=\(coordinates)&directionsmode=driving&x-success=telegram://?resume=true&x-source=Telegram")
|
||||
@ -159,7 +161,7 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
}
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Yandex.Maps", identifier: 313877526, scheme: "yandexmaps", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "yandexMaps", application: .other(title: "Yandex.Maps", identifier: 313877526, scheme: "yandexmaps", store: nil), action: {
|
||||
if withDirections {
|
||||
return .openUrl(url: "yandexmaps://build_route_on_map?lat_to=\(lat)&lon_to=\(lon)")
|
||||
} else {
|
||||
@ -167,7 +169,7 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
}
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Uber", identifier: 368677368, scheme: "uber", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "uber", application: .other(title: "Uber", identifier: 368677368, scheme: "uber", store: nil), action: {
|
||||
let dropoffName: String
|
||||
let dropoffAddress: String
|
||||
if let title = location.venue?.title.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), title.count > 0 {
|
||||
@ -183,12 +185,12 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
return .openUrl(url: "uber://?client_id=&action=setPickup&pickup=my_location&dropoff[latitude]=\(lat)&dropoff[longitude]=\(lon)&dropoff[nickname]=\(dropoffName)&dropoff[formatted_address]=\(dropoffAddress)")
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Lyft", identifier: 529379082, scheme: "lyft", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "lyft", application: .other(title: "Lyft", identifier: 529379082, scheme: "lyft", store: nil), action: {
|
||||
return .openUrl(url: "lyft://ridetype?id=lyft&destination[latitude]=\(lat)&destination[longitude]=\(lon)")
|
||||
}))
|
||||
|
||||
if withDirections {
|
||||
options.append(OpenInOption(application: .other(title: "Citymapper", identifier: 469463298, scheme: "citymapper", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "citymapper", application: .other(title: "Citymapper", identifier: 469463298, scheme: "citymapper", store: nil), action: {
|
||||
let endName: String
|
||||
let endAddress: String
|
||||
if let title = location.venue?.title.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), title.count > 0 {
|
||||
@ -204,12 +206,12 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
return .openUrl(url: "citymapper://directions?endcoord=\(lat),\(lon)&endname=\(endName)&endaddress=\(endAddress)")
|
||||
}))
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Yandex.Navi", identifier: 474500851, scheme: "yandexnavi", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "yandexNavi", application: .other(title: "Yandex.Navi", identifier: 474500851, scheme: "yandexnavi", store: nil), action: {
|
||||
return .openUrl(url: "yandexnavi://build_route_on_map?lat_to=\(lat)&lon_to=\(lon)")
|
||||
}))
|
||||
}
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Moovit", identifier: 498477945, scheme: "moovit", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "moovit", application: .other(title: "Moovit", identifier: 498477945, scheme: "moovit", store: nil), action: {
|
||||
if withDirections {
|
||||
let destName: String
|
||||
if let title = location.venue?.title.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), title.count > 0 {
|
||||
@ -224,12 +226,12 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
}))
|
||||
|
||||
if !withDirections {
|
||||
options.append(OpenInOption(application: .other(title: "HERE Maps", identifier: 955837609, scheme: "here-location", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "hereMaps", application: .other(title: "HERE Maps", identifier: 955837609, scheme: "here-location", store: nil), action: {
|
||||
return .openUrl(url: "here-location://\(lat),\(lon)")
|
||||
}))
|
||||
}
|
||||
|
||||
options.append(OpenInOption(application: .other(title: "Waze", identifier: 323229106, scheme: "waze", store: nil), action: {
|
||||
options.append(OpenInOption(identifier: "waze", application: .other(title: "Waze", identifier: 323229106, scheme: "waze", store: nil), action: {
|
||||
let url = "waze://?ll=\(lat),\(lon)"
|
||||
if withDirections {
|
||||
return .openUrl(url: url.appending("&navigate=yes"))
|
||||
|
@ -83,6 +83,7 @@ static_library(
|
||||
"//submodules/UndoUI:UndoUI",
|
||||
"//submodules/DeleteChatPeerActionSheetItem:DeleteChatPeerActionSheetItem",
|
||||
"//submodules/PhoneNumberFormat:PhoneNumberFormat",
|
||||
"//submodules/OpenInExternalAppUI:OpenInExternalAppUI",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -11,6 +11,7 @@ import TelegramUIPreferences
|
||||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import OpenInExternalAppUI
|
||||
|
||||
private final class DataAndStorageControllerArguments {
|
||||
let openStorageUsage: () -> Void
|
||||
@ -24,8 +25,9 @@ private final class DataAndStorageControllerArguments {
|
||||
let toggleAutoplayGifs: (Bool) -> Void
|
||||
let toggleAutoplayVideos: (Bool) -> Void
|
||||
let toggleDownloadInBackground: (Bool) -> Void
|
||||
|
||||
init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, openVoiceUseLessData: @escaping () -> Void, openSaveIncomingPhotos: @escaping () -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, toggleAutoplayGifs: @escaping (Bool) -> Void, toggleAutoplayVideos: @escaping (Bool) -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void) {
|
||||
let openBrowserSelection: () -> Void
|
||||
|
||||
init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, openVoiceUseLessData: @escaping () -> Void, openSaveIncomingPhotos: @escaping () -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, toggleAutoplayGifs: @escaping (Bool) -> Void, toggleAutoplayVideos: @escaping (Bool) -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void) {
|
||||
self.openStorageUsage = openStorageUsage
|
||||
self.openNetworkUsage = openNetworkUsage
|
||||
self.openProxy = openProxy
|
||||
@ -37,6 +39,7 @@ private final class DataAndStorageControllerArguments {
|
||||
self.toggleAutoplayGifs = toggleAutoplayGifs
|
||||
self.toggleAutoplayVideos = toggleAutoplayVideos
|
||||
self.toggleDownloadInBackground = toggleDownloadInBackground
|
||||
self.openBrowserSelection = openBrowserSelection
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +83,7 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
case otherHeader(PresentationTheme, String)
|
||||
case saveIncomingPhotos(PresentationTheme, String)
|
||||
case saveEditedPhotos(PresentationTheme, String, Bool)
|
||||
case openLinksIn(PresentationTheme, String, String)
|
||||
case downloadInBackground(PresentationTheme, String, Bool)
|
||||
case downloadInBackgroundInfo(PresentationTheme, String)
|
||||
case connectionHeader(PresentationTheme, String)
|
||||
@ -95,7 +99,7 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
return DataAndStorageSection.autoPlay.rawValue
|
||||
case .voiceCallsHeader, .useLessVoiceData:
|
||||
return DataAndStorageSection.voiceCalls.rawValue
|
||||
case .otherHeader, .saveIncomingPhotos, .saveEditedPhotos, .downloadInBackground, .downloadInBackgroundInfo:
|
||||
case .otherHeader, .saveIncomingPhotos, .saveEditedPhotos, .openLinksIn, .downloadInBackground, .downloadInBackgroundInfo:
|
||||
return DataAndStorageSection.other.rawValue
|
||||
case .connectionHeader, .connectionProxy:
|
||||
return DataAndStorageSection.connection.rawValue
|
||||
@ -132,14 +136,16 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
return 12
|
||||
case .saveEditedPhotos:
|
||||
return 13
|
||||
case .downloadInBackground:
|
||||
case .openLinksIn:
|
||||
return 14
|
||||
case .downloadInBackgroundInfo:
|
||||
case .downloadInBackground:
|
||||
return 15
|
||||
case .connectionHeader:
|
||||
case .downloadInBackgroundInfo:
|
||||
return 16
|
||||
case .connectionProxy:
|
||||
case .connectionHeader:
|
||||
return 17
|
||||
case .connectionProxy:
|
||||
return 18
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,6 +235,12 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .openLinksIn(lhsTheme, lhsText, lhsValue):
|
||||
if case let .openLinksIn(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .downloadInBackground(lhsTheme, lhsText, lhsValue):
|
||||
if case let .downloadInBackground(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
@ -313,6 +325,10 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleSaveEditedPhotos(value)
|
||||
}, tag: DataAndStorageEntryTag.saveEditedPhotos)
|
||||
case let .openLinksIn(theme, text, value):
|
||||
return ItemListDisclosureItem(theme: theme, title: text, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openBrowserSelection()
|
||||
})
|
||||
case let .downloadInBackground(theme, text, value):
|
||||
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleDownloadInBackground(value)
|
||||
@ -415,7 +431,7 @@ private func stringForAutoDownloadSetting(strings: PresentationStrings, decimalS
|
||||
}
|
||||
}
|
||||
|
||||
private func dataAndStorageControllerEntries(state: DataAndStorageControllerState, data: DataAndStorageData, presentationData: PresentationData) -> [DataAndStorageEntry] {
|
||||
private func dataAndStorageControllerEntries(state: DataAndStorageControllerState, data: DataAndStorageData, presentationData: PresentationData, defaultWebBrowser: String) -> [DataAndStorageEntry] {
|
||||
var entries: [DataAndStorageEntry] = []
|
||||
|
||||
entries.append(.storageUsage(presentationData.theme, presentationData.strings.ChatSettings_Cache))
|
||||
@ -439,6 +455,7 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat
|
||||
entries.append(.otherHeader(presentationData.theme, presentationData.strings.ChatSettings_Other))
|
||||
entries.append(.saveIncomingPhotos(presentationData.theme, presentationData.strings.Settings_SaveIncomingPhotos))
|
||||
entries.append(.saveEditedPhotos(presentationData.theme, presentationData.strings.Settings_SaveEditedPhotos, data.generatedMediaStoreSettings.storeEditedPhotos))
|
||||
entries.append(.openLinksIn(presentationData.theme, presentationData.strings.ChatSettings_OpenLinksIn, defaultWebBrowser))
|
||||
entries.append(.downloadInBackground(presentationData.theme, presentationData.strings.ChatSettings_DownloadInBackground, data.automaticMediaDownloadSettings.downloadInBackground))
|
||||
entries.append(.downloadInBackgroundInfo(presentationData.theme, presentationData.strings.ChatSettings_DownloadInBackgroundInfo))
|
||||
|
||||
@ -558,19 +575,30 @@ func dataAndStorageController(context: AccountContext, focusOnItemTag: DataAndSt
|
||||
settings.autoplayVideos = value
|
||||
return settings
|
||||
}).start()
|
||||
}, toggleDownloadInBackground: { value in
|
||||
}, toggleDownloadInBackground: { value in
|
||||
let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
|
||||
var settings = settings
|
||||
settings.downloadInBackground = value
|
||||
return settings
|
||||
}).start()
|
||||
}, openBrowserSelection: {
|
||||
let controller = webBrowserSettingsController(context: context)
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
|
||||
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), dataAndStorageDataPromise.get()) |> deliverOnMainQueue
|
||||
|> map { presentationData, state, dataAndStorageData -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), dataAndStorageDataPromise.get(), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.webBrowserSettings])) |> deliverOnMainQueue
|
||||
|> map { presentationData, state, dataAndStorageData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let webBrowserSettings = (sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings] as? WebBrowserSettings) ?? WebBrowserSettings.defaultSettings
|
||||
let options = availableOpenInOptions(context: context, item: .url(url: "https://telegram.org"))
|
||||
let defaultWebBrowser: String
|
||||
if let option = options.first(where: { $0.identifier == webBrowserSettings.defaultWebBrowser }) {
|
||||
defaultWebBrowser = option.title
|
||||
} else {
|
||||
defaultWebBrowser = presentationData.strings.WebBrowser_InAppSafari
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.ChatSettings_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: dataAndStorageControllerEntries(state: state, data: dataAndStorageData, presentationData: presentationData), style: .blocks, ensureVisibleItemTag: focusOnItemTag, emptyStateItem: nil, animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: dataAndStorageControllerEntries(state: state, data: dataAndStorageData, presentationData: presentationData, defaultWebBrowser: defaultWebBrowser), style: .blocks, ensureVisibleItemTag: focusOnItemTag, emptyStateItem: nil, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
} |> afterDisposed {
|
||||
|
@ -0,0 +1,124 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import ItemListUI
|
||||
import AccountContext
|
||||
import OpenInExternalAppUI
|
||||
|
||||
private final class WebBrowserSettingsControllerArguments {
|
||||
let updateDefaultBrowser: (String?) -> Void
|
||||
|
||||
init(updateDefaultBrowser: @escaping (String?) -> Void) {
|
||||
self.updateDefaultBrowser = updateDefaultBrowser
|
||||
}
|
||||
}
|
||||
|
||||
private enum WebBrowserSettingsSection: Int32 {
|
||||
case browsers
|
||||
}
|
||||
|
||||
private enum WebBrowserSettingsControllerEntry: ItemListNodeEntry {
|
||||
case browserHeader(PresentationTheme, String)
|
||||
case browser(PresentationTheme, String, String?, Bool, Int32)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .browserHeader, .browser:
|
||||
return WebBrowserSettingsSection.browsers.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
var stableId: Int32 {
|
||||
switch self {
|
||||
case .browserHeader:
|
||||
return 0
|
||||
case let .browser(_, _, _, _, index):
|
||||
return 1 + index
|
||||
}
|
||||
}
|
||||
|
||||
static func ==(lhs: WebBrowserSettingsControllerEntry, rhs: WebBrowserSettingsControllerEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .browserHeader(lhsTheme, lhsText):
|
||||
if case let .browserHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .browser(lhsTheme, lhsTitle, lhsIdentifier, lhsSelected, lhsIndex):
|
||||
if case let .browser(rhsTheme, rhsTitle, rhsIdentifier, rhsSelected, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsIdentifier == rhsIdentifier, lhsSelected == rhsSelected, lhsIndex == rhsIndex {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func <(lhs: WebBrowserSettingsControllerEntry, rhs: WebBrowserSettingsControllerEntry) -> Bool {
|
||||
return lhs.stableId < rhs.stableId
|
||||
}
|
||||
|
||||
func item(_ arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! WebBrowserSettingsControllerArguments
|
||||
switch self {
|
||||
case let .browserHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||
case let .browser(theme, title, identifier, selected, _):
|
||||
return ItemListCheckboxItem(theme: theme, title: title, style: .right, checked: selected, zeroSeparatorInsets: false, sectionId: self.section) {
|
||||
arguments.updateDefaultBrowser(identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func webBrowserSettingsControllerEntries(context: AccountContext, presentationData: PresentationData, selectedBrowser: String?) -> [WebBrowserSettingsControllerEntry] {
|
||||
var entries: [WebBrowserSettingsControllerEntry] = []
|
||||
|
||||
let options = availableOpenInOptions(context: context, item: .url(url: "http://telegram.org"))
|
||||
|
||||
entries.append(.browserHeader(presentationData.theme, presentationData.strings.WebBrowser_DefaultBrowser))
|
||||
entries.append(.browser(presentationData.theme, presentationData.strings.WebBrowser_InAppSafari, nil, selectedBrowser == nil, 0))
|
||||
|
||||
var index: Int32 = 1
|
||||
for option in options {
|
||||
entries.append(.browser(presentationData.theme, option.title, option.identifier, option.identifier == selectedBrowser, index))
|
||||
index += 1
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
public func webBrowserSettingsController(context: AccountContext) -> ViewController {
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
var presentControllerImpl: ((ViewController) -> Void)?
|
||||
|
||||
let updateDisposable = MetaDisposable()
|
||||
let arguments = WebBrowserSettingsControllerArguments(updateDefaultBrowser: { identifier in
|
||||
let _ = updateWebBrowserSettingsInteractively(accountManager: context.sharedContext.accountManager, { $0.withUpdatedDefaultWebBrowser(identifier) }).start()
|
||||
})
|
||||
|
||||
let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.webBrowserSettings]))
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings] as? WebBrowserSettings) ?? WebBrowserSettings.defaultSettings
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.WebBrowser_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(entries: webBrowserSettingsControllerEntries(context: context, presentationData: presentationData, selectedBrowser: settings.defaultWebBrowser), style: .blocks, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
||||
let controller = ItemListController(context: context, state: signal)
|
||||
pushControllerImpl = { [weak controller] c in
|
||||
(controller?.navigationController as? NavigationController)?.pushViewController(c)
|
||||
}
|
||||
presentControllerImpl = { [weak controller] c in
|
||||
controller?.present(c, in: .window(.root))
|
||||
}
|
||||
return controller
|
||||
}
|
@ -16,6 +16,7 @@ import Geocoding
|
||||
import WallpaperResources
|
||||
|
||||
private enum TriggerMode {
|
||||
case system
|
||||
case none
|
||||
case timeBased
|
||||
case brightness
|
||||
@ -53,6 +54,7 @@ private enum ThemeAutoNightSettingsControllerSection: Int32 {
|
||||
}
|
||||
|
||||
private enum ThemeAutoNightSettingsControllerEntry: ItemListNodeEntry {
|
||||
case modeSystem(PresentationTheme, String, Bool)
|
||||
case modeDisabled(PresentationTheme, String, Bool)
|
||||
case modeTimeBased(PresentationTheme, String, Bool)
|
||||
case modeBrightness(PresentationTheme, String, Bool)
|
||||
@ -70,7 +72,7 @@ private enum ThemeAutoNightSettingsControllerEntry: ItemListNodeEntry {
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .modeDisabled, .modeTimeBased, .modeBrightness:
|
||||
case .modeSystem, .modeDisabled, .modeTimeBased, .modeBrightness:
|
||||
return ThemeAutoNightSettingsControllerSection.mode.rawValue
|
||||
case .settingsHeader, .timeBasedAutomaticLocation, .timeBasedAutomaticLocationValue, .timeBasedManualFrom, .timeBasedManualTo, .brightnessValue, .settingInfo:
|
||||
return ThemeAutoNightSettingsControllerSection.settings.rawValue
|
||||
@ -81,35 +83,43 @@ private enum ThemeAutoNightSettingsControllerEntry: ItemListNodeEntry {
|
||||
|
||||
var stableId: Int32 {
|
||||
switch self {
|
||||
case .modeDisabled:
|
||||
case .modeSystem:
|
||||
return 0
|
||||
case .modeTimeBased:
|
||||
case .modeDisabled:
|
||||
return 1
|
||||
case .modeBrightness:
|
||||
case .modeTimeBased:
|
||||
return 2
|
||||
case .settingsHeader:
|
||||
case .modeBrightness:
|
||||
return 3
|
||||
case .timeBasedAutomaticLocation:
|
||||
case .settingsHeader:
|
||||
return 4
|
||||
case .timeBasedAutomaticLocationValue:
|
||||
case .timeBasedAutomaticLocation:
|
||||
return 5
|
||||
case .timeBasedManualFrom:
|
||||
case .timeBasedAutomaticLocationValue:
|
||||
return 6
|
||||
case .timeBasedManualTo:
|
||||
case .timeBasedManualFrom:
|
||||
return 7
|
||||
case .brightnessValue:
|
||||
case .timeBasedManualTo:
|
||||
return 8
|
||||
case .settingInfo:
|
||||
case .brightnessValue:
|
||||
return 9
|
||||
case .themeHeader:
|
||||
case .settingInfo:
|
||||
return 10
|
||||
case .themeItem:
|
||||
case .themeHeader:
|
||||
return 11
|
||||
case .themeItem:
|
||||
return 12
|
||||
}
|
||||
}
|
||||
|
||||
static func ==(lhs: ThemeAutoNightSettingsControllerEntry, rhs: ThemeAutoNightSettingsControllerEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .modeSystem(lhsTheme, lhsTitle, lhsValue):
|
||||
if case let .modeSystem(rhsTheme, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .modeDisabled(lhsTheme, lhsTitle, lhsValue):
|
||||
if case let .modeDisabled(rhsTheme, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue {
|
||||
return true
|
||||
@ -192,6 +202,10 @@ private enum ThemeAutoNightSettingsControllerEntry: ItemListNodeEntry {
|
||||
func item(_ arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! ThemeAutoNightSettingsControllerArguments
|
||||
switch self {
|
||||
case let .modeSystem(theme, title, value):
|
||||
return ItemListCheckboxItem(theme: theme, title: title, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
arguments.updateMode(.system)
|
||||
})
|
||||
case let .modeDisabled(theme, title, value):
|
||||
return ItemListCheckboxItem(theme: theme, title: title, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
arguments.updateMode(.none)
|
||||
@ -243,7 +257,13 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s
|
||||
|
||||
let activeTriggerMode: TriggerMode
|
||||
switch switchSetting.trigger {
|
||||
case .none:
|
||||
case .system:
|
||||
if #available(iOSApplicationExtension 13.0, iOS 13.0, *) {
|
||||
activeTriggerMode = .system
|
||||
} else {
|
||||
activeTriggerMode = .none
|
||||
}
|
||||
case .explicitNone:
|
||||
activeTriggerMode = .none
|
||||
case .timeBased:
|
||||
activeTriggerMode = .timeBased
|
||||
@ -251,12 +271,15 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s
|
||||
activeTriggerMode = .brightness
|
||||
}
|
||||
|
||||
if #available(iOSApplicationExtension 13.0, iOS 13.0, *) {
|
||||
entries.append(.modeSystem(theme, strings.AutoNightTheme_System, activeTriggerMode == .system))
|
||||
}
|
||||
entries.append(.modeDisabled(theme, strings.AutoNightTheme_Disabled, activeTriggerMode == .none))
|
||||
entries.append(.modeTimeBased(theme, strings.AutoNightTheme_Scheduled, activeTriggerMode == .timeBased))
|
||||
entries.append(.modeBrightness(theme, strings.AutoNightTheme_Automatic, activeTriggerMode == .brightness))
|
||||
|
||||
switch switchSetting.trigger {
|
||||
case .none:
|
||||
case .system, .explicitNone:
|
||||
break
|
||||
case let .timeBased(setting):
|
||||
entries.append(.settingsHeader(theme, strings.AutoNightTheme_ScheduleSection))
|
||||
@ -286,9 +309,9 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s
|
||||
}
|
||||
|
||||
switch switchSetting.trigger {
|
||||
case .none:
|
||||
case .explicitNone:
|
||||
break
|
||||
case .timeBased, .brightness:
|
||||
case .system, .timeBased, .brightness:
|
||||
entries.append(.themeHeader(theme, strings.AutoNightTheme_PreferredTheme))
|
||||
entries.append(.themeItem(theme, strings, availableThemes, switchSetting.theme, settings.themeSpecificAccentColors))
|
||||
}
|
||||
@ -305,7 +328,7 @@ private func roundTimeToDay(_ timestamp: Int32) -> Int32 {
|
||||
|
||||
private func areSettingsValid(_ settings: AutomaticThemeSwitchSetting) -> Bool {
|
||||
switch settings.trigger {
|
||||
case .none:
|
||||
case .system, .explicitNone, .brightness:
|
||||
return true
|
||||
case let .timeBased(setting):
|
||||
switch setting {
|
||||
@ -318,8 +341,6 @@ private func areSettingsValid(_ settings: AutomaticThemeSwitchSetting) -> Bool {
|
||||
case .manual:
|
||||
return true
|
||||
}
|
||||
case .brightness:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,8 +407,10 @@ public func themeAutoNightSettingsController(context: AccountContext) -> ViewCon
|
||||
updateSettings { settings in
|
||||
var settings = settings
|
||||
switch mode {
|
||||
case .system:
|
||||
settings.trigger = .system
|
||||
case .none:
|
||||
settings.trigger = .none
|
||||
settings.trigger = .explicitNone
|
||||
case .timeBased:
|
||||
if case .timeBased = settings.trigger {
|
||||
} else {
|
||||
|
@ -366,7 +366,13 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
||||
|
||||
let title: String
|
||||
switch autoNightSettings.trigger {
|
||||
case .none:
|
||||
case .system:
|
||||
if #available(iOSApplicationExtension 13.0, iOS 13.0, *) {
|
||||
title = strings.AutoNightTheme_System
|
||||
} else {
|
||||
title = strings.AutoNightTheme_Disabled
|
||||
}
|
||||
case .explicitNone:
|
||||
title = strings.AutoNightTheme_Disabled
|
||||
case .timeBased:
|
||||
title = strings.AutoNightTheme_Scheduled
|
||||
|
@ -387,7 +387,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
let _ = (updatePresentationThemeSettingsInteractively(accountManager: strongSelf.context.sharedContext.accountManager, { current in
|
||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||
var chatWallpaper = current.chatWallpaper
|
||||
if automaticThemeShouldSwitchNow(settings: current.automaticThemeSwitchSetting, currentTheme: current.theme) {
|
||||
if automaticThemeShouldSwitchNow(settings: current.automaticThemeSwitchSetting, systemUserInterfaceStyle: .light) {
|
||||
themeSpecificChatWallpapers[current.automaticThemeSwitchSetting.theme.index] = wallpaper
|
||||
} else {
|
||||
themeSpecificChatWallpapers[current.theme.index] = wallpaper
|
||||
|
@ -249,7 +249,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager) -
|
||||
var effectiveChatWallpaper: TelegramWallpaper = themeSettings.chatWallpaper
|
||||
|
||||
let parameters = AutomaticThemeSwitchParameters(settings: themeSettings.automaticThemeSwitchSetting)
|
||||
if automaticThemeShouldSwitchNow(parameters, currentTheme: themeSettings.theme) {
|
||||
if automaticThemeShouldSwitchNow(parameters, systemUserInterfaceStyle: .light) {
|
||||
effectiveTheme = themeSettings.automaticThemeSwitchSetting.theme
|
||||
} else {
|
||||
effectiveTheme = themeSettings.theme
|
||||
@ -290,7 +290,8 @@ private func roundTimeToDay(_ timestamp: Int32) -> Int32 {
|
||||
}
|
||||
|
||||
private enum PreparedAutomaticThemeSwitchTrigger {
|
||||
case none
|
||||
case explicitNone
|
||||
case system
|
||||
case time(fromSeconds: Int32, toSeconds: Int32)
|
||||
case brightness(threshold: Double)
|
||||
}
|
||||
@ -302,8 +303,10 @@ private struct AutomaticThemeSwitchParameters {
|
||||
init(settings: AutomaticThemeSwitchSetting) {
|
||||
let trigger: PreparedAutomaticThemeSwitchTrigger
|
||||
switch settings.trigger {
|
||||
case .none:
|
||||
trigger = .none
|
||||
case .system:
|
||||
trigger = .system
|
||||
case .explicitNone:
|
||||
trigger = .explicitNone
|
||||
case let .timeBased(setting):
|
||||
let fromValue: Int32
|
||||
let toValue: Int32
|
||||
@ -325,10 +328,12 @@ private struct AutomaticThemeSwitchParameters {
|
||||
}
|
||||
}
|
||||
|
||||
private func automaticThemeShouldSwitchNow(_ parameters: AutomaticThemeSwitchParameters, currentTheme: PresentationThemeReference) -> Bool {
|
||||
private func automaticThemeShouldSwitchNow(_ parameters: AutomaticThemeSwitchParameters, systemUserInterfaceStyle: WindowUserInterfaceStyle) -> Bool {
|
||||
switch parameters.trigger {
|
||||
case .none:
|
||||
case .explicitNone:
|
||||
return false
|
||||
case .system:
|
||||
return systemUserInterfaceStyle == .dark
|
||||
case let .time(fromValue, toValue):
|
||||
let roundedTimestamp = roundTimeToDay(Int32(Date().timeIntervalSince1970))
|
||||
if roundedTimestamp >= fromValue || roundedTimestamp <= toValue {
|
||||
@ -341,21 +346,21 @@ private func automaticThemeShouldSwitchNow(_ parameters: AutomaticThemeSwitchPar
|
||||
}
|
||||
}
|
||||
|
||||
public func automaticThemeShouldSwitchNow(settings: AutomaticThemeSwitchSetting, currentTheme: PresentationThemeReference) -> Bool {
|
||||
public func automaticThemeShouldSwitchNow(settings: AutomaticThemeSwitchSetting, systemUserInterfaceStyle: WindowUserInterfaceStyle) -> Bool {
|
||||
let parameters = AutomaticThemeSwitchParameters(settings: settings)
|
||||
return automaticThemeShouldSwitchNow(parameters, currentTheme: currentTheme)
|
||||
return automaticThemeShouldSwitchNow(parameters, systemUserInterfaceStyle: systemUserInterfaceStyle)
|
||||
}
|
||||
|
||||
private func automaticThemeShouldSwitch(_ settings: AutomaticThemeSwitchSetting, currentTheme: PresentationThemeReference) -> Signal<Bool, NoError> {
|
||||
if case .none = settings.trigger {
|
||||
private func automaticThemeShouldSwitch(_ settings: AutomaticThemeSwitchSetting, systemUserInterfaceStyle: WindowUserInterfaceStyle) -> Signal<Bool, NoError> {
|
||||
if case .explicitNone = settings.trigger {
|
||||
return .single(false)
|
||||
} else {
|
||||
return Signal { subscriber in
|
||||
let parameters = AutomaticThemeSwitchParameters(settings: settings)
|
||||
subscriber.putNext(automaticThemeShouldSwitchNow(parameters, currentTheme: currentTheme))
|
||||
subscriber.putNext(automaticThemeShouldSwitchNow(parameters, systemUserInterfaceStyle: systemUserInterfaceStyle))
|
||||
|
||||
let timer = SwiftSignalKit.Timer(timeout: 1.0, repeat: true, completion: {
|
||||
subscriber.putNext(automaticThemeShouldSwitchNow(parameters, currentTheme: currentTheme))
|
||||
subscriber.putNext(automaticThemeShouldSwitchNow(parameters, systemUserInterfaceStyle: systemUserInterfaceStyle))
|
||||
}, queue: Queue.mainQueue())
|
||||
timer.start()
|
||||
|
||||
@ -467,9 +472,9 @@ public func chatServiceBackgroundColor(wallpaper: TelegramWallpaper, mediaBox: M
|
||||
}
|
||||
}
|
||||
|
||||
public func updatedPresentationData(accountManager: AccountManager, applicationInForeground: Signal<Bool, NoError>) -> Signal<PresentationData, NoError> {
|
||||
return accountManager.sharedData(keys: [SharedDataKeys.localizationSettings, ApplicationSpecificSharedDataKeys.presentationThemeSettings, ApplicationSpecificSharedDataKeys.contactSynchronizationSettings])
|
||||
|> mapToSignal { sharedData -> Signal<PresentationData, NoError> in
|
||||
public func updatedPresentationData(accountManager: AccountManager, applicationInForeground: Signal<Bool, NoError>, systemUserInterfaceStyle: Signal<WindowUserInterfaceStyle, NoError>) -> Signal<PresentationData, NoError> {
|
||||
return combineLatest(accountManager.sharedData(keys: [SharedDataKeys.localizationSettings, ApplicationSpecificSharedDataKeys.presentationThemeSettings, ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]), systemUserInterfaceStyle)
|
||||
|> mapToSignal { sharedData, systemUserInterfaceStyle -> Signal<PresentationData, NoError> in
|
||||
let themeSettings: PresentationThemeSettings
|
||||
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings {
|
||||
themeSettings = current
|
||||
@ -492,7 +497,7 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
||||
return applicationInForeground
|
||||
|> mapToSignal { inForeground -> Signal<PresentationData, NoError> in
|
||||
if inForeground {
|
||||
return automaticThemeShouldSwitch(themeSettings.automaticThemeSwitchSetting, currentTheme: themeSettings.theme)
|
||||
return automaticThemeShouldSwitch(themeSettings.automaticThemeSwitchSetting, systemUserInterfaceStyle: systemUserInterfaceStyle)
|
||||
|> distinctUntilChanged
|
||||
|> map { shouldSwitch in
|
||||
var effectiveTheme: PresentationThemeReference
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -46,6 +46,7 @@ import PeerInfoUI
|
||||
import RaiseToListen
|
||||
import UrlHandling
|
||||
import ReactionSelectionNode
|
||||
import AvatarNode
|
||||
import MessageReactionListUI
|
||||
import AppBundle
|
||||
import WalletUI
|
||||
@ -527,6 +528,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.addContact(phoneNumber)
|
||||
}
|
||||
}, storeMediaPlaybackState: { [weak self] messageId, timestamp in
|
||||
var storedState: MediaPlaybackStoredState?
|
||||
if let timestamp = timestamp {
|
||||
storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: .x1)
|
||||
}
|
||||
let _ = updateMediaPlaybackStoredStateInteractively(postbox: strongSelf.context.account.postbox, messageId: messageId, state: storedState).start()
|
||||
})))
|
||||
}, openPeer: { [weak self] id, navigation, fromMessage in
|
||||
self?.openPeer(peerId: id, navigation: navigation, fromMessage: fromMessage)
|
||||
@ -2786,7 +2793,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
|
||||
strongSelf.donateIntent()
|
||||
strongSelf.donateSendMessageIntent()
|
||||
}
|
||||
}
|
||||
|
||||
@ -5965,7 +5972,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
|
||||
self.donateIntent()
|
||||
self.donateSendMessageIntent()
|
||||
} else {
|
||||
let mode: ChatScheduleTimeControllerMode
|
||||
if peerId == self.context.account.peerId {
|
||||
@ -8037,17 +8044,32 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
|
||||
private func donateIntent() {
|
||||
private func donateSendMessageIntent() {
|
||||
guard case let .peer(peerId) = self.chatLocation, peerId.namespace == Namespaces.Peer.CloudUser && peerId != context.account.peerId else {
|
||||
return
|
||||
}
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||
let _ = (self.context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
|> mapToSignal { peer -> Signal<(Peer, UIImage?), NoError> in
|
||||
let avatarImage = peerAvatarImage(account: self.context.account, peer: peer, authorOfMessage: nil, representation: peer.smallProfileImage, round: false) ?? .single(nil)
|
||||
|
||||
return avatarImage
|
||||
|> map { avatarImage in
|
||||
return (peer, avatarImage)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer, avatarImage in
|
||||
if let strongSelf = self, let peer = peer as? TelegramUser {
|
||||
let recipientHandle = INPersonHandle(value: "tg\(peerId.id)", type: .unknown)
|
||||
let recipient = INPerson(personHandle: recipientHandle, nameComponents: nil, displayName: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), image: nil, contactIdentifier: nil, customIdentifier: "tg\(peerId.id)")
|
||||
let intent = INSendMessageIntent(recipients: [recipient], content: nil, groupName: nil, serviceName: nil, sender: nil)
|
||||
var nameComponents = PersonNameComponents()
|
||||
nameComponents.givenName = peer.firstName
|
||||
nameComponents.familyName = peer.lastName
|
||||
let displayTitle = peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
|
||||
let recipient = INPerson(personHandle: recipientHandle, nameComponents: nameComponents, displayName: displayTitle, image: nil, contactIdentifier: nil, customIdentifier: "tg\(peerId.id)")
|
||||
let intent = INSendMessageIntent(recipients: [recipient], content: nil, speakableGroupName: INSpeakableString(spokenPhrase: displayTitle), conversationIdentifier: "tg\(peerId.id)", serviceName: nil, sender: nil)
|
||||
if #available(iOS 12.0, *), let avatarImage = avatarImage, let avatarImageData = avatarImage.jpegData(compressionQuality: 0.8) {
|
||||
intent.setImage(INImage(imageData: avatarImageData), forParameterNamed: \.groupName)
|
||||
}
|
||||
let interaction = INInteraction(intent: intent, response: nil)
|
||||
interaction.direction = .outgoing
|
||||
interaction.donate { error in
|
||||
|
@ -50,6 +50,7 @@ private var telegramUIDeclaredEncodables: Void = {
|
||||
declareEncodable(VoipDerivedState.self, f: { VoipDerivedState(decoder: $0) })
|
||||
declareEncodable(ChatArchiveSettings.self, f: { ChatArchiveSettings(decoder: $0) })
|
||||
declareEncodable(MediaPlaybackStoredState.self, f: { MediaPlaybackStoredState(decoder: $0) })
|
||||
declareEncodable(WebBrowserSettings.self, f: { WebBrowserSettings(decoder: $0) })
|
||||
return
|
||||
}()
|
||||
|
||||
|
@ -29,7 +29,7 @@ private enum ChatMessageGalleryControllerData {
|
||||
case stickerPack(StickerPackReference)
|
||||
case audio(TelegramMediaFile)
|
||||
case document(TelegramMediaFile, Bool)
|
||||
case gallery(GalleryController)
|
||||
case gallery(Signal<GalleryController, NoError>)
|
||||
case secretGallery(SecretMediaPreviewController)
|
||||
case chatAvatars(AvatarGalleryController, Media)
|
||||
case theme(TelegramMediaFile)
|
||||
@ -151,7 +151,7 @@ private func chatMessageGalleryControllerData(context: AccountContext, message:
|
||||
let gallery = GalleryController(context: context, source: .peerMessagesAtId(message.id), invertItemOrder: reverseMessageGalleryOrder, streamSingleVideo: stream, fromPlayingVideo: autoplayingVideo, landscape: landscape, timecode: timecode, synchronousLoad: synchronousLoad, replaceRootController: { [weak navigationController] controller, ready in
|
||||
navigationController?.replaceTopController(controller, animated: false, ready: ready)
|
||||
}, baseNavigationController: navigationController, actionInteraction: actionInteraction)
|
||||
return .gallery(gallery)
|
||||
return .gallery(.single(gallery))
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ private func chatMessageGalleryControllerData(context: AccountContext, message:
|
||||
let gallery = GalleryController(context: context, source: .peerMessagesAtId(message.id), invertItemOrder: reverseMessageGalleryOrder, streamSingleVideo: stream, fromPlayingVideo: autoplayingVideo, landscape: landscape, timecode: timecode, synchronousLoad: synchronousLoad, replaceRootController: { [weak navigationController] controller, ready in
|
||||
navigationController?.replaceTopController(controller, animated: false, ready: ready)
|
||||
}, baseNavigationController: navigationController, actionInteraction: actionInteraction)
|
||||
return .gallery(gallery)
|
||||
return .gallery(.single(gallery))
|
||||
}
|
||||
|
||||
if !file.isVideo {
|
||||
@ -176,11 +176,25 @@ private func chatMessageGalleryControllerData(context: AccountContext, message:
|
||||
let gallery = SecretMediaPreviewController(context: context, messageId: message.id)
|
||||
return .secretGallery(gallery)
|
||||
} else {
|
||||
let gallery = GalleryController(context: context, source: standalone ? .standaloneMessage(message) : .peerMessagesAtId(message.id), invertItemOrder: reverseMessageGalleryOrder, streamSingleVideo: stream, fromPlayingVideo: autoplayingVideo, landscape: landscape, timecode: timecode, synchronousLoad: synchronousLoad, replaceRootController: { [weak navigationController] controller, ready in
|
||||
navigationController?.replaceTopController(controller, animated: false, ready: ready)
|
||||
let startTimecode: Signal<Double?, NoError>
|
||||
if let timecode = timecode {
|
||||
startTimecode = .single(timecode)
|
||||
} else {
|
||||
startTimecode = mediaPlaybackStoredState(postbox: context.account.postbox, messageId: message.id)
|
||||
|> map { state in
|
||||
return state?.timestamp
|
||||
}
|
||||
}
|
||||
|
||||
return .gallery(startTimecode
|
||||
|> deliverOnMainQueue
|
||||
|> map { timecode in
|
||||
let gallery = GalleryController(context: context, source: standalone ? .standaloneMessage(message) : .peerMessagesAtId(message.id), invertItemOrder: reverseMessageGalleryOrder, streamSingleVideo: stream, fromPlayingVideo: autoplayingVideo, landscape: landscape, timecode: timecode, synchronousLoad: synchronousLoad, replaceRootController: { [weak navigationController] controller, ready in
|
||||
navigationController?.replaceTopController(controller, animated: false, ready: ready)
|
||||
}, baseNavigationController: navigationController, actionInteraction: actionInteraction)
|
||||
gallery.temporaryDoNotWaitForReady = autoplayingVideo
|
||||
return .gallery(gallery)
|
||||
gallery.temporaryDoNotWaitForReady = autoplayingVideo
|
||||
return gallery
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -200,7 +214,7 @@ func chatMessagePreviewControllerData(context: AccountContext, message: Message,
|
||||
if let mediaData = chatMessageGalleryControllerData(context: context, message: message, navigationController: navigationController, standalone: standalone, reverseMessageGalleryOrder: reverseMessageGalleryOrder, mode: .default, synchronousLoad: true, actionInteraction: nil) {
|
||||
switch mediaData {
|
||||
case let .gallery(gallery):
|
||||
return .gallery(gallery)
|
||||
break
|
||||
case let .instantPage(gallery, centralIndex, galleryMedia):
|
||||
return .instantPage(gallery, centralIndex, galleryMedia)
|
||||
default:
|
||||
@ -311,13 +325,16 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
||||
return true
|
||||
case let .gallery(gallery):
|
||||
params.dismissInput()
|
||||
params.present(gallery, GalleryControllerPresentationArguments(transitionArguments: { messageId, media in
|
||||
let selectedTransitionNode = params.transitionNode(messageId, media)
|
||||
if let selectedTransitionNode = selectedTransitionNode {
|
||||
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: params.addToTransitionSurface)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
let _ = (gallery
|
||||
|> deliverOnMainQueue).start(next: { gallery in
|
||||
params.present(gallery, GalleryControllerPresentationArguments(transitionArguments: { messageId, media in
|
||||
let selectedTransitionNode = params.transitionNode(messageId, media)
|
||||
if let selectedTransitionNode = selectedTransitionNode {
|
||||
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: params.addToTransitionSurface)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
})
|
||||
return true
|
||||
case let .secretGallery(gallery):
|
||||
params.dismissInput()
|
||||
|
@ -11,12 +11,14 @@ import MtProtoKit
|
||||
import MtProtoKitDynamic
|
||||
#endif
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import UrlEscaping
|
||||
import PassportUI
|
||||
import UrlHandling
|
||||
import WalletUI
|
||||
import WalletUrl
|
||||
import OpenInExternalAppUI
|
||||
|
||||
public struct ParsedSecureIdUrl {
|
||||
public let peerId: PeerId
|
||||
|
Binary file not shown.
@ -183,7 +183,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
|
||||
self._presentationData.set(.single(initialPresentationDataAndSettings.presentationData)
|
||||
|> then(
|
||||
updatedPresentationData(accountManager: self.accountManager, applicationInForeground: self.applicationBindings.applicationInForeground)
|
||||
updatedPresentationData(accountManager: self.accountManager, applicationInForeground: self.applicationBindings.applicationInForeground, systemUserInterfaceStyle: mainWindow?.systemUserInterfaceStyle ?? .single(.light))
|
||||
))
|
||||
self._automaticMediaDownloadSettings.set(.single(initialPresentationDataAndSettings.automaticMediaDownloadSettings)
|
||||
|> then(accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings])
|
||||
|
@ -67,7 +67,7 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager {
|
||||
validIds.insert(themeSettings.theme.index)
|
||||
themes[themeSettings.theme.index] = (themeSettings.theme, false)
|
||||
}
|
||||
if case .cloud = themeSettings.automaticThemeSwitchSetting.theme, themeSettings.automaticThemeSwitchSetting.trigger != .none {
|
||||
if case .cloud = themeSettings.automaticThemeSwitchSetting.theme, themeSettings.automaticThemeSwitchSetting.trigger != .explicitNone {
|
||||
validIds.insert(themeSettings.automaticThemeSwitchSetting.theme.index)
|
||||
themes[themeSettings.automaticThemeSwitchSetting.theme.index] = (themeSettings.automaticThemeSwitchSetting.theme, true)
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ private enum ApplicationSpecificSharedDataKeyValues: Int32 {
|
||||
case watchPresetSettings = 13
|
||||
case webSearchSettings = 14
|
||||
case contactSynchronizationSettings = 15
|
||||
case webBrowserSettings = 16
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificSharedDataKeys {
|
||||
@ -49,6 +50,7 @@ public struct ApplicationSpecificSharedDataKeys {
|
||||
public static let watchPresetSettings = applicationSpecificSharedDataKey(ApplicationSpecificSharedDataKeyValues.watchPresetSettings.rawValue)
|
||||
public static let webSearchSettings = applicationSpecificSharedDataKey(ApplicationSpecificSharedDataKeyValues.webSearchSettings.rawValue)
|
||||
public static let contactSynchronizationSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.contactSynchronizationSettings.rawValue)
|
||||
public static let webBrowserSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.webBrowserSettings.rawValue)
|
||||
}
|
||||
|
||||
private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
|
||||
|
@ -238,27 +238,30 @@ public enum AutomaticThemeSwitchTimeBasedSetting: PostboxCoding, Equatable {
|
||||
}
|
||||
|
||||
public enum AutomaticThemeSwitchTrigger: PostboxCoding, Equatable {
|
||||
case none
|
||||
case system
|
||||
case explicitNone
|
||||
case timeBased(setting: AutomaticThemeSwitchTimeBasedSetting)
|
||||
case brightness(threshold: Double)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("_t", orElse: 0) {
|
||||
case 0:
|
||||
self = .none
|
||||
self = .system
|
||||
case 1:
|
||||
self = .timeBased(setting: decoder.decodeObjectForKey("setting", decoder: { AutomaticThemeSwitchTimeBasedSetting(decoder: $0) }) as! AutomaticThemeSwitchTimeBasedSetting)
|
||||
case 2:
|
||||
self = .brightness(threshold: decoder.decodeDoubleForKey("threshold", orElse: 0.2))
|
||||
case 3:
|
||||
self = .explicitNone
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .none
|
||||
self = .system
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
switch self {
|
||||
case .none:
|
||||
case .system:
|
||||
encoder.encodeInt32(0, forKey: "_t")
|
||||
case let .timeBased(setting):
|
||||
encoder.encodeInt32(1, forKey: "_t")
|
||||
@ -266,6 +269,8 @@ public enum AutomaticThemeSwitchTrigger: PostboxCoding, Equatable {
|
||||
case let .brightness(threshold):
|
||||
encoder.encodeInt32(2, forKey: "_t")
|
||||
encoder.encodeDouble(threshold, forKey: "threshold")
|
||||
case .explicitNone:
|
||||
encoder.encodeInt32(3, forKey: "_t")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -450,7 +455,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
||||
}
|
||||
|
||||
public static var defaultSettings: PresentationThemeSettings {
|
||||
return PresentationThemeSettings(chatWallpaper: .builtin(WallpaperSettings()), theme: .builtin(.dayClassic), themeSpecificAccentColors: [:], themeSpecificChatWallpapers: [:], fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .none, theme: .builtin(.nightAccent)), largeEmoji: true, disableAnimations: true)
|
||||
return PresentationThemeSettings(chatWallpaper: .builtin(WallpaperSettings()), theme: .builtin(.dayClassic), themeSpecificAccentColors: [:], themeSpecificChatWallpapers: [:], fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .system, theme: .builtin(.night)), largeEmoji: true, disableAnimations: true)
|
||||
}
|
||||
|
||||
public init(chatWallpaper: TelegramWallpaper, theme: PresentationThemeReference, themeSpecificAccentColors: [Int64: PresentationThemeAccentColor], themeSpecificChatWallpapers: [Int64: TelegramWallpaper], fontSize: PresentationFontSize, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting, largeEmoji: Bool, disableAnimations: Bool) {
|
||||
@ -506,7 +511,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
||||
}
|
||||
|
||||
self.fontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("f", orElse: PresentationFontSize.regular.rawValue)) ?? .regular
|
||||
self.automaticThemeSwitchSetting = (decoder.decodeObjectForKey("automaticThemeSwitchSetting", decoder: { AutomaticThemeSwitchSetting(decoder: $0) }) as? AutomaticThemeSwitchSetting) ?? AutomaticThemeSwitchSetting(trigger: .none, theme: .builtin(.nightAccent))
|
||||
self.automaticThemeSwitchSetting = (decoder.decodeObjectForKey("automaticThemeSwitchSetting", decoder: { AutomaticThemeSwitchSetting(decoder: $0) }) as? AutomaticThemeSwitchSetting) ?? AutomaticThemeSwitchSetting(trigger: .system, theme: .builtin(.night))
|
||||
self.largeEmoji = decoder.decodeBoolForKey("largeEmoji", orElse: true)
|
||||
self.disableAnimations = decoder.decodeBoolForKey("disableAnimations", orElse: true)
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
|
||||
public struct WebBrowserSettings: PreferencesEntry, Equatable {
|
||||
public let defaultWebBrowser: String?
|
||||
|
||||
public static var defaultSettings: WebBrowserSettings {
|
||||
return WebBrowserSettings(defaultWebBrowser: nil)
|
||||
}
|
||||
|
||||
public init(defaultWebBrowser: String?) {
|
||||
self.defaultWebBrowser = defaultWebBrowser
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.defaultWebBrowser = decoder.decodeOptionalStringForKey("defaultWebBrowser")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
if let defaultWebBrowser = self.defaultWebBrowser {
|
||||
encoder.encodeString(defaultWebBrowser, forKey: "defaultWebBrowser")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "defaultWebBrowser")
|
||||
}
|
||||
}
|
||||
|
||||
public func isEqual(to: PreferencesEntry) -> Bool {
|
||||
if let to = to as? WebBrowserSettings {
|
||||
return self == to
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public static func ==(lhs: WebBrowserSettings, rhs: WebBrowserSettings) -> Bool {
|
||||
return lhs.defaultWebBrowser == rhs.defaultWebBrowser
|
||||
}
|
||||
|
||||
public func withUpdatedDefaultWebBrowser(_ defaultWebBrowser: String?) -> WebBrowserSettings {
|
||||
return WebBrowserSettings(defaultWebBrowser: defaultWebBrowser)
|
||||
}
|
||||
}
|
||||
|
||||
public func updateWebBrowserSettingsInteractively(accountManager: AccountManager, _ f: @escaping (WebBrowserSettings) -> WebBrowserSettings) -> Signal<Void, NoError> {
|
||||
return accountManager.transaction { transaction -> Void in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.webBrowserSettings, { entry in
|
||||
let currentSettings: WebBrowserSettings
|
||||
if let entry = entry as? WebBrowserSettings {
|
||||
currentSettings = entry
|
||||
} else {
|
||||
currentSettings = WebBrowserSettings.defaultSettings
|
||||
}
|
||||
return f(currentSettings)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user