Cloud themes improvements

This commit is contained in:
Ilya Laktyushin 2019-08-29 05:31:34 +03:00
parent 4ac24e4369
commit f3db3a29b0
64 changed files with 3452 additions and 3048 deletions

View File

@ -8,6 +8,11 @@
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${APP_NAME}</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict/>
<dict/>
</array>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIcons</key>
@ -332,5 +337,29 @@
<false/>
<key>UIViewGroupOpacity</key>
<false/>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>Telegram iOS Color Theme File</string>
<key>UTTypeIconFiles</key>
<array>
<string>BlueIcon@3x.png</string>
</array>
<key>UTTypeIdentifier</key>
<string>org.telegram.Telegram-iOS.theme</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>tgios-theme</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

View File

@ -33,7 +33,5 @@
<string>merchant.privatbank.test.telergramios</string>
<string>merchant.privatbank.prod.telergram</string>
</array>
<key>com.apple.developer.carplay-messaging</key>
<true/>
</dict>
</plist>

View File

@ -4660,19 +4660,27 @@ Any member of this group will be able to see messages in the channel.";
"Appearance.CreateTheme" = "Create New Theme";
"Appearance.EditTheme" = "Edit Theme";
"Appearance.ShareTheme" = "Share";
"Appearance.RemoveTheme" = "Remove";
"Appearance.CreateThemeInfo" = "A new theme template has been created from your current theme and added to your Saved Messages.";
"Appearance.RemoveThemeConfirmation" = "Remove Theme";
"Conversation.Theme" = "Color Theme";
"Conversation.ViewTheme" = "VIEW THEME";
"Message.Theme" = "Color Theme";
"EditTheme.Title" = "Edit Theme";
"EditTheme.Preview" = "PREVIEW";
"EditTheme.Title" = "Title";
"EditTheme.ShortLink" = "Short Link";
"EditTheme.ShortLinkInfo" = "Short Link";
"EditTheme.CreateTitle" = "Create Theme";
"EditTheme.EditTitle" = "Edit Theme";
"EditTheme.Title" = "Theme Name";
"EditTheme.ShortLink" = "link";
"EditTheme.ShortLinkInfo" = "Short Link Info";
"EditTheme.Preview" = "CHAT PREVIEW";
"EditTheme.UploadNewTheme" = "Select a File...";
"EditTheme.UploadEditedTheme" = "Select Updated File...";
"EditTheme.UploadNewInfo" = "This theme will be based on your current theme and wallpaper. Otherwise, you can use a custom theme file if you already have one.";
"EditTheme.UploadEditedInfo" = "You can select a new file to update the theme. It will be updated for all users.";
"EditTheme.ThemeTemplateAlert" = "A copy of your theme template has been added to your Saved Messages.";
"EditTheme.FileReadError" = "Invalid theme file";
"Wallpaper.ErrorNotFound" = "Sorry, this chat background doesn't seem to exist.";
"Theme.ErrorNotFound" = "Sorry, this color theme doesn't seem to exist.";

View File

@ -152,7 +152,7 @@ private final class BotCheckoutPasswordAlertContentNode: AlertContentNode {
self.textFieldNode.textField.textColor = theme.actionSheet.primaryTextColor
self.textFieldNode.textField.font = Font.regular(12.0)
self.textFieldNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(12.0)]
self.textFieldNode.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textFieldNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textFieldNode.textField.isSecureTextEntry = true
self.textFieldNode.textField.tintColor = theme.list.itemAccentColor

View File

@ -42,7 +42,7 @@ final class BotPaymentCardInputItemNode: BotPaymentItemNode, STPPaymentCardTextF
self.cardField.textColor = theme.list.itemPrimaryTextColor
self.cardField.textErrorColor = theme.list.itemDestructiveColor
self.cardField.placeholderColor = theme.list.itemPlaceholderTextColor
self.cardField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.cardField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
}
self.cardField.frame = CGRect(origin: CGPoint(x: 5.0, y: 0.0), size: CGSize(width: width - 10.0, height: 44.0))

View File

@ -79,7 +79,7 @@ final class BotPaymentFieldItemNode: BotPaymentItemNode, UITextFieldDelegate {
self.titleNode.attributedText = NSAttributedString(string: self.title, font: titleFont, textColor: theme.list.itemPrimaryTextColor)
self.textField.textField.textColor = theme.list.itemPrimaryTextColor
self.textField.textField.attributedPlaceholder = NSAttributedString(string: placeholder, font: titleFont, textColor: theme.list.itemPlaceholderTextColor)
self.textField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textField.textField.tintColor = theme.list.itemAccentColor
}
@ -97,7 +97,7 @@ final class BotPaymentFieldItemNode: BotPaymentItemNode, UITextFieldDelegate {
if self.theme !== theme {
self.theme = theme
self.titleNode.attributedText = NSAttributedString(string: self.title, font: titleFont, textColor: theme.list.itemPrimaryTextColor)
self.textField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textField.textField.tintColor = theme.list.itemAccentColor
}

View File

@ -321,7 +321,7 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
strongSelf.textNode.attributedPlaceholderText = attributedPlaceholderText
}
strongSelf.textNode.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
strongSelf.textNode.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
strongSelf.textClippingNode.frame = CGRect(origin: CGPoint(x: revealOffset + leftInset, y: textTopInset), size: CGSize(width: params.width - leftInset - params.rightInset, height: textLayout.size.height))
strongSelf.textNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: params.width - leftInset - rightInset, height: textLayout.size.height + 1.0))

View File

@ -93,7 +93,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
self.effectView = UIVisualEffectView()
if #available(iOS 9.0, *) {
} else {
if theme.chatList.searchBarKeyboardColor == .dark {
if theme.rootController.keyboardColor == .dark {
self.effectView.effect = UIBlurEffect(style: .dark)
} else {
self.effectView.effect = UIBlurEffect(style: .light)

View File

@ -17,8 +17,8 @@ import OpenInExternalAppUI
private let deleteImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: .white)
private let actionImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: .white)
private let backwardImage = UIImage(bundleImageName: "Media Gallery/BackwardButton")
private let forwardImage = UIImage(bundleImageName: "Media Gallery/ForwardButton")
private let backwardImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/BackwardButton"), color: .white)
private let forwardImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/ForwardButton"), color: .white)
private let pauseImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/PauseButton"), color: .white)
private let playImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/PlayButton"), color: .white)
@ -600,8 +600,13 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.actionButton.frame = CGRect(origin: CGPoint(x: leftInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))
self.deleteButton.frame = CGRect(origin: CGPoint(x: width - 44.0 - rightInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))
self.backwardButton.frame = CGRect(origin: CGPoint(x: floor((width - 44.0) / 2.0) - 66.0, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))
self.forwardButton.frame = CGRect(origin: CGPoint(x: floor((width - 44.0) / 2.0) + 66.0, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))
if let image = self.backwardButton.image(for: .normal) {
self.backwardButton.frame = CGRect(origin: CGPoint(x: floor((width - image.size.width) / 2.0) - 66.0, y: panelHeight - bottomInset - 44.0 + 7.0), size: image.size)
}
if let image = self.forwardButton.image(for: .normal) {
self.forwardButton.frame = CGRect(origin: CGPoint(x: floor((width - image.size.width) / 2.0) + 66.0, y: panelHeight - bottomInset - 44.0 + 7.0), size: image.size)
}
self.playbackControlButton.frame = CGRect(origin: CGPoint(x: floor((width - 44.0) / 2.0), y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))

View File

@ -473,7 +473,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
}
seekable = value.duration >= 45.0
seekable = value.duration >= 30.0
}
var fetching = false

View File

@ -672,7 +672,7 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo
if strongSelf.inputSeparator == nil {
animateIn = true
}
let keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
let keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
switch editingName {
case let .personName(firstName, lastName):
if strongSelf.inputSeparator == nil {

View File

@ -251,7 +251,7 @@ public class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNod
strongSelf.textNode.attributedPlaceholderText = attributedPlaceholderText
}
strongSelf.textNode.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
strongSelf.textNode.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
strongSelf.textClippingNode.frame = CGRect(origin: CGPoint(x: leftInset, y: textTopInset), size: CGSize(width: params.width - leftInset - params.rightInset, height: textLayout.size.height))
strongSelf.textNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: params.width - leftInset - 16.0 - rightInset, height: textLayout.size.height + 1.0))

View File

