mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Various improvements
This commit is contained in:
parent
bbef11084a
commit
4a5e7ebed4
@ -14932,3 +14932,44 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Notification.ChangedThemeGift" = "%1$@ changed chat theme to %2$@";
|
||||
"Notification.YouChangedThemeGift" = "You changed chat theme to %@";
|
||||
|
||||
"Conversation.Theme.GiftTransfer.Text" = "This gift is already your theme in the chat with **%@**. Remove it there and use it here instead?";
|
||||
"Conversation.Theme.GiftTransfer.Proceed" = "Yes";
|
||||
|
||||
"PeerInfo.Tabs.SetMainTab" = "Set as Main Tab";
|
||||
"PeerInfo.Tabs.SetMainTab.Succeed" = "Tab order changed.";
|
||||
|
||||
"MediaPlayer.SavedMusic.AddToProfile" = "Add to Profile";
|
||||
"MediaPlayer.SavedMusic.RemoveFromProfile" = "This audio is visible on your profile. [Remove >]()";
|
||||
|
||||
"MediaPlayer.SavedMusic.AddedToProfile.View" = "View";
|
||||
"MediaPlayer.SavedMusic.AddedToProfile" = "Audio added to your profile.";
|
||||
"MediaPlayer.SavedMusic.RemovedFromProfile" = "Audio removed from your profile.";
|
||||
|
||||
"MediaPlayer.ContextMenu.SaveToFiles" = "Save to Files";
|
||||
"MediaPlayer.ContextMenu.SaveTo" = "Save to...";
|
||||
"MediaPlayer.ContextMenu.SaveTo.Profile" = "Profile";
|
||||
"MediaPlayer.ContextMenu.SaveTo.SavedMessages" = "Saved Messages";
|
||||
"MediaPlayer.ContextMenu.SaveTo.Files" = "Files";
|
||||
"MediaPlayer.ContextMenu.SaveTo.Info" = "Save to Files";
|
||||
"MediaPlayer.ContextMenu.ShowInChat" = "Show in Chat";
|
||||
"MediaPlayer.ContextMenu.Forward" = "Forward";
|
||||
"MediaPlayer.ContextMenu.Delete" = "Delete";
|
||||
"MediaPlayer.ContextMenu.Remove" = "Remove";
|
||||
|
||||
"MediaPlayer.Playlist.ThisChat" = "AUDIO IN THIS CHAT";
|
||||
"MediaPlayer.Playlist.SavedMusic" = "%@'S PLAYLIST";
|
||||
"MediaPlayer.Playlist.SavedMusicYou" = "YOUR PLAYLIST";
|
||||
|
||||
"Notification.PremiumGift.Stars_1" = "%@ Star";
|
||||
"Notification.PremiumGift.Stars_any" = "%@ Stars";
|
||||
|
||||
"Ton.ProceedsOverview" = "PROCEEDS OVERVIEW";
|
||||
"Ton.AvailableBalance" = "Balance Available to Withdraw";
|
||||
"Ton.LifetimeProceeds" = "Total Lifetime Proceeds";
|
||||
|
||||
"Ton.WithdrawViaFragment" = "Withdraw via Fragment";
|
||||
"Ton.WithdrawViaFragment.Info" = "Collect your TON using Fragment. [Learn More >]()";
|
||||
"Ton.WithdrawViaFragment.Info_URL" = "https://telegram.org/tos/bot-developers#6-2-2-tpa-balance";
|
||||
|
||||
"MESSAGE_GIFT_THEME" = "%1$@ changed theme to %2$@";
|
||||
|
@ -809,6 +809,27 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
themePeerId: self.themePeerId
|
||||
)
|
||||
}
|
||||
|
||||
public func withThemePeerId(_ themePeerId: EnginePeer.Id?) -> UniqueGift {
|
||||
return UniqueGift(
|
||||
id: self.id,
|
||||
giftId: self.giftId,
|
||||
title: self.title,
|
||||
number: self.number,
|
||||
slug: self.slug,
|
||||
owner: self.owner,
|
||||
attributes: self.attributes,
|
||||
availability: self.availability,
|
||||
giftAddress: self.giftAddress,
|
||||
resellAmounts: self.resellAmounts,
|
||||
resellForTonOnly: self.resellForTonOnly,
|
||||
releasedBy: self.releasedBy,
|
||||
valueAmount: self.valueAmount,
|
||||
valueCurrency: self.valueCurrency,
|
||||
flags: self.flags,
|
||||
themePeerId: themePeerId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public enum DecodingError: Error {
|
||||
|
@ -148,6 +148,20 @@ public enum ChatTheme: PostboxCoding, Codable, Equatable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func withThemePeerId(_ themePeerId: EnginePeer.Id?) -> ChatTheme {
|
||||
switch self {
|
||||
case .emoticon:
|
||||
return self
|
||||
case let .gift(gift, themeSettings):
|
||||
switch gift {
|
||||
case let .unique(uniqueGift):
|
||||
return .gift(.unique(uniqueGift.withThemePeerId(themePeerId)), themeSettings)
|
||||
case .generic:
|
||||
return self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ChatTheme {
|
||||
@ -235,6 +249,22 @@ func _internal_setChatTheme(account: Account, peerId: PeerId, chatTheme: ChatThe
|
||||
return .complete()
|
||||
}
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
var chatTheme = chatTheme
|
||||
if case let .gift(gift, _) = chatTheme, case let .unique(uniqueGift) = gift, let previousThemePeerId = uniqueGift.themePeerId {
|
||||
transaction.updatePeerCachedData(peerIds: Set([previousThemePeerId]), update: { _, current in
|
||||
if let current = current as? CachedUserData {
|
||||
return current.withUpdatedChatTheme(nil)
|
||||
} else if let current = current as? CachedGroupData {
|
||||
return current.withUpdatedChatTheme(nil)
|
||||
} else if let current = current as? CachedChannelData {
|
||||
return current.withUpdatedChatTheme(nil)
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
})
|
||||
}
|
||||
chatTheme = chatTheme?.withThemePeerId(peerId)
|
||||
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||
if let current = current as? CachedUserData {
|
||||
return current.withUpdatedChatTheme(chatTheme)
|
||||
@ -246,6 +276,7 @@ func _internal_setChatTheme(account: Account, peerId: PeerId, chatTheme: ChatThe
|
||||
return current
|
||||
}
|
||||
})
|
||||
|
||||
let inputTheme: Api.InputChatTheme
|
||||
if let chatTheme {
|
||||
inputTheme = chatTheme.apiChatTheme
|
||||
@ -466,7 +497,7 @@ public final class UniqueGiftChatThemesContext {
|
||||
private let cacheDisposable = MetaDisposable()
|
||||
|
||||
private var themes: [ChatTheme] = []
|
||||
private var nextOffset: Int32?
|
||||
private var nextOffset: Int32 = 0
|
||||
private var dataState: UniqueGiftChatThemesContext.State.DataState = .ready(canLoadMore: true)
|
||||
|
||||
private let stateValue = Promise<State>()
|
||||
@ -487,7 +518,7 @@ public final class UniqueGiftChatThemesContext {
|
||||
|
||||
public func reload() {
|
||||
self.themes = []
|
||||
self.nextOffset = nil
|
||||
self.nextOffset = 0
|
||||
self.dataState = .ready(canLoadMore: true)
|
||||
self.loadMore(reload: true)
|
||||
}
|
||||
@ -521,7 +552,7 @@ public final class UniqueGiftChatThemesContext {
|
||||
self.pushState()
|
||||
}
|
||||
|
||||
let signal = network.request(Api.functions.account.getUniqueGiftChatThemes(offset: offset ?? 0, limit: 32, hash: 0))
|
||||
let signal = network.request(Api.functions.account.getUniqueGiftChatThemes(offset: offset, limit: 32, hash: 0))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { error in
|
||||
return .single(nil)
|
||||
@ -557,7 +588,9 @@ public final class UniqueGiftChatThemesContext {
|
||||
} else {
|
||||
self.themes.append(contentsOf: themes)
|
||||
}
|
||||
|
||||
if let nextOffset {
|
||||
self.nextOffset = nextOffset
|
||||
}
|
||||
self.dataState = .ready(canLoadMore: nextOffset != nil)
|
||||
self.pushState()
|
||||
}))
|
||||
|
@ -830,8 +830,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
} else {
|
||||
let price: String
|
||||
if currency == "XTR" {
|
||||
//TODO:localize
|
||||
price = "\(amount) Stars"
|
||||
price = strings.Notification_PremiumGift_Stars(Int32(clamping: amount))
|
||||
} else {
|
||||
price = formatCurrencyAmount(amount, currency: currency)
|
||||
}
|
||||
|
@ -485,6 +485,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Stars/BalanceNeededScreen",
|
||||
"//submodules/TelegramUI/Components/FaceScanScreen",
|
||||
"//submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist",
|
||||
"//submodules/TelegramUI/Components/ChatThemeScreen",
|
||||
"//submodules/ContactsHelper",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
|
44
submodules/TelegramUI/Components/ChatThemeScreen/BUILD
Normal file
44
submodules/TelegramUI/Components/ChatThemeScreen/BUILD
Normal file
@ -0,0 +1,44 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatThemeScreen",
|
||||
module_name = "ChatThemeScreen",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/TelegramUIPreferences",
|
||||
"//submodules/PresentationDataUtils",
|
||||
"//submodules/TelegramNotices",
|
||||
"//submodules/AnimationUI",
|
||||
"//submodules/MergeLists",
|
||||
"//submodules/MediaResources",
|
||||
"//submodules/StickerResources",
|
||||
"//submodules/WallpaperResources",
|
||||
"//submodules/TooltipUI",
|
||||
"//submodules/SolidRoundedButtonNode",
|
||||
"//submodules/AnimatedStickerNode",
|
||||
"//submodules/TelegramAnimatedStickerNode",
|
||||
"//submodules/ShimmerEffect",
|
||||
"//submodules/AttachmentUI",
|
||||
"//submodules/AvatarNode",
|
||||
"//submodules/Markdown",
|
||||
"//submodules/AppBundle",
|
||||
"//submodules/ActivityIndicator",
|
||||
"//submodules/TelegramUI/Components/Gifts/GiftItemComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
@ -21,12 +21,14 @@ import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ShimmerEffect
|
||||
import AttachmentUI
|
||||
import AvatarNode
|
||||
|
||||
private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
|
||||
let index: Int
|
||||
let chatTheme: ChatTheme?
|
||||
let emojiFile: TelegramMediaFile?
|
||||
let themeReference: PresentationThemeReference?
|
||||
let peer: EnginePeer?
|
||||
let nightMode: Bool
|
||||
var selected: Bool
|
||||
let theme: PresentationTheme
|
||||
@ -47,6 +49,9 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
|
||||
if lhs.themeReference?.index != rhs.themeReference?.index {
|
||||
return false
|
||||
}
|
||||
if lhs.peer != rhs.peer {
|
||||
return false
|
||||
}
|
||||
if lhs.nightMode != rhs.nightMode {
|
||||
return false
|
||||
}
|
||||
@ -70,16 +75,16 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
|
||||
}
|
||||
|
||||
func item(context: AccountContext, action: @escaping (ChatTheme?) -> Void) -> ListViewItem {
|
||||
return ThemeSettingsThemeIconItem(context: context, chatTheme: self.chatTheme, emojiFile: self.emojiFile, themeReference: self.themeReference, nightMode: self.nightMode, selected: self.selected, theme: self.theme, strings: self.strings, wallpaper: self.wallpaper, action: action)
|
||||
return ThemeSettingsThemeIconItem(context: context, chatTheme: self.chatTheme, emojiFile: self.emojiFile, themeReference: self.themeReference, peer: self.peer, nightMode: self.nightMode, selected: self.selected, theme: self.theme, strings: self.strings, wallpaper: self.wallpaper, action: action)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ThemeSettingsThemeIconItem: ListViewItem {
|
||||
let context: AccountContext
|
||||
let chatTheme: ChatTheme?
|
||||
let emojiFile: TelegramMediaFile?
|
||||
let themeReference: PresentationThemeReference?
|
||||
let peer: EnginePeer?
|
||||
let nightMode: Bool
|
||||
let selected: Bool
|
||||
let theme: PresentationTheme
|
||||
@ -87,11 +92,24 @@ private class ThemeSettingsThemeIconItem: ListViewItem {
|
||||
let wallpaper: TelegramWallpaper?
|
||||
let action: (ChatTheme?) -> Void
|
||||
|
||||
public init(context: AccountContext, chatTheme: ChatTheme?, emojiFile: TelegramMediaFile?, themeReference: PresentationThemeReference?, nightMode: Bool, selected: Bool, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper?, action: @escaping (ChatTheme?) -> Void) {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
chatTheme: ChatTheme?,
|
||||
emojiFile: TelegramMediaFile?,
|
||||
themeReference: PresentationThemeReference?,
|
||||
peer: EnginePeer?,
|
||||
nightMode: Bool,
|
||||
selected: Bool,
|
||||
theme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
wallpaper: TelegramWallpaper?,
|
||||
action: @escaping (ChatTheme?) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.chatTheme = chatTheme
|
||||
self.emojiFile = emojiFile
|
||||
self.themeReference = themeReference
|
||||
self.peer = peer
|
||||
self.nightMode = nightMode
|
||||
self.selected = selected
|
||||
self.theme = theme
|
||||
@ -525,9 +543,9 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
final class ChatThemeScreen: ViewController {
|
||||
static let themeCrossfadeDuration: Double = 0.3
|
||||
static let themeCrossfadeDelay: Double = 0.25
|
||||
public final class ChatThemeScreen: ViewController {
|
||||
public static let themeCrossfadeDuration: Double = 0.3
|
||||
public static let themeCrossfadeDelay: Double = 0.25
|
||||
|
||||
private var controllerNode: ChatThemeScreenNode {
|
||||
return self.displayNode as! ChatThemeScreenNode
|
||||
@ -539,7 +557,7 @@ final class ChatThemeScreen: ViewController {
|
||||
private let animatedEmojiStickers: [String: [StickerPackItem]]
|
||||
private let initiallySelectedTheme: ChatTheme?
|
||||
private let peerName: String
|
||||
let canResetWallpaper: Bool
|
||||
fileprivate let canResetWallpaper: Bool
|
||||
private let previewTheme: (ChatTheme?, Bool?) -> Void
|
||||
fileprivate let changeWallpaper: () -> Void
|
||||
fileprivate let resetWallpaper: () -> Void
|
||||
@ -548,9 +566,9 @@ final class ChatThemeScreen: ViewController {
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
var dismissed: (() -> Void)?
|
||||
public var dismissed: (() -> Void)?
|
||||
|
||||
var passthroughHitTestImpl: ((CGPoint) -> UIView?)? {
|
||||
public var passthroughHitTestImpl: ((CGPoint) -> UIView?)? {
|
||||
didSet {
|
||||
if self.isNodeLoaded {
|
||||
self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl
|
||||
@ -558,7 +576,7 @@ final class ChatThemeScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
init(
|
||||
public init(
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>),
|
||||
animatedEmojiStickers: [String: [StickerPackItem]],
|
||||
@ -657,7 +675,7 @@ final class ChatThemeScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
override public func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss()
|
||||
@ -683,7 +701,7 @@ final class ChatThemeScreen: ViewController {
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
}
|
||||
|
||||
func dimTapped() {
|
||||
public func dimTapped() {
|
||||
self.controllerNode.dimTapped()
|
||||
}
|
||||
}
|
||||
@ -908,28 +926,13 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
chatTheme: nil,
|
||||
emojiFile: nil,
|
||||
themeReference: nil,
|
||||
peer: nil,
|
||||
nightMode: false,
|
||||
selected: selectedTheme == nil,
|
||||
theme: presentationData.theme,
|
||||
strings: presentationData.strings,
|
||||
wallpaper: nil
|
||||
))
|
||||
for theme in themes {
|
||||
guard let emoticon = theme.emoticon else {
|
||||
continue
|
||||
}
|
||||
entries.append(ThemeSettingsThemeEntry(
|
||||
index: entries.count,
|
||||
chatTheme: .emoticon(emoticon),
|
||||
emojiFile: animatedEmojiStickers[emoticon]?.first?.file._parse(),
|
||||
themeReference: .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil, creatorAccountId: nil)),
|
||||
nightMode: isDarkAppearance,
|
||||
selected: selectedTheme?.id == ChatTheme.emoticon(emoticon).id,
|
||||
theme: presentationData.theme,
|
||||
strings: presentationData.strings,
|
||||
wallpaper: nil
|
||||
))
|
||||
}
|
||||
for theme in uniqueGiftChatThemesState.themes {
|
||||
guard case let .gift(gift, themeSettings) = theme else {
|
||||
continue
|
||||
@ -954,6 +957,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
chatTheme: theme,
|
||||
emojiFile: emojiFile,
|
||||
themeReference: .builtin(.dayClassic),
|
||||
peer: nil,
|
||||
nightMode: isDarkAppearance,
|
||||
selected: selectedTheme?.id == theme.id,
|
||||
theme: presentationData.theme,
|
||||
@ -961,6 +965,24 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
wallpaper: wallpaper
|
||||
))
|
||||
}
|
||||
for theme in themes {
|
||||
guard let emoticon = theme.emoticon else {
|
||||
continue
|
||||
}
|
||||
entries.append(ThemeSettingsThemeEntry(
|
||||
index: entries.count,
|
||||
chatTheme: .emoticon(emoticon),
|
||||
emojiFile: animatedEmojiStickers[emoticon]?.first?.file._parse(),
|
||||
themeReference: .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil, creatorAccountId: nil)),
|
||||
peer: nil,
|
||||
nightMode: isDarkAppearance,
|
||||
selected: selectedTheme?.id == ChatTheme.emoticon(emoticon).id,
|
||||
theme: presentationData.theme,
|
||||
strings: presentationData.strings,
|
||||
wallpaper: nil
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
let action: (ChatTheme?) -> Void = { [weak self] chatTheme in
|
||||
if let self, self.selectedTheme != chatTheme {
|
@ -0,0 +1,296 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import AppBundle
|
||||
import AvatarNode
|
||||
import Markdown
|
||||
import GiftItemComponent
|
||||
import ActivityIndicator
|
||||
|
||||
private final class GiftThemeTransferAlertContentNode: AlertContentNode {
|
||||
private let context: AccountContext
|
||||
private let strings: PresentationStrings
|
||||
private var presentationTheme: PresentationTheme
|
||||
private let title: String
|
||||
private let text: String
|
||||
private let gift: StarGift.UniqueGift
|
||||
|
||||
private let titleNode: ASTextNode
|
||||
private let giftView = ComponentView<Empty>()
|
||||
private let textNode: ASTextNode
|
||||
private let arrowNode: ASImageNode
|
||||
private let avatarNode: AvatarNode
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
|
||||
private var activityIndicator: ActivityIndicator?
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
var inProgress = false {
|
||||
didSet {
|
||||
if let size = self.validLayout {
|
||||
let _ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var dismissOnOutsideTap: Bool {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
theme: AlertControllerTheme,
|
||||
ptheme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
gift: StarGift.UniqueGift,
|
||||
peer: EnginePeer,
|
||||
title: String,
|
||||
text: String,
|
||||
actions: [TextAlertAction]
|
||||
) {
|
||||
self.context = context
|
||||
self.strings = strings
|
||||
self.presentationTheme = ptheme
|
||||
self.title = title
|
||||
self.text = text
|
||||
self.gift = gift
|
||||
|
||||
self.titleNode = ASTextNode()
|
||||
self.titleNode.maximumNumberOfLines = 0
|
||||
|
||||
self.textNode = ASTextNode()
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
|
||||
self.arrowNode = ASImageNode()
|
||||
self.arrowNode.displaysAsynchronously = false
|
||||
self.arrowNode.displayWithoutProcessing = true
|
||||
|
||||
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0))
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
|
||||
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
|
||||
return TextAlertContentActionNode(theme: theme, action: action)
|
||||
}
|
||||
|
||||
var actionVerticalSeparators: [ASDisplayNode] = []
|
||||
if actions.count > 1 {
|
||||
for _ in 0 ..< actions.count - 1 {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.isLayerBacked = true
|
||||
actionVerticalSeparators.append(separatorNode)
|
||||
}
|
||||
}
|
||||
self.actionVerticalSeparators = actionVerticalSeparators
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.arrowNode)
|
||||
self.addSubnode(self.avatarNode)
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
for actionNode in self.actionNodes {
|
||||
self.addSubnode(actionNode)
|
||||
}
|
||||
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
|
||||
self.updateTheme(theme)
|
||||
|
||||
self.avatarNode.setPeer(context: context, theme: ptheme, peer: peer)
|
||||
}
|
||||
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.semibold(17.0), textColor: theme.primaryColor)
|
||||
self.textNode.attributedText = parseMarkdownIntoAttributedString(self.text, attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor),
|
||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor),
|
||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor),
|
||||
linkAttribute: { url in
|
||||
return ("URL", url)
|
||||
}
|
||||
), textAlignment: .center)
|
||||
self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Peer Info/AlertArrow"), color: theme.secondaryColor)
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
actionNode.updateTheme(theme)
|
||||
}
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
separatorNode.backgroundColor = theme.separatorColor
|
||||
}
|
||||
|
||||
if let size = self.validLayout {
|
||||
_ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
var size = size
|
||||
size.width = min(size.width, 270.0)
|
||||
|
||||
self.validLayout = size
|
||||
|
||||
var origin: CGPoint = CGPoint(x: 0.0, y: 20.0)
|
||||
|
||||
let avatarSize = CGSize(width: 60.0, height: 60.0)
|
||||
self.avatarNode.updateSize(size: avatarSize)
|
||||
|
||||
let giftFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarSize.width) / 2.0) - 44.0, y: origin.y), size: avatarSize)
|
||||
|
||||
let _ = self.giftView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(
|
||||
GiftItemComponent(
|
||||
context: self.context,
|
||||
theme: self.presentationTheme,
|
||||
strings: self.strings,
|
||||
peer: nil,
|
||||
subject: .uniqueGift(gift: self.gift, price: nil),
|
||||
mode: .thumbnail
|
||||
)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: avatarSize
|
||||
)
|
||||
if let view = self.giftView.view {
|
||||
if view.superview == nil {
|
||||
self.view.addSubview(view)
|
||||
}
|
||||
view.frame = giftFrame
|
||||
}
|
||||
|
||||
if let arrowImage = self.arrowNode.image {
|
||||
let arrowFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - arrowImage.size.width) / 2.0), y: origin.y + floorToScreenPixels((avatarSize.height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
|
||||
transition.updateFrame(node: self.arrowNode, frame: arrowFrame)
|
||||
}
|
||||
|
||||
let avatarFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarSize.width) / 2.0) + 44.0, y: origin.y), size: avatarSize)
|
||||
transition.updateFrame(node: self.avatarNode, frame: avatarFrame)
|
||||
|
||||
origin.y += avatarSize.height + 17.0
|
||||
|
||||
let titleSize = self.titleNode.measure(CGSize(width: size.width - 32.0, height: size.height))
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: origin.y), size: titleSize))
|
||||
origin.y += titleSize.height + 5.0
|
||||
|
||||
let textSize = self.textNode.measure(CGSize(width: size.width - 32.0, height: size.height))
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
|
||||
origin.y += textSize.height + 10.0
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
var minActionsWidth: CGFloat = 0.0
|
||||
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
|
||||
let actionTitleInsets: CGFloat = 8.0
|
||||
|
||||
for actionNode in self.actionNodes {
|
||||
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
|
||||
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
|
||||
}
|
||||
|
||||
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 18.0, right: 18.0)
|
||||
|
||||
let contentWidth = max(size.width, minActionsWidth)
|
||||
|
||||
let actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||
|
||||
let resultSize = CGSize(width: contentWidth, height: avatarSize.height + titleSize.height + textSize.height + actionsHeight + 24.0 + insets.top + insets.bottom)
|
||||
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
|
||||
var actionOffset: CGFloat = 0.0
|
||||
var separatorIndex = -1
|
||||
var nodeIndex = 0
|
||||
for actionNode in self.actionNodes {
|
||||
if separatorIndex >= 0 {
|
||||
let separatorNode = self.actionVerticalSeparators[separatorIndex]
|
||||
do {
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
}
|
||||
}
|
||||
separatorIndex += 1
|
||||
|
||||
let currentActionWidth: CGFloat
|
||||
do {
|
||||
currentActionWidth = resultSize.width
|
||||
}
|
||||
|
||||
let actionNodeFrame: CGRect
|
||||
do {
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += actionButtonHeight
|
||||
}
|
||||
|
||||
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
|
||||
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
if self.inProgress {
|
||||
let activityIndicator: ActivityIndicator
|
||||
if let current = self.activityIndicator {
|
||||
activityIndicator = current
|
||||
} else {
|
||||
activityIndicator = ActivityIndicator(type: .custom(self.presentationTheme.list.freeInputField.controlColor, 18.0, 1.5, false))
|
||||
self.addSubnode(activityIndicator)
|
||||
}
|
||||
|
||||
if let actionNode = self.actionNodes.first {
|
||||
actionNode.isHidden = true
|
||||
|
||||
let indicatorSize = CGSize(width: 22.0, height: 22.0)
|
||||
transition.updateFrame(node: activityIndicator, frame: CGRect(origin: CGPoint(x: actionNode.frame.minX + floor((actionNode.frame.width - indicatorSize.width) / 2.0), y: actionNode.frame.minY + floor((actionNode.frame.height - indicatorSize.height) / 2.0)), size: indicatorSize))
|
||||
}
|
||||
}
|
||||
|
||||
return resultSize
|
||||
}
|
||||
}
|
||||
|
||||
public func giftThemeTransferAlertController(
|
||||
context: AccountContext,
|
||||
gift: StarGift.UniqueGift,
|
||||
previousPeer: EnginePeer,
|
||||
commit: @escaping () -> Void
|
||||
) -> AlertController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let strings = presentationData.strings
|
||||
|
||||
var contentNode: GiftThemeTransferAlertContentNode?
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Conversation_Theme_GiftTransfer_Proceed, action: { [weak contentNode] in
|
||||
contentNode?.inProgress = true
|
||||
commit()
|
||||
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
})]
|
||||
|
||||
let text = strings.Conversation_Theme_GiftTransfer_Text(previousPeer.compactDisplayTitle).string
|
||||
contentNode = GiftThemeTransferAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: strings, gift: gift, peer: previousPeer, title: "", text: text, actions: actions)
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode!)
|
||||
dismissImpl = { [weak controller] animated in
|
||||
if animated {
|
||||
controller?.dismissAnimated()
|
||||
} else {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
return controller
|
||||
}
|
@ -1163,9 +1163,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
|
||||
return
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: "Set as Main Tab", icon: { theme in
|
||||
items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Tabs_SetMainTab, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
guard let self else {
|
||||
@ -1183,7 +1182,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let controller = UndoOverlayController(presentationData: params.presentationData, content: .actionSucceeded(title: nil, text: "Tab order changed.", cancel: nil, destructive: false), action: { _ in return true })
|
||||
let controller = UndoOverlayController(presentationData: params.presentationData, content: .actionSucceeded(title: nil, text: params.presentationData.strings.PeerInfo_Tabs_SetMainTab_Succeed, cancel: nil, destructive: false), action: { _ in return true })
|
||||
self.parentController?.present(controller, in: .current)
|
||||
})
|
||||
}
|
||||
|
@ -680,7 +680,7 @@ final class StarsTransactionsScreenComponent: Component {
|
||||
theme: environment.theme,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "Proceeds Overview".uppercased(),
|
||||
string: environment.strings.Ton_ProceedsOverview.uppercased(),
|
||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
@ -691,14 +691,14 @@ final class StarsTransactionsScreenComponent: Component {
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(StarsOverviewItemComponent(
|
||||
theme: environment.theme,
|
||||
dateTimeFormat: environment.dateTimeFormat,
|
||||
title: "Balance Available to Withdraw",
|
||||
title: environment.strings.Ton_AvailableBalance,
|
||||
value: self.revenueState?.balances.availableBalance ?? CurrencyAmount(amount: .zero, currency: .ton),
|
||||
rate: self.revenueState?.usdRate ?? 0.0
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(StarsOverviewItemComponent(
|
||||
theme: environment.theme,
|
||||
dateTimeFormat: environment.dateTimeFormat,
|
||||
title: "Total Lifetime Proceeds",
|
||||
title: environment.strings.Ton_LifetimeProceeds,
|
||||
value: self.revenueState?.balances.overallRevenue ?? CurrencyAmount(amount: .zero, currency: .ton),
|
||||
rate: self.revenueState?.usdRate ?? 0.0
|
||||
)))
|
||||
@ -725,7 +725,7 @@ final class StarsTransactionsScreenComponent: Component {
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
})
|
||||
|
||||
let balanceInfoRawString = "Collect your TON using Fragment. [Learn More >]()"
|
||||
let balanceInfoRawString = environment.strings.Ton_WithdrawViaFragment_Info
|
||||
let balanceInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(balanceInfoRawString, attributes: termsMarkdownAttributes, textAlignment: .natural))
|
||||
if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme {
|
||||
self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Contact List/SubtitleArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
|
||||
@ -754,7 +754,7 @@ final class StarsTransactionsScreenComponent: Component {
|
||||
},
|
||||
tapAction: { [weak self] attributes, _ in
|
||||
if let controller = self?.controller?() as? StarsTransactionsScreen, let navigationController = controller.navigationController as? NavigationController {
|
||||
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: environment.strings.Stars_BotRevenue_Withdraw_Info_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
|
||||
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: component.starsContext.ton ? environment.strings.Ton_WithdrawViaFragment_Info_URL : environment.strings.Stars_BotRevenue_Withdraw_Info_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
|
||||
}
|
||||
}
|
||||
)) : nil,
|
||||
@ -766,7 +766,7 @@ final class StarsTransactionsScreenComponent: Component {
|
||||
count: self.starsState?.balance ?? StarsAmount.zero,
|
||||
currency: component.starsContext.ton ? .ton : .stars,
|
||||
rate: nil,
|
||||
actionTitle: component.starsContext.ton ? "Withdraw via Fragment" : (withdrawAvailable ? environment.strings.Stars_Intro_BuyShort : environment.strings.Stars_Intro_Buy),
|
||||
actionTitle: component.starsContext.ton ? environment.strings.Ton_WithdrawViaFragment : (withdrawAvailable ? environment.strings.Stars_Intro_BuyShort : environment.strings.Stars_Intro_Buy),
|
||||
actionAvailable: (!premiumConfiguration.areStarsDisabled && !premiumConfiguration.isPremiumDisabled),
|
||||
actionIsEnabled: true,
|
||||
actionIcon: component.starsContext.ton ? nil : PresentationResourcesItemList.itemListRoundTopupIcon(environment.theme),
|
||||
|
@ -123,6 +123,7 @@ import ChatEmptyNode
|
||||
import ChatMediaInputStickerGridItem
|
||||
import AdsInfoScreen
|
||||
import Photos
|
||||
import ChatThemeScreen
|
||||
|
||||
extension ChatControllerImpl {
|
||||
public func presentThemeSelection() {
|
||||
@ -186,11 +187,11 @@ extension ChatControllerImpl {
|
||||
}
|
||||
},
|
||||
changeWallpaper: { [weak self] in
|
||||
guard let strongSelf = self, let peerId else {
|
||||
guard let self, let peerId else {
|
||||
return
|
||||
}
|
||||
if let themeController = strongSelf.themeScreen {
|
||||
strongSelf.themeScreen = nil
|
||||
if let themeController = self.themeScreen {
|
||||
self.themeScreen = nil
|
||||
themeController.dimTapped()
|
||||
}
|
||||
let dismissControllers = { [weak self] in
|
||||
@ -206,60 +207,58 @@ extension ChatControllerImpl {
|
||||
}
|
||||
var openWallpaperPickerImpl: ((Bool) -> Void)?
|
||||
let openWallpaperPicker = { [weak self] animateAppearance in
|
||||
guard let strongSelf = self else {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let controller = wallpaperMediaPickerController(
|
||||
context: strongSelf.context,
|
||||
updatedPresentationData: strongSelf.updatedPresentationData,
|
||||
context: context,
|
||||
updatedPresentationData: self.updatedPresentationData,
|
||||
peer: EnginePeer(peer),
|
||||
animateAppearance: animateAppearance,
|
||||
completion: { [weak self] _, result in
|
||||
guard let strongSelf = self, let asset = result as? PHAsset else {
|
||||
guard let self, let asset = result as? PHAsset else {
|
||||
return
|
||||
}
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: .peer(EnginePeer(peer), false))
|
||||
let controller = WallpaperGalleryController(context: context, source: .asset(asset), mode: .peer(EnginePeer(peer), false))
|
||||
controller.navigationPresentation = .modal
|
||||
controller.apply = { [weak self] wallpaper, options, editedImage, cropRect, brightness, forBoth in
|
||||
if let strongSelf = self {
|
||||
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, editedImage: editedImage, cropRect: cropRect, brightness: brightness, peerId: peerId, forBoth: forBoth, completion: {
|
||||
Queue.mainQueue().after(0.3, {
|
||||
dismissControllers()
|
||||
})
|
||||
controller.apply = { wallpaper, options, editedImage, cropRect, brightness, forBoth in
|
||||
uploadCustomPeerWallpaper(context: context, wallpaper: wallpaper, mode: options, editedImage: editedImage, cropRect: cropRect, brightness: brightness, peerId: peerId, forBoth: forBoth, completion: {
|
||||
Queue.mainQueue().after(0.3, {
|
||||
dismissControllers()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
self.push(controller)
|
||||
},
|
||||
openColors: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), push: { [weak self] controller in
|
||||
if let strongSelf = self {
|
||||
strongSelf.push(controller)
|
||||
let controller = standaloneColorPickerController(context: context, peer: EnginePeer(peer), push: { [weak self] controller in
|
||||
if let self {
|
||||
self.push(controller)
|
||||
}
|
||||
}, openGallery: {
|
||||
openWallpaperPickerImpl?(false)
|
||||
})
|
||||
controller.navigationPresentation = .flatModal
|
||||
strongSelf.push(controller)
|
||||
self.push(controller)
|
||||
}
|
||||
)
|
||||
controller.navigationPresentation = .flatModal
|
||||
strongSelf.push(controller)
|
||||
self.push(controller)
|
||||
}
|
||||
openWallpaperPickerImpl = openWallpaperPicker
|
||||
openWallpaperPicker(true)
|
||||
},
|
||||
resetWallpaper: { [weak self] in
|
||||
guard let strongSelf = self, let peerId else {
|
||||
guard let self, let peerId else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: nil, forBoth: false).startStandalone()
|
||||
let _ = self.context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: nil, forBoth: false).startStandalone()
|
||||
},
|
||||
completion: { [weak self] chatTheme in
|
||||
guard let strongSelf = self, let peerId else {
|
||||
guard let self, let peerId else {
|
||||
return
|
||||
}
|
||||
if canResetWallpaper && chatTheme != nil {
|
||||
@ -267,8 +266,8 @@ extension ChatControllerImpl {
|
||||
}
|
||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), nil)))
|
||||
let _ = context.engine.themes.setChatTheme(peerId: peerId, chatTheme: chatTheme ?? .emoticon("")).startStandalone(completed: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((nil, nil)))
|
||||
if let self {
|
||||
self.chatThemeAndDarkAppearancePreviewPromise.set(.single((nil, nil)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -141,6 +141,7 @@ import SuggestedPostApproveAlert
|
||||
import AVFoundation
|
||||
import BalanceNeededScreen
|
||||
import FaceScanScreen
|
||||
import ChatThemeScreen
|
||||
|
||||
public final class ChatControllerOverlayPresentationData {
|
||||
public let expandData: (ASDisplayNode?, () -> Void)
|
||||
|
@ -46,6 +46,7 @@ import ComponentFlow
|
||||
import ChatEmptyNode
|
||||
import SpaceWarpView
|
||||
import ChatSideTopicsPanel
|
||||
import ChatThemeScreen
|
||||
|
||||
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
||||
let itemNode: OverlayMediaItemNode
|
||||
|
@ -570,19 +570,18 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
func addToSavedMusic(file: FileMediaReference) {
|
||||
self.dismissAllTooltips()
|
||||
|
||||
var actionText: String? = "View"
|
||||
var actionText: String? = self.presentationData.strings.MediaPlayer_SavedMusic_AddedToProfile_View
|
||||
if let itemId = self.controlsNode.currentItemId as? PeerMessagesMediaPlaylistItemId, itemId.messageId.namespace == Namespaces.Message.Local && itemId.messageId.peerId == self.context.account.peerId {
|
||||
actionText = nil
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let controller = UndoOverlayController(
|
||||
presentationData: self.presentationData,
|
||||
content: .universalImage(
|
||||
image: generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SavedMusic"), color: .white)!,
|
||||
size: nil,
|
||||
title: nil,
|
||||
text: "Audio added to your profile.",
|
||||
text: self.presentationData.strings.MediaPlayer_SavedMusic_AddedToProfile,
|
||||
customUndoText: actionText,
|
||||
timeout: 3.0
|
||||
),
|
||||
@ -620,14 +619,13 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
func removeFromSavedMusic(file: FileMediaReference) {
|
||||
self.dismissAllTooltips()
|
||||
|
||||
//TODO:localize
|
||||
let controller = UndoOverlayController(
|
||||
presentationData: self.presentationData,
|
||||
content: .universalImage(
|
||||
image: generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SavedMusic"), color: .white)!,
|
||||
size: nil,
|
||||
title: nil,
|
||||
text: "Audio removed from your profile.",
|
||||
text: self.presentationData.strings.MediaPlayer_SavedMusic_RemovedFromProfile,
|
||||
customUndoText: nil,
|
||||
timeout: 3.0
|
||||
),
|
||||
@ -1029,10 +1027,9 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
//TODO:localize
|
||||
if canSaveToProfile || canSaveToSavedMessages {
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: "Save to...", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/DownloadTone"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_SaveTo, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/DownloadTone"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
if let self {
|
||||
var subActions: [ContextMenuItem] = []
|
||||
subActions.append(
|
||||
@ -1044,7 +1041,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
|
||||
if canSaveToProfile {
|
||||
subActions.append(
|
||||
.action(ContextMenuActionItem(text: "Profile", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_SaveTo_Profile, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
if let self {
|
||||
@ -1056,7 +1053,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
|
||||
if canSaveToSavedMessages {
|
||||
subActions.append(
|
||||
.action(ContextMenuActionItem(text: "Saved Messages", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Fave"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_SaveTo_SavedMessages, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Fave"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
if let self {
|
||||
@ -1067,7 +1064,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
}
|
||||
|
||||
subActions.append(
|
||||
.action(ContextMenuActionItem(text: "Files", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_SaveTo_Files, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
if let self {
|
||||
@ -1091,7 +1088,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
|
||||
let noAction: ((ContextMenuActionItem.Action) -> Void)? = nil
|
||||
subActions.append(
|
||||
.action(ContextMenuActionItem(text: "Choose where you want this audio to be saved.", textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: noAction))
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_SaveTo_Info, textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: noAction))
|
||||
)
|
||||
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subActions))))
|
||||
@ -1099,7 +1096,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
}))
|
||||
)
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: "Save to Files", icon: { theme in
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_SaveToFiles, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
@ -1131,7 +1128,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
addedSeparator = true
|
||||
}
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: "Show in Chat", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_ShowInChat, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
guard let self else {
|
||||
@ -1144,7 +1141,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
}
|
||||
|
||||
// items.append(
|
||||
// .action(ContextMenuActionItem(text: "Forward", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
// .action(ContextMenuActionItem(text: presentationData.strings.MediaPlayer_ContextMenu_Forward, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
// f(.default)
|
||||
//
|
||||
// if let _ = self {
|
||||
@ -1181,9 +1178,9 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
items.append(.separator)
|
||||
addedSeparator = true
|
||||
}
|
||||
var actionTitle = "Delete"
|
||||
var actionTitle = presentationData.strings.MediaPlayer_ContextMenu_Delete
|
||||
if case .custom = self.source {
|
||||
actionTitle = "Remove"
|
||||
actionTitle = presentationData.strings.MediaPlayer_ContextMenu_Remove
|
||||
}
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: actionTitle, textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, f in
|
||||
|
@ -1026,13 +1026,12 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
self.separatorNode.isHidden = hasSectionHeader
|
||||
|
||||
if hasSectionHeader {
|
||||
//TODO:localize
|
||||
let sideInset: CGFloat = 16.0
|
||||
var sectionTitle = "AUDIO IN THIS CHAT"
|
||||
var sectionTitle = self.presentationData.strings.MediaPlayer_Playlist_ThisChat
|
||||
if let peerName = self.peerName {
|
||||
sectionTitle = "\(peerName.uppercased())'S PLAYLIST"
|
||||
sectionTitle = self.presentationData.strings.MediaPlayer_Playlist_SavedMusic(peerName.uppercased()).string
|
||||
} else if case .custom = self.source {
|
||||
sectionTitle = "YOUR PLAYLIST"
|
||||
sectionTitle = self.presentationData.strings.MediaPlayer_Playlist_SavedMusicYou
|
||||
}
|
||||
let sectionTitleSize = self.sectionTitle.update(
|
||||
transition: .immediate,
|
||||
@ -1096,7 +1095,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
})
|
||||
|
||||
let attributedString = parseMarkdownIntoAttributedString("This audio is visible on your profile. [Remove >]()", attributes: markdownAttributes, textAlignment: .center).mutableCopy() as! NSMutableAttributedString
|
||||
let attributedString = parseMarkdownIntoAttributedString(self.presentationData.strings.MediaPlayer_SavedMusic_RemoveFromProfile, attributes: markdownAttributes, textAlignment: .center).mutableCopy() as! NSMutableAttributedString
|
||||
if let range = attributedString.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 {
|
||||
attributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: attributedString.string))
|
||||
attributedString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedString.string))
|
||||
@ -1125,7 +1124,6 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
))
|
||||
profileAudioOffset = 18.0
|
||||
} else {
|
||||
//TODO:localize
|
||||
profileAudioComponent = AnyComponent(ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
color: self.presentationData.theme.list.itemCheckColors.fillColor,
|
||||
@ -1139,7 +1137,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
BundleIconComponent(name: "Peer Info/SaveMusic", tintColor: self.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||
)),
|
||||
AnyComponentWithIdentity(id: "label", component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: "Add to Profile", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemCheckColors.foregroundColor)))
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: self.presentationData.strings.MediaPlayer_SavedMusic_AddToProfile, font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemCheckColors.foregroundColor)))
|
||||
))
|
||||
], spacing: 8.0)
|
||||
)),
|
||||
|
Loading…
x
Reference in New Issue
Block a user