mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
5dd0a03d9a
@ -14789,3 +14789,82 @@ Sorry for the inconvenience.";
|
|||||||
"Stars.SellGift.OnlyTonInfo" = "If the buyer pays you in TON, there's no risk of refunds, unlike with Stars payments.";
|
"Stars.SellGift.OnlyTonInfo" = "If the buyer pays you in TON, there's no risk of refunds, unlike with Stars payments.";
|
||||||
|
|
||||||
"Chat.ViewCollection" = "VIEW COLLECTION";
|
"Chat.ViewCollection" = "VIEW COLLECTION";
|
||||||
|
|
||||||
|
"CallList.DeleteConfirmation" = "Do you want to delete the information about this call?";
|
||||||
|
|
||||||
|
"ChatList.Search.FilterGlobalPosts" = "Posts";
|
||||||
|
"ChatList.HeaderPublicPosts" = "PUBLIC POSTS";
|
||||||
|
"ChatList.PaidSearchToast.Text_1" = "%@ Star spent on extra search.";
|
||||||
|
"ChatList.PaidSearchToast.Text_any" = "%@ Stars spent on extra search.";
|
||||||
|
|
||||||
|
"ChatList.GlobalSearch.StartPlaceholder.Title" = "Global Search";
|
||||||
|
"ChatList.GlobalSearch.StartPlaceholder.Text" = "Type a keyword to search all posts\nfrom public channels.";
|
||||||
|
"ChatList.GlobalSearch.StartPlaceholder.Subtitle" = "Global search is a Premium feature.";
|
||||||
|
"ChatList.GlobalSearch.StartPlaceholder.RemainingSubtitle_1" = "%@ free search remaining today.";
|
||||||
|
"ChatList.GlobalSearch.StartPlaceholder.RemainingSubtitle_any" = "%@ free searches remaining today.";
|
||||||
|
"ChatList.GlobalSearch.LimitPlaceholder.Title" = "Limit Reached";
|
||||||
|
"ChatList.GlobalSearch.LimitPlaceholder.Text_1" = "You can make up to\n%@ search query per day.";
|
||||||
|
"ChatList.GlobalSearch.LimitPlaceholder.Text_any" = "You can make up to\n%@ search queries per day.";
|
||||||
|
"ChatList.GlobalSearch.SearchButton" = "Search";
|
||||||
|
"ChatList.GlobalSearch.SearchButtonPremium" = "Subscribe to Premium";
|
||||||
|
"ChatList.GlobalSearch.SearchButtonQuery" = "Search {}";
|
||||||
|
"ChatList.GlobalSearch.SearchButtonPaidTitle" = "Search for * %@";
|
||||||
|
"ChatList.GlobalSearch.SearchButtonPaidSubtitle" = "free search unlocks in %@";
|
||||||
|
|
||||||
|
"Chat.ViewCollection" = "VIEW COLLECTION";
|
||||||
|
"Chat.ViewAlbum" = "VIEW ALBUM";
|
||||||
|
|
||||||
|
"PeerInfo.MenuAddStories" = "Add Stories";
|
||||||
|
"Stories.MenuDeleteAlbum" = "Delete Album";
|
||||||
|
"Stories.AddStoriesTitle" = "Add Stories";
|
||||||
|
"Stories.AddStoriesEmpty" = "Add Stories";
|
||||||
|
"Stories.AddStories_1" = "Add %@ Story";
|
||||||
|
"Stories.AddStories_any" = "Add %@ Stories";
|
||||||
|
"Stories.MenuAddToAlbum" = "Add to Album";
|
||||||
|
"Stories.MenuRemoveFromAlbum" = "Remove from Album";
|
||||||
|
"Stories.MenuNewAlbum" = "New Album";
|
||||||
|
"Stories.MenuRenameAlbum" = "Rename Album";
|
||||||
|
"Stories.StatusEmpty" = "no stories";
|
||||||
|
"Stories.AlbumAll" = "All Stories";
|
||||||
|
"Stories.AlbumAdd" = "+ Add Album";
|
||||||
|
"Stories.AlbumEmptyTitle" = "Organize Your Stories";
|
||||||
|
"Stories.AlbumEmptyText" = "Add some stories to this album.";
|
||||||
|
"Stories.AlbumEmptyButton" = "Add to Album";
|
||||||
|
"Stories.CreateAlbum.Title" = "Create a New Album";
|
||||||
|
"Stories.CreateAlbum.Text" = "Choose a name for your album and start adding your stories there.";
|
||||||
|
"Stories.CreateAlbum.Placeholder" = "Title";
|
||||||
|
"Stories.EditAlbum.Title" = "Edit Album Name";
|
||||||
|
"Stories.EditAlbum.Text" = "Choose a new name for your album.";
|
||||||
|
"Stories.DeleteAlbum.Confirmation" = "Delete %@?";
|
||||||
|
|
||||||
|
"ProfileLevelInfo.Title" = "Rating";
|
||||||
|
"ProfileLevelInfo.MyText" = "The rating reflects your activity on Telegram. What affects it:";
|
||||||
|
"ProfileLevelInfo.MyDescriptionToday_1" = "The rating updates today.\n\%@ point is pending.";
|
||||||
|
"ProfileLevelInfo.MyDescriptionToday_any" = "The rating updates today.\n\%@ points are pending.";
|
||||||
|
"ProfileLevelInfo.MyDescriptionDays_1" = "%@ day";
|
||||||
|
"ProfileLevelInfo.MyDescriptionDays_any" = "%@ days";
|
||||||
|
"ProfileLevelInfo.MyDescriptionPoints_1" = "%@ point is";
|
||||||
|
"ProfileLevelInfo.MyDescriptionPoints_any" = "%@ points are";
|
||||||
|
"ProfileLevelInfo.MyDescription" = "The rating updates in %@ after purchases.\n\%@ pending.";
|
||||||
|
"ProfileLevelInfo.OtherDescription" = "The rating reflects **%@'s** activity on Telegram. What affects it:";
|
||||||
|
"ProfileLevelInfo.LevelIndex_1" = "Level %@";
|
||||||
|
"ProfileLevelInfo.LevelIndex_any" = "Level %@";
|
||||||
|
"ProfileLevelInfo.CloseButton" = "Understood";
|
||||||
|
|
||||||
|
"ProfileLevelInfo.Item0.Title" = "Gifts from Telegram";
|
||||||
|
"ProfileLevelInfo.Item0.Text" = "100% of the Stars spent on gifts purchased from Telegram.";
|
||||||
|
"ProfileLevelInfo.Item0.Badge" = "ADDED";
|
||||||
|
"ProfileLevelInfo.Item1.Title" = "Gifts and Posts from Users";
|
||||||
|
"ProfileLevelInfo.Item1.Text" = "20% of the Stars spent on gifts or posts from users and channels.";
|
||||||
|
"ProfileLevelInfo.Item1.Badge" = "ADDED";
|
||||||
|
"ProfileLevelInfo.Item2.Title" = "Refunds and Conversions";
|
||||||
|
"ProfileLevelInfo.Item2.Text" = "10x of refunded Stars and 85% of bought gifts converted to Stars.";
|
||||||
|
"ProfileLevelInfo.Item2.Badge" = "DEDUCTED";
|
||||||
|
|
||||||
|
"Call.AlertMoveToConference" = "End current call and start a conference?";
|
||||||
|
|
||||||
|
"Stories.Post.Album" = "Album";
|
||||||
|
"Stories.Post.AlbumFooter" = "Choose the albums where you want to share your story.";
|
||||||
|
"Stories.Post.AlbumAll" = "All Stories";
|
||||||
|
"Stories.Post.AlbumCount_1" = "%@ Album";
|
||||||
|
"Stories.Post.AlbumCount_any" = "%@ Albums";
|
||||||
|
@ -350,8 +350,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||||
var items: [ActionSheetItem] = []
|
var items: [ActionSheetItem] = []
|
||||||
|
|
||||||
//TODO:localize
|
items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.CallList_DeleteConfirmation, parseMarkdown: true))
|
||||||
items.append(ActionSheetTextItem(title: "Do you want to delete the information about this call?", parseMarkdown: true))
|
|
||||||
|
|
||||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_DeleteMessagesFor(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string, color: .destructive, action: { [weak actionSheet] in
|
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_DeleteMessagesFor(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string, color: .destructive, action: { [weak actionSheet] in
|
||||||
actionSheet?.dismissAnimated()
|
actionSheet?.dismissAnimated()
|
||||||
|
@ -93,9 +93,8 @@ private final class ItemNode: ASDisplayNode {
|
|||||||
title = presentationData.strings.ChatList_Search_FilterApps
|
title = presentationData.strings.ChatList_Search_FilterApps
|
||||||
icon = nil
|
icon = nil
|
||||||
case .globalPosts:
|
case .globalPosts:
|
||||||
//TODO:localize
|
title = presentationData.strings.ChatList_Search_FilterGlobalPosts
|
||||||
title = "Posts"
|
titleBadge = presentationData.strings.ChatList_ContextMenuBadgeNew
|
||||||
titleBadge = "NEW"
|
|
||||||
icon = nil
|
icon = nil
|
||||||
case .media:
|
case .media:
|
||||||
title = presentationData.strings.ChatList_Search_FilterMedia
|
title = presentationData.strings.ChatList_Search_FilterMedia
|
||||||
|
@ -291,8 +291,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if case .globalPosts = key {
|
} else if case .globalPosts = key {
|
||||||
//TODO:localize
|
header = ChatListSearchItemHeader(type: .text(strings.ChatList_HeaderPublicPosts, 0), theme: theme, strings: strings, actionTitle: nil, action: nil)
|
||||||
header = ChatListSearchItemHeader(type: .text("Public Posts", 0), theme: theme, strings: strings, actionTitle: nil, action: nil)
|
|
||||||
} else {
|
} else {
|
||||||
header = ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: { _ in
|
header = ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: { _ in
|
||||||
clearRecentlySearchedPeers()
|
clearRecentlySearchedPeers()
|
||||||
@ -1121,7 +1120,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
var headerType: ChatListSearchItemHeaderType = .messages(location: nil)
|
var headerType: ChatListSearchItemHeaderType = .messages(location: nil)
|
||||||
var actionTitle: String?
|
var actionTitle: String?
|
||||||
if key == .globalPosts {
|
if key == .globalPosts {
|
||||||
headerType = .text("Public Posts", 0)
|
headerType = .text(presentationData.strings.ChatList_HeaderPublicPosts, 0)
|
||||||
} else {
|
} else {
|
||||||
if case let .forum(peerId) = location, let peer = peer.peer, peer.id == peerId {
|
if case let .forum(peerId) = location, let peer = peer.peer, peer.id == peerId {
|
||||||
headerType = .messages(location: peer.compactDisplayTitle)
|
headerType = .messages(location: peer.compactDisplayTitle)
|
||||||
@ -1138,8 +1137,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
case .privateChats:
|
case .privateChats:
|
||||||
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
|
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
|
||||||
case .globalPosts:
|
case .globalPosts:
|
||||||
//TODO:localize
|
filterTitle = presentationData.strings.ChatList_HeaderPublicPosts
|
||||||
filterTitle = "Public Posts"
|
|
||||||
}
|
}
|
||||||
actionTitle = "\(filterTitle) <"
|
actionTitle = "\(filterTitle) <"
|
||||||
}
|
}
|
||||||
@ -1230,14 +1228,13 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
case .privateChats:
|
case .privateChats:
|
||||||
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
|
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
|
||||||
case .globalPosts:
|
case .globalPosts:
|
||||||
filterTitle = "Public Posts"
|
filterTitle = presentationData.strings.ChatList_HeaderPublicPosts
|
||||||
}
|
}
|
||||||
actionTitle = "\(filterTitle) <"
|
actionTitle = "\(filterTitle) <"
|
||||||
|
|
||||||
let header: ChatListSearchItemHeader
|
let header: ChatListSearchItemHeader
|
||||||
if key == .globalPosts {
|
if key == .globalPosts {
|
||||||
//TODO:localize
|
header = ChatListSearchItemHeader(type: .text(presentationData.strings.ChatList_HeaderPublicPosts, 0), theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||||
header = ChatListSearchItemHeader(type: .text("Public Posts", 0), theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
|
||||||
} else {
|
} else {
|
||||||
header = ChatListSearchItemHeader(type: .messages(location: nil), theme: presentationData.theme, strings: presentationData.strings, actionTitle: actionTitle, action: { sourceNode in
|
header = ChatListSearchItemHeader(type: .messages(location: nil), theme: presentationData.theme, strings: presentationData.strings, actionTitle: actionTitle, action: { sourceNode in
|
||||||
openMessagesFilter(sourceNode)
|
openMessagesFilter(sourceNode)
|
||||||
@ -1257,8 +1254,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
case .privateChats:
|
case .privateChats:
|
||||||
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
|
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
|
||||||
case .globalPosts:
|
case .globalPosts:
|
||||||
//TODO:localize
|
filterTitle = presentationData.strings.ChatList_HeaderPublicPosts
|
||||||
filterTitle = "Public Posts"
|
|
||||||
}
|
}
|
||||||
actionTitle = "\(filterTitle) <"
|
actionTitle = "\(filterTitle) <"
|
||||||
|
|
||||||
@ -5133,14 +5129,13 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
))
|
))
|
||||||
|
|
||||||
if let price {
|
if let price {
|
||||||
//TODO:localize
|
|
||||||
if let controller = self.navigationController?.topViewController as? ViewController {
|
if let controller = self.navigationController?.topViewController as? ViewController {
|
||||||
controller.present(UndoOverlayController(
|
controller.present(UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .starsSent(context: self.context, title: "", text: [AnimatedTextComponent.Item(
|
content: .starsSent(context: self.context, title: "", text: [AnimatedTextComponent.Item(
|
||||||
id: AnyHashable(0),
|
id: AnyHashable(0),
|
||||||
isUnbreakable: true,
|
isUnbreakable: true,
|
||||||
content: .text("\(price) Stars spent on extra search.")
|
content: .text(presentationData.strings.ChatList_PaidSearchToast_Text(Int32(price)))
|
||||||
)], hasUndo: false),
|
)], hasUndo: false),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
animateInAsReplacement: false,
|
animateInAsReplacement: false,
|
||||||
@ -5400,9 +5395,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
if strongSelf.key == .globalPosts, let globalSearchStateValue = transition.globalSearchStateValue {
|
if strongSelf.key == .globalPosts, let globalSearchStateValue = transition.globalSearchStateValue {
|
||||||
if !strongSelf.isPremium {
|
if !strongSelf.isPremium {
|
||||||
emptyResultsButtonContent = .premiumRequired
|
emptyResultsButtonContent = .premiumRequired
|
||||||
emptyResultsTitle = "Global Search"
|
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Title
|
||||||
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
|
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Text
|
||||||
emptyResultsButtonSubtitleText = "Global search is a Premium feature."
|
emptyResultsButtonSubtitleText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Subtitle
|
||||||
} else if let query = transition.query, !query.isEmpty {
|
} else if let query = transition.query, !query.isEmpty {
|
||||||
if transition.approvedGlobalPostQueryState?.query == query {
|
if transition.approvedGlobalPostQueryState?.query == query {
|
||||||
emptyResultsButtonContent = nil
|
emptyResultsButtonContent = nil
|
||||||
@ -5410,18 +5405,14 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
emptyResultsText = strongSelf.presentationData.strings.ChatList_Search_NoResultsQueryDescription(query).string
|
emptyResultsText = strongSelf.presentationData.strings.ChatList_Search_NoResultsQueryDescription(query).string
|
||||||
} else {
|
} else {
|
||||||
if globalSearchStateValue.remainingFreeSearches != 0 {
|
if globalSearchStateValue.remainingFreeSearches != 0 {
|
||||||
emptyResultsTitle = "Global Search"
|
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Title
|
||||||
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
|
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Text
|
||||||
if globalSearchStateValue.remainingFreeSearches == 1 {
|
emptyResultsButtonSubtitleText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_RemainingSubtitle(Int32(globalSearchStateValue.remainingFreeSearches))
|
||||||
emptyResultsButtonSubtitleText = "1 free search remaining today."
|
|
||||||
} else {
|
|
||||||
emptyResultsButtonSubtitleText = "\(globalSearchStateValue.remainingFreeSearches) free searches remaining today."
|
|
||||||
}
|
|
||||||
|
|
||||||
emptyResultsButtonContent = .searchQuery(query)
|
emptyResultsButtonContent = .searchQuery(query)
|
||||||
} else {
|
} else {
|
||||||
emptyResultsTitle = "Limit Reached"
|
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Title
|
||||||
emptyResultsText = "You can make up to\n\(globalSearchStateValue.totalFreeSearches) search queries per day."
|
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Text(Int32(globalSearchStateValue.totalFreeSearches))
|
||||||
|
|
||||||
emptyResultsButtonContent = .paidSearch(
|
emptyResultsButtonContent = .paidSearch(
|
||||||
price: Int(globalSearchStateValue.price.value),
|
price: Int(globalSearchStateValue.price.value),
|
||||||
@ -5432,17 +5423,12 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
} else {
|
} else {
|
||||||
if globalSearchStateValue.remainingFreeSearches != 0 {
|
if globalSearchStateValue.remainingFreeSearches != 0 {
|
||||||
emptyResultsButtonContent = .searchEmpty
|
emptyResultsButtonContent = .searchEmpty
|
||||||
emptyResultsTitle = "Global Search"
|
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Title
|
||||||
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
|
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Text
|
||||||
|
emptyResultsButtonSubtitleText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_RemainingSubtitle(Int32(globalSearchStateValue.remainingFreeSearches))
|
||||||
if globalSearchStateValue.remainingFreeSearches == 1 {
|
|
||||||
emptyResultsButtonSubtitleText = "1 free search remaining today."
|
|
||||||
} else {
|
|
||||||
emptyResultsButtonSubtitleText = "\(globalSearchStateValue.remainingFreeSearches) free searches remaining today."
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
emptyResultsTitle = "Limit Reached"
|
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Title
|
||||||
emptyResultsText = "You can make up to\n10 search queries per day."
|
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Text(Int32(globalSearchStateValue.totalFreeSearches))
|
||||||
|
|
||||||
emptyResultsButtonContent = .paidSearch(
|
emptyResultsButtonContent = .paidSearch(
|
||||||
price: Int(globalSearchStateValue.price.value),
|
price: Int(globalSearchStateValue.price.value),
|
||||||
@ -6228,10 +6214,20 @@ private final class EmptyResultsButtonSearchContent: Component {
|
|||||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let string = NSMutableAttributedString()
|
let string = NSMutableAttributedString()
|
||||||
string.append(NSAttributedString(string: "Search ", font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
|
|
||||||
string.append(NSAttributedString(string: component.query.trimmingCharacters(in: .whitespacesAndNewlines), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor.withMultipliedAlpha(0.7)))
|
let rawString = component.strings.ChatList_GlobalSearch_SearchButtonQuery
|
||||||
|
if let range = rawString.range(of: "{}") {
|
||||||
|
if range.lowerBound != rawString.startIndex {
|
||||||
|
string.append(NSAttributedString(string: String(rawString[rawString.startIndex ..< range.lowerBound]), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
|
||||||
|
}
|
||||||
|
string.append(NSAttributedString(string: component.query.trimmingCharacters(in: .whitespacesAndNewlines), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor.withMultipliedAlpha(0.7)))
|
||||||
|
if range.upperBound != rawString.endIndex {
|
||||||
|
string.append(NSAttributedString(string: String(rawString[range.upperBound...]), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
string.append(NSAttributedString(string: rawString, font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
|
||||||
|
}
|
||||||
|
|
||||||
let textSize = self.text.update(
|
let textSize = self.text.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
@ -6338,14 +6334,13 @@ private final class EmptyResultsButtonPaidSearchContent: Component {
|
|||||||
self.component = component
|
self.component = component
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
let attributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: "Search for * \(component.price)", font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
|
let attributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: component.strings.ChatList_GlobalSearch_SearchButtonPaidTitle("\(component.price)").string, font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
|
||||||
if let range = attributedString.string.range(of: "*"), let starImage = self.cachedStarImage {
|
if let range = attributedString.string.range(of: "*"), let starImage = self.cachedStarImage {
|
||||||
attributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: attributedString.string))
|
attributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: attributedString.string))
|
||||||
attributedString.addAttribute(.foregroundColor, value: component.theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: attributedString.string))
|
attributedString.addAttribute(.foregroundColor, value: component.theme.list.itemCheckColors.foregroundColor, 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))
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(MultilineTextComponent(
|
component: AnyComponent(MultilineTextComponent(
|
||||||
@ -6359,7 +6354,7 @@ private final class EmptyResultsButtonPaidSearchContent: Component {
|
|||||||
if let unlockTimestamp = component.unlockTimestamp {
|
if let unlockTimestamp = component.unlockTimestamp {
|
||||||
var remainingTime: Int32 = unlockTimestamp - Int32(Date().timeIntervalSince1970)
|
var remainingTime: Int32 = unlockTimestamp - Int32(Date().timeIntervalSince1970)
|
||||||
remainingTime = max(0, remainingTime)
|
remainingTime = max(0, remainingTime)
|
||||||
subtitleText = "free search unlocks in \(stringForRemainingTime(remainingTime))"
|
subtitleText = component.strings.ChatList_GlobalSearch_SearchButtonPaidSubtitle(stringForRemainingTime(remainingTime)).string
|
||||||
|
|
||||||
if self.timer == nil {
|
if self.timer == nil {
|
||||||
self.timer = Foundation.Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { [weak self] _ in
|
self.timer = Foundation.Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { [weak self] _ in
|
||||||
@ -6484,7 +6479,7 @@ private final class EmptyResultsButton: Component {
|
|||||||
isEnabled = false
|
isEnabled = false
|
||||||
buttonContent = AnyComponentWithIdentity(id: "empty", component: AnyComponent(MultilineTextComponent(
|
buttonContent = AnyComponentWithIdentity(id: "empty", component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: "Search",
|
string: component.strings.ChatList_GlobalSearch_SearchButton,
|
||||||
font: Font.medium(17.0),
|
font: Font.medium(17.0),
|
||||||
textColor: component.theme.list.itemCheckColors.foregroundColor
|
textColor: component.theme.list.itemCheckColors.foregroundColor
|
||||||
))
|
))
|
||||||
@ -6492,7 +6487,7 @@ private final class EmptyResultsButton: Component {
|
|||||||
case .premiumRequired:
|
case .premiumRequired:
|
||||||
buttonContent = AnyComponentWithIdentity(id: "premium", component: AnyComponent(MultilineTextComponent(
|
buttonContent = AnyComponentWithIdentity(id: "premium", component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: "Subscribe to Premium",
|
string: component.strings.ChatList_GlobalSearch_SearchButtonPremium,
|
||||||
font: Font.medium(17.0),
|
font: Font.medium(17.0),
|
||||||
textColor: component.theme.list.itemCheckColors.foregroundColor
|
textColor: component.theme.list.itemCheckColors.foregroundColor
|
||||||
))
|
))
|
||||||
|
@ -362,7 +362,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
|||||||
)
|
)
|
||||||
strongSelf.updateCurrentCall(call)
|
strongSelf.updateCurrentCall(call)
|
||||||
}))
|
}))
|
||||||
} else if let currentCall = self.currentCall, currentCall.peerId == firstState.1.id, currentCall.peerId.id._internalGetInt64Value() < firstState.0.account.peerId.id._internalGetInt64Value() {
|
} else if !"".isEmpty, let currentCall = self.currentCall, currentCall.peerId == firstState.1.id, currentCall.peerId.id._internalGetInt64Value() < firstState.0.account.peerId.id._internalGetInt64Value() {
|
||||||
let _ = currentCall.hangUp().startStandalone()
|
let _ = currentCall.hangUp().startStandalone()
|
||||||
|
|
||||||
self.currentCallDisposable.set((combineLatest(
|
self.currentCallDisposable.set((combineLatest(
|
||||||
|
@ -837,7 +837,6 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
if arguments.areStarReactionsEnabled && !hadStars && !mappedReactions.isEmpty {
|
if arguments.areStarReactionsEnabled && !hadStars && !mappedReactions.isEmpty {
|
||||||
var centerAnimation: TelegramMediaFile?
|
var centerAnimation: TelegramMediaFile?
|
||||||
let animationFileId: Int64? = nil
|
let animationFileId: Int64? = nil
|
||||||
|
@ -478,6 +478,8 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
|||||||
actionTitle = item.presentationData.strings.Chat_ViewGroupCall
|
actionTitle = item.presentationData.strings.Chat_ViewGroupCall
|
||||||
case "telegram_collection":
|
case "telegram_collection":
|
||||||
actionTitle = item.presentationData.strings.Chat_ViewCollection
|
actionTitle = item.presentationData.strings.Chat_ViewCollection
|
||||||
|
case "telegram_story_album":
|
||||||
|
actionTitle = item.presentationData.strings.Chat_ViewAlbum
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,6 @@ public final class PeerInfoRatingComponent: Component {
|
|||||||
|
|
||||||
let iconSize = CGSize(width: 26.0, height: 26.0)
|
let iconSize = CGSize(width: 26.0, height: 26.0)
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
if previousComponent?.level != level || previousComponent?.borderColor != component.borderColor || previousComponent?.foregroundColor != component.foregroundColor || previousComponent?.backgroundColor != component.backgroundColor || "".isEmpty {
|
if previousComponent?.level != level || previousComponent?.borderColor != component.borderColor || previousComponent?.foregroundColor != component.foregroundColor || previousComponent?.backgroundColor != component.backgroundColor || "".isEmpty {
|
||||||
let attributedText = NSAttributedString(string: "\(level)", attributes: [
|
let attributedText = NSAttributedString(string: "\(level)", attributes: [
|
||||||
NSAttributedString.Key.font: Font.semibold(10.0),
|
NSAttributedString.Key.font: Font.semibold(10.0),
|
||||||
@ -219,8 +218,9 @@ public final class PeerInfoRatingComponent: Component {
|
|||||||
|
|
||||||
var textFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textLayout.size.width) * 0.5), y: floorToScreenPixels((size.height - textLayout.size.height) * 0.5)), size: textLayout.size)
|
var textFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textLayout.size.width) * 0.5), y: floorToScreenPixels((size.height - textLayout.size.height) * 0.5)), size: textLayout.size)
|
||||||
if level == 1 {
|
if level == 1 {
|
||||||
} else {
|
|
||||||
textFrame.origin.x += UIScreenPixel
|
textFrame.origin.x += UIScreenPixel
|
||||||
|
} else {
|
||||||
|
textFrame.origin.x += 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
context.saveGState()
|
context.saveGState()
|
||||||
|
@ -1959,7 +1959,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
self.currentPendingStarRating = cachedData.pendingStarRating
|
self.currentPendingStarRating = cachedData.pendingStarRating
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
self.currentPendingStarRating = TelegramStarPendingRating(rating: TelegramStarRating(level: starRating.level, currentLevelStars: starRating.currentLevelStars, stars: starRating.stars + 123, nextLevelStars: starRating.nextLevelStars), timestamp: 0)
|
self.currentPendingStarRating = TelegramStarPendingRating(rating: TelegramStarRating(level: starRating.level, currentLevelStars: starRating.currentLevelStars, stars: starRating.stars + 123, nextLevelStars: starRating.nextLevelStars), timestamp: Int32(Date().timeIntervalSince1970) + 60 * 60 * 24 * 3)
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
self.currentStarRating = nil
|
self.currentStarRating = nil
|
||||||
@ -1978,7 +1978,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
self.subtitleRating = subtitleRating
|
self.subtitleRating = subtitleRating
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
subtitleRatingSize = subtitleRating.update(
|
subtitleRatingSize = subtitleRating.update(
|
||||||
transition: subtitleRatingTransition,
|
transition: subtitleRatingTransition,
|
||||||
component: AnyComponent(PeerInfoRatingComponent(
|
component: AnyComponent(PeerInfoRatingComponent(
|
||||||
|
@ -11711,12 +11711,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
|
|
||||||
let strings = self.presentationData.strings
|
let strings = self.presentationData.strings
|
||||||
let _ = strings
|
|
||||||
|
|
||||||
var ignoreNextActions = false
|
var ignoreNextActions = false
|
||||||
|
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_MenuAddStories, icon: { theme in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Add Stories", icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak self] _, a in
|
}, action: { [weak self] _, a in
|
||||||
if ignoreNextActions {
|
if ignoreNextActions {
|
||||||
@ -11731,7 +11729,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
})))
|
})))
|
||||||
|
|
||||||
if let _ = pane.currentStoryFolder {
|
if let _ = pane.currentStoryFolder {
|
||||||
items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuShare, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak pane] _, a in
|
}, action: { [weak pane] _, a in
|
||||||
if ignoreNextActions {
|
if ignoreNextActions {
|
||||||
@ -11765,7 +11763,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
if let folder = pane.currentStoryFolder {
|
if let folder = pane.currentStoryFolder {
|
||||||
let _ = folder
|
let _ = folder
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: "Delete Album", textColor: .destructive, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: strings.Stories_MenuDeleteAlbum, textColor: .destructive, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||||
}, action: { [weak pane] _, a in
|
}, action: { [weak pane] _, a in
|
||||||
if ignoreNextActions {
|
if ignoreNextActions {
|
||||||
|
@ -353,14 +353,11 @@ final class PeerInfoStoryGridScreenComponent: Component {
|
|||||||
let buttonText: String
|
let buttonText: String
|
||||||
var buttonIsEnabled = true
|
var buttonIsEnabled = true
|
||||||
if component.selectionModeCompletion != nil {
|
if component.selectionModeCompletion != nil {
|
||||||
//TODO:localize
|
|
||||||
if self.selectedCount == 0 {
|
if self.selectedCount == 0 {
|
||||||
buttonText = "Add Stories"
|
buttonText = environment.strings.Stories_AddStoriesEmpty
|
||||||
buttonIsEnabled = false
|
buttonIsEnabled = false
|
||||||
} else if self.selectedCount == 1 {
|
|
||||||
buttonText = "Add 1 Story"
|
|
||||||
} else {
|
} else {
|
||||||
buttonText = "Add \(self.selectedCount) Stories"
|
buttonText = environment.strings.Stories_AddStories(Int32(self.selectedCount))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch component.scope {
|
switch component.scope {
|
||||||
@ -679,8 +676,7 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
|
|||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
if self.selectionModeCompletion != nil {
|
if self.selectionModeCompletion != nil {
|
||||||
//TODO:localize
|
self.titleView?.titleContent = .custom(presentationData.strings.Stories_AddStoriesTitle, nil, false)
|
||||||
self.titleView?.titleContent = .custom("Add Stories", nil, false)
|
|
||||||
} else {
|
} else {
|
||||||
switch self.scope {
|
switch self.scope {
|
||||||
case .saved:
|
case .saved:
|
||||||
|
@ -2507,8 +2507,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
|
|
||||||
if canManage, case let .peer(peerId, _, isArchived) = self.scope {
|
if canManage, case let .peer(peerId, _, isArchived) = self.scope {
|
||||||
if !isArchived && self.canManageStories && self.isProfileEmbedded {
|
if !isArchived && self.canManageStories && self.isProfileEmbedded {
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuAddToAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Add to Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
|
||||||
guard let self, let c else {
|
guard let self, let c else {
|
||||||
f(.default)
|
f(.default)
|
||||||
return
|
return
|
||||||
@ -2529,7 +2528,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
})))
|
})))
|
||||||
items.append(.separator)
|
items.append(.separator)
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: "New Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuNewAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
f(.default)
|
f(.default)
|
||||||
return
|
return
|
||||||
@ -2786,8 +2785,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
|
|
||||||
if canManage {
|
if canManage {
|
||||||
if let folder = self.currentStoryFolder {
|
if let folder = self.currentStoryFolder {
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuRemoveFromAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolderUp"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Remove from Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolderUp"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
f(.default)
|
f(.default)
|
||||||
return
|
return
|
||||||
@ -2924,8 +2922,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
if state.isLoading {
|
if state.isLoading {
|
||||||
title = self.presentationData.strings.BotPreviews_SubtitleLoading
|
title = self.presentationData.strings.BotPreviews_SubtitleLoading
|
||||||
} else {
|
} else {
|
||||||
//TODO:localize
|
title = self.presentationData.strings.Stories_StatusEmpty
|
||||||
title = "no stories"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if case let .peer(_, isSaved, isArchived) = self.scope {
|
} else if case let .peer(_, isSaved, isArchived) = self.scope {
|
||||||
@ -3849,10 +3846,9 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
mainTitle = self.presentationData.strings.BotPreviews_LanguageTab_Main
|
mainTitle = self.presentationData.strings.BotPreviews_LanguageTab_Main
|
||||||
addTitle = self.presentationData.strings.BotPreviews_LanguageTab_Add
|
addTitle = self.presentationData.strings.BotPreviews_LanguageTab_Add
|
||||||
} else {
|
} else {
|
||||||
//TODO:localize
|
mainTitle = self.presentationData.strings.Stories_AlbumAll
|
||||||
mainTitle = "All Stories"
|
|
||||||
if self.currentStoryFolders.count < self.maxStoryFolders {
|
if self.currentStoryFolders.count < self.maxStoryFolders {
|
||||||
addTitle = "+ Add Album"
|
addTitle = self.presentationData.strings.Stories_AlbumAdd
|
||||||
} else {
|
} else {
|
||||||
addTitle = nil
|
addTitle = nil
|
||||||
}
|
}
|
||||||
@ -3899,8 +3895,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
canAddStories = await self.canAddStoriesToFolder(folder: folder)
|
canAddStories = await self.canAddStoriesToFolder(folder: folder)
|
||||||
}
|
}
|
||||||
if canAddStories {
|
if canAddStories {
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_MenuAddStories, icon: { theme in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Add Stories", icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak self] _, a in
|
}, action: { [weak self] _, a in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -3915,8 +3910,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.canManageStories {
|
if self.canManageStories {
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuRenameAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Rename Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
c?.dismiss(completion: nil)
|
c?.dismiss(completion: nil)
|
||||||
return
|
return
|
||||||
@ -3930,8 +3924,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuShare, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
c?.dismiss(completion: nil)
|
c?.dismiss(completion: nil)
|
||||||
return
|
return
|
||||||
@ -3947,8 +3940,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.canManageStories {
|
if self.canManageStories {
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.BotPreviews_MenuReorder, icon: { theme in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Reorder", icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak self] _, a in
|
}, action: { [weak self] _, a in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -3961,8 +3953,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
self.beginReordering()
|
self.beginReordering()
|
||||||
})))
|
})))
|
||||||
|
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuDeleteAlbum, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, _ in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Delete Album", textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, _ in
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
c?.dismiss(completion: nil)
|
c?.dismiss(completion: nil)
|
||||||
return
|
return
|
||||||
@ -4477,12 +4468,11 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
self.actionPanel = actionPanel
|
self.actionPanel = actionPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let actionPanelSize = actionPanel.update(
|
let actionPanelSize = actionPanel.update(
|
||||||
transition: actionPanelTransition,
|
transition: actionPanelTransition,
|
||||||
component: AnyComponent(BottomButtonPanelComponent(
|
component: AnyComponent(BottomButtonPanelComponent(
|
||||||
theme: presentationData.theme,
|
theme: presentationData.theme,
|
||||||
title: "Add Stories",
|
title: presentationData.strings.Stories_AddStoriesEmpty,
|
||||||
label: nil,
|
label: nil,
|
||||||
icon: AnyComponentWithIdentity(id: 0, component: AnyComponent(BundleIconComponent(
|
icon: AnyComponentWithIdentity(id: 0, component: AnyComponent(BundleIconComponent(
|
||||||
name: "Item List/AddItemIcon",
|
name: "Item List/AddItemIcon",
|
||||||
@ -4534,7 +4524,6 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
self.emptyStateView = emptyStateView
|
self.emptyStateView = emptyStateView
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let emptyStateSize = emptyStateView.update(
|
let emptyStateSize = emptyStateView.update(
|
||||||
transition: emptyStateTransition,
|
transition: emptyStateTransition,
|
||||||
component: AnyComponent(EmptyStateIndicatorComponent(
|
component: AnyComponent(EmptyStateIndicatorComponent(
|
||||||
@ -4542,9 +4531,9 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
theme: presentationData.theme,
|
theme: presentationData.theme,
|
||||||
fitToHeight: self.isProfileEmbedded,
|
fitToHeight: self.isProfileEmbedded,
|
||||||
animationName: nil,
|
animationName: nil,
|
||||||
title: "Organize Your Stories",
|
title: presentationData.strings.Stories_AlbumEmptyTitle,
|
||||||
text: "Add some stories to this album.",
|
text: presentationData.strings.Stories_AlbumEmptyText,
|
||||||
actionTitle: "Add to Album",
|
actionTitle: presentationData.strings.Stories_AlbumEmptyButton,
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
guard let self, let currentStoryFolder = self.currentStoryFolder else {
|
guard let self, let currentStoryFolder = self.currentStoryFolder else {
|
||||||
return
|
return
|
||||||
@ -5007,15 +4996,14 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func presentAddStoryFolder(addItems: [EngineStoryItem] = []) {
|
private func presentAddStoryFolder(addItems: [EngineStoryItem] = []) {
|
||||||
//TODO:localize
|
|
||||||
let promptController = promptController(
|
let promptController = promptController(
|
||||||
sharedContext: self.context.sharedContext,
|
sharedContext: self.context.sharedContext,
|
||||||
updatedPresentationData: nil,
|
updatedPresentationData: nil,
|
||||||
text: "Create a New Album",
|
text: self.presentationData.strings.Stories_CreateAlbum_Title,
|
||||||
titleFont: .bold,
|
titleFont: .bold,
|
||||||
subtitle: "Choose a name for your album and start adding your stories there.",
|
subtitle: self.presentationData.strings.Stories_CreateAlbum_Text,
|
||||||
value: "",
|
value: "",
|
||||||
placeholder: "Title",
|
placeholder: self.presentationData.strings.Stories_CreateAlbum_Placeholder,
|
||||||
characterLimit: 20,
|
characterLimit: 20,
|
||||||
displayCharacterLimit: true,
|
displayCharacterLimit: true,
|
||||||
apply: { [weak self] value in
|
apply: { [weak self] value in
|
||||||
@ -5041,15 +5029,14 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func presentRenameStoryFolder(id: Int64, title: String) {
|
private func presentRenameStoryFolder(id: Int64, title: String) {
|
||||||
//TODO:localize
|
|
||||||
let promptController = promptController(
|
let promptController = promptController(
|
||||||
sharedContext: self.context.sharedContext,
|
sharedContext: self.context.sharedContext,
|
||||||
updatedPresentationData: nil,
|
updatedPresentationData: nil,
|
||||||
text: "Edit Album Name",
|
text: self.presentationData.strings.Stories_EditAlbum_Title,
|
||||||
titleFont: .bold,
|
titleFont: .bold,
|
||||||
subtitle: "Choose a new name for your album.",
|
subtitle: self.presentationData.strings.Stories_EditAlbum_Text,
|
||||||
value: title,
|
value: title,
|
||||||
placeholder: "Title",
|
placeholder: self.presentationData.strings.Stories_CreateAlbum_Placeholder,
|
||||||
characterLimit: 20,
|
characterLimit: 20,
|
||||||
displayCharacterLimit: true,
|
displayCharacterLimit: true,
|
||||||
apply: { [weak self] value in
|
apply: { [weak self] value in
|
||||||
@ -5133,13 +5120,12 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
|||||||
controller?.dismissAnimated()
|
controller?.dismissAnimated()
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
let title: String = presentationData.strings.Stories_DeleteAlbum_Confirmation(folder.title).string
|
||||||
let title: String = "Delete \(folder.title)?"
|
|
||||||
|
|
||||||
controller.setItemGroups([
|
controller.setItemGroups([
|
||||||
ActionSheetItemGroup(items: [
|
ActionSheetItemGroup(items: [
|
||||||
ActionSheetTextItem(title: title),
|
ActionSheetTextItem(title: title),
|
||||||
ActionSheetButtonItem(title: "Delete", color: .destructive, action: { [weak self] in
|
ActionSheetButtonItem(title: presentationData.strings.Common_Delete, color: .destructive, action: { [weak self] in
|
||||||
dismissAction()
|
dismissAction()
|
||||||
|
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
@ -42,6 +42,14 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class TransitionHint {
|
||||||
|
let isChangingPreview: Bool
|
||||||
|
|
||||||
|
init(isChangingPreview: Bool) {
|
||||||
|
self.isChangingPreview = isChangingPreview
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final class ScrollView: UIScrollView {
|
private final class ScrollView: UIScrollView {
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
return super.hitTest(point, with: event)
|
return super.hitTest(point, with: event)
|
||||||
@ -98,10 +106,12 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
private var environment: ViewControllerComponentContainer.Environment?
|
private var environment: ViewControllerComponentContainer.Environment?
|
||||||
private var isUpdating: Bool = false
|
private var isUpdating: Bool = false
|
||||||
|
private var isPreviewingPendingRating: Bool = false
|
||||||
|
|
||||||
private var itemLayout: ItemLayout?
|
private var itemLayout: ItemLayout?
|
||||||
private var topOffsetDistance: CGFloat?
|
private var topOffsetDistance: CGFloat?
|
||||||
|
|
||||||
|
private var cachedChevronImage: UIImage?
|
||||||
private var cachedCloseImage: UIImage?
|
private var cachedCloseImage: UIImage?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
@ -219,7 +229,7 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
|
|
||||||
transition.setPosition(view: self.navigationBarContainer, position: CGPoint(x: 0.0, y: topOffset + itemLayout.containerInset))
|
transition.setPosition(view: self.navigationBarContainer, position: CGPoint(x: 0.0, y: topOffset + itemLayout.containerInset))
|
||||||
|
|
||||||
let topOffsetDistance: CGFloat = min(200.0, floor(itemLayout.containerSize.height * 0.25))
|
let topOffsetDistance: CGFloat = 80.0
|
||||||
self.topOffsetDistance = topOffsetDistance
|
self.topOffsetDistance = topOffsetDistance
|
||||||
var topOffsetFraction = topOffset / topOffsetDistance
|
var topOffsetFraction = topOffset / topOffsetDistance
|
||||||
topOffsetFraction = max(0.0, min(1.0, topOffsetFraction))
|
topOffsetFraction = max(0.0, min(1.0, topOffsetFraction))
|
||||||
@ -273,6 +283,8 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
self.isUpdating = false
|
self.isUpdating = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let alphaTransition: ComponentTransition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.16)
|
||||||
|
|
||||||
let environment = environment[ViewControllerComponentContainer.Environment.self].value
|
let environment = environment[ViewControllerComponentContainer.Environment.self].value
|
||||||
let themeUpdated = self.environment?.theme !== environment.theme
|
let themeUpdated = self.environment?.theme !== environment.theme
|
||||||
|
|
||||||
@ -330,21 +342,31 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
|
|
||||||
let clippingY: CGFloat
|
let clippingY: CGFloat
|
||||||
|
|
||||||
//TODO:localize
|
let titleString: String = environment.strings.ProfileLevelInfo_Title
|
||||||
let titleString: String = "Rating"
|
|
||||||
let descriptionTextString: String
|
let descriptionTextString: String
|
||||||
var secondaryDescriptionTextString: String?
|
var secondaryDescriptionTextString: String?
|
||||||
if component.peer.id == component.context.account.peerId {
|
if component.peer.id == component.context.account.peerId {
|
||||||
descriptionTextString = "The rating reflects your activity on Telegram. What affects it:"
|
descriptionTextString = environment.strings.ProfileLevelInfo_MyText
|
||||||
|
|
||||||
if let pendingStarRating = component.pendingStarRating {
|
let timestamp = Int32(Date().timeIntervalSince1970)
|
||||||
|
if let pendingStarRating = component.pendingStarRating, pendingStarRating.timestamp > timestamp {
|
||||||
if pendingStarRating.rating.stars > component.starRating.stars {
|
if pendingStarRating.rating.stars > component.starRating.stars {
|
||||||
let pendingPoints = pendingStarRating.rating.stars - component.starRating.stars
|
let pendingPoints = pendingStarRating.rating.stars - component.starRating.stars
|
||||||
secondaryDescriptionTextString = "The rating updates in 21 days after purchases.\n\(pendingPoints) points are pending."
|
|
||||||
|
if self.isPreviewingPendingRating {
|
||||||
|
secondaryDescriptionTextString = "This will be your rating in 21 days,\n after \(pendingPoints) points are added. [Back >]()"
|
||||||
|
} else {
|
||||||
|
let dayCount = (pendingStarRating.timestamp - timestamp) / (24 * 60 * 60)
|
||||||
|
if dayCount == 0 {
|
||||||
|
secondaryDescriptionTextString = environment.strings.ProfileLevelInfo_MyDescriptionToday(Int32(pendingPoints))
|
||||||
|
} else {
|
||||||
|
secondaryDescriptionTextString = environment.strings.ProfileLevelInfo_MyDescription(environment.strings.ProfileLevelInfo_MyDescriptionDays(Int32(dayCount)), environment.strings.ProfileLevelInfo_MyDescriptionPoints(Int32(pendingPoints))).string
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
descriptionTextString = "The rating reflects **\(component.peer.compactDisplayTitle)'s** activity on Telegram. What affects it:"
|
descriptionTextString = environment.strings.ProfileLevelInfo_OtherDescription(component.peer.compactDisplayTitle).string
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
@ -378,16 +400,36 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
]
|
]
|
||||||
|
|
||||||
let levelFraction: CGFloat
|
let levelFraction: CGFloat
|
||||||
if let nextLevelStars = component.starRating.nextLevelStars {
|
|
||||||
levelFraction = Double(component.starRating.stars) / Double(nextLevelStars)
|
|
||||||
} else {
|
|
||||||
levelFraction = 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
let badgeText = starCountString(Int64(component.starRating.stars), decimalSeparator: ".")
|
let badgeText: String
|
||||||
var badgeTextSuffix: String?
|
var badgeTextSuffix: String?
|
||||||
if let nextLevelStars = component.starRating.nextLevelStars {
|
let currentLevel: Int32
|
||||||
badgeTextSuffix = " / \(starCountString(Int64(nextLevelStars), decimalSeparator: "."))"
|
let nextLevel: Int32?
|
||||||
|
|
||||||
|
if let pendingStarRating = component.pendingStarRating, pendingStarRating.rating.stars > component.starRating.stars, self.isPreviewingPendingRating {
|
||||||
|
badgeText = starCountString(Int64(pendingStarRating.rating.stars), decimalSeparator: ".")
|
||||||
|
currentLevel = pendingStarRating.rating.level
|
||||||
|
nextLevel = pendingStarRating.rating.nextLevelStars == nil ? nil : currentLevel + 1
|
||||||
|
if let nextLevelStars = pendingStarRating.rating.nextLevelStars {
|
||||||
|
badgeTextSuffix = " / \(starCountString(Int64(nextLevelStars), decimalSeparator: "."))"
|
||||||
|
}
|
||||||
|
if let nextLevelStars = pendingStarRating.rating.nextLevelStars {
|
||||||
|
levelFraction = Double(pendingStarRating.rating.stars) / Double(nextLevelStars)
|
||||||
|
} else {
|
||||||
|
levelFraction = 1.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
badgeText = starCountString(Int64(component.starRating.stars), decimalSeparator: ".")
|
||||||
|
currentLevel = component.starRating.level
|
||||||
|
nextLevel = component.starRating.nextLevelStars == nil ? nil : currentLevel + 1
|
||||||
|
if let nextLevelStars = component.starRating.nextLevelStars {
|
||||||
|
badgeTextSuffix = " / \(starCountString(Int64(nextLevelStars), decimalSeparator: "."))"
|
||||||
|
}
|
||||||
|
if let nextLevelStars = component.starRating.nextLevelStars {
|
||||||
|
levelFraction = Double(component.starRating.stars) / Double(nextLevelStars)
|
||||||
|
} else {
|
||||||
|
levelFraction = 1.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let levelInfoSize = self.levelInfo.update(
|
let levelInfoSize = self.levelInfo.update(
|
||||||
@ -395,11 +437,11 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
component: AnyComponent(PremiumLimitDisplayComponent(
|
component: AnyComponent(PremiumLimitDisplayComponent(
|
||||||
inactiveColor: environment.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5),
|
inactiveColor: environment.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5),
|
||||||
activeColors: gradientColors,
|
activeColors: gradientColors,
|
||||||
inactiveTitle: "Level \(component.starRating.level)",
|
inactiveTitle: environment.strings.ProfileLevelInfo_LevelIndex(Int32(currentLevel)),
|
||||||
inactiveValue: "",
|
inactiveValue: "",
|
||||||
inactiveTitleColor: environment.theme.list.itemPrimaryTextColor,
|
inactiveTitleColor: environment.theme.list.itemPrimaryTextColor,
|
||||||
activeTitle: "",
|
activeTitle: "",
|
||||||
activeValue: component.starRating.nextLevelStars == nil ? "" : "Level \(component.starRating.level + 1)",
|
activeValue: nextLevel.flatMap { environment.strings.ProfileLevelInfo_LevelIndex(Int32($0)) } ?? "",
|
||||||
activeTitleColor: .white,
|
activeTitleColor: .white,
|
||||||
badgeIconName: "Peer Info/ProfileLevelProgressIcon",
|
badgeIconName: "Peer Info/ProfileLevelProgressIcon",
|
||||||
badgeText: badgeText,
|
badgeText: badgeText,
|
||||||
@ -421,32 +463,72 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
|
|
||||||
contentHeight += 129.0
|
contentHeight += 129.0
|
||||||
|
|
||||||
|
let isChangingPreview = transition.userData(TransitionHint.self)?.isChangingPreview ?? false
|
||||||
|
|
||||||
if let secondaryDescriptionTextString {
|
if let secondaryDescriptionTextString {
|
||||||
|
if isChangingPreview, let secondaryDescriptionTextView = self.secondaryDescriptionText?.view {
|
||||||
|
self.secondaryDescriptionText = nil
|
||||||
|
transition.setTransform(view: secondaryDescriptionTextView, transform: CATransform3DMakeScale(0.9, 0.9, 1.0))
|
||||||
|
alphaTransition.setAlpha(view: secondaryDescriptionTextView, alpha: 0.0, completion: { [weak secondaryDescriptionTextView] _ in
|
||||||
|
secondaryDescriptionTextView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
contentHeight -= 8.0
|
contentHeight -= 8.0
|
||||||
let secondaryDescriptionText: ComponentView<Empty>
|
let secondaryDescriptionText: ComponentView<Empty>
|
||||||
|
var secondaryDescriptionTextTransition = transition
|
||||||
if let current = self.secondaryDescriptionText {
|
if let current = self.secondaryDescriptionText {
|
||||||
secondaryDescriptionText = current
|
secondaryDescriptionText = current
|
||||||
} else {
|
} else {
|
||||||
|
secondaryDescriptionTextTransition = .immediate
|
||||||
secondaryDescriptionText = ComponentView()
|
secondaryDescriptionText = ComponentView()
|
||||||
self.secondaryDescriptionText = secondaryDescriptionText
|
self.secondaryDescriptionText = secondaryDescriptionText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let secondaryDescriptionAttributedString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(secondaryDescriptionTextString, attributes: MarkdownAttributes(
|
||||||
|
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
|
||||||
|
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
|
||||||
|
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemAccentColor),
|
||||||
|
linkAttribute: { url in
|
||||||
|
return ("URL", url)
|
||||||
|
}
|
||||||
|
)))
|
||||||
|
|
||||||
|
let chevronImage: UIImage?
|
||||||
|
if let current = self.cachedChevronImage {
|
||||||
|
chevronImage = current
|
||||||
|
} else {
|
||||||
|
chevronImage = generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: .white)
|
||||||
|
self.cachedChevronImage = chevronImage
|
||||||
|
}
|
||||||
|
if let range = secondaryDescriptionAttributedString.string.range(of: ">"), let chevronImage {
|
||||||
|
secondaryDescriptionAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: secondaryDescriptionAttributedString.string))
|
||||||
|
}
|
||||||
|
|
||||||
let secondaryDescriptionTextSize = secondaryDescriptionText.update(
|
let secondaryDescriptionTextSize = secondaryDescriptionText.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(BalancedTextComponent(
|
component: AnyComponent(BalancedTextComponent(
|
||||||
text: .markdown(
|
text: .plain(secondaryDescriptionAttributedString),
|
||||||
text: secondaryDescriptionTextString,
|
|
||||||
attributes: MarkdownAttributes(
|
|
||||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
|
|
||||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
|
|
||||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemAccentColor),
|
|
||||||
linkAttribute: { url in
|
|
||||||
return ("URL", url)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
),
|
|
||||||
horizontalAlignment: .center,
|
horizontalAlignment: .center,
|
||||||
maximumNumberOfLines: 0,
|
maximumNumberOfLines: 0,
|
||||||
lineSpacing: 0.2
|
lineSpacing: 0.2,
|
||||||
|
highlightColor: environment.theme.list.itemAccentColor.withMultipliedAlpha(0.1),
|
||||||
|
highlightAction: { attributes in
|
||||||
|
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
||||||
|
return NSAttributedString.Key(rawValue: "URL")
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tapAction: { [weak self] attributes, _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isPreviewingPendingRating = !self.isPreviewingPendingRating
|
||||||
|
var transition: ComponentTransition = .spring(duration: 0.4)
|
||||||
|
transition = transition.withUserData(TransitionHint(isChangingPreview: true))
|
||||||
|
self.state?.updated(transition: transition)
|
||||||
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||||
@ -455,8 +537,12 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
if let secondaryDescriptionTextView = secondaryDescriptionText.view {
|
if let secondaryDescriptionTextView = secondaryDescriptionText.view {
|
||||||
if secondaryDescriptionTextView.superview == nil {
|
if secondaryDescriptionTextView.superview == nil {
|
||||||
self.scrollContentView.addSubview(secondaryDescriptionTextView)
|
self.scrollContentView.addSubview(secondaryDescriptionTextView)
|
||||||
|
if isChangingPreview {
|
||||||
|
transition.animateScale(view: secondaryDescriptionTextView, from: 0.9, to: 1.0)
|
||||||
|
alphaTransition.animateAlpha(view: secondaryDescriptionTextView, from: 0.0, to: 1.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
transition.setPosition(view: secondaryDescriptionTextView, position: secondaryDescriptionTextFrame.center)
|
secondaryDescriptionTextTransition.setPosition(view: secondaryDescriptionTextView, position: secondaryDescriptionTextFrame.center)
|
||||||
secondaryDescriptionTextView.bounds = CGRect(origin: CGPoint(), size: secondaryDescriptionTextFrame.size)
|
secondaryDescriptionTextView.bounds = CGRect(origin: CGPoint(), size: secondaryDescriptionTextFrame.size)
|
||||||
}
|
}
|
||||||
contentHeight += secondaryDescriptionTextSize.height
|
contentHeight += secondaryDescriptionTextSize.height
|
||||||
@ -572,8 +658,7 @@ private final class ProfileLevelInfoScreenComponent: Component {
|
|||||||
|
|
||||||
contentHeight += 31.0
|
contentHeight += 31.0
|
||||||
|
|
||||||
//TODO:localize
|
let actionButtonTitle: String = environment.strings.ProfileLevelInfo_CloseButton
|
||||||
let actionButtonTitle: String = "Understood"
|
|
||||||
|
|
||||||
var buttonTitle: [AnyComponentWithIdentity<Empty>] = []
|
var buttonTitle: [AnyComponentWithIdentity<Empty>] = []
|
||||||
let playButtonAnimation = ActionSlot<Void>()
|
let playButtonAnimation = ActionSlot<Void>()
|
||||||
|
@ -991,15 +991,14 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
|
|
||||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let promptController = promptController(
|
let promptController = promptController(
|
||||||
sharedContext: component.context.sharedContext,
|
sharedContext: component.context.sharedContext,
|
||||||
updatedPresentationData: (initial: presentationData, signal: .single(presentationData)),
|
updatedPresentationData: (initial: presentationData, signal: .single(presentationData)),
|
||||||
text: "Create a New Album",
|
text: presentationData.strings.Stories_CreateAlbum_Title,
|
||||||
titleFont: .bold,
|
titleFont: .bold,
|
||||||
subtitle: "Choose a name for your album and start adding your stories there.",
|
subtitle: presentationData.strings.Stories_CreateAlbum_Text,
|
||||||
value: "",
|
value: "",
|
||||||
placeholder: "Title",
|
placeholder: presentationData.strings.Stories_CreateAlbum_Placeholder,
|
||||||
characterLimit: 20,
|
characterLimit: 20,
|
||||||
apply: { [weak self] value in
|
apply: { [weak self] value in
|
||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
@ -1834,7 +1833,8 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
sectionOffset += footerSize.height
|
sectionOffset += footerSize.height
|
||||||
} else if section.id == 4 && section.itemCount > 0 {
|
} else if section.id == 4 && section.itemCount > 0 {
|
||||||
var sectionItemOffset: CGFloat = 0.0
|
var sectionItemOffset: CGFloat = 0.0
|
||||||
if self.selectedOptions.contains(.pin) {
|
//TODO:release
|
||||||
|
if self.selectedOptions.contains(.pin) && !"".isEmpty {
|
||||||
let itemFrame = CGRect(origin: CGPoint(x: itemLayout.sideInset, y: sectionOffset + section.insets.top + sectionItemOffset), size: CGSize(width: itemLayout.containerSize.width, height: section.itemHeight))
|
let itemFrame = CGRect(origin: CGPoint(x: itemLayout.sideInset, y: sectionOffset + section.insets.top + sectionItemOffset), size: CGSize(width: itemLayout.containerSize.width, height: section.itemHeight))
|
||||||
if !visibleBounds.intersects(itemFrame) {
|
if !visibleBounds.intersects(itemFrame) {
|
||||||
continue
|
continue
|
||||||
@ -1855,17 +1855,15 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
self.visibleItems[itemId] = visibleItem
|
self.visibleItems[itemId] = visibleItem
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
var foldersText = environment.strings.Stories_Post_AlbumAll
|
||||||
var foldersText = "All Stories"
|
|
||||||
if !self.shareToFolders.isEmpty {
|
if !self.shareToFolders.isEmpty {
|
||||||
if self.shareToFolders.count == 1 {
|
if self.shareToFolders.count == 1 {
|
||||||
foldersText = self.shareToFolders[0].title
|
foldersText = self.shareToFolders[0].title
|
||||||
} else {
|
} else {
|
||||||
foldersText = "\(self.shareToFolders.count) Albums"
|
foldersText = environment.strings.Stories_Post_AlbumCount(Int32(self.shareToFolders.count))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let _ = visibleItem.update(
|
let _ = visibleItem.update(
|
||||||
transition: itemTransition,
|
transition: itemTransition,
|
||||||
component: AnyComponent(ListActionItemComponent(
|
component: AnyComponent(ListActionItemComponent(
|
||||||
@ -1874,7 +1872,7 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
title: AnyComponent(VStack([
|
title: AnyComponent(VStack([
|
||||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: "Album",
|
string: environment.strings.Stories_Post_Album,
|
||||||
font: Font.regular(17.0),
|
font: Font.regular(17.0),
|
||||||
textColor: environment.theme.list.itemPrimaryTextColor
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
)),
|
)),
|
||||||
@ -1977,7 +1975,7 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
footerText = isSendAsGroup ? environment.strings.Story_Privacy_ChooseCoverGroupInfo : environment.strings.Story_Privacy_ChooseCoverChannelInfo
|
footerText = isSendAsGroup ? environment.strings.Story_Privacy_ChooseCoverGroupInfo : environment.strings.Story_Privacy_ChooseCoverChannelInfo
|
||||||
}
|
}
|
||||||
if component.coverItem == nil {
|
if component.coverItem == nil {
|
||||||
footerText = "Choose the albums where you want to share your story."
|
footerText = environment.strings.Stories_Post_AlbumFooter
|
||||||
}
|
}
|
||||||
|
|
||||||
let footerSize = sectionFooter.update(
|
let footerSize = sectionFooter.update(
|
||||||
@ -2731,15 +2729,18 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
if hasCover {
|
if hasCover {
|
||||||
itemCount += 1
|
itemCount += 1
|
||||||
}
|
}
|
||||||
if self.selectedOptions.contains(.pin) {
|
//TODO:release
|
||||||
|
/*if self.selectedOptions.contains(.pin) {
|
||||||
itemCount += 1
|
itemCount += 1
|
||||||
|
}*/
|
||||||
|
if itemCount != 0 {
|
||||||
|
sections.append(ItemLayout.Section(
|
||||||
|
id: 4,
|
||||||
|
insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 0.0, right: 0.0),
|
||||||
|
itemHeight: optionItemSize.height,
|
||||||
|
itemCount: itemCount
|
||||||
|
))
|
||||||
}
|
}
|
||||||
sections.append(ItemLayout.Section(
|
|
||||||
id: 4,
|
|
||||||
insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 0.0, right: 0.0),
|
|
||||||
itemHeight: optionItemSize.height,
|
|
||||||
itemCount: 1
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sections.append(ItemLayout.Section(
|
sections.append(ItemLayout.Section(
|
||||||
|
@ -6109,8 +6109,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
|
|
||||||
//TODO:localize
|
items.append(.action(ContextMenuActionItem(text: component.strings.Stories_MenuAddToAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||||
items.append(.action(ContextMenuActionItem(text: "Add to Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
|
||||||
guard let self, let c else {
|
guard let self, let c else {
|
||||||
f(.default)
|
f(.default)
|
||||||
return
|
return
|
||||||
@ -6131,7 +6130,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
})))
|
})))
|
||||||
items.append(.separator)
|
items.append(.separator)
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: "New Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
|
items.append(.action(ContextMenuActionItem(text: component.strings.Stories_MenuNewAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
f(.default)
|
f(.default)
|
||||||
return
|
return
|
||||||
@ -7142,11 +7141,11 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
let promptController = promptController(
|
let promptController = promptController(
|
||||||
sharedContext: component.context.sharedContext,
|
sharedContext: component.context.sharedContext,
|
||||||
updatedPresentationData: (initial: presentationData, signal: .single(presentationData)),
|
updatedPresentationData: (initial: presentationData, signal: .single(presentationData)),
|
||||||
text: "Create a New Album",
|
text: presentationData.strings.Stories_CreateAlbum_Title,
|
||||||
titleFont: .bold,
|
titleFont: .bold,
|
||||||
subtitle: "Choose a name for your album and start adding your stories there.",
|
subtitle: presentationData.strings.Stories_CreateAlbum_Text,
|
||||||
value: "",
|
value: "",
|
||||||
placeholder: "Title",
|
placeholder: presentationData.strings.Stories_CreateAlbum_Placeholder,
|
||||||
characterLimit: 20,
|
characterLimit: 20,
|
||||||
apply: { [weak self] value in
|
apply: { [weak self] value in
|
||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
|
@ -787,8 +787,7 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
}
|
}
|
||||||
} else if case .peer = currentCallType {
|
} else if case .peer = currentCallType {
|
||||||
let text: String
|
let text: String
|
||||||
//TODO:localize
|
text = presentationData.strings.Call_AlertMoveToConference
|
||||||
text = "End current call and start a conference?";
|
|
||||||
strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_CallInProgressTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_CallInProgressTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user