@ -13,6 +13,21 @@ public enum ItemListSingleLineInputItemType: Equatable {
case username
}
public enum ItemListSingleLineInputClearType: Equatable {
case none
case always
case onFocus
var hasButton: Bool {
switch self {
case .none:
return false
case .always, .onFocus:
return true
}
}
}
public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
let theme: PresentationTheme
let strings: PresentationStrings
@ -22,7 +37,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
let type: ItemListSingleLineInputItemType
let returnKeyType: UIReturnKeyType
let spacing: CGFloat
let clearButton: Bool
let clearType: ItemListSingleLineInputClearType
let enabled: Bool
public let sectionId: ItemListSectionId
let action: () -> Void
@ -32,7 +47,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
let updatedFocus: ((Bool) -> Void)?
public let tag: ItemListItemTag?
public init(theme: PresentationTheme, strings: PresentationStrings, title: NSAttributedString, text: String, placeholder: String, type: ItemListSingleLineInputItemType = .regular(capitalization: true, autocorrection: true), returnKeyType: UIReturnKeyType = .`default`, spacing: CGFloat = 0.0, clearButton: Bool = false, enabled: Bool = true, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, processPaste: ((String) -> String)? = nil, updatedFocus: ((Bool) -> Void)? = nil, action: @escaping () -> Void) {
public init(theme: PresentationTheme, strings: PresentationStrings, title: NSAttributedString, text: String, placeholder: String, type: ItemListSingleLineInputItemType = .regular(capitalization: true, autocorrection: true), returnKeyType: UIReturnKeyType = .`default`, spacing: CGFloat = 0.0, clearType: ItemListSingleLineInputClearType = .none, enabled: Bool = true, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, processPaste: ((String) -> String)? = nil, updatedFocus: ((Bool) -> Void)? = nil, action: @escaping () -> Void) {
self.theme = theme
self.strings = strings
self.title = title
@ -41,7 +56,7 @@ public class ItemListSingleLineInputItem: ListViewItem, ItemListItem {
self.type = type
self.returnKeyType = returnKeyType
self.spacing = spacing
self.clearButton = clearButton
self.clearType = clearType
self.enabled = enabled
self.tag = tag
self.sectionId = sectionId
@ -153,7 +168,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
self.textNode.textField.font = Font.regular(17.0)
if let item = self.item {
self.textNode.textField.textColor = item.theme.list.itemPrimaryTextColor
self.textNode.textField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textNode.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
self.textNode.textField.tintColor = item.theme.list.itemAccentColor
self.textNode.textField.accessibilityHint = item.placeholder
}
@ -180,7 +195,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
let leftInset: CGFloat = 16.0 + params.leftInset
var rightInset: CGFloat = 16.0 + params.rightInset
if item.clearButton {
if item.clearType.hasButton {
rightInset += 32.0
}
@ -210,7 +225,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor
strongSelf.textNode.textField.textColor = item.theme.list.itemPrimaryTextColor
strongSelf.textNode.textField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
strongSelf.textNode.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
strongSelf.textNode.textField.tintColor = item.theme.list.itemAccentColor
}
@ -290,9 +305,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
strongSelf.clearIconNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - buttonSize.width + floor((buttonSize.width - image.size.width) / 2.0), y: floor((layout.contentSize.height - image.size.height) / 2.0)), size: image.size)
}
strongSelf.clearIconNode.isHidden = !item.clearButton || item.text.isEmpty
strongSelf.clearButtonNode.isHidden = !item.clearButton || item.text.isEmpty
strongSelf.clearButtonNode.isAccessibilityElement = !strongSelf.clearButtonNode.isHidden
strongSelf.updateClearButtonVisibility()
if strongSelf.backgroundNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
@ -334,6 +347,24 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
}
}
private func updateClearButtonVisibility() {
guard let item = self.item else {
return
}
let isHidden: Bool
switch item.clearType {
case .none:
isHidden = true
case .always:
isHidden = item.text.isEmpty
case .onFocus:
isHidden = !self.textNode.textField.isFirstResponder || item.text.isEmpty
}
self.clearIconNode.isHidden = isHidden
self.clearButtonNode.isHidden = isHidden
self.clearButtonNode.isAccessibilityElement = isHidden
}
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
}
@ -392,10 +423,12 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
self.item?.updatedFocus?(true)
self.updateClearButtonVisibility()
}
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
self.item?.updatedFocus?(false)
self.updateClearButtonVisibility()
}
public func animateError() {

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
096C16E62317412A0047887D /* LegacyICloudFilePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C16E5231741290047887D /* LegacyICloudFilePicker.swift */; };
D03E3F6E2304C4840049C28B /* LegacyMediaPickerUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E3F6C2304C4840049C28B /* LegacyMediaPickerUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E3F802304C50E0049C28B /* LegacyMediaPickers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E3F782304C50D0049C28B /* LegacyMediaPickers.swift */; };
D03E3F812304C50E0049C28B /* LegacyImageProcessors.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E3F792304C50D0049C28B /* LegacyImageProcessors.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -32,6 +33,7 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
096C16E5231741290047887D /* LegacyICloudFilePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyICloudFilePicker.swift; sourceTree = "<group>"; };
D03E3F692304C4840049C28B /* LegacyMediaPickerUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LegacyMediaPickerUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E3F6C2304C4840049C28B /* LegacyMediaPickerUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LegacyMediaPickerUI.h; sourceTree = "<group>"; };
D03E3F6D2304C4840049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -111,6 +113,7 @@
D03E3F782304C50D0049C28B /* LegacyMediaPickers.swift */,
D03E3F7B2304C50D0049C28B /* LegacySuggestionContext.swift */,
D03E3F7F2304C50D0049C28B /* LegacyWallpaperPicker.swift */,
096C16E5231741290047887D /* LegacyICloudFilePicker.swift */,
D03E3F6C2304C4840049C28B /* LegacyMediaPickerUI.h */,
);
path = Sources;
@ -219,6 +222,7 @@
files = (
D03E3F872304C50E0049C28B /* LegacyWallpaperPicker.swift in Sources */,
D03E3F842304C50E0049C28B /* LegacyImagePicker.swift in Sources */,
096C16E62317412A0047887D /* LegacyICloudFilePicker.swift in Sources */,
D03E3F822304C50E0049C28B /* LegacyAttachmentMenu.swift in Sources */,
D03E3F852304C50E0049C28B /* LegacyImageProcessors.m in Sources */,
D03E3F802304C50E0049C28B /* LegacyMediaPickers.swift in Sources */,

View File

@ -30,7 +30,21 @@ private final class LegacyICloudFileController: LegacyController, UIDocumentPick
}
}
func legacyICloudFileController(theme: PresentationTheme, completion: @escaping ([URL]) -> Void) -> ViewController {
public enum LegacyICloudFilePickerMode {
case `default`
case `import`
var documentPickerMode: UIDocumentPickerMode {
switch self {
case .default:
return .open
case .import:
return .import
}
}
}
public func legacyICloudFilePicker(theme: PresentationTheme, mode: LegacyICloudFilePickerMode = .default, documentTypes: [String] = ["public.item"], completion: @escaping ([URL]) -> Void) -> ViewController {
var dismissImpl: (() -> Void)?
let legacyController = LegacyICloudFileController(presentation: .modal(animateIn: true), theme: theme, completion: { urls in
dismissImpl?()
@ -38,25 +52,9 @@ func legacyICloudFileController(theme: PresentationTheme, completion: @escaping
})
legacyController.statusBar.statusBarStyle = .Black
let documentTypes: [String] = [
"public.item"
// "public.composite-content",
// "public.text",
// "public.image",
// "public.audio",
// "public.video",
// "public.movie",
// "public.font",
// "public.data",
// "org.telegram.Telegram.webp",
// "com.apple.iwork.pages.pages",
// "com.apple.iwork.numbers.numbers",
// "com.apple.iwork.keynote.key"
]
let controller = UIDocumentPickerViewController(documentTypes: documentTypes, in: .open)
let controller = UIDocumentPickerViewController(documentTypes: documentTypes, in: mode.documentPickerMode)
controller.delegate = legacyController
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
if #available(iOSApplicationExtension 11.0, iOS 11.0, *), case .default = mode {
controller.allowsMultipleSelection = true
}

View File

@ -82,7 +82,7 @@ final class PasscodeSetupControllerNode: ASDisplayNode {
passcodeType = .digits6
}
self.inputFieldNode = PasscodeEntryInputFieldNode(color: self.presentationData.theme.list.itemPrimaryTextColor, accentColor: self.presentationData.theme.list.itemAccentColor, fieldType: passcodeType, keyboardAppearance: self.presentationData.theme.chatList.searchBarKeyboardColor.keyboardAppearance)
self.inputFieldNode = PasscodeEntryInputFieldNode(color: self.presentationData.theme.list.itemPrimaryTextColor, accentColor: self.presentationData.theme.list.itemAccentColor, fieldType: passcodeType, keyboardAppearance: self.presentationData.theme.rootController.keyboardColor.keyboardAppearance)
self.inputFieldBackgroundNode = ASImageNode()
self.inputFieldBackgroundNode.alpha = passcodeType == .alphanumeric ? 1.0 : 0.0
self.inputFieldBackgroundNode.contentMode = .scaleToFill

View File

@ -143,7 +143,7 @@ final class FormControllerTextInputItemNode: FormBlockItemNode<FormControllerTex
self.textField.textField.returnKeyType = item.returnKeyType
}
self.textField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textField.textField.tintColor = theme.list.itemAccentColor
let attributedPlaceholder = NSAttributedString(string: item.placeholder, font: textFont, textColor: theme.list.itemPlaceholderTextColor)

View File

@ -46,7 +46,7 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo
self.inputField = TextFieldNode()
self.inputButtonNode = HighlightableButtonNode()
self.inputActivityNode = ActivityIndicator(type: .custom(theme.list.itemAccentColor, 18.0, 1.5, false))
self.inputActivityNode = ActivityIndicator(type: .custom(theme.list.freeInputField.controlColor, 18.0, 1.5, false))
if let image = generateTintedImage(image: UIImage(bundleImageName: "Secure ID/PasswordHelpIcon"), color: theme.list.freeInputField.controlColor) {
self.inputButtonNode.setImage(image, for: [])
@ -59,7 +59,7 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo
self.inputField.textField.font = passwordFont
self.inputField.textField.textColor = theme.list.freeInputField.primaryColor
self.inputField.textField.attributedPlaceholder = NSAttributedString(string: hint.isEmpty ? strings.LoginPassword_PasswordPlaceholder : hint, font: passwordFont, textColor: theme.list.freeInputField.placeholderColor)
self.inputField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.inputField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.inputField.textField.tintColor = theme.list.itemAccentColor
self.buttonNode = HighlightableButtonNode()

View File

@ -126,8 +126,8 @@ final class SecureIdValueFormPhoneItemNode: FormBlockItemNode<SecureIdValueFormP
self.phoneInputNode.countryCodeField.textField.tintColor = theme.list.itemAccentColor
self.phoneInputNode.numberField.textField.tintColor = theme.list.itemAccentColor
self.phoneInputNode.countryCodeField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.phoneInputNode.numberField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.phoneInputNode.countryCodeField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.phoneInputNode.numberField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
}
self.item = item

View File

@ -59,7 +59,7 @@ final class SetupTwoStepVerificationContentNode: ASDisplayNode, UITextFieldDeleg
self.inputNode.textField.font = Font.regular(22.0)
self.inputNode.textField.attributedPlaceholder = NSAttributedString(string: placeholder, font: Font.regular(22.0), textColor: theme.list.itemPlaceholderTextColor)
self.inputNode.textField.textAlignment = .center
self.inputNode.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.inputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.inputNode.textField.tintColor = theme.list.itemAccentColor
switch inputType {
case .password:
@ -126,7 +126,7 @@ final class SetupTwoStepVerificationContentNode: ASDisplayNode, UITextFieldDeleg
func updatePresentationData(_ presentationData: PresentationData) {
self.theme = presentationData.theme
self.inputNode.textField.keyboardAppearance = self.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.inputNode.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.inputSeparator.backgroundColor = self.theme.list.itemPlainSeparatorColor
self.inputNode.textField.tintColor = self.theme.list.itemAccentColor
}

View File

@ -372,7 +372,7 @@ private enum ChannelAdminEntry: ItemListNodeEntry {
}
return ItemListSectionHeaderItem(theme: theme, text: text, accessoryText: accessoryText, sectionId: self.section)
case let .rank(theme, strings, placeholder, text, enabled):
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: "", textColor: .black), text: text, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: true), spacing: 0.0, clearButton: enabled, enabled: enabled, tag: ChannelAdminEntryTag.rank, sectionId: self.section, textUpdated: { updatedText in
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: "", textColor: .black), text: text, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: true), spacing: 0.0, clearType: enabled ? .always : .none, enabled: enabled, tag: ChannelAdminEntryTag.rank, sectionId: self.section, textUpdated: { updatedText in
arguments.updateRank(text, updatedText)
}, shouldUpdateText: { text in
if text.containsEmoji {

View File

@ -845,7 +845,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi
}
}, openStats: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var urlSignal = channelStatsUrl(postbox: context.account.postbox, network: context.account.network, peerId: peerId, params: "", darkTheme: presentationData.theme.chatList.searchBarKeyboardColor.keyboardAppearance == .dark)
var urlSignal = channelStatsUrl(postbox: context.account.postbox, network: context.account.network, peerId: peerId, params: "", darkTheme: presentationData.theme.rootController.keyboardColor.keyboardAppearance == .dark)
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { subscriber in

View File

@ -80,7 +80,7 @@ private final class ChannelOwnershipTransferPasswordFieldNode: ASDisplayNode, UI
self.textInputNode.textField.textColor = self.theme.list.itemPrimaryTextColor
self.textInputNode.textField.isSecureTextEntry = true
self.textInputNode.textField.returnKeyType = .done
self.textInputNode.textField.keyboardAppearance = self.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textInputNode.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.textInputNode.clipsToBounds = true
self.textInputNode.textField.delegate = self
self.textInputNode.textField.addTarget(self, action: #selector(self.textFieldTextChanged(_:)), for: .editingChanged)
@ -92,7 +92,7 @@ private final class ChannelOwnershipTransferPasswordFieldNode: ASDisplayNode, UI
self.theme = theme
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 16.0, color: theme.actionSheet.inputHollowBackgroundColor, strokeColor: theme.actionSheet.inputBorderColor, strokeWidth: UIScreenPixel)
self.textInputNode.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textInputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textInputNode.textField.textColor = theme.list.itemPrimaryTextColor
self.textInputNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(14.0), NSAttributedString.Key.foregroundColor: theme.actionSheet.inputTextColor]
self.textInputNode.textField.tintColor = theme.list.itemAccentColor

View File

