mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' into experimental-2
This commit is contained in:
commit
8a6f5dd66e
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -8,7 +8,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-10.15
|
||||
runs-on: macos-11
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@ -17,7 +17,7 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Set active Xcode path
|
||||
run: sudo xcode-select -s /Applications/Xcode_12.4.app/Contents/Developer
|
||||
run: sudo xcode-select -s /Applications/Xcode_12.5.1.app/Contents/Developer
|
||||
|
||||
- name: Create canonical source directory
|
||||
run: |
|
||||
|
@ -104,6 +104,7 @@
|
||||
"PUSH_ALBUM" = "%1$@|sent you an album";
|
||||
"PUSH_MESSAGE_FILES_TEXT_1" = "sent you a file";
|
||||
"PUSH_MESSAGE_FILES_TEXT_any" = "sent you %d files";
|
||||
"PUSH_MESSAGE_THEME" = "%1$@|changed theme to %2$@";
|
||||
|
||||
"PUSH_CHANNEL_MESSAGE_TEXT" = "%1$@|%2$@";
|
||||
"PUSH_CHANNEL_MESSAGE_NOTEXT" = "%1$@|posted a message";
|
||||
@ -176,6 +177,7 @@
|
||||
"PUSH_CHAT_ALBUM" = "%2$@|%1$@ sent an album";
|
||||
"PUSH_CHAT_MESSAGE_DOCS_TEXT_1" = "{author} sent a file";
|
||||
"PUSH_CHAT_MESSAGE_DOCS_TEXT_any" = "{author} sent %d files";
|
||||
"PUSH_CHAT_MESSAGE_THEME" = "%1$@|set theme to %3$@ in the group %2$@";
|
||||
|
||||
"PUSH_PINNED_TEXT" = "%1$@|pinned \"%2$@\" ";
|
||||
"PUSH_PINNED_NOTEXT" = "%1$@|pinned a message";
|
||||
@ -2478,11 +2480,15 @@ Unused sets are archived when you add more.";
|
||||
"Call.CallInProgressTitle" = "Call in Progress";
|
||||
"Call.CallInProgressMessage" = "Finish call with %1$@ and start a new one with %2$@?";
|
||||
"Call.CallInProgressVoiceChatMessage" = "Finish call with %1$@ and start a voice chat with %2$@?";
|
||||
"Call.CallInProgressLiveStreamMessage" = "Finish call with %1$@ and start a live stream with %2$@?";
|
||||
"Call.ExternalCallInProgressMessage" = "Please finish the current call first.";
|
||||
|
||||
"Call.VoiceChatInProgressTitle" = "Voice Chat in Progress";
|
||||
"Call.LiveStreamInProgressTitle" = "Live Stream in Progress";
|
||||
"Call.VoiceChatInProgressMessage" = "Leave voice chat in %1$@ and start a new one with %2$@?";
|
||||
"Call.LiveStreamInProgressMessage" = "Leave live stream in %1$@ and start a new one with %2$@?";
|
||||
"Call.VoiceChatInProgressCallMessage" = "Leave voice chat in %1$@ and start a call with %2$@?";
|
||||
"Call.LiveStreamInProgressCallMessage" = "Leave live stream in %1$@ and start a call with %2$@?";
|
||||
|
||||
"Call.Message" = "Message";
|
||||
|
||||
@ -2616,6 +2622,7 @@ Unused sets are archived when you add more.";
|
||||
"Channel.AdminLog.CanBeAnonymous" = "Remain Anonymous";
|
||||
"Channel.AdminLog.CanEditMessages" = "Edit Messages";
|
||||
"Channel.AdminLog.CanManageCalls" = "Manage Voice Chats";
|
||||
"Channel.AdminLog.CanManageLiveStreams" = "Manage Live Streams";
|
||||
|
||||
"Channel.AdminLog.MessageToggleInvitesOn" = "%@ enabled group invites";
|
||||
"Channel.AdminLog.MessageToggleInvitesOff" = "%@ disabled group invites";
|
||||
@ -2674,6 +2681,7 @@ Unused sets are archived when you add more.";
|
||||
"Channel.AdminLogFilter.EventsPinned" = "Pinned Messages";
|
||||
"Channel.AdminLogFilter.EventsLeaving" = "Members Removed";
|
||||
"Channel.AdminLogFilter.EventsCalls" = "Voice Chats";
|
||||
"Channel.AdminLogFilter.EventsLiveStreams" = "Live Streams";
|
||||
"Channel.AdminLogFilter.EventsInviteLinks" = "Invite Links";
|
||||
"Channel.AdminLogFilter.AdminsTitle" = "ADMINS";
|
||||
"Channel.AdminLogFilter.AdminsAll" = "All Admins";
|
||||
@ -2694,6 +2702,7 @@ Unused sets are archived when you add more.";
|
||||
|
||||
"Conversation.ViewChannel" = "VIEW CHANNEL";
|
||||
"Conversation.ViewGroup" = "VIEW GROUP";
|
||||
"Conversation.ViewBot" = "VIEW BOT";
|
||||
|
||||
"GroupInfo.ActionPromote" = "Promote";
|
||||
"GroupInfo.ActionRestrict" = "Restrict";
|
||||
@ -5705,6 +5714,7 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.SpeakPermissionAdmin" = "New paricipants are muted";
|
||||
"VoiceChat.Share" = "Share Invite Link";
|
||||
"VoiceChat.EndVoiceChat" = "End Voice Chat";
|
||||
"VoiceChat.EndLiveStream" = "End Live Stream";
|
||||
|
||||
"VoiceChat.CopyInviteLink" = "Copy Invite Link";
|
||||
"VoiceChat.InviteLinkCopiedText" = "Invite link copied to clipboard";
|
||||
@ -5717,18 +5727,20 @@ Sorry for the inconvenience.";
|
||||
|
||||
"VoiceChat.PanelJoin" = "Join";
|
||||
"VoiceChat.Title" = "Voice Chat";
|
||||
"VoiceChatChannel.Title" = "Live Stream";
|
||||
|
||||
"VoiceChat.InviteMember" = "Invite Member";
|
||||
"VoiceChat.UserInvited" = "You invited **%@** to the voice chat";
|
||||
|
||||
"Notification.VoiceChatInvitation" = "%1$@ invited %2$@ to the voice chat";
|
||||
"Notification.VoiceChatInvitationForYou" = "%1$@ invited you to the voice chat";
|
||||
|
||||
"VoiceChat.InvitedPeerText" = "You invited %@ to the voice chat";
|
||||
"LiveStream.InvitedPeerText" = "You invited %@ to the live stream";
|
||||
"VoiceChat.RemovedPeerText" = "You removed %@ from this group";
|
||||
|
||||
"Notification.VoiceChatStarted" = "%1$@ started a voice chat";
|
||||
"Notification.VoiceChatEnded" = "Voice chat ended (%@)";
|
||||
"Notification.LiveStreamEnded" = "Live stream ended (%@)";
|
||||
"Notification.VoiceChatEndedGroup" = "%1$@ ended the voice chat (%2$@)";
|
||||
|
||||
"VoiceChat.Panel.TapToJoin" = "Tap to join";
|
||||
@ -5748,12 +5760,17 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.Status.MembersFormat" = "%1$@ %2$@";
|
||||
|
||||
"ChannelInfo.CreateVoiceChat" = "Start Voice Chat";
|
||||
"ChannelInfo.CreateLiveStream" = "Start Live Stream";
|
||||
|
||||
"VoiceChat.AnonymousDisabledAlertText" = "Sorry, you can't join voice chat as an anonymous admin.";
|
||||
"LiveStream.AnonymousDisabledAlertText" = "Sorry, you can't join live stream as an anonymous admin.";
|
||||
"VoiceChat.ChatFullAlertText" = "Sorry, this voice chat has too many participants at the moment.";
|
||||
"LiveStream.ChatFullAlertText" = "Sorry, this live stream has too many participants at the moment.";
|
||||
|
||||
"VoiceChat.EndConfirmationTitle" = "End voice chat";
|
||||
"LiveStream.EndConfirmationTitle" = "End live stream";
|
||||
"VoiceChat.EndConfirmationText" = "Are you sure you want to end this voice chat?";
|
||||
"LiveStream.EndConfirmationText" = "Are you sure you want to end this live stream?";
|
||||
"VoiceChat.EndConfirmationEnd" = "End";
|
||||
|
||||
"VoiceChat.InviteMemberToGroupFirstText" = "%1$@ isn't a member of \"%2$@\" yet. Add them to the group?";
|
||||
@ -5761,6 +5778,7 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.InviteMemberToGroupFirstAdd" = "Add";
|
||||
|
||||
"VoiceChat.CreateNewVoiceChatText" = "Voice chat ended. Start a new one?";
|
||||
"LiveStream.CreateNewVoiceChatText" = "Live stream ended. Start a new one?";
|
||||
"VoiceChat.CreateNewVoiceChatStart" = "Start";
|
||||
"VoiceChat.CreateNewVoiceChatStartNow" = "Start Now";
|
||||
"VoiceChat.CreateNewVoiceChatSchedule" = "Schedule";
|
||||
@ -5770,8 +5788,10 @@ Sorry for the inconvenience.";
|
||||
"PUSH_CHAT_VOICECHAT_INVITE_YOU" = "%2$@|%1$@ invited you to the voice chat";
|
||||
"PUSH_CHAT_VOICECHAT_END" = "%2$@|%1$@ has ended the voice chat";
|
||||
|
||||
"Call.VoiceChatInProgressTitle" = "Voice Chat in Progress";
|
||||
"Call.VoiceChatInProgressMessageCall" = "Leave voice chat in %1$@ and start a call with %2$@?";
|
||||
"PUSH_CHAT_LIVESTREAM_START" = "%2$@|%1$@ started a live stream";
|
||||
"PUSH_CHAT_LIVESTREAM_INVITE" = "%2$@|%1$@ invited %3$@ to the live stream";
|
||||
"PUSH_CHAT_LIVESTREAM_INVITE_YOU" = "%2$@|%1$@ invited you to the live stream";
|
||||
"PUSH_CHAT_LIVESTREAM_END" = "%2$@|%1$@ has ended the live stream";
|
||||
|
||||
"Conversation.Dice.u1F3B3" = "Send a bowling emoji to try your luck.";
|
||||
|
||||
@ -5787,7 +5807,9 @@ Sorry for the inconvenience.";
|
||||
"VoiceOver.Chat.MessagesSelected_any" = "%@ messages selected";
|
||||
|
||||
"Channel.AdminLog.StartedVoiceChat" = "%1$@ started voice chat";
|
||||
"Channel.AdminLog.StartedLiveStream" = "%1$@ started live stream";
|
||||
"Channel.AdminLog.EndedVoiceChat" = "%1$@ ended voice chat";
|
||||
"Channel.AdminLog.EndedLiveStream" = "%1$@ ended live stream";
|
||||
"Channel.AdminLog.MutedParticipant" = "%1$@ muted %2$@";
|
||||
"Channel.AdminLog.UnmutedMutedParticipant" = "%1$@ unmuted %2$@";
|
||||
"Channel.AdminLog.AllowedNewMembersToSpeak" = "%1$@ allowed new members to speak";
|
||||
@ -5796,22 +5818,29 @@ Sorry for the inconvenience.";
|
||||
"Group.GroupMembersHeader" = "GROUP MEMBERS";
|
||||
|
||||
"Conversation.VoiceChatMediaRecordingRestricted" = "You can't record voice and video messages during a voice chat.";
|
||||
"Conversation.LiveStreamMediaRecordingRestricted" = "You can't record voice and video messages during a live stream.";
|
||||
|
||||
"CallList.ActiveVoiceChatsHeader" = "ACTIVE VOICE CHATS";
|
||||
"CallList.RecentCallsHeader" = "RECENT CALLS";
|
||||
|
||||
"VoiceChat.PeerJoinedText" = "%@ joined the voice chat";
|
||||
"LiveStream.PeerJoinedText" = "%@ joined the live stream";
|
||||
|
||||
"VoiceChat.StartRecording" = "Start Recording";
|
||||
"LiveStream.StartRecording" = "Start Recording";
|
||||
"VoiceChat.StopRecording" = "Stop Recording";
|
||||
|
||||
"VoiceChat.StartRecordingTitle" = "Start Recording";
|
||||
"LiveStream.StartRecordingTitle" = "Start Recording";
|
||||
"VoiceChat.StartRecordingText" = "Do you want to start recording this chat and save the result into an audio file?\n\nOther members will see that the chat is being recorded.";
|
||||
"LiveStream.StartRecordingText" = "Do you want to start recording this live stream and save the result into an audio file?\n\nOther members will see that the chat is being recorded.";
|
||||
"VoiceChat.StartRecordingStart" = "Start";
|
||||
|
||||
"VoiceChat.RecordingTitlePlaceholder" = "Audio Title (Optional)";
|
||||
"VoiceChat.RecordingStarted" = "Voice chat recording started";
|
||||
"LiveStream.RecordingStarted" = "Live stream recording started";
|
||||
"VoiceChat.RecordingInProgress" = "Voice chat is being recorded";
|
||||
"LiveStream.RecordingInProgress" = "Live stream is being recorded";
|
||||
|
||||
"VoiceChat.StopRecordingTitle" = "Stop Recording?";
|
||||
"VoiceChat.StopRecordingStop" = "Stop";
|
||||
@ -5836,6 +5865,7 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.MuteForMe" = "Mute for Me";
|
||||
|
||||
"PeerInfo.ButtonVoiceChat" = "Voice Chat";
|
||||
"PeerInfo.ButtonLiveStream" = "Live Stream";
|
||||
"VoiceChat.OpenChat" = "Open Chat";
|
||||
|
||||
"GroupInfo.InviteLinks" = "Invite Links";
|
||||
@ -6183,16 +6213,20 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.DisplayAsInfo" = "Choose whether you want to be displayed as your personal account or as your channel.";
|
||||
"VoiceChat.DisplayAsInfoGroup" = "Choose whether you want to be displayed as your personal account, this group, or one of your channels.";
|
||||
"VoiceChat.DisplayAsSuccess" = "Members of this voice chat will now see your as **%@**.";
|
||||
"LiveStream.DisplayAsSuccess" = "Members of this live stream will now see your as **%@**.";
|
||||
"VoiceChat.PersonalAccount" = "personal account";
|
||||
"VoiceChat.EditTitle" = "Edit Voice Chat Title";
|
||||
"LiveStream.EditTitle" = "Edit Live Stream Title";
|
||||
"VoiceChat.EditPermissions" = "Edit Permissions";
|
||||
|
||||
"VoiceChat.OpenChannel" = "Open Channel";
|
||||
|
||||
"VoiceChat.EditTitleTitle" = "Voice Chat Title";
|
||||
"VoiceChat.EditTitleText" = "Edit a title of this voice chat.";
|
||||
"LiveStream.EditTitleText" = "Edit a title of this live stream.";
|
||||
"VoiceChat.EditTitleSuccess" = "Voice chat title changed to **%@**.";
|
||||
"LiveStream.EditTitleSuccess" = "Live stream title changed to **%@**.";
|
||||
"VoiceChat.EditTitleRemoveSuccess" = "Voice chat title removed.";
|
||||
"LiveStream.EditTitleRemoveSuccess" = "Live Stream title removed.";
|
||||
|
||||
"VoiceChat.InviteLink.Speaker" = "Speaker";
|
||||
"VoiceChat.InviteLink.Listener" = "Listener";
|
||||
@ -6213,8 +6247,6 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.InviteLink.InviteListeners_many" = "[%@] Invite Listeners";
|
||||
"VoiceChat.InviteLink.InviteListeners_any" = "[%@] Invite Listeners";
|
||||
|
||||
"Conversation.JoinVoiceChat" = "JOIN VOICE CHAT";
|
||||
|
||||
"Conversation.CancelForwardTitle" = "Cancel Forwarding";
|
||||
"Conversation.CancelForwardText" = "Do you want to cancel forwarding or send messages to a different chat?";
|
||||
"Conversation.CancelForwardCancelForward" = "Cancel Forwarding";
|
||||
@ -6256,8 +6288,10 @@ Sorry for the inconvenience.";
|
||||
|
||||
"VoiceChat.RemovePeerConfirmationChannel" = "Are you sure you want to remove %@ from the channel?";
|
||||
"VoiceChat.RemoveAndBanPeerConfirmation" = "Do you want to remove %1$@ from the voice chat and ban them in %2$@?";
|
||||
"LiveStream.RemoveAndBanPeerConfirmation" = "Do you want to remove %1$@ from the live stream and ban them in %2$@?";
|
||||
|
||||
"Notification.VoiceChatStartedChannel" = "Voice chat started";
|
||||
"Notification.LiveStreamStarted" = "Live stream started";
|
||||
|
||||
"Conversation.MessageCopied" = "Message copied to clipboard";
|
||||
"Conversation.LinkCopied" = "Link copied to clipboard";
|
||||
@ -6276,14 +6310,19 @@ Sorry for the inconvenience.";
|
||||
"Conversation.DeletedFromContacts" = "**%@** deleted from your contacts";
|
||||
|
||||
"Conversation.VoiceChat" = "Voice Chat";
|
||||
"Conversation.LiveStream" = "Live Stream";
|
||||
|
||||
"Conversation.JoinVoiceChatAsSpeaker" = "JOIN AS SPEAKER";
|
||||
"Conversation.JoinVoiceChatAsListener" = "JOIN AS LISTENER";
|
||||
|
||||
"VoiceChat.LeaveConfirmation" = "Are you sure you want to leave this voice chat?";
|
||||
"LiveStream.LeaveConfirmation" = "Are you sure you want to leave this live stream?";
|
||||
"VoiceChat.LeaveVoiceChat" = "Leave Voice Chat";
|
||||
"LiveStream.LeaveVoiceChat" = "Leave Live Stream";
|
||||
"VoiceChat.LeaveAndEndVoiceChat" = "End Voice Chat";
|
||||
"LiveStream.LeaveAndEndVoiceChat" = "End Live Stream";
|
||||
"VoiceChat.LeaveAndCancelVoiceChat" = "Abort Voice Chat";
|
||||
"LiveStream.LeaveAndCancelVoiceChat" = "Abort Live Stream";
|
||||
|
||||
"VoiceChat.ForwardTooltip.Chat" = "Invite link forwarded to **%@**";
|
||||
"VoiceChat.ForwardTooltip.TwoChats" = "Invite link forwarded to **%@** and **%@**";
|
||||
@ -6337,12 +6376,15 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.UnpinVideo" = "Unpin Video";
|
||||
|
||||
"Notification.VoiceChatScheduledChannel" = "Voice chat scheduled for %@";
|
||||
"Notification.LiveStreamScheduled" = "Live stream scheduled for %@";
|
||||
"Notification.VoiceChatScheduled" = "%1$@ scheduled a voice chat for %2$@";
|
||||
|
||||
"Notification.VoiceChatScheduledTodayChannel" = "Voice chat scheduled for today at %@";
|
||||
"Notification.LiveStreamScheduledToday" = "Live stream scheduled for today at %@";
|
||||
"Notification.VoiceChatScheduledToday" = "%1$@ scheduled a voice chat for today at %2$@";
|
||||
|
||||
"Notification.VoiceChatScheduledTomorrowChannel" = "Voice chat scheduled for tomorrow at %@";
|
||||
"Notification.LiveStreamScheduledTomorrow" = "Live stream scheduled for tomorrow at %@";
|
||||
"Notification.VoiceChatScheduledTomorrow" = "%1$@ scheduled a voice chat for tomorrow at %2$@";
|
||||
|
||||
"VoiceChat.StartsIn" = "Starts in";
|
||||
@ -6361,27 +6403,36 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.TapToEditTitle" = "Tap to edit title";
|
||||
|
||||
"ChannelInfo.ScheduleVoiceChat" = "Schedule Voice Chat";
|
||||
"ChannelInfo.ScheduleLiveStream" = "Schedule Live Stream";
|
||||
|
||||
"ScheduleVoiceChat.Title" = "Schedule Voice Chat";
|
||||
"ScheduleLiveStream.Title" = "Schedule Live Stream";
|
||||
"ScheduleVoiceChat.GroupText" = "The members of the group will be notified that the voice chat will start in %@.";
|
||||
"ScheduleVoiceChat.ChannelText" = "The members of the channel will be notified that the voice chat will start in %@.";
|
||||
"ScheduleLiveStream.ChannelText" = "The members of the channel will be notified that the live stream will start in %@.";
|
||||
|
||||
"ScheduleVoiceChat.ScheduleToday" = "Start today at %@";
|
||||
"ScheduleVoiceChat.ScheduleTomorrow" = "Start tomorrow at %@";
|
||||
"ScheduleVoiceChat.ScheduleOn" = "Start on %@ at %@";
|
||||
|
||||
"Conversation.ScheduledVoiceChat" = "Scheduled Voice Chat";
|
||||
"Conversation.ScheduledLiveStream" = "Scheduled Live Stream";
|
||||
|
||||
"Conversation.ScheduledVoiceChatStartsOn" = "Voice chat starts on %@";
|
||||
"Conversation.ScheduledLiveStreamStartsOn" = "Live stream starts on %@";
|
||||
"Conversation.ScheduledVoiceChatStartsOnShort" = "Starts on %@";
|
||||
"Conversation.ScheduledVoiceChatStartsToday" = "Voice chat starts today at %@";
|
||||
"Conversation.ScheduledLiveStreamStartsToday" = "Live stream starts today at %@";
|
||||
"Conversation.ScheduledVoiceChatStartsTodayShort" = "Starts today at %@";
|
||||
"Conversation.ScheduledVoiceChatStartsTomorrow" = "Voice chat starts tomorrow at %@";
|
||||
"Conversation.ScheduledLiveStreamStartsTomorrow" = "Live stream starts tomorrow at %@";
|
||||
"Conversation.ScheduledVoiceChatStartsTomorrowShort" = "Starts tomorrow at %@";
|
||||
|
||||
"VoiceChat.CancelVoiceChat" = "Abort Voice Chat";
|
||||
"VoiceChat.CancelLiveStream" = "Abort Live Stream";
|
||||
"VoiceChat.CancelConfirmationTitle" = "Abort Voice Chat";
|
||||
"LiveStream.CancelConfirmationTitle" = "Abort Live Stream";
|
||||
"VoiceChat.CancelConfirmationText" = "Do you want to abort the scheduled voice chat?";
|
||||
"LiveStream.CancelConfirmationText" = "Do you want to abort the scheduled live stream?";
|
||||
"VoiceChat.CancelConfirmationEnd" = "Abort";
|
||||
|
||||
"ScheduledIn.Seconds_1" = "%@ second";
|
||||
@ -6588,11 +6639,48 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Conversation.ForwardOptions.Text" = "What whould you like to do with %1$@ from %2$@?";
|
||||
"Conversation.ForwardOptions.TextPersonal" = "What whould you like to do with %1$@ from your chat with %2$@?";
|
||||
"Conversation.ForwardOptions.ForwardToAnotherChat" = "Forward to Another Chat";
|
||||
"Conversation.ForwardOptions.ShowOptions" = "Show Forwarding Options";
|
||||
"Conversation.ForwardOptions.CancelForwarding" = "Cancel Forwarding";
|
||||
|
||||
"Conversation.ForwardOptions.HideSendersName" = "Hide Sender's Name";
|
||||
"Conversation.ForwardOptions.ShowSendersName" = "Show Sender's Name";
|
||||
|
||||
"Conversation.ForwardOptions.HideSendersNames" = "Hide Senders' Names";
|
||||
"Conversation.ForwardOptions.ShowSendersNames" = "Show Senders' Names";
|
||||
|
||||
"Conversation.ForwardOptions.ShowCaption" = "Show Captions";
|
||||
"Conversation.ForwardOptions.HideCaption" = "Hide Captions";
|
||||
|
||||
"Conversation.ForwardOptions.ChangeRecipient" = "Change Recipient";
|
||||
"Conversation.ForwardOptions.SendMessage" = "Send Message";
|
||||
"Conversation.ForwardOptions.SendMessages" = "Send Messages";
|
||||
|
||||
"Conversation.ForwardOptions.TapForOptions" = "Tap here for forwarding options";
|
||||
"Conversation.ForwardOptions.TapForOptionsShort" = "Tap here for options";
|
||||
|
||||
"Conversation.ForwardOptions.UserMessageForwardVisible" = "%@ will see that it was forwarded";
|
||||
"Conversation.ForwardOptions.UserMessageForwardHidden" = "%@ won't see that it was forwarded";
|
||||
"Conversation.ForwardOptions.UserMessagesForwardVisible" = "%@ will see they were forwarded";
|
||||
"Conversation.ForwardOptions.UserMessagesForwardHidden" = "%@ won't see they were forwarded";
|
||||
|
||||
"Conversation.ForwardOptions.GroupMessageForwardVisible" = "Members will see that it was forwarded";
|
||||
"Conversation.ForwardOptions.GroupMessageForwardHidden" = "Members won't see that it was forwarded";
|
||||
"Conversation.ForwardOptions.GroupMessagesForwardVisible" = "Members will see they were forwarded";
|
||||
"Conversation.ForwardOptions.GroupMessagesForwardHidden" = "Members won't see they were forwarded";
|
||||
|
||||
"Conversation.ForwardOptions.ChannelMessageForwardVisible" = "Subscribers will see that it was forwarded";
|
||||
"Conversation.ForwardOptions.ChannelMessageForwardHidden" = "Subscribers won't see that it was forwarded";
|
||||
"Conversation.ForwardOptions.ChannelMessagesForwardVisible" = "Subscribers will see they were forwarded";
|
||||
"Conversation.ForwardOptions.ChannelMessagesForwardHidden" = "Subscribers won't see they were forwarded";
|
||||
|
||||
"Conversation.ForwardOptions.ForwardTitleSingle" = "Forward Message";
|
||||
"Conversation.ForwardOptions.ForwardTitle_1" = "Forward %@ Message";
|
||||
"Conversation.ForwardOptions.ForwardTitle_2" = "Forward %@ Messages";
|
||||
"Conversation.ForwardOptions.ForwardTitle_3_10" = "Forward %@ Messages";
|
||||
"Conversation.ForwardOptions.ForwardTitle_any" = "Forward %@ Messages";
|
||||
"Conversation.ForwardOptions.ForwardTitle_many" = "Forward %@ Messages";
|
||||
"Conversation.ForwardOptions.ForwardTitle_0" = "Forward %@ Messages";
|
||||
|
||||
"Conversation.ForwardOptions.Title_1" = "%@ Message";
|
||||
"Conversation.ForwardOptions.Title_2" = "%@ Messages";
|
||||
"Conversation.ForwardOptions.Title_3_10" = "%@ Messages";
|
||||
@ -6607,9 +6695,9 @@ Sorry for the inconvenience.";
|
||||
"Conversation.ForwardOptions.Messages_many" = "%@ messages";
|
||||
"Conversation.ForwardOptions.Messages_0" = "%@ messages";
|
||||
|
||||
"Conversation.ForwardOptions.You" = "You (senders' names hidden)";
|
||||
|
||||
"Activity.ChoosingSticker" = "choosing sticker";
|
||||
"DialogList.SingleChoosingStickerSuffix" = "%@ is choosing sticker";
|
||||
|
||||
"WallpaperPreview.Animate" = "Animate";
|
||||
"WallpaperPreview.AnimateDescription" = "Colors will move when you send messages";
|
||||
|
||||
@ -6637,6 +6725,9 @@ Sorry for the inconvenience.";
|
||||
"Notification.YouChangedTheme" = "You changed chat theme to %@";
|
||||
"Notification.YouDisabledTheme" = "You disabled chat theme";
|
||||
|
||||
"Notification.ChannelChangedTheme" = "Channel theme changed to %1$@";
|
||||
"Notification.ChannelDisabledTheme" = "Channel theme disabled";
|
||||
|
||||
"Appstore.Cloud" = "**Cloud-based**\nUnlimited storage for chats,\nmedia and documents.";
|
||||
"Appstore.Cloud.Profile" = "**Jennifer**\n23 y.o. designer from San Francisco.";
|
||||
"Appstore.Creative" = "**Creative**\nColor themes, stickers, GIFs,\nvideo messages and more.";
|
||||
@ -6668,3 +6759,37 @@ Sorry for the inconvenience.";
|
||||
"Appstore.Secure" = "**Secure**\nAll chats are protected\nwith strong encryption.";
|
||||
"Appstore.Secure.Chat" = "**Little Sister**\nAny gift ideas for mom?\n**You**A dog!\n**You**I'm serious. Let's get her a puppy. \n**You**\nI saw this!\n**Little Sister**\nI needed proof this was your idea!";
|
||||
"Appstore.Secure.Chat.Name" = "**Little Sister**";
|
||||
|
||||
"Conversation.ReplyMessagePanelTitle" = "Reply to %@";
|
||||
|
||||
"Channel.AdminLog.MessageChangedThemeSet" = "%1$@ changed chat theme to %2$@";
|
||||
"Channel.AdminLog.MessageChangedThemeRemove" = "%1$@ disabled chat theme";
|
||||
|
||||
"SponsoredMessageMenu.Info" = "What are sponsored\nmessages?";
|
||||
"SponsoredMessageInfo.Text" = "See https://telegram.org";
|
||||
"SponsoredMessageInfo.Action" = "Learn More";
|
||||
"SponsoredMessageInfo.ActionUrl" = "https://telegram.org";
|
||||
|
||||
"Chat.NavigationNoChannels" = "You have no unread channels";
|
||||
|
||||
"Message.SponsoredLabel" = "sponsored";
|
||||
|
||||
"Stickers.Favorites" = "Favorites";
|
||||
"Stickers.Recent" = "Recent";
|
||||
"Stickers.Stickers" = "Stickers";
|
||||
"Stickers.Gifs" = "GIFs";
|
||||
"Stickers.Trending" = "Trending";
|
||||
"Stickers.Settings" = "Settings";
|
||||
|
||||
"Gif.Emotion.Angry" = "Angry";
|
||||
"Gif.Emotion.Surprised" = "Surprised";
|
||||
"Gif.Emotion.Joy" = "Joy";
|
||||
"Gif.Emotion.Kiss" = "Kiss";
|
||||
"Gif.Emotion.Hearts" = "Hearts";
|
||||
"Gif.Emotion.ThumbsUp" = "Thumbs Up";
|
||||
"Gif.Emotion.ThumbsDown" = "Thumbs Down";
|
||||
"Gif.Emotion.RollEyes" = "Roll-Eyes";
|
||||
"Gif.Emotion.Cool" = "Cool";
|
||||
"Gif.Emotion.Party" = "Party";
|
||||
|
||||
"Conversation.ForwardFrom" = "From: %@";
|
||||
|
@ -130,6 +130,37 @@ public enum ChatControllerInteractionNavigateToPeer {
|
||||
case withBotStartPayload(ChatControllerInitialBotStart)
|
||||
}
|
||||
|
||||
public struct ChatInterfaceForwardOptionsState: Codable, Equatable {
|
||||
public var hideNames: Bool
|
||||
public var hideCaptions: Bool
|
||||
public var unhideNamesOnCaptionChange: Bool
|
||||
|
||||
public static func ==(lhs: ChatInterfaceForwardOptionsState, rhs: ChatInterfaceForwardOptionsState) -> Bool {
|
||||
return lhs.hideNames == rhs.hideNames && lhs.hideCaptions == rhs.hideCaptions && lhs.unhideNamesOnCaptionChange == rhs.unhideNamesOnCaptionChange
|
||||
}
|
||||
|
||||
public init(hideNames: Bool, hideCaptions: Bool, unhideNamesOnCaptionChange: Bool) {
|
||||
self.hideNames = hideNames
|
||||
self.hideCaptions = hideCaptions
|
||||
self.unhideNamesOnCaptionChange = unhideNamesOnCaptionChange
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.hideNames = (try? container.decodeIfPresent(Bool.self, forKey: "hn")) ?? false
|
||||
self.hideCaptions = (try? container.decodeIfPresent(Bool.self, forKey: "hc")) ?? false
|
||||
self.unhideNamesOnCaptionChange = false
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.hideNames, forKey: "hn")
|
||||
try container.encode(self.hideCaptions, forKey: "hc")
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatTextInputState: Codable, Equatable {
|
||||
public let inputText: NSAttributedString
|
||||
public let selectionRange: Range<Int>
|
||||
@ -328,9 +359,49 @@ public struct ChatTextInputStateText: Codable, Equatable {
|
||||
}
|
||||
|
||||
public enum ChatControllerSubject: Equatable {
|
||||
public struct ForwardOptions: Equatable {
|
||||
public let hideNames: Bool
|
||||
public let hideCaptions: Bool
|
||||
|
||||
public init(hideNames: Bool, hideCaptions: Bool) {
|
||||
self.hideNames = hideNames
|
||||
self.hideCaptions = hideCaptions
|
||||
}
|
||||
}
|
||||
|
||||
case message(id: EngineMessage.Id, highlight: Bool, timecode: Double?)
|
||||
case scheduledMessages
|
||||
case pinnedMessages(id: EngineMessage.Id?)
|
||||
case forwardedMessages(ids: [EngineMessage.Id], options: Signal<ForwardOptions, NoError>)
|
||||
|
||||
public static func ==(lhs: ChatControllerSubject, rhs: ChatControllerSubject) -> Bool {
|
||||
switch lhs {
|
||||
case let .message(lhsId, lhsHighlight, lhsTimecode):
|
||||
if case let .message(rhsId, rhsHighlight, rhsTimecode) = rhs, lhsId == rhsId && lhsHighlight == rhsHighlight && lhsTimecode == rhsTimecode {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .scheduledMessages:
|
||||
if case .scheduledMessages = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pinnedMessages(id):
|
||||
if case .pinnedMessages(id) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .forwardedMessages(lhsIds, _):
|
||||
if case let .forwardedMessages(rhsIds, _) = rhs, lhsIds == rhsIds {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatControllerPresentationMode: Equatable {
|
||||
|
@ -6,6 +6,7 @@ import SwiftSignalKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import UniversalMediaPlayer
|
||||
import TelegramPresentationData
|
||||
|
||||
public enum ChatControllerInteractionOpenMessageMode {
|
||||
case `default`
|
||||
@ -18,6 +19,7 @@ public enum ChatControllerInteractionOpenMessageMode {
|
||||
|
||||
public final class OpenChatMessageParams {
|
||||
public let context: AccountContext
|
||||
public let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
public let chatLocation: ChatLocation?
|
||||
public let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?
|
||||
public let message: Message
|
||||
@ -44,6 +46,7 @@ public final class OpenChatMessageParams {
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||
chatLocation: ChatLocation?,
|
||||
chatLocationContextHolder: Atomic<ChatLocationContextHolder?>?,
|
||||
message: Message,
|
||||
@ -69,6 +72,7 @@ public final class OpenChatMessageParams {
|
||||
centralItemUpdated: ((MessageId) -> Void)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.chatLocation = chatLocation
|
||||
self.chatLocationContextHolder = chatLocationContextHolder
|
||||
self.message = message
|
||||
|
@ -66,7 +66,7 @@ public enum PeerSelectionControllerSendMode {
|
||||
|
||||
public protocol PeerSelectionController: ViewController {
|
||||
var peerSelected: ((Peer) -> Void)? { get set }
|
||||
var multiplePeersSelected: (([Peer], [PeerId: Peer], NSAttributedString, PeerSelectionControllerSendMode, Bool) -> Void)? { get set }
|
||||
var multiplePeersSelected: (([Peer], [PeerId: Peer], NSAttributedString, PeerSelectionControllerSendMode, ChatInterfaceForwardOptionsState?) -> Void)? { get set }
|
||||
var inProgress: Bool { get set }
|
||||
var customDismiss: (() -> Void)? { get set }
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ public final class AnimationNode : ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
view.logHierarchyKeypaths()
|
||||
|
||||
return view
|
||||
} else {
|
||||
return LOTAnimationView()
|
||||
|
@ -264,7 +264,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
public let composeDisableUrlPreview: String?
|
||||
public let replyMessageId: EngineMessage.Id?
|
||||
public let forwardMessageIds: [EngineMessage.Id]?
|
||||
public let forwardMessageHideSendersNames: Bool
|
||||
public let forwardOptionsState: ChatInterfaceForwardOptionsState?
|
||||
public let editMessage: ChatEditMessageState?
|
||||
public let selectionState: ChatInterfaceSelectionState?
|
||||
public let messageActionsState: ChatInterfaceMessageActionsState
|
||||
@ -307,7 +307,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
self.composeDisableUrlPreview = nil
|
||||
self.replyMessageId = nil
|
||||
self.forwardMessageIds = nil
|
||||
self.forwardMessageHideSendersNames = false
|
||||
self.forwardOptionsState = nil
|
||||
self.editMessage = nil
|
||||
self.selectionState = nil
|
||||
self.messageActionsState = ChatInterfaceMessageActionsState()
|
||||
@ -317,13 +317,13 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
self.inputLanguage = nil
|
||||
}
|
||||
|
||||
public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: EngineMessage.Id?, forwardMessageIds: [EngineMessage.Id]?, forwardMessageHideSendersNames: Bool, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, silentPosting: Bool, inputLanguage: String?) {
|
||||
public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: EngineMessage.Id?, forwardMessageIds: [EngineMessage.Id]?, forwardOptionsState: ChatInterfaceForwardOptionsState?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, silentPosting: Bool, inputLanguage: String?) {
|
||||
self.timestamp = timestamp
|
||||
self.composeInputState = composeInputState
|
||||
self.composeDisableUrlPreview = composeDisableUrlPreview
|
||||
self.replyMessageId = replyMessageId
|
||||
self.forwardMessageIds = forwardMessageIds
|
||||
self.forwardMessageHideSendersNames = forwardMessageHideSendersNames
|
||||
self.forwardOptionsState = forwardOptionsState
|
||||
self.editMessage = editMessage
|
||||
self.selectionState = selectionState
|
||||
self.messageActionsState = messageActionsState
|
||||
@ -360,7 +360,11 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
} else {
|
||||
self.forwardMessageIds = nil
|
||||
}
|
||||
self.forwardMessageHideSendersNames = ((try? container.decodeIfPresent(Int32.self, forKey: "fhn")) ?? 0) != 0
|
||||
if let forwardOptionsState = try? container.decodeIfPresent(ChatInterfaceForwardOptionsState.self, forKey: "fo") {
|
||||
self.forwardOptionsState = forwardOptionsState
|
||||
} else {
|
||||
self.forwardOptionsState = nil
|
||||
}
|
||||
if let editMessage = try? container.decodeIfPresent(ChatEditMessageState.self, forKey: "em") {
|
||||
self.editMessage = editMessage
|
||||
} else {
|
||||
@ -410,7 +414,11 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
} else {
|
||||
try container.encodeNil(forKey: "fm")
|
||||
}
|
||||
try container.encode((self.forwardMessageHideSendersNames ? 1 : 0) as Int32, forKey: "fhn")
|
||||
if let forwardOptionsState = self.forwardOptionsState {
|
||||
try container.encode(forwardOptionsState, forKey: "fo")
|
||||
} else {
|
||||
try container.encodeNil(forKey: "fo")
|
||||
}
|
||||
if let editMessage = self.editMessage {
|
||||
try container.encode(editMessage, forKey: "em")
|
||||
} else {
|
||||
@ -451,7 +459,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
} else if (lhs.forwardMessageIds != nil) != (rhs.forwardMessageIds != nil) {
|
||||
return false
|
||||
}
|
||||
if lhs.forwardMessageHideSendersNames != rhs.forwardMessageHideSendersNames {
|
||||
if lhs.forwardOptionsState != rhs.forwardOptionsState {
|
||||
return false
|
||||
}
|
||||
if lhs.messageActionsState != rhs.messageActionsState {
|
||||
@ -475,11 +483,11 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||
let updatedComposeInputState = inputState
|
||||
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedComposeDisableUrlPreview(_ disableUrlPreview: String?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: disableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: disableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||
@ -491,19 +499,19 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
updatedComposeInputState = inputState
|
||||
}
|
||||
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedReplyMessageId(_ replyMessageId: EngineMessage.Id?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedForwardMessageIds(_ forwardMessageIds: [EngineMessage.Id]?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedForwardMessageHideSendersNames(_ forwardMessageHideSendersNames: Bool) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
public func withUpdatedForwardOptionsState(_ forwardOptionsState: ChatInterfaceForwardOptionsState?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedSelectedMessages(_ messageIds: [EngineMessage.Id]) -> ChatInterfaceState {
|
||||
@ -514,7 +522,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
for messageId in messageIds {
|
||||
selectedIds.insert(messageId)
|
||||
}
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withToggledSelectedMessages(_ messageIds: [EngineMessage.Id], value: Bool) -> ChatInterfaceState {
|
||||
@ -529,39 +537,39 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
selectedIds.remove(messageId)
|
||||
}
|
||||
}
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withoutSelectionState() -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedSilentPosting(_ silentPosting: Bool) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: silentPosting, inputLanguage: self.inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: silentPosting, inputLanguage: self.inputLanguage)
|
||||
}
|
||||
|
||||
public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardMessageHideSendersNames: self.forwardMessageHideSendersNames, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: inputLanguage)
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: inputLanguage)
|
||||
}
|
||||
|
||||
public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState {
|
||||
|
@ -891,7 +891,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}).start()
|
||||
|
||||
let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled], multipleSelection: true))
|
||||
peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, peerMap, messageText, mode, hideSendersNames in
|
||||
peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, peerMap, messageText, mode, forwardOptions in
|
||||
guard let strongSelf = self, let strongController = peerSelectionController else {
|
||||
return
|
||||
}
|
||||
@ -913,9 +913,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}
|
||||
|
||||
var attributes: [MessageAttribute] = []
|
||||
if hideSendersNames {
|
||||
attributes.append(ForwardHideSendersNamesMessageAttribute())
|
||||
}
|
||||
attributes.append(ForwardOptionsMessageAttribute(hideNames: forwardOptions?.hideNames == true, hideCaptions: forwardOptions?.hideCaptions == true))
|
||||
|
||||
result.append(contentsOf: messageIds.map { messageId -> EnqueueMessage in
|
||||
return .forward(source: messageId, grouping: .auto, attributes: attributes, correlationId: nil)
|
||||
|
@ -1725,7 +1725,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
})
|
||||
}
|
||||
|
||||
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context, displayBackground: true)
|
||||
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context, presentationData: self.presentationData, displayBackground: true)
|
||||
mediaAccessoryPanel.containerNode.headerNode.displayScrubber = item.playbackData?.type != .instantVideo
|
||||
mediaAccessoryPanel.getController = { [weak self] in
|
||||
return self?.navigationController?.topViewController as? ViewController
|
||||
|
@ -104,7 +104,7 @@ final class ChatListInputActivitiesNode: ASDisplayNode {
|
||||
case .typingText:
|
||||
text = strings.DialogList_SingleTypingSuffix(peerTitle).string
|
||||
case .choosingSticker:
|
||||
text = ""
|
||||
text = strings.DialogList_SingleChoosingStickerSuffix(peerTitle).string
|
||||
case .speakingInGroupCall:
|
||||
text = ""
|
||||
}
|
||||
|
@ -90,10 +90,6 @@ private class ChatChoosingStickerActivityIndicatorNode: ChatTitleActivityIndicat
|
||||
|
||||
context.strokeEllipse(in: CGRect(x: rightCenter.x - eyeWidth / 2.0, y: rightCenter.y - eyeHeight / 2.0, width: eyeWidth, height: eyeHeight))
|
||||
context.fillEllipse(in: CGRect(x: rightCenter.x - pupilSize / 2.0 + pupilCenter.x * eyeWidth / 4.0, y: rightCenter.y - pupilSize / 2.0, width: pupilSize, height: pupilSize))
|
||||
|
||||
// context.strokeEllipse(in: CGRect(x: 0.0, y: 0.0, width: 10.0, height: 20.0))
|
||||
// context.fillEllipse(in: CGRect(x: , y: , width: 4.0, height: 4.0))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +101,7 @@ class ChatChoosingStickerActivityContentNode: ChatTitleActivityContentNode {
|
||||
self.indicatorNode = ChatChoosingStickerActivityIndicatorNode(color: color)
|
||||
|
||||
var text = text
|
||||
self.advanced = text.string == "choosing sticker"
|
||||
self.advanced = text.string == "choosing a sticker"
|
||||
if self.advanced {
|
||||
let mutable = text.mutableCopy() as? NSMutableAttributedString
|
||||
mutable?.replaceCharacters(in: NSMakeRange(2, 2), with: " ")
|
||||
@ -121,6 +117,7 @@ class ChatChoosingStickerActivityContentNode: ChatTitleActivityContentNode {
|
||||
|
||||
override func updateLayout(_ constrainedSize: CGSize, offset: CGFloat, alignment: NSTextAlignment) -> CGSize {
|
||||
let size = self.textNode.updateLayout(constrainedSize)
|
||||
let scale = size.height / 15.0
|
||||
let indicatorSize = CGSize(width: 24.0, height: 16.0)
|
||||
let originX: CGFloat
|
||||
let indicatorOriginX: CGFloat
|
||||
@ -131,15 +128,30 @@ class ChatChoosingStickerActivityContentNode: ChatTitleActivityContentNode {
|
||||
originX = floorToScreenPixels((indicatorSize.width - size.width) / 2.0)
|
||||
}
|
||||
} else {
|
||||
originX = indicatorSize.width
|
||||
if self.advanced {
|
||||
originX = 4.0
|
||||
} else {
|
||||
originX = indicatorSize.width * scale - 1.0
|
||||
}
|
||||
}
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: originX, y: 0.0), size: size)
|
||||
if self.advanced {
|
||||
indicatorOriginX = self.textNode.frame.minX + 14.0 + UIScreenPixel
|
||||
if case .center = alignment {
|
||||
indicatorOriginX = self.textNode.frame.minX + 26.0 + UIScreenPixel
|
||||
} else {
|
||||
var scale = scale
|
||||
if scale > 1.25 {
|
||||
scale *= 0.95
|
||||
}
|
||||
indicatorOriginX = self.textNode.frame.minX + floorToScreenPixels(26.0 * scale) + UIScreenPixel
|
||||
}
|
||||
} else {
|
||||
indicatorOriginX = self.textNode.frame.minX - indicatorSize.width
|
||||
indicatorOriginX = self.textNode.frame.minX - (indicatorSize.width * scale) / 2.0 + 3.0
|
||||
}
|
||||
self.indicatorNode.frame = CGRect(origin: CGPoint(x: indicatorOriginX, y: 0.0), size: indicatorSize)
|
||||
self.indicatorNode.bounds = CGRect(origin: CGPoint(), size: indicatorSize)
|
||||
self.indicatorNode.position = CGPoint(x: indicatorOriginX, y: size.height / 2.0)
|
||||
self.indicatorNode.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||
|
||||
return CGSize(width: size.width + indicatorSize.width, height: size.height)
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ private let animationDurationFactor: Double = 1.0
|
||||
|
||||
public protocol ContextControllerProtocol {
|
||||
var useComplexItemsTransitionAnimation: Bool { get set }
|
||||
var immediateItemsTransitionAnimation: Bool { get set }
|
||||
|
||||
func setItems(_ items: Signal<[ContextMenuItem], NoError>)
|
||||
func dismiss(completion: (() -> Void)?)
|
||||
@ -119,6 +120,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
private let reactionSelected: (ReactionContextItem.Reaction) -> Void
|
||||
private let beganAnimatingOut: () -> Void
|
||||
private let attemptTransitionControllerIntoNavigation: () -> Void
|
||||
fileprivate var dismissedForCancel: (() -> Void)?
|
||||
private let getController: () -> ContextControllerProtocol?
|
||||
private weak var gesture: ContextGesture?
|
||||
private var displayTextSelectionTip: Bool
|
||||
@ -157,6 +159,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
||||
private var animatedIn = false
|
||||
private var isAnimatingOut = false
|
||||
|
||||
private let itemsDisposable = MetaDisposable()
|
||||
@ -477,6 +480,10 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
|
||||
@objc private func dimNodeTapped() {
|
||||
guard self.animatedIn else {
|
||||
return
|
||||
}
|
||||
self.dismissedForCancel?()
|
||||
self.beginDismiss(.default)
|
||||
}
|
||||
|
||||
@ -649,7 +656,9 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
|
||||
self.actionsContainerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
let contentContainerOffset = CGPoint(x: localContentSourceFrame.center.x - self.contentContainerNode.frame.center.x, y: localContentSourceFrame.center.y - self.contentContainerNode.frame.center.y)
|
||||
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true, completion: { [weak self] _ in
|
||||
self?.animatedIn = true
|
||||
})
|
||||
}
|
||||
case let .extracted(extracted, keepInPlace):
|
||||
let springDuration: Double = 0.42 * animationDurationFactor
|
||||
@ -689,6 +698,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
let contentContainerOffset = CGPoint(x: localContentSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localContentSourceFrame.center.y - self.contentContainerNode.frame.center.y - contentParentNode.contentRect.minY)
|
||||
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: contentDuration, initialVelocity: 0.0, damping: springDamping, additive: true, completion: { [weak self] _ in
|
||||
self?.clippingNode.view.mask = nil
|
||||
self?.animatedIn = true
|
||||
})
|
||||
contentParentNode.applyAbsoluteOffsetSpring?(-contentContainerOffset.y, springDuration, springDamping)
|
||||
}
|
||||
@ -732,7 +742,9 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
}
|
||||
self.actionsContainerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true, completion: { [weak self] _ in
|
||||
self?.animatedIn = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1164,6 +1176,10 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
|
||||
private func setItems(items: [ContextMenuItem]) {
|
||||
if let _ = self.currentItems, !self.didCompleteAnimationIn && self.getController()?.immediateItemsTransitionAnimation == true {
|
||||
return
|
||||
}
|
||||
|
||||
self.currentItems = items
|
||||
|
||||
let previousActionsContainerNode = self.actionsContainerNode
|
||||
@ -1600,7 +1616,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
|
||||
if let previousActionsContainerNode = previousActionsContainerNode {
|
||||
if transition.isAnimated {
|
||||
if transition.isAnimated && self.getController()?.immediateItemsTransitionAnimation == false {
|
||||
if previousActionsContainerNode.hasAdditionalActions && !self.actionsContainerNode.hasAdditionalActions && self.getController()?.useComplexItemsTransitionAnimation == true {
|
||||
var initialFrame = self.actionsContainerNode.frame
|
||||
let delta = (previousActionsContainerNode.frame.height - self.actionsContainerNode.frame.height)
|
||||
@ -1715,9 +1731,17 @@ public final class ContextControllerReferenceViewInfo {
|
||||
}
|
||||
|
||||
public protocol ContextReferenceContentSource: AnyObject {
|
||||
var shouldBeDismissed: Signal<Bool, NoError> { get }
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo?
|
||||
}
|
||||
|
||||
public extension ContextReferenceContentSource {
|
||||
var shouldBeDismissed: Signal<Bool, NoError> {
|
||||
return .single(false)
|
||||
}
|
||||
}
|
||||
|
||||
public final class ContextControllerTakeViewInfo {
|
||||
public let contentContainingNode: ContextExtractedContentContainingNode
|
||||
public let contentAreaInScreenSpace: CGRect
|
||||
@ -1812,8 +1836,14 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
||||
|
||||
public var reactionSelected: ((ReactionContextItem.Reaction) -> Void)?
|
||||
public var dismissed: (() -> Void)?
|
||||
public var dismissedForCancel: (() -> Void)? {
|
||||
didSet {
|
||||
self.controllerNode.dismissedForCancel = self.dismissedForCancel
|
||||
}
|
||||
}
|
||||
|
||||
public var useComplexItemsTransitionAnimation = false
|
||||
public var immediateItemsTransitionAnimation = false
|
||||
|
||||
private var shouldBeDismissedDisposable: Disposable?
|
||||
|
||||
@ -1830,8 +1860,18 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
|
||||
switch source {
|
||||
case .reference:
|
||||
case let .reference(referenceSource):
|
||||
self.statusBar.statusBarStyle = .Ignore
|
||||
|
||||
self.shouldBeDismissedDisposable = (referenceSource.shouldBeDismissed
|
||||
|> filter { $0 }
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.dismiss(result: .default, completion: {})
|
||||
})
|
||||
case let .extracted(extractedSource):
|
||||
if extractedSource.blurBackground {
|
||||
self.statusBar.statusBarStyle = .Hide
|
||||
@ -1866,7 +1906,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = ContextControllerNode(account: self.account, controller: self, presentationData: self.presentationData, source: self.source, items: self.items, reactionItems: self.reactionItems, beginDismiss: { [weak self] result in
|
||||
self?.dismiss(result: result, completion: nil)
|
||||
}, recognizer: self.recognizer, gesture: self.gesture, reactionSelected: { [weak self] value in
|
||||
}, recognizer: self.recognizer, gesture: self.gesture, reactionSelected: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1887,7 +1927,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
||||
break
|
||||
}
|
||||
}, displayTextSelectionTip: self.displayTextSelectionTip)
|
||||
|
||||
self.controllerNode.dismissedForCancel = self.dismissedForCancel
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
self._ready.set(combineLatest(queue: .mainQueue(), self.controllerNode.itemsReady.get(), self.controllerNode.contentReady.get())
|
||||
|
@ -32,6 +32,7 @@ extension PeekControllerTheme {
|
||||
|
||||
public final class PeekController: ViewController, ContextControllerProtocol {
|
||||
public var useComplexItemsTransitionAnimation: Bool = false
|
||||
public var immediateItemsTransitionAnimation = false
|
||||
|
||||
public func setItems(_ items: Signal<[ContextMenuItem], NoError>) {
|
||||
|
||||
|
@ -142,7 +142,11 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode {
|
||||
}
|
||||
}
|
||||
case .removeFromGroup:
|
||||
text = strings.VoiceChat_RemoveAndBanPeerConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder), chatPeer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||
if case let .channel(channel) = chatPeer, case .broadcast = channel.info {
|
||||
text = strings.LiveStream_RemoveAndBanPeerConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder), chatPeer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||
} else {
|
||||
text = strings.VoiceChat_RemoveAndBanPeerConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder), chatPeer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||
}
|
||||
case .removeFromChannel:
|
||||
text = strings.VoiceChat_RemovePeerConfirmationChannel(peer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||
default:
|
||||
|
@ -328,6 +328,8 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
private var reorderInProgress: Bool = false
|
||||
private var reorderingItemsCompleted: (() -> Void)?
|
||||
private var reorderScrollStartTimestamp: Double?
|
||||
private var reorderScrollUpdateTimestamp: Double?
|
||||
private var reorderLastTimestamp: Double?
|
||||
public var reorderedItemHasShadow = true
|
||||
|
||||
private let waitingForNodesDisposable = MetaDisposable()
|
||||
@ -562,14 +564,22 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
return
|
||||
}
|
||||
|
||||
let timestamp = CACurrentMediaTime()
|
||||
if let reorderItemNode = reorderNode.itemNode, let reorderItemIndex = reorderItemNode.index, reorderItemNode.supernode == self {
|
||||
let verticalOffset = verticalTopOffset
|
||||
var closestIndex: (Int, CGFloat)?
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
if let itemNodeIndex = self.itemNodes[i].index, itemNodeIndex != reorderItemIndex {
|
||||
let itemFrame = self.itemNodes[i].apparentContentFrame
|
||||
let itemOffset = itemFrame.midY
|
||||
let deltaOffset = itemOffset - verticalOffset
|
||||
|
||||
let offsetToMin = itemFrame.minY - verticalOffset
|
||||
let offsetToMax = itemFrame.maxY - verticalOffset
|
||||
let deltaOffset: CGFloat
|
||||
if abs(offsetToMin) > abs(offsetToMax) {
|
||||
deltaOffset = offsetToMax
|
||||
} else {
|
||||
deltaOffset = offsetToMin
|
||||
}
|
||||
if let (_, closestOffset) = closestIndex {
|
||||
if abs(deltaOffset) < abs(closestOffset) {
|
||||
closestIndex = (itemNodeIndex, deltaOffset)
|
||||
@ -580,7 +590,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
}
|
||||
}
|
||||
if let (closestIndexValue, offset) = closestIndex {
|
||||
//print("closest \(closestIndexValue) offset \(offset)")
|
||||
// print("closest \(closestIndexValue) offset \(offset)")
|
||||
var toIndex: Int
|
||||
if offset > 0 {
|
||||
toIndex = closestIndexValue
|
||||
@ -594,7 +604,12 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
}
|
||||
}
|
||||
if toIndex != reorderItemNode.index {
|
||||
if let reorderLastTimestamp = self.reorderLastTimestamp, timestamp < reorderLastTimestamp + 0.2 {
|
||||
return
|
||||
}
|
||||
if reorderNode.currentState?.0 != reorderItemIndex || reorderNode.currentState?.1 != toIndex {
|
||||
self.reorderLastTimestamp = timestamp
|
||||
|
||||
reorderNode.currentState = (reorderItemIndex, toIndex)
|
||||
//print("reorder \(reorderItemIndex) to \(toIndex) offset \(offset)")
|
||||
if self.reorderFeedbackDisposable == nil {
|
||||
@ -2126,7 +2141,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
if let accessoryItemNode = node.accessoryItemNode {
|
||||
node.layoutAccessoryItemNode(accessoryItemNode, leftInset: listInsets.left, rightInset: listInsets.right)
|
||||
}
|
||||
apply().1(ListViewItemApply(isOnScreen: visibleBounds.intersects(nodeFrame)))
|
||||
apply().1(ListViewItemApply(isOnScreen: visibleBounds.intersects(nodeFrame), timestamp: timestamp))
|
||||
self.itemNodes.insert(node, at: nodeIndex)
|
||||
|
||||
var offsetHeight = node.apparentHeight
|
||||
@ -2548,7 +2563,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
var apparentFrame = node.apparentFrame
|
||||
apparentFrame.size.height = updatedApparentHeight
|
||||
|
||||
apply().1(ListViewItemApply(isOnScreen: visibleBounds.intersects(apparentFrame)))
|
||||
apply().1(ListViewItemApply(isOnScreen: visibleBounds.intersects(apparentFrame), timestamp: timestamp))
|
||||
|
||||
var offsetRanges = OffsetRanges()
|
||||
|
||||
@ -3981,7 +3996,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
|
||||
var offset: CGFloat = 6.0
|
||||
if let reorderScrollStartTimestamp = self.reorderScrollStartTimestamp, reorderScrollStartTimestamp + 2.0 < timestamp {
|
||||
offset *= 2.0
|
||||
offset *= 1.5
|
||||
}
|
||||
if reorderOffset < effectiveInsets.top + 10.0 {
|
||||
if self.itemNodes[0].apparentFrame.minY < effectiveInsets.top {
|
||||
@ -4086,7 +4101,13 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
self.enqueueUpdateVisibleItems(synchronous: false)
|
||||
}
|
||||
|
||||
self.checkItemReordering()
|
||||
if scrollingForReorder {
|
||||
if let reorderScrollUpdateTimestamp = self.reorderScrollUpdateTimestamp, timestamp < reorderScrollUpdateTimestamp + 0.05 {
|
||||
return
|
||||
}
|
||||
self.reorderScrollUpdateTimestamp = timestamp
|
||||
self.checkItemReordering(force: true)
|
||||
}
|
||||
}
|
||||
|
||||
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
|
@ -32,9 +32,11 @@ public struct ListViewItemConfigureNodeFlags: OptionSet {
|
||||
|
||||
public struct ListViewItemApply {
|
||||
public let isOnScreen: Bool
|
||||
public let timestamp: Double?
|
||||
|
||||
public init(isOnScreen: Bool) {
|
||||
public init(isOnScreen: Bool, timestamp: Double? = nil) {
|
||||
self.isOnScreen = isOnScreen
|
||||
self.timestamp = timestamp
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ public final class ListViewReorderingGestureRecognizer: UIGestureRecognizer {
|
||||
|
||||
private func startLongPressTimer() {
|
||||
self.longPressTimer?.invalidate()
|
||||
let longPressTimer = SwiftSignalKit.Timer(timeout: 0.8, repeat: false, completion: { [weak self] in
|
||||
let longPressTimer = SwiftSignalKit.Timer(timeout: 0.6, repeat: false, completion: { [weak self] in
|
||||
self?.longPressTimerFired()
|
||||
}, queue: Queue.mainQueue())
|
||||
self.longPressTimer = longPressTimer
|
||||
|
@ -136,7 +136,7 @@ public extension String {
|
||||
continue
|
||||
}
|
||||
string.unicodeScalars.append(scalar)
|
||||
if scalar.value == 0x2764, self.unicodeScalars.count > 1, self.emojis.count == 1 {
|
||||
if scalar.value == 0x2764 && self.unicodeScalars.count < 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ objc_library(
|
||||
]),
|
||||
copts = [
|
||||
"-I{}/PublicHeaders/LegacyComponents".format(package_name()),
|
||||
"-Werror",
|
||||
#"-Werror",
|
||||
],
|
||||
includes = [
|
||||
"PublicHeaders",
|
||||
|
@ -322,7 +322,7 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f;
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (bool)isTracking
|
||||
- (BOOL)isTracking
|
||||
{
|
||||
return _knobView.highlighted;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
@implementation UICollectionView (TGTransitioning)
|
||||
|
||||
- (BOOL)isTransitionInProgress
|
||||
- (bool)isTransitionInProgress
|
||||
{
|
||||
return ([self tg_transitionData] != nil);
|
||||
}
|
||||
|
@ -70,11 +70,11 @@ public final class LocationPickerController: ViewController {
|
||||
|
||||
private var interaction: LocationPickerInteraction?
|
||||
|
||||
public init(context: AccountContext, mode: LocationPickerMode, completion: @escaping (TelegramMediaMap, String?) -> Void) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: LocationPickerMode, completion: @escaping (TelegramMediaMap, String?) -> Void) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.completion = completion
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(.clear), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
|
||||
@ -85,7 +85,7 @@ public final class LocationPickerController: ViewController {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.searchPressed))
|
||||
self.navigationItem.rightBarButtonItem?.accessibilityLabel = self.presentationData.strings.Common_Search
|
||||
|
||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
guard let strongSelf = self, strongSelf.presentationData.theme !== presentationData.theme else {
|
||||
return
|
||||
|
@ -85,12 +85,12 @@ public final class LocationViewController: ViewController {
|
||||
|
||||
private var rightBarButtonAction: LocationViewRightBarButton = .none
|
||||
|
||||
public init(context: AccountContext, subject: Message, params: LocationViewParams) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, subject: Message, params: LocationViewParams) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
self.showAll = params.showAll
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(.clear), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
|
||||
@ -99,7 +99,7 @@ public final class LocationViewController: ViewController {
|
||||
self.title = self.presentationData.strings.Map_LocationTitle
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Close, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
|
||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
guard let strongSelf = self, strongSelf.presentationData.theme !== presentationData.theme else {
|
||||
return
|
||||
|
@ -293,3 +293,22 @@ public final class CachedAnimatedStickerRepresentation: CachedMediaResourceRepre
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class CachedPreparedPatternWallpaperRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
return "prepared-pattern-wallpaper"
|
||||
}
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
if to is CachedPreparedPatternWallpaperRepresentation {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,11 +421,11 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
_cleanupSessionIdsByAuthKeyId = [[NSMutableDictionary alloc] initWithDictionary:cleanupSessionIdsByAuthKeyId];
|
||||
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTContext#%llx: received keychain globalTimeDifference:%f datacenterAuthInfoById:%@]", (intptr_t)self, _globalTimeDifference, _datacenterAuthInfoById);
|
||||
MTLog(@"[MTContext#%" PRIxPTR ": received keychain globalTimeDifference:%f datacenterAuthInfoById:%@]", (intptr_t)self, _globalTimeDifference, _datacenterAuthInfoById);
|
||||
}
|
||||
} else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTContext#%llx: received keychain nil]", (intptr_t)self);
|
||||
MTLog(@"[MTContext#%" PRIxPTR ": received keychain nil]", (intptr_t)self);
|
||||
}
|
||||
}
|
||||
}];
|
||||
@ -484,7 +484,7 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
_globalTimeDifference = globalTimeDifference;
|
||||
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTContext#%llx: global time difference changed: %.1fs]", (intptr_t)self, globalTimeDifference);
|
||||
MTLog(@"[MTContext#%" PRIxPTR ": global time difference changed: %.1fs]", (intptr_t)self, globalTimeDifference);
|
||||
}
|
||||
|
||||
[_keychain setObject:@(_globalTimeDifference) forKey:@"globalTimeDifference" group:@"temp"];
|
||||
@ -506,7 +506,7 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
if (addressSet != nil && datacenterId != 0)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTContext#%llx: address set updated for %d]", (intptr_t)self, datacenterId);
|
||||
MTLog(@"[MTContext#%" PRIxPTR ": address set updated for %d]", (intptr_t)self, datacenterId);
|
||||
}
|
||||
|
||||
bool updateSchemes = forceUpdateSchemes;
|
||||
@ -599,7 +599,7 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
if (updated)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTContext#%llx: added address %@ for datacenter %d]", (intptr_t)self, address, datacenterId);
|
||||
MTLog(@"[MTContext#%" PRIxPTR ": added address %@ for datacenter %d]", (intptr_t)self, address, datacenterId);
|
||||
}
|
||||
|
||||
_datacenterAddressSetById[@(datacenterId)] = addressSet;
|
||||
@ -638,7 +638,7 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
if (MTLogEnabled()) {
|
||||
MTDatacenterAuthInfo *persistentInfo = _datacenterAuthInfoById[authInfoMapIntegerKey((int32_t)datacenterId, MTDatacenterAuthInfoSelectorPersistent)];
|
||||
|
||||
MTLog(@"[MTContext#%llx: auth info updated for %d selector %d to %@ (persistent key id is %llu)]", (intptr_t)self, datacenterId, selector, authInfo, persistentInfo.authKeyId);
|
||||
MTLog(@"[MTContext#%" PRIxPTR ": auth info updated for %d selector %d to %@ (persistent key id is %llu)]", (intptr_t)self, datacenterId, selector, authInfo, persistentInfo.authKeyId);
|
||||
}
|
||||
|
||||
[_keychain setObject:_datacenterAuthInfoById forKey:@"datacenterAuthInfoById" group:@"persistent"];
|
||||
@ -713,7 +713,7 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
NSArray *currentListeners = [[NSArray alloc] initWithArray:_changeListeners];
|
||||
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTContext#%llx: %@ transport scheme updated for %d: %@]", (intptr_t)self, media ? @"media" : @"generic", datacenterId, transportScheme);
|
||||
MTLog(@"[MTContext#%" PRIxPTR ": %@ transport scheme updated for %d: %@]", (intptr_t)self, media ? @"media" : @"generic", datacenterId, transportScheme);
|
||||
}
|
||||
|
||||
for (id<MTContextChangeListener> listener in currentListeners) {
|
||||
|
@ -117,7 +117,7 @@
|
||||
|
||||
if (request.requestContext.messageId != 0) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTRequestMessageService#%llx drop %" PRId64 "]", (intptr_t)self, request.requestContext.messageId);
|
||||
MTLog(@"[MTRequestMessageService#%" PRIxPTR " drop %" PRId64 "]", (intptr_t)self, request.requestContext.messageId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -933,8 +933,8 @@
|
||||
request.requestContext.responseMessageId = responseMessageId;
|
||||
return true;
|
||||
} else {
|
||||
MTLog(@"[MTRequestMessageService#%llx will not request message %" PRId64 " (transaction was not completed)]", (intptr_t)self, messageId);
|
||||
MTLog(@"[MTRequestMessageService#%llx but today it will]", (intptr_t)self);
|
||||
MTLog(@"[MTRequestMessageService#%" PRIxPTR " will not request message %" PRId64 " (transaction was not completed)]", (intptr_t)self, messageId);
|
||||
MTLog(@"[MTRequestMessageService#%" PRIxPTR " but today it will]", (intptr_t)self);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -861,14 +861,14 @@ struct ctr_state {
|
||||
if (MTLogEnabled()) {
|
||||
if (strongSelf->_socksIp != nil) {
|
||||
if (strongSelf->_socksUsername.length == 0) {
|
||||
MTLog(@"[MTTcpConnection#%llx connecting to %@:%d via %@:%d]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port, strongSelf->_socksIp, (int)strongSelf->_socksPort);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " connecting to %@:%d via %@:%d]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port, strongSelf->_socksIp, (int)strongSelf->_socksPort);
|
||||
} else {
|
||||
MTLog(@"[MTTcpConnection#%llx connecting to %@:%d via %@:%d using %@:%@]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port, strongSelf->_socksIp, (int)strongSelf->_socksPort, strongSelf->_socksUsername, strongSelf->_socksPassword);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " connecting to %@:%d via %@:%d using %@:%@]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port, strongSelf->_socksIp, (int)strongSelf->_socksPort, strongSelf->_socksUsername, strongSelf->_socksPassword);
|
||||
}
|
||||
} else if (strongSelf->_mtpIp != nil) {
|
||||
MTLog(@"[MTTcpConnection#%llx connecting to %@:%d via mtp://%@:%d:%@]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port, strongSelf->_mtpIp, (int)strongSelf->_mtpPort, strongSelf->_mtpSecret);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " connecting to %@:%d via mtp://%@:%d:%@]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port, strongSelf->_mtpIp, (int)strongSelf->_mtpPort, strongSelf->_mtpSecret);
|
||||
} else {
|
||||
MTLog(@"[MTTcpConnection#%llx connecting to %@:%d]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " connecting to %@:%d]", (intptr_t)strongSelf, strongSelf->_scheme.address.ip, (int)strongSelf->_scheme.address.port);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1280,7 +1280,7 @@ struct ctr_state {
|
||||
_responseTimeoutTimer = nil;
|
||||
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpConnection#%llx response timeout]", (intptr_t)self);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " response timeout]", (intptr_t)self);
|
||||
}
|
||||
[self closeAndNotifyWithError:true];
|
||||
}
|
||||
@ -1421,7 +1421,7 @@ struct ctr_state {
|
||||
|
||||
if (resp.Reply != 0x00) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** %llx %s: socks5 connect failed, error 0x%02x", (intptr_t)self, __PRETTY_FUNCTION__, resp.Reply);
|
||||
MTLog(@"***** " PRIxPTR " %s: socks5 connect failed, error 0x%02x", (intptr_t)self, __PRETTY_FUNCTION__, resp.Reply);
|
||||
}
|
||||
[self closeAndNotifyWithError:true];
|
||||
return;
|
||||
@ -1772,7 +1772,7 @@ struct ctr_state {
|
||||
} else {
|
||||
if (length > 16 * 1024 * 1024) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpConnection#%llx received invalid length %d]", (intptr_t)self, length);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " received invalid length %d]", (intptr_t)self, length);
|
||||
}
|
||||
[self closeAndNotifyWithError:true];
|
||||
} else {
|
||||
@ -1848,7 +1848,7 @@ struct ctr_state {
|
||||
}
|
||||
} else if (header == 0 && packetData.length < 16) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpConnection#%llx received nop packet]", (intptr_t)self);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " received nop packet]", (intptr_t)self);
|
||||
}
|
||||
ignorePacket = true;
|
||||
}
|
||||
@ -1907,12 +1907,12 @@ struct ctr_state {
|
||||
{
|
||||
if (error != nil) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpConnection#%llx disconnected from %@ (%@)]", (intptr_t)self, _scheme.address.ip, error);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " disconnected from %@ (%@)]", (intptr_t)self, _scheme.address.ip, error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpConnection#%llx disconnected from %@]", (intptr_t)self, _scheme.address.ip);
|
||||
MTLog(@"[MTTcpConnection#%" PRIxPTR " disconnected from %@]", (intptr_t)self, _scheme.address.ip);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,7 +573,7 @@ static const NSTimeInterval MTTcpTransportSleepWatchdogTimeout = 60.0;
|
||||
if (!transportContext.didSendActualizationPingAfterConnection)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpTransport#%llx unlocking transaction processing due to connection context update task]", (intptr_t)self);
|
||||
MTLog(@"[MTTcpTransport#%" PRIxPTR " unlocking transaction processing due to connection context update task]", (intptr_t)self);
|
||||
}
|
||||
transportContext.isWaitingForTransactionToBecomeReady = false;
|
||||
transportContext.transactionLockTime = 0.0;
|
||||
@ -581,7 +581,7 @@ static const NSTimeInterval MTTcpTransportSleepWatchdogTimeout = 60.0;
|
||||
else if (CFAbsoluteTimeGetCurrent() > transportContext.transactionLockTime + 1.0)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpTransport#%llx unlocking transaction processing due to timeout]", (intptr_t)self);
|
||||
MTLog(@"[MTTcpTransport#%" PRIxPTR " unlocking transaction processing due to timeout]", (intptr_t)self);
|
||||
}
|
||||
transportContext.isWaitingForTransactionToBecomeReady = false;
|
||||
transportContext.transactionLockTime = 0.0;
|
||||
@ -589,7 +589,7 @@ static const NSTimeInterval MTTcpTransportSleepWatchdogTimeout = 60.0;
|
||||
else
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTTcpTransport#%llx skipping transaction request]", (intptr_t)self);
|
||||
MTLog(@"[MTTcpTransport#%" PRIxPTR " skipping transaction request]", (intptr_t)self);
|
||||
}
|
||||
transportContext.requestAnotherTransactionWhenReady = true;
|
||||
|
||||
|
@ -379,7 +379,7 @@ private struct ChannelAdminControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func stringForRight(strings: PresentationStrings, right: TelegramChatAdminRightsFlags, isGroup: Bool, defaultBannedRights: TelegramChatBannedRights?) -> String {
|
||||
private func stringForRight(strings: PresentationStrings, right: TelegramChatAdminRightsFlags, isGroup: Bool, isChannel: Bool, defaultBannedRights: TelegramChatBannedRights?) -> String {
|
||||
if right.contains(.canChangeInfo) {
|
||||
return isGroup ? strings.Group_EditAdmin_PermissionChangeInfo : strings.Channel_EditAdmin_PermissionChangeInfo
|
||||
} else if right.contains(.canPostMessages) {
|
||||
@ -407,7 +407,11 @@ private func stringForRight(strings: PresentationStrings, right: TelegramChatAdm
|
||||
} else if right.contains(.canBeAnonymous) {
|
||||
return strings.Channel_AdminLog_CanBeAnonymous
|
||||
} else if right.contains(.canManageCalls) {
|
||||
return strings.Channel_AdminLog_CanManageCalls
|
||||
if isChannel {
|
||||
return strings.Channel_AdminLog_CanManageLiveStreams
|
||||
} else {
|
||||
return strings.Channel_AdminLog_CanManageCalls
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
@ -498,6 +502,11 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
|
||||
if let channel = channelView.peers[channelView.peerId] as? TelegramChannel, let admin = adminView.peers[adminView.peerId] {
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, admin, adminView.peerPresences[admin.id] as? TelegramUserPresence))
|
||||
|
||||
var isChannel = false
|
||||
if case .broadcast = channel.info {
|
||||
isChannel = true
|
||||
}
|
||||
|
||||
var isCreator = false
|
||||
if let initialParticipant = initialParticipant, case .creator = initialParticipant {
|
||||
@ -566,7 +575,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), right == .canBeAnonymous))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), right == .canBeAnonymous))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -596,7 +605,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && admin.id != accountPeerId && !rightEnabledByDefault(channelPeer: channel, right: right)))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && admin.id != accountPeerId && !rightEnabledByDefault(channelPeer: channel, right: right)))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -628,7 +637,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
} else if let initialParticipant = initialParticipant, case let .member(_, _, maybeAdminInfo, _, _) = initialParticipant, let adminInfo = maybeAdminInfo {
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: channel.defaultBannedRights), right, adminInfo.rights.rights, adminInfo.rights.rights.contains(right), false))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: channel.defaultBannedRights), right, adminInfo.rights.rights, adminInfo.rights.rights.contains(right), false))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -683,6 +692,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
entries.append(.rightsTitle(presentationData.theme, presentationData.strings.Channel_EditAdmin_PermissionsHeader))
|
||||
|
||||
let isGroup = true
|
||||
let isChannel = false
|
||||
let maskRightsFlags: TelegramChatAdminRightsFlags = .groupSpecific
|
||||
let rightsOrder: [TelegramChatAdminRightsFlags] = [
|
||||
.canChangeInfo,
|
||||
@ -714,7 +724,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
var index = 0
|
||||
for right in rightsOrder {
|
||||
if accountUserRightsFlags.contains(right) {
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: group.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && accountIsCreator))
|
||||
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, isChannel: isChannel, defaultBannedRights: group.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && accountIsCreator))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
@ -642,6 +642,14 @@ public final class Message {
|
||||
self.associatedMessageIds = associatedMessageIds
|
||||
}
|
||||
|
||||
public func withUpdatedText(_ text: String) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, author: self.author, text: text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds)
|
||||
}
|
||||
|
||||
public func withUpdatedTimestamp(_ timestamp: Int32) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds)
|
||||
}
|
||||
|
||||
public func withUpdatedMedia(_ media: [Media]) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds)
|
||||
}
|
||||
@ -665,6 +673,14 @@ public final class Message {
|
||||
func withUpdatedAssociatedMessages(_ associatedMessages: SimpleDictionary<MessageId, Message>) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: associatedMessages, associatedMessageIds: self.associatedMessageIds)
|
||||
}
|
||||
|
||||
public func withUpdatedForwardInfo(_ forwardInfo: MessageForwardInfo?) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds)
|
||||
}
|
||||
|
||||
public func withUpdatedAuthor(_ author: Peer?) -> Message {
|
||||
return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, author: author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds)
|
||||
}
|
||||
}
|
||||
|
||||
public struct StoreMessageFlags: OptionSet {
|
||||
|
@ -329,11 +329,11 @@ public final class ShareController: ViewController {
|
||||
|
||||
public var debugAction: (() -> Void)?
|
||||
|
||||
public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, forceTheme: forceTheme, forcedActionTitle: forcedActionTitle)
|
||||
public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, updatedPresentationData: updatedPresentationData, forceTheme: forceTheme, forcedActionTitle: forcedActionTitle)
|
||||
}
|
||||
|
||||
public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.sharedContext = sharedContext
|
||||
self.currentContext = currentContext
|
||||
self.currentAccount = currentContext.account
|
||||
@ -347,7 +347,7 @@ public final class ShareController: ViewController {
|
||||
self.segmentedValues = segmentedValues
|
||||
self.forceTheme = forceTheme
|
||||
|
||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = updatedPresentationData?.initial ?? sharedContext.currentPresentationData.with { $0 }
|
||||
if let forceTheme = self.forceTheme {
|
||||
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
|
||||
}
|
||||
@ -463,7 +463,7 @@ public final class ShareController: ViewController {
|
||||
})
|
||||
}
|
||||
|
||||
self.presentationDataDisposable = (self.sharedContext.presentationData
|
||||
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? self.sharedContext.presentationData)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded {
|
||||
strongSelf.controllerNode.updatePresentationData(presentationData)
|
||||
@ -484,7 +484,7 @@ public final class ShareController: ViewController {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = ShareControllerNode(sharedContext: self.sharedContext, presetText: self.presetText, defaultAction: self.defaultAction, requestLayout: { [weak self] transition in
|
||||
self.displayNode = ShareControllerNode(sharedContext: self.sharedContext, presentationData: self.presentationData, presetText: self.presetText, defaultAction: self.defaultAction, requestLayout: { [weak self] transition in
|
||||
self?.requestLayout(transition: transition)
|
||||
}, presentError: { [weak self] title, text in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -80,9 +80,9 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
private let presetText: String?
|
||||
|
||||
init(sharedContext: SharedAccountContext, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forceTheme: PresentationTheme?, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
init(sharedContext: SharedAccountContext, presentationData: PresentationData, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forceTheme: PresentationTheme?, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
self.sharedContext = sharedContext
|
||||
self.presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = presentationData
|
||||
self.forceTheme = forceTheme
|
||||
self.externalShare = externalShare
|
||||
self.immediateExternalShare = immediateExternalShare
|
||||
|
@ -74,6 +74,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
self.titleNode.displaysAsynchronously = false
|
||||
|
||||
self.subtitleNode = ImmediateTextNode()
|
||||
self.subtitleNode.isUserInteractionEnabled = false
|
||||
@ -129,6 +130,10 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
self.buttonGlossNode.color = theme.foregroundColor
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title ?? "", font: self.font == .bold ? Font.semibold(17.0) : Font.regular(17.0), textColor: theme.foregroundColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.regular(14.0), textColor: theme.foregroundColor)
|
||||
|
||||
if let width = self.validLayout {
|
||||
_ = self.updateLayout(width: width, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
public func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
|
@ -4,6 +4,9 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NSData * _Nullable prepareSvgImage(NSData * _Nonnull data);
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size);
|
||||
|
||||
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor * _Nullable backgroundColor, UIColor * _Nullable foregroundColor);
|
||||
|
||||
#endif /* Lottie_h */
|
||||
|
@ -229,3 +229,431 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b
|
||||
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
|
||||
@interface CGContextCoder : NSObject {
|
||||
NSMutableData *_data;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) NSData *data;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CGContextCoder
|
||||
|
||||
- (instancetype)initWithSize:(CGSize)size {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_data = [[NSMutableData alloc] init];
|
||||
|
||||
int32_t intWidth = size.width;
|
||||
int32_t intHeight = size.height;
|
||||
[_data appendBytes:&intWidth length:sizeof(intWidth)];
|
||||
[_data appendBytes:&intHeight length:sizeof(intHeight)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setFillColorWithOpacity:(CGFloat)opacity {
|
||||
uint8_t command = 1;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
|
||||
uint8_t intOpacity = opacity * 255.0;
|
||||
[_data appendBytes:&intOpacity length:sizeof(intOpacity)];
|
||||
}
|
||||
|
||||
- (void)setupStrokeOpacity:(CGFloat)opacity mitterLimit:(CGFloat)mitterLimit lineWidth:(CGFloat)lineWidth lineCap:(CGLineCap)lineCap lineJoin:(CGLineJoin)lineJoin {
|
||||
uint8_t command = 2;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
|
||||
uint8_t intOpacity = opacity * 255.0;
|
||||
[_data appendBytes:&intOpacity length:sizeof(intOpacity)];
|
||||
|
||||
float floatMitterLimit = mitterLimit;
|
||||
[_data appendBytes:&floatMitterLimit length:sizeof(floatMitterLimit)];
|
||||
|
||||
float floatLineWidth = lineWidth;
|
||||
[_data appendBytes:&floatLineWidth length:sizeof(floatLineWidth)];
|
||||
|
||||
uint8_t intLineCap = lineCap;
|
||||
[_data appendBytes:&intLineCap length:sizeof(intLineCap)];
|
||||
|
||||
uint8_t intLineJoin = lineJoin;
|
||||
[_data appendBytes:&intLineJoin length:sizeof(intLineJoin)];
|
||||
}
|
||||
|
||||
- (void)beginPath {
|
||||
uint8_t command = 3;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
}
|
||||
|
||||
- (void)moveToPoint:(CGPoint)point {
|
||||
uint8_t command = 4;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
|
||||
float floatX = point.x;
|
||||
[_data appendBytes:&floatX length:sizeof(floatX)];
|
||||
|
||||
float floatY = point.y;
|
||||
[_data appendBytes:&floatY length:sizeof(floatY)];
|
||||
}
|
||||
|
||||
- (void)addLineToPoint:(CGPoint)point {
|
||||
uint8_t command = 5;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
|
||||
float floatX = point.x;
|
||||
[_data appendBytes:&floatX length:sizeof(floatX)];
|
||||
|
||||
float floatY = point.y;
|
||||
[_data appendBytes:&floatY length:sizeof(floatY)];
|
||||
}
|
||||
|
||||
- (void)addCurveToPoint:(CGPoint)p1 p2:(CGPoint)p2 p3:(CGPoint)p3 {
|
||||
uint8_t command = 6;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
|
||||
float floatX1 = p1.x;
|
||||
[_data appendBytes:&floatX1 length:sizeof(floatX1)];
|
||||
|
||||
float floatY1 = p1.y;
|
||||
[_data appendBytes:&floatY1 length:sizeof(floatY1)];
|
||||
|
||||
float floatX2 = p2.x;
|
||||
[_data appendBytes:&floatX2 length:sizeof(floatX2)];
|
||||
|
||||
float floatY2 = p2.y;
|
||||
[_data appendBytes:&floatY2 length:sizeof(floatY2)];
|
||||
|
||||
float floatX3 = p3.x;
|
||||
[_data appendBytes:&floatX3 length:sizeof(floatX3)];
|
||||
|
||||
float floatY3 = p3.y;
|
||||
[_data appendBytes:&floatY3 length:sizeof(floatY3)];
|
||||
}
|
||||
|
||||
- (void)closePath {
|
||||
uint8_t command = 7;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
}
|
||||
|
||||
- (void)eoFillPath {
|
||||
uint8_t command = 8;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
}
|
||||
|
||||
- (void)fillPath {
|
||||
uint8_t command = 9;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
}
|
||||
|
||||
- (void)strokePath {
|
||||
uint8_t command = 10;
|
||||
[_data appendBytes:&command length:sizeof(command)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size) {
|
||||
NSDate *startTime = [NSDate date];
|
||||
|
||||
UIColor *foregroundColor = [UIColor whiteColor];
|
||||
UIColor *backgroundColor = [UIColor blackColor];
|
||||
|
||||
int32_t ptr = 0;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
|
||||
[data getBytes:&width range:NSMakeRange(ptr, sizeof(width))];
|
||||
ptr += sizeof(width);
|
||||
[data getBytes:&height range:NSMakeRange(ptr, sizeof(height))];
|
||||
ptr += sizeof(height);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, true, 1.0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
|
||||
CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height));
|
||||
|
||||
CGSize svgSize = CGSizeMake(width, height);
|
||||
CGSize drawingSize = aspectFillSize(svgSize, size);
|
||||
|
||||
CGFloat scale = MAX(size.width / MAX(1.0, svgSize.width), size.height / MAX(1.0, svgSize.height));
|
||||
|
||||
CGContextScaleCTM(context, scale, scale);
|
||||
CGContextTranslateCTM(context, (size.width - drawingSize.width) / 2.0, (size.height - drawingSize.height) / 2.0);
|
||||
|
||||
while (ptr < data.length) {
|
||||
uint8_t cmd;
|
||||
[data getBytes:&cmd range:NSMakeRange(ptr, sizeof(cmd))];
|
||||
ptr += sizeof(cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case 1:
|
||||
{
|
||||
uint8_t opacity;
|
||||
[data getBytes:&opacity range:NSMakeRange(ptr, sizeof(opacity))];
|
||||
ptr += sizeof(opacity);
|
||||
CGContextSetFillColorWithColor(context, [foregroundColor colorWithAlphaComponent:opacity / 255.0].CGColor);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
uint8_t opacity;
|
||||
[data getBytes:&opacity range:NSMakeRange(ptr, sizeof(opacity))];
|
||||
ptr += sizeof(opacity);
|
||||
CGContextSetStrokeColorWithColor(context, [foregroundColor colorWithAlphaComponent:opacity / 255.0].CGColor);
|
||||
|
||||
float mitterLimit;
|
||||
[data getBytes:&mitterLimit range:NSMakeRange(ptr, sizeof(mitterLimit))];
|
||||
ptr += sizeof(mitterLimit);
|
||||
CGContextSetMiterLimit(context, mitterLimit);
|
||||
|
||||
float lineWidth;
|
||||
[data getBytes:&lineWidth range:NSMakeRange(ptr, sizeof(lineWidth))];
|
||||
ptr += sizeof(lineWidth);
|
||||
CGContextSetLineWidth(context, lineWidth);
|
||||
|
||||
uint8_t lineCap;
|
||||
[data getBytes:&lineCap range:NSMakeRange(ptr, sizeof(lineCap))];
|
||||
ptr += sizeof(lineCap);
|
||||
CGContextSetLineCap(context, lineCap);
|
||||
|
||||
uint8_t lineJoin;
|
||||
[data getBytes:&lineJoin range:NSMakeRange(ptr, sizeof(lineJoin))];
|
||||
ptr += sizeof(lineJoin);
|
||||
CGContextSetLineCap(context, lineJoin);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
float x;
|
||||
[data getBytes:&x range:NSMakeRange(ptr, sizeof(x))];
|
||||
ptr += sizeof(x);
|
||||
|
||||
float y;
|
||||
[data getBytes:&y range:NSMakeRange(ptr, sizeof(y))];
|
||||
ptr += sizeof(y);
|
||||
|
||||
CGContextMoveToPoint(context, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
{
|
||||
float x;
|
||||
[data getBytes:&x range:NSMakeRange(ptr, sizeof(x))];
|
||||
ptr += sizeof(x);
|
||||
|
||||
float y;
|
||||
[data getBytes:&y range:NSMakeRange(ptr, sizeof(y))];
|
||||
ptr += sizeof(y);
|
||||
|
||||
CGContextAddLineToPoint(context, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
{
|
||||
float x1;
|
||||
[data getBytes:&x1 range:NSMakeRange(ptr, sizeof(x1))];
|
||||
ptr += sizeof(x1);
|
||||
|
||||
float y1;
|
||||
[data getBytes:&y1 range:NSMakeRange(ptr, sizeof(y1))];
|
||||
ptr += sizeof(y1);
|
||||
|
||||
float x2;
|
||||
[data getBytes:&x2 range:NSMakeRange(ptr, sizeof(x2))];
|
||||
ptr += sizeof(x2);
|
||||
|
||||
float y2;
|
||||
[data getBytes:&y2 range:NSMakeRange(ptr, sizeof(y2))];
|
||||
ptr += sizeof(y2);
|
||||
|
||||
float x3;
|
||||
[data getBytes:&x3 range:NSMakeRange(ptr, sizeof(x3))];
|
||||
ptr += sizeof(x3);
|
||||
|
||||
float y3;
|
||||
[data getBytes:&y3 range:NSMakeRange(ptr, sizeof(y3))];
|
||||
ptr += sizeof(y3);
|
||||
|
||||
CGContextAddCurveToPoint(context, x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
{
|
||||
CGContextClosePath(context);
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
{
|
||||
CGContextEOFillPath(context);
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
{
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
{
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
double deltaTime = -1.0f * [startTime timeIntervalSinceNow];
|
||||
printf("drawingTime %fx%f = %f\n", size.width, size.height, deltaTime);
|
||||
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
NSData * _Nullable prepareSvgImage(NSData * _Nonnull data) {
|
||||
NSDate *startTime = [NSDate date];
|
||||
|
||||
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
|
||||
if (parser == nil) {
|
||||
return nil;
|
||||
}
|
||||
SvgXMLParsingDelegate *delegate = [[SvgXMLParsingDelegate alloc] init];
|
||||
parser.delegate = delegate;
|
||||
[parser parse];
|
||||
|
||||
NSMutableString *xmlString = [[NSMutableString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
if (xmlString == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (NSString *styleName in delegate.styles) {
|
||||
NSString *styleValue = delegate.styles[styleName];
|
||||
[xmlString replaceOccurrencesOfString:[NSString stringWithFormat:@"class=\"%@\"", styleName] withString:[NSString stringWithFormat:@"style=\"%@\"", styleValue] options:0 range:NSMakeRange(0, xmlString.length)];
|
||||
}
|
||||
|
||||
const char *zeroTerminatedData = xmlString.UTF8String;
|
||||
|
||||
NSVGimage *image = nsvgParse((char *)zeroTerminatedData, "px", 96);
|
||||
if (image == nil || image->width < 1.0f || image->height < 1.0f) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
double deltaTime = -1.0f * [startTime timeIntervalSinceNow];
|
||||
printf("parseTime = %f\n", deltaTime);
|
||||
|
||||
startTime = [NSDate date];
|
||||
|
||||
CGContextCoder *context = [[CGContextCoder alloc] initWithSize:CGSizeMake(image->width, image->height)];
|
||||
|
||||
for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
|
||||
if (!(shape->flags & NSVG_FLAGS_VISIBLE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shape->fill.type != NSVG_PAINT_NONE) {
|
||||
[context setFillColorWithOpacity:shape->opacity];
|
||||
|
||||
bool isFirst = true;
|
||||
bool hasStartPoint = false;
|
||||
CGPoint startPoint;
|
||||
for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
|
||||
if (isFirst) {
|
||||
[context beginPath];
|
||||
|
||||
isFirst = false;
|
||||
hasStartPoint = true;
|
||||
startPoint.x = path->pts[0];
|
||||
startPoint.y = path->pts[1];
|
||||
}
|
||||
[context moveToPoint:CGPointMake(path->pts[0], path->pts[1])];
|
||||
for (int i = 0; i < path->npts - 1; i += 3) {
|
||||
float *p = &path->pts[i * 2];
|
||||
[context addCurveToPoint:CGPointMake(p[2], p[3]) p2:CGPointMake(p[4], p[5]) p3:CGPointMake(p[6], p[7])];
|
||||
}
|
||||
|
||||
if (path->closed) {
|
||||
if (hasStartPoint) {
|
||||
hasStartPoint = false;
|
||||
[context addLineToPoint:startPoint];
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (shape->fillRule) {
|
||||
case NSVG_FILLRULE_EVENODD:
|
||||
[context eoFillPath];
|
||||
break;
|
||||
default:
|
||||
[context fillPath];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shape->stroke.type != NSVG_PAINT_NONE) {
|
||||
CGLineCap lineCap = kCGLineCapButt;
|
||||
CGLineJoin lineJoin = kCGLineJoinMiter;
|
||||
switch (shape->strokeLineCap) {
|
||||
case NSVG_CAP_BUTT:
|
||||
lineCap = kCGLineCapButt;
|
||||
break;
|
||||
case NSVG_CAP_ROUND:
|
||||
lineCap = kCGLineCapRound;
|
||||
break;
|
||||
case NSVG_CAP_SQUARE:
|
||||
lineCap = kCGLineCapSquare;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (shape->strokeLineJoin) {
|
||||
case NSVG_JOIN_BEVEL:
|
||||
lineJoin = kCGLineJoinBevel;
|
||||
break;
|
||||
case NSVG_JOIN_MITER:
|
||||
lineJoin = kCGLineJoinMiter;
|
||||
break;
|
||||
case NSVG_JOIN_ROUND:
|
||||
lineJoin = kCGLineJoinRound;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
[context setupStrokeOpacity:shape->opacity mitterLimit:shape->miterLimit lineWidth:shape->strokeWidth lineCap:lineCap lineJoin:lineJoin];
|
||||
|
||||
for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
|
||||
[context beginPath];
|
||||
[context moveToPoint:CGPointMake(path->pts[0], path->pts[1])];
|
||||
for (int i = 0; i < path->npts - 1; i += 3) {
|
||||
float *p = &path->pts[i * 2];
|
||||
[context addCurveToPoint:CGPointMake(p[2], p[3]) p2:CGPointMake(p[4], p[5]) p3:CGPointMake(p[6], p[7])];
|
||||
}
|
||||
|
||||
if (path->closed) {
|
||||
[context closePath];
|
||||
}
|
||||
[context strokePath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsvgDelete(image);
|
||||
return context.data;
|
||||
}
|
||||
|
@ -465,6 +465,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-384910503] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionExportedInviteEdit($0) }
|
||||
dict[1048537159] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantVolume($0) }
|
||||
dict[1855199800] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeHistoryTTL($0) }
|
||||
dict[-26672755] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeTheme($0) }
|
||||
dict[-1271602504] = { return Api.auth.ExportedAuthorization.parse_exportedAuthorization($0) }
|
||||
dict[2103482845] = { return Api.SecurePlainData.parse_securePlainPhone($0) }
|
||||
dict[569137759] = { return Api.SecurePlainData.parse_securePlainEmail($0) }
|
||||
@ -737,7 +738,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1625153079] = { return Api.InputWebFileLocation.parse_inputWebFileGeoPointLocation($0) }
|
||||
dict[-1275374751] = { return Api.EmojiLanguage.parse_emojiLanguage($0) }
|
||||
dict[1601666510] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) }
|
||||
dict[-160304943] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[708589599] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[-1012849566] = { return Api.BaseTheme.parse_baseThemeClassic($0) }
|
||||
dict[-69724536] = { return Api.BaseTheme.parse_baseThemeDay($0) }
|
||||
dict[-1212997976] = { return Api.BaseTheme.parse_baseThemeNight($0) }
|
||||
|
@ -11316,6 +11316,7 @@ public extension Api {
|
||||
case channelAdminLogEventActionExportedInviteEdit(prevInvite: Api.ExportedChatInvite, newInvite: Api.ExportedChatInvite)
|
||||
case channelAdminLogEventActionParticipantVolume(participant: Api.GroupCallParticipant)
|
||||
case channelAdminLogEventActionChangeHistoryTTL(prevValue: Int32, newValue: Int32)
|
||||
case channelAdminLogEventActionChangeTheme(prevValue: String, newValue: String)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -11525,6 +11526,13 @@ public extension Api {
|
||||
serializeInt32(prevValue, buffer: buffer, boxed: false)
|
||||
serializeInt32(newValue, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .channelAdminLogEventActionChangeTheme(let prevValue, let newValue):
|
||||
if boxed {
|
||||
buffer.appendInt32(-26672755)
|
||||
}
|
||||
serializeString(prevValue, buffer: buffer, boxed: false)
|
||||
serializeString(newValue, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -11594,6 +11602,8 @@ public extension Api {
|
||||
return ("channelAdminLogEventActionParticipantVolume", [("participant", participant)])
|
||||
case .channelAdminLogEventActionChangeHistoryTTL(let prevValue, let newValue):
|
||||
return ("channelAdminLogEventActionChangeHistoryTTL", [("prevValue", prevValue), ("newValue", newValue)])
|
||||
case .channelAdminLogEventActionChangeTheme(let prevValue, let newValue):
|
||||
return ("channelAdminLogEventActionChangeTheme", [("prevValue", prevValue), ("newValue", newValue)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -12039,6 +12049,20 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_channelAdminLogEventActionChangeTheme(_ reader: BufferReader) -> ChannelAdminLogEventAction? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.ChannelAdminLogEventAction.channelAdminLogEventActionChangeTheme(prevValue: _1!, newValue: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum SecurePlainData: TypeConstructorDescription {
|
||||
@ -19214,20 +19238,19 @@ public extension Api {
|
||||
|
||||
}
|
||||
public enum SponsoredMessage: TypeConstructorDescription {
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, peerId: Api.Peer, fromId: Api.Peer, message: String, media: Api.MessageMedia?, entities: [Api.MessageEntity]?)
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer, startParam: String?, message: String, entities: [Api.MessageEntity]?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let peerId, let fromId, let message, let media, let entities):
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let startParam, let message, let entities):
|
||||
if boxed {
|
||||
buffer.appendInt32(-160304943)
|
||||
buffer.appendInt32(708589599)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeBytes(randomId, buffer: buffer, boxed: false)
|
||||
peerId.serialize(buffer, true)
|
||||
fromId.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)}
|
||||
serializeString(message, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {media!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(entities!.count))
|
||||
for item in entities! {
|
||||
@ -19239,8 +19262,8 @@ public extension Api {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let peerId, let fromId, let message, let media, let entities):
|
||||
return ("sponsoredMessage", [("flags", flags), ("randomId", randomId), ("peerId", peerId), ("fromId", fromId), ("message", message), ("media", media), ("entities", entities)])
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let startParam, let message, let entities):
|
||||
return ("sponsoredMessage", [("flags", flags), ("randomId", randomId), ("fromId", fromId), ("startParam", startParam), ("message", message), ("entities", entities)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -19253,29 +19276,22 @@ public extension Api {
|
||||
if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
}
|
||||
var _4: Api.Peer?
|
||||
if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
}
|
||||
var _4: String?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
|
||||
var _5: String?
|
||||
_5 = parseString(reader)
|
||||
var _6: Api.MessageMedia?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||
_6 = Api.parse(reader, signature: signature) as? Api.MessageMedia
|
||||
} }
|
||||
var _7: [Api.MessageEntity]?
|
||||
var _6: [Api.MessageEntity]?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
|
||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, peerId: _3!, fromId: _4!, message: _5!, media: _6, entities: _7)
|
||||
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, fromId: _3!, startParam: _4, message: _5!, entities: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -4447,6 +4447,21 @@ public extension Api {
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func getMessageReadParticipants(peer: Api.InputPeer, msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int64]>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(745510839)
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "messages.getMessageReadParticipants", parameters: [("peer", peer), ("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int64]? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: [Int64]?
|
||||
if let _ = reader.readInt32() {
|
||||
result = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public struct channels {
|
||||
public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
|
@ -17,14 +17,14 @@ public final class MediaNavigationAccessoryContainerNode: ASDisplayNode, UIGestu
|
||||
|
||||
private var presentationData: PresentationData
|
||||
|
||||
init(context: AccountContext, displayBackground: Bool) {
|
||||
init(context: AccountContext, presentationData: PresentationData, displayBackground: Bool) {
|
||||
self.displayBackground = displayBackground
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationData = presentationData
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.separatorNode = ASDisplayNode()
|
||||
self.headerNode = MediaNavigationAccessoryHeaderNode(context: context)
|
||||
self.headerNode = MediaNavigationAccessoryHeaderNode(context: context, presentationData: presentationData)
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -217,9 +217,11 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext) {
|
||||
private let dismissedPromise = ValuePromise<Bool>(false)
|
||||
|
||||
public init(context: AccountContext, presentationData: PresentationData) {
|
||||
self.context = context
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.theme = presentationData.theme
|
||||
self.strings = presentationData.strings
|
||||
self.dateTimeFormat = presentationData.dateTimeFormat
|
||||
@ -437,6 +439,8 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
||||
guard let (size, _, _) = self.validLayout else {
|
||||
return
|
||||
}
|
||||
|
||||
self.dismissedPromise.set(true)
|
||||
|
||||
transition.updatePosition(node: self.separatorNode, position: self.separatorNode.position.offsetBy(dx: 0.0, dy: size.height))
|
||||
}
|
||||
@ -551,7 +555,8 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
||||
return
|
||||
}
|
||||
let items: Signal<[ContextMenuItem], NoError> = self.contextMenuSpeedItems()
|
||||
let contextController = ContextController(account: self.context.account, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode)), items: items, reactionItems: [], gesture: gesture)
|
||||
let contextController = ContextController(account: self.context.account, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode, shouldBeDismissed: self.dismissedPromise.get())), items: items, reactionItems: [], gesture: gesture)
|
||||
|
||||
self.presentInGlobalOverlay?(contextController)
|
||||
}
|
||||
|
||||
@ -766,11 +771,14 @@ private final class HeaderContextReferenceContentSource: ContextReferenceContent
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ContextReferenceContentNode
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextReferenceContentNode) {
|
||||
var shouldBeDismissed: Signal<Bool, NoError>
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextReferenceContentNode, shouldBeDismissed: Signal<Bool, NoError>) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
self.shouldBeDismissed = shouldBeDismissed
|
||||
}
|
||||
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import AsyncDisplayKit
|
||||
import TelegramCore
|
||||
import AccountContext
|
||||
import TelegramUIPreferences
|
||||
import TelegramPresentationData
|
||||
|
||||
public final class MediaNavigationAccessoryPanel: ASDisplayNode {
|
||||
public let containerNode: MediaNavigationAccessoryContainerNode
|
||||
@ -19,8 +20,8 @@ public final class MediaNavigationAccessoryPanel: ASDisplayNode {
|
||||
public var getController: (() -> ViewController?)?
|
||||
public var presentInGlobalOverlay: ((ViewController) -> Void)?
|
||||
|
||||
public init(context: AccountContext, displayBackground: Bool = false) {
|
||||
self.containerNode = MediaNavigationAccessoryContainerNode(context: context, displayBackground: displayBackground)
|
||||
public init(context: AccountContext, presentationData: PresentationData, displayBackground: Bool = false) {
|
||||
self.containerNode = MediaNavigationAccessoryContainerNode(context: context, presentationData: presentationData, displayBackground: displayBackground)
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -265,20 +265,31 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
let availableGroupCall: Signal<GroupCallPanelData?, NoError>
|
||||
if case let .peer(peerId) = groupCallPanelSource {
|
||||
availableGroupCall = context.account.viewTracker.peerView(peerId)
|
||||
|> map { peerView -> CachedChannelData.ActiveCall? in
|
||||
|> map { peerView -> (CachedChannelData.ActiveCall?, EnginePeer?) in
|
||||
let peer = peerView.peers[peerId].flatMap(EnginePeer.init)
|
||||
if let cachedData = peerView.cachedData as? CachedChannelData {
|
||||
return cachedData.activeCall
|
||||
return (cachedData.activeCall, peer)
|
||||
} else if let cachedData = peerView.cachedData as? CachedGroupData {
|
||||
return cachedData.activeCall
|
||||
return (cachedData.activeCall, peer)
|
||||
} else {
|
||||
return nil
|
||||
return (nil, peer)
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { activeCall -> Signal<GroupCallPanelData?, NoError> in
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
if lhs.0 != rhs.0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|> mapToSignal { activeCall, peer -> Signal<GroupCallPanelData?, NoError> in
|
||||
guard let activeCall = activeCall else {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
var isChannel = false
|
||||
if let peer = peer, case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
isChannel = true
|
||||
}
|
||||
|
||||
return Signal { [weak context] subscriber in
|
||||
guard let context = context, let callContextCache = context.cachedGroupCallContexts as? AccountGroupCallContextCacheImpl else {
|
||||
@ -288,7 +299,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
callContextCache.impl.syncWith { impl in
|
||||
let callContext = impl.get(account: context.account, engine: context.engine, peerId: peerId, call: EngineGroupCallDescription(activeCall))
|
||||
let callContext = impl.get(account: context.account, engine: context.engine, peerId: peerId, isChannel: isChannel, call: EngineGroupCallDescription(activeCall))
|
||||
disposable.set((callContext.context.panelData
|
||||
|> deliverOnMainQueue).start(next: { panelData in
|
||||
callContext.keep()
|
||||
@ -333,7 +344,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
}
|
||||
}
|
||||
|
||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||
self.presentationDataDisposable = (self.updatedPresentationData.1
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
let previousTheme = strongSelf.presentationData.theme
|
||||
@ -350,6 +361,10 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
})
|
||||
}
|
||||
|
||||
open var updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>) {
|
||||
return (self.presentationData, self.context.sharedContext.presentationData)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.mediaStatusDisposable?.dispose()
|
||||
self.locationBroadcastDisposable?.dispose()
|
||||
@ -643,7 +658,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
})
|
||||
}
|
||||
|
||||
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context)
|
||||
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context, presentationData: self.updatedPresentationData.0)
|
||||
mediaAccessoryPanel.containerNode.headerNode.displayScrubber = item.playbackData?.type != .instantVideo
|
||||
mediaAccessoryPanel.getController = { [weak self] in
|
||||
return self
|
||||
|
@ -40,6 +40,7 @@ public enum GroupCallPanelSource {
|
||||
|
||||
public final class GroupCallPanelData {
|
||||
public let peerId: PeerId
|
||||
public let isChannel: Bool
|
||||
public let info: GroupCallInfo
|
||||
public let topParticipants: [GroupCallParticipantsContext.Participant]
|
||||
public let participantCount: Int
|
||||
@ -48,6 +49,7 @@ public final class GroupCallPanelData {
|
||||
|
||||
public init(
|
||||
peerId: PeerId,
|
||||
isChannel: Bool,
|
||||
info: GroupCallInfo,
|
||||
topParticipants: [GroupCallParticipantsContext.Participant],
|
||||
participantCount: Int,
|
||||
@ -55,6 +57,7 @@ public final class GroupCallPanelData {
|
||||
groupCall: PresentationGroupCall?
|
||||
) {
|
||||
self.peerId = peerId
|
||||
self.isChannel = isChannel
|
||||
self.info = info
|
||||
self.topParticipants = topParticipants
|
||||
self.participantCount = participantCount
|
||||
@ -523,6 +526,11 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
||||
|
||||
var joinText = self.strings.VoiceChat_PanelJoin
|
||||
var title = self.strings.VoiceChat_Title
|
||||
var isChannel = false
|
||||
if let currentData = self.currentData, currentData.isChannel {
|
||||
title = self.strings.VoiceChatChannel_Title
|
||||
isChannel = true
|
||||
}
|
||||
var text = self.currentText
|
||||
var isScheduled = false
|
||||
var isLate = false
|
||||
@ -530,9 +538,9 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
||||
isScheduled = true
|
||||
if let voiceChatTitle = self.currentData?.info.title {
|
||||
title = voiceChatTitle
|
||||
text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, alwaysShowTime: true, format: HumanReadableStringFormat(dateFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsOn($0) }, tomorrowFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTomorrow($0) }, todayFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsToday($0) })).string
|
||||
text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, alwaysShowTime: true, format: HumanReadableStringFormat(dateFormatString: { isChannel ? self.strings.Conversation_ScheduledLiveStreamStartsOn($0) : self.strings.Conversation_ScheduledVoiceChatStartsOn($0) }, tomorrowFormatString: { isChannel ? self.strings.Conversation_ScheduledLiveStreamStartsTomorrow($0) : self.strings.Conversation_ScheduledVoiceChatStartsTomorrow($0) }, todayFormatString: { isChannel ? self.strings.Conversation_ScheduledLiveStreamStartsToday($0) : self.strings.Conversation_ScheduledVoiceChatStartsToday($0) })).string
|
||||
} else {
|
||||
title = self.strings.Conversation_ScheduledVoiceChat
|
||||
title = isChannel ? self.strings.Conversation_ScheduledLiveStream : self.strings.Conversation_ScheduledVoiceChat
|
||||
text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, alwaysShowTime: true, format: HumanReadableStringFormat(dateFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsOnShort($0) }, tomorrowFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTomorrowShort($0) }, todayFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTodayShort($0) })).string
|
||||
}
|
||||
|
||||
|
@ -650,9 +650,12 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|
||||
return accessEnabledSignal
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
accessEnabledSignal,
|
||||
accountContext.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
)
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { [weak self] accessEnabled -> Signal<Bool, NoError> in
|
||||
|> mapToSignal { [weak self] accessEnabled, peer -> Signal<Bool, NoError> in
|
||||
guard let strongSelf = self else {
|
||||
return .single(false)
|
||||
}
|
||||
@ -660,6 +663,11 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
if !accessEnabled {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
var isChannel = false
|
||||
if let peer = peer, case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
isChannel = true
|
||||
}
|
||||
|
||||
let call = PresentationGroupCallImpl(
|
||||
accountContext: accountContext,
|
||||
@ -669,6 +677,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
initialCall: nil,
|
||||
internalId: internalId,
|
||||
peerId: peerId,
|
||||
isChannel: isChannel,
|
||||
invite: nil,
|
||||
joinAsPeerId: nil
|
||||
)
|
||||
@ -803,9 +812,12 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|
||||
return accessEnabledSignal
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
accessEnabledSignal,
|
||||
accountContext.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
)
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { [weak self] accessEnabled -> Signal<Bool, NoError> in
|
||||
|> mapToSignal { [weak self] accessEnabled, peer -> Signal<Bool, NoError> in
|
||||
guard let strongSelf = self else {
|
||||
return .single(false)
|
||||
}
|
||||
@ -813,6 +825,11 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
if !accessEnabled {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
var isChannel = false
|
||||
if let peer = peer, case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
isChannel = true
|
||||
}
|
||||
|
||||
let call = PresentationGroupCallImpl(
|
||||
accountContext: accountContext,
|
||||
@ -822,6 +839,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
initialCall: initialCall,
|
||||
internalId: internalId,
|
||||
peerId: peerId,
|
||||
isChannel: isChannel,
|
||||
invite: invite,
|
||||
joinAsPeerId: joinAsPeerId
|
||||
)
|
||||
|
@ -91,9 +91,10 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
||||
return self.panelDataPromise.get()
|
||||
}
|
||||
|
||||
public init(account: Account, engine: TelegramEngine, peerId: PeerId, call: EngineGroupCallDescription) {
|
||||
public init(account: Account, engine: TelegramEngine, peerId: PeerId, isChannel: Bool, call: EngineGroupCallDescription) {
|
||||
self.panelDataPromise.set(.single(GroupCallPanelData(
|
||||
peerId: peerId,
|
||||
isChannel: isChannel,
|
||||
info: GroupCallInfo(
|
||||
id: call.id,
|
||||
accessHash: call.accessHash,
|
||||
@ -113,13 +114,18 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
||||
activeSpeakers: Set(),
|
||||
groupCall: nil
|
||||
)))
|
||||
|
||||
let state = engine.calls.getGroupCallParticipants(callId: call.id, accessHash: call.accessHash, offset: "", ssrcs: [], limit: 100, sortAscending: nil)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
self.disposable = (engine.calls.getGroupCallParticipants(callId: call.id, accessHash: call.accessHash, offset: "", ssrcs: [], limit: 100, sortAscending: nil)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
self.disposable = (combineLatest(queue: .mainQueue(),
|
||||
state,
|
||||
engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state, peer in
|
||||
guard let strongSelf = self, let state = state else {
|
||||
return
|
||||
}
|
||||
@ -145,8 +151,15 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
||||
}
|
||||
topParticipants.append(participant)
|
||||
}
|
||||
|
||||
var isChannel = false
|
||||
if let peer = peer, case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
isChannel = true
|
||||
}
|
||||
|
||||
return GroupCallPanelData(
|
||||
peerId: peerId,
|
||||
isChannel: isChannel,
|
||||
info: GroupCallInfo(id: call.id, accessHash: call.accessHash, participantCount: state.totalCount, streamDcId: nil, title: state.title, scheduleTimestamp: state.scheduleTimestamp, subscribedToScheduled: state.subscribedToScheduled, recordingStartTimestamp: nil, sortAscending: state.sortAscending, defaultParticipantsAreMuted: state.defaultParticipantsAreMuted, isVideoEnabled: state.isVideoEnabled, unmutedVideoLimit: state.unmutedVideoLimit),
|
||||
topParticipants: topParticipants,
|
||||
participantCount: state.totalCount,
|
||||
@ -183,12 +196,12 @@ public final class AccountGroupCallContextCacheImpl: AccountGroupCallContextCach
|
||||
self.queue = queue
|
||||
}
|
||||
|
||||
public func get(account: Account, engine: TelegramEngine, peerId: PeerId, call: EngineGroupCallDescription) -> AccountGroupCallContextImpl.Proxy {
|
||||
public func get(account: Account, engine: TelegramEngine, peerId: PeerId, isChannel: Bool, call: EngineGroupCallDescription) -> AccountGroupCallContextImpl.Proxy {
|
||||
let result: Record
|
||||
if let current = self.contexts[call.id] {
|
||||
result = current
|
||||
} else {
|
||||
let context = AccountGroupCallContextImpl(account: account, engine: engine, peerId: peerId, call: call)
|
||||
let context = AccountGroupCallContextImpl(account: account, engine: engine, peerId: peerId, isChannel: isChannel, call: call)
|
||||
result = Record(context: context)
|
||||
self.contexts[call.id] = result
|
||||
}
|
||||
@ -385,6 +398,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
private var initialCall: EngineGroupCallDescription?
|
||||
public let internalId: CallSessionInternalId
|
||||
public let peerId: PeerId
|
||||
private let isChannel: Bool
|
||||
private var invite: String?
|
||||
private var joinAsPeerId: PeerId
|
||||
private var ignorePreviousJoinAsPeerId: (PeerId, UInt32)?
|
||||
@ -624,6 +638,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
initialCall: EngineGroupCallDescription?,
|
||||
internalId: CallSessionInternalId,
|
||||
peerId: PeerId,
|
||||
isChannel: Bool,
|
||||
invite: String?,
|
||||
joinAsPeerId: PeerId?
|
||||
) {
|
||||
@ -636,6 +651,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
self.initialCall = initialCall
|
||||
self.internalId = internalId
|
||||
self.peerId = peerId
|
||||
self.isChannel = isChannel
|
||||
self.invite = invite
|
||||
self.joinAsPeerId = joinAsPeerId ?? accountContext.account.peerId
|
||||
self.schedulePending = initialCall == nil
|
||||
@ -822,7 +838,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
})
|
||||
|
||||
if let initialCall = initialCall, let temporaryParticipantsContext = (self.accountContext.cachedGroupCallContexts as? AccountGroupCallContextCacheImpl)?.impl.syncWith({ impl in
|
||||
impl.get(account: accountContext.account, engine: accountContext.engine, peerId: peerId, call: EngineGroupCallDescription(id: initialCall.id, accessHash: initialCall.accessHash, title: initialCall.title, scheduleTimestamp: initialCall.scheduleTimestamp, subscribedToScheduled: initialCall.subscribedToScheduled))
|
||||
impl.get(account: accountContext.account, engine: accountContext.engine, peerId: peerId, isChannel: isChannel, call: EngineGroupCallDescription(id: initialCall.id, accessHash: initialCall.accessHash, title: initialCall.title, scheduleTimestamp: initialCall.scheduleTimestamp, subscribedToScheduled: initialCall.subscribedToScheduled))
|
||||
}) {
|
||||
self.switchToTemporaryParticipantsContext(sourceContext: temporaryParticipantsContext.context.participantsContext, oldMyPeerId: self.joinAsPeerId)
|
||||
} else {
|
||||
@ -1510,12 +1526,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
if case .anonymousNotAllowed = error {
|
||||
let presentationData = strongSelf.accountContext.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.VoiceChat_AnonymousDisabledAlertText, actions: [
|
||||
strongSelf.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: strongSelf.isChannel ? presentationData.strings.LiveStream_AnonymousDisabledAlertText : presentationData.strings.VoiceChat_AnonymousDisabledAlertText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})
|
||||
]), on: .root, blockInteraction: false, completion: {})
|
||||
} else if case .tooManyParticipants = error {
|
||||
let presentationData = strongSelf.accountContext.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.VoiceChat_ChatFullAlertText, actions: [
|
||||
strongSelf.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: strongSelf.isChannel ? presentationData.strings.LiveStream_ChatFullAlertText : presentationData.strings.VoiceChat_ChatFullAlertText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})
|
||||
]), on: .root, blockInteraction: false, completion: {})
|
||||
} else if case .invalidJoinAsPeer = error {
|
||||
|
@ -858,6 +858,8 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
private var currentLoadToken: String?
|
||||
|
||||
private var scrollAtTop = true
|
||||
|
||||
private var effectiveMuteState: GroupCallParticipantsContext.Participant.MuteState? {
|
||||
if self.pushingToTalk {
|
||||
return nil
|
||||
@ -1236,7 +1238,13 @@ public final class VoiceChatController: ViewController {
|
||||
dismissController?()
|
||||
|
||||
if strongSelf.call.invitePeer(participant.peer.id) {
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: participant.peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return false })
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: participant.peer, text: text), action: { _ in return false })
|
||||
}
|
||||
} else {
|
||||
if let groupPeer = groupPeer as? TelegramChannel, let listenerLink = inviteLinks?.listenerLink, !groupPeer.hasPermission(.inviteMembers) {
|
||||
@ -1336,7 +1344,13 @@ public final class VoiceChatController: ViewController {
|
||||
dismissController?()
|
||||
|
||||
if strongSelf.call.invitePeer(peer.id) {
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return false })
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text), action: { _ in return false })
|
||||
}
|
||||
}))
|
||||
} else if let groupPeer = groupPeer as? TelegramGroup {
|
||||
@ -1398,7 +1412,13 @@ public final class VoiceChatController: ViewController {
|
||||
dismissController?()
|
||||
|
||||
if strongSelf.call.invitePeer(peer.id) {
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return false })
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text), action: { _ in return false })
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -2157,6 +2177,22 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.visibleContentOffsetChanged = { [weak self] offset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var scrollAtTop = false
|
||||
if case let .known(value) = offset, value < 180.0 {
|
||||
scrollAtTop = true
|
||||
} else {
|
||||
scrollAtTop = false
|
||||
}
|
||||
if scrollAtTop != strongSelf.scrollAtTop {
|
||||
strongSelf.scrollAtTop = scrollAtTop
|
||||
strongSelf.updateTitle(transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -2175,7 +2211,13 @@ public final class VoiceChatController: ViewController {
|
||||
return
|
||||
}
|
||||
if event.joined {
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: event.peer, text: strongSelf.presentationData.strings.VoiceChat_PeerJoinedText(event.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return false })
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_PeerJoinedText(event.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_PeerJoinedText(event.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: event.peer, text: text), action: { _ in return false })
|
||||
}
|
||||
}))
|
||||
|
||||
@ -2184,7 +2226,13 @@ public final class VoiceChatController: ViewController {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_DisplayAsSuccess(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return false })
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_DisplayAsSuccess(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_DisplayAsSuccess(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string
|
||||
}
|
||||
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text), action: { _ in return false })
|
||||
}))
|
||||
|
||||
self.stateVersionDisposable.set((self.call.stateVersion
|
||||
@ -2210,7 +2258,13 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
if !hasTooltipAlready {
|
||||
let location = strongSelf.titleNode.recordingIconNode.convert(strongSelf.titleNode.recordingIconNode.bounds, to: nil)
|
||||
strongSelf.controller?.present(TooltipScreen(text: presentationData.strings.VoiceChat_RecordingInProgress, icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = presentationData.strings.LiveStream_RecordingInProgress
|
||||
} else {
|
||||
text = presentationData.strings.VoiceChat_RecordingInProgress
|
||||
}
|
||||
strongSelf.controller?.present(TooltipScreen(text: text, icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: true)
|
||||
}), in: .window(.root))
|
||||
}
|
||||
@ -2457,7 +2511,13 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
|
||||
if canManageCall {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_EditTitle, icon: { theme -> UIImage? in
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_EditTitle
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_EditTitle
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: text, icon: { theme -> UIImage? in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Pencil"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
@ -2571,8 +2631,14 @@ public final class VoiceChatController: ViewController {
|
||||
self?.controller?.present(alertController, in: .window(.root))
|
||||
}), false))
|
||||
} else {
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_StartRecording
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_StartRecording
|
||||
}
|
||||
if strongSelf.callState?.scheduleTimestamp == nil {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_StartRecording, icon: { theme -> UIImage? in
|
||||
items.append(.action(ContextMenuActionItem(text: text, icon: { theme -> UIImage? in
|
||||
return generateStartRecordingIcon(color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
@ -2581,22 +2647,40 @@ public final class VoiceChatController: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
let controller = VoiceChatRecordingSetupController(context: strongSelf.context, completion: { [weak self] videoOrientation in
|
||||
if let strongSelf = self {
|
||||
strongSelf.call.setShouldBeRecording(true, title: "", videoOrientation: videoOrientation)
|
||||
|
||||
strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: strongSelf.presentationData.strings.VoiceChat_RecordingStarted), action: { _ in return false })
|
||||
strongSelf.call.playTone(.recordingStarted)
|
||||
}
|
||||
})
|
||||
// let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: presentationData.strings.VoiceChat_StartRecordingTitle, text: presentationData.strings.VoiceChat_StartRecordingText, placeholder: presentationData.strings.VoiceChat_RecordingTitlePlaceholder, value: nil, maxLength: 40, apply: { title in
|
||||
// if let strongSelf = self, let title = title {
|
||||
// strongSelf.call.setShouldBeRecording(true, title: title)
|
||||
// let controller = VoiceChatRecordingSetupController(context: strongSelf.context, completion: { [weak self] videoOrientation in
|
||||
// if let strongSelf = self {
|
||||
// strongSelf.call.setShouldBeRecording(true, title: "", videoOrientation: videoOrientation)
|
||||
//
|
||||
// strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: strongSelf.presentationData.strings.VoiceChat_RecordingStarted), action: { _ in return false })
|
||||
// strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: text), action: { _ in return false })
|
||||
// strongSelf.call.playTone(.recordingStarted)
|
||||
// }
|
||||
// })
|
||||
|
||||
let title: String
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
title = strongSelf.presentationData.strings.LiveStream_StartRecordingTitle
|
||||
text = strongSelf.presentationData.strings.LiveStream_StartRecordingText
|
||||
} else {
|
||||
title = strongSelf.presentationData.strings.VoiceChat_StartRecordingTitle
|
||||
text = strongSelf.presentationData.strings.VoiceChat_StartRecordingText
|
||||
}
|
||||
|
||||
let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: title, text: text, placeholder: strongSelf.presentationData.strings.VoiceChat_RecordingTitlePlaceholder, value: nil, maxLength: 40, apply: { title in
|
||||
if let strongSelf = self, let title = title {
|
||||
strongSelf.call.setShouldBeRecording(true, title: title, videoOrientation: nil)
|
||||
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = strongSelf.presentationData.strings.LiveStream_RecordingStarted
|
||||
} else {
|
||||
text = strongSelf.presentationData.strings.VoiceChat_RecordingStarted
|
||||
}
|
||||
|
||||
strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: text), action: { _ in return false })
|
||||
strongSelf.call.playTone(.recordingStarted)
|
||||
}
|
||||
})
|
||||
self?.controller?.present(controller, in: .window(.root))
|
||||
})))
|
||||
}
|
||||
@ -2604,7 +2688,13 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
|
||||
if canManageCall {
|
||||
items.append(.action(ContextMenuActionItem(text: isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelVoiceChat : strongSelf.presentationData.strings.VoiceChat_EndVoiceChat, textColor: .destructive, icon: { theme in
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelLiveStream : strongSelf.presentationData.strings.VoiceChat_EndLiveStream
|
||||
} else {
|
||||
text = isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelVoiceChat : strongSelf.presentationData.strings.VoiceChat_EndVoiceChat
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: text, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
@ -2626,13 +2716,29 @@ public final class VoiceChatController: ViewController {
|
||||
})
|
||||
}
|
||||
|
||||
let alertController = textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationTitle : strongSelf.presentationData.strings.VoiceChat_EndConfirmationTitle, text: isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationText : strongSelf.presentationData.strings.VoiceChat_EndConfirmationText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationEnd : strongSelf.presentationData.strings.VoiceChat_EndConfirmationEnd, action: {
|
||||
let title: String
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
title = isScheduled ? strongSelf.presentationData.strings.LiveStream_CancelConfirmationTitle : strongSelf.presentationData.strings.LiveStream_EndConfirmationTitle
|
||||
text = isScheduled ? strongSelf.presentationData.strings.LiveStream_CancelConfirmationText : strongSelf.presentationData.strings.LiveStream_EndConfirmationText
|
||||
} else {
|
||||
title = isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationTitle : strongSelf.presentationData.strings.VoiceChat_EndConfirmationTitle
|
||||
text = isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationText : strongSelf.presentationData.strings.VoiceChat_EndConfirmationText
|
||||
}
|
||||
|
||||
let alertController = textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationEnd : strongSelf.presentationData.strings.VoiceChat_EndConfirmationEnd, action: {
|
||||
action()
|
||||
})])
|
||||
strongSelf.controller?.present(alertController, in: .window(.root))
|
||||
})))
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_LeaveVoiceChat, textColor: .destructive, icon: { theme in
|
||||
let leaveText: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
leaveText = strongSelf.presentationData.strings.LiveStream_LeaveVoiceChat
|
||||
} else {
|
||||
leaveText = strongSelf.presentationData.strings.VoiceChat_LeaveVoiceChat
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: leaveText, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
@ -2949,7 +3055,7 @@ public final class VoiceChatController: ViewController {
|
||||
isGroup = false
|
||||
}
|
||||
let intervalString = scheduledTimeIntervalString(strings: self.presentationData.strings, value: max(60, delta))
|
||||
self.scheduleTextNode.attributedText = NSAttributedString(string: isGroup ? self.presentationData.strings.ScheduleVoiceChat_GroupText(intervalString).string : self.presentationData.strings.ScheduleVoiceChat_ChannelText(intervalString).string, font: Font.regular(14.0), textColor: UIColor(rgb: 0x8e8e93))
|
||||
self.scheduleTextNode.attributedText = NSAttributedString(string: isGroup ? self.presentationData.strings.ScheduleVoiceChat_GroupText(intervalString).string : self.presentationData.strings.ScheduleLiveStream_ChannelText(intervalString).string, font: Font.regular(14.0), textColor: UIColor(rgb: 0x8e8e93))
|
||||
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
||||
@ -3090,14 +3196,35 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
let actionSheet = ActionSheetController(presentationData: self.presentationData.withUpdated(theme: self.darkTheme))
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
let leaveTitle: String
|
||||
let leaveAndCancelTitle: String
|
||||
|
||||
if let channel = self.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
leaveTitle = self.presentationData.strings.LiveStream_LeaveConfirmation
|
||||
leaveAndCancelTitle = self.isScheduled ? self.presentationData.strings.LiveStream_LeaveAndCancelVoiceChat : self.presentationData.strings.LiveStream_LeaveAndEndVoiceChat
|
||||
} else {
|
||||
leaveTitle = self.presentationData.strings.VoiceChat_LeaveConfirmation
|
||||
leaveAndCancelTitle = self.isScheduled ? self.presentationData.strings.VoiceChat_LeaveAndCancelVoiceChat : self.presentationData.strings.VoiceChat_LeaveAndEndVoiceChat
|
||||
}
|
||||
|
||||
items.append(ActionSheetTextItem(title: self.presentationData.strings.VoiceChat_LeaveConfirmation))
|
||||
items.append(ActionSheetButtonItem(title: self.isScheduled ? self.presentationData.strings.VoiceChat_LeaveAndCancelVoiceChat : self.presentationData.strings.VoiceChat_LeaveAndEndVoiceChat, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
items.append(ActionSheetTextItem(title: leaveTitle))
|
||||
items.append(ActionSheetButtonItem(title: leaveAndCancelTitle, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
if let strongSelf = self {
|
||||
let title: String
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
title = strongSelf.isScheduled ? strongSelf.presentationData.strings.LiveStream_CancelConfirmationTitle : strongSelf.presentationData.strings.LiveStream_EndConfirmationTitle
|
||||
text = strongSelf.isScheduled ? strongSelf.presentationData.strings.LiveStream_CancelConfirmationText : strongSelf.presentationData.strings.LiveStream_EndConfirmationText
|
||||
} else {
|
||||
title = strongSelf.isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationTitle : strongSelf.presentationData.strings.VoiceChat_EndConfirmationTitle
|
||||
text = strongSelf.isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationText : strongSelf.presentationData.strings.VoiceChat_EndConfirmationText
|
||||
}
|
||||
|
||||
if let (members, _) = strongSelf.currentCallMembers, members.count >= 10 || true {
|
||||
let alertController = textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: strongSelf.isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationTitle : strongSelf.presentationData.strings.VoiceChat_EndConfirmationTitle, text: strongSelf.isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationText : strongSelf.presentationData.strings.VoiceChat_EndConfirmationText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationEnd : strongSelf.presentationData.strings.VoiceChat_EndConfirmationEnd, action: {
|
||||
let alertController = textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.isScheduled ? strongSelf.presentationData.strings.VoiceChat_CancelConfirmationEnd : strongSelf.presentationData.strings.VoiceChat_EndConfirmationEnd, action: {
|
||||
action()
|
||||
})])
|
||||
strongSelf.controller?.present(alertController, in: .window(.root))
|
||||
@ -3106,7 +3233,15 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.VoiceChat_LeaveVoiceChat, color: .accent, action: { [weak self, weak actionSheet] in
|
||||
|
||||
let leaveText: String
|
||||
if let channel = self.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
leaveText = self.presentationData.strings.LiveStream_LeaveVoiceChat
|
||||
} else {
|
||||
leaveText = self.presentationData.strings.VoiceChat_LeaveVoiceChat
|
||||
}
|
||||
|
||||
items.append(ActionSheetButtonItem(title: leaveText, color: .accent, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
@ -3920,19 +4055,34 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
var title = self.currentTitle
|
||||
if self.isScheduling {
|
||||
title = self.presentationData.strings.ScheduleVoiceChat_Title
|
||||
if let peer = self.peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
title = self.presentationData.strings.ScheduleLiveStream_Title
|
||||
} else {
|
||||
title = self.presentationData.strings.ScheduleVoiceChat_Title
|
||||
}
|
||||
} else if case .modal(_, false) = self.displayMode, !self.currentTitleIsCustom {
|
||||
if let navigationController = self.controller?.navigationController as? NavigationController {
|
||||
for controller in navigationController.viewControllers.reversed() {
|
||||
if let controller = controller as? ChatController, case let .peer(peerId) = controller.chatLocation, peerId == self.call.peerId {
|
||||
title = self.presentationData.strings.VoiceChat_Title
|
||||
if let peer = self.peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
title = self.presentationData.strings.VoiceChatChannel_Title
|
||||
} else {
|
||||
title = self.presentationData.strings.VoiceChat_Title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var subtitle = self.currentSpeakingSubtitle ?? self.currentSubtitle
|
||||
var speaking = self.currentSpeakingSubtitle != nil
|
||||
var subtitle = ""
|
||||
var speaking = false
|
||||
if self.scrollAtTop {
|
||||
subtitle = self.currentSubtitle
|
||||
speaking = false
|
||||
} else {
|
||||
subtitle = self.currentSpeakingSubtitle ?? self.currentSubtitle
|
||||
speaking = self.currentSpeakingSubtitle != nil
|
||||
}
|
||||
if self.isScheduling {
|
||||
subtitle = ""
|
||||
speaking = false
|
||||
@ -4258,7 +4408,7 @@ public final class VoiceChatController: ViewController {
|
||||
childrenSafeInsets.right = childrenSafeInsets.left + (size.width - contentLeftInset)
|
||||
}
|
||||
} else if !self.isLandscape, case .fullscreen = effectiveDisplayMode {
|
||||
childrenInsets.bottom += self.effectiveBottomAreaHeight + fullscreenListHeight + 30.0
|
||||
childrenInsets.bottom += self.effectiveBottomAreaHeight + fullscreenListHeight + 36.0
|
||||
}
|
||||
childrenLayout.safeInsets = childrenSafeInsets
|
||||
childrenLayout.intrinsicInsets = childrenInsets
|
||||
@ -5849,11 +5999,29 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
|
||||
let initialTitle = strongSelf.callState?.title ?? ""
|
||||
let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: strongSelf.presentationData.strings.VoiceChat_EditTitleTitle, text: strongSelf.presentationData.strings.VoiceChat_EditTitleText, placeholder: chatPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), value: initialTitle, maxLength: 40, apply: { title in
|
||||
|
||||
let title: String
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
title = strongSelf.presentationData.strings.LiveStream_EditTitle
|
||||
text = strongSelf.presentationData.strings.LiveStream_EditTitleText
|
||||
} else {
|
||||
title = strongSelf.presentationData.strings.VoiceChat_EditTitle
|
||||
text = strongSelf.presentationData.strings.VoiceChat_EditTitleText
|
||||
}
|
||||
|
||||
let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: title, text: text, placeholder: chatPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), value: initialTitle, maxLength: 40, apply: { title in
|
||||
if let strongSelf = self, let title = title, title != initialTitle {
|
||||
strongSelf.call.updateTitle(title)
|
||||
|
||||
strongSelf.presentUndoOverlay(content: .voiceChatFlag(text: title.isEmpty ? strongSelf.presentationData.strings.VoiceChat_EditTitleRemoveSuccess : strongSelf.presentationData.strings.VoiceChat_EditTitleSuccess(title).string), action: { _ in return false })
|
||||
let text: String
|
||||
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
text = title.isEmpty ? strongSelf.presentationData.strings.LiveStream_EditTitleRemoveSuccess : strongSelf.presentationData.strings.LiveStream_EditTitleSuccess(title).string
|
||||
} else {
|
||||
text = title.isEmpty ? strongSelf.presentationData.strings.VoiceChat_EditTitleRemoveSuccess : strongSelf.presentationData.strings.VoiceChat_EditTitleSuccess(title).string
|
||||
}
|
||||
|
||||
strongSelf.presentUndoOverlay(content: .voiceChatFlag(text: text), action: { _ in return false })
|
||||
}
|
||||
})
|
||||
strongSelf.controller?.present(controller, in: .window(.root))
|
||||
|
@ -389,7 +389,7 @@ class VoiceChatFullscreenParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
profileNode.frame = CGRect(origin: CGPoint(), size: extractedRect.size)
|
||||
self.profileNode = profileNode
|
||||
self.contextSourceNode.contentNode.addSubnode(profileNode)
|
||||
|
||||
|
||||
profileNode.animateIn(from: self, targetRect: extractedRect, transition: transition)
|
||||
var appearenceTransition = transition
|
||||
if transition.isAnimated {
|
||||
@ -706,20 +706,28 @@ class VoiceChatFullscreenParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
audioLevelView.layer.mask = playbackMaskLayer
|
||||
|
||||
audioLevelView.setColor(wavesColor)
|
||||
audioLevelView.alpha = strongSelf.isExtracted ? 0.0 : 1.0
|
||||
|
||||
strongSelf.audioLevelView = audioLevelView
|
||||
strongSelf.offsetContainerNode.view.insertSubview(audioLevelView, at: 0)
|
||||
|
||||
if let _ = strongSelf.item, strongSelf.videoNode != nil && !active {
|
||||
audioLevelView.alpha = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
let level = min(1.0, max(0.0, CGFloat(value)))
|
||||
if let audioLevelView = strongSelf.audioLevelView {
|
||||
audioLevelView.updateLevel(CGFloat(value))
|
||||
|
||||
var hasVideo = false
|
||||
if let videoNode = strongSelf.videoNode, videoNode.supernode == strongSelf.videoContainerNode, !videoNode.alpha.isZero {
|
||||
hasVideo = true
|
||||
}
|
||||
|
||||
var audioLevelAlpha: CGFloat = 1.0
|
||||
if strongSelf.isExtracted {
|
||||
audioLevelAlpha = 0.0
|
||||
} else {
|
||||
audioLevelAlpha = hasVideo ? 0.0 : 1.0
|
||||
}
|
||||
audioLevelView.alpha = audioLevelAlpha
|
||||
|
||||
let avatarScale: CGFloat
|
||||
if value > 0.02 {
|
||||
audioLevelView.startAnimating()
|
||||
|
@ -565,23 +565,35 @@ private class PreviewIconNode: ASDisplayNode {
|
||||
override init() {
|
||||
self.avatar1Node = ASImageNode()
|
||||
self.avatar1Node.cornerRadius = 4.0
|
||||
self.avatar1Node.clipsToBounds = true
|
||||
self.avatar1Node.displaysAsynchronously = false
|
||||
self.avatar1Node.backgroundColor = UIColor(rgb: 0x834fff)
|
||||
self.avatar1Node.image = UIImage(bundleImageName: "Call/Avatar1")
|
||||
self.avatar1Node.contentMode = .bottom
|
||||
|
||||
self.avatar2Node = ASImageNode()
|
||||
self.avatar2Node.cornerRadius = 4.0
|
||||
self.avatar2Node.clipsToBounds = true
|
||||
self.avatar2Node.displaysAsynchronously = false
|
||||
self.avatar2Node.backgroundColor = UIColor(rgb: 0x63d5c9)
|
||||
self.avatar2Node.image = UIImage(bundleImageName: "Call/Avatar2")
|
||||
self.avatar2Node.contentMode = .scaleAspectFit
|
||||
|
||||
self.avatar3Node = ASImageNode()
|
||||
self.avatar3Node.cornerRadius = 4.0
|
||||
self.avatar3Node.clipsToBounds = true
|
||||
self.avatar3Node.displaysAsynchronously = false
|
||||
self.avatar3Node.backgroundColor = UIColor(rgb: 0xccff60)
|
||||
self.avatar3Node.image = UIImage(bundleImageName: "Call/Avatar3")
|
||||
self.avatar3Node.contentMode = .scaleAspectFit
|
||||
|
||||
self.avatar4Node = ASImageNode()
|
||||
self.avatar4Node.cornerRadius = 4.0
|
||||
self.avatar4Node.clipsToBounds = true
|
||||
self.avatar4Node.displaysAsynchronously = false
|
||||
self.avatar4Node.backgroundColor = UIColor(rgb: 0xf5512a)
|
||||
self.avatar4Node.image = UIImage(bundleImageName: "Call/Avatar4")
|
||||
self.avatar4Node.contentMode = .scaleAspectFit
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -234,7 +234,7 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(CachedDisplayAsPeers.self, f: { CachedDisplayAsPeers(decoder: $0) })
|
||||
declareEncodable(WallpapersState.self, f: { WallpapersState(decoder: $0) })
|
||||
declareEncodable(WallpaperDataResource.self, f: { WallpaperDataResource(decoder: $0) })
|
||||
declareEncodable(ForwardHideSendersNamesMessageAttribute.self, f: { ForwardHideSendersNamesMessageAttribute(decoder: $0) })
|
||||
declareEncodable(ForwardOptionsMessageAttribute.self, f: { ForwardOptionsMessageAttribute(decoder: $0) })
|
||||
declareEncodable(ChatTheme.self, f: { ChatTheme(decoder: $0) })
|
||||
declareEncodable(ChatThemes.self, f: { ChatThemes(decoder: $0) })
|
||||
|
||||
|
@ -3,9 +3,11 @@ import Postbox
|
||||
|
||||
public final class AdMessageAttribute: MessageAttribute {
|
||||
public let opaqueId: Data
|
||||
public let startParam: String?
|
||||
|
||||
public init(opaqueId: Data) {
|
||||
public init(opaqueId: Data, startParam: String?) {
|
||||
self.opaqueId = opaqueId
|
||||
self.startParam = startParam
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
|
@ -109,18 +109,46 @@ private func roundUp(_ value: Int, to multiple: Int) -> Int {
|
||||
private let dataHashLength: Int32 = 128 * 1024
|
||||
|
||||
private final class MultipartCdnHashSource {
|
||||
private final class ClusterContext {
|
||||
final class Subscriber {
|
||||
let completion: ([Int32: Data]) -> Void
|
||||
let error: (MultipartFetchDownloadError) -> Void
|
||||
|
||||
init(completion: @escaping ([Int32: Data]) -> Void, error: @escaping (MultipartFetchDownloadError) -> Void) {
|
||||
self.completion = completion
|
||||
self.error = error
|
||||
}
|
||||
}
|
||||
|
||||
let disposable: Disposable
|
||||
let subscribers = Bag<Subscriber>()
|
||||
|
||||
var result: [Int32: Data]?
|
||||
var error: MultipartFetchDownloadError?
|
||||
|
||||
init(disposable: Disposable) {
|
||||
self.disposable = disposable
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private let queue: Queue
|
||||
|
||||
private let fileToken: Data
|
||||
private let masterDownload: DownloadWrapper
|
||||
private let continueInBackground: Bool
|
||||
|
||||
private var clusterContexts: [Int32: ClusterContext] = [:]
|
||||
|
||||
private var knownUpperBound: Int32
|
||||
/*private var knownUpperBound: Int32
|
||||
private var hashes: [Int32: Data] = [:]
|
||||
private var requestOffsetAndDisposable: (Int32, Disposable)?
|
||||
private var requestedUpperBound: Int32?
|
||||
|
||||
private var subscribers = Bag<(Int32, Int32, ([Int32: Data]) -> Void)>()
|
||||
private var subscribers = Bag<(Int32, Int32, ([Int32: Data]) -> Void)>()*/
|
||||
|
||||
init(queue: Queue, fileToken: Data, hashes: [Int32: Data], masterDownload: DownloadWrapper, continueInBackground: Bool) {
|
||||
assert(queue.isCurrent())
|
||||
@ -130,22 +158,17 @@ private final class MultipartCdnHashSource {
|
||||
self.masterDownload = masterDownload
|
||||
self.continueInBackground = continueInBackground
|
||||
|
||||
let knownUpperBound: Int32 = 0
|
||||
/*self.hashes = hashes
|
||||
for (offset, _) in hashes {
|
||||
assert(offset % dataHashLength == 0)
|
||||
knownUpperBound = max(knownUpperBound, offset + dataHashLength)
|
||||
}*/
|
||||
self.knownUpperBound = knownUpperBound
|
||||
/*let knownUpperBound: Int32 = 0
|
||||
self.knownUpperBound = knownUpperBound*/
|
||||
}
|
||||
|
||||
deinit {
|
||||
assert(self.queue.isCurrent())
|
||||
|
||||
self.requestOffsetAndDisposable?.1.dispose()
|
||||
//self.requestOffsetAndDisposable?.1.dispose()
|
||||
}
|
||||
|
||||
private func take(offset: Int32, limit: Int32) -> [Int32: Data]? {
|
||||
/*private func take(offset: Int32, limit: Int32) -> [Int32: Data]? {
|
||||
assert(offset % dataHashLength == 0)
|
||||
assert(limit % dataHashLength == 0)
|
||||
|
||||
@ -162,9 +185,9 @@ private final class MultipartCdnHashSource {
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}*/
|
||||
|
||||
func get(offset: Int32, limit: Int32) -> Signal<[Int32: Data], MultipartFetchDownloadError> {
|
||||
/*func get(offset: Int32, limit: Int32) -> Signal<[Int32: Data], MultipartFetchDownloadError> {
|
||||
assert(self.queue.isCurrent())
|
||||
|
||||
let queue = self.queue
|
||||
@ -262,6 +285,130 @@ private final class MultipartCdnHashSource {
|
||||
}
|
||||
}
|
||||
}))
|
||||
}*/
|
||||
|
||||
func getCluster(offset: Int32, completion: @escaping ([Int32: Data]) -> Void, error: @escaping (MultipartFetchDownloadError) -> Void) -> Disposable {
|
||||
precondition(offset % (1 * 1024 * 1024) == 0)
|
||||
|
||||
let clusterContext: ClusterContext
|
||||
if let current = self.clusterContexts[offset] {
|
||||
clusterContext = current
|
||||
} else {
|
||||
let disposable = MetaDisposable()
|
||||
clusterContext = ClusterContext(disposable: disposable)
|
||||
self.clusterContexts[offset] = clusterContext
|
||||
|
||||
disposable.set((self.masterDownload.request(Api.functions.upload.getCdnFileHashes(fileToken: Buffer(data: self.fileToken), offset: offset), tag: nil, continueInBackground: self.continueInBackground)
|
||||
|> map { partHashes -> [Int32: Data] in
|
||||
var parsedPartHashes: [Int32: Data] = [:]
|
||||
for part in partHashes {
|
||||
switch part {
|
||||
case let .fileHash(offset, limit, bytes):
|
||||
assert(limit == 128 * 1024)
|
||||
parsedPartHashes[offset] = bytes.makeData()
|
||||
}
|
||||
}
|
||||
return parsedPartHashes
|
||||
}
|
||||
|> deliverOn(self.queue)).start(next: { [weak self, weak clusterContext] result in
|
||||
guard let _ = self, let clusterContext = clusterContext else {
|
||||
return
|
||||
}
|
||||
clusterContext.result = result
|
||||
for subscriber in clusterContext.subscribers.copyItems() {
|
||||
subscriber.completion(result)
|
||||
}
|
||||
}, error: { [weak self, weak clusterContext] _ in
|
||||
guard let _ = self, let clusterContext = clusterContext else {
|
||||
return
|
||||
}
|
||||
clusterContext.error = .generic
|
||||
for subscriber in clusterContext.subscribers.copyItems() {
|
||||
subscriber.error(.generic)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if let result = clusterContext.result {
|
||||
completion(result)
|
||||
|
||||
return EmptyDisposable
|
||||
} else if let errorValue = clusterContext.error {
|
||||
error(errorValue)
|
||||
|
||||
return EmptyDisposable
|
||||
} else {
|
||||
let index = clusterContext.subscribers.add(ClusterContext.Subscriber(completion: completion, error: error))
|
||||
let queue = self.queue
|
||||
return ActionDisposable { [weak self, weak clusterContext] in
|
||||
queue.async {
|
||||
guard let strongSelf = self, let clusterContext = clusterContext else {
|
||||
return
|
||||
}
|
||||
clusterContext.subscribers.remove(index)
|
||||
if clusterContext.subscribers.isEmpty {
|
||||
if strongSelf.clusterContexts[offset] === clusterContext {
|
||||
strongSelf.clusterContexts.removeValue(forKey: offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func cluster(offset: Int32) -> Signal<[Int32: Data], MultipartFetchDownloadError> {
|
||||
let queue = self.queue
|
||||
return Signal { [weak self] subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
queue.async {
|
||||
guard let strongSelf = self else {
|
||||
subscriber.putError(.generic)
|
||||
return
|
||||
}
|
||||
|
||||
disposable.set(strongSelf.getCluster(offset: offset, completion: { result in
|
||||
subscriber.putNext(result)
|
||||
subscriber.putCompletion()
|
||||
}, error: { error in
|
||||
subscriber.putError(error)
|
||||
}))
|
||||
}
|
||||
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
func get(offset: Int32, limit: Int32) -> Signal<[Int32: Data], MultipartFetchDownloadError> {
|
||||
precondition(offset % dataHashLength == 0)
|
||||
precondition((offset + limit) % dataHashLength == 0)
|
||||
|
||||
var clusterOffsets = Set<Int32>()
|
||||
for partOffset in stride(from: offset, to: offset + limit, by: Int(dataHashLength)) {
|
||||
clusterOffsets.insert(partOffset - (partOffset % (1 * 1024 * 1024)))
|
||||
}
|
||||
|
||||
return combineLatest(clusterOffsets.map { clusterOffset in
|
||||
return self.cluster(offset: clusterOffset)
|
||||
})
|
||||
|> mapToSignal { clusterResults -> Signal<[Int32: Data], MultipartFetchDownloadError> in
|
||||
var result: [Int32: Data] = [:]
|
||||
|
||||
for partOffset in stride(from: offset, to: offset + limit, by: Int(dataHashLength)) {
|
||||
var found = false
|
||||
for cluster in clusterResults {
|
||||
if let data = cluster[partOffset] {
|
||||
result[partOffset] = data
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|
||||
return .single(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAtt
|
||||
return true
|
||||
case _ as EmojiSearchQueryMessageAttribute:
|
||||
return true
|
||||
case _ as ForwardHideSendersNamesMessageAttribute:
|
||||
case _ as ForwardOptionsMessageAttribute:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@ -132,7 +132,7 @@ private func filterMessageAttributesForForwardedMessage(_ attributes: [MessageAt
|
||||
return true
|
||||
case _ as OutgoingScheduleInfoMessageAttribute:
|
||||
return true
|
||||
case _ as ForwardHideSendersNamesMessageAttribute:
|
||||
case _ as ForwardOptionsMessageAttribute:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@ -520,6 +520,8 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
||||
case let .forward(source, grouping, requestedAttributes, correlationId):
|
||||
let sourceMessage = transaction.getMessage(source)
|
||||
if let sourceMessage = sourceMessage, let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] {
|
||||
var messageText = sourceMessage.text
|
||||
|
||||
if let peer = peer as? TelegramSecretChat {
|
||||
var isAction = false
|
||||
for media in sourceMessage.media {
|
||||
@ -564,13 +566,24 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
||||
var forwardInfo: StoreMessageForwardInfo?
|
||||
|
||||
var hideSendersNames = false
|
||||
var hideCaptions = false
|
||||
for attribute in requestedAttributes {
|
||||
if let _ = attribute as? ForwardHideSendersNamesMessageAttribute {
|
||||
hideSendersNames = true
|
||||
if let attribute = attribute as? ForwardOptionsMessageAttribute {
|
||||
hideSendersNames = attribute.hideNames
|
||||
hideCaptions = attribute.hideCaptions
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hideCaptions {
|
||||
for media in sourceMessage.media {
|
||||
if media is TelegramMediaImage || media is TelegramMediaFile {
|
||||
messageText = ""
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sourceMessage.id.namespace == Namespaces.Message.Cloud && peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
attributes.append(ForwardSourceInfoAttribute(messageId: sourceMessage.id))
|
||||
|
||||
@ -725,7 +738,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
||||
augmentedMediaList = augmentedMediaList.map(convertForwardedMediaForSecretChat)
|
||||
}
|
||||
|
||||
storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: sourceMessage.text, attributes: attributes, media: augmentedMediaList))
|
||||
storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: augmentedMediaList))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2447,7 +2447,7 @@ func replayFinalState(accountManager: AccountManager<TelegramAccountManagerTypes
|
||||
})
|
||||
}
|
||||
switch action.action {
|
||||
case let .setChatTheme(emoji):
|
||||
case let .setChatTheme(emoticon):
|
||||
transaction.updatePeerCachedData(peerIds: [message.id.peerId], update: { peerId, current in
|
||||
var current = current
|
||||
if current == nil {
|
||||
@ -2460,11 +2460,11 @@ func replayFinalState(accountManager: AccountManager<TelegramAccountManagerTypes
|
||||
}
|
||||
}
|
||||
if let cachedData = current as? CachedUserData {
|
||||
return cachedData.withUpdatedThemeEmoticon(!emoji.isEmpty ? emoji : nil)
|
||||
return cachedData.withUpdatedThemeEmoticon(!emoticon.isEmpty ? emoticon : nil)
|
||||
} else if let cachedData = current as? CachedGroupData {
|
||||
return cachedData.withUpdatedThemeEmoticon(!emoji.isEmpty ? emoji : nil)
|
||||
return cachedData.withUpdatedThemeEmoticon(!emoticon.isEmpty ? emoticon : nil)
|
||||
} else if let cachedData = current as? CachedChannelData {
|
||||
return cachedData.withUpdatedThemeEmoticon(!emoji.isEmpty ? emoji : nil)
|
||||
return cachedData.withUpdatedThemeEmoticon(!emoticon.isEmpty ? emoticon : nil)
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
|
@ -698,6 +698,7 @@ public final class PendingMessageManager {
|
||||
} else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
var isForward = false
|
||||
var hideSendersNames = false
|
||||
var hideCaptions = false
|
||||
var replyMessageId: Int32?
|
||||
var scheduleTime: Int32?
|
||||
|
||||
@ -715,8 +716,9 @@ public final class PendingMessageManager {
|
||||
} else if let attribute = attribute as? OutgoingScheduleInfoMessageAttribute {
|
||||
flags |= Int32(1 << 10)
|
||||
scheduleTime = attribute.scheduleTime
|
||||
} else if let _ = attribute as? ForwardHideSendersNamesMessageAttribute {
|
||||
hideSendersNames = true
|
||||
} else if let attribute = attribute as? ForwardOptionsMessageAttribute {
|
||||
hideSendersNames = attribute.hideNames
|
||||
hideCaptions = attribute.hideCaptions
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,6 +730,9 @@ public final class PendingMessageManager {
|
||||
if hideSendersNames {
|
||||
flags |= (1 << 11)
|
||||
}
|
||||
if hideCaptions {
|
||||
flags |= (1 << 12)
|
||||
}
|
||||
|
||||
var forwardIds: [(MessageId, Int64)] = []
|
||||
for (message, content) in messages {
|
||||
|
@ -309,6 +309,6 @@ public final class CachedGroupData: CachedPeerData {
|
||||
}
|
||||
|
||||
public func withUpdatedThemeEmoticon(_ themeEmoticon: String?) -> CachedGroupData {
|
||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: callJoinPeerId, themeEmoticon: themeEmoticon)
|
||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: themeEmoticon)
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,22 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public class ForwardHideSendersNamesMessageAttribute: MessageAttribute {
|
||||
public init() {
|
||||
public class ForwardOptionsMessageAttribute: MessageAttribute {
|
||||
public let hideNames: Bool
|
||||
public let hideCaptions: Bool
|
||||
|
||||
public init(hideNames: Bool, hideCaptions: Bool) {
|
||||
self.hideNames = hideNames
|
||||
self.hideCaptions = hideCaptions
|
||||
}
|
||||
|
||||
required public init(decoder: PostboxDecoder) {
|
||||
self.hideNames = decoder.decodeBoolForKey("hideNames", orElse: false)
|
||||
self.hideCaptions = decoder.decodeBoolForKey("hideCaptions", orElse: false)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeBool(self.hideNames, forKey: "hideNames")
|
||||
encoder.encodeBool(self.hideCaptions, forKey: "hideCaptions")
|
||||
}
|
||||
}
|
||||
|
@ -111,5 +111,13 @@ public extension TelegramEngine {
|
||||
public func groupCall(peerId: PeerId, myPeerId: PeerId, id: Int64, accessHash: Int64, state: GroupCallParticipantsContext.State, previousServiceState: GroupCallParticipantsContext.ServiceState?) -> GroupCallParticipantsContext {
|
||||
return GroupCallParticipantsContext(account: self.account, peerId: peerId, myPeerId: myPeerId, id: id, accessHash: accessHash, state: state, previousServiceState: previousServiceState)
|
||||
}
|
||||
|
||||
public func serverTime() -> Signal<Int64, NoError> {
|
||||
return self.account.network.currentGlobalTime
|
||||
|> map { value -> Int64 in
|
||||
return Int64(value * 1000.0)
|
||||
}
|
||||
|> take(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
case textEntities
|
||||
case media
|
||||
case authorId
|
||||
case startParam
|
||||
}
|
||||
|
||||
public let opaqueId: Data
|
||||
@ -18,19 +19,22 @@ private class AdMessagesHistoryContextImpl {
|
||||
public let textEntities: [MessageTextEntity]
|
||||
public let media: [Media]
|
||||
public let authorId: PeerId
|
||||
public let startParam: String?
|
||||
|
||||
public init(
|
||||
opaqueId: Data,
|
||||
text: String,
|
||||
textEntities: [MessageTextEntity],
|
||||
media: [Media],
|
||||
authorId: PeerId
|
||||
authorId: PeerId,
|
||||
startParam: String?
|
||||
) {
|
||||
self.opaqueId = opaqueId
|
||||
self.text = text
|
||||
self.textEntities = textEntities
|
||||
self.media = media
|
||||
self.authorId = authorId
|
||||
self.startParam = startParam
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@ -47,6 +51,8 @@ private class AdMessagesHistoryContextImpl {
|
||||
}
|
||||
|
||||
self.authorId = try container.decode(PeerId.self, forKey: .authorId)
|
||||
|
||||
self.startParam = try container.decodeIfPresent(String.self, forKey: .startParam)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -64,6 +70,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
try container.encode(mediaData, forKey: .media)
|
||||
|
||||
try container.encode(self.authorId, forKey: .authorId)
|
||||
try container.encodeIfPresent(self.startParam, forKey: .startParam)
|
||||
}
|
||||
|
||||
public static func ==(lhs: CachedMessage, rhs: CachedMessage) -> Bool {
|
||||
@ -87,13 +94,16 @@ private class AdMessagesHistoryContextImpl {
|
||||
if lhs.authorId != rhs.authorId {
|
||||
return false
|
||||
}
|
||||
if lhs.startParam != rhs.startParam {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func toMessage(peerId: PeerId, transaction: Transaction) -> Message {
|
||||
var attributes: [MessageAttribute] = []
|
||||
|
||||
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId))
|
||||
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, startParam: self.startParam))
|
||||
if !self.textEntities.isEmpty {
|
||||
let attribute = TextEntitiesMessageAttribute(entities: self.textEntities)
|
||||
attributes.append(attribute)
|
||||
@ -307,25 +317,27 @@ private class AdMessagesHistoryContextImpl {
|
||||
|
||||
for message in messages {
|
||||
switch message {
|
||||
case let .sponsoredMessage(_, randomId, _, fromId, message, media, entities):
|
||||
case let .sponsoredMessage(_, randomId, fromId, startParam, message, entities):
|
||||
var parsedEntities: [MessageTextEntity] = []
|
||||
if let entities = entities {
|
||||
parsedEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
}
|
||||
|
||||
var parsedMedia: [Media] = []
|
||||
if let media = media {
|
||||
let parsedMedia: [Media] = []
|
||||
/*if let media = media {
|
||||
let (mediaValue, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
if let mediaValue = mediaValue {
|
||||
parsedMedia.append(mediaValue)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
parsedMessages.append(CachedMessage(
|
||||
opaqueId: randomId.makeData(),
|
||||
text: message,
|
||||
textEntities: parsedEntities,
|
||||
media: parsedMedia, authorId: fromId.peerId
|
||||
media: parsedMedia,
|
||||
authorId: fromId.peerId,
|
||||
startParam: startParam
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ public enum AdminLogEventAction {
|
||||
case editExportedInvitation(previous: ExportedInvitation, updated: ExportedInvitation)
|
||||
case participantJoinedViaInvite(ExportedInvitation)
|
||||
case changeHistoryTTL(previousValue: Int32?, updatedValue: Int32?)
|
||||
case changeTheme(previous: String?, updated: String?)
|
||||
}
|
||||
|
||||
public enum ChannelAdminLogEventError {
|
||||
@ -249,6 +250,8 @@ func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, m
|
||||
action = .groupCallUpdateParticipantVolume(peerId: parsedParticipant.peerId, volume: parsedParticipant.volume ?? 10000)
|
||||
case let .channelAdminLogEventActionChangeHistoryTTL(prevValue, newValue):
|
||||
action = .changeHistoryTTL(previousValue: prevValue, updatedValue: newValue)
|
||||
case let .channelAdminLogEventActionChangeTheme(prevValue, newValue):
|
||||
action = .changeTheme(previous: prevValue, updated: newValue)
|
||||
}
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||
if let action = action {
|
||||
|
@ -549,8 +549,11 @@ public extension TelegramEngine {
|
||||
}
|
||||
}
|
||||
|
||||
guard let peerGroupId = transaction.getPeerChatListIndex(peerId)?.0 else {
|
||||
return nil
|
||||
let peerGroupId: PeerGroupId
|
||||
if let peerGroupIdValue = transaction.getPeerChatListIndex(peerId)?.0 {
|
||||
peerGroupId = peerGroupIdValue
|
||||
} else {
|
||||
peerGroupId = .root
|
||||
}
|
||||
|
||||
if let filterId = chatListFilterId {
|
||||
|
@ -111,7 +111,7 @@ func _internal_getChatThemes(accountManager: AccountManager<TelegramAccountManag
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_setChatTheme(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, emoji: String?) -> Signal<Void, NoError> {
|
||||
func _internal_setChatTheme(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, emoticon: String?) -> Signal<Void, NoError> {
|
||||
return postbox.loadedPeerWithId(peerId)
|
||||
|> mapToSignal { peer in
|
||||
guard let inputPeer = apiInputPeer(peer) else {
|
||||
@ -121,17 +121,17 @@ func _internal_setChatTheme(postbox: Postbox, network: Network, stateManager: Ac
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||
if let current = current as? CachedUserData {
|
||||
return current.withUpdatedThemeEmoticon(emoji)
|
||||
return current.withUpdatedThemeEmoticon(emoticon)
|
||||
} else if let current = current as? CachedGroupData {
|
||||
return current.withUpdatedThemeEmoticon(emoji)
|
||||
return current.withUpdatedThemeEmoticon(emoticon)
|
||||
} else if let current = current as? CachedChannelData {
|
||||
return current.withUpdatedThemeEmoticon(emoji)
|
||||
return current.withUpdatedThemeEmoticon(emoticon)
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
})
|
||||
|
||||
return network.request(Api.functions.messages.setChatTheme(peer: inputPeer, emoticon: emoji ?? ""))
|
||||
return network.request(Api.functions.messages.setChatTheme(peer: inputPeer, emoticon: emoticon ?? ""))
|
||||
|> `catch` { error in
|
||||
return .complete()
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ public extension TelegramEngine {
|
||||
return _internal_getChatThemes(accountManager: accountManager, network: self.account.network, forceUpdate: forceUpdate, onlyCached: onlyCached)
|
||||
}
|
||||
|
||||
public func setChatTheme(peerId: PeerId, emoji: String?) -> Signal<Void, NoError> {
|
||||
return _internal_setChatTheme(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, emoji: emoji)
|
||||
public func setChatTheme(peerId: PeerId, emoticon: String?) -> Signal<Void, NoError> {
|
||||
return _internal_setChatTheme(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, emoticon: emoticon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +167,8 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
||||
case locationProximityAlertTip = 20
|
||||
case nextChatSuggestionTip = 21
|
||||
case dismissedTrendingStickerPacks = 22
|
||||
case chatSpecificThemesDarkPreviewTip = 23
|
||||
case chatForwardOptionsTip = 24
|
||||
|
||||
var key: ValueBoxKey {
|
||||
let v = ValueBoxKey(length: 4)
|
||||
@ -306,6 +308,14 @@ private struct ApplicationSpecificNoticeKeys {
|
||||
static func dismissedTrendingStickerPacks() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedTrendingStickerPacks.key)
|
||||
}
|
||||
|
||||
static func chatSpecificThemesDarkPreviewTip() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatSpecificThemesDarkPreviewTip.key)
|
||||
}
|
||||
|
||||
static func chatForwardOptionsTip() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatForwardOptionsTip.key)
|
||||
}
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificNotice {
|
||||
@ -813,6 +823,56 @@ public struct ApplicationSpecificNotice {
|
||||
}
|
||||
}
|
||||
|
||||
public static func getChatSpecificThemesDarkPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemesDarkPreviewTip()) as? ApplicationSpecificCounterNotice {
|
||||
return value.value
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func incrementChatSpecificThemesDarkPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
|
||||
return accountManager.transaction { transaction -> Int in
|
||||
var currentValue: Int32 = 0
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemesDarkPreviewTip()) as? ApplicationSpecificCounterNotice {
|
||||
currentValue = value.value
|
||||
}
|
||||
let previousValue = currentValue
|
||||
currentValue += Int32(count)
|
||||
|
||||
transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemesDarkPreviewTip(), ApplicationSpecificCounterNotice(value: currentValue))
|
||||
|
||||
return Int(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
public static func getChatForwardOptionsTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip()) as? ApplicationSpecificCounterNotice {
|
||||
return value.value
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func incrementChatForwardOptionsTip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
|
||||
return accountManager.transaction { transaction -> Int in
|
||||
var currentValue: Int32 = 0
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip()) as? ApplicationSpecificCounterNotice {
|
||||
currentValue = value.value
|
||||
}
|
||||
let previousValue = currentValue
|
||||
currentValue += Int32(count)
|
||||
|
||||
transaction.setNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip(), ApplicationSpecificCounterNotice(value: currentValue))
|
||||
|
||||
return Int(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
public static func reset(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Void, NoError> {
|
||||
return accountManager.transaction { transaction -> Void in
|
||||
}
|
||||
|
@ -696,8 +696,10 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
|
||||
let buttonStrokeColor = accentColor.withMultiplied(hue: 1.014, saturation: 0.56, brightness: 0.64).withAlphaComponent(0.15)
|
||||
let incomingFillColor = mainBackgroundColor.withMultipliedAlpha(0.9)
|
||||
|
||||
let incomingBubbleAlpha: CGFloat = 0.9
|
||||
|
||||
let message = PresentationThemeChatMessage(
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: [incomingFillColor], highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor, shadow: nil), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: [incomingFillColor], highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor, shadow: nil)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: UIColor(rgb: 0xff6767), textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, accentControlDisabledColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.5), mediaControlInnerBackgroundColor: mainBackgroundColor, pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: accentColor, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.585, brightness: 0.23), polls: PresentationThemeChatBubblePolls(radioButton: accentColor.withMultiplied(hue: 0.995, saturation: 0.317, brightness: 0.51), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: mainSeparatorColor, bar: accentColor, barIconForeground: .white, barPositive: UIColor(rgb: 0x00A700), barNegative: UIColor(rgb: 0xFE3824)), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: [incomingFillColor.withAlphaComponent(incomingBubbleAlpha)], highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor, shadow: nil), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: [incomingFillColor.withAlphaComponent(incomingBubbleAlpha)], highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor, shadow: nil)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: UIColor(rgb: 0xff6767), textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, accentControlDisabledColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.5), mediaControlInnerBackgroundColor: mainBackgroundColor, pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: accentColor, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.585, brightness: 0.23), polls: PresentationThemeChatBubblePolls(radioButton: accentColor.withMultiplied(hue: 0.995, saturation: 0.317, brightness: 0.51), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: mainSeparatorColor, bar: accentColor, barIconForeground: .white, barPositive: UIColor(rgb: 0x00A700), barNegative: UIColor(rgb: 0xFE3824)), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColors, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleFillColors[0], shadow: nil), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColors, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleFillColors[0], shadow: nil)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor.white.withAlphaComponent(0.5), scamColor: outgoingScamColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, accentControlDisabledColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, mediaControlInnerBackgroundColor: outgoingBubbleFillColors[0], pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.804, brightness: 0.51), polls: PresentationThemeChatBubblePolls(radioButton: outgoingPrimaryTextColor, radioProgress: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0), highlight: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0).withAlphaComponent(0.12), separator: mainSeparatorColor, bar: outgoingPrimaryTextColor, barIconForeground: .clear, barPositive: outgoingPrimaryTextColor, barNegative: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
|
||||
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: [mainBackgroundColor], highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor, shadow: nil), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: [mainBackgroundColor], highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor, shadow: nil)),
|
||||
infoPrimaryTextColor: UIColor(rgb: 0xffffff),
|
||||
|
@ -35,7 +35,7 @@ public let defaultServiceBackgroundColor = UIColor(rgb: 0x000000, alpha: 0.2)
|
||||
public let defaultPresentationTheme = makeDefaultDayPresentationTheme(serviceBackgroundColor: defaultServiceBackgroundColor, day: false, preview: false)
|
||||
public let defaultDayAccentColor = UIColor(rgb: 0x007ee5)
|
||||
|
||||
public func customizeDefaultDayTheme(theme: PresentationTheme, editing: Bool, title: String?, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper forcedWallpaper: TelegramWallpaper? = nil, serviceBackgroundColor: UIColor?) -> PresentationTheme {
|
||||
public func customizeDefaultDayTheme(theme: PresentationTheme, specialMode: Bool = false, editing: Bool, title: String?, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper forcedWallpaper: TelegramWallpaper? = nil, serviceBackgroundColor: UIColor?) -> PresentationTheme {
|
||||
if (theme.referenceTheme != .day && theme.referenceTheme != .dayClassic) {
|
||||
return theme
|
||||
}
|
||||
@ -52,24 +52,74 @@ public func customizeDefaultDayTheme(theme: PresentationTheme, editing: Bool, ti
|
||||
var suggestedWallpaper: TelegramWallpaper?
|
||||
|
||||
var bubbleColors = bubbleColors
|
||||
if bubbleColors.isEmpty, editing {
|
||||
if day {
|
||||
let accentColor = accentColor ?? defaultDayAccentColor
|
||||
bubbleColors = [accentColor.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98).rgb, accentColor.rgb]
|
||||
} else {
|
||||
if let accentColor = accentColor, !accentColor.alpha.isZero {
|
||||
let hsb = accentColor.hsb
|
||||
bubbleColors = [UIColor(hue: hsb.0, saturation: (hsb.1 > 0.0 && hsb.2 > 0.0) ? 0.14 : 0.0, brightness: 0.79 + hsb.2 * 0.21, alpha: 1.0).rgb]
|
||||
if accentColor.lightness > 0.705 {
|
||||
outgoingAccent = UIColor(hue: hsb.0, saturation: min(1.0, hsb.1 * 1.1), brightness: min(hsb.2, 0.6), alpha: 1.0)
|
||||
} else {
|
||||
outgoingAccent = accentColor
|
||||
if specialMode, bubbleColors.count < 3, let color = bubbleColors.first.flatMap({ UIColor(rgb: $0) }) {
|
||||
let colorHSB = color.hsb
|
||||
if colorHSB.b > 0.9 {
|
||||
let bubbleColor = color.withMultiplied(hue: 0.9, saturation: 1.3, brightness: 1.0)
|
||||
bubbleColors = [bubbleColor.rgb]
|
||||
|
||||
let colorPairs: [(UInt32, UInt32)] = [
|
||||
(0xe5f9d7, 0x6cd516),
|
||||
(0xe7f5ff, 0x43b6f9),
|
||||
(0xe3f7f5, 0x4ccbb8),
|
||||
(0xfff6cf, 0xe8b816),
|
||||
(0xfffac9, 0xe2c714),
|
||||
(0xc5a61e, 0xd6b534)
|
||||
]
|
||||
|
||||
func generateAccentColor(color: UIColor) -> UIColor {
|
||||
var nearest: (color: (UInt32, UInt32), distance: Int32)?
|
||||
for (sample, accentSample) in colorPairs {
|
||||
let distance = color.distance(to: UIColor(rgb: sample))
|
||||
if let currentNearest = nearest {
|
||||
if distance < currentNearest.distance {
|
||||
nearest = ((sample, accentSample), distance)
|
||||
}
|
||||
} else {
|
||||
nearest = ((sample, accentSample), distance)
|
||||
}
|
||||
}
|
||||
|
||||
suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
|
||||
|
||||
if let colors = nearest?.color {
|
||||
let colorHsb = color.hsb
|
||||
let similarColorHsb = UIColor(rgb: colors.0).hsb
|
||||
let accentColorHsb = UIColor(rgb: colors.1).hsb
|
||||
|
||||
let correction = (similarColorHsb.0 > 0.0 ? colorHsb.0 / similarColorHsb.0 : 1.0, similarColorHsb.1 > 0.0 ? colorHsb.1 / similarColorHsb.1 : 1.0, similarColorHsb.2 > 0.0 ? colorHsb.2 / similarColorHsb.2 : 1.0)
|
||||
let correctedComplementingColor = UIColor(hue: min(1.0, accentColorHsb.0 * correction.0), saturation: min(1.0, accentColorHsb.1 * correction.1), brightness: min(1.0, accentColorHsb.2 * correction.2), alpha: 1.0)
|
||||
return correctedComplementingColor
|
||||
} else {
|
||||
return color
|
||||
}
|
||||
}
|
||||
|
||||
outgoingAccent = generateAccentColor(color: color)
|
||||
} else {
|
||||
let bubbleColor = color.withMultiplied(hue: 1.014, saturation: 0.12, brightness: 1.29)
|
||||
bubbleColors = [bubbleColor.rgb]
|
||||
|
||||
outgoingAccent = color
|
||||
}
|
||||
} else {
|
||||
if bubbleColors.isEmpty, editing {
|
||||
if day {
|
||||
let accentColor = accentColor ?? defaultDayAccentColor
|
||||
bubbleColors = [accentColor.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98).rgb, accentColor.rgb]
|
||||
} else {
|
||||
bubbleColors = [UIColor(rgb: 0xe1ffc7).rgb]
|
||||
suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
|
||||
if let accentColor = accentColor, !accentColor.alpha.isZero {
|
||||
let hsb = accentColor.hsb
|
||||
bubbleColors = [UIColor(hue: hsb.0, saturation: (hsb.1 > 0.0 && hsb.2 > 0.0) ? 0.14 : 0.0, brightness: 0.79 + hsb.2 * 0.21, alpha: 1.0).rgb]
|
||||
if accentColor.lightness > 0.705 {
|
||||
outgoingAccent = UIColor(hue: hsb.0, saturation: min(1.0, hsb.1 * 1.1), brightness: min(hsb.2, 0.6), alpha: 1.0)
|
||||
} else {
|
||||
outgoingAccent = accentColor
|
||||
}
|
||||
|
||||
suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
|
||||
} else {
|
||||
bubbleColors = [UIColor(rgb: 0xe1ffc7).rgb]
|
||||
suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,7 +218,7 @@ public func customizeDefaultDayTheme(theme: PresentationTheme, editing: Bool, ti
|
||||
outgoingLinkTextColor = outgoingAccent
|
||||
outgoingScamColor = UIColor(rgb: 0xff3b30)
|
||||
outgoingControlColor = outgoingAccent
|
||||
outgoingInactiveControlColor = outgoingAccent //1111
|
||||
outgoingInactiveControlColor = outgoingAccent
|
||||
outgoingFileTitleColor = outgoingAccent
|
||||
outgoingPollsProgressColor = accentColor
|
||||
outgoingSelectionColor = outgoingAccent.withMultiplied(hue: 1.0, saturation: 1.292, brightness: 0.871)
|
||||
|
@ -19,13 +19,13 @@ public func makeDefaultPresentationTheme(reference: PresentationBuiltinThemeRefe
|
||||
return theme
|
||||
}
|
||||
|
||||
public func customizePresentationTheme(_ theme: PresentationTheme, editing: Bool, title: String? = nil, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil) -> PresentationTheme {
|
||||
public func customizePresentationTheme(_ theme: PresentationTheme, specialMode: Bool = false, editing: Bool, title: String? = nil, accentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil) -> PresentationTheme {
|
||||
if accentColor == nil && bubbleColors.isEmpty && backgroundColors.isEmpty && wallpaper == nil {
|
||||
return theme
|
||||
}
|
||||
switch theme.referenceTheme {
|
||||
case .day, .dayClassic:
|
||||
return customizeDefaultDayTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors ?? false, wallpaper: wallpaper, serviceBackgroundColor: nil)
|
||||
return customizeDefaultDayTheme(theme: theme, specialMode: specialMode, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors ?? false, wallpaper: wallpaper, serviceBackgroundColor: nil)
|
||||
case .night:
|
||||
return customizeDefaultDarkPresentationTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors ?? false, wallpaper: wallpaper, baseColor: baseColor)
|
||||
case .nightAccent:
|
||||
@ -33,17 +33,21 @@ public func customizePresentationTheme(_ theme: PresentationTheme, editing: Bool
|
||||
}
|
||||
}
|
||||
|
||||
public func makePresentationTheme(settings: TelegramThemeSettings, title: String? = nil, serviceBackgroundColor: UIColor? = nil) -> PresentationTheme? {
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: nil, serviceBackgroundColor: serviceBackgroundColor, preview: false)
|
||||
return customizePresentationTheme(defaultTheme, editing: true, title: title, accentColor: UIColor(argb: settings.accentColor), backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
|
||||
public func makePresentationTheme(settings: TelegramThemeSettings, specialMode: Bool = false, title: String? = nil, serviceBackgroundColor: UIColor? = nil) -> PresentationTheme? {
|
||||
var baseTheme: TelegramBaseTheme = settings.baseTheme
|
||||
if specialMode && baseTheme == .night {
|
||||
baseTheme = .tinted
|
||||
}
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: baseTheme), extendingThemeReference: nil, serviceBackgroundColor: serviceBackgroundColor, preview: false)
|
||||
return customizePresentationTheme(defaultTheme, specialMode: specialMode, editing: true, title: title, accentColor: UIColor(argb: settings.accentColor), backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
|
||||
}
|
||||
|
||||
public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: [UInt32] = [], animateBubbleColors: Bool? = nil, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil, serviceBackgroundColor: UIColor? = nil, preview: Bool = false) -> PresentationTheme? {
|
||||
public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: [UInt32] = [], animateBubbleColors: Bool? = nil, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil, serviceBackgroundColor: UIColor? = nil, specialMode: Bool = false, preview: Bool = false) -> PresentationTheme? {
|
||||
let theme: PresentationTheme
|
||||
switch themeReference {
|
||||
case let .builtin(reference):
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: reference, extendingThemeReference: extendingThemeReference, serviceBackgroundColor: serviceBackgroundColor, preview: preview)
|
||||
theme = customizePresentationTheme(defaultTheme, editing: true, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors, wallpaper: wallpaper, baseColor: baseColor)
|
||||
theme = customizePresentationTheme(defaultTheme, specialMode: specialMode, editing: true, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors, wallpaper: wallpaper, baseColor: baseColor)
|
||||
case let .local(info):
|
||||
if let path = mediaBox.completedResourcePath(info.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let loadedTheme = makePresentationTheme(data: data, themeReference: themeReference, resolvedWallpaper: info.resolvedWallpaper) {
|
||||
theme = customizePresentationTheme(loadedTheme, editing: false, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors, wallpaper: wallpaper)
|
||||
|
@ -136,6 +136,11 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatInputPanelEncircledCloseIconImage
|
||||
case chatInputPanelVerticalSeparatorLineImage
|
||||
|
||||
case chatInputPanelForwardIconImage
|
||||
case chatInputPanelReplyIconImage
|
||||
case chatInputPanelEditIconImage
|
||||
case chatInputPanelWebpageIconImage
|
||||
|
||||
case chatMediaInputPanelHighlightedIconImage
|
||||
case chatInputMediaPanelSavedStickersIconImage
|
||||
case chatInputMediaPanelRecentStickersIconImage
|
||||
|
@ -195,7 +195,7 @@ public struct PresentationResourcesChat {
|
||||
return generateImage(CGSize(width: 12.0, height: 12.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setBlendMode(.copy)
|
||||
context.setStrokeColor(theme.chat.inputPanel.panelControlColor.cgColor)
|
||||
context.setStrokeColor(theme.chat.inputPanel.panelControlAccentColor.cgColor)
|
||||
context.setLineWidth(2.0)
|
||||
context.setLineCap(.round)
|
||||
context.move(to: CGPoint(x: 1.0, y: 1.0))
|
||||
@ -226,6 +226,30 @@ public struct PresentationResourcesChat {
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputPanelForwardIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputPanelForwardIconImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/ForwardIcon"), color: theme.chat.inputPanel.panelControlAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputPanelReplyIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputPanelReplyIconImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/ReplyIcon"), color: theme.chat.inputPanel.panelControlAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputPanelEditIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputPanelEditIconImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/EditIcon"), color: theme.chat.inputPanel.panelControlAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputPanelWebpageIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputPanelWebpageIconImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/WebpageIcon"), color: theme.chat.inputPanel.panelControlAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatMediaInputPanelHighlightedIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatMediaInputPanelHighlightedIconImage.rawValue, { theme in
|
||||
return generateStretchableFilledCircleImage(radius: 9.0, color: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor)
|
||||
@ -234,7 +258,7 @@ public struct PresentationResourcesChat {
|
||||
|
||||
public static func chatInputMediaPanelSavedStickersIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelSavedStickersIconImage.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
|
||||
return generateImage(CGSize(width: 42.0, height: 42.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/SavedStickersTabIcon"), color: theme.chat.inputMediaPanel.panelIconColor) {
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
@ -245,7 +269,7 @@ public struct PresentationResourcesChat {
|
||||
|
||||
public static func chatInputMediaPanelStickersModeIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelStickersModeIcon.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
|
||||
return generateImage(CGSize(width: 42.0, height: 42.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/StickersMode"), color: theme.chat.inputMediaPanel.panelIconColor) {
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
@ -256,7 +280,7 @@ public struct PresentationResourcesChat {
|
||||
|
||||
public static func chatInputMediaPanelTrendingGifsIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelTrendingGifsIcon.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
|
||||
return generateImage(CGSize(width: 42.0, height: 42.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/TrendingGifs"), color: theme.chat.inputMediaPanel.panelIconColor) {
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
@ -267,7 +291,7 @@ public struct PresentationResourcesChat {
|
||||
|
||||
public static func chatInputMediaPanelRecentStickersIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelRecentStickersIconImage.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
|
||||
return generateImage(CGSize(width: 42.0, height: 42.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/RecentTabIcon"), color: theme.chat.inputMediaPanel.panelIconColor) {
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
@ -278,7 +302,7 @@ public struct PresentationResourcesChat {
|
||||
|
||||
public static func chatInputMediaPanelRecentGifsIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelRecentGifsIconImage.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
|
||||
return generateImage(CGSize(width: 42.0, height: 42.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/GifsTabIcon"), color: theme.chat.inputMediaPanel.panelIconColor) {
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
|
@ -41,6 +41,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
|
||||
let bodyAttributes = MarkdownAttributeSet(font: titleFont, textColor: primaryTextColor, additionalAttributes: [:])
|
||||
let boldAttributes = MarkdownAttributeSet(font: titleBoldFont, textColor: primaryTextColor, additionalAttributes: [:])
|
||||
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
@ -439,7 +440,12 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
case let .groupPhoneCall(_, _, scheduleDate, duration):
|
||||
if let scheduleDate = scheduleDate {
|
||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
let titleString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: scheduleDate, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(dateFormatString: { strings.Notification_VoiceChatScheduledChannel($0) }, tomorrowFormatString: { strings.Notification_VoiceChatScheduledTomorrowChannel($0) }, todayFormatString: { strings.Notification_VoiceChatScheduledTodayChannel($0) }))
|
||||
let titleString: PresentationStrings.FormattedString
|
||||
if let channel = message.author as? TelegramChannel, case .broadcast = channel.info {
|
||||
titleString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: scheduleDate, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(dateFormatString: { strings.Notification_LiveStreamScheduled($0) }, tomorrowFormatString: { strings.Notification_LiveStreamScheduledTomorrow($0) }, todayFormatString: { strings.Notification_LiveStreamScheduledToday($0) }))
|
||||
} else {
|
||||
titleString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: scheduleDate, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(dateFormatString: { strings.Notification_VoiceChatScheduledChannel($0) }, tomorrowFormatString: { strings.Notification_VoiceChatScheduledTomorrowChannel($0) }, todayFormatString: { strings.Notification_VoiceChatScheduledTodayChannel($0) }))
|
||||
}
|
||||
attributedString = NSAttributedString(string: titleString.string, font: titleFont, textColor: primaryTextColor)
|
||||
} else {
|
||||
let titleString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: scheduleDate, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(dateFormatString: { strings.Notification_VoiceChatScheduled(authorName, $0) }, tomorrowFormatString: { strings.Notification_VoiceChatScheduledTomorrow(authorName, $0) }, todayFormatString: { strings.Notification_VoiceChatScheduledToday(authorName, $0) }))
|
||||
@ -448,7 +454,12 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
} else if let duration = duration {
|
||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
let titleString = strings.Notification_VoiceChatEnded(callDurationString(strings: strings, value: duration)).string
|
||||
let titleString: String
|
||||
if let channel = message.author as? TelegramChannel, case .broadcast = channel.info {
|
||||
titleString = strings.Notification_LiveStreamEnded(callDurationString(strings: strings, value: duration)).string
|
||||
} else {
|
||||
titleString = strings.Notification_VoiceChatEnded(callDurationString(strings: strings, value: duration)).string
|
||||
}
|
||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||
} else {
|
||||
let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)]
|
||||
@ -457,8 +468,13 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
} else {
|
||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
let titleString = strings.Notification_VoiceChatStartedChannel
|
||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||
let titleString: String
|
||||
if let channel = message.author as? TelegramChannel, case .broadcast = channel.info {
|
||||
titleString = strings.Notification_LiveStreamStarted
|
||||
} else {
|
||||
titleString = strings.Notification_VoiceChatStartedChannel
|
||||
}
|
||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||
} else {
|
||||
let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)]
|
||||
let titleString = strings.Notification_VoiceChatStarted(authorName)
|
||||
@ -530,7 +546,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds))
|
||||
case let .setChatTheme(emoji):
|
||||
if emoji.isEmpty {
|
||||
if message.author?.id == accountPeerId {
|
||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
attributedString = NSAttributedString(string: strings.Notification_ChannelDisabledTheme, font: titleFont, textColor: primaryTextColor)
|
||||
} else if message.author?.id == accountPeerId {
|
||||
attributedString = NSAttributedString(string: strings.Notification_YouDisabledTheme, font: titleFont, textColor: primaryTextColor)
|
||||
} else {
|
||||
let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)]
|
||||
@ -538,12 +556,13 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds))
|
||||
}
|
||||
} else {
|
||||
if message.author?.id == accountPeerId {
|
||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
attributedString = NSAttributedString(string: strings.Notification_ChannelChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor)
|
||||
} else if message.author?.id == accountPeerId {
|
||||
attributedString = NSAttributedString(string: strings.Notification_YouChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor)
|
||||
} else {
|
||||
let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)]
|
||||
let resultTitleString = strings.Notification_ChangedTheme(authorName, emoji)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds))
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
||||
}
|
||||
}
|
||||
case .unknown:
|
||||
|
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Call/Avatar1.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Call/Avatar1.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Avatar1.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Call/Avatar2.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Call/Avatar2.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Avatar3.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Call/Avatar3.imageset/Avatar2.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Call/Avatar3.imageset/Avatar2.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Call/Avatar3.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Call/Avatar3.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Avatar2.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Call/Avatar4.imageset/Avatar4.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Call/Avatar4.imageset/Avatar4.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Call/Avatar4.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Call/Avatar4.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Avatar4.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_edit (1).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
105
submodules/TelegramUI/Images.xcassets/Chat/Input/Accessory Panels/EditIcon.imageset/ic_edit (1).pdf
vendored
Normal file
105
submodules/TelegramUI/Images.xcassets/Chat/Input/Accessory Panels/EditIcon.imageset/ic_edit (1).pdf
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 5.557617 5.409590 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
17.940434 18.091030 m
|
||||
17.391258 18.640203 16.500872 18.640203 15.951696 18.091030 c
|
||||
15.220630 17.359962 l
|
||||
15.166833 17.292160 l
|
||||
15.092115 17.171638 15.092115 17.017958 15.166833 16.897436 c
|
||||
15.220630 16.829634 l
|
||||
16.682323 15.373500 l
|
||||
16.750134 15.319892 l
|
||||
16.894726 15.230575 17.086790 15.248649 17.212147 15.374005 c
|
||||
17.940434 16.102291 l
|
||||
18.049709 16.224945 l
|
||||
18.486807 16.776924 18.450382 17.581081 17.940434 18.091030 c
|
||||
h
|
||||
14.264824 15.991543 m
|
||||
14.120199 16.081203 13.927823 16.063271 13.802298 15.937746 c
|
||||
1.567463 3.702911 l
|
||||
1.505585 3.635180 l
|
||||
1.420033 3.534018 1.322288 3.389440 1.212350 3.201446 c
|
||||
1.038298 2.886894 l
|
||||
0.845957 2.507218 l
|
||||
0.812376 2.438513 0.778033 2.367094 0.742928 2.292961 c
|
||||
0.523152 1.815601 l
|
||||
0.285087 1.273121 l
|
||||
0.028709 0.665525 l
|
||||
0.004916 0.582302 l
|
||||
-0.022651 0.414373 0.067465 0.243452 0.231453 0.175440 c
|
||||
0.323435 0.137291 0.426812 0.137291 0.518794 0.175440 c
|
||||
1.126400 0.431795 l
|
||||
1.668884 0.669861 l
|
||||
1.753871 0.708015 1.836145 0.745407 1.915705 0.782036 c
|
||||
2.360504 0.992668 l
|
||||
2.740180 1.185009 l
|
||||
3.054732 1.359062 l
|
||||
3.289725 1.496485 3.456881 1.614855 3.556201 1.714174 c
|
||||
15.791036 13.949008 l
|
||||
15.844832 14.016811 l
|
||||
15.934494 14.161437 15.916561 14.353812 15.791036 14.479338 c
|
||||
14.332628 15.937746 l
|
||||
14.264824 15.991543 l
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1385
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001475 00000 n
|
||||
0000001498 00000 n
|
||||
0000001671 00000 n
|
||||
0000001745 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1804
|
||||
%%EOF
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_forward (1).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.000732 4.530336 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
12.230824 17.257004 m
|
||||
12.217503 17.237732 12.204754 17.209534 12.204754 17.161430 c
|
||||
12.204754 13.844664 l
|
||||
12.204754 13.386267 11.833150 13.014664 11.374754 13.014664 c
|
||||
7.468079 13.014664 5.174883 11.337335 3.779674 9.261284 c
|
||||
2.536480 7.411429 1.984342 5.205478 1.745940 3.479214 c
|
||||
3.423516 5.195779 6.440499 7.174664 11.374754 7.174664 c
|
||||
11.594884 7.174664 11.805998 7.087217 11.961653 6.931562 c
|
||||
12.117308 6.775908 12.204754 6.564794 12.204754 6.344664 c
|
||||
12.204754 3.027895 l
|
||||
12.204754 2.979794 12.217503 2.951595 12.230824 2.932323 c
|
||||
12.246586 2.909521 12.272385 2.886978 12.307174 2.871906 c
|
||||
12.341963 2.856834 12.376053 2.853432 12.403469 2.857529 c
|
||||
12.426641 2.860991 12.455934 2.870977 12.491026 2.903875 c
|
||||
20.028908 9.970642 l
|
||||
20.100548 10.037804 20.100548 10.151523 20.028908 10.218686 c
|
||||
12.491024 17.285452 l
|
||||
12.455932 17.318352 12.426641 17.328337 12.403469 17.331800 c
|
||||
12.376053 17.335897 12.341963 17.332493 12.307174 17.317421 c
|
||||
12.272386 17.302349 12.246587 17.279808 12.230824 17.257004 c
|
||||
h
|
||||
10.544754 17.161430 m
|
||||
10.544754 18.763487 12.457608 19.592196 13.626367 18.496485 c
|
||||
21.164249 11.429716 l
|
||||
21.935432 10.706734 21.935434 9.482596 21.164251 8.759610 c
|
||||
13.626369 1.692844 l
|
||||
12.457612 0.597136 10.544754 1.425837 10.544754 3.027895 c
|
||||
10.544754 5.493531 l
|
||||
6.222875 5.270346 3.785475 3.326345 2.558439 1.912291 c
|
||||
2.109840 1.395319 1.440466 1.356445 0.981544 1.502619 c
|
||||
0.518860 1.649990 -0.070318 2.115324 0.006868 2.903498 c
|
||||
0.193950 4.813872 0.749841 7.728971 2.401903 10.187214 c
|
||||
3.980999 12.536886 6.535074 14.422771 10.544754 14.651388 c
|
||||
10.544754 17.161430 l
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1710
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001800 00000 n
|
||||
0000001823 00000 n
|
||||
0000001996 00000 n
|
||||
0000002070 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
2129
|
||||
%%EOF
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_reply.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
100
submodules/TelegramUI/Images.xcassets/Chat/Input/Accessory Panels/ReplyIcon.imageset/ic_reply.pdf
vendored
Normal file
100
submodules/TelegramUI/Images.xcassets/Chat/Input/Accessory Panels/ReplyIcon.imageset/ic_reply.pdf
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
-1.000000 -0.000000 -0.000000 1.000000 25.743408 4.905336 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
12.230824 17.257004 m
|
||||
12.217503 17.237732 12.204754 17.209534 12.204754 17.161430 c
|
||||
12.204754 13.844664 l
|
||||
12.204754 13.386267 11.833150 13.014664 11.374754 13.014664 c
|
||||
7.468079 13.014664 5.174883 11.337335 3.779674 9.261284 c
|
||||
2.536480 7.411429 1.984342 5.205478 1.745940 3.479214 c
|
||||
3.423516 5.195779 6.440499 7.174664 11.374754 7.174664 c
|
||||
11.594884 7.174664 11.805998 7.087217 11.961653 6.931562 c
|
||||
12.117308 6.775908 12.204754 6.564794 12.204754 6.344664 c
|
||||
12.204754 3.027895 l
|
||||
12.204754 2.979794 12.217503 2.951595 12.230824 2.932323 c
|
||||
12.246586 2.909521 12.272385 2.886978 12.307174 2.871906 c
|
||||
12.341963 2.856834 12.376053 2.853432 12.403469 2.857529 c
|
||||
12.426641 2.860991 12.455934 2.870977 12.491026 2.903875 c
|
||||
20.028908 9.970642 l
|
||||
20.100548 10.037804 20.100548 10.151523 20.028908 10.218686 c
|
||||
12.491024 17.285452 l
|
||||
12.455932 17.318352 12.426641 17.328337 12.403469 17.331800 c
|
||||
12.376053 17.335897 12.341963 17.332493 12.307174 17.317421 c
|
||||
12.272386 17.302349 12.246587 17.279808 12.230824 17.257004 c
|
||||
h
|
||||
10.544754 17.161430 m
|
||||
10.544754 18.763487 12.457608 19.592196 13.626367 18.496485 c
|
||||
21.164249 11.429716 l
|
||||
21.935432 10.706734 21.935434 9.482596 21.164251 8.759610 c
|
||||
13.626369 1.692844 l
|
||||
12.457612 0.597136 10.544754 1.425837 10.544754 3.027895 c
|
||||
10.544754 5.493531 l
|
||||
6.222875 5.270346 3.785475 3.326345 2.558439 1.912291 c
|
||||
2.109840 1.395319 1.440466 1.356445 0.981544 1.502619 c
|
||||
0.518860 1.649990 -0.070318 2.115324 0.006868 2.903498 c
|
||||
0.193950 4.813872 0.749841 7.728971 2.401903 10.187214 c
|
||||
3.980999 12.536886 6.535074 14.422771 10.544754 14.651388 c
|
||||
10.544754 17.161430 l
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1713
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001803 00000 n
|
||||
0000001826 00000 n
|
||||
0000001999 00000 n
|
||||
0000002073 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
2132
|
||||
%%EOF
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_link (1).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.120117 9.915810 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
12.468664 12.994003 m
|
||||
14.215596 14.740936 17.047935 14.740936 18.794868 12.994003 c
|
||||
20.541801 11.247070 20.541801 8.414734 18.794868 6.667801 c
|
||||
16.294868 4.167801 l
|
||||
14.547935 2.420868 11.715596 2.420868 9.968664 4.167801 c
|
||||
9.736349 4.400116 9.535478 4.650879 9.365597 4.915045 c
|
||||
9.117653 5.300597 8.604102 5.412152 8.218549 5.164208 c
|
||||
7.832996 4.916265 7.721442 4.402714 7.969386 4.017161 c
|
||||
8.202941 3.653981 8.478252 3.310617 8.794867 2.994003 c
|
||||
11.190070 0.598801 15.073462 0.598801 17.468666 2.994003 c
|
||||
19.968666 5.494003 l
|
||||
22.363869 7.889207 22.363869 11.772597 19.968666 14.167801 c
|
||||
17.573463 16.563004 13.690070 16.563004 11.294867 14.167801 c
|
||||
8.794867 11.667801 l
|
||||
8.470732 11.343666 8.470732 10.818138 8.794867 10.494003 c
|
||||
9.119002 10.169868 9.644528 10.169868 9.968664 10.494003 c
|
||||
12.468664 12.994003 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.120117 9.915810 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
9.296402 -2.832201 m
|
||||
7.549469 -4.579134 4.717132 -4.579134 2.970200 -2.832201 c
|
||||
1.223267 -1.085268 1.223267 1.747069 2.970200 3.494002 c
|
||||
5.470199 5.994002 l
|
||||
7.217132 7.740935 10.049470 7.740935 11.796402 5.994002 c
|
||||
12.028717 5.761687 12.229589 5.510924 12.399469 5.246758 c
|
||||
12.647413 4.861206 13.160964 4.749651 13.546517 4.997595 c
|
||||
13.932070 5.245539 14.043624 5.759089 13.795681 6.144642 c
|
||||
13.562125 6.507822 13.286814 6.851186 12.970200 7.167800 c
|
||||
10.574996 9.563003 6.691605 9.563003 4.296402 7.167800 c
|
||||
1.796402 4.667800 l
|
||||
-0.598801 2.272596 -0.598801 -1.610796 1.796402 -4.005999 c
|
||||
4.191605 -6.401201 8.074997 -6.401201 10.470200 -4.005999 c
|
||||
12.970200 -1.505999 l
|
||||
13.294334 -1.181864 13.294334 -0.656336 12.970200 -0.332201 c
|
||||
12.646064 -0.008066 12.120538 -0.008066 11.796402 -0.332201 c
|
||||
9.296402 -2.832201 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1852
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001942 00000 n
|
||||
0000001965 00000 n
|
||||
0000002138 00000 n
|
||||
0000002212 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
2271
|
||||
%%EOF
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_input_gifs.pdf",
|
||||
"filename" : "gif_48.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
249
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/GifsTabIcon.imageset/gif_48.pdf
vendored
Normal file
249
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/GifsTabIcon.imageset/gif_48.pdf
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 30.400024 17.342773 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
-1.328000 2.657227 m
|
||||
-1.328000 1.923792 -0.733434 1.329226 0.000000 1.329226 c
|
||||
0.733434 1.329226 1.328000 1.923792 1.328000 2.657227 c
|
||||
-1.328000 2.657227 l
|
||||
h
|
||||
4.000000 9.329226 m
|
||||
4.733434 9.329226 5.328000 9.923793 5.328000 10.657227 c
|
||||
5.328000 11.390660 4.733434 11.985227 4.000000 11.985227 c
|
||||
4.000000 9.329226 l
|
||||
h
|
||||
1.328000 2.657227 m
|
||||
1.328000 9.377226 l
|
||||
-1.328000 9.377226 l
|
||||
-1.328000 2.657227 l
|
||||
1.328000 2.657227 l
|
||||
h
|
||||
1.280000 9.329226 m
|
||||
4.000000 9.329226 l
|
||||
4.000000 11.985227 l
|
||||
1.280000 11.985227 l
|
||||
1.280000 9.329226 l
|
||||
h
|
||||
1.328000 9.377226 m
|
||||
1.328000 9.492270 1.328034 9.578946 1.329198 9.653058 c
|
||||
1.330364 9.727207 1.332460 9.769691 1.334489 9.794523 c
|
||||
1.338678 9.845800 1.338141 9.750368 1.270451 9.617519 c
|
||||
-1.096062 10.823318 l
|
||||
-1.250946 10.519341 -1.295081 10.226333 -1.312690 10.010806 c
|
||||
-1.329033 9.810783 -1.328000 9.579334 -1.328000 9.377226 c
|
||||
1.328000 9.377226 l
|
||||
h
|
||||
1.280000 11.985227 m
|
||||
1.077892 11.985227 0.846443 11.986259 0.646420 11.969916 c
|
||||
0.430894 11.952308 0.137886 11.908173 -0.166092 11.753288 c
|
||||
1.039707 9.386775 l
|
||||
0.906858 9.319085 0.811426 9.318548 0.862703 9.322738 c
|
||||
0.887536 9.324766 0.930019 9.326862 1.004169 9.328028 c
|
||||
1.078280 9.329193 1.164957 9.329226 1.280000 9.329226 c
|
||||
1.280000 11.985227 l
|
||||
h
|
||||
1.270451 9.617519 m
|
||||
1.219830 9.518170 1.139057 9.437396 1.039707 9.386775 c
|
||||
-0.166092 11.753288 l
|
||||
-0.566501 11.549270 -0.892043 11.223727 -1.096062 10.823318 c
|
||||
1.270451 9.617519 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 30.400024 22.144531 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 3.183762 m
|
||||
-0.733434 3.183762 -1.328000 2.589196 -1.328000 1.855762 c
|
||||
-1.328000 1.122328 -0.733434 0.527762 0.000000 0.527762 c
|
||||
0.000000 3.183762 l
|
||||
h
|
||||
4.000000 0.527762 m
|
||||
4.733434 0.527762 5.328000 1.122328 5.328000 1.855762 c
|
||||
5.328000 2.589196 4.733434 3.183762 4.000000 3.183762 c
|
||||
4.000000 0.527762 l
|
||||
h
|
||||
0.000000 0.527762 m
|
||||
4.000000 0.527762 l
|
||||
4.000000 3.183762 l
|
||||
0.000000 3.183762 l
|
||||
0.000000 0.527762 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 24.799927 17.343750 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
2.128000 10.656250 m
|
||||
2.128000 11.389684 1.533434 11.984250 0.800000 11.984250 c
|
||||
0.066566 11.984250 -0.528000 11.389684 -0.528000 10.656250 c
|
||||
2.128000 10.656250 l
|
||||
h
|
||||
-0.528000 2.656250 m
|
||||
-0.528000 1.922815 0.066566 1.328250 0.800000 1.328250 c
|
||||
1.533434 1.328250 2.128000 1.922815 2.128000 2.656250 c
|
||||
-0.528000 2.656250 l
|
||||
h
|
||||
-0.528000 10.656250 m
|
||||
-0.528000 2.656250 l
|
||||
2.128000 2.656250 l
|
||||
2.128000 10.656250 l
|
||||
-0.528000 10.656250 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 13.599976 17.343750 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
5.231635 9.028395 m
|
||||
5.882138 8.689614 6.684110 8.942316 7.022890 9.592818 c
|
||||
7.361670 10.243321 7.108968 11.045293 6.458466 11.384073 c
|
||||
5.231635 9.028395 l
|
||||
h
|
||||
7.584592 5.588284 m
|
||||
8.889243 5.340351 l
|
||||
8.901488 5.404787 l
|
||||
8.907325 5.470116 l
|
||||
7.584592 5.588284 l
|
||||
h
|
||||
5.600000 7.984250 m
|
||||
4.866566 7.984250 4.272000 7.389684 4.272000 6.656250 c
|
||||
4.272000 5.922816 4.866566 5.328250 5.600000 5.328250 c
|
||||
5.600000 7.984250 l
|
||||
h
|
||||
6.458466 11.384073 m
|
||||
5.721497 11.767884 4.884068 11.984250 4.000000 11.984250 c
|
||||
4.000000 9.328250 l
|
||||
4.446894 9.328250 4.864512 9.219591 5.231635 9.028395 c
|
||||
6.458466 11.384073 l
|
||||
h
|
||||
4.000000 11.984250 m
|
||||
1.057427 11.984250 -1.328000 9.598824 -1.328000 6.656250 c
|
||||
1.328000 6.656250 l
|
||||
1.328000 8.131955 2.524295 9.328250 4.000000 9.328250 c
|
||||
4.000000 11.984250 l
|
||||
h
|
||||
-1.328000 6.656250 m
|
||||
-1.328000 3.713677 1.057427 1.328250 4.000000 1.328250 c
|
||||
4.000000 3.984250 l
|
||||
2.524295 3.984250 1.328000 5.180545 1.328000 6.656250 c
|
||||
-1.328000 6.656250 l
|
||||
h
|
||||
4.000000 1.328250 m
|
||||
6.144260 1.328250 8.394547 2.737200 8.889243 5.340351 c
|
||||
6.279942 5.836216 l
|
||||
6.056704 4.661514 5.055740 3.984250 4.000000 3.984250 c
|
||||
4.000000 1.328250 l
|
||||
h
|
||||
8.907325 5.470116 m
|
||||
8.956036 6.015371 l
|
||||
6.310571 6.251707 l
|
||||
6.261860 5.706451 l
|
||||
8.907325 5.470116 l
|
||||
h
|
||||
7.155208 7.984250 m
|
||||
5.600000 7.984250 l
|
||||
5.600000 5.328250 l
|
||||
7.155208 5.328250 l
|
||||
7.155208 7.984250 l
|
||||
h
|
||||
8.956036 6.015371 m
|
||||
9.050537 7.073197 8.217244 7.984250 7.155208 7.984250 c
|
||||
7.155208 5.328250 l
|
||||
6.657084 5.328250 6.266247 5.755558 6.310571 6.251707 c
|
||||
8.956036 6.015371 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 5.599976 2.943848 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
35.472000 21.056055 m
|
||||
35.472000 11.627451 27.828604 3.984055 18.400000 3.984055 c
|
||||
18.400000 1.328056 l
|
||||
29.295473 1.328056 38.127998 10.160582 38.127998 21.056055 c
|
||||
35.472000 21.056055 l
|
||||
h
|
||||
18.400000 3.984055 m
|
||||
8.971395 3.984055 1.328000 11.627451 1.328000 21.056055 c
|
||||
-1.328000 21.056055 l
|
||||
-1.328000 10.160582 7.504526 1.328056 18.400000 1.328056 c
|
||||
18.400000 3.984055 l
|
||||
h
|
||||
1.328000 21.056055 m
|
||||
1.328000 30.484661 8.971395 38.128056 18.400000 38.128056 c
|
||||
18.400000 40.784054 l
|
||||
7.504526 40.784054 -1.328000 31.951529 -1.328000 21.056055 c
|
||||
1.328000 21.056055 l
|
||||
h
|
||||
18.400000 38.128056 m
|
||||
27.828604 38.128056 35.472000 30.484661 35.472000 21.056055 c
|
||||
38.127998 21.056055 l
|
||||
38.127998 31.951529 29.295473 40.784054 18.400000 40.784054 c
|
||||
18.400000 38.128056 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
5025
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 48.000000 48.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000005115 00000 n
|
||||
0000005138 00000 n
|
||||
0000005311 00000 n
|
||||
0000005385 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
5444
|
||||
%%EOF
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_input_recent.pdf",
|
||||
"filename" : "recent_48.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
89
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/RecentTabIcon.imageset/recent_48.pdf
vendored
Normal file
89
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/RecentTabIcon.imageset/recent_48.pdf
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.271973 4.271973 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
2.656000 19.728054 m
|
||||
2.656000 29.156660 10.299395 36.800056 19.728001 36.800056 c
|
||||
29.156605 36.800056 36.799999 29.156660 36.799999 19.728054 c
|
||||
36.799999 10.299450 29.156605 2.656055 19.728001 2.656055 c
|
||||
10.299395 2.656055 2.656000 10.299450 2.656000 19.728054 c
|
||||
h
|
||||
19.728001 39.456055 m
|
||||
8.832526 39.456055 0.000000 30.623528 0.000000 19.728054 c
|
||||
0.000000 8.832581 8.832526 0.000057 19.728001 0.000057 c
|
||||
30.623474 0.000057 39.455997 8.832581 39.455997 19.728054 c
|
||||
39.455997 30.623528 30.623474 39.456055 19.728001 39.456055 c
|
||||
h
|
||||
21.056000 30.928055 m
|
||||
21.056000 31.661489 20.461435 32.256054 19.728001 32.256054 c
|
||||
18.994566 32.256054 18.400002 31.661489 18.400002 30.928055 c
|
||||
18.400002 20.440632 l
|
||||
18.400002 19.610584 18.752302 18.819542 19.369272 18.264267 c
|
||||
26.839615 11.540958 l
|
||||
27.384773 11.050316 28.224453 11.094513 28.715096 11.639668 c
|
||||
29.205738 12.184826 29.161543 13.024506 28.616386 13.515148 c
|
||||
21.146042 20.238457 l
|
||||
21.088728 20.290041 21.056000 20.363525 21.056000 20.440632 c
|
||||
21.056000 30.928055 l
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1137
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 48.000000 48.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001227 00000 n
|
||||
0000001250 00000 n
|
||||
0000001423 00000 n
|
||||
0000001497 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1556
|
||||
%%EOF
|
@ -1,22 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "StickerKeyboardFavoriteTab@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "StickerKeyboardFavoriteTab@3x.png",
|
||||
"scale" : "3x"
|
||||
"filename" : "fave_48.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
247
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/fave_48.pdf
vendored
Normal file
247
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/fave_48.pdf
vendored
Normal file
@ -0,0 +1,247 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 5.000000 3.946289 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
8.635828 2.820679 m
|
||||
9.321689 1.681164 l
|
||||
8.635828 2.820679 l
|
||||
h
|
||||
9.731453 16.567810 m
|
||||
10.600920 17.574253 l
|
||||
9.731453 16.567810 l
|
||||
h
|
||||
1.384685 25.091970 m
|
||||
1.496809 23.766705 l
|
||||
1.384685 25.091970 l
|
||||
h
|
||||
1.051567 24.066368 m
|
||||
1.921034 25.072811 l
|
||||
1.051567 24.066368 l
|
||||
h
|
||||
20.038393 37.786930 m
|
||||
18.814356 37.266705 l
|
||||
20.038393 37.786930 l
|
||||
h
|
||||
18.961609 37.786930 m
|
||||
17.737572 38.307156 l
|
||||
18.961609 37.786930 l
|
||||
h
|
||||
26.180216 26.059437 m
|
||||
26.292339 27.384703 l
|
||||
26.180216 26.059437 l
|
||||
h
|
||||
24.508167 27.270023 m
|
||||
23.284132 26.749798 l
|
||||
24.508167 27.270023 l
|
||||
h
|
||||
37.948433 24.066368 m
|
||||
38.817898 23.059925 l
|
||||
37.948433 24.066368 l
|
||||
h
|
||||
37.615314 25.091970 m
|
||||
37.503193 23.766705 l
|
||||
37.615314 25.091970 l
|
||||
h
|
||||
28.628592 14.598795 m
|
||||
27.333555 14.295841 l
|
||||
28.628592 14.598795 l
|
||||
h
|
||||
29.268547 16.567810 m
|
||||
28.399080 17.574253 l
|
||||
29.268547 16.567810 l
|
||||
h
|
||||
30.364174 2.820679 m
|
||||
31.050034 3.960194 l
|
||||
31.050034 3.960194 l
|
||||
30.364174 2.820679 l
|
||||
h
|
||||
31.235470 3.455151 m
|
||||
32.530506 3.758102 l
|
||||
31.235470 3.455151 l
|
||||
h
|
||||
19.801676 9.178118 m
|
||||
19.115814 8.038603 l
|
||||
19.115814 8.038603 l
|
||||
19.801676 9.178118 l
|
||||
h
|
||||
19.115814 8.038603 m
|
||||
29.678312 1.681164 l
|
||||
31.050034 3.960194 l
|
||||
20.487535 10.317635 l
|
||||
19.115814 8.038603 l
|
||||
h
|
||||
32.530506 3.758102 m
|
||||
29.923628 14.901747 l
|
||||
27.333555 14.295841 l
|
||||
29.940432 3.152195 l
|
||||
32.530506 3.758102 l
|
||||
h
|
||||
30.138014 15.561367 m
|
||||
38.817898 23.059925 l
|
||||
37.078964 25.072811 l
|
||||
28.399080 17.574253 l
|
||||
30.138014 15.561367 l
|
||||
h
|
||||
37.727440 26.417236 m
|
||||
26.292339 27.384703 l
|
||||
26.068092 24.734173 l
|
||||
37.503193 23.766705 l
|
||||
37.727440 26.417236 l
|
||||
h
|
||||
25.732204 27.790249 m
|
||||
21.262428 38.307156 l
|
||||
18.814356 37.266705 l
|
||||
23.284132 26.749798 l
|
||||
25.732204 27.790249 l
|
||||
h
|
||||
17.737572 38.307156 m
|
||||
13.267798 27.790249 l
|
||||
15.715871 26.749798 l
|
||||
20.185644 37.266705 l
|
||||
17.737572 38.307156 l
|
||||
h
|
||||
12.707662 27.384703 m
|
||||
1.272561 26.417236 l
|
||||
1.496809 23.766705 l
|
||||
12.931910 24.734173 l
|
||||
12.707662 27.384703 l
|
||||
h
|
||||
0.182100 23.059925 m
|
||||
8.861986 15.561367 l
|
||||
10.600920 17.574253 l
|
||||
1.921034 25.072811 l
|
||||
0.182100 23.059925 l
|
||||
h
|
||||
9.076371 14.901747 m
|
||||
6.469495 3.758102 l
|
||||
9.059568 3.152195 l
|
||||
11.666444 14.295841 l
|
||||
9.076371 14.901747 l
|
||||
h
|
||||
9.321689 1.681164 m
|
||||
19.884186 8.038603 l
|
||||
18.512465 10.317635 l
|
||||
7.949968 3.960194 l
|
||||
9.321689 1.681164 l
|
||||
h
|
||||
6.469495 3.758102 m
|
||||
6.083770 2.109238 7.870839 0.807915 9.321689 1.681164 c
|
||||
7.949968 3.960194 l
|
||||
8.514397 4.299919 9.209628 3.793659 9.059568 3.152195 c
|
||||
6.469495 3.758102 l
|
||||
h
|
||||
8.861986 15.561367 m
|
||||
9.050550 15.398468 9.133131 15.144379 9.076371 14.901747 c
|
||||
11.666444 14.295841 l
|
||||
11.948550 15.501760 11.538106 16.764618 10.600920 17.574253 c
|
||||
8.861986 15.561367 l
|
||||
h
|
||||
1.272561 26.417236 m
|
||||
-0.416872 26.274302 -1.100905 24.168316 0.182100 23.059925 c
|
||||
1.921034 25.072811 l
|
||||
2.420168 24.641609 2.154054 23.822311 1.496809 23.766705 c
|
||||
1.272561 26.417236 l
|
||||
h
|
||||
13.267798 27.790249 m
|
||||
13.170667 27.561710 12.955100 27.405638 12.707662 27.384703 c
|
||||
12.931910 24.734173 l
|
||||
14.161719 24.838221 15.233116 25.613928 15.715871 26.749798 c
|
||||
13.267798 27.790249 l
|
||||
h
|
||||
21.262428 38.307156 m
|
||||
20.601709 39.861759 18.398293 39.861763 17.737572 38.307156 c
|
||||
20.185644 37.266705 l
|
||||
19.928600 36.661911 19.071398 36.661915 18.814356 37.266705 c
|
||||
21.262428 38.307156 l
|
||||
h
|
||||
26.292339 27.384703 m
|
||||
26.044901 27.405638 25.829334 27.561710 25.732204 27.790249 c
|
||||
23.284132 26.749798 l
|
||||
23.766886 25.613926 24.838282 24.838221 26.068092 24.734173 c
|
||||
26.292339 27.384703 l
|
||||
h
|
||||
38.817898 23.059925 m
|
||||
40.100903 24.168312 39.416878 26.274300 37.727440 26.417236 c
|
||||
37.503193 23.766705 l
|
||||
36.845943 23.822311 36.579834 24.641613 37.078964 25.072811 c
|
||||
38.817898 23.059925 l
|
||||
h
|
||||
29.923628 14.901747 m
|
||||
29.866869 15.144379 29.949450 15.398466 30.138014 15.561367 c
|
||||
28.399080 17.574253 l
|
||||
27.461895 16.764618 27.051451 15.501762 27.333555 14.295841 c
|
||||
29.923628 14.901747 l
|
||||
h
|
||||
29.678312 1.681164 m
|
||||
31.129168 0.807911 32.916229 2.109245 32.530506 3.758102 c
|
||||
29.940432 3.152195 l
|
||||
29.790373 3.793655 30.485600 4.299923 31.050034 3.960194 c
|
||||
29.678312 1.681164 l
|
||||
h
|
||||
20.487535 10.317635 m
|
||||
19.879963 10.683325 19.120041 10.683329 18.512465 10.317635 c
|
||||
19.884186 8.038603 l
|
||||
19.647816 7.896336 19.352180 7.896338 19.115814 8.038603 c
|
||||
20.487535 10.317635 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
4135
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 48.000000 48.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000004225 00000 n
|
||||
0000004248 00000 n
|
||||
0000004421 00000 n
|
||||
0000004495 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
4554
|
||||
%%EOF
|
@ -1,22 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "StickerKeyboardSettingsIcon@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "StickerKeyboardSettingsIcon@3x.png",
|
||||
"scale" : "3x"
|
||||
"filename" : "settings_48.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 859 B |
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
198
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/settings_48.pdf
vendored
Normal file
198
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/settings_48.pdf
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.500000 3.500000 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
22.000000 39.500000 m
|
||||
22.000000 40.328426 21.328428 41.000000 20.500000 41.000000 c
|
||||
19.671574 41.000000 19.000000 40.328426 19.000000 39.500000 c
|
||||
19.000000 38.338337 l
|
||||
19.000000 37.690460 18.579983 37.117363 17.962181 36.922268 c
|
||||
17.088881 36.646984 l
|
||||
16.504770 36.524204 15.932035 36.370529 15.372461 36.187752 c
|
||||
14.486683 35.991013 l
|
||||
13.854101 35.851067 13.203807 36.137375 12.879869 36.698452 c
|
||||
12.299038 37.704483 l
|
||||
11.884825 38.421921 10.967439 38.667736 10.250000 38.253521 c
|
||||
9.532561 37.839306 9.286749 36.921921 9.700962 36.204483 c
|
||||
10.281794 35.198452 l
|
||||
10.605731 34.637375 10.528535 33.931049 10.091049 33.453190 c
|
||||
9.444299 32.748505 l
|
||||
9.026765 32.371395 8.628606 31.973236 8.251495 31.555702 c
|
||||
7.546809 30.908951 l
|
||||
7.068950 30.471466 6.362623 30.394268 5.801547 30.718206 c
|
||||
4.795517 31.299038 l
|
||||
4.078078 31.713251 3.160693 31.467438 2.746479 30.750000 c
|
||||
2.332266 30.032562 2.578078 29.115175 3.295517 28.700962 c
|
||||
4.301547 28.120131 l
|
||||
4.862623 27.796192 5.148933 27.145899 5.008989 26.513317 c
|
||||
4.812248 25.627539 l
|
||||
4.629469 25.067965 4.475796 24.495230 4.353016 23.911119 c
|
||||
4.077733 23.037819 l
|
||||
3.882637 22.420017 3.309538 22.000000 2.661662 22.000000 c
|
||||
1.500000 22.000000 l
|
||||
0.671573 22.000000 0.000000 21.328426 0.000000 20.500000 c
|
||||
0.000000 19.671572 0.671573 19.000000 1.500000 19.000000 c
|
||||
2.661662 19.000000 l
|
||||
3.309538 19.000000 3.882637 18.579983 4.077733 17.962181 c
|
||||
4.353333 17.087372 l
|
||||
4.475950 16.504307 4.629352 15.932577 4.811759 15.373960 c
|
||||
5.008989 14.486683 l
|
||||
5.148933 13.854101 4.862623 13.203808 4.301547 12.879869 c
|
||||
3.295517 12.299038 l
|
||||
2.578078 11.884825 2.332266 10.967440 2.746479 10.250000 c
|
||||
3.160693 9.532560 4.078078 9.286747 4.795517 9.700962 c
|
||||
5.801547 10.281792 l
|
||||
6.362623 10.605730 7.068950 10.528536 7.546809 10.091049 c
|
||||
8.250140 9.445797 l
|
||||
8.627652 9.027718 9.026265 8.629059 9.444299 8.251495 c
|
||||
10.091049 7.546806 l
|
||||
10.528535 7.068951 10.605731 6.362625 10.281794 5.801548 c
|
||||
9.700962 4.795517 l
|
||||
9.286749 4.078079 9.532561 3.160690 10.250000 2.746479 c
|
||||
10.967439 2.332264 11.884825 2.578079 12.299038 3.295517 c
|
||||
12.879869 4.301548 l
|
||||
13.203807 4.862625 13.854101 5.148933 14.486683 5.008987 c
|
||||
15.384456 4.808334 l
|
||||
15.943589 4.626175 16.515841 4.473072 17.099430 4.350803 c
|
||||
17.962181 4.077732 l
|
||||
18.125601 4.015381 l
|
||||
18.652878 3.777821 19.000000 3.250641 19.000000 2.661663 c
|
||||
19.000000 1.500000 l
|
||||
19.010092 1.325066 l
|
||||
19.096739 0.579060 19.730747 0.000000 20.500000 0.000000 c
|
||||
21.328428 0.000000 22.000000 0.671574 22.000000 1.500000 c
|
||||
22.000000 2.661663 l
|
||||
22.010246 2.836273 l
|
||||
22.078001 3.410614 22.476181 3.900372 23.037819 4.077732 c
|
||||
23.905090 4.351749 l
|
||||
24.486071 4.473644 25.055811 4.626099 25.612547 4.807358 c
|
||||
26.513317 5.008987 l
|
||||
27.145899 5.148933 27.796192 4.862625 28.120131 4.301548 c
|
||||
28.700962 3.295517 l
|
||||
29.115175 2.578079 30.032560 2.332264 30.750000 2.746479 c
|
||||
31.467440 3.160690 31.713253 4.078079 31.299038 4.795517 c
|
||||
30.718208 5.801548 l
|
||||
30.394270 6.362625 30.471464 7.068951 30.908951 7.546806 c
|
||||
31.555702 8.251495 l
|
||||
31.973736 8.629059 32.372349 9.027718 32.749863 9.445797 c
|
||||
33.453194 10.091049 l
|
||||
33.931049 10.528536 34.637375 10.605730 35.198452 10.281792 c
|
||||
36.204483 9.700962 l
|
||||
36.921921 9.286747 37.839310 9.532560 38.253521 10.250000 c
|
||||
38.667736 10.967440 38.421921 11.884825 37.704483 12.299038 c
|
||||
36.698452 12.879869 l
|
||||
36.137375 13.203808 35.851067 13.854101 35.991013 14.486683 c
|
||||
36.192642 15.387453 l
|
||||
36.373901 15.944189 36.526356 16.513929 36.648251 17.094910 c
|
||||
36.922268 17.962181 l
|
||||
37.117363 18.579983 37.690460 19.000000 38.338337 19.000000 c
|
||||
39.500000 19.000000 l
|
||||
40.328426 19.000000 41.000000 19.671572 41.000000 20.500000 c
|
||||
41.000000 21.328426 40.328426 22.000000 39.500000 22.000000 c
|
||||
38.338337 22.000000 l
|
||||
37.690460 22.000000 37.117363 22.420017 36.922268 23.037819 c
|
||||
36.648884 23.902077 l
|
||||
36.526775 24.484623 36.373940 25.055870 36.192154 25.614044 c
|
||||
35.991013 26.513317 l
|
||||
35.851067 27.145899 36.137375 27.796192 36.698452 28.120131 c
|
||||
37.704483 28.700962 l
|
||||
38.421921 29.115175 38.667736 30.032562 38.253521 30.750000 c
|
||||
37.839310 31.467438 36.921921 31.713251 36.204483 31.299038 c
|
||||
35.198452 30.718206 l
|
||||
34.637375 30.394268 33.931049 30.471466 33.453194 30.908951 c
|
||||
32.748505 31.555702 l
|
||||
32.370941 31.973736 31.972282 32.372349 31.554203 32.749859 c
|
||||
30.908951 33.453190 l
|
||||
30.471464 33.931049 30.394270 34.637375 30.718208 35.198452 c
|
||||
31.299038 36.204483 l
|
||||
31.713253 36.921921 31.467440 37.839306 30.750000 38.253521 c
|
||||
30.032560 38.667736 29.115175 38.421921 28.700962 37.704483 c
|
||||
28.120131 36.698452 l
|
||||
27.796192 36.137375 27.145899 35.851067 26.513317 35.991013 c
|
||||
25.626040 36.188240 l
|
||||
25.067423 36.370647 24.495693 36.524048 23.912628 36.646667 c
|
||||
23.037819 36.922268 l
|
||||
22.420017 37.117363 22.000000 37.690460 22.000000 38.338337 c
|
||||
22.000000 39.500000 l
|
||||
h
|
||||
6.999939 20.500244 m
|
||||
6.999939 27.956089 13.044094 34.000244 20.499939 34.000244 c
|
||||
27.955784 34.000244 33.999939 27.956089 33.999939 20.500244 c
|
||||
33.999939 13.044399 27.955784 7.000244 20.499939 7.000244 c
|
||||
13.044094 7.000244 6.999939 13.044399 6.999939 20.500244 c
|
||||
h
|
||||
14.233011 30.086567 m
|
||||
14.833106 30.510162 15.662971 30.367085 16.086567 29.766989 c
|
||||
21.689148 21.830000 l
|
||||
30.500000 21.830000 l
|
||||
31.234539 21.830000 31.830000 21.234539 31.830000 20.500000 c
|
||||
31.830000 19.765461 31.234539 19.170000 30.500000 19.170000 c
|
||||
21.689148 19.170000 l
|
||||
16.086567 11.233011 l
|
||||
15.662971 10.632917 14.833106 10.489836 14.233011 10.913433 c
|
||||
13.632916 11.337029 13.489837 12.166895 13.913433 12.766989 c
|
||||
19.372028 20.500000 l
|
||||
13.913433 28.233011 l
|
||||
13.489837 28.833107 13.632916 29.662971 14.233011 30.086567 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
5648
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 48.000000 48.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000005738 00000 n
|
||||
0000005761 00000 n
|
||||
0000005934 00000 n
|
||||
0000006008 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
6067
|
||||
%%EOF
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_input_stickers.pdf",
|
||||
"filename" : "stickers_48.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
Binary file not shown.
123
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/StickersMode.imageset/stickers_48.pdf
vendored
Normal file
123
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/StickersMode.imageset/stickers_48.pdf
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.270020 4.152344 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
16.315697 39.500134 m
|
||||
17.465136 39.695385 18.643398 39.519531 19.692223 38.997250 c
|
||||
20.036819 38.810360 l
|
||||
20.329382 38.633312 l
|
||||
22.423059 37.333458 25.297297 34.879963 28.991110 31.253437 c
|
||||
30.068821 30.185352 l
|
||||
30.611883 29.639896 l
|
||||
34.713905 25.501024 37.402637 22.349218 38.705769 20.126995 c
|
||||
39.294643 19.122784 39.547707 17.960588 39.433071 16.802202 c
|
||||
39.381195 16.416437 l
|
||||
39.289803 15.914349 l
|
||||
39.216812 15.566687 l
|
||||
39.100006 15.079699 l
|
||||
36.891888 6.359375 29.005989 0.117638 19.853556 0.117638 c
|
||||
8.888740 0.117638 0.000000 9.006048 0.000000 19.970463 c
|
||||
0.000000 29.125599 6.246058 37.013073 14.970581 39.218063 c
|
||||
15.710625 39.388660 l
|
||||
16.315697 39.500134 l
|
||||
h
|
||||
12.798756 35.489426 m
|
||||
12.631100 35.425148 l
|
||||
12.241472 35.242031 l
|
||||
6.578289 32.429054 2.786009 26.584171 2.786009 19.970726 c
|
||||
2.786009 10.544853 10.427470 2.903671 19.853691 2.903671 c
|
||||
26.466494 2.903671 32.311123 6.694832 35.134140 12.353510 c
|
||||
35.125557 12.358789 l
|
||||
35.308681 12.748402 l
|
||||
35.384480 12.909666 35.423779 13.085659 35.423779 13.263847 c
|
||||
35.423779 13.877327 34.967880 14.384329 34.376385 14.464569 c
|
||||
34.211948 14.475632 l
|
||||
32.160770 14.475632 l
|
||||
22.489969 14.475632 14.620218 22.186560 14.364793 31.795357 c
|
||||
14.358393 32.277351 l
|
||||
14.358393 34.328457 l
|
||||
14.358393 34.506645 14.319095 34.682640 14.243299 34.843903 c
|
||||
13.984495 35.394527 13.364433 35.659653 12.798756 35.489426 c
|
||||
h
|
||||
16.782263 36.753235 m
|
||||
17.411953 36.860195 18.059189 36.741272 18.609720 36.417446 c
|
||||
18.873783 36.257626 l
|
||||
19.147327 36.083416 l
|
||||
21.103546 34.807701 23.928543 32.350906 27.572746 28.738895 c
|
||||
28.098915 28.215038 l
|
||||
29.130342 27.174446 l
|
||||
32.797047 23.440453 35.195877 20.604664 36.302593 18.717381 c
|
||||
36.625195 18.167248 36.743385 17.520950 36.636360 16.892254 c
|
||||
36.563797 16.495956 l
|
||||
35.903824 16.976896 35.090961 17.260666 34.211819 17.260666 c
|
||||
32.160641 17.260666 l
|
||||
31.717884 17.267069 l
|
||||
23.629288 17.501270 17.144138 24.131626 17.144138 32.276615 c
|
||||
17.144138 34.327721 l
|
||||
17.128656 34.679214 l
|
||||
17.087467 35.145836 16.964489 35.602531 16.764452 36.028126 c
|
||||
16.655125 36.260727 16.526255 36.477886 16.380722 36.678566 c
|
||||
16.574390 36.716927 l
|
||||
16.782263 36.753235 l
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
2244
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 48.000000 48.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000002334 00000 n
|
||||
0000002357 00000 n
|
||||
0000002530 00000 n
|
||||
0000002604 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
2663
|
||||
%%EOF
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user