Various improvements

This commit is contained in:
Ilya Laktyushin 2024-10-05 01:05:29 +04:00
parent 119d22a1a5
commit 62517683ad
8 changed files with 66 additions and 24 deletions

View File

@ -13049,6 +13049,7 @@ Sorry for the inconvenience.";
"Report.Title.User" = "Report User"; "Report.Title.User" = "Report User";
"Report.Title.Group" = "Report Group"; "Report.Title.Group" = "Report Group";
"Report.Title.Channel" = "Report Channel"; "Report.Title.Channel" = "Report Channel";
"Report.Title.Bot" = "Report Bot";
"Report.Comment.Placeholder" = "Add Comment"; "Report.Comment.Placeholder" = "Add Comment";
"Report.Comment.Placeholder.Optional" = "Add Comment (Optional)"; "Report.Comment.Placeholder.Optional" = "Add Comment (Optional)";
"Report.Comment.Info" = "Please help us by telling what is wrong with the message you have selected."; "Report.Comment.Info" = "Please help us by telling what is wrong with the message you have selected.";
@ -13064,3 +13065,6 @@ Sorry for the inconvenience.";
"Notification.StarsGift.Stars_1" = "%@ Star"; "Notification.StarsGift.Stars_1" = "%@ Star";
"Notification.StarsGift.Stars_any" = "%@ Stars"; "Notification.StarsGift.Stars_any" = "%@ Stars";
"WebBrowser.AuthChallenge.Title" = "Sign in to %@";
"WebBrowser.AuthChallenge.Text" = "Your login information will be sent securely.";

View File