@ -90,7 +90,7 @@ final class ChannelStatsControllerNode: ViewControllerTracingNode, WKNavigationD
}
}
}
self.refreshDisposable.set((channelStatsUrl(postbox: self.context.account.postbox, network: self.context.account.network, peerId: self.peerId, params: params, darkTheme: self.presentationData.theme.chatList.searchBarKeyboardColor.keyboardAppearance == .dark)
self.refreshDisposable.set((channelStatsUrl(postbox: self.context.account.postbox, network: self.context.account.network, peerId: self.peerId, params: params, darkTheme: self.presentationData.theme.rootController.keyboardColor.keyboardAppearance == .dark)
|> deliverOnMainQueue).start(next: { [weak self] url in
guard let strongSelf = self else {
return

View File

@ -287,7 +287,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
}
}, tag: ChannelVisibilityEntryTag.privateLink)
case let .editablePublicLink(theme, strings, placeholder, currentText):
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: "t.me/", textColor: theme.list.itemPrimaryTextColor), text: currentText, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: false), clearButton: true, tag: ChannelVisibilityEntryTag.publicLink, sectionId: self.section, textUpdated: { updatedText in
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: "t.me/", textColor: theme.list.itemPrimaryTextColor), text: currentText, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: false), clearType: .always, tag: ChannelVisibilityEntryTag.publicLink, sectionId: self.section, textUpdated: { updatedText in
arguments.updatePublicLinkText(currentText, updatedText)
}, updatedFocus: { focus in
if focus {

View File

@ -209,7 +209,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
func item(_ arguments: GroupStickerPackSetupControllerArguments) -> ListViewItem {
switch self {
case let .search(theme, strings, prefix, placeholder, value):
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: prefix, textColor: theme.list.itemPrimaryTextColor), text: value, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: false), spacing: 0.0, clearButton: true, tag: nil, sectionId: self.section, textUpdated: { value in
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: prefix, textColor: theme.list.itemPrimaryTextColor), text: value, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: false), spacing: 0.0, clearType: .always, tag: nil, sectionId: self.section, textUpdated: { value in
arguments.updateSearchText(value)
}, processPaste: { text in
if let url = (URL(string: text) ?? URL(string: "http://" + text)), url.host == "t.me" || url.host == "telegram.me" {

View File

@ -183,7 +183,7 @@ class UserInfoEditingPhoneItemNode: ItemListRevealOptionsItemNode, ItemListItemN
if let item = self.item {
self.phoneNode.numberField?.textField.textColor = item.theme.list.itemPrimaryTextColor
self.phoneNode.numberField?.textField.keyboardAppearance = item.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.phoneNode.numberField?.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
self.phoneNode.numberField?.textField.tintColor = item.theme.list.itemAccentColor
}
}
@ -233,7 +233,7 @@ class UserInfoEditingPhoneItemNode: ItemListRevealOptionsItemNode, ItemListItemN
strongSelf.labelSeparatorNode.backgroundColor = itemSeparatorColor
strongSelf.phoneNode.numberField?.textField.textColor = updatedTheme.list.itemPrimaryTextColor
strongSelf.phoneNode.numberField?.textField.keyboardAppearance = updatedTheme.chatList.searchBarKeyboardColor.keyboardAppearance
strongSelf.phoneNode.numberField?.textField.keyboardAppearance = updatedTheme.rootController.keyboardColor.keyboardAppearance
strongSelf.phoneNode.numberField?.textField.tintColor = item.theme.list.itemAccentColor
strongSelf.clearButton.setImage(generateClearIcon(color: updatedTheme.list.inputClearButtonColor), for: [])

View File

@ -161,7 +161,7 @@ public final class SearchBarNodeTheme: Equatable {
self.inputIcon = theme.rootController.navigationSearchBar.inputIconColor
self.inputClear = theme.rootController.navigationSearchBar.inputClearButtonColor
self.accent = theme.rootController.navigationSearchBar.accentColor
self.keyboard = theme.chatList.searchBarKeyboardColor
self.keyboard = theme.rootController.keyboardColor
}
public static func ==(lhs: SearchBarNodeTheme, rhs: SearchBarNodeTheme) -> Bool {

View File

@ -127,10 +127,10 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
self.phoneInputNode = PhoneInputNode(fontSize: 17.0)
self.phoneInputNode.countryCodeField.textField.textColor = self.presentationData.theme.list.itemPrimaryTextColor
self.phoneInputNode.countryCodeField.textField.keyboardAppearance = self.presentationData.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.phoneInputNode.countryCodeField.textField.keyboardAppearance = self.presentationData.theme.rootController.keyboardColor.keyboardAppearance
self.phoneInputNode.countryCodeField.textField.tintColor = self.presentationData.theme.list.itemAccentColor
self.phoneInputNode.numberField.textField.textColor = self.presentationData.theme.list.itemPrimaryTextColor
self.phoneInputNode.numberField.textField.keyboardAppearance = self.presentationData.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.phoneInputNode.numberField.textField.keyboardAppearance = self.presentationData.theme.rootController.keyboardColor.keyboardAppearance
self.phoneInputNode.numberField.textField.tintColor = self.presentationData.theme.list.itemAccentColor
super.init()

View File

@ -234,7 +234,7 @@ final class TabBarAccountSwitchControllerNode: ViewControllerTracingNode {
self.effectView = UIVisualEffectView()
if #available(iOS 9.0, *) {
} else {
if presentationData.theme.chatList.searchBarKeyboardColor == .dark {
if presentationData.theme.rootController.keyboardColor == .dark {
self.effectView.effect = UIBlurEffect(style: .dark)
} else {
self.effectView.effect = UIBlurEffect(style: .light)
@ -244,7 +244,7 @@ final class TabBarAccountSwitchControllerNode: ViewControllerTracingNode {
self.dimNode = ASDisplayNode()
self.dimNode.alpha = 1.0
if presentationData.theme.chatList.searchBarKeyboardColor == .light {
if presentationData.theme.rootController.keyboardColor == .light {
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.04)
} else {
self.dimNode.backgroundColor = presentationData.theme.chatList.backgroundColor.withAlphaComponent(0.2)
@ -287,7 +287,7 @@ final class TabBarAccountSwitchControllerNode: ViewControllerTracingNode {
func animateIn() {
UIView.animate(withDuration: 0.3, animations: {
if #available(iOS 9.0, *) {
if self.presentationData.theme.chatList.searchBarKeyboardColor == .dark {
if self.presentationData.theme.rootController.keyboardColor == .dark {
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
self.effectView.effect = UIBlurEffect(style: .regular)
if self.effectView.subviews.count == 2 {
@ -310,7 +310,7 @@ final class TabBarAccountSwitchControllerNode: ViewControllerTracingNode {
guard let strongSelf = self else {
return
}
if strongSelf.presentationData.theme.chatList.searchBarKeyboardColor == .dark {
if strongSelf.presentationData.theme.rootController.keyboardColor == .dark {
if strongSelf.effectView.subviews.count == 2 {
strongSelf.effectView.subviews[1].isHidden = true
}

View File

@ -8,70 +8,79 @@ import TelegramPresentationData
import TelegramUIPreferences
import ItemListUI
import AlertUI
import LegacyMediaPickerUI
import AccountContext
private final class EditThemeControllerArguments {
let context: AccountContext
let updateState: ((EditThemeControllerState) -> EditThemeControllerState) -> Void
let openFile: () -> Void
init(context: AccountContext, updateState: @escaping ((EditThemeControllerState) -> EditThemeControllerState) -> Void) {
init(context: AccountContext, updateState: @escaping ((EditThemeControllerState) -> EditThemeControllerState) -> Void, openFile: @escaping () -> Void) {
self.context = context
self.updateState = updateState
self.openFile = openFile
}
}
private enum EditThemeEntryTag: ItemListItemTag {
case title
func isEqual(to other: ItemListItemTag) -> Bool {
if let other = other as? EditThemeEntryTag, self == other {
return true
} else {
return false
}
}
}
private enum EditThemeControllerSection: Int32 {
case chatPreview
case info
case chatPreview
}
private enum EditThemeControllerEntry: ItemListNodeEntry {
case chatPreviewHeader(PresentationTheme, String)
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder)
case title(PresentationTheme, PresentationStrings, String, String)
case title(PresentationTheme, PresentationStrings, String, String, Bool)
case slug(PresentationTheme, PresentationStrings, String, String, Bool)
case slugInfo(PresentationTheme, String)
case chatPreviewHeader(PresentationTheme, String)
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder)
case uploadTheme(PresentationTheme, String)
case uploadInfo(PresentationTheme, String)
var section: ItemListSectionId {
switch self {
case .chatPreviewHeader, .chatPreview:
return EditThemeControllerSection.chatPreview.rawValue
case .title, .slug, .slugInfo:
return EditThemeControllerSection.info.rawValue
case .chatPreviewHeader, .chatPreview, .uploadTheme, .uploadInfo:
return EditThemeControllerSection.chatPreview.rawValue
}
}
var stableId: Int32 {
switch self {
case .chatPreviewHeader:
return 0
case .chatPreview:
return 1
case .title:
return 2
return 0
case .slug:
return 3
return 1
case .slugInfo:
return 2
case .chatPreviewHeader:
return 3
case .chatPreview:
return 4
case .uploadTheme:
return 5
case .uploadInfo:
return 6
}
}
static func ==(lhs: EditThemeControllerEntry, rhs: EditThemeControllerEntry) -> Bool {
switch lhs {
case let .chatPreviewHeader(lhsTheme, lhsText):
if case let .chatPreviewHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .chatPreview(lhsTheme, lhsComponentTheme, lhsWallpaper, lhsFontSize, lhsStrings, lhsTimeFormat, lhsNameOrder):
if case let .chatPreview(rhsTheme, rhsComponentTheme, rhsWallpaper, rhsFontSize, rhsStrings, rhsTimeFormat, rhsNameOrder) = rhs, lhsComponentTheme === rhsComponentTheme, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder {
return true
} else {
return false
}
case let .title(lhsTheme, lhsStrings, lhsTitle, lhsValue):
if case let .title(rhsTheme, rhsStrings, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsTitle == rhsTitle, lhsValue == rhsValue {
case let .title(lhsTheme, lhsStrings, lhsTitle, lhsValue, lhsDone):
if case let .title(rhsTheme, rhsStrings, rhsTitle, rhsValue, rhsDone) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsTitle == rhsTitle, lhsValue == rhsValue, lhsDone == rhsDone {
return true
} else {
return false
@ -88,6 +97,30 @@ private enum EditThemeControllerEntry: ItemListNodeEntry {
} else {
return false
}
case let .chatPreviewHeader(lhsTheme, lhsText):
if case let .chatPreviewHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .chatPreview(lhsTheme, lhsComponentTheme, lhsWallpaper, lhsFontSize, lhsStrings, lhsTimeFormat, lhsNameOrder):
if case let .chatPreview(rhsTheme, rhsComponentTheme, rhsWallpaper, rhsFontSize, rhsStrings, rhsTimeFormat, rhsNameOrder) = rhs, lhsComponentTheme === rhsComponentTheme, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder {
return true
} else {
return false
}
case let .uploadTheme(lhsTheme, lhsText):
if case let .uploadTheme(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .uploadInfo(lhsTheme, lhsText):
if case let .uploadInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
}
}
@ -97,67 +130,109 @@ private enum EditThemeControllerEntry: ItemListNodeEntry {
func item(_ arguments: EditThemeControllerArguments) -> ListViewItem {
switch self {
case let .chatPreviewHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .chatPreview(theme, componentTheme, wallpaper, fontSize, strings, dateTimeFormat, nameDisplayOrder):
return ThemeSettingsChatPreviewItem(context: arguments.context, theme: theme, componentTheme: componentTheme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder)
case let .title(theme, strings, title, text):
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(), text: text, placeholder: title, sectionId: self.section, textUpdated: { value in
case let .title(theme, strings, title, text, done):
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(), text: text, placeholder: title, type: .regular(capitalization: true, autocorrection: false), returnKeyType: done ? .done : .next, clearType: .onFocus, tag: EditThemeEntryTag.title, sectionId: self.section, textUpdated: { value in
arguments.updateState { current in
var state = current
state.title = value
return state
}
}, action: {})
}, action: {
})
case let .slug(theme, strings, title, text, enabled):
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: "t.me/addtheme/", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: title, type: .username, enabled: enabled, sectionId: self.section, textUpdated: { value in
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: "t.me/addtheme/", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: title, type: .username, clearType: .onFocus, enabled: enabled, sectionId: self.section, textUpdated: { value in
arguments.updateState { current in
var state = current
state.slug = value
return state
}
}, action: {})
}, action: {
})
case let .slugInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .chatPreviewHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .chatPreview(theme, componentTheme, wallpaper, fontSize, strings, dateTimeFormat, nameDisplayOrder):
return ThemeSettingsChatPreviewItem(context: arguments.context, theme: theme, componentTheme: componentTheme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder)
case let .uploadTheme(theme, text):
return ItemListActionItem(theme: theme, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
arguments.openFile()
})
case let .uploadInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
}
}
}
private struct EditThemeControllerState: Equatable {
var title: String
var slug: String
var isComplete: Bool {
if self.title.isEmpty || self.slug.isEmpty {
return false
}
return true
}
public enum EditThemeControllerMode: Equatable {
case create
case edit(PresentationCloudTheme)
}
private func EditThemeControllerEntries(presentationData: PresentationData, theme: PresentationTheme?, state: EditThemeControllerState) -> [EditThemeControllerEntry] {
private struct EditThemeControllerState: Equatable {
var mode: EditThemeControllerMode
var title: String
var slug: String
var previewTheme: PresentationTheme
var updatedTheme: PresentationTheme?
var updating: Bool
}
private func editThemeControllerEntries(presentationData: PresentationData, state: EditThemeControllerState) -> [EditThemeControllerEntry] {
var entries: [EditThemeControllerEntry] = []
if let theme = theme {
entries.append(.chatPreviewHeader(presentationData.theme, presentationData.strings.EditTheme_Preview.uppercased()))
entries.append(.chatPreview(presentationData.theme, theme, theme.chat.defaultWallpaper, presentationData.fontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder))
var isCreate = false
if case .create = state.mode {
isCreate = true
}
entries.append(.title(presentationData.theme, presentationData.strings, presentationData.strings.EditTheme_Title, state.title, isCreate))
entries.append(.title(presentationData.theme, presentationData.strings, presentationData.strings.EditTheme_Title, state.title))
if case .edit = state.mode {
entries.append(.slug(presentationData.theme, presentationData.strings, presentationData.strings.EditTheme_ShortLink, state.slug, true))
entries.append(.slugInfo(presentationData.theme, presentationData.strings.EditTheme_ShortLinkInfo))
}
entries.append(.chatPreviewHeader(presentationData.theme, presentationData.strings.EditTheme_Preview.uppercased()))
entries.append(.chatPreview(presentationData.theme, state.previewTheme, state.previewTheme.chat.defaultWallpaper, presentationData.fontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder))
let uploadText: String
let uploadInfo: String
switch state.mode {
case .create:
uploadText = presentationData.strings.EditTheme_UploadNewTheme
uploadInfo = presentationData.strings.EditTheme_UploadNewInfo
case let .edit(theme):
if let _ = theme.theme.file {
uploadText = presentationData.strings.EditTheme_UploadEditedTheme
uploadInfo = presentationData.strings.EditTheme_UploadEditedInfo
} else {
uploadText = presentationData.strings.EditTheme_UploadNewTheme
uploadInfo = presentationData.strings.EditTheme_UploadNewInfo
}
}
entries.append(.uploadTheme(presentationData.theme, uploadText))
entries.append(.uploadInfo(presentationData.theme, uploadInfo))
return entries
}
public enum EditThemeControllerMode {
case createNew
case createForExisting(TelegramTheme)
case edit(TelegramTheme)
}
public func editThemeController(context: AccountContext, theme: TelegramTheme) -> ViewController {
let initialState = EditThemeControllerState(title: theme.title, slug: theme.slug)
public func editThemeController(context: AccountContext, mode: EditThemeControllerMode, navigateToChat: ((PeerId) -> Void)? = nil) -> ViewController {
let initialState: EditThemeControllerState
switch mode {
case .create:
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
initialState = EditThemeControllerState(mode: mode, title: "", slug: "", previewTheme: presentationData.theme.withUpdated(name: "", author: nil, defaultWallpaper: presentationData.chatWallpaper), updatedTheme: nil, updating: false)
case let .edit(theme):
let previewTheme: PresentationTheme
if let file = theme.theme.file, let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path)), let theme = makePresentationTheme(data: data, resolvedWallpaper: theme.resolvedWallpaper) {
previewTheme = theme
} else {
previewTheme = context.sharedContext.currentPresentationData.with { $0 }.theme
}
initialState = EditThemeControllerState(mode: mode, title: theme.theme.title, slug: theme.theme.slug, previewTheme: previewTheme, updatedTheme: nil, updating: false)
}
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState)
let updateState: ((EditThemeControllerState) -> EditThemeControllerState) -> Void = { f in
@ -170,26 +245,151 @@ public func editThemeController(context: AccountContext, theme: TelegramTheme) -
let arguments = EditThemeControllerArguments(context: context, updateState: { f in
updateState(f)
})
var previewTheme: PresentationTheme?
if let file = theme.file, let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path)), let theme = makePresentationTheme(data: data) {
previewTheme = theme
}, openFile: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = legacyICloudFilePicker(theme: presentationData.theme, mode: .import, documentTypes: ["org.telegram.Telegram-iOS.theme"], completion: { urls in
if let url = urls.first, let data = try? Data(contentsOf: url), let theme = makePresentationTheme(data: data) {
updateState { current in
var state = current
state.previewTheme = theme
state.updatedTheme = theme
return state
}
} else {
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.EditTheme_FileReadError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
})
presentControllerImpl?(controller, nil)
})
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get())
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState<EditThemeControllerEntry>, EditThemeControllerEntry.ItemGenerationArguments)) in
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
dismissImpl?()
})
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: {
//let _ = (updateTheme(account: context.account, resource: resource, title: state.title, slug: state.slug) |> deliverOnMainQueue).start(completed: {
// dismissImpl?()
//})
})
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.EditTheme_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(entries: EditThemeControllerEntries(presentationData: presentationData, theme: previewTheme, state: state), style: .blocks, emptyStateItem: nil, animateChanges: false)
var focusItemTag: ItemListItemTag?
if case .create = state.mode {
focusItemTag = EditThemeEntryTag.title
}
let rightNavigationButton: ItemListNavigationButton
if state.updating {
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
} else {
let isComplete: Bool
if case .create = mode {
isComplete = !state.title.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).isEmpty
} else {
isComplete = !state.title.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).isEmpty && !state.slug.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).isEmpty
}
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: isComplete, action: {
arguments.updateState { current in
var state = current
state.updating = true
return state
}
let saveThemeTemplateFile: (String, LocalFileMediaResource, @escaping () -> Void) -> Void = { title, resource, completion in
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: resource.fileId), partialReference: nil, resource: resource, previewRepresentations: [], immediateThumbnailData: nil, mimeType: "application/x-tgtheme-ios", size: nil, attributes: [.FileName(fileName: "\(title).tgios-theme")])
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let _ = enqueueMessages(account: context.account, peerId: context.account.peerId, messages: [message]).start()
if let navigateToChat = navigateToChat {
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.EditTheme_ThemeTemplateAlert, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_SavedMessages, action: {
completion()
navigateToChat(context.account.peerId)
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
completion()
})], actionLayout: .vertical), nil)
} else {
completion()
}
}
let theme: PresentationTheme?
let custom: Bool
if let updatedTheme = state.updatedTheme {
theme = updatedTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil)
custom = true
} else {
if case let .edit(info) = mode, let _ = info.theme.file {
theme = nil
custom = true
} else {
theme = state.previewTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil)
custom = false
}
}
let themeResource: LocalFileMediaResource?
if let theme = theme, let themeString = encodePresentationTheme(theme), let themeData = themeString.data(using: .utf8) {
let resource = LocalFileMediaResource(fileId: arc4random64())
context.account.postbox.mediaBox.storeResourceData(resource.id, data: themeData)
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: themeData)
themeResource = resource
} else {
themeResource = nil
}
switch mode {
case .create:
if let themeResource = themeResource {
let _ = (createTheme(account: context.account, resource: themeResource, title: state.title)
|> deliverOnMainQueue).start(error: { error in
arguments.updateState { current in
var state = current
state.updating = false
return state
}
}, completed: {
if !custom {
saveThemeTemplateFile(state.title, themeResource, {
dismissImpl?()
})
} else {
dismissImpl?()
}
})
}
case let .edit(theme):
let _ = (updateTheme(account: context.account, theme: theme.theme, title: state.title, slug: state.slug, resource: themeResource)
|> deliverOnMainQueue).start(error: { error in
arguments.updateState { current in
var state = current
state.updating = false
return state
}
}, completed: {
if let themeResource = themeResource, !custom {
saveThemeTemplateFile(state.title, themeResource, {
dismissImpl?()
})
} else {
dismissImpl?()
}
})
}
})
}
let title: String
switch mode {
case .create:
title = presentationData.strings.EditTheme_CreateTitle
case let .edit(theme):
if theme.theme.file == nil {
title = presentationData.strings.EditTheme_CreateTitle
} else {
title = presentationData.strings.EditTheme_EditTitle
}
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(entries: editThemeControllerEntries(presentationData: presentationData, state: state), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: nil, animateChanges: false)
return (controllerState, (listState, arguments))
}
@ -202,6 +402,7 @@ public func editThemeController(context: AccountContext, theme: TelegramTheme) -
controller?.present(c, in: .window(.root), with: a)
}
dismissImpl = { [weak controller] in
controller?.view.endEditing(true)
let _ = controller?.dismiss()
}
return controller

