mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 11:50:56 +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.ChangedThemeGift" = "%1$@ changed chat theme to %2$@";
|
||||||
"Notification.YouChangedThemeGift" = "You changed chat theme to %@";
|
"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
|
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 {
|
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 {
|
extension ChatTheme {
|
||||||
@ -235,6 +249,22 @@ func _internal_setChatTheme(account: Account, peerId: PeerId, chatTheme: ChatThe
|
|||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
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
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||||
if let current = current as? CachedUserData {
|
if let current = current as? CachedUserData {
|
||||||
return current.withUpdatedChatTheme(chatTheme)
|
return current.withUpdatedChatTheme(chatTheme)
|
||||||
@ -246,6 +276,7 @@ func _internal_setChatTheme(account: Account, peerId: PeerId, chatTheme: ChatThe
|
|||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let inputTheme: Api.InputChatTheme
|
let inputTheme: Api.InputChatTheme
|
||||||
if let chatTheme {
|
if let chatTheme {
|
||||||
inputTheme = chatTheme.apiChatTheme
|
inputTheme = chatTheme.apiChatTheme
|
||||||
@ -466,7 +497,7 @@ public final class UniqueGiftChatThemesContext {
|
|||||||
private let cacheDisposable = MetaDisposable()
|
private let cacheDisposable = MetaDisposable()
|
||||||
|
|
||||||
private var themes: [ChatTheme] = []
|
private var themes: [ChatTheme] = []
|
||||||
private var nextOffset: Int32?
|
private var nextOffset: Int32 = 0
|
||||||
private var dataState: UniqueGiftChatThemesContext.State.DataState = .ready(canLoadMore: true)
|
private var dataState: UniqueGiftChatThemesContext.State.DataState = .ready(canLoadMore: true)
|
||||||
|
|
||||||
private let stateValue = Promise<State>()
|
private let stateValue = Promise<State>()
|
||||||
@ -487,7 +518,7 @@ public final class UniqueGiftChatThemesContext {
|
|||||||
|
|
||||||
public func reload() {
|
public func reload() {
|
||||||
self.themes = []
|
self.themes = []
|
||||||
self.nextOffset = nil
|
self.nextOffset = 0
|
||||||
self.dataState = .ready(canLoadMore: true)
|
self.dataState = .ready(canLoadMore: true)
|
||||||
self.loadMore(reload: true)
|
self.loadMore(reload: true)
|
||||||
}
|
}
|
||||||
@ -521,7 +552,7 @@ public final class UniqueGiftChatThemesContext {
|
|||||||
self.pushState()
|
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)
|
|> map(Optional.init)
|
||||||
|> `catch` { error in
|
|> `catch` { error in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
@ -557,7 +588,9 @@ public final class UniqueGiftChatThemesContext {
|
|||||||
} else {
|
} else {
|
||||||
self.themes.append(contentsOf: themes)
|
self.themes.append(contentsOf: themes)
|
||||||
}
|
}
|
||||||
|
if let nextOffset {
|
||||||
|
self.nextOffset = nextOffset
|
||||||
|
}
|
||||||
self.dataState = .ready(canLoadMore: nextOffset != nil)
|
self.dataState = .ready(canLoadMore: nextOffset != nil)
|
||||||
self.pushState()
|
self.pushState()
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -830,8 +830,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
} else {
|
} else {
|
||||||
let price: String
|
let price: String
|
||||||
if currency == "XTR" {
|
if currency == "XTR" {
|
||||||
//TODO:localize
|
price = strings.Notification_PremiumGift_Stars(Int32(clamping: amount))
|
||||||
price = "\(amount) Stars"
|
|
||||||
} else {
|
} else {
|
||||||
price = formatCurrencyAmount(amount, currency: currency)
|
price = formatCurrencyAmount(amount, currency: currency)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -485,6 +485,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/Stars/BalanceNeededScreen",
|
"//submodules/TelegramUI/Components/Stars/BalanceNeededScreen",
|
||||||
"//submodules/TelegramUI/Components/FaceScanScreen",
|
"//submodules/TelegramUI/Components/FaceScanScreen",
|
||||||
"//submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist",
|
"//submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist",
|
||||||
|
"//submodules/TelegramUI/Components/ChatThemeScreen",
|
||||||
"//submodules/ContactsHelper",
|
"//submodules/ContactsHelper",
|
||||||
] + select({
|
] + select({
|
||||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
"@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 TelegramAnimatedStickerNode
|
||||||
import ShimmerEffect
|
import ShimmerEffect
|
||||||
import AttachmentUI
|
import AttachmentUI
|
||||||
|
import AvatarNode
|
||||||
|
|
||||||
private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
|
private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
|
||||||
let index: Int
|
let index: Int
|
||||||
let chatTheme: ChatTheme?
|
let chatTheme: ChatTheme?
|
||||||
let emojiFile: TelegramMediaFile?
|
let emojiFile: TelegramMediaFile?
|
||||||
let themeReference: PresentationThemeReference?
|
let themeReference: PresentationThemeReference?
|
||||||
|
let peer: EnginePeer?
|
||||||
let nightMode: Bool
|
let nightMode: Bool
|
||||||
var selected: Bool
|
var selected: Bool
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
@ -47,6 +49,9 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
|
|||||||
if lhs.themeReference?.index != rhs.themeReference?.index {
|
if lhs.themeReference?.index != rhs.themeReference?.index {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.peer != rhs.peer {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.nightMode != rhs.nightMode {
|
if lhs.nightMode != rhs.nightMode {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -70,16 +75,16 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func item(context: AccountContext, action: @escaping (ChatTheme?) -> Void) -> ListViewItem {
|
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 {
|
private class ThemeSettingsThemeIconItem: ListViewItem {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let chatTheme: ChatTheme?
|
let chatTheme: ChatTheme?
|
||||||
let emojiFile: TelegramMediaFile?
|
let emojiFile: TelegramMediaFile?
|
||||||
let themeReference: PresentationThemeReference?
|
let themeReference: PresentationThemeReference?
|
||||||
|
let peer: EnginePeer?
|
||||||
let nightMode: Bool
|
let nightMode: Bool
|
||||||
let selected: Bool
|
let selected: Bool
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
@ -87,11 +92,24 @@ private class ThemeSettingsThemeIconItem: ListViewItem {
|
|||||||
let wallpaper: TelegramWallpaper?
|
let wallpaper: TelegramWallpaper?
|
||||||
let action: (ChatTheme?) -> Void
|
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.context = context
|
||||||
self.chatTheme = chatTheme
|
self.chatTheme = chatTheme
|
||||||
self.emojiFile = emojiFile
|
self.emojiFile = emojiFile
|
||||||
self.themeReference = themeReference
|
self.themeReference = themeReference
|
||||||
|
self.peer = peer
|
||||||
self.nightMode = nightMode
|
self.nightMode = nightMode
|
||||||
self.selected = selected
|
self.selected = selected
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
@ -525,9 +543,9 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ChatThemeScreen: ViewController {
|
public final class ChatThemeScreen: ViewController {
|
||||||
static let themeCrossfadeDuration: Double = 0.3
|
public static let themeCrossfadeDuration: Double = 0.3
|
||||||
static let themeCrossfadeDelay: Double = 0.25
|
public static let themeCrossfadeDelay: Double = 0.25
|
||||||
|
|
||||||
private var controllerNode: ChatThemeScreenNode {
|
private var controllerNode: ChatThemeScreenNode {
|
||||||
return self.displayNode as! ChatThemeScreenNode
|
return self.displayNode as! ChatThemeScreenNode
|
||||||
@ -539,7 +557,7 @@ final class ChatThemeScreen: ViewController {
|
|||||||
private let animatedEmojiStickers: [String: [StickerPackItem]]
|
private let animatedEmojiStickers: [String: [StickerPackItem]]
|
||||||
private let initiallySelectedTheme: ChatTheme?
|
private let initiallySelectedTheme: ChatTheme?
|
||||||
private let peerName: String
|
private let peerName: String
|
||||||
let canResetWallpaper: Bool
|
fileprivate let canResetWallpaper: Bool
|
||||||
private let previewTheme: (ChatTheme?, Bool?) -> Void
|
private let previewTheme: (ChatTheme?, Bool?) -> Void
|
||||||
fileprivate let changeWallpaper: () -> Void
|
fileprivate let changeWallpaper: () -> Void
|
||||||
fileprivate let resetWallpaper: () -> Void
|
fileprivate let resetWallpaper: () -> Void
|
||||||
@ -548,9 +566,9 @@ final class ChatThemeScreen: ViewController {
|
|||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
|
|
||||||
var dismissed: (() -> Void)?
|
public var dismissed: (() -> Void)?
|
||||||
|
|
||||||
var passthroughHitTestImpl: ((CGPoint) -> UIView?)? {
|
public var passthroughHitTestImpl: ((CGPoint) -> UIView?)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl
|
self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl
|
||||||
@ -558,7 +576,7 @@ final class ChatThemeScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>),
|
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>),
|
||||||
animatedEmojiStickers: [String: [StickerPackItem]],
|
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
|
self.forEachController({ controller in
|
||||||
if let controller = controller as? TooltipScreen {
|
if let controller = controller as? TooltipScreen {
|
||||||
controller.dismiss()
|
controller.dismiss()
|
||||||
@ -683,7 +701,7 @@ final class ChatThemeScreen: ViewController {
|
|||||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dimTapped() {
|
public func dimTapped() {
|
||||||
self.controllerNode.dimTapped()
|
self.controllerNode.dimTapped()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -908,28 +926,13 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
|||||||
chatTheme: nil,
|
chatTheme: nil,
|
||||||
emojiFile: nil,
|
emojiFile: nil,
|
||||||
themeReference: nil,
|
themeReference: nil,
|
||||||
|
peer: nil,
|
||||||
nightMode: false,
|
nightMode: false,
|
||||||
selected: selectedTheme == nil,
|
selected: selectedTheme == nil,
|
||||||
theme: presentationData.theme,
|
theme: presentationData.theme,
|
||||||
strings: presentationData.strings,
|
strings: presentationData.strings,
|
||||||
wallpaper: nil
|
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 {
|
for theme in uniqueGiftChatThemesState.themes {
|
||||||
guard case let .gift(gift, themeSettings) = theme else {
|
guard case let .gift(gift, themeSettings) = theme else {
|
||||||
continue
|
continue
|
||||||
@ -954,6 +957,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
|||||||
chatTheme: theme,
|
chatTheme: theme,
|
||||||
emojiFile: emojiFile,
|
emojiFile: emojiFile,
|
||||||
themeReference: .builtin(.dayClassic),
|
themeReference: .builtin(.dayClassic),
|
||||||
|
peer: nil,
|
||||||
nightMode: isDarkAppearance,
|
nightMode: isDarkAppearance,
|
||||||
selected: selectedTheme?.id == theme.id,
|
selected: selectedTheme?.id == theme.id,
|
||||||
theme: presentationData.theme,
|
theme: presentationData.theme,
|
||||||
@ -961,6 +965,24 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
|||||||
wallpaper: wallpaper
|
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
|
let action: (ChatTheme?) -> Void = { [weak self] chatTheme in
|
||||||
if let self, self.selectedTheme != chatTheme {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
var items: [ContextMenuItem] = []
|
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)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { [weak self] _, f in
|
}, action: { [weak self] _, f in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -1183,7 +1182,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
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)
|
self.parentController?.present(controller, in: .current)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -680,7 +680,7 @@ final class StarsTransactionsScreenComponent: Component {
|
|||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
header: AnyComponent(MultilineTextComponent(
|
header: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: "Proceeds Overview".uppercased(),
|
string: environment.strings.Ton_ProceedsOverview.uppercased(),
|
||||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||||
textColor: environment.theme.list.freeTextColor
|
textColor: environment.theme.list.freeTextColor
|
||||||
)),
|
)),
|
||||||
@ -691,14 +691,14 @@ final class StarsTransactionsScreenComponent: Component {
|
|||||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(StarsOverviewItemComponent(
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(StarsOverviewItemComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
dateTimeFormat: environment.dateTimeFormat,
|
dateTimeFormat: environment.dateTimeFormat,
|
||||||
title: "Balance Available to Withdraw",
|
title: environment.strings.Ton_AvailableBalance,
|
||||||
value: self.revenueState?.balances.availableBalance ?? CurrencyAmount(amount: .zero, currency: .ton),
|
value: self.revenueState?.balances.availableBalance ?? CurrencyAmount(amount: .zero, currency: .ton),
|
||||||
rate: self.revenueState?.usdRate ?? 0.0
|
rate: self.revenueState?.usdRate ?? 0.0
|
||||||
))),
|
))),
|
||||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(StarsOverviewItemComponent(
|
AnyComponentWithIdentity(id: 1, component: AnyComponent(StarsOverviewItemComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
dateTimeFormat: environment.dateTimeFormat,
|
dateTimeFormat: environment.dateTimeFormat,
|
||||||
title: "Total Lifetime Proceeds",
|
title: environment.strings.Ton_LifetimeProceeds,
|
||||||
value: self.revenueState?.balances.overallRevenue ?? CurrencyAmount(amount: .zero, currency: .ton),
|
value: self.revenueState?.balances.overallRevenue ?? CurrencyAmount(amount: .zero, currency: .ton),
|
||||||
rate: self.revenueState?.usdRate ?? 0.0
|
rate: self.revenueState?.usdRate ?? 0.0
|
||||||
)))
|
)))
|
||||||
@ -725,7 +725,7 @@ final class StarsTransactionsScreenComponent: Component {
|
|||||||
return (TelegramTextAttributes.URL, contents)
|
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))
|
let balanceInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(balanceInfoRawString, attributes: termsMarkdownAttributes, textAlignment: .natural))
|
||||||
if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme {
|
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)
|
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
|
tapAction: { [weak self] attributes, _ in
|
||||||
if let controller = self?.controller?() as? StarsTransactionsScreen, let navigationController = controller.navigationController as? NavigationController {
|
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,
|
)) : nil,
|
||||||
@ -766,7 +766,7 @@ final class StarsTransactionsScreenComponent: Component {
|
|||||||
count: self.starsState?.balance ?? StarsAmount.zero,
|
count: self.starsState?.balance ?? StarsAmount.zero,
|
||||||
currency: component.starsContext.ton ? .ton : .stars,
|
currency: component.starsContext.ton ? .ton : .stars,
|
||||||
rate: nil,
|
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),
|
actionAvailable: (!premiumConfiguration.areStarsDisabled && !premiumConfiguration.isPremiumDisabled),
|
||||||
actionIsEnabled: true,
|
actionIsEnabled: true,
|
||||||
actionIcon: component.starsContext.ton ? nil : PresentationResourcesItemList.itemListRoundTopupIcon(environment.theme),
|
actionIcon: component.starsContext.ton ? nil : PresentationResourcesItemList.itemListRoundTopupIcon(environment.theme),
|
||||||
|
|||||||
@ -123,6 +123,7 @@ import ChatEmptyNode
|
|||||||
import ChatMediaInputStickerGridItem
|
import ChatMediaInputStickerGridItem
|
||||||
import AdsInfoScreen
|
import AdsInfoScreen
|
||||||
import Photos
|
import Photos
|
||||||
|
import ChatThemeScreen
|
||||||
|
|
||||||
extension ChatControllerImpl {
|
extension ChatControllerImpl {
|
||||||
public func presentThemeSelection() {
|
public func presentThemeSelection() {
|
||||||
@ -186,11 +187,11 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeWallpaper: { [weak self] in
|
changeWallpaper: { [weak self] in
|
||||||
guard let strongSelf = self, let peerId else {
|
guard let self, let peerId else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let themeController = strongSelf.themeScreen {
|
if let themeController = self.themeScreen {
|
||||||
strongSelf.themeScreen = nil
|
self.themeScreen = nil
|
||||||
themeController.dimTapped()
|
themeController.dimTapped()
|
||||||
}
|
}
|
||||||
let dismissControllers = { [weak self] in
|
let dismissControllers = { [weak self] in
|
||||||
@ -206,60 +207,58 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
var openWallpaperPickerImpl: ((Bool) -> Void)?
|
var openWallpaperPickerImpl: ((Bool) -> Void)?
|
||||||
let openWallpaperPicker = { [weak self] animateAppearance in
|
let openWallpaperPicker = { [weak self] animateAppearance in
|
||||||
guard let strongSelf = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let controller = wallpaperMediaPickerController(
|
let controller = wallpaperMediaPickerController(
|
||||||
context: strongSelf.context,
|
context: context,
|
||||||
updatedPresentationData: strongSelf.updatedPresentationData,
|
updatedPresentationData: self.updatedPresentationData,
|
||||||
peer: EnginePeer(peer),
|
peer: EnginePeer(peer),
|
||||||
animateAppearance: animateAppearance,
|
animateAppearance: animateAppearance,
|
||||||
completion: { [weak self] _, result in
|
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
|
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.navigationPresentation = .modal
|
||||||
controller.apply = { [weak self] wallpaper, options, editedImage, cropRect, brightness, forBoth in
|
controller.apply = { wallpaper, options, editedImage, cropRect, brightness, forBoth in
|
||||||
if let strongSelf = self {
|
uploadCustomPeerWallpaper(context: context, wallpaper: wallpaper, mode: options, editedImage: editedImage, cropRect: cropRect, brightness: brightness, peerId: peerId, forBoth: forBoth, completion: {
|
||||||
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, editedImage: editedImage, cropRect: cropRect, brightness: brightness, peerId: peerId, forBoth: forBoth, completion: {
|
|
||||||
Queue.mainQueue().after(0.3, {
|
Queue.mainQueue().after(0.3, {
|
||||||
dismissControllers()
|
dismissControllers()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
self.push(controller)
|
||||||
strongSelf.push(controller)
|
|
||||||
},
|
},
|
||||||
openColors: { [weak self] in
|
openColors: { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), push: { [weak self] controller in
|
let controller = standaloneColorPickerController(context: context, peer: EnginePeer(peer), push: { [weak self] controller in
|
||||||
if let strongSelf = self {
|
if let self {
|
||||||
strongSelf.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
}, openGallery: {
|
}, openGallery: {
|
||||||
openWallpaperPickerImpl?(false)
|
openWallpaperPickerImpl?(false)
|
||||||
})
|
})
|
||||||
controller.navigationPresentation = .flatModal
|
controller.navigationPresentation = .flatModal
|
||||||
strongSelf.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
controller.navigationPresentation = .flatModal
|
controller.navigationPresentation = .flatModal
|
||||||
strongSelf.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
openWallpaperPickerImpl = openWallpaperPicker
|
openWallpaperPickerImpl = openWallpaperPicker
|
||||||
openWallpaperPicker(true)
|
openWallpaperPicker(true)
|
||||||
},
|
},
|
||||||
resetWallpaper: { [weak self] in
|
resetWallpaper: { [weak self] in
|
||||||
guard let strongSelf = self, let peerId else {
|
guard let self, let peerId else {
|
||||||
return
|
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
|
completion: { [weak self] chatTheme in
|
||||||
guard let strongSelf = self, let peerId else {
|
guard let self, let peerId else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if canResetWallpaper && chatTheme != nil {
|
if canResetWallpaper && chatTheme != nil {
|
||||||
@ -267,8 +266,8 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), nil)))
|
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), nil)))
|
||||||
let _ = context.engine.themes.setChatTheme(peerId: peerId, chatTheme: chatTheme ?? .emoticon("")).startStandalone(completed: { [weak self] in
|
let _ = context.engine.themes.setChatTheme(peerId: peerId, chatTheme: chatTheme ?? .emoticon("")).startStandalone(completed: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let self {
|
||||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((nil, nil)))
|
self.chatThemeAndDarkAppearancePreviewPromise.set(.single((nil, nil)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,6 +141,7 @@ import SuggestedPostApproveAlert
|
|||||||
import AVFoundation
|
import AVFoundation
|
||||||
import BalanceNeededScreen
|
import BalanceNeededScreen
|
||||||
import FaceScanScreen
|
import FaceScanScreen
|
||||||
|
import ChatThemeScreen
|
||||||
|
|
||||||
public final class ChatControllerOverlayPresentationData {
|
public final class ChatControllerOverlayPresentationData {
|
||||||
public let expandData: (ASDisplayNode?, () -> Void)
|
public let expandData: (ASDisplayNode?, () -> Void)
|
||||||
|
|||||||
@ -46,6 +46,7 @@ import ComponentFlow
|
|||||||
import ChatEmptyNode
|
import ChatEmptyNode
|
||||||
import SpaceWarpView
|
import SpaceWarpView
|
||||||
import ChatSideTopicsPanel
|
import ChatSideTopicsPanel
|
||||||
|
import ChatThemeScreen
|
||||||
|
|
||||||
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
||||||
let itemNode: OverlayMediaItemNode
|
let itemNode: OverlayMediaItemNode
|
||||||
|
|||||||
@ -570,19 +570,18 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
func addToSavedMusic(file: FileMediaReference) {
|
func addToSavedMusic(file: FileMediaReference) {
|
||||||
self.dismissAllTooltips()
|
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 {
|
if let itemId = self.controlsNode.currentItemId as? PeerMessagesMediaPlaylistItemId, itemId.messageId.namespace == Namespaces.Message.Local && itemId.messageId.peerId == self.context.account.peerId {
|
||||||
actionText = nil
|
actionText = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let controller = UndoOverlayController(
|
let controller = UndoOverlayController(
|
||||||
presentationData: self.presentationData,
|
presentationData: self.presentationData,
|
||||||
content: .universalImage(
|
content: .universalImage(
|
||||||
image: generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SavedMusic"), color: .white)!,
|
image: generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SavedMusic"), color: .white)!,
|
||||||
size: nil,
|
size: nil,
|
||||||
title: nil,
|
title: nil,
|
||||||
text: "Audio added to your profile.",
|
text: self.presentationData.strings.MediaPlayer_SavedMusic_AddedToProfile,
|
||||||
customUndoText: actionText,
|
customUndoText: actionText,
|
||||||
timeout: 3.0
|
timeout: 3.0
|
||||||
),
|
),
|
||||||
@ -620,14 +619,13 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
func removeFromSavedMusic(file: FileMediaReference) {
|
func removeFromSavedMusic(file: FileMediaReference) {
|
||||||
self.dismissAllTooltips()
|
self.dismissAllTooltips()
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let controller = UndoOverlayController(
|
let controller = UndoOverlayController(
|
||||||
presentationData: self.presentationData,
|
presentationData: self.presentationData,
|
||||||
content: .universalImage(
|
content: .universalImage(
|
||||||
image: generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SavedMusic"), color: .white)!,
|
image: generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SavedMusic"), color: .white)!,
|
||||||
size: nil,
|
size: nil,
|
||||||
title: nil,
|
title: nil,
|
||||||
text: "Audio removed from your profile.",
|
text: self.presentationData.strings.MediaPlayer_SavedMusic_RemovedFromProfile,
|
||||||
customUndoText: nil,
|
customUndoText: nil,
|
||||||
timeout: 3.0
|
timeout: 3.0
|
||||||
),
|
),
|
||||||
@ -1029,10 +1027,9 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}
|
}
|
||||||
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
//TODO:localize
|
|
||||||
if canSaveToProfile || canSaveToSavedMessages {
|
if canSaveToProfile || canSaveToSavedMessages {
|
||||||
items.append(
|
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 {
|
if let self {
|
||||||
var subActions: [ContextMenuItem] = []
|
var subActions: [ContextMenuItem] = []
|
||||||
subActions.append(
|
subActions.append(
|
||||||
@ -1044,7 +1041,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
|
|
||||||
if canSaveToProfile {
|
if canSaveToProfile {
|
||||||
subActions.append(
|
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)
|
f(.default)
|
||||||
|
|
||||||
if let self {
|
if let self {
|
||||||
@ -1056,7 +1053,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
|
|
||||||
if canSaveToSavedMessages {
|
if canSaveToSavedMessages {
|
||||||
subActions.append(
|
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)
|
f(.default)
|
||||||
|
|
||||||
if let self {
|
if let self {
|
||||||
@ -1067,7 +1064,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}
|
}
|
||||||
|
|
||||||
subActions.append(
|
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)
|
f(.default)
|
||||||
|
|
||||||
if let self {
|
if let self {
|
||||||
@ -1091,7 +1088,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
|
|
||||||
let noAction: ((ContextMenuActionItem.Action) -> Void)? = nil
|
let noAction: ((ContextMenuActionItem.Action) -> Void)? = nil
|
||||||
subActions.append(
|
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))))
|
c?.pushItems(items: .single(ContextController.Items(content: .list(subActions))))
|
||||||
@ -1099,7 +1096,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
} else {
|
} 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)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { [weak self] _, f in
|
}, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
@ -1131,7 +1128,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
addedSeparator = true
|
addedSeparator = true
|
||||||
}
|
}
|
||||||
items.append(
|
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)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -1144,7 +1141,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// items.append(
|
// 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)
|
// f(.default)
|
||||||
//
|
//
|
||||||
// if let _ = self {
|
// if let _ = self {
|
||||||
@ -1181,9 +1178,9 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
items.append(.separator)
|
items.append(.separator)
|
||||||
addedSeparator = true
|
addedSeparator = true
|
||||||
}
|
}
|
||||||
var actionTitle = "Delete"
|
var actionTitle = presentationData.strings.MediaPlayer_ContextMenu_Delete
|
||||||
if case .custom = self.source {
|
if case .custom = self.source {
|
||||||
actionTitle = "Remove"
|
actionTitle = presentationData.strings.MediaPlayer_ContextMenu_Remove
|
||||||
}
|
}
|
||||||
items.append(
|
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
|
.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
|
self.separatorNode.isHidden = hasSectionHeader
|
||||||
|
|
||||||
if hasSectionHeader {
|
if hasSectionHeader {
|
||||||
//TODO:localize
|
|
||||||
let sideInset: CGFloat = 16.0
|
let sideInset: CGFloat = 16.0
|
||||||
var sectionTitle = "AUDIO IN THIS CHAT"
|
var sectionTitle = self.presentationData.strings.MediaPlayer_Playlist_ThisChat
|
||||||
if let peerName = self.peerName {
|
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 {
|
} else if case .custom = self.source {
|
||||||
sectionTitle = "YOUR PLAYLIST"
|
sectionTitle = self.presentationData.strings.MediaPlayer_Playlist_SavedMusicYou
|
||||||
}
|
}
|
||||||
let sectionTitleSize = self.sectionTitle.update(
|
let sectionTitleSize = self.sectionTitle.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
@ -1096,7 +1095,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
|||||||
return (TelegramTextAttributes.URL, contents)
|
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 {
|
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(.attachment, value: chevronImage, range: NSRange(range, in: attributedString.string))
|
||||||
attributedString.addAttribute(.baselineOffset, value: 1.0, 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
|
profileAudioOffset = 18.0
|
||||||
} else {
|
} else {
|
||||||
//TODO:localize
|
|
||||||
profileAudioComponent = AnyComponent(ButtonComponent(
|
profileAudioComponent = AnyComponent(ButtonComponent(
|
||||||
background: ButtonComponent.Background(
|
background: ButtonComponent.Background(
|
||||||
color: self.presentationData.theme.list.itemCheckColors.fillColor,
|
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)
|
BundleIconComponent(name: "Peer Info/SaveMusic", tintColor: self.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||||
)),
|
)),
|
||||||
AnyComponentWithIdentity(id: "label", component: AnyComponent(
|
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)
|
], spacing: 8.0)
|
||||||
)),
|
)),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user