@ -399,7 +399,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
case topic(EnginePeer, ChatListItemContent.ThreadInfo, Int, PresentationTheme, PresentationStrings, ChatListSearchSectionExpandType) case topic(EnginePeer, ChatListItemContent.ThreadInfo, Int, PresentationTheme, PresentationStrings, ChatListSearchSectionExpandType)
case recentlySearchedPeer(EnginePeer, EnginePeer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, PeerStoryStats?, Bool) case recentlySearchedPeer(EnginePeer, EnginePeer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, PeerStoryStats?, Bool)
case localPeer(EnginePeer, EnginePeer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, PeerStoryStats?, Bool) case localPeer(EnginePeer, EnginePeer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, PeerStoryStats?, Bool)
case globalPeer(FoundPeer, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, PeerStoryStats?, Bool) case globalPeer(FoundPeer, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, PeerStoryStats?, Bool, String?)
case message(EngineMessage, EngineRenderedPeer, EnginePeerReadCounters?, EngineMessageHistoryThread.Info?, ChatListPresentationData, Int32, Bool?, Bool, MessageOrderingKey, (id: String, size: Int64, isFirstInList: Bool)?, MessageSection, Bool, PeerStoryStats?, Bool) case message(EngineMessage, EngineRenderedPeer, EnginePeerReadCounters?, EngineMessageHistoryThread.Info?, ChatListPresentationData, Int32, Bool?, Bool, MessageOrderingKey, (id: String, size: Int64, isFirstInList: Bool)?, MessageSection, Bool, PeerStoryStats?, Bool)
case addContact(String, PresentationTheme, PresentationStrings) case addContact(String, PresentationTheme, PresentationStrings)
@ -411,7 +411,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
return .localPeerId(peer.id) return .localPeerId(peer.id)
case let .localPeer(peer, _, _, _, _, _, _, _, _, _, _): case let .localPeer(peer, _, _, _, _, _, _, _, _, _, _):
return .localPeerId(peer.id) return .localPeerId(peer.id)
case let .globalPeer(peer, _, _, _, _, _, _, _, _, _): case let .globalPeer(peer, _, _, _, _, _, _, _, _, _, _):
return .globalPeerId(peer.peer.id) return .globalPeerId(peer.peer.id)
case let .message(message, _, _, _, _, _, _, _, _, _, section, _, _, _): case let .message(message, _, _, _, _, _, _, _, _, _, section, _, _, _):
return .messageId(message.id, section) return .messageId(message.id, section)
@ -440,8 +440,8 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
} else { } else {
return false return false
} }
case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder, lhsExpandType, lhsStoryStats, lhsRequiresPremiumForMessaging): case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder, lhsExpandType, lhsStoryStats, lhsRequiresPremiumForMessaging, lhsQuery):
if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder, rhsExpandType, rhsStoryStats, rhsRequiresPremiumForMessaging) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge?.0 == rhsUnreadBadge?.0 && lhsUnreadBadge?.1 == rhsUnreadBadge?.1 && lhsExpandType == rhsExpandType && lhsStoryStats == rhsStoryStats && lhsRequiresPremiumForMessaging == rhsRequiresPremiumForMessaging { if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder, rhsExpandType, rhsStoryStats, rhsRequiresPremiumForMessaging, rhsQuery) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge?.0 == rhsUnreadBadge?.0 && lhsUnreadBadge?.1 == rhsUnreadBadge?.1 && lhsExpandType == rhsExpandType && lhsStoryStats == rhsStoryStats && lhsRequiresPremiumForMessaging == rhsRequiresPremiumForMessaging, lhsQuery == rhsQuery {
return true return true
} else { } else {
return false return false
@ -543,11 +543,11 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
case .globalPeer, .message, .addContact: case .globalPeer, .message, .addContact:
return true return true
} }
case let .globalPeer(_, _, lhsIndex, _, _, _, _, _, _, _): case let .globalPeer(_, _, lhsIndex, _, _, _, _, _, _, _, _):
switch rhs { switch rhs {
case .topic, .recentlySearchedPeer, .localPeer: case .topic, .recentlySearchedPeer, .localPeer:
return false return false
case let .globalPeer(_, _, rhsIndex, _, _, _, _, _, _, _): case let .globalPeer(_, _, rhsIndex, _, _, _, _, _, _, _, _):
return lhsIndex <= rhsIndex return lhsIndex <= rhsIndex
case .message, .addContact: case .message, .addContact:
return true return true
@ -798,7 +798,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
openStories(peer.id, sourceNode.avatarNode) openStories(peer.id, sourceNode.avatarNode)
} }
}) })
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, storyStats, requiresPremiumForMessaging): case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, storyStats, requiresPremiumForMessaging, query):
var enabled = true var enabled = true
if filter.contains(.onlyWriteable) { if filter.contains(.onlyWriteable) {
enabled = canSendMessagesToPeer(peer.peer) enabled = canSendMessagesToPeer(peer.peer)
@ -822,7 +822,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
var suffixString = "" var suffixString = ""
if let subscribers = peer.subscribers, subscribers != 0 { if let subscribers = peer.subscribers, subscribers != 0 {
if peer.peer is TelegramUser { if peer.peer is TelegramUser {
suffixString = ", \(strings.Conversation_StatusSubscribers(subscribers))" suffixString = ", \(strings.Conversation_StatusBotSubscribers(subscribers))"
} else if let channel = peer.peer as? TelegramChannel, case .broadcast = channel.info { } else if let channel = peer.peer as? TelegramChannel, case .broadcast = channel.info {
suffixString = ", \(strings.Conversation_StatusSubscribers(subscribers))" suffixString = ", \(strings.Conversation_StatusSubscribers(subscribers))"
} else { } else {
@ -858,7 +858,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
isSavedMessages = true isSavedMessages = true
} }
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch(isSavedMessages: isSavedMessages), peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .addressName(suffixString), badge: badge, requiresPremiumForMessaging: requiresPremiumForMessaging, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch(isSavedMessages: isSavedMessages), peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .addressName(suffixString), badge: badge, requiresPremiumForMessaging: requiresPremiumForMessaging, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, searchQuery: query, action: { _ in
interaction.peerSelected(EnginePeer(peer.peer), nil, nil, nil) interaction.peerSelected(EnginePeer(peer.peer), nil, nil, nil)
}, disabledAction: { _ in }, disabledAction: { _ in
interaction.disabledPeerSelected(EnginePeer(peer.peer), nil, requiresPremiumForMessaging ? .premiumRequired : .generic) interaction.disabledPeerSelected(EnginePeer(peer.peer), nil, requiresPremiumForMessaging ? .premiumRequired : .generic)
@ -2607,7 +2607,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
if !existingPeerIds.contains(peer.peer.id), filteredPeer(EnginePeer(peer.peer), EnginePeer(accountPeer)) { if !existingPeerIds.contains(peer.peer.id), filteredPeer(EnginePeer(peer.peer), EnginePeer(accountPeer)) {
existingPeerIds.insert(peer.peer.id) existingPeerIds.insert(peer.peer.id)
entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType, nil, false)) entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType, nil, false, finalQuery))
index += 1 index += 1
numberOfGlobalPeers += 1 numberOfGlobalPeers += 1
} }
@ -2953,7 +2953,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
if case let .user(user) = peer, user.flags.contains(.requirePremium) { if case let .user(user) = peer, user.flags.contains(.requirePremium) {
requiresPremiumForMessagingPeerIds.append(peer.id) requiresPremiumForMessagingPeerIds.append(peer.id)
} }
case let .globalPeer(foundPeer, _, _, _, _, _, _, _, _, _): case let .globalPeer(foundPeer, _, _, _, _, _, _, _, _, _, _):
storyStatsIds.append(foundPeer.peer.id) storyStatsIds.append(foundPeer.peer.id)
if let user = foundPeer.peer as? TelegramUser, user.flags.contains(.requirePremium) { if let user = foundPeer.peer as? TelegramUser, user.flags.contains(.requirePremium) {
requiresPremiumForMessagingPeerIds.append(foundPeer.peer.id) requiresPremiumForMessagingPeerIds.append(foundPeer.peer.id)
@ -2994,8 +2994,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
mappedItems[i] = .recentlySearchedPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, stats[peer.id] ?? nil, requiresPremiumForMessaging[peer.id] ?? false) mappedItems[i] = .recentlySearchedPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, stats[peer.id] ?? nil, requiresPremiumForMessaging[peer.id] ?? false)
case let .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _, _): case let .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _, _):
mappedItems[i] = .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.id] ?? nil, requiresPremiumForMessaging[peer.id] ?? false) mappedItems[i] = .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.id] ?? nil, requiresPremiumForMessaging[peer.id] ?? false)
case let .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _, _): case let .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _, _, searchQuery):
mappedItems[i] = .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.peer.id] ?? nil, requiresPremiumForMessaging[peer.peer.id] ?? false) mappedItems[i] = .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.peer.id] ?? nil, requiresPremiumForMessaging[peer.peer.id] ?? false, searchQuery)
case let .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, _, _): case let .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, _, _):
mappedItems[i] = .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, stats[peer.peerId] ?? nil, requiresPremiumForMessaging[peer.peerId] ?? false) mappedItems[i] = .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, stats[peer.peerId] ?? nil, requiresPremiumForMessaging[peer.peerId] ?? false)
default: default:

View File

@ -1714,9 +1714,20 @@ public final class ChatListNode: ListView {
guard let self else { guard let self else {
return return
} }
if let birthdays, birthdays.count == 1, let peerId = birthdays.keys.first {
let _ = (self.context.engine.payments.premiumGiftCodeOptions(peerId: nil, onlyCached: true)
|> filter { !$0.isEmpty }
|> deliverOnMainQueue).start(next: { giftOptions in
let premiumOptions = giftOptions.filter { $0.users == 1 }.map { CachedPremiumGiftOption(months: $0.months, currency: $0.currency, amount: $0.amount, botUrl: "", storeProductId: $0.storeProductId) }
let controller = self.context.sharedContext.makeGiftOptionsController(context: self.context, peerId: peerId, premiumOptions: premiumOptions)
controller.navigationPresentation = .modal
self.push?(controller)
})
} else {
let controller = self.context.sharedContext.makePremiumGiftController(context: self.context, source: .chatList(birthdays), completion: nil) let controller = self.context.sharedContext.makePremiumGiftController(context: self.context, source: .chatList(birthdays), completion: nil)
controller.navigationPresentation = .modal controller.navigationPresentation = .modal
self.push?(controller) self.push?(controller)
}
}, openPremiumManagement: { [weak self] in }, openPremiumManagement: { [weak self] in
guard let self else { guard let self else {
return return

View File

@ -175,6 +175,7 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader {
let options: [ItemListPeerItemRevealOption] let options: [ItemListPeerItemRevealOption]
let additionalActions: [ContactsPeerItemAction] let additionalActions: [ContactsPeerItemAction]
let actionIcon: ContactsPeerItemActionIcon let actionIcon: ContactsPeerItemActionIcon
let searchQuery: String?
let action: ((ContactsPeerItemPeer) -> Void)? let action: ((ContactsPeerItemPeer) -> Void)?
let disabledAction: ((ContactsPeerItemPeer) -> Void)? let disabledAction: ((ContactsPeerItemPeer) -> Void)?
let setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)? let setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)?
@ -215,6 +216,7 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader {
actionIcon: ContactsPeerItemActionIcon = .none, actionIcon: ContactsPeerItemActionIcon = .none,
index: SortIndex?, index: SortIndex?,
header: ListViewItemHeader?, header: ListViewItemHeader?,
searchQuery: String? = nil,
action: ((ContactsPeerItemPeer) -> Void)?, action: ((ContactsPeerItemPeer) -> Void)?,
disabledAction: ((ContactsPeerItemPeer) -> Void)? = nil, disabledAction: ((ContactsPeerItemPeer) -> Void)? = nil,
setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)? = nil, setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)? = nil,
@ -245,6 +247,7 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader {
self.options = options self.options = options
self.additionalActions = additionalActions self.additionalActions = additionalActions
self.actionIcon = actionIcon self.actionIcon = actionIcon
self.searchQuery = searchQuery
self.action = action self.action = action
self.disabledAction = disabledAction self.disabledAction = disabledAction
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
@ -880,7 +883,16 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
statusAttributedString = NSAttributedString(string: string, font: statusFont, textColor: activity ? item.presentationData.theme.list.itemAccentColor : item.presentationData.theme.list.itemSecondaryTextColor) statusAttributedString = NSAttributedString(string: string, font: statusFont, textColor: activity ? item.presentationData.theme.list.itemAccentColor : item.presentationData.theme.list.itemSecondaryTextColor)
} }
case let .addressName(suffix): case let .addressName(suffix):
if let addressName = peer.addressName { var addressName = peer.addressName
if let currentAddressName = addressName, let searchQuery = item.searchQuery?.lowercased(), !peer.usernames.isEmpty && !currentAddressName.lowercased().contains(searchQuery) {
for username in peer.usernames {
if username.username.lowercased().contains(searchQuery) {
addressName = username.username
break
}
}
}
if let addressName {
let addressNameString = NSAttributedString(string: "@" + addressName, font: statusFont, textColor: item.presentationData.theme.list.itemAccentColor) let addressNameString = NSAttributedString(string: "@" + addressName, font: statusFont, textColor: item.presentationData.theme.list.itemAccentColor)
if !suffix.isEmpty { if !suffix.isEmpty {
let suffixString = NSAttributedString(string: suffix, font: statusFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor) let suffixString = NSAttributedString(string: suffix, font: statusFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor)

View File

@ -463,6 +463,10 @@ public extension EnginePeer {
return self._asPeer().addressName return self._asPeer().addressName
} }
var usernames: [TelegramPeerUsername] {
return self._asPeer().usernames
}
var indexName: EnginePeer.IndexName { var indexName: EnginePeer.IndexName {
return EnginePeer.IndexName(self._asPeer().indexName) return EnginePeer.IndexName(self._asPeer().indexName)
} }

View File

@ -61,9 +61,13 @@ public func _internal_searchPeers(accountPeerId: PeerId, postbox: Postbox, netwo
if let group = peer as? TelegramGroup, group.migrationReference != nil { if let group = peer as? TelegramGroup, group.migrationReference != nil {
continue continue
} }
if let user = peer as? TelegramUser {
renderedMyPeers.append(FoundPeer(peer: peer, subscribers: user.subscriberCount))
} else {
renderedMyPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) renderedMyPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId]))
} }
} }
}
var renderedPeers: [FoundPeer] = [] var renderedPeers: [FoundPeer] = []
for result in results { for result in results {
@ -72,9 +76,13 @@ public func _internal_searchPeers(accountPeerId: PeerId, postbox: Postbox, netwo
if let group = peer as? TelegramGroup, group.migrationReference != nil { if let group = peer as? TelegramGroup, group.migrationReference != nil {
continue continue
} }
if let user = peer as? TelegramUser {
renderedPeers.append(FoundPeer(peer: peer, subscribers: user.subscriberCount))
} else {
renderedPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) renderedPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId]))
} }
} }
}
switch scope { switch scope {
case .everywhere: case .everywhere:

View File

@ -468,8 +468,12 @@ private final class SheetContent: CombinedComponent {
switch component.subject { switch component.subject {
case .peer: case .peer:
if let peer = state.peer { if let peer = state.peer {
if case .user = peer { if case let .user(user) = peer {
if let _ = user.botInfo {
mainTitle = environment.strings.Report_Title_Bot
} else {
mainTitle = environment.strings.Report_Title_User mainTitle = environment.strings.Report_Title_User
}
} else if case let .channel(channel) = peer, case .broadcast = channel.info { } else if case let .channel(channel) = peer, case .broadcast = channel.info {
mainTitle = environment.strings.Report_Title_Channel mainTitle = environment.strings.Report_Title_Channel
} else { } else {

View File

@ -564,8 +564,7 @@ final class GiftSetupScreenComponent: Component {
contentHeight += 26.0 contentHeight += 26.0
if case let .starGift(starGift) = component.subject, let availability = starGift.availability { if case let .starGift(starGift) = component.subject, let availability = starGift.availability {
//TODO:localize let remains: Int32 = availability.remains
let remains: Int32 = Int32(CGFloat(availability.remains) * 0.66)
let position = CGFloat(remains) / CGFloat(availability.total) let position = CGFloat(remains) / CGFloat(availability.total)
let remainsString = "\(remains)" //presentationStringsFormattedNumber(remains, environment.dateTimeFormat.groupingSeparator) let remainsString = "\(remains)" //presentationStringsFormattedNumber(remains, environment.dateTimeFormat.groupingSeparator)
let totalString = presentationStringsFormattedNumber(availability.total, environment.dateTimeFormat.groupingSeparator) let totalString = presentationStringsFormattedNumber(availability.total, environment.dateTimeFormat.groupingSeparator)