View File

@ -116,7 +116,7 @@ public final class ThemePreviewController: ViewController {
|> take(1)
|> map { theme in
if let theme = theme {
return .cloud(theme)
return .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil))
} else {
return nil
}

View File

@ -8,6 +8,7 @@ import TelegramPresentationData
import TelegramUIPreferences
import ItemListUI
import AlertUI
import ShareController
import AccountContext
func themeDisplayName(strings: PresentationStrings, reference: PresentationThemeReference) -> String {
@ -27,7 +28,7 @@ func themeDisplayName(strings: PresentationStrings, reference: PresentationTheme
case let .local(theme):
name = theme.title
case let .cloud(theme):
name = theme.title
name = theme.theme.title
}
return name
}
@ -372,6 +373,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
var pushControllerImpl: ((ViewController) -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)?
var getNavigationControllerImpl: (() -> NavigationController?)?
var selectThemeImpl: ((PresentationThemeReference) -> Void)?
var moreImpl: (() -> Void)?
@ -463,34 +465,44 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let actionSheet = ActionSheetController(presentationTheme: presentationData.theme)
var items: [ActionSheetItem] = []
items.append(ActionSheetTextItem(title: theme.title))
items.append(ActionSheetTextItem(title: theme.theme.title))
if theme.theme.isCreator {
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_EditTheme, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let controller = editThemeController(context: context, theme: theme)
let controller = editThemeController(context: context, mode: .edit(theme), navigateToChat: { peerId in
if let navigationController = getNavigationControllerImpl?() {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
}
})
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}))
}
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_ShareTheme, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let controller = ShareController(context: context, subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default)
presentControllerImpl?(controller, nil)
}))
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveTheme, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let _ = (cloudThemes.get()
|> take(1)
|> deliverOnMainQueue).start(next: { themes in
if isCurrent, let themeIndex = themes.firstIndex(where: { $0.id == theme.id }) {
let newTheme: PresentationThemeReference
if themeIndex > 0 {
newTheme = .cloud(themes[themeIndex - 1])
} else {
newTheme = .builtin(.nightAccent)
}
selectThemeImpl?(newTheme)
}
let updatedThemes = themes.filter { $0.id != theme.id }
cloudThemes.set(.single(updatedThemes) |> then(updatedCloudThemes))
let _ = (deleteTheme(account: context.account, theme: theme)).start()
})
// let _ = (cloudThemes.get()
// |> take(1)
// |> deliverOnMainQueue).start(next: { themes in
// if isCurrent, let themeIndex = themes.firstIndex(where: { $0.id == theme.id }) {
// let newTheme: PresentationThemeReference
// if themeIndex > 0 {
// newTheme = .cloud(themes[themeIndex - 1])
// } else {
// newTheme = .builtin(.nightAccent)
// }
// selectThemeImpl?(newTheme)
// }
//
// let updatedThemes = themes.filter { $0.id != theme.id }
// cloudThemes.set(.single(updatedThemes) |> then(updatedCloudThemes))
//
// let _ = (deleteTheme(account: context.account, theme: theme)).start()
// })
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
@ -524,7 +536,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
})
let defaultThemes: [PresentationThemeReference] = [.builtin(.dayClassic), .builtin(.day), .builtin(.night), .builtin(.nightAccent)]
let cloudThemes: [PresentationThemeReference] = cloudThemes.map { .cloud($0) }
let cloudThemes: [PresentationThemeReference] = cloudThemes.map { .cloud(PresentationCloudTheme(theme: $0, resolvedWallpaper: nil)) }
var availableThemes = defaultThemes
if !defaultThemes.contains(settings.theme) && !cloudThemes.contains(settings.theme) {
@ -544,37 +556,27 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
(controller?.navigationController as? NavigationController)?.pushViewController(c)
}
presentControllerImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
}
getNavigationControllerImpl = { [weak controller] in
return controller?.navigationController as? NavigationController
}
selectThemeImpl = { theme in
arguments.selectTheme(theme)
}
moreImpl = { [weak controller] in
moreImpl = {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let actionSheet = ActionSheetController(presentationTheme: presentationData.theme)
var items: [ActionSheetItem] = []
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_CreateTheme, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
var randomId: Int64 = 0
arc4random_buf(&randomId, 8)
let path = NSTemporaryDirectory() + "\(randomId)"
guard let string = encodePresentationTheme(presentationData.theme), let _ = try? string.write(toFile: path, atomically: true, encoding: .utf8) else {
return
let controller = editThemeController(context: context, mode: .create, navigateToChat: { peerId in
if let navigationController = getNavigationControllerImpl?() {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
}
let id = arc4random64()
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: id), previewRepresentations: [], immediateThumbnailData: nil, mimeType: "application/x-tgtheme-ios", size: nil, attributes: [.FileName(fileName: "\(presentationData.theme.name.string).tgios-theme")])
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let _ = enqueueMessages(account: context.account, peerId: context.account.peerId, messages: [message]).start()
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Appearance_CreateThemeInfo, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_SavedMessages, action: {
if let controller = controller, let navigationController = controller.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(context.account.peerId)))
}
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})], actionLayout: .vertical), nil)
})
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in

