mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Add support for web app header and background color customization
This commit is contained in:
@@ -74,7 +74,7 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
case suggestedPreset(index: PresetIndex, title: String, label: String, preset: ChatListFilterData)
|
case suggestedPreset(index: PresetIndex, title: String, label: String, preset: ChatListFilterData)
|
||||||
case suggestedAddCustom(String)
|
case suggestedAddCustom(String)
|
||||||
case listHeader(String)
|
case listHeader(String)
|
||||||
case preset(index: PresetIndex, title: String, label: String, preset: ChatListFilter, canBeReordered: Bool, canBeDeleted: Bool, isEditing: Bool, isAllChats: Bool)
|
case preset(index: PresetIndex, title: String, label: String, preset: ChatListFilter, canBeReordered: Bool, canBeDeleted: Bool, isEditing: Bool, isAllChats: Bool, isDisabled: Bool)
|
||||||
case addItem(text: String, isEditing: Bool)
|
case addItem(text: String, isEditing: Bool)
|
||||||
case listFooter(String)
|
case listFooter(String)
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
return 0
|
return 0
|
||||||
case .listHeader:
|
case .listHeader:
|
||||||
return 100
|
return 100
|
||||||
case let .preset(index, _, _, _, _, _, _, _):
|
case let .preset(index, _, _, _, _, _, _, _, _):
|
||||||
return 101 + index.value
|
return 101 + index.value
|
||||||
case .addItem:
|
case .addItem:
|
||||||
return 1000
|
return 1000
|
||||||
@@ -122,7 +122,7 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
return .suggestedAddCustom
|
return .suggestedAddCustom
|
||||||
case .listHeader:
|
case .listHeader:
|
||||||
return .listHeader
|
return .listHeader
|
||||||
case let .preset(_, _, _, preset, _, _, _, _):
|
case let .preset(_, _, _, preset, _, _, _, _, _):
|
||||||
return .preset(preset.id)
|
return .preset(preset.id)
|
||||||
case .addItem:
|
case .addItem:
|
||||||
return .addItem
|
return .addItem
|
||||||
@@ -152,8 +152,8 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
})
|
})
|
||||||
case let .listHeader(text):
|
case let .listHeader(text):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
|
||||||
case let .preset(_, title, label, preset, canBeReordered, canBeDeleted, isEditing, isAllChats):
|
case let .preset(_, title, label, preset, canBeReordered, canBeDeleted, isEditing, isAllChats, isDisabled):
|
||||||
return ChatListFilterPresetListItem(presentationData: presentationData, preset: preset, title: title, label: label, editing: ChatListFilterPresetListItemEditing(editable: true, editing: isEditing, revealed: false), canBeReordered: canBeReordered, canBeDeleted: canBeDeleted, isAllChats: isAllChats, sectionId: self.section, action: {
|
return ChatListFilterPresetListItem(presentationData: presentationData, preset: preset, title: title, label: label, editing: ChatListFilterPresetListItemEditing(editable: true, editing: isEditing, revealed: false), canBeReordered: canBeReordered, canBeDeleted: canBeDeleted, isAllChats: isAllChats, isDisabled: isDisabled, sectionId: self.section, action: {
|
||||||
arguments.openPreset(preset)
|
arguments.openPreset(preset)
|
||||||
}, setItemWithRevealedOptions: { lhs, rhs in
|
}, setItemWithRevealedOptions: { lhs, rhs in
|
||||||
arguments.setItemWithRevealedOptions(lhs, rhs)
|
arguments.setItemWithRevealedOptions(lhs, rhs)
|
||||||
@@ -219,10 +219,10 @@ private func chatListFilterPresetListControllerEntries(presentationData: Present
|
|||||||
|
|
||||||
for (filter, chatCount) in filtersWithAppliedOrder(filters: filters, order: updatedFilterOrder) {
|
for (filter, chatCount) in filtersWithAppliedOrder(filters: filters, order: updatedFilterOrder) {
|
||||||
if isPremium, case .allChats = filter {
|
if isPremium, case .allChats = filter {
|
||||||
entries.append(.preset(index: PresetIndex(value: entries.count), title: "", label: "", preset: filter, canBeReordered: filters.count > 1, canBeDeleted: false, isEditing: state.isEditing, isAllChats: true))
|
entries.append(.preset(index: PresetIndex(value: entries.count), title: "", label: "", preset: filter, canBeReordered: filters.count > 1, canBeDeleted: false, isEditing: state.isEditing, isAllChats: true, isDisabled: false))
|
||||||
}
|
}
|
||||||
if case let .filter(_, title, _, _) = filter {
|
if case let .filter(_, title, _, _) = filter {
|
||||||
entries.append(.preset(index: PresetIndex(value: entries.count), title: title, label: chatCount == 0 ? "" : "\(chatCount)", preset: filter, canBeReordered: filters.count > 1, canBeDeleted: true, isEditing: state.isEditing, isAllChats: false))
|
entries.append(.preset(index: PresetIndex(value: entries.count), title: title, label: chatCount == 0 ? "" : "\(chatCount)", preset: filter, canBeReordered: filters.count > 1, canBeDeleted: true, isEditing: state.isEditing, isAllChats: false, isDisabled: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if actualFilters.count < limits.maxFoldersCount {
|
if actualFilters.count < limits.maxFoldersCount {
|
||||||
@@ -528,7 +528,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||||||
}
|
}
|
||||||
controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [ChatListFilterPresetListEntry]) -> Signal<Bool, NoError> in
|
controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [ChatListFilterPresetListEntry]) -> Signal<Bool, NoError> in
|
||||||
let fromEntry = entries[fromIndex]
|
let fromEntry = entries[fromIndex]
|
||||||
guard case let .preset(_, _, _, fromPreset, _, _, _, _) = fromEntry else {
|
guard case let .preset(_, _, _, fromPreset, _, _, _, _, _) = fromEntry else {
|
||||||
return .single(false)
|
return .single(false)
|
||||||
}
|
}
|
||||||
var referenceFilter: ChatListFilter?
|
var referenceFilter: ChatListFilter?
|
||||||
@@ -536,7 +536,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||||||
var afterAll = false
|
var afterAll = false
|
||||||
if toIndex < entries.count {
|
if toIndex < entries.count {
|
||||||
switch entries[toIndex] {
|
switch entries[toIndex] {
|
||||||
case let .preset(_, _, _, preset, _, _, _, _):
|
case let .preset(_, _, _, preset, _, _, _, _, _):
|
||||||
referenceFilter = preset
|
referenceFilter = preset
|
||||||
default:
|
default:
|
||||||
if entries[toIndex] < fromEntry {
|
if entries[toIndex] < fromEntry {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ final class ChatListFilterPresetListItem: ListViewItem, ItemListItem {
|
|||||||
let canBeReordered: Bool
|
let canBeReordered: Bool
|
||||||
let canBeDeleted: Bool
|
let canBeDeleted: Bool
|
||||||
let isAllChats: Bool
|
let isAllChats: Bool
|
||||||
|
let isDisabled: Bool
|
||||||
let sectionId: ItemListSectionId
|
let sectionId: ItemListSectionId
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
let setItemWithRevealedOptions: (Int32?, Int32?) -> Void
|
let setItemWithRevealedOptions: (Int32?, Int32?) -> Void
|
||||||
@@ -38,6 +39,7 @@ final class ChatListFilterPresetListItem: ListViewItem, ItemListItem {
|
|||||||
canBeReordered: Bool,
|
canBeReordered: Bool,
|
||||||
canBeDeleted: Bool,
|
canBeDeleted: Bool,
|
||||||
isAllChats: Bool,
|
isAllChats: Bool,
|
||||||
|
isDisabled: Bool,
|
||||||
sectionId: ItemListSectionId,
|
sectionId: ItemListSectionId,
|
||||||
action: @escaping () -> Void,
|
action: @escaping () -> Void,
|
||||||
setItemWithRevealedOptions: @escaping (Int32?, Int32?) -> Void,
|
setItemWithRevealedOptions: @escaping (Int32?, Int32?) -> Void,
|
||||||
@@ -51,6 +53,7 @@ final class ChatListFilterPresetListItem: ListViewItem, ItemListItem {
|
|||||||
self.canBeReordered = canBeReordered
|
self.canBeReordered = canBeReordered
|
||||||
self.canBeDeleted = canBeDeleted
|
self.canBeDeleted = canBeDeleted
|
||||||
self.isAllChats = isAllChats
|
self.isAllChats = isAllChats
|
||||||
|
self.isDisabled = isDisabled
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
self.action = action
|
self.action = action
|
||||||
self.setItemWithRevealedOptions = setItemWithRevealedOptions
|
self.setItemWithRevealedOptions = setItemWithRevealedOptions
|
||||||
@@ -380,7 +383,7 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN
|
|||||||
if let arrowImage = strongSelf.arrowNode.image {
|
if let arrowImage = strongSelf.arrowNode.image {
|
||||||
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 7.0 - arrowImage.size.width + revealOffset, y: floorToScreenPixels((layout.contentSize.height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
|
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 7.0 - arrowImage.size.width + revealOffset, y: floorToScreenPixels((layout.contentSize.height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
|
||||||
}
|
}
|
||||||
strongSelf.arrowNode.isHidden = item.isAllChats
|
strongSelf.arrowNode.isHidden = item.isAllChats || item.isDisabled
|
||||||
|
|
||||||
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: 0.0), size: CGSize(width: params.width - params.rightInset - 56.0 - (leftInset + revealOffset + editingOffset), height: layout.contentSize.height))
|
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: 0.0), size: CGSize(width: params.width - params.rightInset - 56.0 - (leftInset + revealOffset + editingOffset), height: layout.contentSize.height))
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ public final class SolidRoundedButtonComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let button = self.button {
|
if let button = self.button {
|
||||||
|
button.title = component.title
|
||||||
button.updateTheme(component.theme)
|
button.updateTheme(component.theme)
|
||||||
let height = button.updateLayout(width: availableSize.width, transition: .immediate)
|
let height = button.updateLayout(width: availableSize.width, transition: .immediate)
|
||||||
transition.setFrame(view: button, frame: CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height)), completion: nil)
|
transition.setFrame(view: button, frame: CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height)), completion: nil)
|
||||||
|
|||||||
@@ -129,15 +129,20 @@ private final class GradientBackgroundComponent: Component {
|
|||||||
|
|
||||||
final class DemoPageEnvironment: Equatable {
|
final class DemoPageEnvironment: Equatable {
|
||||||
public let isDisplaying: Bool
|
public let isDisplaying: Bool
|
||||||
|
public let isCentral: Bool
|
||||||
|
|
||||||
public init(isDisplaying: Bool) {
|
public init(isDisplaying: Bool, isCentral: Bool) {
|
||||||
self.isDisplaying = isDisplaying
|
self.isDisplaying = isDisplaying
|
||||||
|
self.isCentral = isCentral
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: DemoPageEnvironment, rhs: DemoPageEnvironment) -> Bool {
|
public static func ==(lhs: DemoPageEnvironment, rhs: DemoPageEnvironment) -> Bool {
|
||||||
if lhs.isDisplaying != rhs.isDisplaying {
|
if lhs.isDisplaying != rhs.isDisplaying {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.isCentral != rhs.isCentral {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,7 +322,7 @@ private final class DemoPagerComponent: Component {
|
|||||||
if let itemView = self.itemViews[item.content.id] {
|
if let itemView = self.itemViews[item.content.id] {
|
||||||
let isDisplaying = itemView.frame.intersects(self.scrollView.bounds)
|
let isDisplaying = itemView.frame.intersects(self.scrollView.bounds)
|
||||||
|
|
||||||
let environment = DemoPageEnvironment(isDisplaying: isDisplaying)
|
let environment = DemoPageEnvironment(isDisplaying: isDisplaying, isCentral: isDisplaying)
|
||||||
let _ = itemView.update(
|
let _ = itemView.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: item.content.component,
|
component: item.content.component,
|
||||||
@@ -362,7 +367,7 @@ private final class DemoPagerComponent: Component {
|
|||||||
let itemFrame = CGRect(origin: CGPoint(x: availableSize.width * CGFloat(i), y: 0.0), size: availableSize)
|
let itemFrame = CGRect(origin: CGPoint(x: availableSize.width * CGFloat(i), y: 0.0), size: availableSize)
|
||||||
let isDisplaying = itemFrame.intersects(self.scrollView.bounds)
|
let isDisplaying = itemFrame.intersects(self.scrollView.bounds)
|
||||||
|
|
||||||
let environment = DemoPageEnvironment(isDisplaying: isDisplaying)
|
let environment = DemoPageEnvironment(isDisplaying: isDisplaying, isCentral: isDisplaying)
|
||||||
let _ = itemView.update(
|
let _ = itemView.update(
|
||||||
transition: itemTransition,
|
transition: itemTransition,
|
||||||
component: item.content.component,
|
component: item.content.component,
|
||||||
|
|||||||
@@ -718,13 +718,15 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
typealias EnvironmentType = (ViewControllerComponentContainer.Environment, ScrollChildEnvironment)
|
typealias EnvironmentType = (ViewControllerComponentContainer.Environment, ScrollChildEnvironment)
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
|
let isPremium: Bool?
|
||||||
let price: String?
|
let price: String?
|
||||||
let present: (ViewController) -> Void
|
let present: (ViewController) -> Void
|
||||||
let buy: () -> Void
|
let buy: () -> Void
|
||||||
let updateIsFocused: (Bool) -> Void
|
let updateIsFocused: (Bool) -> Void
|
||||||
|
|
||||||
init(context: AccountContext, price: String?, present: @escaping (ViewController) -> Void, buy: @escaping () -> Void, updateIsFocused: @escaping (Bool) -> Void) {
|
init(context: AccountContext, isPremium: Bool?, price: String?, present: @escaping (ViewController) -> Void, buy: @escaping () -> Void, updateIsFocused: @escaping (Bool) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
self.isPremium = isPremium
|
||||||
self.price = price
|
self.price = price
|
||||||
self.present = present
|
self.present = present
|
||||||
self.buy = buy
|
self.buy = buy
|
||||||
@@ -735,6 +737,9 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
if lhs.context !== rhs.context {
|
if lhs.context !== rhs.context {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.isPremium != rhs.isPremium {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.price != rhs.price {
|
if lhs.price != rhs.price {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -841,7 +846,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
let text = text.update(
|
let text = text.update(
|
||||||
component: MultilineTextComponent(
|
component: MultilineTextComponent(
|
||||||
text: .markdown(
|
text: .markdown(
|
||||||
text: strings.Premium_Description,
|
text: context.component.isPremium == true ? strings.Premium_SubscribedDescription : strings.Premium_Description,
|
||||||
attributes: markdownAttributes
|
attributes: markdownAttributes
|
||||||
),
|
),
|
||||||
horizontalAlignment: .center,
|
horizontalAlignment: .center,
|
||||||
@@ -1166,6 +1171,8 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
|
|
||||||
var inProgress = false
|
var inProgress = false
|
||||||
var premiumProduct: InAppPurchaseManager.Product?
|
var premiumProduct: InAppPurchaseManager.Product?
|
||||||
|
var isPremium: Bool?
|
||||||
|
|
||||||
private var disposable: Disposable?
|
private var disposable: Disposable?
|
||||||
private var paymentDisposable = MetaDisposable()
|
private var paymentDisposable = MetaDisposable()
|
||||||
private var activationDisposable = MetaDisposable()
|
private var activationDisposable = MetaDisposable()
|
||||||
@@ -1178,10 +1185,17 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
if let inAppPurchaseManager = context.sharedContext.inAppPurchaseManager {
|
if let inAppPurchaseManager = context.sharedContext.inAppPurchaseManager {
|
||||||
self.disposable = (inAppPurchaseManager.availableProducts
|
self.disposable = combineLatest(
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] products in
|
queue: Queue.mainQueue(),
|
||||||
|
inAppPurchaseManager.availableProducts,
|
||||||
|
context.account.postbox.peerView(id: context.account.peerId)
|
||||||
|
|> map { view -> Bool in
|
||||||
|
return view.peers[view.peerId]?.isPremium ?? false
|
||||||
|
}
|
||||||
|
).start(next: { [weak self] products, isPremium in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.premiumProduct = products.first
|
strongSelf.premiumProduct = products.first
|
||||||
|
strongSelf.isPremium = isPremium
|
||||||
strongSelf.updated(transition: .immediate)
|
strongSelf.updated(transition: .immediate)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1281,7 +1295,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
|
|
||||||
let title = title.update(
|
let title = title.update(
|
||||||
component: Text(
|
component: Text(
|
||||||
text: environment.strings.Premium_Title,
|
text: state.isPremium == true ? environment.strings.Premium_SubscribedTitle : environment.strings.Premium_Title,
|
||||||
font: Font.bold(28.0),
|
font: Font.bold(28.0),
|
||||||
color: environment.theme.rootController.navigationBar.primaryTextColor
|
color: environment.theme.rootController.navigationBar.primaryTextColor
|
||||||
),
|
),
|
||||||
@@ -1336,6 +1350,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
component: ScrollComponent<EnvironmentType>(
|
component: ScrollComponent<EnvironmentType>(
|
||||||
content: AnyComponent(PremiumIntroScreenContentComponent(
|
content: AnyComponent(PremiumIntroScreenContentComponent(
|
||||||
context: context.component.context,
|
context: context.component.context,
|
||||||
|
isPremium: state.isPremium,
|
||||||
price: state.premiumProduct?.price,
|
price: state.premiumProduct?.price,
|
||||||
present: context.component.present,
|
present: context.component.present,
|
||||||
buy: { [weak state] in
|
buy: { [weak state] in
|
||||||
|
|||||||
@@ -43,7 +43,11 @@ final class ReactionsCarouselComponent: Component {
|
|||||||
private var component: ReactionsCarouselComponent?
|
private var component: ReactionsCarouselComponent?
|
||||||
private var node: ReactionCarouselNode?
|
private var node: ReactionCarouselNode?
|
||||||
|
|
||||||
public func update(component: ReactionsCarouselComponent, availableSize: CGSize, transition: Transition) -> CGSize {
|
private var isVisible = false
|
||||||
|
|
||||||
|
public func update(component: ReactionsCarouselComponent, availableSize: CGSize, environment: Environment<DemoPageEnvironment>, transition: Transition) -> CGSize {
|
||||||
|
let isDisplaying = environment[DemoPageEnvironment.self].isDisplaying
|
||||||
|
|
||||||
if self.node == nil {
|
if self.node == nil {
|
||||||
let node = ReactionCarouselNode(
|
let node = ReactionCarouselNode(
|
||||||
context: component.context,
|
context: component.context,
|
||||||
@@ -54,7 +58,6 @@ final class ReactionsCarouselComponent: Component {
|
|||||||
self.addSubnode(node)
|
self.addSubnode(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
let isFirstTime = self.component == nil
|
|
||||||
self.component = component
|
self.component = component
|
||||||
|
|
||||||
if let node = self.node {
|
if let node = self.node {
|
||||||
@@ -62,9 +65,10 @@ final class ReactionsCarouselComponent: Component {
|
|||||||
node.updateLayout(size: availableSize, transition: .immediate)
|
node.updateLayout(size: availableSize, transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isFirstTime {
|
if isDisplaying && !self.isVisible {
|
||||||
self.node?.animateIn()
|
self.node?.animateIn()
|
||||||
}
|
}
|
||||||
|
self.isVisible = isDisplaying
|
||||||
|
|
||||||
return availableSize
|
return availableSize
|
||||||
}
|
}
|
||||||
@@ -75,7 +79,7 @@ final class ReactionsCarouselComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<DemoPageEnvironment>, transition: Transition) -> CGSize {
|
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<DemoPageEnvironment>, transition: Transition) -> CGSize {
|
||||||
return view.update(component: self, availableSize: availableSize, transition: transition)
|
return view.update(component: self, availableSize: availableSize, environment: environment, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public func generateWebAppThemeParams(_ presentationTheme: PresentationTheme) ->
|
|||||||
var secondaryBackgroundColor = presentationTheme.list.blocksBackgroundColor.rgb
|
var secondaryBackgroundColor = presentationTheme.list.blocksBackgroundColor.rgb
|
||||||
if backgroundColor == 0x000000 {
|
if backgroundColor == 0x000000 {
|
||||||
backgroundColor = presentationTheme.list.itemBlocksBackgroundColor.rgb
|
backgroundColor = presentationTheme.list.itemBlocksBackgroundColor.rgb
|
||||||
secondaryBackgroundColor = presentationTheme.list.plainBackgroundColor.rgb
|
secondaryBackgroundColor = presentationTheme.list.itemBlocksBackgroundColor.rgb
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
"bg_color": Int32(bitPattern: backgroundColor),
|
"bg_color": Int32(bitPattern: backgroundColor),
|
||||||
@@ -186,6 +186,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
fileprivate class Node: ViewControllerTracingNode, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate {
|
fileprivate class Node: ViewControllerTracingNode, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate {
|
||||||
private weak var controller: WebAppController?
|
private weak var controller: WebAppController?
|
||||||
|
|
||||||
|
private let backgroundNode: ASDisplayNode
|
||||||
|
private let headerBackgroundNode: ASDisplayNode
|
||||||
|
|
||||||
fileprivate var webView: WebAppWebView?
|
fileprivate var webView: WebAppWebView?
|
||||||
private var placeholderIcon: (UIImage, Bool)?
|
private var placeholderIcon: (UIImage, Bool)?
|
||||||
private var placeholderNode: ShimmerEffectNode?
|
private var placeholderNode: ShimmerEffectNode?
|
||||||
@@ -213,6 +216,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.presentationData = controller.presentationData
|
self.presentationData = controller.presentationData
|
||||||
|
|
||||||
|
self.backgroundNode = ASDisplayNode()
|
||||||
|
self.headerBackgroundNode = ASDisplayNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
if self.presentationData.theme.list.plainBackgroundColor.rgb == 0x000000 {
|
if self.presentationData.theme.list.plainBackgroundColor.rgb == 0x000000 {
|
||||||
@@ -244,6 +250,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
self.addSubnode(placeholderNode)
|
self.addSubnode(placeholderNode)
|
||||||
self.placeholderNode = placeholderNode
|
self.placeholderNode = placeholderNode
|
||||||
|
|
||||||
|
self.addSubnode(self.backgroundNode)
|
||||||
|
self.addSubnode(self.headerBackgroundNode)
|
||||||
|
|
||||||
let placeholder: Signal<(FileMediaReference, Bool)?, NoError>
|
let placeholder: Signal<(FileMediaReference, Bool)?, NoError>
|
||||||
if durgerKingBotIds.contains(controller.botId.id._internalGetInt64Value()) {
|
if durgerKingBotIds.contains(controller.botId.id._internalGetInt64Value()) {
|
||||||
placeholder = .single(nil)
|
placeholder = .single(nil)
|
||||||
@@ -471,6 +480,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
let previousLayout = self.validLayout?.0
|
let previousLayout = self.validLayout?.0
|
||||||
self.validLayout = (layout, navigationBarHeight)
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: .zero, size: layout.size))
|
||||||
|
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: navigationBarHeight)))
|
||||||
|
|
||||||
if let webView = self.webView {
|
if let webView = self.webView {
|
||||||
let frame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom)))
|
let frame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom)))
|
||||||
let viewportFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom - layout.additionalInsets.bottom)))
|
let viewportFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom - layout.additionalInsets.bottom)))
|
||||||
@@ -669,11 +681,45 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "web_app_set_background_color":
|
||||||
|
if let json = json, let colorValue = json["color"] as? String, let color = UIColor(hexString: colorValue) {
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear)
|
||||||
|
transition.updateBackgroundColor(node: self.backgroundNode, color: color)
|
||||||
|
}
|
||||||
|
case "web_app_set_header_color":
|
||||||
|
if let json = json, let colorKey = json["color_key"] as? String, ["bg_color", "secondary_bg_color"].contains(colorKey) {
|
||||||
|
self.headerColorKey = colorKey
|
||||||
|
self.updateHeaderBackgroundColor(transition: .animated(duration: 0.2, curve: .linear))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var headerColorKey: String?
|
||||||
|
private func updateHeaderBackgroundColor(transition: ContainedViewLayoutTransition) {
|
||||||
|
let color: UIColor?
|
||||||
|
var backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
|
var secondaryBackgroundColor = self.presentationData.theme.list.blocksBackgroundColor
|
||||||
|
if backgroundColor.rgb == 0x000000 {
|
||||||
|
backgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
|
secondaryBackgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
|
}
|
||||||
|
if let headerColorKey = self.headerColorKey {
|
||||||
|
switch headerColorKey {
|
||||||
|
case "bg_color":
|
||||||
|
color = backgroundColor
|
||||||
|
case "secondary_bg_color":
|
||||||
|
color = secondaryBackgroundColor
|
||||||
|
default:
|
||||||
|
color = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
color = nil
|
||||||
|
}
|
||||||
|
transition.updateBackgroundColor(node: self.headerBackgroundNode, color: color ?? .clear)
|
||||||
|
}
|
||||||
|
|
||||||
private func handleSendData(data string: String) {
|
private func handleSendData(data string: String) {
|
||||||
guard let controller = self.controller, let buttonText = controller.buttonText, !self.dismissed else {
|
guard let controller = self.controller, let buttonText = controller.buttonText, !self.dismissed else {
|
||||||
return
|
return
|
||||||
@@ -702,6 +748,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
} else {
|
} else {
|
||||||
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
}
|
}
|
||||||
|
self.updateHeaderBackgroundColor(transition: .immediate)
|
||||||
self.sendThemeChangedEvent()
|
self.sendThemeChangedEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user