mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '172aa382701692eed41c1167e527af829814a13f'
This commit is contained in:
commit
d366ea37d7
15
.gitattributes
vendored
Normal file
15
.gitattributes
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# Linguist overrides for vendored code
|
||||
submodules/AsyncDisplayKit/* linguist-vendored
|
||||
submodules/ffmpeg/* linguist-vendored
|
||||
submodules/HockeySDK-iOS/* linguist-vendored
|
||||
submodules/libphonenumber/* linguist-vendored
|
||||
submodules/libtgvoip/* linguist-vendored
|
||||
submodules/lottie-ios/* linguist-vendored
|
||||
submodules/Opus/* linguist-vendored
|
||||
submodules/OpusBinding/* linguist-vendored
|
||||
submodules/rlottie/rlottie/* linguist-vendored
|
||||
submodules/sqlcipher/* linguist-vendored
|
||||
submodules/Stripe/* linguist-vendored
|
||||
submodules/ton/tonlib-src/* linguist-vendored
|
||||
submodules/webp/include/* linguist-vendored
|
||||
third-party/* linguist-vendored
|
Binary file not shown.
Binary file not shown.
@ -5838,6 +5838,7 @@ Sorry for the inconvenience.";
|
||||
"InviteLink.PeopleJoined_many" = "%@ people joined";
|
||||
"InviteLink.PeopleJoined_any" = "%@ people joined";
|
||||
"InviteLink.CreatePrivateLinkHelp" = "Anyone who has Telegram installed will be able to join your group by following this link.";
|
||||
"InviteLink.CreatePrivateLinkHelpChannel" = "Anyone who has Telegram installed will be able to join your channel by following this link.";
|
||||
"InviteLink.Manage" = "Manage Invite Links";
|
||||
|
||||
"InviteLink.PeopleJoinedShortNoneExpired" = "no one joined";
|
||||
@ -5899,6 +5900,7 @@ Sorry for the inconvenience.";
|
||||
|
||||
"InviteLink.QRCode.Title" = "Invite by QR Code";
|
||||
"InviteLink.QRCode.Info" = "Everyone on Telegram can scan this code to join your group.";
|
||||
"InviteLink.QRCode.InfoChannel" = "Everyone on Telegram can scan this code to join your channel.";
|
||||
"InviteLink.QRCode.Share" = "Share QR Code";
|
||||
|
||||
"InviteLink.InviteLink" = "Invite Link";
|
||||
@ -6021,6 +6023,9 @@ Sorry for the inconvenience.";
|
||||
"Channel.AdminLog.DeletedInviteLink" = "%1$@ deleted invite link %2$@";
|
||||
"Channel.AdminLog.RevokedInviteLink" = "%1$@ revoked invite link %2$@";
|
||||
"Channel.AdminLog.EditedInviteLink" = "%1$@ edited invite link %2$@";
|
||||
"Channel.AdminLog.CreatedInviteLink" = "%1$@ created invite link %2$@";
|
||||
|
||||
"Channel.AdminLog.JoinedViaInviteLink" = "%1$@ joined via invite link %2$@";
|
||||
|
||||
"GroupInfo.Permissions.BroadcastTitle" = "Broadcast Channel";
|
||||
"GroupInfo.Permissions.BroadcastConvert" = "Convert Group to Channel";
|
||||
@ -6056,7 +6061,6 @@ Sorry for the inconvenience.";
|
||||
"Report.Report" = "Report";
|
||||
"Report.Succeed" = "Telegram moderators will study your report. Thank you!";
|
||||
|
||||
|
||||
"Conversation.AutoremoveRemainingTime" = "auto-delete in %@";
|
||||
"Conversation.AutoremoveRemainingDays_1" = "auto-delete in %@ day";
|
||||
"Conversation.AutoremoveRemainingDays_any" = "auto-delete in %@ days";
|
||||
@ -6066,3 +6070,7 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Conversation.AutoremoveChanged" = "Auto-Delete timer set to %@";
|
||||
|
||||
"PeerInfo.ReportProfilePhoto" = "Report Profile Photo";
|
||||
"PeerInfo.ReportProfileVideo" = "Report Profile Video";
|
||||
|
||||
"Channel.AdminLog.CanInviteUsersViaLink" = "Invite Users via Link";
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="17156" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="umr-Wa-jBL">
|
||||
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="17701" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="umr-Wa-jBL">
|
||||
<device id="watch38"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="17034"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="17500"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--TGNeoConversationController-->
|
||||
@ -1569,11 +1569,445 @@ contacts found.</string>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="729" y="757.25"/>
|
||||
</scene>
|
||||
<!--Static M-->
|
||||
<scene sceneID="uW0-5W-J6c">
|
||||
<objects>
|
||||
<notificationController backgroundImage="BubbleNotification" spacing="0.0" id="JcB-1W-jcv" userLabel="Static M">
|
||||
<items>
|
||||
<group width="1" alignment="left" radius="0.0" id="11B-ry-7nl">
|
||||
<items>
|
||||
<label alignment="left" text="Text" numberOfLines="0" id="RMV-rW-0qs">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" style="UICTFontTextStyleBody"/>
|
||||
</label>
|
||||
</items>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<edgeInsets key="margins" left="8" right="8" top="10" bottom="11"/>
|
||||
</group>
|
||||
</items>
|
||||
<notificationCategory key="notificationCategory" identifier="m" id="MXx-dC-nsP">
|
||||
<color key="titleColor" red="0.10051588710000001" green="0.10051287709999999" blue="0.1005146056" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="sashColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</notificationCategory>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="4"/>
|
||||
<connections>
|
||||
<outlet property="notificationAlertLabel" destination="RMV-rW-0qs" id="buR-qh-N93"/>
|
||||
<segue destination="RQh-4n-Jyy" kind="relationship" relationship="dynamicNotificationInterface" id="wDy-DD-bRl"/>
|
||||
<segue destination="RQh-4n-Jyy" kind="relationship" relationship="dynamicInteractiveNotificationInterface" id="MKi-5u-rhv"/>
|
||||
</connections>
|
||||
</notificationController>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="263" y="875"/>
|
||||
</scene>
|
||||
<!--Dynamic M-->
|
||||
<scene sceneID="aFy-up-fB6">
|
||||
<objects>
|
||||
<controller backgroundImage="BubbleNotification" id="RQh-4n-Jyy" userLabel="Dynamic M" customClass="TGNotificationController">
|
||||
<items>
|
||||
<group width="1" alignment="left" layout="vertical" radius="0.0" spacing="0.0" id="Dd4-YD-hsp">
|
||||
<items>
|
||||
<group width="1" alignment="left" layout="vertical" spacing="0.0" id="ZlG-DJ-Ctv">
|
||||
<items>
|
||||
<label alignment="left" hidden="YES" text="Chat Title" id="frP-KX-c0b">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" hidden="YES" text="Name" id="JUM-Bm-hxM">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="16"/>
|
||||
</label>
|
||||
<group width="1" height="29" alignment="left" hidden="YES" layout="vertical" spacing="0.0" id="r84-Ll-prj">
|
||||
<items>
|
||||
<label alignment="left" verticalAlignment="center" text="Forwarded from" id="Br6-65-UTH" userLabel="ForwardTitle">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" verticalAlignment="center" text="Name" id="DI0-a4-1u0" userLabel="ForwardFrom">
|
||||
<color key="textColor" red="0.1131299585" green="0.50641471149999995" blue="0.96399867530000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="1" height="29" alignment="left" hidden="YES" spacing="4" id="Th4-sR-kDF" userLabel="ReplyHeader">
|
||||
<items>
|
||||
<group width="2" height="26" alignment="left" verticalAlignment="center" radius="0.0" spacing="0.0" id="n46-ZY-9jJ" userLabel="ReplyLine">
|
||||
<color key="backgroundColor" red="0.1131299585" green="0.50641471149999995" blue="0.96399867530000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="26" height="26" alignment="left" verticalAlignment="center" radius="2" id="FmK-ex-jTs" userLabel="ReplyImage">
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.089999999999999997" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" layout="vertical" spacing="0.0" id="tQQ-et-qfm" userLabel="ReplyMessage">
|
||||
<items>
|
||||
<label alignment="left" text="Name" id="ifF-tf-ens" userLabel="ReplyAuthor">
|
||||
<color key="textColor" red="0.1131299585" green="0.50641471149999995" blue="0.96399867530000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" text="Text" id="tWb-zc-3NN" userLabel="ReplyText">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<label alignment="left" text="Text" numberOfLines="0" id="t9S-qg-lnm">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" style="UICTFontTextStyleBody"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="8" right="8" top="0.0" bottom="5"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" hidden="YES" layout="vertical" id="CMM-a2-p1K" userLabel="WrapperGroup">
|
||||
<items>
|
||||
<group width="1" alignment="left" layout="vertical" radius="10" spacing="0.0" id="r4K-n7-uKy" userLabel="LocationGroup">
|
||||
<items>
|
||||
<map height="92" alignment="left" id="PY6-r9-1nn"/>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" spacing="5" id="XJr-R0-HOA" userLabel="FileGroup">
|
||||
<items>
|
||||
<imageView width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" image="Location" contentMode="center" id="vZ3-mt-ICu" userLabel="VenueIcon">
|
||||
<color key="tintColor" red="0.35566622019999999" green="0.68838506939999999" blue="0.91561108830000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</imageView>
|
||||
<group width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" radius="13" spacing="0.0" id="IJt-Cp-BKm" userLabel="AudioGroup">
|
||||
<items>
|
||||
<imageView width="26" height="26" alignment="left" image="MediaAudioPlay" contentMode="center" id="PDu-Bz-gy5"/>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.35566622019999999" green="0.68838506939999999" blue="0.91561108830000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="26" height="26" alignment="left" verticalAlignment="center" radius="0.0" id="Gd3-ap-jO4" userLabel="FileIconGroup">
|
||||
<items>
|
||||
<imageView alignment="center" verticalAlignment="center" image="File.png" contentMode="center" id="dZu-99-pMR">
|
||||
<color key="tintColor" red="0.14697439970000001" green="0.5607914329" blue="0.88162887099999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</imageView>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</group>
|
||||
<group alignment="left" verticalAlignment="center" layout="vertical" spacing="0.0" id="DHa-mY-ceB" userLabel="FileMetaGroup">
|
||||
<items>
|
||||
<label alignment="left" text="File Name" id="tul-U8-7fj">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" text="Size" id="m2I-fn-zCe">
|
||||
<color key="textColor" red="0.41865724329999998" green="0.41825520989999998" blue="0.4306421876" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="6.5" right="6.5" top="2" bottom="1"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" spacing="0.0" id="DLM-Wi-QFQ" userLabel="StickerWrapper">
|
||||
<items>
|
||||
<group width="0.5" height="64" alignment="left" contentMode="scaleAspectFit" id="7TZ-8f-EgD" userLabel="StickerGroup">
|
||||
<variation key="device=watch42mm" height="72"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="6.5" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" radius="12" id="sxE-kX-fH5" userLabel="MediaGroup">
|
||||
<items>
|
||||
<group alignment="right" verticalAlignment="bottom" radius="10" id="GEf-6R-cw1" userLabel="DurationGroup">
|
||||
<items>
|
||||
<label alignment="left" text="2:34" id="wRk-Fm-UIl" userLabel="Duration">
|
||||
<color key="textColor" red="0.2461894453" green="0.24618205430000001" blue="0.2461862564" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.89292949440000002" green="0.91148859260000004" blue="0.93112039570000005" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="6" right="6" top="2" bottom="2"/>
|
||||
</group>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.089999999999999997" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="4" right="4" top="4" bottom="4"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" id="W49-eu-bIX" userLabel="CaptionGroup">
|
||||
<items>
|
||||
<label alignment="left" text="Caption" numberOfLines="0" id="3dY-xL-bio">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="16"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="8" right="8" top="4" bottom="4"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="1.5" right="1.5" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
</items>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="10" bottom="5"/>
|
||||
</group>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="4"/>
|
||||
<connections>
|
||||
<outlet property="audioGroup" destination="IJt-Cp-BKm" id="UDG-gj-AJm"/>
|
||||
<outlet property="captionGroup" destination="W49-eu-bIX" id="fLo-8u-qJ7"/>
|
||||
<outlet property="captionLabel" destination="3dY-xL-bio" id="HPd-qv-6SR"/>
|
||||
<outlet property="chatTitleLabel" destination="frP-KX-c0b" id="gQB-RH-eAC"/>
|
||||
<outlet property="durationGroup" destination="GEf-6R-cw1" id="b6I-rw-1ma"/>
|
||||
<outlet property="durationLabel" destination="wRk-Fm-UIl" id="OY4-mh-oGN"/>
|
||||
<outlet property="fileGroup" destination="XJr-R0-HOA" id="jAA-6n-GcD"/>
|
||||
<outlet property="fileIconGroup" destination="Gd3-ap-jO4" id="Gk0-pX-7xT"/>
|
||||
<outlet property="forwardFromLabel" destination="DI0-a4-1u0" id="97d-FM-hvd"/>
|
||||
<outlet property="forwardHeaderGroup" destination="r84-Ll-prj" id="eOS-0I-fH2"/>
|
||||
<outlet property="forwardTitleLabel" destination="Br6-65-UTH" id="ZXg-hL-4Nt"/>
|
||||
<outlet property="map" destination="PY6-r9-1nn" id="QtL-Ma-9i3"/>
|
||||
<outlet property="mapGroup" destination="r4K-n7-uKy" id="QaM-0N-n60"/>
|
||||
<outlet property="mediaGroup" destination="sxE-kX-fH5" id="oMl-K9-upS"/>
|
||||
<outlet property="messageTextLabel" destination="t9S-qg-lnm" id="NTR-1N-c27"/>
|
||||
<outlet property="nameLabel" destination="JUM-Bm-hxM" id="Eiz-Pp-a1C"/>
|
||||
<outlet property="replyAuthorNameLabel" destination="ifF-tf-ens" id="NSF-eV-jEP"/>
|
||||
<outlet property="replyHeaderGroup" destination="Th4-sR-kDF" id="SjQ-KI-BYD"/>
|
||||
<outlet property="replyHeaderImageGroup" destination="FmK-ex-jTs" id="j7i-Sc-BUV"/>
|
||||
<outlet property="replyMessageTextLabel" destination="tWb-zc-3NN" id="aSf-v0-kQf"/>
|
||||
<outlet property="stickerGroup" destination="7TZ-8f-EgD" id="f6z-Rx-GYV"/>
|
||||
<outlet property="stickerWrapperGroup" destination="DLM-Wi-QFQ" id="wXu-ff-inw"/>
|
||||
<outlet property="subtitleLabel" destination="m2I-fn-zCe" id="WMT-u4-Tgp"/>
|
||||
<outlet property="titleLabel" destination="tul-U8-7fj" id="VxJ-io-0DL"/>
|
||||
<outlet property="venueIcon" destination="vZ3-mt-ICu" id="WvO-Db-hRw"/>
|
||||
<outlet property="wrapperGroup" destination="CMM-a2-p1K" id="SSt-aA-79a"/>
|
||||
</connections>
|
||||
</controller>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="503" y="874.75"/>
|
||||
</scene>
|
||||
<!--Static R-->
|
||||
<scene sceneID="Aix-4r-fFK">
|
||||
<objects>
|
||||
<notificationController backgroundImage="BubbleNotification" spacing="0.0" id="crw-Qo-dti" userLabel="Static R">
|
||||
<items>
|
||||
<group width="1" alignment="left" layout="vertical" radius="0.0" id="RTo-Ed-NsD">
|
||||
<items>
|
||||
<label alignment="left" text="Text" numberOfLines="0" id="6f0-WK-Add">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" style="UICTFontTextStyleBody"/>
|
||||
</label>
|
||||
</items>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<edgeInsets key="margins" left="8" right="8" top="10" bottom="11"/>
|
||||
</group>
|
||||
</items>
|
||||
<notificationCategory key="notificationCategory" id="pgn-NP-bt0">
|
||||
<color key="titleColor" red="0.10051588710000001" green="0.10051287709999999" blue="0.1005146056" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="sashColor" red="1" green="0.99997437" blue="0.99999129769999995" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</notificationCategory>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="4"/>
|
||||
<connections>
|
||||
<outlet property="notificationAlertLabel" destination="6f0-WK-Add" id="ioT-Xv-KJp"/>
|
||||
<segue destination="79a-X2-tmF" kind="relationship" relationship="dynamicNotificationInterface" id="dmG-n7-HwD"/>
|
||||
<segue destination="79a-X2-tmF" kind="relationship" relationship="dynamicInteractiveNotificationInterface" id="UyA-Ra-UVy"/>
|
||||
</connections>
|
||||
</notificationController>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="263" y="1281"/>
|
||||
</scene>
|
||||
<!--Dynamic R-->
|
||||
<scene sceneID="K4P-nV-Yqh">
|
||||
<objects>
|
||||
<controller backgroundImage="BubbleNotification" spacing="0.0" id="79a-X2-tmF" userLabel="Dynamic R" customClass="TGNotificationController">
|
||||
<items>
|
||||
<group width="1" alignment="left" layout="vertical" radius="0.0" spacing="0.0" id="Go3-q1-pnJ">
|
||||
<items>
|
||||
<group width="1" alignment="left" layout="vertical" spacing="0.0" id="JAA-Ky-cyx">
|
||||
<items>
|
||||
<label alignment="left" hidden="YES" text="Chat Title" id="HtY-WB-aFI">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" hidden="YES" text="Name" id="Hqd-Pr-2zp">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="16"/>
|
||||
</label>
|
||||
<group width="1" height="29" alignment="left" hidden="YES" layout="vertical" spacing="0.0" id="Kzq-HH-8Ev">
|
||||
<items>
|
||||
<label alignment="left" verticalAlignment="center" text="Forwarded from" id="NTL-lz-9dd" userLabel="ForwardTitle">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" verticalAlignment="center" text="Name" id="B2R-Qa-MeP" userLabel="ForwardFrom">
|
||||
<color key="textColor" red="0.1131299585" green="0.50641471149999995" blue="0.96399867530000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="1" height="29" alignment="left" hidden="YES" spacing="4" id="KRV-O6-45y" userLabel="ReplyHeader">
|
||||
<items>
|
||||
<group width="2" height="26" alignment="left" verticalAlignment="center" radius="0.0" spacing="0.0" id="eW6-JQ-FAY" userLabel="ReplyLine">
|
||||
<color key="backgroundColor" red="0.1131299585" green="0.50641471149999995" blue="0.96399867530000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="26" height="26" alignment="left" verticalAlignment="center" radius="2" id="swd-Nx-MDo" userLabel="ReplyImage">
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.089999999999999997" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" layout="vertical" spacing="0.0" id="h1Y-se-IEW" userLabel="ReplyMessage">
|
||||
<items>
|
||||
<label alignment="left" text="Name" id="g6r-Nm-SOQ" userLabel="ReplyAuthor">
|
||||
<color key="textColor" red="0.1131299585" green="0.50641471149999995" blue="0.96399867530000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" text="Text" id="dAz-x8-jbh" userLabel="ReplyText">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<label alignment="left" text="Text" numberOfLines="0" id="wxg-r7-aSG">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" style="UICTFontTextStyleBody"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="8" right="8" top="0.0" bottom="5"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" hidden="YES" layout="vertical" id="0ch-zY-dJX" userLabel="WrapperGroup">
|
||||
<items>
|
||||
<group width="1" alignment="left" layout="vertical" radius="10" spacing="0.0" id="vel-8f-OFm" userLabel="LocationGroup">
|
||||
<items>
|
||||
<map height="92" alignment="left" id="k4c-6T-xVa"/>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" spacing="5" id="pRF-iD-Gt4" userLabel="FileGroup">
|
||||
<items>
|
||||
<imageView width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" image="Location" contentMode="center" id="uxs-Nx-we9" userLabel="VenueIcon">
|
||||
<color key="tintColor" red="0.35566622019999999" green="0.68838506939999999" blue="0.91561108830000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</imageView>
|
||||
<group width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" radius="13" spacing="0.0" id="Y04-zP-Wh2" userLabel="AudioGroup">
|
||||
<items>
|
||||
<imageView width="26" height="26" alignment="left" image="MediaAudioPlay" contentMode="center" id="pcd-Ly-8eO"/>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.35566622019999999" green="0.68838506939999999" blue="0.91561108830000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="26" height="26" alignment="left" verticalAlignment="center" radius="0.0" id="vs3-R3-hff" userLabel="FileIconGroup">
|
||||
<items>
|
||||
<imageView alignment="center" verticalAlignment="center" image="File.png" contentMode="center" id="XqZ-BE-Abt">
|
||||
<color key="tintColor" red="0.14697439970000001" green="0.5607914329" blue="0.88162887099999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</imageView>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</group>
|
||||
<group alignment="left" verticalAlignment="center" layout="vertical" spacing="0.0" id="7Mg-3H-okj" userLabel="FileMetaGroup">
|
||||
<items>
|
||||
<label alignment="left" text="File Name" id="xUk-Hc-qsr">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
|
||||
</label>
|
||||
<label alignment="left" text="Size" id="d5k-bL-6BP">
|
||||
<color key="textColor" red="0.41865724329999998" green="0.41825520989999998" blue="0.4306421876" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="6.5" right="6.5" top="2" bottom="1"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" spacing="0.0" id="zqd-Tm-ZRg" userLabel="StickerWrapper">
|
||||
<items>
|
||||
<group width="84" height="84" alignment="left" contentMode="scaleAspectFit" id="CH0-jD-uni" userLabel="StickerGroup">
|
||||
<variation key="device=watch38mm" height="72" width="72"/>
|
||||
<variation key="device=watch40mm" height="88" width="88"/>
|
||||
<variation key="device=watch44mm" height="100" width="100"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="6.5" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" radius="12" id="hTA-bS-Jf1" userLabel="MediaGroup">
|
||||
<items>
|
||||
<group alignment="right" verticalAlignment="bottom" radius="10" id="eEx-yh-cyr" userLabel="DurationGroup">
|
||||
<items>
|
||||
<label alignment="left" text="2:34" id="RiW-Br-zCj" userLabel="Duration">
|
||||
<color key="textColor" red="0.2461894453" green="0.24618205430000001" blue="0.2461862564" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="12"/>
|
||||
</label>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.89292949440000002" green="0.91148859260000004" blue="0.93112039570000005" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="6" right="6" top="2" bottom="2"/>
|
||||
</group>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.089999999999999997" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="4" right="4" top="4" bottom="4"/>
|
||||
</group>
|
||||
<group width="1" alignment="left" id="0B5-0H-Py3" userLabel="CaptionGroup">
|
||||
<items>
|
||||
<label alignment="left" text="Caption" numberOfLines="0" id="isV-kh-Mdr">
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="font" type="system" pointSize="16"/>
|
||||
</label>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="8" right="8" top="4" bottom="4"/>
|
||||
</group>
|
||||
</items>
|
||||
<edgeInsets key="margins" left="1.5" right="1.5" top="0.0" bottom="0.0"/>
|
||||
</group>
|
||||
</items>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="10" bottom="5"/>
|
||||
</group>
|
||||
</items>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<edgeInsets key="margins" left="0.0" right="0.0" top="0.0" bottom="4"/>
|
||||
<connections>
|
||||
<outlet property="audioGroup" destination="Y04-zP-Wh2" id="qTp-zF-Epj"/>
|
||||
<outlet property="captionGroup" destination="0B5-0H-Py3" id="jwq-FC-JCS"/>
|
||||
<outlet property="captionLabel" destination="isV-kh-Mdr" id="egK-Dy-gRD"/>
|
||||
<outlet property="chatTitleLabel" destination="HtY-WB-aFI" id="sSF-mw-4JJ"/>
|
||||
<outlet property="durationGroup" destination="eEx-yh-cyr" id="8Qk-ml-oO8"/>
|
||||
<outlet property="durationLabel" destination="RiW-Br-zCj" id="19H-az-0O6"/>
|
||||
<outlet property="fileGroup" destination="pRF-iD-Gt4" id="I5Q-Fx-UjF"/>
|
||||
<outlet property="fileIconGroup" destination="vs3-R3-hff" id="MGI-5h-Lv8"/>
|
||||
<outlet property="forwardFromLabel" destination="B2R-Qa-MeP" id="kPS-wB-hNR"/>
|
||||
<outlet property="forwardHeaderGroup" destination="Kzq-HH-8Ev" id="bhU-ZI-H0w"/>
|
||||
<outlet property="forwardTitleLabel" destination="NTL-lz-9dd" id="CCG-3i-IZ9"/>
|
||||
<outlet property="map" destination="k4c-6T-xVa" id="2aI-Tb-Oqf"/>
|
||||
<outlet property="mapGroup" destination="vel-8f-OFm" id="mDw-hR-bxF"/>
|
||||
<outlet property="mediaGroup" destination="hTA-bS-Jf1" id="nQw-W2-W4B"/>
|
||||
<outlet property="messageTextLabel" destination="wxg-r7-aSG" id="yS9-nx-01R"/>
|
||||
<outlet property="nameLabel" destination="Hqd-Pr-2zp" id="ija-IM-5QH"/>
|
||||
<outlet property="replyAuthorNameLabel" destination="g6r-Nm-SOQ" id="dK1-3l-hWN"/>
|
||||
<outlet property="replyHeaderGroup" destination="KRV-O6-45y" id="RZE-Vt-aui"/>
|
||||
<outlet property="replyHeaderImageGroup" destination="swd-Nx-MDo" id="aYu-g3-upQ"/>
|
||||
<outlet property="replyMessageTextLabel" destination="dAz-x8-jbh" id="6Cn-zA-Kcs"/>
|
||||
<outlet property="stickerGroup" destination="CH0-jD-uni" id="CcD-rg-vXX"/>
|
||||
<outlet property="stickerWrapperGroup" destination="zqd-Tm-ZRg" id="kps-Rx-vsc"/>
|
||||
<outlet property="subtitleLabel" destination="d5k-bL-6BP" id="7va-0d-xfX"/>
|
||||
<outlet property="titleLabel" destination="xUk-Hc-qsr" id="ck7-ks-w9e"/>
|
||||
<outlet property="venueIcon" destination="uxs-Nx-we9" id="ab7-gA-XrO"/>
|
||||
<outlet property="wrapperGroup" destination="0ch-zY-dJX" id="YqT-J5-azh"/>
|
||||
</connections>
|
||||
</controller>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="503" y="1283"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="UyA-Ra-UVy"/>
|
||||
<segue reference="wDy-DD-bRl"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<color key="tintColor" red="0.15550534427165985" green="0.57037848234176636" blue="0.8720671534538269" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<resources>
|
||||
<image name="BotCommandIcon" width="128" height="128"/>
|
||||
<image name="BubbleNotification" width="128" height="128"/>
|
||||
<image name="File.png" width="128" height="128"/>
|
||||
<image name="Location" width="128" height="128"/>
|
||||
<image name="LocationIcon" width="128" height="128"/>
|
||||
<image name="LoginIcon" width="128" height="128"/>
|
||||
<image name="MediaAudioPlay" width="128" height="128"/>
|
||||
|
@ -10,15 +10,15 @@ public func transformedWithFitzModifier(data: Data, fitzModifier: EmojiFitzModif
|
||||
let replacementColors: [UIColor]
|
||||
switch fitzModifier {
|
||||
case .type12:
|
||||
replacementColors = [0xca907a, 0xedc5a5, 0xf7e3c3, 0xfbefd6].map { UIColor(rgb: $0) }
|
||||
replacementColors = [0xcb7b55, 0xf6b689, 0xffcda7, 0xffdfc5].map { UIColor(rgb: $0) }
|
||||
case .type3:
|
||||
replacementColors = [0xaa7c60, 0xc8a987, 0xddc89f, 0xe6d6b2].map { UIColor(rgb: $0) }
|
||||
replacementColors = [0xa45a38, 0xdf986b, 0xedb183, 0xf4c3a0].map { UIColor(rgb: $0) }
|
||||
case .type4:
|
||||
replacementColors = [0x8c6148, 0xad8562, 0xc49e76, 0xd4b188].map { UIColor(rgb: $0) }
|
||||
replacementColors = [0x703a17, 0xab673d, 0xc37f4e, 0xd89667].map { UIColor(rgb: $0) }
|
||||
case .type5:
|
||||
replacementColors = [0x6e3c2c, 0x925a34, 0xa16e46, 0xac7a52].map { UIColor(rgb: $0) }
|
||||
replacementColors = [0x4a2409, 0x7d3e0e, 0x965529, 0xa96337].map { UIColor(rgb: $0) }
|
||||
case .type6:
|
||||
replacementColors = [0x291c12, 0x472a22, 0x573b30, 0x68493c].map { UIColor(rgb: $0) }
|
||||
replacementColors = [0x200f0a, 0x412924, 0x593d37, 0x63453f].map { UIColor(rgb: $0) }
|
||||
}
|
||||
|
||||
func colorToString(_ color: UIColor) -> String {
|
||||
|
@ -835,7 +835,6 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
items.append(ActionSheetButtonItem(title: globalTitle, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||
let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forEveryone).start()
|
||||
|
||||
strongSelf.updateState { state in
|
||||
@ -859,7 +858,6 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
items.append(ActionSheetButtonItem(title: localOptionText, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||
let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forLocalPeer).start()
|
||||
|
||||
strongSelf.updateState { state in
|
||||
|
@ -307,23 +307,6 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
|
||||
public var valueUpdated: ((Date) -> Void)?
|
||||
|
||||
public var maximumDate: Date {
|
||||
get {
|
||||
return self.state.maxDate
|
||||
}
|
||||
set {
|
||||
guard newValue != self.maximumDate else {
|
||||
return
|
||||
}
|
||||
|
||||
let updatedState = State(minDate: self.state.minDate, maxDate: newValue, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: self.state.selectedMonth)
|
||||
self.updateState(updatedState, animated: false)
|
||||
|
||||
if let size = self.validLayout {
|
||||
let _ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
public var minimumDate: Date {
|
||||
get {
|
||||
return self.state.minDate
|
||||
@ -336,11 +319,34 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
let updatedState = State(minDate: newValue, maxDate: self.state.maxDate, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: self.state.selectedMonth)
|
||||
self.updateState(updatedState, animated: false)
|
||||
|
||||
self.pickerNode.minimumDate = newValue
|
||||
|
||||
if let size = self.validLayout {
|
||||
let _ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var maximumDate: Date {
|
||||
get {
|
||||
return self.state.maxDate
|
||||
}
|
||||
set {
|
||||
guard newValue != self.maximumDate else {
|
||||
return
|
||||
}
|
||||
|
||||
let updatedState = State(minDate: self.state.minDate, maxDate: newValue, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: self.state.selectedMonth)
|
||||
self.updateState(updatedState, animated: false)
|
||||
|
||||
self.pickerNode.maximumDate = newValue
|
||||
|
||||
if let size = self.validLayout {
|
||||
let _ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var date: Date {
|
||||
get {
|
||||
return self.state.date
|
||||
@ -385,6 +391,8 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
self.pickerNode = MonthPickerNode(theme: theme, strings: strings, date: self.state.date, yearRange: yearRange(for: self.state), valueChanged: { date in
|
||||
monthChangedImpl?(date)
|
||||
})
|
||||
self.pickerNode.minimumDate = self.state.minDate
|
||||
self.pickerNode.maximumDate = self.state.maxDate
|
||||
|
||||
self.monthButtonNode = HighlightTrackingButtonNode()
|
||||
self.monthTextNode = ImmediateTextNode()
|
||||
@ -768,8 +776,8 @@ private final class MonthPickerNode: ASDisplayNode, UIPickerViewDelegate, UIPick
|
||||
}
|
||||
}
|
||||
|
||||
var minDate: Date?
|
||||
var maxDate: Date?
|
||||
var minimumDate: Date?
|
||||
var maximumDate: Date?
|
||||
|
||||
private let valueChanged: (Date) -> Void
|
||||
private let pickerView: UIPickerView
|
||||
@ -847,7 +855,26 @@ private final class MonthPickerNode: ASDisplayNode, UIPickerViewDelegate, UIPick
|
||||
let numberOfDays = calendar.range(of: .day, in: .month, for: tempDate)!.count
|
||||
components.day = min(day, numberOfDays)
|
||||
|
||||
let date = calendar.date(from: components)!
|
||||
var date = calendar.date(from: components)!
|
||||
|
||||
if let minimumDate = self.minimumDate, let maximumDate = self.maximumDate {
|
||||
var changed = false
|
||||
if date < minimumDate {
|
||||
date = minimumDate
|
||||
changed = true
|
||||
}
|
||||
if date > maximumDate {
|
||||
date = maximumDate
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
let month = calendar.component(.month, from: date)
|
||||
let year = calendar.component(.year, from: date)
|
||||
self.pickerView.selectRow(month - 1, inComponent: 0, animated: true)
|
||||
self.pickerView.selectRow(year - yearRange.startIndex, inComponent: 1, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
self.date = date
|
||||
|
||||
self.valueChanged(date)
|
||||
@ -924,7 +951,7 @@ private final class TimePickerNode: ASDisplayNode {
|
||||
let minutes = Int32(calendar.component(.hour, from: self.date))
|
||||
let string = stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: self.dateTimeFormat).replacingOccurrences(of: " AM", with: "").replacingOccurrences(of: " PM", with: "")
|
||||
|
||||
self.textNode.attributedText = NSAttributedString(string: string, font: Font.with(size: 21.0, design: .monospace, weight: .regular, traits: []), textColor: self.theme.textColor)
|
||||
self.textNode.attributedText = NSAttributedString(string: string, font: Font.with(size: 21.0, design: .regular, weight: .regular, traits: [.monospacedNumbers]), textColor: self.theme.textColor)
|
||||
let textSize = self.textNode.updateLayout(size)
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((self.backgroundNode.frame.width - textSize.width) / 2.0), y: floorToScreenPixels((self.backgroundNode.frame.height - textSize.height) / 2.0)), size: textSize)
|
||||
|
||||
|
@ -48,14 +48,12 @@ private struct InviteLinkInviteTransaction {
|
||||
private enum InviteLinkInviteEntryId: Hashable {
|
||||
case header
|
||||
case mainLink
|
||||
case links(Int32)
|
||||
case manage
|
||||
}
|
||||
|
||||
private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
||||
case header(PresentationTheme, String, String)
|
||||
case mainLink(PresentationTheme, ExportedInvitation)
|
||||
case links(Int32, PresentationTheme, [ExportedInvitation])
|
||||
case manage(PresentationTheme, String, Bool)
|
||||
|
||||
var stableId: InviteLinkInviteEntryId {
|
||||
@ -64,8 +62,6 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
||||
return .header
|
||||
case .mainLink:
|
||||
return .mainLink
|
||||
case let .links(index, _, _):
|
||||
return .links(index)
|
||||
case .manage:
|
||||
return .manage
|
||||
}
|
||||
@ -85,12 +81,6 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .links(lhsIndex, lhsTheme, lhsInvitations):
|
||||
if case let .links(rhsIndex, rhsTheme, rhsInvitations) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsInvitations == rhsInvitations {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .manage(lhsTheme, lhsText, lhsStandalone):
|
||||
if case let .manage(rhsTheme, rhsText, rhsStandalone) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsStandalone == rhsStandalone {
|
||||
return true
|
||||
@ -106,28 +96,19 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
||||
switch rhs {
|
||||
case .header:
|
||||
return false
|
||||
case .mainLink, .links, .manage:
|
||||
case .mainLink, .manage:
|
||||
return true
|
||||
}
|
||||
case .mainLink:
|
||||
switch rhs {
|
||||
case .header, .mainLink:
|
||||
return false
|
||||
case .links, .manage:
|
||||
return true
|
||||
}
|
||||
case let .links(lhsIndex, _, _):
|
||||
switch rhs {
|
||||
case .header, .mainLink:
|
||||
return false
|
||||
case let .links(rhsIndex, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
case .manage:
|
||||
return true
|
||||
}
|
||||
case .manage:
|
||||
switch rhs {
|
||||
case .header, .mainLink, .links:
|
||||
case .header, .mainLink:
|
||||
return false
|
||||
case .manage:
|
||||
return true
|
||||
@ -148,12 +129,6 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
|
||||
interaction.mainLinkContextAction(invite, node, nil)
|
||||
}, viewAction: {
|
||||
})
|
||||
case let .links(_, _, invites):
|
||||
return ItemListInviteLinkGridItem(presentationData: ItemListPresentationData(presentationData), invites: invites, count: 0, share: true, sectionId: 1, style: .plain, tapAction: { invite in
|
||||
interaction.copyLink(invite)
|
||||
}, contextAction: { invite, _ in
|
||||
interaction.shareLink(invite)
|
||||
})
|
||||
case let .manage(theme, text, standalone):
|
||||
return InviteLinkInviteManageItem(theme: theme, text: text, standalone: standalone, action: {
|
||||
interaction.manageLinks()
|
||||
@ -372,8 +347,17 @@ public final class InviteLinkInviteController: ViewController {
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
if let invite = invite {
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||
self?.controller?.present(controller, in: .window(.root))
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
let isGroup: Bool
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
isGroup = false
|
||||
} else {
|
||||
isGroup = true
|
||||
}
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
|
||||
self?.controller?.present(controller, in: .window(.root))
|
||||
})
|
||||
}
|
||||
})))
|
||||
|
||||
@ -392,10 +376,6 @@ public final class InviteLinkInviteController: ViewController {
|
||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
// revokePeerExportedInvitation(account: <#T##Account#>, peerId: <#T##PeerId#>, link: <#T##String#>)
|
||||
// self?.revokeDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
|
||||
//
|
||||
// }))
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
@ -430,7 +410,13 @@ public final class InviteLinkInviteController: ViewController {
|
||||
if let strongSelf = self {
|
||||
var entries: [InviteLinkInviteEntry] = []
|
||||
|
||||
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_InviteLink, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
|
||||
let helpText: String
|
||||
if let peer = peerViewMainPeer(view) as? TelegramChannel, case .broadcast = peer.info {
|
||||
helpText = presentationData.strings.InviteLink_CreatePrivateLinkHelpChannel
|
||||
} else {
|
||||
helpText = presentationData.strings.InviteLink_CreatePrivateLinkHelp
|
||||
}
|
||||
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_InviteLink, helpText))
|
||||
|
||||
let mainInvite: ExportedInvitation?
|
||||
if let cachedData = view.cachedData as? CachedGroupData, let invite = cachedData.exportedInvitation {
|
||||
@ -444,19 +430,7 @@ public final class InviteLinkInviteController: ViewController {
|
||||
entries.append(.mainLink(presentationData.theme, mainInvite))
|
||||
}
|
||||
|
||||
let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
|
||||
var index: Int32 = 0
|
||||
for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
|
||||
var invitesPair: [ExportedInvitation] = []
|
||||
invitesPair.append(additionalInvites[i])
|
||||
if i + 1 < additionalInvites.count {
|
||||
invitesPair.append(additionalInvites[i + 1])
|
||||
}
|
||||
entries.append(.links(index, presentationData.theme, invitesPair))
|
||||
index += 1
|
||||
}
|
||||
|
||||
entries.append(.manage(presentationData.theme, presentationData.strings.InviteLink_Manage, additionalInvites.isEmpty))
|
||||
entries.append(.manage(presentationData.theme, presentationData.strings.InviteLink_Manage, true))
|
||||
|
||||
let previousEntries = previousEntries.swap(entries)
|
||||
|
||||
|
@ -70,7 +70,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
|
||||
case revokedLinksHeader(PresentationTheme, String)
|
||||
case revokedLinksDeleteAll(PresentationTheme, String)
|
||||
case revokedLinks(Int32, PresentationTheme, ExportedInvitation?)
|
||||
case revokedLink(Int32, PresentationTheme, ExportedInvitation?)
|
||||
|
||||
case adminsHeader(PresentationTheme, String)
|
||||
case admin(Int32, PresentationTheme, ExportedInvitationCreator)
|
||||
@ -83,7 +83,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
return InviteLinksListSection.mainLink.rawValue
|
||||
case .linksHeader, .linksCreate, .link, .linksInfo:
|
||||
return InviteLinksListSection.links.rawValue
|
||||
case .revokedLinksHeader, .revokedLinksDeleteAll, .revokedLinks:
|
||||
case .revokedLinksHeader, .revokedLinksDeleteAll, .revokedLink:
|
||||
return InviteLinksListSection.revokedLinks.rawValue
|
||||
case .adminsHeader, .admin:
|
||||
return InviteLinksListSection.admins.rawValue
|
||||
@ -112,7 +112,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
return 10001
|
||||
case .revokedLinksDeleteAll:
|
||||
return 10002
|
||||
case let .revokedLinks(index, _, _):
|
||||
case let .revokedLink(index, _, _):
|
||||
return 10003 + index
|
||||
case .adminsHeader:
|
||||
return 20001
|
||||
@ -183,8 +183,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .revokedLinks(lhsIndex, lhsTheme, lhsLink):
|
||||
if case let .revokedLinks(rhsIndex, rhsTheme, rhsLink) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsLink == rhsLink {
|
||||
case let .revokedLink(lhsIndex, lhsTheme, lhsLink):
|
||||
if case let .revokedLink(rhsIndex, rhsTheme, rhsLink) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsLink == rhsLink {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -253,7 +253,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.deleteIconImage(theme), title: text, sectionId: self.section, color: .destructive, editing: false, action: {
|
||||
arguments.deleteAllRevokedLinks()
|
||||
})
|
||||
case let .revokedLinks(_, _, invite):
|
||||
case let .revokedLink(_, _, invite):
|
||||
return ItemListInviteLinkItem(presentationData: presentationData, invite: invite, share: false, sectionId: self.section, style: .blocks) { invite in
|
||||
arguments.openLink(invite)
|
||||
} contextAction: { invite, node, gesture in
|
||||
@ -273,7 +273,13 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
||||
var entries: [InviteLinksListEntry] = []
|
||||
|
||||
if admin == nil {
|
||||
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
|
||||
let helpText: String
|
||||
if let peer = peerViewMainPeer(view) as? TelegramChannel, case .broadcast = peer.info {
|
||||
helpText = presentationData.strings.InviteLink_CreatePrivateLinkHelpChannel
|
||||
} else {
|
||||
helpText = presentationData.strings.InviteLink_CreatePrivateLinkHelp
|
||||
}
|
||||
entries.append(.header(presentationData.theme, helpText))
|
||||
}
|
||||
|
||||
let mainInvite: ExportedInvitation?
|
||||
@ -308,21 +314,32 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
||||
entries.append(.mainLinkOtherInfo(presentationData.theme, string.0))
|
||||
}
|
||||
|
||||
entries.append(.linksHeader(presentationData.theme, presentationData.strings.InviteLink_AdditionalLinks.uppercased()))
|
||||
if admin == nil {
|
||||
entries.append(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
|
||||
}
|
||||
var additionalInvites: [ExportedInvitation]?
|
||||
if let invites = invites {
|
||||
additionalInvites = invites.filter { $0.link != mainInvite?.link }
|
||||
}
|
||||
|
||||
var hasLinks = false
|
||||
if let additionalInvites = additionalInvites, !additionalInvites.isEmpty {
|
||||
hasLinks = true
|
||||
} else if let admin = admin, admin.count > 1 {
|
||||
hasLinks = true
|
||||
}
|
||||
|
||||
if hasLinks {
|
||||
entries.append(.linksHeader(presentationData.theme, presentationData.strings.InviteLink_AdditionalLinks.uppercased()))
|
||||
}
|
||||
if admin == nil {
|
||||
entries.append(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
|
||||
}
|
||||
|
||||
if let additionalInvites = additionalInvites {
|
||||
var index: Int32 = 0
|
||||
for invite in additionalInvites {
|
||||
entries.append(.link(index, presentationData.theme, invite, invite.expireDate != nil ? tick : nil))
|
||||
index += 1
|
||||
}
|
||||
} else if let admin = admin, admin.count > 0 {
|
||||
} else if let admin = admin, admin.count > 1 {
|
||||
var index: Int32 = 0
|
||||
for _ in 0 ..< admin.count - 1 {
|
||||
entries.append(.link(index, presentationData.theme, nil, nil))
|
||||
@ -340,7 +357,13 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
||||
}
|
||||
var index: Int32 = 0
|
||||
for invite in revokedInvites {
|
||||
entries.append(.revokedLinks(index, presentationData.theme, invite))
|
||||
entries.append(.revokedLink(index, presentationData.theme, invite))
|
||||
index += 1
|
||||
}
|
||||
} else if let admin = admin, admin.revokedCount > 0 {
|
||||
var index: Int32 = 0
|
||||
for _ in 0 ..< admin.revokedCount {
|
||||
entries.append(.revokedLink(index, presentationData.theme, nil))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -387,7 +410,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
|
||||
var getControllerImpl: (() -> ViewController?)?
|
||||
|
||||
let adminId = admin?.peer.peer?.id
|
||||
let invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: adminId, revoked: false, forceUpdate: false)
|
||||
let invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: adminId, revoked: false, forceUpdate: true)
|
||||
let revokedInvitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: adminId, revoked: true, forceUpdate: true)
|
||||
|
||||
let creators: Signal<[ExportedInvitationCreator], NoError>
|
||||
@ -435,8 +458,17 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||
presentControllerImpl?(controller, nil)
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let isGroup: Bool
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
isGroup = false
|
||||
} else {
|
||||
isGroup = true
|
||||
}
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
|
||||
presentControllerImpl?(controller, nil)
|
||||
})
|
||||
})))
|
||||
|
||||
if invite.adminId.toInt64() != 0 {
|
||||
@ -545,8 +577,17 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||
presentControllerImpl?(controller, nil)
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let isGroup: Bool
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
isGroup = false
|
||||
} else {
|
||||
isGroup = true
|
||||
}
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
|
||||
presentControllerImpl?(controller, nil)
|
||||
})
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextEdit, icon: { theme in
|
||||
|
@ -37,14 +37,16 @@ public final class InviteLinkQRCodeController: ViewController {
|
||||
|
||||
private let context: AccountContext
|
||||
private let invite: ExportedInvitation
|
||||
private let isGroup: Bool
|
||||
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
private let idleTimerExtensionDisposable = MetaDisposable()
|
||||
|
||||
public init(context: AccountContext, invite: ExportedInvitation) {
|
||||
public init(context: AccountContext, invite: ExportedInvitation, isGroup: Bool) {
|
||||
self.context = context
|
||||
self.invite = invite
|
||||
self.isGroup = isGroup
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
|
||||
@ -74,7 +76,7 @@ public final class InviteLinkQRCodeController: ViewController {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = Node(context: self.context, invite: self.invite)
|
||||
self.displayNode = Node(context: self.context, invite: self.invite, isGroup: self.isGroup)
|
||||
self.controllerNode.dismiss = { [weak self] in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
@ -133,7 +135,7 @@ public final class InviteLinkQRCodeController: ViewController {
|
||||
var dismiss: (() -> Void)?
|
||||
var cancel: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, invite: ExportedInvitation) {
|
||||
init(context: AccountContext, invite: ExportedInvitation, isGroup: Bool) {
|
||||
self.context = context
|
||||
self.invite = invite
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -211,7 +213,7 @@ public final class InviteLinkQRCodeController: ViewController {
|
||||
|
||||
let textFont = Font.regular(13.0)
|
||||
|
||||
self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.InviteLink_QRCode_Info, font: textFont, textColor: secondaryTextColor)
|
||||
self.textNode.attributedText = NSAttributedString(string: isGroup ? self.presentationData.strings.InviteLink_QRCode_Info : self.presentationData.strings.InviteLink_QRCode_InfoChannel, font: textFont, textColor: secondaryTextColor)
|
||||
self.buttonNode.title = self.presentationData.strings.InviteLink_QRCode_Share
|
||||
|
||||
self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
@ -343,7 +343,6 @@ public final class InviteLinkViewController: ViewController {
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
private var disposable: Disposable?
|
||||
private let actionDisposable = MetaDisposable()
|
||||
|
||||
private let dimNode: ASDisplayNode
|
||||
private let contentNode: ASDisplayNode
|
||||
@ -473,9 +472,10 @@ public final class InviteLinkViewController: ViewController {
|
||||
ActionSheetTextItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Text),
|
||||
ActionSheetButtonItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Action, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
self?.actionDisposable.set((deletePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
}))
|
||||
self?.controller?.dismiss()
|
||||
|
||||
let _ = (deletePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
})
|
||||
|
||||
self?.controller?.revokedInvitationsContext?.remove(invite)
|
||||
})
|
||||
@ -490,7 +490,42 @@ public final class InviteLinkViewController: ViewController {
|
||||
}, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
let isGroup: Bool
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
isGroup = false
|
||||
} else {
|
||||
isGroup = true
|
||||
}
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
|
||||
self?.controller?.present(controller, in: .window(.root))
|
||||
})
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
let controller = ActionSheetController(presentationData: presentationData)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeAlert_Text),
|
||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||
dismissAction()
|
||||
self?.controller?.dismiss()
|
||||
|
||||
let _ = (revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
})
|
||||
|
||||
self?.controller?.revokedInvitationsContext?.remove(invite)
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
self?.controller?.present(controller, in: .window(.root))
|
||||
})))
|
||||
}
|
||||
@ -739,6 +774,7 @@ public final class InviteLinkViewController: ViewController {
|
||||
subtitleText = self.presentationData.strings.InviteLink_Revoked
|
||||
} else if let usageLimit = self.invite.usageLimit, let count = self.invite.count, count >= usageLimit {
|
||||
subtitleText = self.presentationData.strings.InviteLink_UsageLimitReached
|
||||
subtitleColor = self.presentationData.theme.list.itemDestructiveColor
|
||||
} else if let expireDate = self.invite.expireDate {
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
if currentTime >= expireDate {
|
||||
|
@ -1,670 +0,0 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import SyncCore
|
||||
import TelegramPresentationData
|
||||
import ItemListUI
|
||||
import SolidRoundedButtonNode
|
||||
import RadialStatusNode
|
||||
|
||||
private let itemSpacing: CGFloat = 10.0
|
||||
private let titleFont = Font.semibold(17.0)
|
||||
private let subtitleFont = Font.regular(12.0)
|
||||
|
||||
private enum ItemBackgroundColor: Equatable {
|
||||
case blue
|
||||
case green
|
||||
case yellow
|
||||
case red
|
||||
case gray
|
||||
|
||||
var colors: (top: UIColor, bottom: UIColor, text: UIColor) {
|
||||
switch self {
|
||||
case .blue:
|
||||
return (UIColor(rgb: 0x00b5f7), UIColor(rgb: 0x00b2f6), UIColor(rgb: 0xa7f4ff))
|
||||
case .green:
|
||||
return (UIColor(rgb: 0x4aca62), UIColor(rgb: 0x43c85c), UIColor(rgb: 0xc5ffe6))
|
||||
case .yellow:
|
||||
return (UIColor(rgb: 0xf8a953), UIColor(rgb: 0xf7a64e), UIColor(rgb: 0xfeffd7))
|
||||
case .red:
|
||||
return (UIColor(rgb: 0xf2656a), UIColor(rgb: 0xf25f65), UIColor(rgb: 0xffd3de))
|
||||
case .gray:
|
||||
return (UIColor(rgb: 0xa8b2bb), UIColor(rgb: 0xa2abb4), UIColor(rgb: 0xe3e6e8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let moreIcon = generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setBlendMode(.clear)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 4.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 11.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 18.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
|
||||
})
|
||||
|
||||
private let shareIcon = generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
if let maskImage = UIImage(bundleImageName: "Chat/Links/Share") {
|
||||
context.clip(to: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - maskImage.size.width) / 2.0), y: floorToScreenPixels((size.height - maskImage.size.height) / 2.0)), size: maskImage.size), mask: maskImage.cgImage!)
|
||||
context.setBlendMode(.clear)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
})
|
||||
|
||||
private class ItemNode: ASDisplayNode {
|
||||
private let selectionNode: HighlightTrackingButtonNode
|
||||
private let wrapperNode: ASDisplayNode
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let backgroundGradientLayer: CAGradientLayer
|
||||
|
||||
private let iconNode: ASImageNode
|
||||
private var timerNode: TimerNode?
|
||||
|
||||
private let extractedContainerNode: ContextExtractedContentContainingNode
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
private let buttonIconNode: ASImageNode
|
||||
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let subtitleNode: ImmediateTextNode
|
||||
|
||||
private var updateTimer: SwiftSignalKit.Timer?
|
||||
|
||||
private var params: (size: CGSize, wide: Bool, invite: ExportedInvitation?, color: ItemBackgroundColor, presentationData: ItemListPresentationData)?
|
||||
|
||||
var action: (() -> Void)?
|
||||
var contextAction: ((ASDisplayNode) -> Void)?
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
||||
override init() {
|
||||
self.selectionNode = HighlightTrackingButtonNode()
|
||||
self.wrapperNode = ASDisplayNode()
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.clipsToBounds = true
|
||||
self.backgroundNode.cornerRadius = 15.0
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
self.backgroundNode.isUserInteractionEnabled = false
|
||||
|
||||
self.backgroundGradientLayer = CAGradientLayer()
|
||||
self.backgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
|
||||
self.backgroundGradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
|
||||
self.backgroundNode.layer.addSublayer(self.backgroundGradientLayer)
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
self.iconNode.isUserInteractionEnabled = false
|
||||
|
||||
self.buttonNode = HighlightTrackingButtonNode()
|
||||
self.extractedContainerNode = ContextExtractedContentContainingNode()
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
self.containerNode.isGestureEnabled = false
|
||||
self.buttonIconNode = ASImageNode()
|
||||
self.buttonIconNode.displaysAsynchronously = false
|
||||
self.buttonIconNode.displayWithoutProcessing = true
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.maximumNumberOfLines = 2
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
|
||||
self.subtitleNode = ImmediateTextNode()
|
||||
self.subtitleNode.maximumNumberOfLines = 1
|
||||
self.subtitleNode.isUserInteractionEnabled = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.wrapperNode)
|
||||
self.wrapperNode.addSubnode(self.backgroundNode)
|
||||
self.wrapperNode.addSubnode(self.iconNode)
|
||||
|
||||
self.containerNode.addSubnode(self.extractedContainerNode)
|
||||
self.extractedContainerNode.contentNode.addSubnode(self.buttonIconNode)
|
||||
self.containerNode.targetNodeForActivationProgress = self.extractedContainerNode.contentNode
|
||||
self.buttonNode.addSubnode(self.containerNode)
|
||||
|
||||
self.wrapperNode.addSubnode(self.selectionNode)
|
||||
self.wrapperNode.addSubnode(self.buttonNode)
|
||||
|
||||
self.wrapperNode.addSubnode(self.titleNode)
|
||||
self.wrapperNode.addSubnode(self.subtitleNode)
|
||||
|
||||
self.selectionNode.addTarget(self, action: #selector(self.tapped), forControlEvents: .touchUpInside)
|
||||
self.selectionNode.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.18, curve: .linear)
|
||||
transition.updateSublayerTransformScale(node: strongSelf, scale: 0.95)
|
||||
} else {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .linear)
|
||||
transition.updateSublayerTransformScale(node: strongSelf, scale: 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.buttonIconNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.buttonIconNode.alpha = 0.4
|
||||
} else {
|
||||
strongSelf.buttonIconNode.alpha = 1.0
|
||||
strongSelf.buttonIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.updateTimer?.invalidate()
|
||||
}
|
||||
|
||||
@objc private func tapped() {
|
||||
self.hapticFeedback.impact(.light)
|
||||
self.action?()
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
self.contextAction?(self.extractedContainerNode)
|
||||
}
|
||||
|
||||
func update(size: CGSize, wide: Bool, share: Bool, invite: ExportedInvitation?, presentationData: ItemListPresentationData, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
|
||||
let availability = invite.flatMap { invitationAvailability($0) } ?? 0.0
|
||||
let transitionFraction: CGFloat
|
||||
let color: ItemBackgroundColor
|
||||
let nextColor: ItemBackgroundColor
|
||||
if let invite = invite {
|
||||
if invite.isRevoked {
|
||||
color = .gray
|
||||
nextColor = .gray
|
||||
transitionFraction = 0.0
|
||||
} else if invite.expireDate == nil && invite.usageLimit == nil {
|
||||
color = .blue
|
||||
nextColor = .blue
|
||||
transitionFraction = 0.0
|
||||
} else if availability >= 0.5 {
|
||||
color = .green
|
||||
nextColor = .yellow
|
||||
transitionFraction = (availability - 0.5) / 0.5
|
||||
} else if availability > 0.0 {
|
||||
color = .yellow
|
||||
nextColor = .red
|
||||
transitionFraction = availability / 0.5
|
||||
} else {
|
||||
color = .red
|
||||
nextColor = .red
|
||||
transitionFraction = 0.0
|
||||
}
|
||||
} else {
|
||||
color = .gray
|
||||
nextColor = .gray
|
||||
transitionFraction = 0.0
|
||||
}
|
||||
|
||||
let previousParams = self.params
|
||||
self.params = (size, wide, invite, color, presentationData)
|
||||
|
||||
let previousExpireDate = previousParams?.invite?.expireDate
|
||||
if previousExpireDate != invite?.expireDate {
|
||||
self.updateTimer?.invalidate()
|
||||
self.updateTimer = nil
|
||||
|
||||
if let expireDate = invite?.expireDate, availability > 0.0 {
|
||||
let timeout = min(2.0, max(0.001, Double(expireDate - currentTime)))
|
||||
let updateTimer = SwiftSignalKit.Timer(timeout: timeout, repeat: true, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let (size, wide, invite, _, presentationData) = strongSelf.params {
|
||||
let _ = strongSelf.update(size: size, wide: wide, share: share, invite: invite, presentationData: presentationData, transition: .animated(duration: 0.3, curve: .linear))
|
||||
}
|
||||
}
|
||||
}, queue: Queue.mainQueue())
|
||||
self.updateTimer = updateTimer
|
||||
updateTimer.start()
|
||||
}
|
||||
} else if availability.isZero {
|
||||
self.updateTimer?.invalidate()
|
||||
self.updateTimer = nil
|
||||
}
|
||||
|
||||
let topColor = color.colors.top
|
||||
let bottomColor = color.colors.bottom
|
||||
let nextTopColor = nextColor.colors.top
|
||||
let nextBottomColor = nextColor.colors.bottom
|
||||
let colors: NSArray
|
||||
if let invite = invite {
|
||||
colors = [nextTopColor.mixedWith(topColor, alpha: transitionFraction).cgColor, nextBottomColor.mixedWith(bottomColor, alpha: transitionFraction).cgColor]
|
||||
} else {
|
||||
colors = [UIColor(rgb: 0xf2f2f7).cgColor, UIColor(rgb: 0xf2f2f7).cgColor]
|
||||
}
|
||||
|
||||
if let (_, _, previousInvite, previousColor, _) = previousParams, previousInvite == invite {
|
||||
if previousColor != color && color == .red {
|
||||
if let snapshotView = self.wrapperNode.view.snapshotContentTree() {
|
||||
snapshotView.frame = self.wrapperNode.bounds
|
||||
self.wrapperNode.view.addSubview(snapshotView)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||
} else if (color == .green && nextColor == .yellow) || (color == .yellow && nextColor == .red) {
|
||||
let previousColors = self.backgroundGradientLayer.colors
|
||||
if transition.isAnimated {
|
||||
self.backgroundGradientLayer.animate(from: previousColors as AnyObject, to: self.backgroundGradientLayer.colors as AnyObject, keyPath: "colors", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 2.5)
|
||||
}
|
||||
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||
}
|
||||
} else {
|
||||
self.backgroundGradientLayer.colors = colors as? [Any]
|
||||
}
|
||||
|
||||
let secondaryTextColor = nextColor.colors.text.mixedWith(color.colors.text, alpha: transitionFraction)
|
||||
|
||||
let itemWidth = wide ? size.width : floor((size.width - itemSpacing) / 2.0)
|
||||
var inviteLink = invite?.link.replacingOccurrences(of: "https://", with: "") ?? ""
|
||||
if !wide {
|
||||
inviteLink = inviteLink.replacingOccurrences(of: "joinchat/", with: "joinchat/\n")
|
||||
inviteLink = inviteLink.replacingOccurrences(of: "join/", with: "join/\n")
|
||||
}
|
||||
let title: NSMutableAttributedString = NSMutableAttributedString(string: inviteLink, font: titleFont, textColor: UIColor.white)
|
||||
if inviteLink.hasPrefix("t.me/joinchat/") {
|
||||
title.addAttribute(NSAttributedString.Key.foregroundColor, value: secondaryTextColor, range: NSMakeRange(0, "t.me/joinchat/".count))
|
||||
} else if inviteLink.hasPrefix("t.me/join/") {
|
||||
title.addAttribute(NSAttributedString.Key.foregroundColor, value: secondaryTextColor, range: NSMakeRange(0, "t.me/join/".count))
|
||||
}
|
||||
self.titleNode.attributedText = title
|
||||
|
||||
self.buttonIconNode.image = share ? shareIcon : moreIcon
|
||||
|
||||
var subtitleText: String = ""
|
||||
if let invite = invite {
|
||||
if let count = invite.count {
|
||||
subtitleText = presentationData.strings.InviteLink_PeopleJoinedShort(count)
|
||||
} else {
|
||||
subtitleText = [.red, .gray].contains(color) ? presentationData.strings.InviteLink_PeopleJoinedShortNoneExpired : presentationData.strings.InviteLink_PeopleJoinedShortNone
|
||||
}
|
||||
if invite.isRevoked {
|
||||
if !subtitleText.isEmpty {
|
||||
subtitleText += " • "
|
||||
}
|
||||
subtitleText += presentationData.strings.InviteLink_Revoked
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
|
||||
self.timerNode?.removeFromSupernode()
|
||||
self.timerNode = nil
|
||||
} else if let expireDate = invite.expireDate, currentTime >= expireDate {
|
||||
if !subtitleText.isEmpty {
|
||||
subtitleText += " • "
|
||||
}
|
||||
if share {
|
||||
subtitleText = presentationData.strings.InviteLink_Expired
|
||||
} else {
|
||||
subtitleText += presentationData.strings.InviteLink_Expired
|
||||
}
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
|
||||
self.timerNode?.removeFromSupernode()
|
||||
self.timerNode = nil
|
||||
} else if let usageLimit = invite.usageLimit, let count = invite.count, count >= usageLimit {
|
||||
if !subtitleText.isEmpty {
|
||||
subtitleText += " • "
|
||||
}
|
||||
if share {
|
||||
subtitleText = presentationData.strings.InviteLink_UsageLimitReached
|
||||
} else {
|
||||
subtitleText += presentationData.strings.InviteLink_UsageLimitReached
|
||||
}
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
|
||||
self.timerNode?.removeFromSupernode()
|
||||
self.timerNode = nil
|
||||
} else if let expireDate = invite.expireDate {
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Flame"), color: .white)
|
||||
let timerNode: TimerNode
|
||||
if let current = self.timerNode {
|
||||
timerNode = current
|
||||
} else {
|
||||
timerNode = TimerNode()
|
||||
timerNode.isUserInteractionEnabled = false
|
||||
self.timerNode = timerNode
|
||||
self.addSubnode(timerNode)
|
||||
}
|
||||
timerNode.update(color: UIColor.white, creationTimestamp: invite.startDate ?? invite.date, deadlineTimestamp: expireDate)
|
||||
if share {
|
||||
subtitleText = presentationData.strings.InviteLink_TapToCopy
|
||||
}
|
||||
} else {
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Link"), color: .white)
|
||||
self.timerNode?.removeFromSupernode()
|
||||
self.timerNode = nil
|
||||
if share {
|
||||
subtitleText = presentationData.strings.InviteLink_TapToCopy
|
||||
}
|
||||
}
|
||||
self.iconNode.isHidden = false
|
||||
self.buttonIconNode.isHidden = false
|
||||
} else {
|
||||
self.iconNode.isHidden = true
|
||||
self.buttonIconNode.isHidden = true
|
||||
}
|
||||
|
||||
self.iconNode.frame = CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)
|
||||
self.timerNode?.frame = CGRect(x: 8.0, y: 8.0, width: 34.0, height: 34.0)
|
||||
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: subtitleText, font: subtitleFont, textColor: secondaryTextColor)
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: itemWidth - 24.0, height: 100.0))
|
||||
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: itemWidth - 24.0, height: 100.0))
|
||||
|
||||
self.titleNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 52.0), size: titleSize)
|
||||
self.subtitleNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 52.0 + titleSize.height + 3.0), size: subtitleSize)
|
||||
|
||||
let itemSize = CGSize(width: itemWidth, height: wide ? 102.0 : 122.0)
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(), size: itemSize)
|
||||
transition.updateFrame(node: self.wrapperNode, frame: backgroundFrame)
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
transition.updateFrame(node: self.selectionNode, frame: backgroundFrame)
|
||||
transition.updateFrame(layer: self.backgroundGradientLayer, frame: backgroundFrame)
|
||||
|
||||
let buttonSize = CGSize(width: 26.0, height: 26.0)
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: itemSize.width - buttonSize.width - 12.0, y: 12.0), size: buttonSize)
|
||||
transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
|
||||
|
||||
self.extractedContainerNode.frame = CGRect(origin: CGPoint(), size: buttonSize)
|
||||
self.extractedContainerNode.contentRect = CGRect(origin: CGPoint(), size: buttonSize)
|
||||
self.buttonIconNode.frame = CGRect(origin: CGPoint(), size: buttonSize)
|
||||
|
||||
return itemSize
|
||||
}
|
||||
}
|
||||
|
||||
class InviteLinksGridNode: ASDisplayNode {
|
||||
private var items: [ExportedInvitation]?
|
||||
private var itemNodes: [String: ItemNode] = [:]
|
||||
|
||||
var action: ((ExportedInvitation) -> Void)?
|
||||
var contextAction: ((ASDisplayNode, ExportedInvitation) -> Void)?
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
return result
|
||||
}
|
||||
|
||||
func update(size: CGSize, safeInset: CGFloat, items: [ExportedInvitation]?, count: Int, share: Bool, presentationData: ItemListPresentationData, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
self.items = items
|
||||
|
||||
var contentSize: CGSize = size
|
||||
var contentHeight: CGFloat = 0.0
|
||||
|
||||
let sideInset: CGFloat = 16.0 + safeInset
|
||||
|
||||
var validIds = Set<String>()
|
||||
|
||||
let count = items?.count ?? count
|
||||
|
||||
for i in 0 ..< count {
|
||||
let invite: ExportedInvitation?
|
||||
let id: String
|
||||
if let items = items, i < items.count {
|
||||
invite = items[i]
|
||||
id = invite!.link
|
||||
} else {
|
||||
invite = nil
|
||||
id = "placeholder_\(i)"
|
||||
}
|
||||
|
||||
validIds.insert(id)
|
||||
|
||||
var itemNode: ItemNode?
|
||||
var wasAdded = false
|
||||
|
||||
if let current = self.itemNodes[id] {
|
||||
itemNode = current
|
||||
} else {
|
||||
wasAdded = true
|
||||
let addedItemNode = ItemNode()
|
||||
itemNode = addedItemNode
|
||||
self.itemNodes[id] = addedItemNode
|
||||
self.addSubnode(addedItemNode)
|
||||
}
|
||||
if let itemNode = itemNode {
|
||||
let col = CGFloat(i % 2)
|
||||
let row = floor(CGFloat(i) / 2.0)
|
||||
let wide = (i == count - 1 && (count % 2) != 0)
|
||||
let itemSize = itemNode.update(size: CGSize(width: size.width - sideInset * 2.0, height: size.height), wide: wide, share: share, invite: invite, presentationData: presentationData, transition: transition)
|
||||
var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: 4.0 + row * (122.0 + itemSpacing)), size: itemSize)
|
||||
if !wide && col > 0 {
|
||||
itemFrame.origin.x += itemSpacing + itemSize.width
|
||||
}
|
||||
|
||||
contentHeight = max(contentHeight, itemFrame.maxY + itemSpacing)
|
||||
|
||||
if wasAdded {
|
||||
itemNode.frame = itemFrame
|
||||
} else {
|
||||
transition.updateFrame(node: itemNode, frame: itemFrame)
|
||||
}
|
||||
itemNode.action = { [weak self] in
|
||||
if let invite = invite {
|
||||
self?.action?(invite)
|
||||
}
|
||||
}
|
||||
itemNode.contextAction = { [weak self] node in
|
||||
if let invite = invite {
|
||||
self?.contextAction?(node, invite)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var removeIds: [String] = []
|
||||
for (id, _) in self.itemNodes {
|
||||
if !validIds.contains(id) {
|
||||
removeIds.append(id)
|
||||
}
|
||||
}
|
||||
for id in removeIds {
|
||||
if let itemNode = self.itemNodes.removeValue(forKey: id) {
|
||||
itemNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
contentSize.height = contentHeight
|
||||
return contentSize
|
||||
}
|
||||
}
|
||||
|
||||
private struct ContentParticle {
|
||||
var position: CGPoint
|
||||
var direction: CGPoint
|
||||
var velocity: CGFloat
|
||||
var alpha: CGFloat
|
||||
var lifetime: Double
|
||||
var beginTime: Double
|
||||
|
||||
init(position: CGPoint, direction: CGPoint, velocity: CGFloat, alpha: CGFloat, lifetime: Double, beginTime: Double) {
|
||||
self.position = position
|
||||
self.direction = direction
|
||||
self.velocity = velocity
|
||||
self.alpha = alpha
|
||||
self.lifetime = lifetime
|
||||
self.beginTime = beginTime
|
||||
}
|
||||
}
|
||||
|
||||
private final class TimerNode: ASDisplayNode {
|
||||
private struct Params: Equatable {
|
||||
var color: UIColor
|
||||
var creationTimestamp: Int32
|
||||
var deadlineTimestamp: Int32
|
||||
}
|
||||
|
||||
private let hierarchyTrackingNode: HierarchyTrackingNode
|
||||
private var inHierarchyValue: Bool = false
|
||||
|
||||
private var animator: ConstantDisplayLinkAnimator?
|
||||
private let contentNode: ASDisplayNode
|
||||
private var particles: [ContentParticle] = []
|
||||
|
||||
private var currentParams: Params?
|
||||
|
||||
var reachedTimeout: (() -> Void)?
|
||||
|
||||
override init() {
|
||||
var updateInHierarchy: ((Bool) -> Void)?
|
||||
self.hierarchyTrackingNode = HierarchyTrackingNode({ value in
|
||||
updateInHierarchy?(value)
|
||||
})
|
||||
|
||||
self.contentNode = ASDisplayNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.contentNode)
|
||||
|
||||
updateInHierarchy = { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.inHierarchyValue = value
|
||||
strongSelf.animator?.isPaused = value
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.animator?.invalidate()
|
||||
}
|
||||
|
||||
func update(color: UIColor, creationTimestamp: Int32, deadlineTimestamp: Int32) {
|
||||
let params = Params(
|
||||
color: color,
|
||||
creationTimestamp: creationTimestamp,
|
||||
deadlineTimestamp: deadlineTimestamp
|
||||
)
|
||||
self.currentParams = params
|
||||
|
||||
self.updateValues()
|
||||
}
|
||||
|
||||
private func updateValues() {
|
||||
guard let params = self.currentParams else {
|
||||
return
|
||||
}
|
||||
|
||||
let color = params.color
|
||||
|
||||
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
var fraction = CGFloat(params.deadlineTimestamp - currentTimestamp) / CGFloat(params.deadlineTimestamp - params.creationTimestamp)
|
||||
fraction = max(0.0001, 1.0 - max(0.0, min(1.0, fraction)))
|
||||
|
||||
let image: UIImage?
|
||||
|
||||
let diameter: CGFloat = 26.0
|
||||
let inset: CGFloat = 8.0
|
||||
let lineWidth: CGFloat = 2.0
|
||||
|
||||
let timestamp = CACurrentMediaTime()
|
||||
|
||||
let center = CGPoint(x: (diameter + inset) / 2.0, y: (diameter + inset) / 2.0)
|
||||
let radius: CGFloat = (diameter - lineWidth / 2.0) / 2.0
|
||||
|
||||
let startAngle: CGFloat = -CGFloat.pi / 2.0
|
||||
let endAngle: CGFloat = -CGFloat.pi / 2.0 + 2.0 * CGFloat.pi * fraction
|
||||
|
||||
let sparks = fraction > 0.1 && fraction != 1.0
|
||||
if sparks {
|
||||
let v = CGPoint(x: sin(endAngle), y: -cos(endAngle))
|
||||
let c = CGPoint(x: -v.y * radius + center.x, y: v.x * radius + center.y)
|
||||
|
||||
let dt: CGFloat = 1.0 / 60.0
|
||||
var removeIndices: [Int] = []
|
||||
for i in 0 ..< self.particles.count {
|
||||
let currentTime = timestamp - self.particles[i].beginTime
|
||||
if currentTime > self.particles[i].lifetime {
|
||||
removeIndices.append(i)
|
||||
} else {
|
||||
let input: CGFloat = CGFloat(currentTime / self.particles[i].lifetime)
|
||||
let decelerated: CGFloat = (1.0 - (1.0 - input) * (1.0 - input))
|
||||
self.particles[i].alpha = 1.0 - decelerated
|
||||
|
||||
var p = self.particles[i].position
|
||||
let d = self.particles[i].direction
|
||||
let v = self.particles[i].velocity
|
||||
p = CGPoint(x: p.x + d.x * v * dt, y: p.y + d.y * v * dt)
|
||||
self.particles[i].position = p
|
||||
}
|
||||
}
|
||||
|
||||
for i in removeIndices.reversed() {
|
||||
self.particles.remove(at: i)
|
||||
}
|
||||
|
||||
let newParticleCount = 1
|
||||
for _ in 0 ..< newParticleCount {
|
||||
let degrees: CGFloat = CGFloat(arc4random_uniform(140)) - 40.0
|
||||
let angle: CGFloat = degrees * CGFloat.pi / 180.0
|
||||
|
||||
let direction = CGPoint(x: v.x * cos(angle) - v.y * sin(angle), y: v.x * sin(angle) + v.y * cos(angle))
|
||||
let velocity = (20.0 + (CGFloat(arc4random()) / CGFloat(UINT32_MAX)) * 4.0) * 0.3
|
||||
|
||||
let lifetime = Double(0.4 + CGFloat(arc4random_uniform(100)) * 0.01)
|
||||
|
||||
let particle = ContentParticle(position: c, direction: direction, velocity: velocity, alpha: 1.0, lifetime: lifetime, beginTime: timestamp)
|
||||
self.particles.append(particle)
|
||||
}
|
||||
}
|
||||
|
||||
image = generateImage(CGSize(width: diameter + inset, height: diameter + inset), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setStrokeColor(color.cgColor)
|
||||
context.setFillColor(color.cgColor)
|
||||
context.setLineWidth(lineWidth)
|
||||
context.setLineCap(.round)
|
||||
|
||||
let path = CGMutablePath()
|
||||
path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||
context.addPath(path)
|
||||
context.strokePath()
|
||||
|
||||
if sparks {
|
||||
for particle in self.particles {
|
||||
let size: CGFloat = 2.0
|
||||
context.setAlpha(particle.alpha)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: particle.position.x - size / 2.0, y: particle.position.y - size / 2.0), size: CGSize(width: size, height: size)))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.contentNode.contents = image?.cgImage
|
||||
if let image = image {
|
||||
self.contentNode.frame = CGRect(origin: CGPoint(), size: image.size)
|
||||
}
|
||||
|
||||
if fraction <= .ulpOfOne {
|
||||
self.animator?.invalidate()
|
||||
self.animator = nil
|
||||
} else {
|
||||
if self.animator == nil {
|
||||
let animator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||
self?.updateValues()
|
||||
})
|
||||
self.animator = animator
|
||||
animator.isPaused = self.inHierarchyValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,267 +0,0 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import SyncCore
|
||||
import TelegramPresentationData
|
||||
import ItemListUI
|
||||
|
||||
public class ItemListInviteLinkGridItem: ListViewItem, ItemListItem {
|
||||
let presentationData: ItemListPresentationData
|
||||
let invites: [ExportedInvitation]?
|
||||
let count: Int
|
||||
let share: Bool
|
||||
public let sectionId: ItemListSectionId
|
||||
let style: ItemListStyle
|
||||
let tapAction: ((ExportedInvitation) -> Void)?
|
||||
let contextAction: ((ExportedInvitation, ASDisplayNode) -> Void)?
|
||||
public let tag: ItemListItemTag?
|
||||
|
||||
public init(
|
||||
presentationData: ItemListPresentationData,
|
||||
invites: [ExportedInvitation]?,
|
||||
count: Int,
|
||||
share: Bool,
|
||||
sectionId: ItemListSectionId,
|
||||
style: ItemListStyle,
|
||||
tapAction: ((ExportedInvitation) -> Void)?,
|
||||
contextAction: ((ExportedInvitation, ASDisplayNode) -> Void)?,
|
||||
tag: ItemListItemTag? = nil
|
||||
) {
|
||||
self.presentationData = presentationData
|
||||
self.invites = invites
|
||||
self.count = count
|
||||
self.share = share
|
||||
self.sectionId = sectionId
|
||||
self.style = style
|
||||
self.tapAction = tapAction
|
||||
self.contextAction = contextAction
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
async {
|
||||
let node = ItemListInviteLinkGridItemNode()
|
||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
|
||||
Queue.mainQueue().async {
|
||||
completion(node, {
|
||||
return (nil, { _ in apply() })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||
Queue.mainQueue().async {
|
||||
if let nodeValue = node() as? ItemListInviteLinkGridItemNode {
|
||||
let makeLayout = nodeValue.asyncLayout()
|
||||
|
||||
async {
|
||||
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
Queue.mainQueue().async {
|
||||
completion(layout, { _ in
|
||||
apply()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var selectable: Bool = false
|
||||
|
||||
public func selected(listView: ListView){
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let topStripeNode: ASDisplayNode
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let gridNode: InviteLinksGridNode
|
||||
|
||||
private var item: ItemListInviteLinkGridItem?
|
||||
|
||||
override public var canBeSelected: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public var tag: ItemListItemTag? {
|
||||
return self.item?.tag
|
||||
}
|
||||
|
||||
public init() {
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.backgroundColor = .white
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
|
||||
self.topStripeNode = ASDisplayNode()
|
||||
self.topStripeNode.isLayerBacked = true
|
||||
|
||||
self.bottomStripeNode = ASDisplayNode()
|
||||
self.bottomStripeNode.isLayerBacked = true
|
||||
|
||||
self.gridNode = InviteLinksGridNode()
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.addSubnode(self.gridNode)
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ item: ItemListInviteLinkGridItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
let currentItem = self.item
|
||||
|
||||
return { item, params, neighbors in
|
||||
var updatedTheme: PresentationTheme?
|
||||
if currentItem?.presentationData.theme !== item.presentationData.theme {
|
||||
updatedTheme = item.presentationData.theme
|
||||
}
|
||||
|
||||
let contentSize: CGSize
|
||||
let insets: UIEdgeInsets
|
||||
let separatorHeight = UIScreenPixel
|
||||
let itemBackgroundColor: UIColor
|
||||
let itemSeparatorColor: UIColor
|
||||
|
||||
let leftInset = 16.0 + params.leftInset
|
||||
let topInset: CGFloat
|
||||
if case .plain = item.style, case .otherSection = neighbors.top {
|
||||
topInset = 16.0
|
||||
} else if case .blocks = item.style, case .sameSection(true) = neighbors.top {
|
||||
topInset = 16.0
|
||||
} else {
|
||||
topInset = 4.0
|
||||
}
|
||||
|
||||
var height: CGFloat
|
||||
let count = item.invites?.count ?? item.count
|
||||
if count > 0 {
|
||||
if count % 2 == 0 {
|
||||
height = topInset + 122.0 + 6.0
|
||||
} else {
|
||||
height = topInset + 102.0 + 6.0
|
||||
}
|
||||
} else {
|
||||
height = 0.001
|
||||
}
|
||||
|
||||
switch item.style {
|
||||
case .plain:
|
||||
itemBackgroundColor = item.presentationData.theme.list.blocksBackgroundColor
|
||||
itemSeparatorColor = item.presentationData.theme.list.blocksBackgroundColor
|
||||
insets = UIEdgeInsets()
|
||||
case .blocks:
|
||||
itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
|
||||
itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor
|
||||
insets = itemListNeighborsGroupedInsets(neighbors)
|
||||
}
|
||||
if case .sameSection(false) = neighbors.bottom {
|
||||
} else {
|
||||
height += 10.0
|
||||
}
|
||||
contentSize = CGSize(width: params.width, height: height)
|
||||
|
||||
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = item
|
||||
|
||||
if let _ = updatedTheme {
|
||||
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
|
||||
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
|
||||
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||
}
|
||||
|
||||
let gridSize = strongSelf.gridNode.update(size: contentSize, safeInset: params.leftInset, items: item.invites, count: item.count, share: item.share, presentationData: item.presentationData, transition: .immediate)
|
||||
strongSelf.gridNode.frame = CGRect(origin: CGPoint(x: 0.0, y: topInset - 4.0), size: gridSize)
|
||||
strongSelf.gridNode.action = { invite in
|
||||
item.tapAction?(invite)
|
||||
}
|
||||
strongSelf.gridNode.contextAction = { node, invite in
|
||||
item.contextAction?(invite, node)
|
||||
}
|
||||
|
||||
switch item.style {
|
||||
case .plain:
|
||||
if strongSelf.backgroundNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||
}
|
||||
if strongSelf.topStripeNode.supernode != nil {
|
||||
strongSelf.topStripeNode.removeFromSupernode()
|
||||
}
|
||||
if strongSelf.bottomStripeNode.supernode != nil {
|
||||
strongSelf.bottomStripeNode.removeFromSupernode()
|
||||
}
|
||||
if strongSelf.maskNode.supernode != nil {
|
||||
strongSelf.maskNode.removeFromSupernode()
|
||||
}
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: params.width, height: contentSize.height))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||
case .blocks:
|
||||
if strongSelf.backgroundNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||
}
|
||||
if strongSelf.topStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||
}
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||
}
|
||||
if strongSelf.maskNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||
}
|
||||
|
||||
let hasCorners = itemListHasRoundedBlockLayout(params)
|
||||
var hasTopCorners = false
|
||||
var hasBottomCorners = false
|
||||
switch neighbors.top {
|
||||
case .sameSection(false):
|
||||
strongSelf.topStripeNode.isHidden = true
|
||||
default:
|
||||
hasTopCorners = true
|
||||
strongSelf.topStripeNode.isHidden = hasCorners
|
||||
}
|
||||
let bottomStripeInset: CGFloat
|
||||
switch neighbors.bottom {
|
||||
case .sameSection(false):
|
||||
bottomStripeInset = leftInset
|
||||
strongSelf.bottomStripeNode.isHidden = true
|
||||
default:
|
||||
bottomStripeInset = 0.0
|
||||
hasBottomCorners = true
|
||||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||
}
|
||||
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||
}
|
||||
|
||||
override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
|
@ -363,6 +363,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if let expireDate = invite.expireDate, currentTime >= expireDate {
|
||||
isExpired = true
|
||||
}
|
||||
var isFull = false
|
||||
|
||||
if let usageLimit = invite.usageLimit {
|
||||
if !isExpired {
|
||||
@ -376,6 +377,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
timerValue = .fraction(fraction)
|
||||
}
|
||||
} else if remaining == 0 {
|
||||
isFull = true
|
||||
if !subtitleText.isEmpty {
|
||||
subtitleText += " • "
|
||||
}
|
||||
@ -383,7 +385,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let expireDate = invite.expireDate {
|
||||
if let expireDate = invite.expireDate, !isFull {
|
||||
if !isExpired {
|
||||
if !subtitleText.isEmpty {
|
||||
subtitleText += " • "
|
||||
@ -570,7 +572,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
timerNode = TimerNode()
|
||||
timerNode.isUserInteractionEnabled = false
|
||||
strongSelf.timerNode = timerNode
|
||||
strongSelf.addSubnode(timerNode)
|
||||
strongSelf.offsetContainerNode.addSubnode(timerNode)
|
||||
}
|
||||
timerNode.update(color: iconColor, value: timerValue)
|
||||
} else if let timerNode = strongSelf.timerNode {
|
||||
@ -785,7 +787,7 @@ private final class TimerNode: ASDisplayNode {
|
||||
let startAngle: CGFloat = -CGFloat.pi / 2.0
|
||||
let endAngle: CGFloat = -CGFloat.pi / 2.0 + 2.0 * CGFloat.pi * fraction
|
||||
|
||||
let sparks = fraction > 0.1 && fraction != 1.0
|
||||
let sparks = fraction > 0.05 && fraction != 1.0
|
||||
if sparks {
|
||||
let v = CGPoint(x: sin(endAngle), y: -cos(endAngle))
|
||||
let c = CGPoint(x: -v.y * radius + center.x, y: v.x * radius + center.y)
|
||||
|
@ -287,25 +287,6 @@ private func ChannelMembersControllerEntries(context: AccountContext, presentati
|
||||
|
||||
var index: Int32 = 0
|
||||
let sortedParticipants = participants
|
||||
/*
|
||||
participants.sorted(by: { lhs, rhs in
|
||||
let lhsInvitedAt: Int32
|
||||
switch lhs.participant {
|
||||
case .creator:
|
||||
lhsInvitedAt = Int32.min
|
||||
case let .member(_, invitedAt, _, _):
|
||||
lhsInvitedAt = invitedAt
|
||||
}
|
||||
let rhsInvitedAt: Int32
|
||||
switch rhs.participant {
|
||||
case .creator:
|
||||
rhsInvitedAt = Int32.min
|
||||
case let .member(_, invitedAt, _, _):
|
||||
rhsInvitedAt = invitedAt
|
||||
}
|
||||
return lhsInvitedAt < rhsInvitedAt
|
||||
})
|
||||
*/
|
||||
for participant in sortedParticipants {
|
||||
var editable = true
|
||||
var canEditMembers = false
|
||||
|
@ -968,8 +968,17 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
|
||||
return nil
|
||||
} |> deliverOnMainQueue).start(next: { invite in
|
||||
if let invite = invite {
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite)
|
||||
presentControllerImpl?(controller, nil)
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let isGroup: Bool
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
isGroup = false
|
||||
} else {
|
||||
isGroup = true
|
||||
}
|
||||
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
|
||||
presentControllerImpl?(controller, nil)
|
||||
})
|
||||
}
|
||||
})
|
||||
})))
|
||||
|
@ -78,7 +78,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
if let reportReason = reportReason {
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason)
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
parent?.present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
@ -86,7 +86,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
completion(reportReason, true)
|
||||
})
|
||||
case let .messages(messageIds):
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason)
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
parent?.present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
@ -155,12 +155,16 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
break
|
||||
}
|
||||
if let reportReason = reportReason {
|
||||
var passthrough = passthrough
|
||||
if case .fake = reportReason {
|
||||
passthrough = false
|
||||
}
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
if passthrough {
|
||||
completion(reportReason, true)
|
||||
} else {
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason)
|
||||
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil)
|
||||
@ -172,7 +176,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
|
||||
if passthrough {
|
||||
completion(reportReason, true)
|
||||
} else {
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason)
|
||||
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: "")
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil)
|
||||
@ -326,7 +330,7 @@ private func peerReportController(context: AccountContext, subject: PeerReportSu
|
||||
}
|
||||
|
||||
if !text.isEmpty {
|
||||
let reportReason: ReportReason = .custom(text)
|
||||
let reportReason: ReportReason = .custom
|
||||
let completed: () -> Void = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.ReportPeer_AlertSuccess, actions: [TextAlertAction.init(type: TextAlertActionType.defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
@ -335,12 +339,12 @@ private func peerReportController(context: AccountContext, subject: PeerReportSu
|
||||
}
|
||||
switch subject {
|
||||
case let .peer(peerId):
|
||||
reportDisposable.set((reportPeer(account: context.account, peerId: peerId, reason: reportReason)
|
||||
reportDisposable.set((reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: text)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completed()
|
||||
}))
|
||||
case let .messages(messageIds):
|
||||
reportDisposable.set((reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason)
|
||||
reportDisposable.set((reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: text)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completed()
|
||||
}))
|
||||
|
@ -1017,7 +1017,7 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
|
||||
let _ = removePeerChat(account: context.account, peerId: peerId, reportChatSpam: reportSpam).start()
|
||||
popToRootImpl?()
|
||||
} else if reportSpam {
|
||||
let _ = reportPeer(account: context.account, peerId: peerId, reason: .spam).start()
|
||||
let _ = reportPeer(account: context.account, peerId: peerId, reason: .spam, message: "").start()
|
||||
}
|
||||
|
||||
deleteSendMessageIntents(peerId: peerId)
|
||||
|
@ -117,8 +117,14 @@ private class SectionHeaderItemNode: ListViewItemNode {
|
||||
strongSelf.headerNode = headerNode
|
||||
}
|
||||
headerNode.title = item.title
|
||||
switch item.additionalText {
|
||||
case .none, .generic:
|
||||
headerNode.actionType = .generic
|
||||
case .destructive:
|
||||
headerNode.actionType = .destructive
|
||||
|
||||
}
|
||||
headerNode.action = item.additionalText.text
|
||||
|
||||
headerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
|
||||
headerNode.updateLayout(size: contentSize, leftInset: params.leftInset, rightInset: params.rightInset)
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ public final class ShareInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegat
|
||||
private let clearButton: HighlightableButtonNode
|
||||
|
||||
public var updateHeight: (() -> Void)?
|
||||
public var updateText: ((String) -> Void)?
|
||||
|
||||
private let backgroundInsets = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 1.0, right: 16.0)
|
||||
private let inputInsets = UIEdgeInsets(top: 10.0, left: 8.0, bottom: 10.0, right: 16.0)
|
||||
@ -168,6 +169,7 @@ public final class ShareInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegat
|
||||
|
||||
@objc public func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
|
||||
self.updateTextNodeText(animated: true)
|
||||
self.updateText?(editableTextNode.attributedText?.string ?? "")
|
||||
}
|
||||
|
||||
public func editableTextNodeDidBeginEditing(_ editableTextNode: ASEditableTextNode) {
|
||||
|
@ -144,6 +144,7 @@ public struct TelegramChannelFlags: OptionSet {
|
||||
public static let hasVoiceChat = TelegramChannelFlags(rawValue: 1 << 4)
|
||||
public static let hasActiveVoiceChat = TelegramChannelFlags(rawValue: 1 << 5)
|
||||
public static let isFake = TelegramChannelFlags(rawValue: 1 << 6)
|
||||
public static let isGigagroup = TelegramChannelFlags(rawValue: 1 << 7)
|
||||
}
|
||||
|
||||
public final class TelegramChannel: Peer {
|
||||
|
@ -11,8 +11,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
||||
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
||||
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
||||
dict[-500874592] = { return Api.ChatFull.parse_chatFull($0) }
|
||||
dict[-66811386] = { return Api.ChatFull.parse_channelFull($0) }
|
||||
dict[-500874592] = { return Api.ChatFull.parse_chatFull($0) }
|
||||
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
||||
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
||||
dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
|
||||
@ -33,20 +33,20 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1216809369] = { return Api.PageBlock.parse_pageBlockFooter($0) }
|
||||
dict[-618614392] = { return Api.PageBlock.parse_pageBlockDivider($0) }
|
||||
dict[-837994576] = { return Api.PageBlock.parse_pageBlockAnchor($0) }
|
||||
dict[-454524911] = { return Api.PageBlock.parse_pageBlockList($0) }
|
||||
dict[641563686] = { return Api.PageBlock.parse_pageBlockBlockquote($0) }
|
||||
dict[1329878739] = { return Api.PageBlock.parse_pageBlockPullquote($0) }
|
||||
dict[972174080] = { return Api.PageBlock.parse_pageBlockCover($0) }
|
||||
dict[-283684427] = { return Api.PageBlock.parse_pageBlockChannel($0) }
|
||||
dict[504660880] = { return Api.PageBlock.parse_pageBlockKicker($0) }
|
||||
dict[-1085412734] = { return Api.PageBlock.parse_pageBlockTable($0) }
|
||||
dict[391759200] = { return Api.PageBlock.parse_pageBlockPhoto($0) }
|
||||
dict[2089805750] = { return Api.PageBlock.parse_pageBlockVideo($0) }
|
||||
dict[972174080] = { return Api.PageBlock.parse_pageBlockCover($0) }
|
||||
dict[-2143067670] = { return Api.PageBlock.parse_pageBlockAudio($0) }
|
||||
dict[-1468953147] = { return Api.PageBlock.parse_pageBlockEmbed($0) }
|
||||
dict[-229005301] = { return Api.PageBlock.parse_pageBlockEmbedPost($0) }
|
||||
dict[1705048653] = { return Api.PageBlock.parse_pageBlockCollage($0) }
|
||||
dict[52401552] = { return Api.PageBlock.parse_pageBlockSlideshow($0) }
|
||||
dict[-283684427] = { return Api.PageBlock.parse_pageBlockChannel($0) }
|
||||
dict[-2143067670] = { return Api.PageBlock.parse_pageBlockAudio($0) }
|
||||
dict[504660880] = { return Api.PageBlock.parse_pageBlockKicker($0) }
|
||||
dict[-1085412734] = { return Api.PageBlock.parse_pageBlockTable($0) }
|
||||
dict[-454524911] = { return Api.PageBlock.parse_pageBlockList($0) }
|
||||
dict[-1702174239] = { return Api.PageBlock.parse_pageBlockOrderedList($0) }
|
||||
dict[1987480557] = { return Api.PageBlock.parse_pageBlockDetails($0) }
|
||||
dict[370236054] = { return Api.PageBlock.parse_pageBlockRelatedArticles($0) }
|
||||
@ -66,10 +66,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[590459437] = { return Api.Photo.parse_photoEmpty($0) }
|
||||
dict[-82216347] = { return Api.Photo.parse_photo($0) }
|
||||
dict[-1683826688] = { return Api.Chat.parse_chatEmpty($0) }
|
||||
dict[1004149726] = { return Api.Chat.parse_chat($0) }
|
||||
dict[120753115] = { return Api.Chat.parse_chatForbidden($0) }
|
||||
dict[-753232354] = { return Api.Chat.parse_channel($0) }
|
||||
dict[681420594] = { return Api.Chat.parse_channelForbidden($0) }
|
||||
dict[1004149726] = { return Api.Chat.parse_chat($0) }
|
||||
dict[-753232354] = { return Api.Chat.parse_channel($0) }
|
||||
dict[1202287072] = { return Api.StatsURL.parse_statsURL($0) }
|
||||
dict[1516793212] = { return Api.ChatInvite.parse_chatInviteAlready($0) }
|
||||
dict[-540871282] = { return Api.ChatInvite.parse_chatInvite($0) }
|
||||
@ -113,11 +113,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[414687501] = { return Api.DcOption.parse_dcOption($0) }
|
||||
dict[997055186] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) }
|
||||
dict[-1705233435] = { return Api.account.PasswordSettings.parse_passwordSettings($0) }
|
||||
dict[-1945767479] = { return Api.help.SupportName.parse_supportName($0) }
|
||||
dict[-288727837] = { return Api.LangPackLanguage.parse_langPackLanguage($0) }
|
||||
dict[-399391402] = { return Api.VideoSize.parse_videoSize($0) }
|
||||
dict[497489295] = { return Api.help.AppUpdate.parse_appUpdate($0) }
|
||||
dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) }
|
||||
dict[497489295] = { return Api.help.AppUpdate.parse_appUpdate($0) }
|
||||
dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) }
|
||||
dict[-815649386] = { return Api.PeerHistoryTTL.parse_peerHistoryTTLPM($0) }
|
||||
dict[1041354473] = { return Api.PeerHistoryTTL.parse_peerHistoryTTL($0) }
|
||||
@ -142,12 +141,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1690108678] = { return Api.InputEncryptedFile.parse_inputEncryptedFileUploaded($0) }
|
||||
dict[1511503333] = { return Api.InputEncryptedFile.parse_inputEncryptedFile($0) }
|
||||
dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) }
|
||||
dict[1304052993] = { return Api.account.Takeout.parse_takeout($0) }
|
||||
dict[-1456996667] = { return Api.messages.InactiveChats.parse_inactiveChats($0) }
|
||||
dict[1690708501] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
|
||||
dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) }
|
||||
dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) }
|
||||
dict[289586518] = { return Api.SavedContact.parse_savedPhoneContact($0) }
|
||||
dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) }
|
||||
dict[-855308010] = { return Api.auth.Authorization.parse_authorization($0) }
|
||||
dict[1148485274] = { return Api.auth.Authorization.parse_authorizationSignUpRequired($0) }
|
||||
@ -211,14 +208,12 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-337352679] = { return Api.Update.parse_updateServiceNotification($0) }
|
||||
dict[-298113238] = { return Api.Update.parse_updatePrivacy($0) }
|
||||
dict[314130811] = { return Api.Update.parse_updateUserPhone($0) }
|
||||
dict[-1667805217] = { return Api.Update.parse_updateReadHistoryInbox($0) }
|
||||
dict[791617983] = { return Api.Update.parse_updateReadHistoryOutbox($0) }
|
||||
dict[2139689491] = { return Api.Update.parse_updateWebPage($0) }
|
||||
dict[1757493555] = { return Api.Update.parse_updateReadMessagesContents($0) }
|
||||
dict[-352032773] = { return Api.Update.parse_updateChannelTooLong($0) }
|
||||
dict[-1227598250] = { return Api.Update.parse_updateChannel($0) }
|
||||
dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($0) }
|
||||
dict[856380452] = { return Api.Update.parse_updateReadChannelInbox($0) }
|
||||
dict[-1015733815] = { return Api.Update.parse_updateDeleteChannelMessages($0) }
|
||||
dict[-1734268085] = { return Api.Update.parse_updateChannelMessageViews($0) }
|
||||
dict[-1232070311] = { return Api.Update.parse_updateChatParticipantAdmin($0) }
|
||||
@ -226,7 +221,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[196268545] = { return Api.Update.parse_updateStickerSetsOrder($0) }
|
||||
dict[1135492588] = { return Api.Update.parse_updateStickerSets($0) }
|
||||
dict[-1821035490] = { return Api.Update.parse_updateSavedGifs($0) }
|
||||
dict[1059076315] = { return Api.Update.parse_updateBotInlineQuery($0) }
|
||||
dict[239663460] = { return Api.Update.parse_updateBotInlineSend($0) }
|
||||
dict[457133559] = { return Api.Update.parse_updateEditChannelMessage($0) }
|
||||
dict[-415938591] = { return Api.Update.parse_updateBotCallbackQuery($0) }
|
||||
@ -239,23 +233,25 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1574314746] = { return Api.Update.parse_updateConfig($0) }
|
||||
dict[861169551] = { return Api.Update.parse_updatePtsChanged($0) }
|
||||
dict[1081547008] = { return Api.Update.parse_updateChannelWebPage($0) }
|
||||
dict[1852826908] = { return Api.Update.parse_updateDialogPinned($0) }
|
||||
dict[-99664734] = { return Api.Update.parse_updatePinnedDialogs($0) }
|
||||
dict[-2095595325] = { return Api.Update.parse_updateBotWebhookJSON($0) }
|
||||
dict[-1684914010] = { return Api.Update.parse_updateBotWebhookJSONQuery($0) }
|
||||
dict[-523384512] = { return Api.Update.parse_updateBotShippingQuery($0) }
|
||||
dict[1563376297] = { return Api.Update.parse_updateBotPrecheckoutQuery($0) }
|
||||
dict[-1425052898] = { return Api.Update.parse_updatePhoneCall($0) }
|
||||
dict[1180041828] = { return Api.Update.parse_updateLangPackTooLong($0) }
|
||||
dict[1442983757] = { return Api.Update.parse_updateLangPack($0) }
|
||||
dict[-451831443] = { return Api.Update.parse_updateFavedStickers($0) }
|
||||
dict[-1987495099] = { return Api.Update.parse_updateChannelReadMessagesContents($0) }
|
||||
dict[1887741886] = { return Api.Update.parse_updateContactsReset($0) }
|
||||
dict[1893427255] = { return Api.Update.parse_updateChannelAvailableMessages($0) }
|
||||
dict[-513517117] = { return Api.Update.parse_updateDialogUnreadMark($0) }
|
||||
dict[1180041828] = { return Api.Update.parse_updateLangPackTooLong($0) }
|
||||
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
|
||||
dict[1421875280] = { return Api.Update.parse_updateChatDefaultBannedRights($0) }
|
||||
dict[422972864] = { return Api.Update.parse_updateFolderPeers($0) }
|
||||
dict[1852826908] = { return Api.Update.parse_updateDialogPinned($0) }
|
||||
dict[-99664734] = { return Api.Update.parse_updatePinnedDialogs($0) }
|
||||
dict[856380452] = { return Api.Update.parse_updateReadChannelInbox($0) }
|
||||
dict[-1667805217] = { return Api.Update.parse_updateReadHistoryInbox($0) }
|
||||
dict[1786671974] = { return Api.Update.parse_updatePeerSettings($0) }
|
||||
dict[-1263546448] = { return Api.Update.parse_updatePeerLocated($0) }
|
||||
dict[967122427] = { return Api.Update.parse_updateNewScheduledMessage($0) }
|
||||
@ -279,15 +275,16 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[321954198] = { return Api.Update.parse_updateChat($0) }
|
||||
dict[-219423922] = { return Api.Update.parse_updateGroupCallParticipants($0) }
|
||||
dict[-1537295973] = { return Api.Update.parse_updateGroupCall($0) }
|
||||
dict[1059076315] = { return Api.Update.parse_updateBotInlineQuery($0) }
|
||||
dict[19291112] = { return Api.Update.parse_updatePeerHistoryTTL($0) }
|
||||
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
|
||||
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
|
||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
||||
dict[367766557] = { return Api.ChannelParticipant.parse_channelParticipant($0) }
|
||||
dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) }
|
||||
dict[1149094475] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) }
|
||||
dict[-859915345] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) }
|
||||
dict[470789295] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) }
|
||||
dict[-859915345] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) }
|
||||
dict[1149094475] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) }
|
||||
dict[-1010402965] = { return Api.ChannelParticipant.parse_channelParticipantLeft($0) }
|
||||
dict[-1567730343] = { return Api.MessageUserVote.parse_messageUserVote($0) }
|
||||
dict[909603888] = { return Api.MessageUserVote.parse_messageUserVoteInputOption($0) }
|
||||
@ -296,9 +293,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-513392236] = { return Api.contacts.Blocked.parse_blockedSlice($0) }
|
||||
dict[-55902537] = { return Api.InputDialogPeer.parse_inputDialogPeer($0) }
|
||||
dict[1684014375] = { return Api.InputDialogPeer.parse_inputDialogPeerFolder($0) }
|
||||
dict[-994444869] = { return Api.Error.parse_error($0) }
|
||||
dict[-1560655744] = { return Api.KeyboardButton.parse_keyboardButton($0) }
|
||||
dict[629866245] = { return Api.KeyboardButton.parse_keyboardButtonUrl($0) }
|
||||
dict[901503851] = { return Api.KeyboardButton.parse_keyboardButtonCallback($0) }
|
||||
dict[-1318425559] = { return Api.KeyboardButton.parse_keyboardButtonRequestPhone($0) }
|
||||
dict[-59151553] = { return Api.KeyboardButton.parse_keyboardButtonRequestGeoLocation($0) }
|
||||
dict[90744648] = { return Api.KeyboardButton.parse_keyboardButtonSwitchInline($0) }
|
||||
@ -307,6 +304,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[280464681] = { return Api.KeyboardButton.parse_keyboardButtonUrlAuth($0) }
|
||||
dict[-802258988] = { return Api.KeyboardButton.parse_inputKeyboardButtonUrlAuth($0) }
|
||||
dict[-1144565411] = { return Api.KeyboardButton.parse_keyboardButtonRequestPoll($0) }
|
||||
dict[901503851] = { return Api.KeyboardButton.parse_keyboardButtonCallback($0) }
|
||||
dict[-748155807] = { return Api.ContactStatus.parse_contactStatus($0) }
|
||||
dict[1679398724] = { return Api.SecureFile.parse_secureFileEmpty($0) }
|
||||
dict[-534283678] = { return Api.SecureFile.parse_secureFile($0) }
|
||||
@ -328,32 +326,33 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1881892265] = { return Api.account.WallPapers.parse_wallPapers($0) }
|
||||
dict[1012306921] = { return Api.InputTheme.parse_inputTheme($0) }
|
||||
dict[-175567375] = { return Api.InputTheme.parse_inputThemeSlug($0) }
|
||||
dict[1158290442] = { return Api.messages.FoundGifs.parse_foundGifs($0) }
|
||||
dict[-1132476723] = { return Api.FileLocation.parse_fileLocationToBeDeprecated($0) }
|
||||
dict[-2032041631] = { return Api.Poll.parse_poll($0) }
|
||||
dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) }
|
||||
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
|
||||
dict[1251338318] = { return Api.InputNotifyPeer.parse_inputNotifyChats($0) }
|
||||
dict[-1311015810] = { return Api.InputNotifyPeer.parse_inputNotifyBroadcasts($0) }
|
||||
dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) }
|
||||
dict[-317144808] = { return Api.EncryptedMessage.parse_encryptedMessage($0) }
|
||||
dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) }
|
||||
dict[-566281095] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsRecent($0) }
|
||||
dict[-1268741783] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsAdmins($0) }
|
||||
dict[-1548400251] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsKicked($0) }
|
||||
dict[-1328445861] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBots($0) }
|
||||
dict[338142689] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBanned($0) }
|
||||
dict[106343499] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsSearch($0) }
|
||||
dict[-1548400251] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsKicked($0) }
|
||||
dict[-1150621555] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsContacts($0) }
|
||||
dict[-531931925] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsMentions($0) }
|
||||
dict[-350980120] = { return Api.WebPage.parse_webPageEmpty($0) }
|
||||
dict[-981018084] = { return Api.WebPage.parse_webPagePending($0) }
|
||||
dict[-392411726] = { return Api.WebPage.parse_webPage($0) }
|
||||
dict[1930545681] = { return Api.WebPage.parse_webPageNotModified($0) }
|
||||
dict[864077702] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaAuto($0) }
|
||||
dict[1036876423] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageText($0) }
|
||||
dict[-1768777083] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
||||
dict[1262639204] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageGame($0) }
|
||||
dict[864077702] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaAuto($0) }
|
||||
dict[1098628881] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaVenue($0) }
|
||||
dict[-1494368259] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaContact($0) }
|
||||
dict[1262639204] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageGame($0) }
|
||||
dict[-1768777083] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
||||
dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) }
|
||||
dict[1088567208] = { return Api.StickerSet.parse_stickerSet($0) }
|
||||
dict[-1111085620] = { return Api.messages.ExportedChatInvites.parse_exportedChatInvites($0) }
|
||||
@ -382,20 +381,21 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[2131196633] = { return Api.contacts.ResolvedPeer.parse_resolvedPeer($0) }
|
||||
dict[-1964327229] = { return Api.SecureData.parse_secureData($0) }
|
||||
dict[-1771768449] = { return Api.InputMedia.parse_inputMediaEmpty($0) }
|
||||
dict[505969924] = { return Api.InputMedia.parse_inputMediaUploadedPhoto($0) }
|
||||
dict[-1279654347] = { return Api.InputMedia.parse_inputMediaPhoto($0) }
|
||||
dict[-104578748] = { return Api.InputMedia.parse_inputMediaGeoPoint($0) }
|
||||
dict[-122978821] = { return Api.InputMedia.parse_inputMediaContact($0) }
|
||||
dict[1530447553] = { return Api.InputMedia.parse_inputMediaUploadedDocument($0) }
|
||||
dict[860303448] = { return Api.InputMedia.parse_inputMediaDocument($0) }
|
||||
dict[1212395773] = { return Api.InputMedia.parse_inputMediaGifExternal($0) }
|
||||
dict[-750828557] = { return Api.InputMedia.parse_inputMediaGame($0) }
|
||||
dict[-1052959727] = { return Api.InputMedia.parse_inputMediaVenue($0) }
|
||||
dict[-186607933] = { return Api.InputMedia.parse_inputMediaInvoice($0) }
|
||||
dict[505969924] = { return Api.InputMedia.parse_inputMediaUploadedPhoto($0) }
|
||||
dict[1530447553] = { return Api.InputMedia.parse_inputMediaUploadedDocument($0) }
|
||||
dict[-1279654347] = { return Api.InputMedia.parse_inputMediaPhoto($0) }
|
||||
dict[-440664550] = { return Api.InputMedia.parse_inputMediaPhotoExternal($0) }
|
||||
dict[-78455655] = { return Api.InputMedia.parse_inputMediaDocumentExternal($0) }
|
||||
dict[-750828557] = { return Api.InputMedia.parse_inputMediaGame($0) }
|
||||
dict[-186607933] = { return Api.InputMedia.parse_inputMediaInvoice($0) }
|
||||
dict[-1759532989] = { return Api.InputMedia.parse_inputMediaGeoLive($0) }
|
||||
dict[-122978821] = { return Api.InputMedia.parse_inputMediaContact($0) }
|
||||
dict[261416433] = { return Api.InputMedia.parse_inputMediaPoll($0) }
|
||||
dict[-428884101] = { return Api.InputMedia.parse_inputMediaDice($0) }
|
||||
dict[-1759532989] = { return Api.InputMedia.parse_inputMediaGeoLive($0) }
|
||||
dict[860303448] = { return Api.InputMedia.parse_inputMediaDocument($0) }
|
||||
dict[2134579434] = { return Api.InputPeer.parse_inputPeerEmpty($0) }
|
||||
dict[2107670217] = { return Api.InputPeer.parse_inputPeerSelf($0) }
|
||||
dict[396093539] = { return Api.InputPeer.parse_inputPeerChat($0) }
|
||||
@ -408,8 +408,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1078332329] = { return Api.help.PassportConfig.parse_passportConfigNotModified($0) }
|
||||
dict[-1600596305] = { return Api.help.PassportConfig.parse_passportConfig($0) }
|
||||
dict[1648543603] = { return Api.FileHash.parse_fileHash($0) }
|
||||
dict[295067450] = { return Api.BotInlineResult.parse_botInlineResult($0) }
|
||||
dict[400266251] = { return Api.BotInlineResult.parse_botInlineMediaResult($0) }
|
||||
dict[295067450] = { return Api.BotInlineResult.parse_botInlineResult($0) }
|
||||
dict[911761060] = { return Api.messages.BotCallbackAnswer.parse_botCallbackAnswer($0) }
|
||||
dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) }
|
||||
dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) }
|
||||
@ -432,7 +432,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-421545947] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeTitle($0) }
|
||||
dict[1427671598] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeAbout($0) }
|
||||
dict[1783299128] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeUsername($0) }
|
||||
dict[1129042607] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangePhoto($0) }
|
||||
dict[460916654] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionToggleInvites($0) }
|
||||
dict[648939889] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionToggleSignatures($0) }
|
||||
dict[-370660328] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionUpdatePinned($0) }
|
||||
@ -447,6 +446,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1599903217] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionTogglePreHistoryHidden($0) }
|
||||
dict[771095562] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionDefaultBannedRights($0) }
|
||||
dict[-1895328189] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionStopPoll($0) }
|
||||
dict[1129042607] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangePhoto($0) }
|
||||
dict[-1569748965] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeLinkedChat($0) }
|
||||
dict[241923758] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeLocation($0) }
|
||||
dict[1401984889] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionToggleSlowMode($0) }
|
||||
@ -455,10 +455,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-115071790] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantMute($0) }
|
||||
dict[-431740480] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantUnmute($0) }
|
||||
dict[1456906823] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionToggleGroupCallSetting($0) }
|
||||
dict[1557846647] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantJoinByInvite($0) }
|
||||
dict[1515256996] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionExportedInviteDelete($0) }
|
||||
dict[1091179342] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionExportedInviteRevoke($0) }
|
||||
dict[-384910503] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionExportedInviteEdit($0) }
|
||||
dict[1557846647] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantJoinByInvite($0) }
|
||||
dict[1048537159] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantVolume($0) }
|
||||
dict[1855199800] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeHistoryTTL($0) }
|
||||
dict[-543777747] = { return Api.auth.ExportedAuthorization.parse_exportedAuthorization($0) }
|
||||
@ -471,7 +471,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) }
|
||||
dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) }
|
||||
dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) }
|
||||
dict[1968737087] = { return Api.InputClientProxy.parse_inputClientProxy($0) }
|
||||
dict[649453030] = { return Api.messages.MessageEditData.parse_messageEditData($0) }
|
||||
dict[-886477832] = { return Api.LabeledPrice.parse_labeledPrice($0) }
|
||||
dict[-438840932] = { return Api.messages.ChatFull.parse_chatFull($0) }
|
||||
@ -485,15 +484,15 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1490799288] = { return Api.ReportReason.parse_inputReportReasonSpam($0) }
|
||||
dict[505595789] = { return Api.ReportReason.parse_inputReportReasonViolence($0) }
|
||||
dict[777640226] = { return Api.ReportReason.parse_inputReportReasonPornography($0) }
|
||||
dict[-1376497949] = { return Api.ReportReason.parse_inputReportReasonChildAbuse($0) }
|
||||
dict[-1041980751] = { return Api.ReportReason.parse_inputReportReasonOther($0) }
|
||||
dict[-1685456582] = { return Api.ReportReason.parse_inputReportReasonCopyright($0) }
|
||||
dict[-1376497949] = { return Api.ReportReason.parse_inputReportReasonChildAbuse($0) }
|
||||
dict[-606798099] = { return Api.ReportReason.parse_inputReportReasonGeoIrrelevant($0) }
|
||||
dict[-170010905] = { return Api.ReportReason.parse_inputReportReasonFake($0) }
|
||||
dict[-1041980751] = { return Api.ReportReason.parse_inputReportReasonOther($0) }
|
||||
dict[-247351839] = { return Api.InputEncryptedChat.parse_inputEncryptedChat($0) }
|
||||
dict[-524237339] = { return Api.PageTableRow.parse_pageTableRow($0) }
|
||||
dict[453805082] = { return Api.DraftMessage.parse_draftMessageEmpty($0) }
|
||||
dict[-40996577] = { return Api.DraftMessage.parse_draftMessage($0) }
|
||||
dict[453805082] = { return Api.DraftMessage.parse_draftMessageEmpty($0) }
|
||||
dict[-1014526429] = { return Api.help.Country.parse_country($0) }
|
||||
dict[418631927] = { return Api.StatsGroupTopPoster.parse_statsGroupTopPoster($0) }
|
||||
dict[-2128640689] = { return Api.account.SentEmailCode.parse_sentEmailCode($0) }
|
||||
@ -509,13 +508,13 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-2036501105] = { return Api.SecureValueError.parse_secureValueError($0) }
|
||||
dict[-1592506512] = { return Api.SecureValueError.parse_secureValueErrorTranslationFile($0) }
|
||||
dict[878931416] = { return Api.SecureValueError.parse_secureValueErrorTranslationFiles($0) }
|
||||
dict[-6249322] = { return Api.InputStickerSetItem.parse_inputStickerSetItem($0) }
|
||||
dict[-1728664459] = { return Api.help.PromoData.parse_promoDataEmpty($0) }
|
||||
dict[-1942390465] = { return Api.help.PromoData.parse_promoData($0) }
|
||||
dict[-1613493288] = { return Api.NotifyPeer.parse_notifyPeer($0) }
|
||||
dict[-1261946036] = { return Api.NotifyPeer.parse_notifyUsers($0) }
|
||||
dict[-1073230141] = { return Api.NotifyPeer.parse_notifyChats($0) }
|
||||
dict[-703403793] = { return Api.NotifyPeer.parse_notifyBroadcasts($0) }
|
||||
dict[-582464156] = { return Api.wallet.KeySecretSalt.parse_secretSalt($0) }
|
||||
dict[1335282456] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyStatusTimestamp($0) }
|
||||
dict[-1107622874] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyChatInvite($0) }
|
||||
dict[-88417185] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyPhoneCall($0) }
|
||||
@ -537,13 +536,13 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-316748368] = { return Api.SecureValueHash.parse_secureValueHash($0) }
|
||||
dict[1722485756] = { return Api.phone.GroupCall.parse_groupCall($0) }
|
||||
dict[-398136321] = { return Api.messages.SearchCounter.parse_searchCounter($0) }
|
||||
dict[-2128698738] = { return Api.auth.CheckedPhone.parse_checkedPhone($0) }
|
||||
dict[-1188055347] = { return Api.PageListItem.parse_pageListItemText($0) }
|
||||
dict[635466748] = { return Api.PageListItem.parse_pageListItemBlocks($0) }
|
||||
dict[-386039788] = { return Api.PeerBlocked.parse_peerBlocked($0) }
|
||||
dict[-1182234929] = { return Api.InputUser.parse_inputUserEmpty($0) }
|
||||
dict[-138301121] = { return Api.InputUser.parse_inputUserSelf($0) }
|
||||
dict[-668391402] = { return Api.InputUser.parse_inputUser($0) }
|
||||
dict[756118935] = { return Api.InputUser.parse_inputUserFromMessage($0) }
|
||||
dict[-1738178803] = { return Api.Page.parse_page($0) }
|
||||
dict[871426631] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) }
|
||||
dict[-875679776] = { return Api.StatsPercentValue.parse_statsPercentValue($0) }
|
||||
@ -576,50 +575,51 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1502174430] = { return Api.InputMessage.parse_inputMessageID($0) }
|
||||
dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) }
|
||||
dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) }
|
||||
dict[-1392895362] = { return Api.InputMessage.parse_inputMessageCallbackQuery($0) }
|
||||
dict[-58224696] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) }
|
||||
dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) }
|
||||
dict[-275956116] = { return Api.messages.AffectedFoundMessages.parse_affectedFoundMessages($0) }
|
||||
dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) }
|
||||
dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) }
|
||||
dict[-1963717851] = { return Api.WallPaper.parse_wallPaperNoFile($0) }
|
||||
dict[-1938715001] = { return Api.messages.Messages.parse_messages($0) }
|
||||
dict[978610270] = { return Api.messages.Messages.parse_messagesSlice($0) }
|
||||
dict[1682413576] = { return Api.messages.Messages.parse_channelMessages($0) }
|
||||
dict[1951620897] = { return Api.messages.Messages.parse_messagesNotModified($0) }
|
||||
dict[1682413576] = { return Api.messages.Messages.parse_channelMessages($0) }
|
||||
dict[978610270] = { return Api.messages.Messages.parse_messagesSlice($0) }
|
||||
dict[-1022713000] = { return Api.Invoice.parse_invoice($0) }
|
||||
dict[1933519201] = { return Api.PeerSettings.parse_peerSettings($0) }
|
||||
dict[1577067778] = { return Api.auth.SentCode.parse_sentCode($0) }
|
||||
dict[480546647] = { return Api.InputChatPhoto.parse_inputChatPhotoEmpty($0) }
|
||||
dict[-968723890] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) }
|
||||
dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) }
|
||||
dict[-968723890] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) }
|
||||
dict[-1228606141] = { return Api.messages.MessageViews.parse_messageViews($0) }
|
||||
dict[375566091] = { return Api.messages.HistoryImport.parse_historyImport($0) }
|
||||
dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($0) }
|
||||
dict[-1387279939] = { return Api.MessageInteractionCounters.parse_messageInteractionCounters($0) }
|
||||
dict[-1107852396] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) }
|
||||
dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) }
|
||||
dict[-84936653] = { return Api.Updates.parse_updateShortMessage($0) }
|
||||
dict[290961496] = { return Api.Updates.parse_updateShortChatMessage($0) }
|
||||
dict[2027216577] = { return Api.Updates.parse_updateShort($0) }
|
||||
dict[1918567619] = { return Api.Updates.parse_updatesCombined($0) }
|
||||
dict[1957577280] = { return Api.Updates.parse_updates($0) }
|
||||
dict[-84936653] = { return Api.Updates.parse_updateShortMessage($0) }
|
||||
dict[290961496] = { return Api.Updates.parse_updateShortChatMessage($0) }
|
||||
dict[-1877614335] = { return Api.Updates.parse_updateShortSentMessage($0) }
|
||||
dict[-276825834] = { return Api.stats.MegagroupStats.parse_megagroupStats($0) }
|
||||
dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) }
|
||||
dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) }
|
||||
dict[1766936791] = { return Api.MessageMedia.parse_messageMediaPhoto($0) }
|
||||
dict[1457575028] = { return Api.MessageMedia.parse_messageMediaGeo($0) }
|
||||
dict[-873313984] = { return Api.MessageMedia.parse_messageMediaContact($0) }
|
||||
dict[-1618676578] = { return Api.MessageMedia.parse_messageMediaUnsupported($0) }
|
||||
dict[-1666158377] = { return Api.MessageMedia.parse_messageMediaDocument($0) }
|
||||
dict[-1557277184] = { return Api.MessageMedia.parse_messageMediaWebPage($0) }
|
||||
dict[784356159] = { return Api.MessageMedia.parse_messageMediaVenue($0) }
|
||||
dict[-38694904] = { return Api.MessageMedia.parse_messageMediaGame($0) }
|
||||
dict[-2074799289] = { return Api.MessageMedia.parse_messageMediaInvoice($0) }
|
||||
dict[-1186937242] = { return Api.MessageMedia.parse_messageMediaGeoLive($0) }
|
||||
dict[784356159] = { return Api.MessageMedia.parse_messageMediaVenue($0) }
|
||||
dict[1766936791] = { return Api.MessageMedia.parse_messageMediaPhoto($0) }
|
||||
dict[-1666158377] = { return Api.MessageMedia.parse_messageMediaDocument($0) }
|
||||
dict[-873313984] = { return Api.MessageMedia.parse_messageMediaContact($0) }
|
||||
dict[1272375192] = { return Api.MessageMedia.parse_messageMediaPoll($0) }
|
||||
dict[1065280907] = { return Api.MessageMedia.parse_messageMediaDice($0) }
|
||||
dict[-1186937242] = { return Api.MessageMedia.parse_messageMediaGeoLive($0) }
|
||||
dict[-842892769] = { return Api.PaymentSavedCredentials.parse_paymentSavedCredentialsCard($0) }
|
||||
dict[1450380236] = { return Api.Null.parse_null($0) }
|
||||
dict[1923290508] = { return Api.auth.CodeType.parse_codeTypeSms($0) }
|
||||
dict[1948046307] = { return Api.auth.CodeType.parse_codeTypeCall($0) }
|
||||
dict[577556219] = { return Api.auth.CodeType.parse_codeTypeFlashCall($0) }
|
||||
@ -649,21 +649,21 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1231326505] = { return Api.messages.ChatAdminsWithInvites.parse_chatAdminsWithInvites($0) }
|
||||
dict[-1729618630] = { return Api.BotInfo.parse_botInfo($0) }
|
||||
dict[-1519637954] = { return Api.updates.State.parse_state($0) }
|
||||
dict[372165663] = { return Api.FoundGif.parse_foundGif($0) }
|
||||
dict[-1670052855] = { return Api.FoundGif.parse_foundGifCached($0) }
|
||||
dict[537022650] = { return Api.User.parse_userEmpty($0) }
|
||||
dict[-1820043071] = { return Api.User.parse_user($0) }
|
||||
dict[678405636] = { return Api.Message.parse_messageService($0) }
|
||||
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
|
||||
dict[-1125940270] = { return Api.Message.parse_message($0) }
|
||||
dict[678405636] = { return Api.Message.parse_messageService($0) }
|
||||
dict[831924812] = { return Api.StatsGroupTopInviter.parse_statsGroupTopInviter($0) }
|
||||
dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) }
|
||||
dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) }
|
||||
dict[-539317279] = { return Api.InputFileLocation.parse_inputFileLocation($0) }
|
||||
dict[-182231723] = { return Api.InputFileLocation.parse_inputEncryptedFileLocation($0) }
|
||||
dict[-1160743548] = { return Api.InputFileLocation.parse_inputDocumentFileLocation($0) }
|
||||
dict[-876089816] = { return Api.InputFileLocation.parse_inputSecureFileLocation($0) }
|
||||
dict[700340377] = { return Api.InputFileLocation.parse_inputTakeoutFileLocation($0) }
|
||||
dict[-539317279] = { return Api.InputFileLocation.parse_inputFileLocation($0) }
|
||||
dict[1075322878] = { return Api.InputFileLocation.parse_inputPhotoFileLocation($0) }
|
||||
dict[-667654413] = { return Api.InputFileLocation.parse_inputPhotoLegacyFileLocation($0) }
|
||||
dict[-1160743548] = { return Api.InputFileLocation.parse_inputDocumentFileLocation($0) }
|
||||
dict[668375447] = { return Api.InputFileLocation.parse_inputPeerPhotoFileLocation($0) }
|
||||
dict[230353641] = { return Api.InputFileLocation.parse_inputStickerSetThumb($0) }
|
||||
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
|
||||
@ -710,8 +710,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1816636575] = { return Api.LangPackString.parse_langPackStringPluralized($0) }
|
||||
dict[695856818] = { return Api.LangPackString.parse_langPackStringDeleted($0) }
|
||||
dict[-1036396922] = { return Api.InputWebFileLocation.parse_inputWebFileLocation($0) }
|
||||
dict[1430205163] = { return Api.InputWebFileLocation.parse_inputWebFileGeoMessageLocation($0) }
|
||||
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[-1012849566] = { return Api.BaseTheme.parse_baseThemeClassic($0) }
|
||||
dict[-69724536] = { return Api.BaseTheme.parse_baseThemeDay($0) }
|
||||
@ -723,6 +723,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1777752804] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotos($0) }
|
||||
dict[-1614803355] = { return Api.MessagesFilter.parse_inputMessagesFilterVideo($0) }
|
||||
dict[1458172132] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotoVideo($0) }
|
||||
dict[-648121413] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotoVideoDocuments($0) }
|
||||
dict[-1629621880] = { return Api.MessagesFilter.parse_inputMessagesFilterDocument($0) }
|
||||
dict[2129714567] = { return Api.MessagesFilter.parse_inputMessagesFilterUrl($0) }
|
||||
dict[-3644025] = { return Api.MessagesFilter.parse_inputMessagesFilterGif($0) }
|
||||
@ -733,6 +734,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[2054952868] = { return Api.MessagesFilter.parse_inputMessagesFilterRoundVoice($0) }
|
||||
dict[-1253451181] = { return Api.MessagesFilter.parse_inputMessagesFilterRoundVideo($0) }
|
||||
dict[-1040652646] = { return Api.MessagesFilter.parse_inputMessagesFilterMyMentions($0) }
|
||||
dict[1187706024] = { return Api.MessagesFilter.parse_inputMessagesFilterMyMentionsUnread($0) }
|
||||
dict[-419271411] = { return Api.MessagesFilter.parse_inputMessagesFilterGeo($0) }
|
||||
dict[-530392189] = { return Api.MessagesFilter.parse_inputMessagesFilterContacts($0) }
|
||||
dict[464520273] = { return Api.MessagesFilter.parse_inputMessagesFilterPinned($0) }
|
||||
@ -744,12 +746,13 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[594408994] = { return Api.EmojiKeyword.parse_emojiKeywordDeleted($0) }
|
||||
dict[-290921362] = { return Api.upload.CdnFile.parse_cdnFileReuploadNeeded($0) }
|
||||
dict[-1449145777] = { return Api.upload.CdnFile.parse_cdnFile($0) }
|
||||
dict[1984136919] = { return Api.wallet.LiteResponse.parse_liteResponse($0) }
|
||||
dict[415997816] = { return Api.help.InviteText.parse_inviteText($0) }
|
||||
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
|
||||
dict[-1937807902] = { return Api.BotInlineMessage.parse_botInlineMessageText($0) }
|
||||
dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
|
||||
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
|
||||
dict[-1970903652] = { return Api.BotInlineMessage.parse_botInlineMessageMediaVenue($0) }
|
||||
dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) }
|
||||
dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
|
||||
dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) }
|
||||
dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) }
|
||||
dict[-209768682] = { return Api.messages.FavedStickers.parse_favedStickers($0) }
|
||||
@ -780,10 +783,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-732254058] = { return Api.PasswordKdfAlgo.parse_passwordKdfAlgoUnknown($0) }
|
||||
dict[982592842] = { return Api.PasswordKdfAlgo.parse_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow($0) }
|
||||
dict[-1390001672] = { return Api.account.Password.parse_password($0) }
|
||||
dict[-2000710887] = { return Api.InputBotInlineResult.parse_inputBotInlineResult($0) }
|
||||
dict[-1462213465] = { return Api.InputBotInlineResult.parse_inputBotInlineResultPhoto($0) }
|
||||
dict[-459324] = { return Api.InputBotInlineResult.parse_inputBotInlineResultDocument($0) }
|
||||
dict[1336154098] = { return Api.InputBotInlineResult.parse_inputBotInlineResultGame($0) }
|
||||
dict[-2000710887] = { return Api.InputBotInlineResult.parse_inputBotInlineResult($0) }
|
||||
dict[1352683077] = { return Api.account.PrivacyRules.parse_privacyRules($0) }
|
||||
dict[-123988] = { return Api.PrivacyRule.parse_privacyValueAllowContacts($0) }
|
||||
dict[1698855810] = { return Api.PrivacyRule.parse_privacyValueAllowAll($0) }
|
||||
@ -830,8 +833,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1674235686] = { return Api.account.AutoDownloadSettings.parse_autoDownloadSettings($0) }
|
||||
dict[-445792507] = { return Api.DialogPeer.parse_dialogPeer($0) }
|
||||
dict[1363483106] = { return Api.DialogPeer.parse_dialogPeerFolder($0) }
|
||||
dict[475467473] = { return Api.WebDocument.parse_webDocument($0) }
|
||||
dict[-104284986] = { return Api.WebDocument.parse_webDocumentNoProxy($0) }
|
||||
dict[475467473] = { return Api.WebDocument.parse_webDocument($0) }
|
||||
dict[42930452] = { return Api.Theme.parse_theme($0) }
|
||||
dict[-1290580579] = { return Api.contacts.Found.parse_found($0) }
|
||||
dict[-368018716] = { return Api.ChannelAdminLogEventsFilter.parse_channelAdminLogEventsFilter($0) }
|
||||
@ -844,8 +847,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1775479590] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) }
|
||||
dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) }
|
||||
dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) }
|
||||
dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($0) }
|
||||
dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) }
|
||||
dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($0) }
|
||||
dict[-1815339214] = { return Api.help.CountriesList.parse_countriesListNotModified($0) }
|
||||
dict[-2016381538] = { return Api.help.CountriesList.parse_countriesList($0) }
|
||||
dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) }
|
||||
@ -883,8 +886,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1730311882] = { return Api.PageListOrderedItem.parse_pageListOrderedItemBlocks($0) }
|
||||
dict[-1417756512] = { return Api.EncryptedChat.parse_encryptedChatEmpty($0) }
|
||||
dict[1006044124] = { return Api.EncryptedChat.parse_encryptedChatWaiting($0) }
|
||||
dict[1651608194] = { return Api.EncryptedChat.parse_encryptedChatRequested($0) }
|
||||
dict[-94974410] = { return Api.EncryptedChat.parse_encryptedChat($0) }
|
||||
dict[1651608194] = { return Api.EncryptedChat.parse_encryptedChatRequested($0) }
|
||||
dict[505183301] = { return Api.EncryptedChat.parse_encryptedChatDiscarded($0) }
|
||||
dict[-901375139] = { return Api.PeerLocated.parse_peerLocated($0) }
|
||||
dict[-118740917] = { return Api.PeerLocated.parse_peerSelfLocated($0) }
|
||||
@ -1013,8 +1016,6 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.account.PasswordSettings:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.SupportName:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.LangPackLanguage:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.VideoSize:
|
||||
@ -1041,16 +1042,12 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputEncryptedFile:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.account.Takeout:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.InactiveChats:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.GroupCallParticipant:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.SentEncryptedMessage:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.SavedContact:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.ExportedMessageLink:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.auth.Authorization:
|
||||
@ -1089,6 +1086,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputDialogPeer:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.Error:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.KeyboardButton:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.ContactStatus:
|
||||
@ -1111,6 +1110,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputTheme:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.FoundGifs:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.FileLocation:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.Poll:
|
||||
@ -1207,8 +1208,6 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.ChatBannedRights:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputClientProxy:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.MessageEditData:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.LabeledPrice:
|
||||
@ -1247,12 +1246,12 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.SecureValueError:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputStickerSetItem:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.PromoData:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.NotifyPeer:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.wallet.KeySecretSalt:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputPrivacyKey:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.RecentMeUrls:
|
||||
@ -1275,6 +1274,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.SearchCounter:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.auth.CheckedPhone:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.PageListItem:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.PeerBlocked:
|
||||
@ -1333,6 +1334,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.AffectedFoundMessages:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.MessageFwdAuthor:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.WallPaper:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.Messages:
|
||||
@ -1365,6 +1368,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.PaymentSavedCredentials:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.Null:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.auth.CodeType:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.DocumentAttribute:
|
||||
@ -1393,6 +1398,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.updates.State:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.FoundGif:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.User:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.Message:
|
||||
@ -1457,8 +1464,6 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputWebFileLocation:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.EmojiLanguage:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.MessageFwdHeader:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.BaseTheme:
|
||||
@ -1475,6 +1480,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.upload.CdnFile:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.wallet.LiteResponse:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.InviteText:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.BotInlineMessage:
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -108,6 +108,9 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
|
||||
if (flags & Int32(1 << 25)) != 0 {
|
||||
channelFlags.insert(.isFake)
|
||||
}
|
||||
if (flags & Int32(1 << 25)) != 0 {
|
||||
channelFlags.insert(.isGigagroup)
|
||||
}
|
||||
|
||||
let restrictionInfo: PeerAccessRestrictionInfo?
|
||||
if let restrictionReason = restrictionReason {
|
||||
|
@ -62,6 +62,7 @@ public enum AdminLogEventAction {
|
||||
case deleteExportedInvitation(ExportedInvitation)
|
||||
case revokeExportedInvitation(ExportedInvitation)
|
||||
case editExportedInvitation(previous: ExportedInvitation, updated: ExportedInvitation)
|
||||
case participantJoinedViaInvite(ExportedInvitation)
|
||||
}
|
||||
|
||||
public enum ChannelAdminLogEventError {
|
||||
@ -241,12 +242,12 @@ public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: Pe
|
||||
action = .revokeExportedInvitation(ExportedInvitation(apiExportedInvite: invite))
|
||||
case let .channelAdminLogEventActionExportedInviteEdit(prevInvite, newInvite):
|
||||
action = .editExportedInvitation(previous: ExportedInvitation(apiExportedInvite: prevInvite), updated: ExportedInvitation(apiExportedInvite: newInvite))
|
||||
case let .channelAdminLogEventActionParticipantJoinByInvite(invite):
|
||||
action = .participantJoinedViaInvite(ExportedInvitation(apiExportedInvite: invite))
|
||||
case let .channelAdminLogEventActionParticipantVolume(participant):
|
||||
let parsedParticipant = GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate(participant)
|
||||
action = .groupCallUpdateParticipantVolume(peerId: parsedParticipant.peerId, volume: parsedParticipant.volume ?? 10000)
|
||||
case let .channelAdminLogEventActionParticipantJoinByInvite(invite):
|
||||
action = nil
|
||||
case .channelAdminLogEventActionChangeHistoryTTL(prevValue: let prevValue, newValue: let newValue):
|
||||
case let .channelAdminLogEventActionChangeHistoryTTL(prevValue, newValue):
|
||||
action = nil
|
||||
}
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||
|
@ -856,6 +856,7 @@ public final class PeerInvitationImportersContext {
|
||||
public struct ExportedInvitationCreator : Equatable {
|
||||
public let peer: RenderedPeer
|
||||
public let count: Int32
|
||||
public let revokedCount: Int32
|
||||
}
|
||||
|
||||
public func peerExportedInvitationsCreators(account: Account, peerId: PeerId) -> Signal<[ExportedInvitationCreator], NoError> {
|
||||
@ -892,7 +893,7 @@ public func peerExportedInvitationsCreators(account: Account, peerId: PeerId) ->
|
||||
case let .chatAdminWithInvites(adminId, invitesCount, revokedInvitesCount):
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: adminId)
|
||||
if let peer = peersMap[peerId], peerId != account.peerId {
|
||||
creators.append(ExportedInvitationCreator(peer: RenderedPeer(peer: peer), count: invitesCount))
|
||||
creators.append(ExportedInvitationCreator(peer: RenderedPeer(peer: peer), count: invitesCount, revokedCount: revokedInvitesCount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ public enum ReportReason: Equatable {
|
||||
case childAbuse
|
||||
case copyright
|
||||
case irrelevantLocation
|
||||
case custom(String)
|
||||
case custom
|
||||
}
|
||||
|
||||
private extension ReportReason {
|
||||
@ -110,16 +110,9 @@ private extension ReportReason {
|
||||
}
|
||||
}
|
||||
|
||||
public func reportPeer(account: Account, peerId: PeerId, reason: ReportReason) -> Signal<Void, NoError> {
|
||||
public func reportPeer(account: Account, peerId: PeerId, reason: ReportReason, message: String) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
var message: String = ""
|
||||
switch reason {
|
||||
case let .custom(text):
|
||||
message = text
|
||||
default:
|
||||
break
|
||||
}
|
||||
return account.network.request(Api.functions.account.reportPeer(peer: inputPeer, reason: reason.apiReason, message: message))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
@ -133,20 +126,13 @@ public func reportPeer(account: Account, peerId: PeerId, reason: ReportReason) -
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func reportPeerMessages(account: Account, messageIds: [MessageId], reason: ReportReason) -> Signal<Void, NoError> {
|
||||
public func reportPeerMessages(account: Account, messageIds: [MessageId], reason: ReportReason, message: String) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
let groupedIds = messagesIdsGroupedByPeerId(messageIds)
|
||||
let signals = groupedIds.values.compactMap { ids -> Signal<Void, NoError>? in
|
||||
guard let peerId = ids.first?.peerId, let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else {
|
||||
return nil
|
||||
}
|
||||
var message: String = ""
|
||||
switch reason {
|
||||
case let .custom(text):
|
||||
message = text
|
||||
default:
|
||||
break
|
||||
}
|
||||
return account.network.request(Api.functions.messages.report(peer: inputPeer, id: ids.map { $0.id }, reason: reason.apiReason, message: message))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
|
@ -359,7 +359,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
|
||||
pageIndicatorInactiveColor: UIColor(white: 1.0, alpha: 0.3),
|
||||
inputClearButtonColor: UIColor(rgb: 0x8b9197),
|
||||
itemBarChart: PresentationThemeItemBarChart(color1: UIColor(rgb: 0xffffff), color2: UIColor(rgb: 0x929196), color3: UIColor(rgb: 0x333333)),
|
||||
itemInputField: PresentationInputFieldTheme(backgroundColor: UIColor(rgb: 0x1c1c1d), strokeColor: UIColor(rgb: 0x1c1c1d), placeholderColor: UIColor(rgb: 0x8f8f8f), primaryColor: UIColor(rgb: 0xffffff), controlColor: UIColor(rgb: 0x8f8f8f))
|
||||
itemInputField: PresentationInputFieldTheme(backgroundColor: UIColor(rgb: 0x0f0f0f), strokeColor: UIColor(rgb: 0x0f0f0f), placeholderColor: UIColor(rgb: 0x8f8f8f), primaryColor: UIColor(rgb: 0xffffff), controlColor: UIColor(rgb: 0x8f8f8f))
|
||||
)
|
||||
|
||||
let chatList = PresentationThemeChatList(
|
||||
|
@ -612,7 +612,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
|
||||
pageIndicatorInactiveColor: mainSecondaryTextColor.withAlphaComponent(0.4),
|
||||
inputClearButtonColor: mainSecondaryColor,
|
||||
itemBarChart: PresentationThemeItemBarChart(color1: accentColor, color2: mainSecondaryTextColor.withAlphaComponent(0.5), color3: accentColor.withMultiplied(hue: 1.038, saturation: 0.329, brightness: 0.33)),
|
||||
itemInputField: PresentationInputFieldTheme(backgroundColor: mainBackgroundColor, strokeColor: mainBackgroundColor, placeholderColor: mainSecondaryColor, primaryColor: UIColor(rgb: 0xffffff), controlColor: mainSecondaryColor)
|
||||
itemInputField: PresentationInputFieldTheme(backgroundColor: mainInputColor, strokeColor: mainInputColor, placeholderColor: mainSecondaryColor, primaryColor: UIColor(rgb: 0xffffff), controlColor: mainSecondaryColor)
|
||||
)
|
||||
|
||||
let chatList = PresentationThemeChatList(
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -2767,10 +2767,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
if let selectionState = presentationInterfaceState.interfaceState.selectionState {
|
||||
if selectionState.selectedIds.count > 0 {
|
||||
strongSelf.chatTitleView?.titleContent = .custom(strongSelf.presentationData.strings.Conversation_SelectedMessages(Int32(selectionState.selectedIds.count ?? 1)), nil, false)
|
||||
strongSelf.chatTitleView?.titleContent = .custom(strongSelf.presentationData.strings.Conversation_SelectedMessages(Int32(selectionState.selectedIds.count)), nil, false)
|
||||
} else {
|
||||
if let reportReason = presentationInterfaceState.reportReason {
|
||||
strongSelf.chatTitleView?.titleContent = .custom("Report Smth", strongSelf.presentationInterfaceState.strings.Conversation_SelectMessages, false)
|
||||
let title: String
|
||||
switch reportReason {
|
||||
case .spam:
|
||||
title = strongSelf.presentationData.strings.ReportPeer_ReasonSpam
|
||||
case .fake:
|
||||
title = strongSelf.presentationData.strings.ReportPeer_ReasonFake
|
||||
case .violence:
|
||||
title = strongSelf.presentationData.strings.ReportPeer_ReasonViolence
|
||||
case .porno:
|
||||
title = strongSelf.presentationData.strings.ReportPeer_ReasonPornography
|
||||
case .childAbuse:
|
||||
title = strongSelf.presentationData.strings.ReportPeer_ReasonChildAbuse
|
||||
case .copyright:
|
||||
title = strongSelf.presentationData.strings.ReportPeer_ReasonCopyright
|
||||
case .custom:
|
||||
title = strongSelf.presentationData.strings.ReportPeer_ReasonOther
|
||||
case .irrelevantLocation:
|
||||
title = ""
|
||||
}
|
||||
strongSelf.chatTitleView?.titleContent = .custom(title, strongSelf.presentationInterfaceState.strings.Conversation_SelectMessages, false)
|
||||
} else {
|
||||
strongSelf.chatTitleView?.titleContent = .custom(strongSelf.presentationInterfaceState.strings.Conversation_SelectMessages, nil, false)
|
||||
}
|
||||
@ -4753,13 +4772,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self?.view.window?.endEditing(true)
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
var message = ""
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ReportPeerHeaderActionSheetItem(context: strongSelf.context, text: presentationData.strings.Report_AdditionalDetailsText))
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: strongSelf.context, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder))
|
||||
items.append(ReportPeerDetailsActionSheetItem(context: strongSelf.context, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
|
||||
message = text
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Report_Report, color: .accent, font: .bold, enabled: true, action: {
|
||||
dismissAction()
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } }, completion: { _ in
|
||||
let _ = (reportPeerMessages(account: strongSelf.context.account, messageIds: Array(messageIds), reason: reportReason)
|
||||
let _ = (reportPeerMessages(account: strongSelf.context.account, messageIds: Array(messageIds), reason: reportReason, message: message)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
if let strongSelf = self, let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
@ -6207,7 +6229,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.reportIrrelvantGeoDisposable = (TelegramCore.reportPeer(account: strongSelf.context.account, peerId: peerId, reason: .irrelevantLocation)
|
||||
strongSelf.reportIrrelvantGeoDisposable = (TelegramCore.reportPeer(account: strongSelf.context.account, peerId: peerId, reason: .irrelevantLocation, message: "")
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.reportIrrelvantGeoNoticePromise.set(.single(true))
|
||||
@ -10667,7 +10689,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let _ = removePeerChat(account: strongSelf.context.account, peerId: chatPeer.id, reportChatSpam: reportSpam).start()
|
||||
strongSelf.effectiveNavigationController?.filterController(strongSelf, animated: true)
|
||||
} else if reportSpam {
|
||||
let _ = TelegramCore.reportPeer(account: strongSelf.context.account, peerId: peer.id, reason: .spam).start()
|
||||
let _ = TelegramCore.reportPeer(account: strongSelf.context.account, peerId: peer.id, reason: .spam, message: "").start()
|
||||
}
|
||||
})
|
||||
] as [ActionSheetItem])
|
||||
|
@ -716,7 +716,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
(.canPostMessages, self.presentationData.strings.Channel_AdminLog_CanSendMessages),
|
||||
(.canDeleteMessages, self.presentationData.strings.Channel_AdminLog_CanDeleteMessagesOfOthers),
|
||||
(.canEditMessages, self.presentationData.strings.Channel_AdminLog_CanEditMessages),
|
||||
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsers),
|
||||
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsersViaLink),
|
||||
(.canPinMessages, self.presentationData.strings.Channel_AdminLog_CanPinMessages),
|
||||
(.canAddAdmins, self.presentationData.strings.Channel_AdminLog_CanAddAdmins),
|
||||
(.canManageCalls, self.presentationData.strings.Channel_AdminLog_CanManageCalls)
|
||||
@ -726,7 +726,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
(.canChangeInfo, self.presentationData.strings.Channel_AdminLog_CanChangeInfo),
|
||||
(.canDeleteMessages, self.presentationData.strings.Channel_AdminLog_CanDeleteMessages),
|
||||
(.canBanUsers, self.presentationData.strings.Channel_AdminLog_CanBanUsers),
|
||||
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsers),
|
||||
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsersViaLink),
|
||||
(.canPinMessages, self.presentationData.strings.Channel_AdminLog_CanPinMessages),
|
||||
(.canBeAnonymous, self.presentationData.strings.Channel_AdminLog_CanBeAnonymous),
|
||||
(.canAddAdmins, self.presentationData.strings.Channel_AdminLog_CanAddAdmins),
|
||||
@ -1192,6 +1192,8 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
return [.TextMention(peerId: author.id)]
|
||||
} else if index == 1 {
|
||||
return [.Bold]
|
||||
}
|
||||
return []
|
||||
}, to: &text, entities: &entities)
|
||||
@ -1211,11 +1213,13 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: (String, [(Int, NSRange)]) = self.presentationData.strings.Channel_AdminLog_DeletedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link)
|
||||
let rawText: (String, [(Int, NSRange)]) = self.presentationData.strings.Channel_AdminLog_DeletedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
return [.TextMention(peerId: author.id)]
|
||||
} else if index == 1 {
|
||||
return [.Bold]
|
||||
}
|
||||
return []
|
||||
}, to: &text, entities: &entities)
|
||||
@ -1235,11 +1239,13 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: (String, [(Int, NSRange)]) = self.presentationData.strings.Channel_AdminLog_RevokedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link)
|
||||
let rawText: (String, [(Int, NSRange)]) = self.presentationData.strings.Channel_AdminLog_RevokedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
return [.TextMention(peerId: author.id)]
|
||||
} else if index == 1 {
|
||||
return [.Bold]
|
||||
}
|
||||
return []
|
||||
}, to: &text, entities: &entities)
|
||||
@ -1259,11 +1265,39 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: (String, [(Int, NSRange)]) = self.presentationData.strings.Channel_AdminLog_EditedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedInvite.link)
|
||||
let rawText: (String, [(Int, NSRange)]) = self.presentationData.strings.Channel_AdminLog_EditedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedInvite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
return [.TextMention(peerId: author.id)]
|
||||
} else if index == 1 {
|
||||
return [.Bold]
|
||||
}
|
||||
return []
|
||||
}, to: &text, entities: &entities)
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes()))
|
||||
case let .participantJoinedViaInvite(invite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
if let peer = self.entry.peers[self.entry.event.peerId] {
|
||||
author = peer
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: (String, [(Int, NSRange)]) = self.presentationData.strings.Channel_AdminLog_JoinedViaInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
return [.TextMention(peerId: author.id)]
|
||||
} else if index == 1 {
|
||||
return [.Bold]
|
||||
}
|
||||
return []
|
||||
}, to: &text, entities: &entities)
|
||||
|
@ -87,7 +87,7 @@ private func peerButtons(_ state: ChatPresentationInterfaceState) -> [ChatReport
|
||||
buttons.append(.shareMyPhoneNumber)
|
||||
}
|
||||
}
|
||||
} else if let _ = state.renderedPeer?.chatMainPeer {
|
||||
} else if let _ = state.renderedPeer?.chatMainPeer, case .peer = state.chatLocation {
|
||||
if let contactStatus = state.contactStatus, let peerStatusSettings = contactStatus.peerStatusSettings, peerStatusSettings.contains(.suggestAddMembers) {
|
||||
buttons.append(.addMembers)
|
||||
} else if let contactStatus = state.contactStatus, contactStatus.canReportIrrelevantLocation, let peerStatusSettings = contactStatus.peerStatusSettings, peerStatusSettings.contains(.canReportIrrelevantGeoLocation) {
|
||||
|
@ -656,7 +656,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
|
||||
if currentInvitationsContext == nil {
|
||||
var canManageInvitations = false
|
||||
if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
|
||||
if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) {
|
||||
canManageInvitations = true
|
||||
}
|
||||
if canManageInvitations {
|
||||
@ -813,9 +813,13 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
|
||||
if currentInvitationsContext == nil {
|
||||
var canManageInvitations = false
|
||||
if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
|
||||
canManageInvitations = true
|
||||
} else if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
|
||||
if let group = peerViewMainPeer(peerView) as? TelegramGroup {
|
||||
if case .creator = group.role {
|
||||
canManageInvitations = true
|
||||
} else if case let .admin(rights, _) = group.role, rights.flags.contains(.canInviteUsers) {
|
||||
canManageInvitations = true
|
||||
}
|
||||
} else if let channel = peerViewMainPeer(peerView) as? TelegramChannel, channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) {
|
||||
canManageInvitations = true
|
||||
}
|
||||
if canManageInvitations {
|
||||
@ -1081,14 +1085,33 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
||||
return result
|
||||
}
|
||||
|
||||
func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?) -> Bool {
|
||||
func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?, isContact: Bool?) -> Bool {
|
||||
if let user = peer as? TelegramUser {
|
||||
if user.isDeleted {
|
||||
return false
|
||||
}
|
||||
if let isContact = isContact, !isContact {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else if peer is TelegramChannel || peer is TelegramGroup {
|
||||
return true
|
||||
} else if let peer = peer as? TelegramChannel {
|
||||
if peer.flags.contains(.isCreator) {
|
||||
return true
|
||||
} else if let adminRights = peer.adminRights, adminRights.flags.contains(.canAddAdmins) || adminRights.flags.contains(.canBanUsers) || adminRights.flags.contains(.canChangeInfo) || adminRights.flags.contains(.canInviteUsers) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else if let peer = peer as? TelegramGroup {
|
||||
if case .creator = peer.role {
|
||||
return true
|
||||
} else if case let .admin(rights, _) = peer.role {
|
||||
if rights.flags.contains(.canAddAdmins) || rights.flags.contains(.canBanUsers) || rights.flags.contains(.canChangeInfo) || rights.flags.contains(.canInviteUsers) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -1201,18 +1201,19 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
}))
|
||||
}
|
||||
|
||||
if channel.flags.contains(.isCreator) || (channel.adminRights != nil && channel.hasPermission(.pinMessages)) {
|
||||
if channel.flags.contains(.isCreator) || (channel.adminRights?.flags.contains(.canInviteUsers) == true) {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
invitesText = "\(count)"
|
||||
} else {
|
||||
invitesText = ""
|
||||
}
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, icon: UIImage(bundleImageName: "Chat/Info/GroupLinksIcon"), action: {
|
||||
interaction.editingOpenInviteLinksSetup()
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
if channel.flags.contains(.isCreator) || (channel.adminRights != nil && channel.hasPermission(.pinMessages)) {
|
||||
let discussionGroupTitle: String
|
||||
if let _ = data.cachedData as? CachedChannelData {
|
||||
if let peer = data.linkedDiscussionPeer {
|
||||
@ -1336,39 +1337,22 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
interaction.editingOpenPreHistorySetup()
|
||||
}))
|
||||
}
|
||||
|
||||
if channel.hasPermission(.inviteMembers) {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
invitesText = "\(count)"
|
||||
} else {
|
||||
invitesText = ""
|
||||
}
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, icon: UIImage(bundleImageName: "Chat/Info/GroupLinksIcon"), action: {
|
||||
interaction.editingOpenInviteLinksSetup()
|
||||
}))
|
||||
}
|
||||
|
||||
/*if channel.hasPermission(.changeInfo) {
|
||||
let timeoutString: String
|
||||
if case let .known(value) = cachedData.autoremoveTimeout {
|
||||
if let value = value?.effectiveValue {
|
||||
timeoutString = timeIntervalString(strings: presentationData.strings, value: value)
|
||||
} else {
|
||||
timeoutString = presentationData.strings.PeerInfo_AutoremoveMessagesDisabled
|
||||
}
|
||||
} else {
|
||||
timeoutString = ""
|
||||
}
|
||||
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAutoremove, label: .text(timeoutString), text: presentationData.strings.PeerInfo_AutoremoveMessages, action: {
|
||||
interaction.editingOpenAutoremoveMesages()
|
||||
}))
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
if isCreator || (channel.hasPermission(.inviteMembers)) {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
invitesText = "\(count)"
|
||||
} else {
|
||||
invitesText = ""
|
||||
}
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, icon: UIImage(bundleImageName: "Chat/Info/GroupLinksIcon"), action: {
|
||||
interaction.editingOpenInviteLinksSetup()
|
||||
}))
|
||||
}
|
||||
|
||||
if cachedData.flags.contains(.canSetStickerSet) && canEditPeerInfo(context: context, peer: channel) {
|
||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemStickerPack, label: .text(cachedData.stickerPack?.title ?? presentationData.strings.GroupInfo_SharedMediaNone), text: presentationData.strings.Stickers_GroupStickers, icon: UIImage(bundleImageName: "Settings/MenuIcons/Stickers"), action: {
|
||||
interaction.editingOpenStickerPackSetup()
|
||||
@ -1472,8 +1456,19 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, text: presentationData.strings.GroupInfo_Administrators, icon: UIImage(bundleImageName: "Chat/Info/GroupAdminsIcon"), action: {
|
||||
interaction.openParticipantsSection(.admins)
|
||||
}))
|
||||
} else if case .admin = group.role {
|
||||
|
||||
} else if case let .admin(rights, _) = group.role {
|
||||
if rights.flags.contains(.canInviteUsers) {
|
||||
let invitesText: String
|
||||
if let count = data.invitations?.count, count > 0 {
|
||||
invitesText = "\(count)"
|
||||
} else {
|
||||
invitesText = ""
|
||||
}
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, icon: UIImage(bundleImageName: "Chat/Info/GroupLinksIcon"), action: {
|
||||
interaction.editingOpenInviteLinksSetup()
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3744,7 +3739,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
let _ = removePeerChat(account: strongSelf.context.account, peerId: strongSelf.peerId, reportChatSpam: reportSpam).start()
|
||||
(strongSelf.controller?.navigationController as? NavigationController)?.popToRoot(animated: true)
|
||||
} else if reportSpam {
|
||||
let _ = reportPeer(account: strongSelf.context.account, peerId: strongSelf.peerId, reason: .spam).start()
|
||||
let _ = reportPeer(account: strongSelf.context.account, peerId: strongSelf.peerId, reason: .spam, message: "").start()
|
||||
}
|
||||
|
||||
deleteSendMessageIntents(peerId: strongSelf.peerId)
|
||||
@ -3875,6 +3870,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
|
||||
private func editingOpenInviteLinksSetup() {
|
||||
|
||||
self.controller?.push(inviteLinkListController(context: self.context, peerId: self.peerId, admin: nil))
|
||||
}
|
||||
|
||||
@ -5307,7 +5303,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
if self.isSettings {
|
||||
navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
|
||||
navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true))
|
||||
} else if peerInfoCanEdit(peer: self.data?.peer, cachedData: self.data?.cachedData) {
|
||||
} else if peerInfoCanEdit(peer: self.data?.peer, cachedData: self.data?.cachedData, isContact: self.data?.isContact) {
|
||||
navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
|
||||
}
|
||||
if self.state.selectedMessageIds == nil {
|
||||
@ -6230,14 +6226,16 @@ func presentAddMembers(context: AccountContext, parentController: ViewController
|
||||
var canCreateInviteLink = false
|
||||
if let group = groupPeer as? TelegramGroup {
|
||||
switch group.role {
|
||||
case .creator, .admin:
|
||||
case .creator:
|
||||
canCreateInviteLink = true
|
||||
case let .admin(rights, _):
|
||||
canCreateInviteLink = rights.flags.contains(.canInviteUsers)
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else if let channel = groupPeer as? TelegramChannel {
|
||||
if channel.hasPermission(.inviteMembers) {
|
||||
if channel.flags.contains(.isCreator) || (channel.adminRights != nil && channel.username == nil) {
|
||||
if channel.flags.contains(.isCreator) || (channel.hasPermission(.inviteMembers)) {
|
||||
canCreateInviteLink = true
|
||||
}
|
||||
}
|
||||
|
@ -13,14 +13,16 @@ import AppBundle
|
||||
public final class ReportPeerDetailsActionSheetItem: ActionSheetItem {
|
||||
let context: AccountContext
|
||||
let placeholderText: String
|
||||
let textUpdated: (String) -> Void
|
||||
|
||||
public init(context: AccountContext, placeholderText: String) {
|
||||
public init(context: AccountContext, placeholderText: String, textUpdated: @escaping (String) -> Void) {
|
||||
self.context = context
|
||||
self.placeholderText = placeholderText
|
||||
self.textUpdated = textUpdated
|
||||
}
|
||||
|
||||
public func node(theme: ActionSheetControllerTheme) -> ActionSheetItemNode {
|
||||
return ReportPeerDetailsActionSheetItemNode(theme: theme, context: self.context, placeholderText: self.placeholderText)
|
||||
return ReportPeerDetailsActionSheetItemNode(theme: theme, context: self.context, placeholderText: self.placeholderText, textUpdated: self.textUpdated)
|
||||
}
|
||||
|
||||
public func updateNode(_ node: ActionSheetItemNode) {
|
||||
@ -34,7 +36,7 @@ private final class ReportPeerDetailsActionSheetItemNode: ActionSheetItemNode {
|
||||
|
||||
private let accessibilityArea: AccessibilityAreaNode
|
||||
|
||||
init(theme: ActionSheetControllerTheme, context: AccountContext, placeholderText: String) {
|
||||
init(theme: ActionSheetControllerTheme, context: AccountContext, placeholderText: String, textUpdated: @escaping (String) -> Void) {
|
||||
self.theme = theme
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -48,7 +50,12 @@ private final class ReportPeerDetailsActionSheetItemNode: ActionSheetItemNode {
|
||||
|
||||
self.addSubnode(self.inputFieldNode)
|
||||
|
||||
// self.inputFieldNode.
|
||||
self.inputFieldNode.updateText = { text in
|
||||
textUpdated(text)
|
||||
}
|
||||
self.inputFieldNode.updateHeight = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||
|
@ -207,7 +207,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.textNode.attributedText = attributedText
|
||||
self.textNode.maximumNumberOfLines = 2
|
||||
displayUndo = false
|
||||
self.originalRemainingSeconds = 4
|
||||
self.originalRemainingSeconds = 3
|
||||
case let .banned(text):
|
||||
self.avatarNode = nil
|
||||
self.iconNode = nil
|
||||
|
Loading…
x
Reference in New Issue
Block a user