View File

@ -60,7 +60,7 @@ private func themeIconImage(context: AccountContext, theme: PresentationThemeRef
if case let .local(theme) = theme {
resource = theme.resource
} else if case let .cloud(theme) = theme {
resource = theme.file?.resource
resource = theme.theme.file?.resource
}
if let resource = resource {
signal = telegramThemeData(account: context.account, accountManager: context.sharedContext.accountManager, resource: resource, synchronousLoad: false)

View File

@ -104,7 +104,7 @@ final class WallpaperColorPanelNode: ASDisplayNode, UITextFieldDelegate {
self.textFieldNode.textField.font = Font.regular(17.0)
self.textFieldNode.textField.textColor = self.theme.chat.inputPanel.inputTextColor
self.textFieldNode.textField.keyboardAppearance = self.theme.chat.inputPanel.keyboardColor.keyboardAppearance
self.textFieldNode.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.textFieldNode.textField.autocorrectionType = .no
self.textFieldNode.textField.autocapitalizationType = .allCharacters
self.textFieldNode.textField.keyboardType = .asciiCapable
@ -123,7 +123,7 @@ final class WallpaperColorPanelNode: ASDisplayNode, UITextFieldDelegate {
self.textBackgroundNode.image = textInputBackgroundImage(fieldColor: self.theme.chat.inputPanel.inputBackgroundColor, strokeColor: self.theme.chat.inputPanel.inputStrokeColor, diameter: 33.0)
self.textFieldNode.textField.textColor = self.theme.chat.inputPanel.inputTextColor
self.textFieldNode.textField.keyboardAppearance = self.theme.chat.inputPanel.keyboardColor.keyboardAppearance
self.textFieldNode.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.textFieldNode.textField.tintColor = self.theme.list.itemAccentColor
}

View File

@ -92,7 +92,7 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
func item(_ arguments: UsernameSetupControllerArguments) -> ListViewItem {
switch self {
case let .editablePublicLink(theme, strings, prefix, currentText, text):
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: prefix, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, spacing: 10.0, clearButton: true, tag: UsernameEntryTag.username, sectionId: self.section, textUpdated: { updatedText in
return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: prefix, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, spacing: 10.0, clearType: .always, tag: UsernameEntryTag.username, sectionId: self.section, textUpdated: { updatedText in
arguments.updatePublicLinkText(currentText, updatedText)
}, action: {
})

View File

@ -50,7 +50,7 @@ final class ShareInputFieldNodeTheme: Equatable {
extension ShareInputFieldNodeTheme {
convenience init(presentationTheme theme: PresentationTheme) {
self.init(backgroundColor: theme.actionSheet.inputBackgroundColor, textColor: theme.actionSheet.inputTextColor, placeholderColor: theme.actionSheet.inputPlaceholderColor, clearButtonColor: theme.actionSheet.inputClearButtonColor, accentColor: theme.actionSheet.controlAccentColor, keyboard: theme.chatList.searchBarKeyboardColor)
self.init(backgroundColor: theme.actionSheet.inputBackgroundColor, textColor: theme.actionSheet.inputTextColor, placeholderColor: theme.actionSheet.inputPlaceholderColor, clearButtonColor: theme.actionSheet.inputClearButtonColor, accentColor: theme.actionSheet.controlAccentColor, keyboard: theme.rootController.keyboardColor)
}
}

View File

@ -48,7 +48,7 @@ final class ShareSearchBarNode: ASDisplayNode, UITextFieldDelegate {
self.textInputNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
self.textInputNode.textField.keyboardAppearance = keyboardAppearance
self.textInputNode.textField.attributedPlaceholder = NSAttributedString(string: placeholder, font: Font.regular(16.0), textColor: theme.actionSheet.inputPlaceholderColor)
self.textInputNode.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textInputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textInputNode.textField.tintColor = theme.actionSheet.controlAccentColor
super.init()

View File

@ -130,6 +130,7 @@ private var declaredEncodables: Void = {
declareEncodable(CachedStickerQueryResult.self, f: { CachedStickerQueryResult(decoder: $0) })
declareEncodable(TelegramWallpaper.self, f: { TelegramWallpaper(decoder: $0) })
declareEncodable(TelegramTheme.self, f: { TelegramTheme(decoder: $0) })
declareEncodable(ThemeSettings.self, f: { ThemeSettings(decoder: $0) })
declareEncodable(SynchronizeMarkAllUnseenPersonalMessagesOperation.self, f: { SynchronizeMarkAllUnseenPersonalMessagesOperation(decoder: $0) })
declareEncodable(SynchronizeAppLogEventsOperation.self, f: { SynchronizeAppLogEventsOperation(decoder: $0) })
declareEncodable(CachedRecentPeers.self, f: { CachedRecentPeers(decoder: $0) })

View File

@ -268,6 +268,7 @@ private enum SharedDataKeyValues: Int32 {
case localizationSettings = 3
case proxySettings = 4
case autodownloadSettings = 5
case themeSettings = 6
}
public struct SharedDataKeys {
@ -300,6 +301,12 @@ public struct SharedDataKeys {
key.setInt32(0, value: SharedDataKeyValues.autodownloadSettings.rawValue)
return key
}()
public static let themeSettings: ValueBoxKey = {
let key = ValueBoxKey(length: 4)
key.setInt32(0, value: SharedDataKeyValues.themeSettings.rawValue)
return key
}()
}
public func applicationSpecificItemCacheCollectionId(_ value: Int8) -> Int8 {

View File

@ -140,12 +140,12 @@ private func saveUnsaveTheme(account: Account, theme: TelegramTheme, unsave: Boo
}
}
public func installTheme(account: Account, theme: TelegramTheme) -> Signal<Void, NoError> {
private func installTheme(account: Account, theme: TelegramTheme) -> Signal<Never, NoError> {
return account.network.request(Api.functions.account.installTheme(format: themeFormat, theme: Api.InputTheme.inputTheme(id: theme.id, accessHash: theme.accessHash)))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .complete()
}
|> mapToSignal { _ -> Signal<Void, NoError> in
|> mapToSignal { _ -> Signal<Never, NoError> in
return .complete()
}
}
@ -233,7 +233,11 @@ public func createTheme(account: Account, resource: MediaResource, title: String
|> mapError { _ in return CreateThemeError.generic }
|> mapToSignal { apiTheme -> Signal<CreateThemeResult, CreateThemeError> in
if let theme = TelegramTheme(apiTheme: apiTheme) {
return .single(.result(theme))
return account.postbox.transaction { transaction -> CreateThemeResult in
return .result(theme)
}
|> introduceError(CreateThemeError.self)
} else {
return .fail(.generic)
}
@ -299,3 +303,50 @@ public func updateTheme(account: Account, theme: TelegramTheme, title: String?,
}
}
}
public final class ThemeSettings: PreferencesEntry, Equatable {
public let currentTheme: TelegramTheme?
public init(currentTheme: TelegramTheme?) {
self.currentTheme = currentTheme
}
public init(decoder: PostboxDecoder) {
self.currentTheme = decoder.decodeObjectForKey("t", decoder: { TelegramTheme(decoder: $0) }) as? TelegramTheme
}
public func encode(_ encoder: PostboxEncoder) {
if let currentTheme = currentTheme {
encoder.encodeObject(currentTheme, forKey: "t")
} else {
encoder.encodeNil(forKey: "t")
}
}
public func isEqual(to: PreferencesEntry) -> Bool {
if let to = to as? ThemeSettings {
return self == to
} else {
return false
}
}
public static func ==(lhs: ThemeSettings, rhs: ThemeSettings) -> Bool {
return lhs.currentTheme == rhs.currentTheme
}
}
public func applyTheme(accountManager: AccountManager, account: Account, theme: TelegramTheme?) -> Signal<Never, NoError> {
return accountManager.transaction { transaction -> Signal<Never, NoError> in
transaction.updateSharedData(SharedDataKeys.themeSettings, { _ in
return ThemeSettings(currentTheme: theme)
})
if let theme = theme {
return installTheme(account: account, theme: theme)
} else {
return .complete()
}
}
|> switchToLatest
}

View File

@ -113,7 +113,8 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
statusBarStyle: .white,
tabBar: rootTabBar,
navigationBar: rootNavigationBar,
navigationSearchBar: navigationSearchBar
navigationSearchBar: navigationSearchBar,
keyboardColor: .dark
)
let switchColors = PresentationThemeSwitch(
@ -138,7 +139,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
itemHighlightedBackgroundColor: UIColor(rgb: 0x313135),
itemBlocksSeparatorColor: UIColor(rgb: 0x3d3d40),
itemPlainSeparatorColor: UIColor(rgb: 0x3d3d40),
disclosureArrowColor: UIColor(rgb: 0x5a5a5e),
disclosureArrowColor: UIColor(rgb: 0xffffff, alpha: 0.28),
sectionHeaderTextColor: UIColor(rgb: 0x8d8e93),
freeTextColor: UIColor(rgb: 0x8d8e93),
freeTextErrorColor: UIColor(rgb: 0xcf3030),
@ -200,7 +201,6 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
regularSearchBarColor: UIColor(rgb: 0x272728),
sectionHeaderFillColor: UIColor(rgb: 0x1c1c1d),
sectionHeaderTextColor: UIColor(rgb: 0xffffff),
searchBarKeyboardColor: .dark,
verifiedIconFillColor: accentColor,
verifiedIconForegroundColor: badgeTextColor,
secretIconColor: secretColor,
@ -258,7 +258,6 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
primaryTextColor: .white,
secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5),
mediaRecordingDotColor: destructiveColor,
keyboardColor: .dark,
mediaRecordingControl: inputPanelMediaRecordingControl
)

View File

@ -81,7 +81,8 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
statusBarStyle: .white,
tabBar: rootTabBar,
navigationBar: rootNavigationBar,
navigationSearchBar: navigationSearchBar
navigationSearchBar: navigationSearchBar,
keyboardColor: .dark
)
let switchColors = PresentationThemeSwitch(
@ -168,7 +169,6 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
regularSearchBarColor: accentColor.withMultiplied(hue: 1.029, saturation: 0.609, brightness: 0.12),
sectionHeaderFillColor: mainBackgroundColor,
sectionHeaderTextColor: mainSecondaryTextColor.withAlphaComponent(0.5),
searchBarKeyboardColor: .dark,
verifiedIconFillColor: accentColor,
verifiedIconForegroundColor: .white,
secretIconColor: secretColor,
@ -228,7 +228,6 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
primaryTextColor: UIColor(rgb: 0xffffff),
secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5),
mediaRecordingDotColor: accentColor,
keyboardColor: .dark,
mediaRecordingControl: inputPanelMediaRecordingControl
)

View File

@ -93,7 +93,8 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
statusBarStyle: .black,
tabBar: rootTabBar,
navigationBar: rootNavigationBar,
navigationSearchBar: navigationSearchBar
navigationSearchBar: navigationSearchBar,
keyboardColor: .light
)
let switchColors = PresentationThemeSwitch(
@ -180,7 +181,6 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
regularSearchBarColor: UIColor(rgb: 0xe9e9e9),
sectionHeaderFillColor: UIColor(rgb: 0xf7f7f7),
sectionHeaderTextColor: UIColor(rgb: 0x8e8e93),
searchBarKeyboardColor: .light,
verifiedIconFillColor: accentColor,
verifiedIconForegroundColor: .white,
secretIconColor: secretColor,
@ -264,7 +264,6 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
primaryTextColor: .black,
secondaryTextColor: UIColor(rgb: 0x8e8e93),
mediaRecordingDotColor: UIColor(rgb: 0xed2521),
keyboardColor: .light,
mediaRecordingControl: inputPanelMediaRecordingControl
)

View File

@ -30,7 +30,7 @@ public func makePresentationTheme(mediaBox: MediaBox, themeReference: Presentati
theme = makeDefaultPresentationTheme(reference: .dayClassic, accentColor: nil, serviceBackgroundColor: serviceBackgroundColor, baseColor: baseColor, preview: preview)
}
case let .cloud(info):
if let file = info.file, let path = mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let loadedTheme = makePresentationTheme(data: data) {
if let file = info.theme.file, let path = mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let loadedTheme = makePresentationTheme(data: data, resolvedWallpaper: info.resolvedWallpaper) {
theme = loadedTheme
} else {
theme = makeDefaultPresentationTheme(reference: .dayClassic, accentColor: nil, serviceBackgroundColor: serviceBackgroundColor, baseColor: baseColor, preview: preview)

View File

@ -140,12 +140,14 @@ public final class PresentationThemeRootController {
public let tabBar: PresentationThemeRootTabBar
public let navigationBar: PresentationThemeRootNavigationBar
public let navigationSearchBar: PresentationThemeNavigationSearchBar
public let keyboardColor: PresentationThemeKeyboardColor
public init(statusBarStyle: PresentationThemeStatusBarStyle, tabBar: PresentationThemeRootTabBar, navigationBar: PresentationThemeRootNavigationBar, navigationSearchBar: PresentationThemeNavigationSearchBar) {
public init(statusBarStyle: PresentationThemeStatusBarStyle, tabBar: PresentationThemeRootTabBar, navigationBar: PresentationThemeRootNavigationBar, navigationSearchBar: PresentationThemeNavigationSearchBar, keyboardColor: PresentationThemeKeyboardColor) {
self.statusBarStyle = statusBarStyle
self.tabBar = tabBar
self.navigationBar = navigationBar
self.navigationSearchBar = navigationSearchBar
self.keyboardColor = keyboardColor
}
}
@ -397,7 +399,6 @@ public final class PresentationThemeChatList {
public let regularSearchBarColor: UIColor
public let sectionHeaderFillColor: UIColor
public let sectionHeaderTextColor: UIColor
public let searchBarKeyboardColor: PresentationThemeKeyboardColor
public let verifiedIconFillColor: UIColor
public let verifiedIconForegroundColor: UIColor
public let secretIconColor: UIColor
@ -405,7 +406,7 @@ public final class PresentationThemeChatList {
public let unpinnedArchiveAvatarColor: PresentationThemeArchiveAvatarColors
public let onlineDotColor: UIColor
init(backgroundColor: UIColor, itemSeparatorColor: UIColor, itemBackgroundColor: UIColor, pinnedItemBackgroundColor: UIColor, itemHighlightedBackgroundColor: UIColor, itemSelectedBackgroundColor: UIColor, titleColor: UIColor, secretTitleColor: UIColor, dateTextColor: UIColor, authorNameColor: UIColor, messageTextColor: UIColor, messageDraftTextColor: UIColor, checkmarkColor: UIColor, pendingIndicatorColor: UIColor, failedFillColor: UIColor, failedForegroundColor: UIColor, muteIconColor: UIColor, unreadBadgeActiveBackgroundColor: UIColor, unreadBadgeActiveTextColor: UIColor, unreadBadgeInactiveBackgroundColor: UIColor, unreadBadgeInactiveTextColor: UIColor, pinnedBadgeColor: UIColor, pinnedSearchBarColor: UIColor, regularSearchBarColor: UIColor, sectionHeaderFillColor: UIColor, sectionHeaderTextColor: UIColor, searchBarKeyboardColor: PresentationThemeKeyboardColor, verifiedIconFillColor: UIColor, verifiedIconForegroundColor: UIColor, secretIconColor: UIColor, pinnedArchiveAvatarColor: PresentationThemeArchiveAvatarColors, unpinnedArchiveAvatarColor: PresentationThemeArchiveAvatarColors, onlineDotColor: UIColor) {
init(backgroundColor: UIColor, itemSeparatorColor: UIColor, itemBackgroundColor: UIColor, pinnedItemBackgroundColor: UIColor, itemHighlightedBackgroundColor: UIColor, itemSelectedBackgroundColor: UIColor, titleColor: UIColor, secretTitleColor: UIColor, dateTextColor: UIColor, authorNameColor: UIColor, messageTextColor: UIColor, messageDraftTextColor: UIColor, checkmarkColor: UIColor, pendingIndicatorColor: UIColor, failedFillColor: UIColor, failedForegroundColor: UIColor, muteIconColor: UIColor, unreadBadgeActiveBackgroundColor: UIColor, unreadBadgeActiveTextColor: UIColor, unreadBadgeInactiveBackgroundColor: UIColor, unreadBadgeInactiveTextColor: UIColor, pinnedBadgeColor: UIColor, pinnedSearchBarColor: UIColor, regularSearchBarColor: UIColor, sectionHeaderFillColor: UIColor, sectionHeaderTextColor: UIColor, verifiedIconFillColor: UIColor, verifiedIconForegroundColor: UIColor, secretIconColor: UIColor, pinnedArchiveAvatarColor: PresentationThemeArchiveAvatarColors, unpinnedArchiveAvatarColor: PresentationThemeArchiveAvatarColors, onlineDotColor: UIColor) {
self.backgroundColor = backgroundColor
self.itemSeparatorColor = itemSeparatorColor
self.itemBackgroundColor = itemBackgroundColor
@ -432,7 +433,6 @@ public final class PresentationThemeChatList {
self.regularSearchBarColor = regularSearchBarColor
self.sectionHeaderFillColor = sectionHeaderFillColor
self.sectionHeaderTextColor = sectionHeaderTextColor
self.searchBarKeyboardColor = searchBarKeyboardColor
self.verifiedIconFillColor = verifiedIconFillColor
self.verifiedIconForegroundColor = verifiedIconForegroundColor
self.secretIconColor = secretIconColor
@ -715,10 +715,9 @@ public final class PresentationThemeChatInputPanel {
public let primaryTextColor: UIColor
public let secondaryTextColor: UIColor
public let mediaRecordingDotColor: UIColor
public let keyboardColor: PresentationThemeKeyboardColor
public let mediaRecordingControl: PresentationThemeChatInputPanelMediaRecordingControl
public init(panelBackgroundColor: UIColor, panelSeparatorColor: UIColor, panelControlAccentColor: UIColor, panelControlColor: UIColor, panelControlDisabledColor: UIColor, panelControlDestructiveColor: UIColor, inputBackgroundColor: UIColor, inputStrokeColor: UIColor, inputPlaceholderColor: UIColor, inputTextColor: UIColor, inputControlColor: UIColor, actionControlFillColor: UIColor, actionControlForegroundColor: UIColor, primaryTextColor: UIColor, secondaryTextColor: UIColor, mediaRecordingDotColor: UIColor, keyboardColor: PresentationThemeKeyboardColor, mediaRecordingControl: PresentationThemeChatInputPanelMediaRecordingControl) {
public init(panelBackgroundColor: UIColor, panelSeparatorColor: UIColor, panelControlAccentColor: UIColor, panelControlColor: UIColor, panelControlDisabledColor: UIColor, panelControlDestructiveColor: UIColor, inputBackgroundColor: UIColor, inputStrokeColor: UIColor, inputPlaceholderColor: UIColor, inputTextColor: UIColor, inputControlColor: UIColor, actionControlFillColor: UIColor, actionControlForegroundColor: UIColor, primaryTextColor: UIColor, secondaryTextColor: UIColor, mediaRecordingDotColor: UIColor, mediaRecordingControl: PresentationThemeChatInputPanelMediaRecordingControl) {
self.panelBackgroundColor = panelBackgroundColor
self.panelSeparatorColor = panelSeparatorColor
self.panelControlAccentColor = panelControlAccentColor
@ -735,7 +734,6 @@ public final class PresentationThemeChatInputPanel {
self.primaryTextColor = primaryTextColor
self.secondaryTextColor = secondaryTextColor
self.mediaRecordingDotColor = mediaRecordingDotColor
self.keyboardColor = keyboardColor
self.mediaRecordingControl = mediaRecordingControl
}
}
@ -822,6 +820,10 @@ public final class PresentationThemeChat {
self.inputButtonPanel = inputButtonPanel
self.historyNavigation = historyNavigation
}
public func withUpdatedDefaultWallpaper(_ defaultWallpaper: TelegramWallpaper?) -> PresentationThemeChat {
return PresentationThemeChat(defaultWallpaper: defaultWallpaper ?? self.defaultWallpaper, message: self.message, serviceMessage: self.serviceMessage, inputPanel: self.inputPanel, inputMediaPanel: self.inputMediaPanel, inputButtonPanel: self.inputButtonPanel, historyNavigation: self.historyNavigation)
}
}
public enum PresentationThemeExpandedNotificationBackgroundType: Int32 {
@ -974,4 +976,21 @@ public final class PresentationTheme: Equatable {
public static func ==(lhs: PresentationTheme, rhs: PresentationTheme) -> Bool {
return lhs === rhs
}
public func withUpdated(name: String?, author: String?, defaultWallpaper: TelegramWallpaper?) -> PresentationTheme {
var defaultWallpaper = defaultWallpaper
if let wallpaper = defaultWallpaper {
switch wallpaper {
case .image:
defaultWallpaper = nil
case let .file(file):
if file.isPattern {
defaultWallpaper = nil
}
default:
break
}
}
return PresentationTheme(name: name.flatMap(PresentationThemeName.custom) ?? .custom(self.name.string), author: author ?? self.author, referenceTheme: self.referenceTheme, overallDarkAppearance: self.overallDarkAppearance, baseColor: nil, intro: self.intro, passcode: self.passcode, rootController: self.rootController, list: self.list, chatList: self.chatList, chat: self.chat.withUpdatedDefaultWallpaper(defaultWallpaper), actionSheet: self.actionSheet, contextMenu: self.contextMenu, inAppNotification: self.inAppNotification)
}
}

View File

@ -1,5 +1,6 @@
import Foundation
import UIKit
import Postbox
import TelegramCore
import TelegramUIPreferences
@ -35,7 +36,7 @@ extension TelegramWallpaper: Codable {
if let color = UIColor(hexString: value) {
self = .color(Int32(bitPattern: color.rgb))
} else {
throw PresentationThemeDecodingError.generic
self = .file(id: 0, accessHash: 0, isCreator: false, isDefault: false, isPattern: false, isDark: false, slug: value, file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], immediateThumbnailData: nil, mimeType: "", size: nil, attributes: []), settings: WallpaperSettings(blur: false, motion: false, color: nil, intensity: nil))
}
}
} else {
@ -50,6 +51,8 @@ extension TelegramWallpaper: Codable {
try container.encode("builtin")
case let .color(value):
try container.encode(String(format: "%06x", value))
case let .file(file):
try container.encode(file.slug)
default:
break
}
@ -354,6 +357,7 @@ extension PresentationThemeRootController: Codable {
case tabBar
case navBar
case searchBar
case keyboard
}
public convenience init(from decoder: Decoder) throws {
@ -361,7 +365,8 @@ extension PresentationThemeRootController: Codable {
self.init(statusBarStyle: try values.decode(PresentationThemeStatusBarStyle.self, forKey: .statusBar),
tabBar: try values.decode(PresentationThemeRootTabBar.self, forKey: .tabBar),
navigationBar: try values.decode(PresentationThemeRootNavigationBar.self, forKey: .navBar),
navigationSearchBar: try values.decode(PresentationThemeNavigationSearchBar.self, forKey: .searchBar))
navigationSearchBar: try values.decode(PresentationThemeNavigationSearchBar.self, forKey: .searchBar),
keyboardColor: try values.decode(PresentationThemeKeyboardColor.self, forKey: .keyboard))
}
public func encode(to encoder: Encoder) throws {
@ -370,6 +375,7 @@ extension PresentationThemeRootController: Codable {
try values.encode(self.tabBar, forKey: .tabBar)
try values.encode(self.navigationBar, forKey: .navBar)
try values.encode(self.navigationSearchBar, forKey: .searchBar)
try values.encode(self.keyboardColor, forKey: .keyboard)
}
}
@ -721,7 +727,6 @@ extension PresentationThemeChatList: Codable {
case regularSearchBar
case sectionHeaderBg
case sectionHeaderText
case searchBarKeyboard
case verifiedIconBg
case verifiedIconFg
case secretIcon
@ -758,7 +763,6 @@ extension PresentationThemeChatList: Codable {
regularSearchBarColor: try decodeColor(values, .regularSearchBar),
sectionHeaderFillColor: try decodeColor(values, .sectionHeaderBg),
sectionHeaderTextColor: try decodeColor(values, .sectionHeaderText),
searchBarKeyboardColor: try values.decode(PresentationThemeKeyboardColor.self, forKey: .searchBarKeyboard),
verifiedIconFillColor: try decodeColor(values, .verifiedIconBg),
verifiedIconForegroundColor: try decodeColor(values, .verifiedIconFg),
secretIconColor: try decodeColor(values, .secretIcon),
@ -795,7 +799,6 @@ extension PresentationThemeChatList: Codable {
try encodeColor(&values, self.regularSearchBarColor, .regularSearchBar)
try encodeColor(&values, self.sectionHeaderFillColor, .sectionHeaderBg)
try encodeColor(&values, self.sectionHeaderTextColor, .sectionHeaderText)
try values.encode(self.searchBarKeyboardColor, forKey: .searchBarKeyboard)
try encodeColor(&values, self.verifiedIconFillColor, .verifiedIconBg)
try encodeColor(&values, self.verifiedIconForegroundColor, .verifiedIconFg)
try encodeColor(&values, self.secretIconColor, .secretIcon)
@ -1143,7 +1146,6 @@ extension PresentationThemeChatInputPanel: Codable {
case primaryText
case secondaryText
case mediaRecordDot
case keyboard
case mediaRecordControl
}
@ -1165,7 +1167,6 @@ extension PresentationThemeChatInputPanel: Codable {
primaryTextColor: try decodeColor(values, .primaryText),
secondaryTextColor: try decodeColor(values, .secondaryText),
mediaRecordingDotColor: try decodeColor(values, .mediaRecordDot),
keyboardColor: try values.decode(PresentationThemeKeyboardColor.self, forKey: .keyboard),
mediaRecordingControl: try values.decode(PresentationThemeChatInputPanelMediaRecordingControl.self, forKey: .mediaRecordControl))
}
@ -1187,7 +1188,6 @@ extension PresentationThemeChatInputPanel: Codable {
try encodeColor(&values, self.primaryTextColor, .primaryText)
try encodeColor(&values, self.secondaryTextColor, .secondaryText)
try encodeColor(&values, self.mediaRecordingDotColor, .mediaRecordDot)
try values.encode(self.keyboardColor, forKey: .keyboard)
try values.encode(self.mediaRecordingControl, forKey: .mediaRecordControl)
}
}
@ -1313,7 +1313,15 @@ extension PresentationThemeChat: Codable {
public convenience init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.init(defaultWallpaper: try values.decode(TelegramWallpaper.self, forKey: .defaultWallpaper),
var wallpaper = try values.decode(TelegramWallpaper.self, forKey: .defaultWallpaper)
if let decoder = decoder as? PresentationThemeDecoding {
if case .file = wallpaper, let resolvedWallpaper = decoder.resolvedWallpaper {
wallpaper = resolvedWallpaper
}
}
self.init(defaultWallpaper: wallpaper,
message: try values.decode(PresentationThemeChatMessage.self, forKey: .message),
serviceMessage: try values.decode(PresentationThemeServiceMessage.self, forKey: .serviceMessage),
inputPanel: try values.decode(PresentationThemeChatInputPanel.self, forKey: .inputPanel),

View File

@ -1,4 +1,5 @@
import Foundation
import TelegramCore
public func encodePresentationTheme(_ theme: PresentationTheme) -> String? {
let encoding = PresentationThemeEncoding()
@ -321,7 +322,7 @@ private class PresentationThemeDecodingLevel {
}
}
public func makePresentationTheme(data: Data) -> PresentationTheme? {
public func makePresentationTheme(data: Data, resolvedWallpaper: TelegramWallpaper? = nil) -> PresentationTheme? {
guard let string = String(data: data, encoding: .utf8) else {
return nil
}
@ -378,6 +379,7 @@ public func makePresentationTheme(data: Data) -> PresentationTheme? {
}
let decoder = PresentationThemeDecoding(referencing: topLevel.data)
decoder.resolvedWallpaper = resolvedWallpaper
if let value = try? decoder.unbox(topLevel.data, as: PresentationTheme.self) {
return value
}
@ -395,6 +397,7 @@ class PresentationThemeDecoding: Decoder {
var referenceTheme: PresentationTheme?
var serviceBackgroundColor: UIColor?
var resolvedWallpaper: TelegramWallpaper?
private var _referenceCoding: PresentationThemeEncoding?
fileprivate var referenceCoding: PresentationThemeEncoding? {

View File

@ -136,7 +136,7 @@ final class AuthorizedApplicationContext {
self.notificationController = NotificationContainerController(context: context)
self.mainWindow.previewThemeAccentColor = presentationData.theme.rootController.navigationBar.accentTextColor
self.mainWindow.previewThemeDarkBlur = presentationData.theme.chatList.searchBarKeyboardColor == .dark
self.mainWindow.previewThemeDarkBlur = presentationData.theme.rootController.keyboardColor == .dark
self.mainWindow.setupVolumeControlStatusBarGraphics(presentationData.volumeControlStatusBarIcons.images)
self.rootController = TelegramRootController(context: context)
@ -740,7 +740,7 @@ final class AuthorizedApplicationContext {
if let strongSelf = self {
if previousTheme.swap(presentationData.theme) !== presentationData.theme {
strongSelf.mainWindow.previewThemeAccentColor = presentationData.theme.rootController.navigationBar.accentTextColor
strongSelf.mainWindow.previewThemeDarkBlur = presentationData.theme.chatList.searchBarKeyboardColor == .dark
strongSelf.mainWindow.previewThemeDarkBlur = presentationData.theme.rootController.keyboardColor == .dark
strongSelf.lockedCoveringView.updateTheme(presentationData.theme)
strongSelf.rootController.updateTheme(NavigationControllerTheme(presentationTheme: presentationData.theme))
}

View File

@ -120,7 +120,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
#endif
self.codeField.textField.returnKeyType = .done
self.codeField.textField.textColor = self.theme.list.itemPrimaryTextColor
self.codeField.textField.keyboardAppearance = self.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.codeField.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.codeField.textField.disableAutomaticKeyboardHandling = [.forward, .backward]
self.codeField.textField.tintColor = self.theme.list.itemAccentColor

View File

@ -70,7 +70,7 @@ final class AuthorizationSequencePasswordEntryControllerNode: ASDisplayNode, UIT
self.codeField.textField.textAlignment = .natural
self.codeField.textField.isSecureTextEntry = true
self.codeField.textField.returnKeyType = .done
self.codeField.textField.keyboardAppearance = self.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.codeField.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.codeField.textField.disableAutomaticKeyboardHandling = [.forward, .backward]
self.codeField.textField.tintColor = self.theme.list.itemAccentColor

View File

@ -58,7 +58,7 @@ final class AuthorizationSequencePasswordRecoveryControllerNode: ASDisplayNode,
self.codeField.textField.textAlignment = .center
self.codeField.textField.attributedPlaceholder = NSAttributedString(string: self.strings.TwoStepAuth_RecoveryCode, font: Font.regular(20.0), textColor: self.theme.list.itemPlaceholderTextColor)
self.codeField.textField.returnKeyType = .done
self.codeField.textField.keyboardAppearance = self.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.codeField.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.codeField.textField.disableAutomaticKeyboardHandling = [.forward, .backward]
self.codeField.textField.tintColor = self.theme.list.itemAccentColor

View File

@ -103,8 +103,8 @@ private final class PhoneAndCountryNode: ASDisplayNode {
self.addSubnode(self.countryButton)
self.addSubnode(self.phoneInputNode)
self.phoneInputNode.countryCodeField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.phoneInputNode.numberField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.phoneInputNode.countryCodeField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.phoneInputNode.numberField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.phoneInputNode.countryCodeField.textField.textColor = theme.list.itemPrimaryTextColor
self.phoneInputNode.numberField.textField.textColor = theme.list.itemPrimaryTextColor
self.phoneInputNode.countryCodeField.textField.tintColor = theme.list.itemAccentColor

View File

@ -108,7 +108,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
self.firstNameField.textField.textContentType = .givenName
}
self.firstNameField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.firstNameField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.firstNameField.textField.tintColor = theme.list.itemAccentColor
self.lastNameField = TextFieldNode()
@ -122,7 +122,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
self.lastNameField.textField.textContentType = .familyName
}
self.lastNameField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.lastNameField.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.lastNameField.textField.tintColor = theme.list.itemAccentColor
self.currentPhotoNode = ASImageNode()

View File

@ -2769,7 +2769,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
self.chatDisplayNode.updateTypingActivity = { [weak self] value in
if let strongSelf = self, strongSelf.presentationInterfaceState.interfaceState.editMessage == nil {
if let strongSelf = self, strongSelf.presentationInterfaceState.interfaceState.editMessage == nil && !strongSelf.presentationInterfaceState.isScheduledMessages {
if value {
strongSelf.typingActivityPromise.set(Signal<Bool, NoError>.single(true)
|> then(
@ -5155,7 +5155,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
ActionSheetButtonItem(title: self.presentationData.strings.Conversation_FileICloudDrive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
if let strongSelf = self {
strongSelf.present(legacyICloudFileController(theme: strongSelf.presentationData.theme, completion: { urls in
strongSelf.present(legacyICloudFilePicker(theme: strongSelf.presentationData.theme, completion: { urls in
if let strongSelf = self, !urls.isEmpty {
var signals: [Signal<ICloudFileDescription?, NoError>] = []
for url in urls {

View File

@ -186,7 +186,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.effectView = UIVisualEffectView()
if #available(iOS 9.0, *) {
} else {
if self.presentationData.theme.chatList.searchBarKeyboardColor == .dark {
if self.presentationData.theme.rootController.keyboardColor == .dark {
self.effectView.effect = UIBlurEffect(style: .dark)
} else {
self.effectView.effect = UIBlurEffect(style: .light)
@ -310,7 +310,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
if #available(iOS 9.0, *) {
} else {
if self.presentationData.theme.chatList.searchBarKeyboardColor == .dark {
if self.presentationData.theme.rootController.keyboardColor == .dark {
self.effectView.effect = UIBlurEffect(style: .dark)
} else {
self.effectView.effect = UIBlurEffect(style: .light)

View File

@ -502,7 +502,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
textColor = presentationInterfaceState.theme.chat.inputPanel.inputTextColor
tintColor = presentationInterfaceState.theme.list.itemAccentColor
baseFontSize = max(17.0, presentationInterfaceState.fontSize.baseDisplaySize)
keyboardAppearance = presentationInterfaceState.theme.chat.inputPanel.keyboardColor.keyboardAppearance
keyboardAppearance = presentationInterfaceState.theme.rootController.keyboardColor.keyboardAppearance
}
let paragraphStyle = NSMutableParagraphStyle()
@ -691,7 +691,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
}
let keyboardAppearance = interfaceState.theme.chat.inputPanel.keyboardColor.keyboardAppearance
let keyboardAppearance = interfaceState.theme.rootController.keyboardColor.keyboardAppearance
if let textInputNode = self.textInputNode, textInputNode.keyboardAppearance != keyboardAppearance, textInputNode.isFirstResponder() {
if textInputNode.isCurrentlyEmoji() {
textInputNode.initialPrimaryLanguage = "emoji"

View File

@ -52,7 +52,7 @@ private final class ChatTextLinkEditInputFieldNode: ASDisplayNode, ASEditableTex
self.textInputNode.clipsToBounds = true
self.textInputNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
self.textInputNode.textContainerInset = UIEdgeInsets(top: self.inputInsets.top, left: 0.0, bottom: self.inputInsets.bottom, right: 0.0)
self.textInputNode.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textInputNode.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textInputNode.keyboardType = .URL
self.textInputNode.autocapitalizationType = .none
self.textInputNode.returnKeyType = .done
@ -77,7 +77,7 @@ private final class ChatTextLinkEditInputFieldNode: ASDisplayNode, ASEditableTex
self.theme = theme
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 33.0, color: self.theme.actionSheet.inputHollowBackgroundColor, strokeColor: self.theme.actionSheet.inputBorderColor, strokeWidth: 1.0)
self.textInputNode.keyboardAppearance = self.theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textInputNode.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.placeholderNode.attributedText = NSAttributedString(string: self.placeholderNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
self.textInputNode.tintColor = self.theme.actionSheet.controlAccentColor
}

View File

@ -67,7 +67,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
}
self.contactListNode = ContactListNode(context: context, presentation: .single(.natural(options: options, includeChatList: includeChatList)), filters: filters, selectionState: ContactListNodeGroupSelectionState())
self.tokenListNode = EditableTokenListNode(theme: EditableTokenListNodeTheme(backgroundColor: self.presentationData.theme.rootController.navigationBar.backgroundColor, separatorColor: self.presentationData.theme.rootController.navigationBar.separatorColor, placeholderTextColor: self.presentationData.theme.list.itemPlaceholderTextColor, primaryTextColor: self.presentationData.theme.list.itemPrimaryTextColor, selectedTextColor: self.presentationData.theme.list.itemAccentColor, accentColor: self.presentationData.theme.list.itemAccentColor, keyboardColor: self.presentationData.theme.chatList.searchBarKeyboardColor), placeholder: placeholder)
self.tokenListNode = EditableTokenListNode(theme: EditableTokenListNodeTheme(backgroundColor: self.presentationData.theme.rootController.navigationBar.backgroundColor, separatorColor: self.presentationData.theme.rootController.navigationBar.separatorColor, placeholderTextColor: self.presentationData.theme.list.itemPlaceholderTextColor, primaryTextColor: self.presentationData.theme.list.itemPrimaryTextColor, selectedTextColor: self.presentationData.theme.list.itemAccentColor, accentColor: self.presentationData.theme.list.itemAccentColor, keyboardColor: self.presentationData.theme.rootController.keyboardColor), placeholder: placeholder)
super.init()

View File

@ -263,7 +263,7 @@ class PaneSearchBarNode: ASDisplayNode, UITextFieldDelegate {
self.iconNode.image = generateLoupeIcon(color: theme.chat.inputMediaPanel.stickersSearchControlColor)
self.clearButton.setImage(generateClearIcon(color: theme.chat.inputMediaPanel.stickersSearchControlColor), for: [])
self.cancelButton.setAttributedTitle(NSAttributedString(string: strings.Common_Cancel, font: Font.regular(17.0), textColor: theme.chat.inputPanel.panelControlAccentColor), for: [])
self.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
self.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textField.tintColor = theme.list.itemAccentColor
if let (boundingSize, leftInset, rightInset) = self.validLayout {

View File

@ -62,7 +62,6 @@
09FFBCD72281BB2D00C33B4B /* ChatTextLinkEditController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FFBCD62281BB2D00C33B4B /* ChatTextLinkEditController.swift */; };
D000CABC21F158AD0011B15D /* PrepareSecretThumbnailData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D000CABB21F158AD0011B15D /* PrepareSecretThumbnailData.swift */; };
D0068FA821760FA300D1B315 /* StoreDownloadedMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0068FA721760FA300D1B315 /* StoreDownloadedMedia.swift */; };
D007019C2029E8F2006B9E34 /* LegacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegacyICloudFileController.swift */; };
D007019E2029EFDD006B9E34 /* ICloudResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019D2029EFDD006B9E34 /* ICloudResources.swift */; };
D008178222B47464008A895F /* NotificationContentContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D008178122B47464008A895F /* NotificationContentContext.swift */; };
D00817D022B47A14008A895F /* WakeupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00817B622B47A12008A895F /* WakeupManager.swift */; };
@ -634,7 +633,6 @@
D002A0DA1E9C190700A81812 /* SoftwareVideoThumbnailLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareVideoThumbnailLayer.swift; sourceTree = "<group>"; };
D002A0DC1E9CD52A00A81812 /* ChatMediaInputRecentGifsItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatMediaInputRecentGifsItem.swift; sourceTree = "<group>"; };
D0068FA721760FA300D1B315 /* StoreDownloadedMedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreDownloadedMedia.swift; sourceTree = "<group>"; };
D007019B2029E8F2006B9E34 /* LegacyICloudFileController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyICloudFileController.swift; sourceTree = "<group>"; };
D007019D2029EFDD006B9E34 /* ICloudResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICloudResources.swift; sourceTree = "<group>"; };
D008178122B47464008A895F /* NotificationContentContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentContext.swift; sourceTree = "<group>"; };
D00817B622B47A12008A895F /* WakeupManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WakeupManager.swift; sourceTree = "<group>"; };
@ -1740,7 +1738,6 @@
children = (
D00E15251DDBD4E700ACF65C /* LegacyCamera.swift */,
D06BB8811F58994B0084FC30 /* LegacyInstantVideoController.swift */,
D007019B2029E8F2006B9E34 /* LegacyICloudFileController.swift */,
D0380DAC204ED434000414AB /* LegacyLiveUploadInterface.swift */,
D0B21B1E22156D92003F741D /* LegacyCache.swift */,
);
@ -3064,7 +3061,6 @@
090B48C82200BCA8005083FA /* WallpaperUploadManager.swift in Sources */,
09F2158D225CF5BC00AEDF6D /* Pasteboard.swift in Sources */,
D0C26D571FDF2388004ABF18 /* OpenChatMessage.swift in Sources */,
D007019C2029E8F2006B9E34 /* LegacyICloudFileController.swift in Sources */,
D000CABC21F158AD0011B15D /* PrepareSecretThumbnailData.swift in Sources */,
D08BDF641FA37BEA009D08E1 /* ChatRecordingPreviewInputPanelNode.swift in Sources */,
D0943B071FDEC529001522CC /* InstantVideoRadialStatusNode.swift in Sources */,

View File

@ -56,10 +56,42 @@ public struct PresentationLocalTheme: PostboxCoding, Equatable {
}
}
public struct PresentationCloudTheme: PostboxCoding, Equatable {
public let theme: TelegramTheme
public let resolvedWallpaper: TelegramWallpaper?
public init(theme: TelegramTheme, resolvedWallpaper: TelegramWallpaper?) {
self.theme = theme
self.resolvedWallpaper = resolvedWallpaper
}
public init(decoder: PostboxDecoder) {
self.theme = decoder.decodeObjectForKey("theme", decoder: { TelegramTheme(decoder: $0) }) as! TelegramTheme
self.resolvedWallpaper = decoder.decodeObjectForKey("wallpaper", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeObject(self.theme, forKey: "theme")
if let resolvedWallpaper = self.resolvedWallpaper {
encoder.encodeObject(resolvedWallpaper, forKey: "wallpaper")
}
}
public static func ==(lhs: PresentationCloudTheme, rhs: PresentationCloudTheme) -> Bool {
if lhs.theme != rhs.theme {
return false
}
if lhs.resolvedWallpaper != rhs.resolvedWallpaper {
return false
}
return true
}
}
public enum PresentationThemeReference: PostboxCoding, Equatable {
case builtin(PresentationBuiltinThemeReference)
case local(PresentationLocalTheme)
case cloud(TelegramTheme)
case cloud(PresentationCloudTheme)
public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("v", orElse: 0) {
@ -68,7 +100,7 @@ public enum PresentationThemeReference: PostboxCoding, Equatable {
case 1:
self = .local(decoder.decodeObjectForKey("localTheme", decoder: { PresentationLocalTheme(decoder: $0) }) as! PresentationLocalTheme)
case 2:
self = .cloud(decoder.decodeObjectForKey("theme", decoder: { TelegramTheme(decoder: $0) }) as! TelegramTheme)
self = .cloud(decoder.decodeObjectForKey("cloudTheme", decoder: { PresentationCloudTheme(decoder: $0) }) as! PresentationCloudTheme)
default:
assertionFailure()
self = .builtin(.dayClassic)
@ -85,7 +117,7 @@ public enum PresentationThemeReference: PostboxCoding, Equatable {
encoder.encodeObject(theme, forKey: "localTheme")
case let .cloud(theme):
encoder.encodeInt32(2, forKey: "v")
encoder.encodeObject(theme, forKey: "theme")
encoder.encodeObject(theme, forKey: "cloudTheme")
}
}
@ -135,7 +167,7 @@ public enum PresentationThemeReference: PostboxCoding, Equatable {
id = themeId(for: theme.resource.fileId)
case let .cloud(theme):
namespace = 2
id = themeId(for: theme.id)
id = themeId(for: theme.theme.id)
}
return (Int64(namespace) << 32) | Int64(bitPattern: UInt64(UInt32(bitPattern: id)))
@ -379,9 +411,12 @@ public struct PresentationThemeSettings: PreferencesEntry {
case let .local(theme):
resources.append(theme.resource.id)
case let .cloud(theme):
if let file = theme.file {
if let file = theme.theme.file {
resources.append(file.resource.id)
}
if let chatWallpaper = theme.resolvedWallpaper {
resources.append(contentsOf: wallpaperResources(chatWallpaper))
}
}
return resources
}