Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
overtake 2020-10-27 11:31:34 +04:00
commit d3df036229
68 changed files with 4609 additions and 5074 deletions

View File

@ -3,7 +3,7 @@
include Utils.makefile
APP_VERSION="7.1.2"
APP_VERSION="7.2"
CORE_COUNT=$(shell sysctl -n hw.logicalcpu)
CORE_COUNT_MINUS_ONE=$(shell expr ${CORE_COUNT} \- 1)

View File

@ -5876,4 +5876,8 @@ Any member of this group will be able to see messages in the channel.";
"Location.LiveLocationRequired.Title" = "Share Location";
"Location.LiveLocationRequired.Description" = "For the alert to work, please share your live location in this chat.";
"Location.LiveLocationRequired.ShareLocation" = "Share Location"; 
"Location.LiveLocationRequired.ShareLocation" = "Share Location";
"Stats.Message.Views" = "Views";
"Stats.Message.PublicShares" = "Public Shares";
"Stats.Message.PrivateShares" = "Private Shares";

View File

@ -1,12 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="14313.18" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="umr-Wa-jBL">
<device id="watch38" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<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">
<device id="watch38"/>
<dependencies>
<deployment identifier="watchOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="14238.10"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="17034"/>
</dependencies>
<scenes>
<!--TGNeoConversationController-->
@ -1097,432 +1094,6 @@ contacts found.</string>
</objects>
<point key="canvasLocation" x="1130" y="463"/>
</scene>
<!--Static M-->
<scene sceneID="AEw-b0-oYE">
<objects>
<notificationController backgroundImage="BubbleNotification" spacing="0.0" id="YCC-NB-fut" userLabel="Static M">
<items>
<group width="1" alignment="left" radius="0.0" id="48N-YZ-6wz">
<items>
<label alignment="left" text="Text" numberOfLines="0" id="D1w-ZG-PyH">
<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="JfB-70-Muf">
<color key="titleColor" red="0.10051588714122772" green="0.10051287710666656" blue="0.10051460564136505" 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="D1w-ZG-PyH" id="jL5-6Q-Ttn"/>
<segue destination="dSi-eZ-mbH" kind="relationship" relationship="dynamicNotificationInterface" id="vxV-TA-VJY"/>
</connections>
</notificationController>
</objects>
<point key="canvasLocation" x="263" y="875"/>
</scene>
<!--Static R-->
<scene sceneID="Cez-Gq-mIP">
<objects>
<notificationController backgroundImage="BubbleNotification" spacing="0.0" id="duo-za-GTK" userLabel="Static R">
<items>
<group width="1" alignment="left" layout="vertical" radius="0.0" id="bh3-Uy-SPM">
<items>
<label alignment="left" text="Text" numberOfLines="0" id="bud-Nf-P9v">
<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="OCD-E6-DAX">
<color key="titleColor" red="0.10051588714122772" green="0.10051287710666656" blue="0.10051460564136505" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="sashColor" red="1" green="0.99997437000274658" blue="0.99999129772186279" 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="bud-Nf-P9v" id="380-p3-pxh"/>
<segue destination="Km6-N5-yeb" kind="relationship" relationship="dynamicNotificationInterface" id="D9i-4a-BEc"/>
</connections>
</notificationController>
</objects>
<point key="canvasLocation" x="268" y="1414"/>
</scene>
<!--Dynamic R-->
<scene sceneID="v88-RH-0Ql">
<objects>
<controller backgroundImage="BubbleNotification" spacing="0.0" id="Km6-N5-yeb" userLabel="Dynamic R" customClass="TGNotificationController">
<items>
<group width="1" alignment="left" layout="vertical" radius="0.0" spacing="0.0" id="mfC-xM-cxy">
<items>
<group width="1" alignment="left" layout="vertical" spacing="0.0" id="wyb-qB-Qel">
<items>
<label alignment="left" hidden="YES" text="Chat Title" id="nY4-PY-ouY">
<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="7s1-eh-fbh">
<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="7ca-gR-lQ3">
<items>
<label alignment="left" verticalAlignment="center" text="Forwarded from" id="ugR-GT-tRD" 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="t2S-5n-2vv" userLabel="ForwardFrom">
<color key="textColor" red="0.11312995851039886" green="0.50641471147537231" blue="0.96399867534637451" 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="mzm-dj-ikh" userLabel="ReplyHeader">
<items>
<group width="2" height="26" alignment="left" verticalAlignment="center" radius="0.0" spacing="0.0" id="yEy-WL-su3" userLabel="ReplyLine">
<color key="backgroundColor" red="0.11312995851039886" green="0.50641471147537231" blue="0.96399867534637451" 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="6N2-x0-qTe" 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="9WC-D4-VbM" userLabel="ReplyMessage">
<items>
<label alignment="left" text="Name" id="W56-AY-6jy" userLabel="ReplyAuthor">
<color key="textColor" red="0.11312995851039886" green="0.50641471147537231" blue="0.96399867534637451" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
</label>
<label alignment="left" text="Text" id="kk0-zw-fCl" 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="nQW-fB-pYI">
<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="1il-cr-5K0" userLabel="WrapperGroup">
<items>
<group width="1" alignment="left" layout="vertical" radius="10" spacing="0.0" id="JJt-07-p6x" userLabel="LocationGroup">
<items>
<map height="92" alignment="left" id="ugQ-yo-LS8"/>
</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="ANN-OG-5Ze" userLabel="FileGroup">
<items>
<imageView width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" image="Location" contentMode="center" id="lG8-D0-tJV" userLabel="VenueIcon">
<color key="tintColor" red="0.35566622018814087" green="0.68838506937026978" blue="0.91561108827590942" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</imageView>
<group width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" radius="13" spacing="0.0" id="RaH-Pv-V61" userLabel="AudioGroup">
<items>
<imageView width="26" height="26" alignment="left" image="MediaAudioPlay" contentMode="center" id="Hcb-8c-4I2"/>
</items>
<color key="backgroundColor" red="0.35566622018814087" green="0.68838506937026978" blue="0.91561108827590942" 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="fSc-ay-AOb" userLabel="FileIconGroup">
<items>
<imageView alignment="center" verticalAlignment="center" image="File.png" contentMode="center" id="cdA-4F-D0E">
<color key="tintColor" red="0.14697439968585968" green="0.56079143285751343" blue="0.88162887096405029" 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="wNt-UG-hOY" userLabel="FileMetaGroup">
<items>
<label alignment="left" text="File Name" id="4kg-td-4gi">
<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="eca-TA-utp">
<color key="textColor" red="0.41865724325180054" green="0.41825520992279053" blue="0.43064218759536743" 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="JwB-Mx-wo3" userLabel="StickerWrapper">
<items>
<group width="84" height="84" alignment="left" contentMode="scaleAspectFit" id="l8v-gE-XXa" 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="TlV-9o-bQ0" userLabel="MediaGroup">
<items>
<group alignment="right" verticalAlignment="bottom" radius="10" id="bII-EE-L0C" userLabel="DurationGroup">
<items>
<label alignment="left" text="2:34" id="DT6-b5-gtK" userLabel="Duration">
<color key="textColor" red="0.24618944525718689" green="0.24618205428123474" blue="0.24618625640869141" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="font" type="system" pointSize="12"/>
</label>
</items>
<color key="backgroundColor" red="0.89292949438095093" green="0.91148859262466431" blue="0.93112039566040039" 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="0to-MY-UuU" userLabel="CaptionGroup">
<items>
<label alignment="left" text="Caption" numberOfLines="0" id="kaM-1v-3k6">
<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="RaH-Pv-V61" id="aSC-wS-UlL"/>
<outlet property="captionGroup" destination="0to-MY-UuU" id="3Qb-RO-mt0"/>
<outlet property="captionLabel" destination="kaM-1v-3k6" id="Hdx-Uo-2pn"/>
<outlet property="chatTitleLabel" destination="nY4-PY-ouY" id="eKb-F4-IDZ"/>
<outlet property="durationGroup" destination="bII-EE-L0C" id="i4e-JX-dgt"/>
<outlet property="durationLabel" destination="DT6-b5-gtK" id="zeN-m6-tAn"/>
<outlet property="fileGroup" destination="ANN-OG-5Ze" id="Xvn-kD-ijA"/>
<outlet property="fileIconGroup" destination="fSc-ay-AOb" id="A6N-g4-8fv"/>
<outlet property="forwardFromLabel" destination="t2S-5n-2vv" id="8Oi-9Y-2Ns"/>
<outlet property="forwardHeaderGroup" destination="7ca-gR-lQ3" id="zs1-fj-L1I"/>
<outlet property="forwardTitleLabel" destination="ugR-GT-tRD" id="1X1-vd-ZQa"/>
<outlet property="map" destination="ugQ-yo-LS8" id="7DS-eu-d65"/>
<outlet property="mapGroup" destination="JJt-07-p6x" id="xDn-aB-wYf"/>
<outlet property="mediaGroup" destination="TlV-9o-bQ0" id="Iyf-d8-jpI"/>
<outlet property="messageTextLabel" destination="nQW-fB-pYI" id="S2O-rN-7Sm"/>
<outlet property="nameLabel" destination="7s1-eh-fbh" id="A3Q-xr-EMc"/>
<outlet property="replyAuthorNameLabel" destination="W56-AY-6jy" id="z6z-jA-Qjn"/>
<outlet property="replyHeaderGroup" destination="mzm-dj-ikh" id="tIx-pO-cmO"/>
<outlet property="replyHeaderImageGroup" destination="6N2-x0-qTe" id="Ss5-RZ-eLX"/>
<outlet property="replyMessageTextLabel" destination="kk0-zw-fCl" id="HQ6-Ia-JdV"/>
<outlet property="stickerGroup" destination="l8v-gE-XXa" id="Rv0-mx-Gif"/>
<outlet property="stickerWrapperGroup" destination="JwB-Mx-wo3" id="Fey-0F-yeS"/>
<outlet property="subtitleLabel" destination="eca-TA-utp" id="5Q6-0R-mLP"/>
<outlet property="titleLabel" destination="4kg-td-4gi" id="eFn-0c-ZNU"/>
<outlet property="venueIcon" destination="lG8-D0-tJV" id="RJo-6C-tAD"/>
<outlet property="wrapperGroup" destination="1il-cr-5K0" id="dHU-Wx-4Zd"/>
</connections>
</controller>
</objects>
<point key="canvasLocation" x="503" y="1413.75"/>
</scene>
<!--Dynamic M-->
<scene sceneID="cqp-oW-egv">
<objects>
<controller backgroundImage="BubbleNotification" id="dSi-eZ-mbH" userLabel="Dynamic M" customClass="TGNotificationController">
<items>
<group width="1" alignment="left" layout="vertical" radius="0.0" spacing="0.0" id="NQT-HX-BaM">
<items>
<group width="1" alignment="left" layout="vertical" spacing="0.0" id="NU6-vv-ud2">
<items>
<label alignment="left" hidden="YES" text="Chat Title" id="nxH-Wj-uqy">
<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="3Z9-Rd-bAn">
<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="Xq9-eF-ZCN">
<items>
<label alignment="left" verticalAlignment="center" text="Forwarded from" id="skX-7L-Ch5" 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="0Za-Qu-4HB" userLabel="ForwardFrom">
<color key="textColor" red="0.11312995851039886" green="0.50641471147537231" blue="0.96399867534637451" 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="HRa-PM-Aqr" userLabel="ReplyHeader">
<items>
<group width="2" height="26" alignment="left" verticalAlignment="center" radius="0.0" spacing="0.0" id="HDc-Da-N0m" userLabel="ReplyLine">
<color key="backgroundColor" red="0.11312995851039886" green="0.50641471147537231" blue="0.96399867534637451" 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="gdR-w4-b1Y" 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="MVH-mF-cZ8" userLabel="ReplyMessage">
<items>
<label alignment="left" text="Name" id="hZA-Ux-hB3" userLabel="ReplyAuthor">
<color key="textColor" red="0.11312995851039886" green="0.50641471147537231" blue="0.96399867534637451" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="font" type="system" weight="medium" pointSize="12"/>
</label>
<label alignment="left" text="Text" id="7DV-4a-9iO" 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="obt-pK-Aw0">
<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="V2H-mQ-YmP" userLabel="WrapperGroup">
<items>
<group width="1" alignment="left" layout="vertical" radius="10" spacing="0.0" id="T64-Bs-ZO0" userLabel="LocationGroup">
<items>
<map height="92" alignment="left" id="0qp-I0-Lit"/>
</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="Rgj-f7-zBW" userLabel="FileGroup">
<items>
<imageView width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" image="Location" contentMode="center" id="yrG-g1-vgS" userLabel="VenueIcon">
<color key="tintColor" red="0.35566622018814087" green="0.68838506937026978" blue="0.91561108827590942" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</imageView>
<group width="26" height="26" alignment="left" verticalAlignment="center" hidden="YES" radius="13" spacing="0.0" id="Jhq-Fp-zJI" userLabel="AudioGroup">
<items>
<imageView width="26" height="26" alignment="left" image="MediaAudioPlay" contentMode="center" id="ReC-bD-5hg"/>
</items>
<color key="backgroundColor" red="0.35566622018814087" green="0.68838506937026978" blue="0.91561108827590942" 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="c6f-XR-VkD" userLabel="FileIconGroup">
<items>
<imageView alignment="center" verticalAlignment="center" image="File.png" contentMode="center" id="J4f-BW-IzH">
<color key="tintColor" red="0.14697439968585968" green="0.56079143285751343" blue="0.88162887096405029" 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="1FL-Q3-zR0" userLabel="FileMetaGroup">
<items>
<label alignment="left" text="File Name" id="vYh-VG-Kbb">
<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="yfu-XJ-oXa">
<color key="textColor" red="0.41865724325180054" green="0.41825520992279053" blue="0.43064218759536743" 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="WVZ-hR-PhJ" userLabel="StickerWrapper">
<items>
<group width="0.5" height="64" alignment="left" contentMode="scaleAspectFit" id="AzN-iK-uh2" 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="ppU-pp-l1S" userLabel="MediaGroup">
<items>
<group alignment="right" verticalAlignment="bottom" radius="10" id="O3C-f6-Vdb" userLabel="DurationGroup">
<items>
<label alignment="left" text="2:34" id="d4e-qi-dHW" userLabel="Duration">
<color key="textColor" red="0.24618944525718689" green="0.24618205428123474" blue="0.24618625640869141" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="font" type="system" pointSize="12"/>
</label>
</items>
<color key="backgroundColor" red="0.89292949438095093" green="0.91148859262466431" blue="0.93112039566040039" 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="q49-gu-zF9" userLabel="CaptionGroup">
<items>
<label alignment="left" text="Caption" numberOfLines="0" id="DFG-U5-QhE">
<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="Jhq-Fp-zJI" id="td2-MW-fXd"/>
<outlet property="captionGroup" destination="q49-gu-zF9" id="VpF-Mn-NPc"/>
<outlet property="captionLabel" destination="DFG-U5-QhE" id="0HU-Lc-aA1"/>
<outlet property="chatTitleLabel" destination="nxH-Wj-uqy" id="M9k-c8-5Jv"/>
<outlet property="durationGroup" destination="O3C-f6-Vdb" id="oAU-5e-HbS"/>
<outlet property="durationLabel" destination="d4e-qi-dHW" id="g8n-fB-TBl"/>
<outlet property="fileGroup" destination="Rgj-f7-zBW" id="Oew-x9-kp2"/>
<outlet property="fileIconGroup" destination="c6f-XR-VkD" id="0vF-hC-7Rp"/>
<outlet property="forwardFromLabel" destination="0Za-Qu-4HB" id="nnp-Ld-lml"/>
<outlet property="forwardHeaderGroup" destination="Xq9-eF-ZCN" id="dNN-9b-RXQ"/>
<outlet property="forwardTitleLabel" destination="skX-7L-Ch5" id="kPe-OY-vjQ"/>
<outlet property="map" destination="0qp-I0-Lit" id="2qQ-iW-AFY"/>
<outlet property="mapGroup" destination="T64-Bs-ZO0" id="Sgr-JR-Db8"/>
<outlet property="mediaGroup" destination="ppU-pp-l1S" id="2M8-CP-Noy"/>
<outlet property="messageTextLabel" destination="obt-pK-Aw0" id="57m-0N-bX8"/>
<outlet property="nameLabel" destination="3Z9-Rd-bAn" id="8kM-mT-2ZN"/>
<outlet property="replyAuthorNameLabel" destination="hZA-Ux-hB3" id="hlt-W5-k5P"/>
<outlet property="replyHeaderGroup" destination="HRa-PM-Aqr" id="I10-gZ-KfR"/>
<outlet property="replyHeaderImageGroup" destination="gdR-w4-b1Y" id="qQS-ZH-fWl"/>
<outlet property="replyMessageTextLabel" destination="7DV-4a-9iO" id="Wzy-4A-GdY"/>
<outlet property="stickerGroup" destination="AzN-iK-uh2" id="Wgo-GU-lNF"/>
<outlet property="stickerWrapperGroup" destination="WVZ-hR-PhJ" id="aR5-Gb-GX2"/>
<outlet property="subtitleLabel" destination="yfu-XJ-oXa" id="Pf7-PQ-6rB"/>
<outlet property="titleLabel" destination="vYh-VG-Kbb" id="bXz-ee-o3E"/>
<outlet property="venueIcon" destination="yrG-g1-vgS" id="VWh-0b-QoX"/>
<outlet property="wrapperGroup" destination="V2H-mQ-YmP" id="LTE-m1-bVJ"/>
</connections>
</controller>
</objects>
<point key="canvasLocation" x="503" y="874.75"/>
</scene>
<!--Telegram-->
<scene sceneID="A9d-DL-l8r">
<objects>
@ -2000,4 +1571,20 @@ contacts found.</string>
</scene>
</scenes>
<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="File.png" 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"/>
<image name="MediaLocation" width="11" height="15"/>
<image name="MessageStatusDot" width="128" height="128"/>
<image name="MicAccessIcon" width="128" height="128"/>
<image name="MicIcon" width="128" height="128"/>
<image name="PickLocation" width="128" height="128"/>
<image name="RemotePlayVideo" width="128" height="128"/>
<image name="Spinner" width="128" height="128"/>
<image name="StickerIcon" width="128" height="128"/>
<image name="VerifiedProfile" width="128" height="128"/>
</resources>
</document>

View File

@ -38,7 +38,7 @@
+ (UIColor *)colorForUserId:(int32_t)userId myUserId:(int32_t)myUserId
{
return [self placeholderColors][userId % 7];
return [self placeholderColors][abs(userId) % 7];
}
+ (UIColor *)colorForGroupId:(int64_t)groupId

View File

@ -54,9 +54,11 @@ BAZEL_OPTIONS=(\
--swiftcopt=-j${CORE_COUNT_MINUS_ONE} \
)
if [ "$BAZEL_CACHE_DIR" != "" ]; then
if [ "$BAZEL_HTTP_CACHE_URL" != "" ]; then
BAZEL_OPTIONS=("${BAZEL_OPTIONS[@]}" --remote_cache="$(echo $BAZEL_HTTP_CACHE_URL | sed -e 's/[\/&]/\\&/g')")
elif [ "$BAZEL_CACHE_DIR" != "" ]; then
BAZEL_OPTIONS=("${BAZEL_OPTIONS[@]}" --disk_cache="$(echo $BAZEL_CACHE_DIR | sed -e 's/[\/&]/\\&/g')")
fi
fi
"$TULSI" -- \
--verbose \

View File

@ -95,7 +95,7 @@ private final class ContextControllerContentSourceImpl: ContextControllerContent
}
}
public class ChatListControllerImpl: TelegramBaseController, ChatListController, UIViewControllerPreviewingDelegate {
public class ChatListControllerImpl: TelegramBaseController, ChatListController {
private var validLayout: ContainerViewLayout?
public let context: AccountContext
@ -1780,111 +1780,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
(self.navigationController as? NavigationController)?.pushViewController(controller)
}
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
if let (controller, rect) = self.previewingController(from: previewingContext.sourceView, for: location) {
previewingContext.sourceRect = rect
return controller
} else {
return nil
}
} else {
return nil
}
}
func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? {
guard let layout = self.validLayout, case .phone = layout.deviceMetrics.type else {
return nil
}
let boundsSize = self.view.bounds.size
let contentSize: CGSize
if case .unknown = layout.deviceMetrics {
contentSize = boundsSize
} else {
contentSize = layout.deviceMetrics.previewingContentSize(inLandscape: boundsSize.width > boundsSize.height)
}
if let searchController = self.chatListDisplayNode.searchDisplayController {
if let (view, bounds, action) = searchController.previewViewAndActionAtLocation(location) {
if let peerId = action as? PeerId, peerId.namespace != Namespaces.Peer.SecretChat {
var sourceRect = view.superview!.convert(view.frame, to: sourceView)
sourceRect = CGRect(x: sourceRect.minX, y: sourceRect.minY + bounds.minY, width: bounds.width, height: bounds.height)
sourceRect.size.height -= UIScreenPixel
let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatController, sourceRect)
} else if let messageId = action as? MessageId, messageId.peerId.namespace != Namespaces.Peer.SecretChat {
var sourceRect = view.superview!.convert(view.frame, to: sourceView)
sourceRect = CGRect(x: sourceRect.minX, y: sourceRect.minY + bounds.minY, width: bounds.width, height: bounds.height)
sourceRect.size.height -= UIScreenPixel
let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatController, sourceRect)
}
}
return nil
}
let listLocation = self.view.convert(location, to: self.chatListDisplayNode.containerNode.currentItemNode.view)
var selectedNode: ChatListItemNode?
self.chatListDisplayNode.containerNode.currentItemNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatListItemNode, itemNode.frame.contains(listLocation), !itemNode.isDisplayingRevealedOptions {
selectedNode = itemNode
}
}
if let selectedNode = selectedNode, let item = selectedNode.item {
var sourceRect = selectedNode.view.superview!.convert(selectedNode.frame, to: sourceView)
sourceRect.size.height -= UIScreenPixel
switch item.content {
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _):
if peer.peerId.namespace != Namespaces.Peer.SecretChat {
let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatController, sourceRect)
} else {
return nil
}
case let .groupReference(groupId, _, _, _, _):
let chatListController = ChatListControllerImpl(context: self.context, groupId: groupId, controlsHistoryPreload: false, enableDebugActions: false)
chatListController.navigationPresentation = .master
chatListController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatListController, sourceRect)
}
} else {
return nil
}
}
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
self.previewingCommit(viewControllerToCommit)
}
func previewingCommit(_ viewControllerToCommit: UIViewController) {
if let viewControllerToCommit = viewControllerToCommit as? ViewController {
if let chatController = viewControllerToCommit as? ChatController {
chatController.canReadHistory.set(true)
chatController.updatePresentationMode(.standard(previewing: false))
if let navigationController = self.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, chatController: chatController, context: self.context, chatLocation: chatController.chatLocation, animated: false))
self.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
}
} else if let chatListController = viewControllerToCommit as? ChatListController {
if let navigationController = self.navigationController as? NavigationController {
navigationController.pushViewController(chatListController, animated: false, completion: {})
self.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
}
}
}
}
public override var keyShortcuts: [KeyShortcut] {
let strings = self.presentationData.strings

View File

@ -14,18 +14,6 @@ import SearchBarNode
import SearchUI
import ContextUI
private final class ChatListControllerNodeView: UITracingLayerView, PreviewingHostView {
var previewingDelegate: PreviewingHostViewDelegate? {
return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in
return self?.controller?.previewingController(from: sourceView, for: point)
}, commitController: { [weak self] controller in
self?.controller?.previewingCommit(controller)
})
}
weak var controller: ChatListControllerImpl?
}
enum ChatListContainerNodeFilter: Equatable {
case all
case filter(ChatListFilter)
@ -1027,7 +1015,7 @@ final class ChatListControllerNode: ASDisplayNode {
super.init()
self.setViewBlock({
return ChatListControllerNodeView()
return UITracingLayerView()
})
self.backgroundColor = presentationData.theme.chatList.backgroundColor
@ -1056,8 +1044,6 @@ final class ChatListControllerNode: ASDisplayNode {
override func didLoad() {
super.didLoad()
(self.view as? ChatListControllerNodeView)?.controller = self.controller
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
self.tapRecognizer = tapRecognizer
self.view.addGestureRecognizer(tapRecognizer)

View File

@ -628,9 +628,9 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
self.selectedLineNode.image = generateImage(CGSize(width: 5.0, height: 3.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: 3.0, height: 3.0)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - 3.0, y: 0.0), size: CGSize(width: 3.0, height: 3.0)))
context.fill(CGRect(x: 1.5, y: 0.0, width: size.width - 3.0, height: 3.0))
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: 4.0, height: 4.0)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - 4.0, y: 0.0), size: CGSize(width: 4.0, height: 4.0)))
context.fill(CGRect(x: 2.0, y: 0.0, width: size.width - 4.0, height: 4.0))
context.fill(CGRect(x: 0.0, y: 2.0, width: size.width, height: 2.0))
})?.resizableImage(withCapInsets: UIEdgeInsets(top: 3.0, left: 3.0, bottom: 0.0, right: 3.0), resizingMode: .stretch)
}

View File

@ -51,7 +51,7 @@ final class ChatListBadgeNode: ASDisplayNode {
self.textNode = TextNode()
self.textNode.isUserInteractionEnabled = false
self.textNode.displaysAsynchronously = true
self.textNode.displaysAsynchronously = false
self.measureTextNode = TextNode()

View File

@ -795,7 +795,13 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
}
embeddedState = embeddedStateValue
summaryInfo = summaryInfoValue
inputActivities = inputActivitiesValue
if let peerPresence = peerPresence as? TelegramUserPresence, case .present = peerPresence.status {
inputActivities = inputActivitiesValue
} else {
inputActivities = nil
}
isPeerGroup = false
promoInfo = promoInfoValue
displayAsMessage = displayAsMessageValue
@ -1320,6 +1326,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
var inputActivitiesSize: CGSize?
var inputActivitiesApply: (() -> Void)?
if let inputActivities = inputActivities, !inputActivities.isEmpty {
let (size, apply) = inputActivitiesLayout(CGSize(width: rawContentWidth - badgeSize, height: 40.0), item.presentationData, item.presentationData.theme.chatList.messageTextColor, item.index.messageIndex.id.peerId, inputActivities)
inputActivitiesSize = size
inputActivitiesApply = apply

View File

@ -396,80 +396,6 @@ public class ContactsController: ViewController {
self.contactsNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationInsetHeight, actualNavigationBarHeight: self.navigationHeight, transition: transition)
}
func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? {
guard let layout = self.validLayout, case .phone = layout.deviceMetrics.type else {
return nil
}
let boundsSize = self.view.bounds.size
let contentSize: CGSize
if case .unknown = layout.deviceMetrics {
contentSize = boundsSize
} else {
contentSize = layout.deviceMetrics.previewingContentSize(inLandscape: boundsSize.width > boundsSize.height)
}
var selectedNode: ContactsPeerItemNode?
if let searchController = self.contactsNode.searchDisplayController {
guard let contentNode = searchController.contentNode as? ContactsSearchContainerNode else {
return nil
}
let listLocation = self.view.convert(location, to: contentNode.listNode.view)
contentNode.listNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ContactsPeerItemNode, itemNode.frame.contains(listLocation), !itemNode.isDisplayingRevealedOptions {
selectedNode = itemNode
}
}
} else {
let listLocation = self.view.convert(location, to: self.contactsNode.contactListNode.listNode.view)
self.contactsNode.contactListNode.listNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ContactsPeerItemNode, itemNode.frame.contains(listLocation), !itemNode.isDisplayingRevealedOptions {
selectedNode = itemNode
}
}
}
if let selectedNode = selectedNode, let peer = selectedNode.item?.peer {
var sourceRect = selectedNode.view.superview!.convert(selectedNode.frame, to: sourceView)
sourceRect.size.height -= UIScreenPixel
switch peer {
case let .peer(peer, _):
guard let peer = peer else {
return nil
}
if peer.id.namespace != Namespaces.Peer.SecretChat {
let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatController, sourceRect)
} else {
return nil
}
case .deviceContact:
return nil
}
} else {
return nil
}
}
func previewingCommit(_ viewControllerToCommit: UIViewController) {
if let viewControllerToCommit = viewControllerToCommit as? ViewController {
if let chatController = viewControllerToCommit as? ChatController {
chatController.canReadHistory.set(true)
chatController.updatePresentationMode(.standard(previewing: false))
if let navigationController = self.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, chatController: chatController, context: self.context, chatLocation: chatController.chatLocation, animated: false))
self.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
}
}
}
}
private func activateSearch() {
if self.displayNavigationBar {
if let searchContentNode = self.searchContentNode {

View File

@ -15,18 +15,6 @@ import SearchUI
import AppBundle
import ContextUI
private final class ContactsControllerNodeView: UITracingLayerView, PreviewingHostView {
var previewingDelegate: PreviewingHostViewDelegate? {
return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in
return self?.controller?.previewingController(from: sourceView, for: point)
}, commitController: { [weak self] controller in
self?.controller?.previewingCommit(controller)
})
}
weak var controller: ContactsController?
}
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
let controller: ViewController
weak var sourceNode: ASDisplayNode?
@ -108,7 +96,7 @@ final class ContactsControllerNode: ASDisplayNode {
super.init()
self.setViewBlock({
return ContactsControllerNodeView()
return UITracingLayerView()
})
self.backgroundColor = self.presentationData.theme.chatList.backgroundColor
@ -150,12 +138,6 @@ final class ContactsControllerNode: ASDisplayNode {
self.presentationDataDisposable?.dispose()
}
override func didLoad() {
super.didLoad()
(self.view as? ContactsControllerNodeView)?.controller = self.controller
}
private func updateThemeAndStrings() {
self.backgroundColor = self.presentationData.theme.chatList.backgroundColor
self.searchDisplayController?.updatePresentationData(self.presentationData)

View File

@ -9,9 +9,9 @@ public enum DeviceLocationMode: Int32 {
private final class DeviceLocationSubscriber {
let id: Int32
let mode: DeviceLocationMode
let update: (CLLocationCoordinate2D, Double, Double?) -> Void
let update: (CLLocation, Double?) -> Void
init(id: Int32, mode: DeviceLocationMode, update: @escaping (CLLocationCoordinate2D, Double, Double?) -> Void) {
init(id: Int32, mode: DeviceLocationMode, update: @escaping (CLLocation, Double?) -> Void) {
self.id = id
self.mode = mode
self.update = update
@ -39,7 +39,7 @@ public final class DeviceLocationManager: NSObject {
private var subscribers: [DeviceLocationSubscriber] = []
private var currentTopMode: DeviceLocationMode?
private var currentLocation: (CLLocationCoordinate2D, Double)?
private var currentLocation: CLLocation?
private var currentHeading: CLHeading?
public init(queue: Queue, log: ((String) -> Void)? = nil) {
@ -56,12 +56,12 @@ public final class DeviceLocationManager: NSObject {
}
self.manager.delegate = self
self.manager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.manager.distanceFilter = 10.0
self.manager.distanceFilter = 5.0
self.manager.activityType = .other
self.manager.pausesLocationUpdatesAutomatically = false
}
public func push(mode: DeviceLocationMode, updated: @escaping (CLLocationCoordinate2D, Double, Double?) -> Void) -> Disposable {
public func push(mode: DeviceLocationMode, updated: @escaping (CLLocation, Double?) -> Void) -> Disposable {
assert(self.queue.isCurrent())
let id = self.nextSubscriberId
@ -69,7 +69,7 @@ public final class DeviceLocationManager: NSObject {
self.subscribers.append(DeviceLocationSubscriber(id: id, mode: mode, update: updated))
if let currentLocation = self.currentLocation {
updated(currentLocation.0, currentLocation.1, self.currentHeading?.magneticHeading)
updated(currentLocation, self.currentHeading?.magneticHeading)
}
self.updateTopMode()
@ -125,9 +125,9 @@ extension DeviceLocationManager: CLLocationManagerDelegate {
if let location = locations.first {
if self.currentTopMode != nil {
self.currentLocation = (location.coordinate, location.horizontalAccuracy)
self.currentLocation = location
for subscriber in self.subscribers {
subscriber.update(location.coordinate, location.horizontalAccuracy, self.currentHeading?.magneticHeading)
subscriber.update(location, self.currentHeading?.magneticHeading)
}
}
}
@ -140,7 +140,7 @@ extension DeviceLocationManager: CLLocationManagerDelegate {
self.currentHeading = newHeading
if let currentLocation = self.currentLocation {
for subscriber in self.subscribers {
subscriber.update(currentLocation.0, currentLocation.1, newHeading.magneticHeading)
subscriber.update(currentLocation, newHeading.magneticHeading)
}
}
}
@ -150,8 +150,8 @@ extension DeviceLocationManager: CLLocationManagerDelegate {
public func currentLocationManagerCoordinate(manager: DeviceLocationManager, timeout timeoutValue: Double) -> Signal<CLLocationCoordinate2D?, NoError> {
return (
Signal { subscriber in
let disposable = manager.push(mode: .precise, updated: { coordinate, _, _ in
subscriber.putNext(coordinate)
let disposable = manager.push(mode: .precise, updated: { location, _ in
subscriber.putNext(location.coordinate)
subscriber.putCompletion()
})
return disposable

View File

@ -12,6 +12,9 @@ public enum DeviceMetrics: CaseIterable, Equatable {
case iPhone6Plus
case iPhoneX
case iPhoneXSMax
case iPhone12Mini
case iPhone12
case iPhone12ProMax
case iPad
case iPadPro10Inch
case iPadPro11Inch
@ -27,6 +30,9 @@ public enum DeviceMetrics: CaseIterable, Equatable {
.iPhone6Plus,
.iPhoneX,
.iPhoneXSMax,
.iPhone12Mini,
.iPhone12,
.iPhone12ProMax,
.iPad,
.iPadPro10Inch,
.iPadPro11Inch,
@ -89,6 +95,12 @@ public enum DeviceMetrics: CaseIterable, Equatable {
return CGSize(width: 375.0, height: 812.0)
case .iPhoneXSMax:
return CGSize(width: 414.0, height: 896.0)
case .iPhone12Mini:
return CGSize(width: 360.0, height: 780.0)
case .iPhone12:
return CGSize(width: 390.0, height: 844.0)
case .iPhone12ProMax:
return CGSize(width: 428.0, height: 926.0)
case .iPad:
return CGSize(width: 768.0, height: 1024.0)
case .iPadPro10Inch:
@ -104,7 +116,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
func safeInsets(inLandscape: Bool) -> UIEdgeInsets {
switch self {
case .iPhoneX, .iPhoneXSMax:
case .iPhoneX, .iPhoneXSMax, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
return inLandscape ? UIEdgeInsets(top: 0.0, left: 44.0, bottom: 0.0, right: 44.0) : UIEdgeInsets(top: 44.0, left: 0.0, bottom: 0.0, right: 0.0)
default:
return UIEdgeInsets.zero
@ -113,7 +125,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
func onScreenNavigationHeight(inLandscape: Bool, systemOnScreenNavigationHeight: CGFloat?) -> CGFloat? {
switch self {
case .iPhoneX, .iPhoneXSMax:
case .iPhoneX, .iPhoneXSMax, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
return inLandscape ? 21.0 : 34.0
case .iPadPro3rdGen, .iPadPro11Inch:
return 21.0
@ -146,7 +158,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
var statusBarHeight: CGFloat {
switch self {
case .iPhoneX, .iPhoneXSMax:
case .iPhoneX, .iPhoneXSMax, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
return 44.0
case .iPadPro11Inch, .iPadPro3rdGen:
return 24.0
@ -164,7 +176,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
return 162.0
case .iPhone6, .iPhone6Plus:
return 163.0
case .iPhoneX, .iPhoneXSMax:
case .iPhoneX, .iPhoneXSMax, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
return 172.0
case .iPad, .iPadPro10Inch:
return 348.0
@ -183,9 +195,9 @@ public enum DeviceMetrics: CaseIterable, Equatable {
return 216.0
case .iPhone6Plus:
return 226.0
case .iPhoneX:
case .iPhoneX, .iPhone12Mini, .iPhone12:
return 291.0
case .iPhoneXSMax:
case .iPhoneXSMax, .iPhone12ProMax:
return 302.0
case .iPad, .iPadPro10Inch:
return 263.0
@ -204,7 +216,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
func predictiveInputHeight(inLandscape: Bool) -> CGFloat {
if inLandscape {
switch self {
case .iPhone4, .iPhone5, .iPhone6, .iPhone6Plus, .iPhoneX, .iPhoneXSMax:
case .iPhone4, .iPhone5, .iPhone6, .iPhone6Plus, .iPhoneX, .iPhoneXSMax, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
return 37.0
case .iPad, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen:
return 50.0
@ -215,7 +227,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
switch self {
case .iPhone4, .iPhone5:
return 37.0
case .iPhone6, .iPhoneX, .iPhoneXSMax:
case .iPhone6, .iPhoneX, .iPhoneXSMax, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
return 44.0
case .iPhone6Plus:
return 45.0
@ -227,44 +239,9 @@ public enum DeviceMetrics: CaseIterable, Equatable {
}
}
public func previewingContentSize(inLandscape: Bool) -> CGSize {
let screenSize = self.screenSize
if inLandscape {
switch self {
case .iPhone5:
return CGSize(width: screenSize.height, height: screenSize.width - 10.0)
case .iPhone6:
return CGSize(width: screenSize.height, height: screenSize.width - 22.0)
case .iPhone6Plus:
return CGSize(width: screenSize.height, height: screenSize.width - 22.0)
case .iPhoneX:
return CGSize(width: screenSize.height, height: screenSize.width + 48.0)
case .iPhoneXSMax:
return CGSize(width: screenSize.height, height: screenSize.width - 30.0)
default:
return CGSize(width: screenSize.height, height: screenSize.width - 10.0)
}
} else {
switch self {
case .iPhone5:
return CGSize(width: screenSize.width, height: screenSize.height - 50.0)
case .iPhone6:
return CGSize(width: screenSize.width, height: screenSize.height - 97.0)
case .iPhone6Plus:
return CGSize(width: screenSize.width, height: screenSize.height - 95.0)
case .iPhoneX:
return CGSize(width: screenSize.width, height: screenSize.height - 154.0)
case .iPhoneXSMax:
return CGSize(width: screenSize.width, height: screenSize.height - 84.0)
default:
return CGSize(width: screenSize.width, height: screenSize.height - 50.0)
}
}
}
public var hasTopNotch: Bool {
switch self {
case .iPhoneX, .iPhoneXSMax:
case .iPhoneX, .iPhoneXSMax, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
return true
default:
return false

View File

@ -95,6 +95,9 @@ public enum TabBarItemContextActionType {
if !self.lockOrientation {
self.lockedOrientation = nil
}
if let window = self.window {
window.invalidateSupportedOrientations()
}
}
}
}

View File

@ -45,6 +45,9 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController {
private var prevoiusHorizontalStrideInterval: Int = 1
public var hourly: Bool = false
public var min5: Bool = false
override public init(chartsCollection: ChartsCollection) {
self.initialChartCollection = chartsCollection
graphControllers = chartsCollection.chartValues.map { _ in GraphController() }
@ -252,8 +255,19 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController {
}
func updateHorizontalLimits(horizontalRange: ClosedRange<CGFloat>, animated: Bool) {
var scaleType: ChartScaleType = .day
if isZoomed {
scaleType = .minutes5
} else {
if self.hourly {
scaleType = .hour
} else if self.min5 {
scaleType = .minutes5
}
}
if let (stride, labels) = horizontalLimitsLabels(horizontalRange: horizontalRange,
scaleType: isZoomed ? .minutes5 : .day,
scaleType: scaleType,
prevoiusHorizontalStrideInterval: prevoiusHorizontalStrideInterval) {
self.horizontalScalesRenderer.setup(labels: labels, animated: animated)
self.prevoiusHorizontalStrideInterval = stride

View File

@ -16,6 +16,8 @@ public enum ChartType {
case step
case twoAxisStep
case hourlyStep
case twoAxisHourlyStep
case twoAxis5MinStep
}
public extension ChartTheme {
@ -90,6 +92,16 @@ public func createChartController(_ data: String, type: ChartType, getDetailsDat
case .hourlyStep:
controller = StepBarsChartController(chartsCollection: collection, hourly: true)
controller.isZoomable = false
case .twoAxisHourlyStep:
let stepController = TwoAxisStepBarsChartController(chartsCollection: collection)
stepController.hourly = true
controller = stepController
controller.isZoomable = false
case .twoAxis5MinStep:
let stepController = TwoAxisStepBarsChartController(chartsCollection: collection)
stepController.min5 = true
controller = stepController
controller.isZoomable = false
}
controller.getDetailsData = { date, completion in
getDetailsData(date, { detailsData in

View File

@ -224,9 +224,6 @@ open class ItemListController: ViewController, KeyShortcutResponder, Presentable
}
}
public var previewItemWithTag: ((ItemListItemTag) -> UIViewController?)?
public var commitPreview: ((UIViewController) -> Void)?
public var willDisappear: ((Bool) -> Void)?
public var didDisappear: ((Bool) -> Void)?
@ -557,52 +554,11 @@ open class ItemListController: ViewController, KeyShortcutResponder, Presentable
public func afterLayout(_ f: @escaping () -> Void) {
(self.displayNode as! ItemListControllerNode).afterLayout(f)
}
public func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? {
guard let layout = self.validLayout, case .phone = layout.deviceMetrics.type else {
return nil
}
let boundsSize = self.view.bounds.size
let contentSize: CGSize
if case .unknown = layout.deviceMetrics {
contentSize = boundsSize
} else {
contentSize = layout.deviceMetrics.previewingContentSize(inLandscape: boundsSize.width > boundsSize.height)
}
var selectedNode: ItemListItemNode?
let listLocation = self.view.convert(location, to: (self.displayNode as! ItemListControllerNode).listNode.view)
(self.displayNode as! ItemListControllerNode).listNode.forEachItemNode { itemNode in
if itemNode.frame.contains(listLocation), let itemNode = itemNode as? ItemListItemNode {
selectedNode = itemNode
}
}
if let selectedNode = selectedNode as? (ItemListItemNode & ListViewItemNode), let tag = selectedNode.tag {
var sourceRect = selectedNode.view.superview!.convert(selectedNode.frame, to: sourceView)
sourceRect.size.height -= UIScreenPixel
if let controller = self.previewItemWithTag?(tag) {
if let controller = controller as? ContainableController {
controller.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
}
return (controller, sourceRect)
} else {
return nil
}
} else {
return nil
}
}
public func clearItemNodesHighlight(animated: Bool = false) {
(self.displayNode as! ItemListControllerNode).listNode.clearHighlightAnimated(animated)
}
public func previewingCommit(_ viewControllerToCommit: UIViewController) {
self.commitPreview?(viewControllerToCommit)
}
public var keyShortcuts: [KeyShortcut] {
return [KeyShortcut(input: UIKeyCommand.inputEscape, action: { [weak self] in
if !(self?.navigationController?.topViewController is TabBarController) {

View File

@ -138,7 +138,7 @@ public final class ItemListNodeVisibleEntries: Sequence {
}
}
public final class ItemListControllerNodeView: UITracingLayerView, PreviewingHostView {
public final class ItemListControllerNodeView: UITracingLayerView {
var onLayout: (() -> Void)?
init(controller: ItemListController?) {
@ -171,14 +171,6 @@ public final class ItemListControllerNodeView: UITracingLayerView, PreviewingHos
}
}
public var previewingDelegate: PreviewingHostViewDelegate? {
return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in
return self?.controller?.previewingController(from: sourceView, for: point)
}, commitController: { [weak self] controller in
self?.controller?.previewingCommit(controller)
})
}
weak var controller: ItemListController?
}

View File

@ -107,9 +107,13 @@ public final class LiveLocationManagerImpl: LiveLocationManager {
if let strongSelf = self {
if value {
let queue = strongSelf.queue
strongSelf.deviceLocationDisposable.set(strongSelf.locationManager.push(mode: .precise, updated: { coordinate, accuracyRadius, heading in
strongSelf.deviceLocationDisposable.set(strongSelf.locationManager.push(mode: .precise, updated: { location, heading in
queue.async {
self?.updateDeviceCoordinate(coordinate, accuracyRadius: accuracyRadius, heading: heading)
var effectiveHeading = heading ?? location.course
if location.speed > 1.0 {
effectiveHeading = location.course
}
self?.updateDeviceCoordinate(location.coordinate, accuracyRadius: location.horizontalAccuracy, heading: effectiveHeading)
}
}))
} else {
@ -213,7 +217,7 @@ public final class LiveLocationManagerImpl: LiveLocationManager {
let ids = self.broadcastToMessageIds
let remainingIds = Atomic<Set<MessageId>>(value: Set(ids.keys))
for id in ids.keys {
self.editMessageDisposables.set((requestEditLiveLocation(postbox: self.postbox, network: self.network, stateManager: self.stateManager, messageId: id, stop: false, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude, accuracyRadius: Int32(accuracyRadius)), heading: Int32(heading ?? 0), proximityNotificationRadius: nil)
self.editMessageDisposables.set((requestEditLiveLocation(postbox: self.postbox, network: self.network, stateManager: self.stateManager, messageId: id, stop: false, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude, accuracyRadius: Int32(accuracyRadius)), heading: heading.flatMap { Int32($0) }, proximityNotificationRadius: nil)
|> deliverOn(self.queue)).start(completed: { [weak self] in
if let strongSelf = self {
strongSelf.editMessageDisposables.set(nil, forKey: id)

View File

@ -105,7 +105,7 @@ final class LocationActionListItem: ListViewItem {
async {
let node = LocationActionListItemNode()
let makeLayout = node.asyncLayout()
let (nodeLayout, nodeApply) = makeLayout(self, params, nextItem is LocationActionListItem)
let (nodeLayout, nodeApply) = makeLayout(self, params, nextItem is LocationActionListItem || nextItem is LocationLiveListItem)
node.contentSize = nodeLayout.contentSize
node.insets = nodeLayout.insets
@ -118,7 +118,7 @@ final class LocationActionListItem: ListViewItem {
if let nodeValue = node() as? LocationActionListItemNode {
let layout = nodeValue.asyncLayout()
async {
let (nodeLayout, apply) = layout(self, params, nextItem is LocationActionListItem)
let (nodeLayout, apply) = layout(self, params, nextItem is LocationActionListItem || nextItem is LocationLiveListItem)
Queue.mainQueue().async {
completion(nodeLayout, { info in
apply().1(info)

View File

@ -96,7 +96,9 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
}
var id: String {
if let peer = self.peer {
if let message = self.message {
return "\(message.id.id)"
} else if let peer = self.peer {
return "\(peer.id.toInt64())"
} else if let venueId = self.location?.venue?.id {
return venueId
@ -257,8 +259,8 @@ class LocationPinAnnotationView: MKAnnotationView {
self.dotNode.isHidden = false
self.backgroundNode.image = UIImage(bundleImageName: "Location/PinBackground")
if let author = message.author, let peer = message.peers[author.id] {
self.setPeer(context: annotation.context, theme: annotation.theme, peer: peer)
if let author = message.author {
self.setPeer(context: annotation.context, theme: annotation.theme, peer: author)
} else if let selfPeer = annotation.selfPeer {
self.setPeer(context: annotation.context, theme: annotation.theme, peer: selfPeer)
}

View File

@ -338,8 +338,14 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
private func updateDoneButtonTitle() {
if let pickerView = self.pickerView {
let largeValue = unitValues[pickerView.selectedRow(inComponent: 0)]
let smallValue = smallUnitValues[pickerView.selectedRow(inComponent: 1)]
let selectedLargeRow = pickerView.selectedRow(inComponent: 0)
var selectedSmallRow = pickerView.selectedRow(inComponent: 1)
if selectedLargeRow == 0 && selectedSmallRow == 0 {
selectedSmallRow = 1
}
let largeValue = unitValues[selectedLargeRow]
let smallValue = smallUnitValues[selectedSmallRow]
var value = largeValue * 1000 + smallValue * 10
if !self.usesMetricSystem() {
@ -353,7 +359,7 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
if let distance = self.distances.first, Double(value) > distance {
if let distance = self.distances.last, Double(value) > distance {
self.doneButton.alpha = 0.0
self.doneButton.isUserInteractionEnabled = false
self.textNode.alpha = 1.0

View File

@ -6,7 +6,10 @@ import Display
import SwiftSignalKit
import TelegramCore
import SyncCore
import AccountContext
import TelegramPresentationData
import TelegramUIPreferences
import TelegramStringFormatting
import ItemListUI
import LocationResources
import AppBundle
@ -15,15 +18,19 @@ import LiveLocationTimerNode
final class LocationLiveListItem: ListViewItem {
let presentationData: ItemListPresentationData
let account: Account
let dateTimeFormat: PresentationDateTimeFormat
let nameDisplayOrder: PresentationPersonNameOrder
let context: AccountContext
let message: Message
let distance: Double?
let action: () -> Void
let longTapAction: () -> Void
public init(presentationData: ItemListPresentationData, account: Account, message: Message, distance: Double?, action: @escaping () -> Void, longTapAction: @escaping () -> Void = { }) {
public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, message: Message, distance: Double?, action: @escaping () -> Void, longTapAction: @escaping () -> Void = { }) {
self.presentationData = presentationData
self.account = account
self.dateTimeFormat = dateTimeFormat
self.nameDisplayOrder = nameDisplayOrder
self.context = context
self.message = message
self.distance = distance
self.action = action
@ -92,6 +99,7 @@ final class LocationLiveListItemNode: ListViewItemNode {
self.highlightedBackgroundNode.isLayerBacked = true
self.avatarNode = AvatarNode(font: avatarFont)
self.avatarNode.isLayerBacked = !smartInvertColorsEnabled()
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
@ -146,20 +154,39 @@ final class LocationLiveListItemNode: ListViewItemNode {
let leftInset: CGFloat = 65.0 + params.leftInset
let rightInset: CGFloat = params.rightInset
let verticalInset: CGFloat = 8.0
let iconSize: CGFloat = 40.0
let titleFont = Font.medium(item.presentationData.fontSize.itemListBaseFontSize)
let subtitleFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0))
let titleAttributedString = NSAttributedString(string: "title", font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor)
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 15.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
var title: String = ""
if let author = item.message.author {
title = author.displayTitle(strings: item.presentationData.strings, displayOrder: item.nameDisplayOrder)
}
let titleAttributedString = NSAttributedString(string: title, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor)
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 54.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let subtitleAttributedString = NSAttributedString(string: "subtitle", font: subtitleFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor)
let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: subtitleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 15.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
var updateTimestamp = item.message.timestamp
for attribute in item.message.attributes {
if let attribute = attribute as? EditedMessageAttribute {
updateTimestamp = attribute.date
break
}
}
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
let timeString = stringForRelativeLiveLocationTimestamp(strings: item.presentationData.strings, relativeTimestamp: Int32(updateTimestamp), relativeTo: Int32(timestamp), dateTimeFormat: item.dateTimeFormat)
var subtitle = timeString
if let distance = item.distance {
let distanceString = item.presentationData.strings.Map_DistanceAway(stringForDistance(strings: item.presentationData.strings, distance: distance)).0
subtitle = "\(timeString)\(distanceString)"
}
let subtitleAttributedString = NSAttributedString(string: subtitle, font: subtitleFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor)
let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: subtitleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 54.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let titleSpacing: CGFloat = 1.0
let bottomInset: CGFloat = hasSeparator ? 0.0 : 4.0
let contentSize = CGSize(width: params.width, height: verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height + bottomInset)
let contentSize = CGSize(width: params.width, height: verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height)
let nodeLayout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets())
return (nodeLayout, { [weak self] in
@ -168,7 +195,7 @@ final class LocationLiveListItemNode: ListViewItemNode {
updatedTheme = item.presentationData.theme
}
return (nil, { _ in
return (self?.avatarNode.ready, { _ in
if let strongSelf = self {
strongSelf.item = item
strongSelf.layoutParams = params
@ -199,32 +226,41 @@ final class LocationLiveListItemNode: ListViewItemNode {
let separatorHeight = UIScreenPixel
let topHighlightInset: CGFloat = separatorHeight
let avatarSize: CGFloat = 40.0
// let iconNodeFrame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: floorToScreenPixels((contentSize.height - bottomInset - iconSize) / 2.0)), size: CGSize(width: iconSize, height: iconSize))
// strongSelf.iconNode.frame = iconNodeFrame
// strongSelf.venueIconNode.frame = iconNodeFrame
if let peer = item.message.author {
strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: nil, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: false)
}
strongSelf.avatarNode.frame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: floorToScreenPixels((contentSize.height - avatarSize) / 2.0)), size: CGSize(width: avatarSize, height: avatarSize))
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: contentSize.width, height: contentSize.height))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top - topHighlightInset), size: CGSize(width: contentSize.width, height: contentSize.height + topHighlightInset))
strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: leftInset, y: nodeLayout.contentSize.height - separatorHeight), size: CGSize(width: nodeLayout.size.width, height: separatorHeight))
strongSelf.separatorNode.isHidden = !hasSeparator
// if let (beginTimestamp, timeout) = item.beginTimeAndTimeout {
// let timerNode: ChatMessageLiveLocationTimerNode
// if let current = strongSelf.timerNode {
// timerNode = current
// } else {
// timerNode = ChatMessageLiveLocationTimerNode()
// strongSelf.addSubnode(timerNode)
// strongSelf.timerNode = timerNode
// }
// let timerSize = CGSize(width: 28.0, height: 28.0)
// timerNode.update(backgroundColor: item.presentationData.theme.list.itemAccentColor.withAlphaComponent(0.4), foregroundColor: item.presentationData.theme.list.itemAccentColor, textColor: item.presentationData.theme.list.itemAccentColor, beginTimestamp: beginTimestamp, timeout: timeout, strings: item.presentationData.strings)
// timerNode.frame = CGRect(origin: CGPoint(x: contentSize.width - 16.0 - timerSize.width, y: floorToScreenPixels((contentSize.height - timerSize.height) / 2.0) - 2.0), size: timerSize)
// } else if let timerNode = strongSelf.timerNode {
// strongSelf.timerNode = nil
// timerNode.removeFromSupernode()
// }
var liveBroadcastingTimeout: Int32 = 0
if let location = getLocation(from: item.message), let timeout = location.liveBroadcastingTimeout {
liveBroadcastingTimeout = timeout
}
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
if currentTimestamp < item.message.timestamp + liveBroadcastingTimeout {
let timerNode: ChatMessageLiveLocationTimerNode
if let current = strongSelf.timerNode {
timerNode = current
} else {
timerNode = ChatMessageLiveLocationTimerNode()
strongSelf.addSubnode(timerNode)
strongSelf.timerNode = timerNode
}
let timerSize = CGSize(width: 28.0, height: 28.0)
timerNode.update(backgroundColor: item.presentationData.theme.list.itemAccentColor.withAlphaComponent(0.4), foregroundColor: item.presentationData.theme.list.itemAccentColor, textColor: item.presentationData.theme.list.itemAccentColor, beginTimestamp: Double(item.message.timestamp), timeout: Double(liveBroadcastingTimeout), strings: item.presentationData.strings)
timerNode.frame = CGRect(origin: CGPoint(x: contentSize.width - 16.0 - timerSize.width, y: floorToScreenPixels((contentSize.height - timerSize.height) / 2.0)), size: timerSize)
} else if let timerNode = strongSelf.timerNode {
strongSelf.timerNode = nil
timerNode.removeFromSupernode()
}
}
})
})

View File

@ -548,7 +548,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
subscriber.putCompletion()
return EmptyDisposable
}
let annotationsPoll = (poll |> then(.complete() |> delay(3.0, queue: Queue.concurrentDefaultQueue()))) |> restart
let annotationsPoll = (poll |> then(.complete() |> delay(1.0, queue: Queue.concurrentDefaultQueue()))) |> restart
return combineLatest(self.userLocation, annotationsPoll)
|> map { userLocation, annotations -> [Double] in
@ -758,7 +758,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
if let zoomRect = zoomRect {
let insets = UIEdgeInsets(top: 0.0, left: 80.0, bottom: 0.0, right: 80.0)
let insets = UIEdgeInsets(top: 88.0, left: 80.0, bottom: 160.0, right: 80.0)
let fittedZoomRect = mapView.mapRectThatFits(zoomRect, edgePadding: insets)
mapView.setVisibleMapRect(fittedZoomRect, animated: animated)
}

View File

@ -884,6 +884,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
let optionsFrame = CGRect(x: 0.0, y: optionsOffset, width: layout.size.width, height: optionsHeight)
transition.updateFrame(node: self.optionsNode, frame: optionsFrame)
self.optionsNode.updateLayout(size: optionsFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: transition)
self.optionsNode.isUserInteractionEnabled = self.state.displayingMapModeOptions
if let searchContainerNode = self.searchContainerNode {
searchContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)

View File

@ -11,6 +11,7 @@ import ItemListUI
import ItemListVenueItem
import TelegramPresentationData
import TelegramStringFormatting
import TelegramUIPreferences
import TelegramNotices
import AccountContext
import AppBundle
@ -48,7 +49,7 @@ private enum LocationViewEntryId: Hashable {
private enum LocationViewEntry: Comparable, Identifiable {
case info(PresentationTheme, TelegramMediaMap, String?, Double?, Double?)
case toggleLiveLocation(PresentationTheme, String, String, CLLocationCoordinate2D?, Double?, Double?)
case liveLocation(PresentationTheme, Message, Double?, Int)
case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, Message, Double?, Int)
var stableId: LocationViewEntryId {
switch self {
@ -56,7 +57,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
return .info
case .toggleLiveLocation:
return .toggleLiveLocation
case let .liveLocation(_, message, _, _):
case let .liveLocation(_, _, _, message, _, _):
return .liveLocation(message.stableId)
}
}
@ -75,8 +76,8 @@ private enum LocationViewEntry: Comparable, Identifiable {
} else {
return false
}
case let .liveLocation(lhsTheme, lhsMessage, lhsDistance, lhsIndex):
if case let .liveLocation(rhsTheme, rhsMessage, rhsDistance, rhsIndex) = rhs, lhsTheme === rhsTheme, areMessagesEqual(lhsMessage, rhsMessage), lhsDistance == rhsDistance, lhsIndex == rhsIndex {
case let .liveLocation(lhsTheme, lhsDateTimeFormat, lhsNameDisplayOrder, lhsMessage, lhsDistance, lhsIndex):
if case let .liveLocation(rhsTheme, rhsDateTimeFormat, rhsNameDisplayOrder, rhsMessage, rhsDistance, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameDisplayOrder == rhsNameDisplayOrder, areMessagesEqual(lhsMessage, rhsMessage), lhsDistance == rhsDistance, lhsIndex == rhsIndex {
return true
} else {
return false
@ -100,17 +101,17 @@ private enum LocationViewEntry: Comparable, Identifiable {
case .liveLocation:
return true
}
case let .liveLocation(_, _, _, lhsIndex):
case let .liveLocation(_, _, _, _, _, lhsIndex):
switch rhs {
case .info, .toggleLiveLocation:
return false
case let .liveLocation(_, _, _, rhsIndex):
case let .liveLocation(_, _, _, _, _, rhsIndex):
return lhsIndex < rhsIndex
}
}
}
func item(account: Account, presentationData: PresentationData, interaction: LocationViewInteraction?) -> ListViewItem {
func item(context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?) -> ListViewItem {
switch self {
case let .info(_, location, address, distance, time):
let addressString: String?
@ -126,7 +127,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
distanceString = nil
}
let eta = time.flatMap { stringForEstimatedDuration(strings: presentationData.strings, eta: $0) }
return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), account: account, location: location, address: addressString, distance: distanceString, eta: eta, action: {
return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), account: context.account, location: location, address: addressString, distance: distanceString, eta: eta, action: {
interaction?.goToCoordinate(location.coordinate)
}, getDirections: {
interaction?.requestDirections()
@ -138,7 +139,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
} else {
beginTimeAndTimeout = nil
}
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), account: account, title: title, subtitle: subtitle, icon: beginTimeAndTimeout != nil ? .stopLiveLocation : .liveLocation, beginTimeAndTimeout: beginTimeAndTimeout, action: {
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), account: context.account, title: title, subtitle: subtitle, icon: beginTimeAndTimeout != nil ? .stopLiveLocation : .liveLocation, beginTimeAndTimeout: beginTimeAndTimeout, action: {
if beginTimeAndTimeout != nil {
interaction?.stopLiveLocation()
} else if let coordinate = coordinate {
@ -147,24 +148,18 @@ private enum LocationViewEntry: Comparable, Identifiable {
}, highlighted: { highlight in
interaction?.updateSendActionHighlight(highlight)
})
case let .liveLocation(_, message, distance, _):
let distanceString: String?
if let distance = distance {
distanceString = distance < 10 ? presentationData.strings.Map_YouAreHere : presentationData.strings.Map_DistanceAway(stringForDistance(strings: presentationData.strings, distance: distance)).0
} else {
distanceString = nil
}
return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), account: account, message: message, distance: distance, action: {}, longTapAction: {})
case let .liveLocation(_, dateTimeFormat, nameDisplayOrder, message, distance, _):
return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: context, message: message, distance: distance, action: {}, longTapAction: {})
}
}
}
private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntries: [LocationViewEntry], account: Account, presentationData: PresentationData, interaction: LocationViewInteraction?) -> LocationViewTransaction {
private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntries: [LocationViewEntry], context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?) -> LocationViewTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
return LocationViewTransaction(deletions: deletions, insertions: insertions, updates: updates)
}
@ -207,7 +202,6 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
private var disposable: Disposable?
private var state: LocationViewState
private let statePromise: Promise<LocationViewState>
private var geocodingDisposable = MetaDisposable()
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
private var listOffset: CGFloat?
@ -276,7 +270,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
return messages
}
setupProximityNotificationImpl = { reset in
setupProximityNotificationImpl = { [weak self] reset in
let _ = (liveLocations
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] messages in
@ -369,7 +363,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
timeout = nil
}
entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, userLocation?.coordinate, beginTime, timeout))
if let channel = subject.author as? TelegramChannel, case .broadcast = channel.info, activeOwnLiveLocation == nil {
} else {
entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, userLocation?.coordinate, beginTime, timeout))
}
var sortedLiveLocations: [Message] = []
@ -390,6 +387,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
}
for message in effectiveLiveLocations {
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info, message.threadId != nil {
continue
}
var liveBroadcastingTimeout: Int32 = 0
if let location = getLocation(from: message), let timeout = location.liveBroadcastingTimeout {
liveBroadcastingTimeout = timeout
@ -401,12 +402,12 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
let subjectLocation = CLLocation(latitude: location.latitude, longitude: location.longitude)
let distance = userLocation.flatMap { subjectLocation.distance(from: $0) }
// entries.append(.liveLocation(presentationData.theme, message, distance, index))
if message.localTags.contains(.OutgoingLiveLocation), let selfPeer = selfPeer {
userAnnotation = LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, heading: location.heading)
} else {
annotations.append(LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, heading: location.heading))
entries.append(.liveLocation(presentationData.theme, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, message, distance, index))
}
index += 1
}
@ -414,11 +415,14 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
if subject.id.peerId.namespace != Namespaces.Peer.CloudUser, proximityNotification == nil {
proximityNotification = false
}
if let channel = subject.author as? TelegramChannel, case .broadcast = channel.info {
proximityNotification = nil
}
let previousEntries = previousEntries.swap(entries)
let previousState = previousState.swap(state)
let transition = preparedTransition(from: previousEntries ?? [], to: entries, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction)
let transition = preparedTransition(from: previousEntries ?? [], to: entries, context: context, presentationData: presentationData, interaction: strongSelf.interaction)
strongSelf.enqueueTransition(transition)
strongSelf.headerNode.updateState(mapMode: state.mapMode, trackingMode: state.trackingMode, displayingMapModeOptions: state.displayingMapModeOptions, displayingPlacesButton: false, proximityNotification: proximityNotification, animated: false)
@ -535,7 +539,6 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
deinit {
self.disposable?.dispose()
self.geocodingDisposable.dispose()
self.locationManager.manager.stopUpdatingHeading()
}
@ -692,5 +695,6 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
let optionsFrame = CGRect(x: 0.0, y: optionsOffset, width: layout.size.width, height: optionsHeight)
transition.updateFrame(node: self.optionsNode, frame: optionsFrame)
self.optionsNode.updateLayout(size: optionsFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: transition)
self.optionsNode.isUserInteractionEnabled = self.state.displayingMapModeOptions
}
}

View File

@ -67,7 +67,7 @@ struct PasscodeKeyboardLayout {
self.topOffset = 226.0
self.biometricsOffset = 30.0
self.deleteOffset = 20.0
case .iPhoneX:
case .iPhoneX, .iPhone12Mini, .iPhone12:
self.buttonSize = 75.0
self.horizontalSecond = 103.0
self.horizontalThird = 206.0
@ -78,7 +78,7 @@ struct PasscodeKeyboardLayout {
self.topOffset = 294.0
self.biometricsOffset = 30.0
self.deleteOffset = 20.0
case .iPhoneXSMax:
case .iPhoneXSMax, .iPhone12ProMax:
self.buttonSize = 85.0
self.horizontalSecond = 115.0
self.horizontalThird = 230.0
@ -151,11 +151,11 @@ public struct PasscodeLayout {
self.titleOffset = 112.0
self.subtitleOffset = -6.0
self.inputFieldOffset = 156.0
case .iPhoneX:
case .iPhoneX, .iPhone12Mini, .iPhone12:
self.titleOffset = 162.0
self.subtitleOffset = 0.0
self.inputFieldOffset = 206.0
case .iPhoneXSMax:
case .iPhoneXSMax, .iPhone12ProMax:
self.titleOffset = 180.0
self.subtitleOffset = 0.0
self.inputFieldOffset = 226.0

View File

@ -2465,8 +2465,8 @@ public func chatWebFileImage(account: Account, file: TelegramMediaWebFile) -> Si
private let precomposedSmallAlbumArt = Atomic<UIImage?>(value: nil)
private func albumArtThumbnailData(postbox: Postbox, thumbnail: MediaResource) -> Signal<Data?, NoError> {
let thumbnailResource = postbox.mediaBox.resourceData(thumbnail)
private func albumArtThumbnailData(postbox: Postbox, thumbnail: MediaResource, attemptSynchronously: Bool = false) -> Signal<Data?, NoError> {
let thumbnailResource = postbox.mediaBox.resourceData(thumbnail, attemptSynchronously: attemptSynchronously)
let signal = thumbnailResource |> take(1) |> mapToSignal { maybeData -> Signal<Data?, NoError> in
if maybeData.complete {
@ -2602,7 +2602,7 @@ private func drawAlbumArtPlaceholder(into c: CGContext, arguments: TransformImag
}
}
public func playerAlbumArt(postbox: Postbox, fileReference: FileMediaReference?, albumArt: SharedMediaPlaybackAlbumArt?, thumbnail: Bool, overlayColor: UIColor? = nil, emptyColor: UIColor? = nil, drawPlaceholderWhenEmpty: Bool = true) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
public func playerAlbumArt(postbox: Postbox, fileReference: FileMediaReference?, albumArt: SharedMediaPlaybackAlbumArt?, thumbnail: Bool, overlayColor: UIColor? = nil, emptyColor: UIColor? = nil, drawPlaceholderWhenEmpty: Bool = true, attemptSynchronously: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
var fileArtworkData: Signal<Data?, NoError> = .single(nil)
if let fileReference = fileReference {
let size = thumbnail ? CGSize(width: 48.0, height: 48.0) : CGSize(width: 320.0, height: 320.0)
@ -2628,7 +2628,7 @@ public func playerAlbumArt(postbox: Postbox, fileReference: FileMediaReference?,
let thumbnail = Signal<Data?, NoError> { subscriber in
let fetchedDisposable = fetchedThumbnail.start()
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource).start(next: { next in
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource, attemptSynchronously: attemptSynchronously).start(next: { next in
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
}, error: subscriber.putError, completed: subscriber.putCompletion)
@ -2643,7 +2643,7 @@ public func playerAlbumArt(postbox: Postbox, fileReference: FileMediaReference?,
}
} else if let albumArt = albumArt {
if thumbnail {
immediateArtworkData = albumArtThumbnailData(postbox: postbox, thumbnail: albumArt.thumbnailResource)
immediateArtworkData = albumArtThumbnailData(postbox: postbox, thumbnail: albumArt.thumbnailResource, attemptSynchronously: attemptSynchronously)
|> map { thumbnailData in
return Tuple(thumbnailData, nil, false)
}

View File

@ -591,8 +591,8 @@ private final class SemanticStatusNodeAppearanceContext {
self.cutout = cutout
}
func drawingState(transitionFraction: CGFloat) -> SemanticStatusNodeAppearanceDrawingState {
return SemanticStatusNodeAppearanceDrawingState(transitionFraction: transitionFraction, background: self.background, foreground: self.foreground, backgroundImage: self.backgroundImage, overlayForeground: self.overlayForeground, cutout: self.cutout)
func drawingState(backgroundTransitionFraction: CGFloat, foregroundTransitionFraction: CGFloat) -> SemanticStatusNodeAppearanceDrawingState {
return SemanticStatusNodeAppearanceDrawingState(backgroundTransitionFraction: backgroundTransitionFraction, foregroundTransitionFraction: foregroundTransitionFraction, background: self.background, foreground: self.foreground, backgroundImage: self.backgroundImage, overlayForeground: self.overlayForeground, cutout: self.cutout)
}
func withUpdatedBackground(_ background: UIColor) -> SemanticStatusNodeAppearanceContext {
@ -617,7 +617,8 @@ private final class SemanticStatusNodeAppearanceContext {
}
private final class SemanticStatusNodeAppearanceDrawingState {
let transitionFraction: CGFloat
let backgroundTransitionFraction: CGFloat
let foregroundTransitionFraction: CGFloat
let background: UIColor
let foreground: UIColor
let backgroundImage: UIImage?
@ -632,8 +633,9 @@ private final class SemanticStatusNodeAppearanceDrawingState {
}
}
init(transitionFraction: CGFloat, background: UIColor, foreground: UIColor, backgroundImage: UIImage?, overlayForeground: UIColor?, cutout: CGRect?) {
self.transitionFraction = transitionFraction
init(backgroundTransitionFraction: CGFloat, foregroundTransitionFraction: CGFloat, background: UIColor, foreground: UIColor, backgroundImage: UIImage?, overlayForeground: UIColor?, cutout: CGRect?) {
self.backgroundTransitionFraction = backgroundTransitionFraction
self.foregroundTransitionFraction = foregroundTransitionFraction
self.background = background
self.foreground = foreground
self.backgroundImage = backgroundImage
@ -644,11 +646,12 @@ private final class SemanticStatusNodeAppearanceDrawingState {
func drawBackground(context: CGContext, size: CGSize) {
let bounds = CGRect(origin: CGPoint(), size: size)
context.setBlendMode(.normal)
if let backgroundImage = self.backgroundImage?.cgImage {
context.saveGState()
context.translateBy(x: 0.0, y: bounds.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setAlpha(self.transitionFraction)
context.setAlpha(self.backgroundTransitionFraction)
context.draw(backgroundImage, in: bounds)
context.restoreGState()
} else {
@ -659,7 +662,7 @@ private final class SemanticStatusNodeAppearanceDrawingState {
func drawForeground(context: CGContext, size: CGSize) {
if let cutout = self.cutout {
let size = CGSize(width: cutout.width * self.transitionFraction, height: cutout.height * self.transitionFraction)
let size = CGSize(width: cutout.width * self.foregroundTransitionFraction, height: cutout.height * self.foregroundTransitionFraction)
let rect = CGRect(origin: CGPoint(x: cutout.midX - size.width / 2.0, y: cutout.midY - size.height / 2.0), size: size)
context.setBlendMode(.clear)
@ -740,13 +743,23 @@ public final class SemanticStatusNode: ASControlNode {
return self.appearanceContext.cutout
}
set {
if self.appearanceContext.cutout != newValue {
self.transitionContext = SemanticStatusNodeTransitionContext(startTime: CACurrentMediaTime(), duration: 0.18, previousStateContext: nil, previousAppearanceContext: self.appearanceContext, completion: {})
self.appearanceContext = self.appearanceContext.withUpdatedCutout(newValue)
self.updateAnimations()
self.setNeedsDisplay()
}
self.setCutout(newValue, animated: false)
}
}
public func setCutout(_ cutout: CGRect?, animated: Bool) {
guard cutout != self.appearanceContext.cutout else {
return
}
if animated {
self.transitionContext = SemanticStatusNodeTransitionContext(startTime: CACurrentMediaTime(), duration: 0.2, previousStateContext: nil, previousAppearanceContext: self.appearanceContext, completion: {})
self.appearanceContext = self.appearanceContext.withUpdatedCutout(cutout)
self.updateAnimations()
self.setNeedsDisplay()
} else {
self.appearanceContext = self.appearanceContext.withUpdatedCutout(cutout)
self.setNeedsDisplay()
}
}
@ -783,7 +796,7 @@ public final class SemanticStatusNode: ASControlNode {
let previousAppearanceContext = strongSelf.appearanceContext
strongSelf.appearanceContext = strongSelf.appearanceContext.withUpdatedBackgroundImage(context?.generateImage())
if CACurrentMediaTime() - start > 0.2 {
if CACurrentMediaTime() - start > 0.3 {
strongSelf.transitionContext = SemanticStatusNodeTransitionContext(startTime: CACurrentMediaTime(), duration: 0.18, previousStateContext: nil, previousAppearanceContext: previousAppearanceContext, completion: {})
strongSelf.updateAnimations()
}
@ -858,7 +871,8 @@ public final class SemanticStatusNode: ASControlNode {
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
var transitionState: SemanticStatusNodeTransitionDrawingState?
var transitionFraction: CGFloat = 1.0
var appearanceTransitionFraction: CGFloat = 1.0
var appearanceBackgroundTransitionFraction: CGFloat = 1.0
var appearanceForegroundTransitionFraction: CGFloat = 1.0
if let transitionContext = self.transitionContext {
let timestamp = CACurrentMediaTime()
@ -868,13 +882,20 @@ public final class SemanticStatusNode: ASControlNode {
if let _ = transitionContext.previousStateContext {
transitionFraction = t
}
if let _ = transitionContext.previousAppearanceContext {
appearanceTransitionFraction = t
var foregroundTransitionFraction: CGFloat = 1.0
if let previousContext = transitionContext.previousAppearanceContext {
if previousContext.backgroundImage != self.appearanceContext.backgroundImage {
appearanceBackgroundTransitionFraction = t
}
if previousContext.cutout != self.appearanceContext.cutout {
appearanceForegroundTransitionFraction = t
foregroundTransitionFraction = 1.0 - t
}
}
transitionState = SemanticStatusNodeTransitionDrawingState(transition: t, drawingState: transitionContext.previousStateContext?.drawingState(transitionFraction: 1.0 - t), appearanceState: transitionContext.previousAppearanceContext?.drawingState(transitionFraction: 1.0 - t))
transitionState = SemanticStatusNodeTransitionDrawingState(transition: t, drawingState: transitionContext.previousStateContext?.drawingState(transitionFraction: 1.0 - t), appearanceState: transitionContext.previousAppearanceContext?.drawingState(backgroundTransitionFraction: 1.0, foregroundTransitionFraction: foregroundTransitionFraction))
}
return SemanticStatusNodeDrawingState(transitionState: transitionState, drawingState: self.stateContext.drawingState(transitionFraction: transitionFraction), appearanceState: self.appearanceContext.drawingState(transitionFraction: appearanceTransitionFraction))
return SemanticStatusNodeDrawingState(transitionState: transitionState, drawingState: self.stateContext.drawingState(transitionFraction: transitionFraction), appearanceState: self.appearanceContext.drawingState(backgroundTransitionFraction: appearanceBackgroundTransitionFraction, foregroundTransitionFraction: appearanceForegroundTransitionFraction))
}
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {

View File

@ -738,12 +738,12 @@ private enum DebugControllerEntry: ItemListNodeEntry {
})
case .voiceConference:
return ItemListDisclosureItem(presentationData: presentationData, title: "Voice Conference (Test)", label: "", sectionId: self.section, style: .blocks, action: {
guard let context = arguments.context else {
/*guard let context = arguments.context else {
return
}
let controller = GroupCallController(context: context)
controller.navigationPresentation = .modal
arguments.pushController(controller)
arguments.pushController(controller)*/
})
case let .preferredVideoCodec(_, title, value, isSelected):
return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .right, checked: isSelected, zeroSeparatorInsets: false, sectionId: self.section, action: {
@ -824,7 +824,7 @@ private func debugControllerEntries(presentationData: PresentationData, loggingS
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))
entries.append(.voiceConference)
//entries.append(.voiceConference)
let codecs: [(String, String?)] = [
("No Preference", nil),

View File

@ -1924,42 +1924,6 @@ public func settingsController(context: AccountContext, accountManager: AccountM
updateNotifyExceptions()
updateActiveSessions()
}
controller.previewItemWithTag = { tag in
if let tag = tag as? SettingsEntryTag, case let .account(id) = tag {
var selectedAccount: Account?
let _ = (accountsAndPeers.get()
|> take(1)
|> deliverOnMainQueue).start(next: { accountsAndPeers in
for (account, _, _) in accountsAndPeers.1 {
if account.id == id {
selectedAccount = account
break
}
}
})
var sharedContext: SharedAccountContext?
let _ = (contextValue.get()
|> deliverOnMainQueue
|> take(1)).start(next: { context in
sharedContext = context.sharedContext
})
if let selectedAccount = selectedAccount, let sharedContext = sharedContext {
let accountContext = sharedContext.makeTempAccountContext(account: selectedAccount)
let chatListController = accountContext.sharedContext.makeChatListController(context: accountContext, groupId: .root, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: enableDebugActions)
return chatListController
}
}
return nil
}
controller.commitPreview = { previewController in
if let chatListController = previewController as? ChatListController {
let _ = (contextValue.get()
|> deliverOnMainQueue
|> take(1)).start(next: { context in
context.sharedContext.switchToAccount(id: chatListController.context.account.id, fromSettingsController: nil, withChatListController: chatListController)
})
}
}
controller.switchToAccount = { id in
let _ = (contextValue.get()
|> take(1)

View File

@ -385,8 +385,8 @@ public func themeAutoNightSettingsController(context: AccountContext) -> ViewCon
let forceUpdateLocation: () -> Void = {
let locationCoordinates = Signal<(Double, Double), NoError> { subscriber in
return context.sharedContext.locationManager!.push(mode: DeviceLocationMode.precise, updated: { coordinate, _, _ in
subscriber.putNext((coordinate.latitude, coordinate.longitude))
return context.sharedContext.locationManager!.push(mode: DeviceLocationMode.precise, updated: { location, _ in
subscriber.putNext((location.coordinate.latitude, location.coordinate.longitude))
subscriber.putCompletion()
})
}

View File

@ -135,16 +135,15 @@ private enum StatsEntry: ItemListNodeEntry {
})
}, sectionId: self.section, style: .blocks)
case let .publicForward(_, _, _, _, message):
var views: Int = 0
var views: Int32 = 0
for attribute in message.attributes {
if let viewsAttribute = attribute as? ViewCountMessageAttribute {
views = viewsAttribute.count
views = Int32(viewsAttribute.count)
break
}
}
var text: String = ""
text += "\(views) views"
let text: String = presentationData.strings.Stats_MessageViews(views)
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .military, dateFormat: .dayFirst, dateSeparator: ".", decimalSeparator: ",", groupingSeparator: ""), nameDisplayOrder: .firstLast, context: arguments.context, peer: message.peers[message.id.peerId]!, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(text), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: {
arguments.openMessage(message.id)
}, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil)
@ -161,7 +160,17 @@ private func messageStatsControllerEntries(data: MessageStats?, messages: Search
if !data.interactionsGraph.isEmpty {
entries.append(.interactionsTitle(presentationData.theme, presentationData.strings.Stats_MessageInteractionsTitle.uppercased()))
entries.append(.interactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.interactionsGraph, .twoAxisStep))
var chartType: ChartType
if data.interactionsGraphDelta == 3600 {
chartType = .twoAxisHourlyStep
} else if data.interactionsGraphDelta == 300 {
chartType = .twoAxis5MinStep
} else {
chartType = .twoAxisStep
}
entries.append(.interactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.interactionsGraph, chartType))
}
if let messages = messages, !messages.messages.isEmpty {

View File

@ -168,11 +168,11 @@ class MessageStatsOverviewItemNode: ListViewItemNode {
rightValueLabelLayoutAndApply = makeRightValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.publicShares.flatMap { "\( compactNumericCountString(item.stats.forwards - Int($0)))" } ?? "", font: valueFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
leftTitleLabelLayoutAndApply = makeLeftTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Views", font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
leftTitleLabelLayoutAndApply = makeLeftTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_Message_Views, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
centerTitleLabelLayoutAndApply = makeCenterTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Public Shares", font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
centerTitleLabelLayoutAndApply = makeCenterTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_Message_PublicShares, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
rightTitleLabelLayoutAndApply = makeRightTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Private Shares", font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
rightTitleLabelLayoutAndApply = makeRightTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_Message_PrivateShares, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
height += rightValueLabelLayoutAndApply!.0.size.height + rightTitleLabelLayoutAndApply!.0.size.height
@ -257,7 +257,7 @@ class MessageStatsOverviewItemNode: ListViewItemNode {
let horizontalSpacing = min(60, (params.width - leftInset - rightInset - sideInset * 2.0 - maxLeftWidth - maxCenterWidth - maxRightWidth) / 2.0)
var x: CGFloat = leftInset + (params.width - maxLeftWidth - maxCenterWidth - maxRightWidth - horizontalSpacing * 2.0) / 2.0
var x: CGFloat = leftInset + (params.width - leftInset - rightInset - maxLeftWidth - maxCenterWidth - maxRightWidth - horizontalSpacing * 2.0) / 2.0
if let leftValueLabelLayout = leftValueLabelLayoutAndApply?.0, let leftTitleLabelLayout = leftTitleLabelLayoutAndApply?.0 {
strongSelf.leftValueLabel.frame = CGRect(origin: CGPoint(x: x, y: topInset), size: leftValueLabelLayout.size)
strongSelf.leftTitleLabel.frame = CGRect(origin: CGPoint(x: x, y: strongSelf.leftValueLabel.frame.maxY), size: leftTitleLabelLayout.size)

View File

@ -10,7 +10,8 @@ import TelegramAudio
import AccountContext
public final class GroupCallController: ViewController {
private final class Node: ViewControllerTracingNode {
}
/* private final class Node: ViewControllerTracingNode {
private let context: AccountContext
private let presentationData: PresentationData
@ -145,3 +146,4 @@ public final class GroupCallController: ViewController {
self.controllerNode.containerLayoutUpdated(layout, transition: transition)
}
}
*/

View File

@ -2992,6 +2992,9 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
}
if upperId >= messageId.id {
transaction.addHole(peerId: messageId.peerId, namespace: messageId.namespace, space: .everywhere, range: messageId.id ... upperId)
transaction.addHole(peerId: messageId.peerId, namespace: messageId.namespace, space: .tag(.pinned), range: 1 ... upperId)
Logger.shared.log("State", "adding hole for peer \(messageId.peerId), \(messageId.id) ... \(upperId)")
} else {
Logger.shared.log("State", "not adding hole for peer \(messageId.peerId), \(upperId) >= \(messageId.id) = false")

View File

@ -416,6 +416,9 @@ private func hashForMessages(_ messages: [Message], withChannelIds: Bool) -> Int
break inner
}
}
if message.tags.contains(.pinned) {
acc = (acc &* 20261) &+ UInt32(1)
}
acc = (acc &* 20261) &+ UInt32(timestamp)
}
return Int32(bitPattern: acc & UInt32(0x7FFFFFFF))

View File

@ -139,7 +139,7 @@ private func requestActivity(postbox: Postbox, network: Network, accountPeerId:
break
case let .present(statusTimestamp):
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if statusTimestamp < timestamp {
if statusTimestamp < timestamp - 30 {
return .complete()
}
}

View File

@ -9,13 +9,13 @@ public struct MessageStats: Equatable {
public let views: Int
public let forwards: Int
public let interactionsGraph: StatsGraph
public let detailedInteractionsGraph: StatsGraph?
public let interactionsGraphDelta: Int64
init(views: Int, forwards: Int, interactionsGraph: StatsGraph, detailedInteractionsGraph: StatsGraph?) {
init(views: Int, forwards: Int, interactionsGraph: StatsGraph, interactionsGraphDelta: Int64) {
self.views = views
self.forwards = forwards
self.interactionsGraph = interactionsGraph
self.detailedInteractionsGraph = detailedInteractionsGraph
self.interactionsGraphDelta = interactionsGraphDelta
}
public static func == (lhs: MessageStats, rhs: MessageStats) -> Bool {
@ -28,14 +28,14 @@ public struct MessageStats: Equatable {
if lhs.interactionsGraph != rhs.interactionsGraph {
return false
}
if lhs.detailedInteractionsGraph != rhs.detailedInteractionsGraph {
if lhs.interactionsGraphDelta != rhs.interactionsGraphDelta {
return false
}
return true
}
public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> MessageStats {
return MessageStats(views: self.views, forwards: self.forwards, interactionsGraph: interactionsGraph, detailedInteractionsGraph: self.detailedInteractionsGraph)
return MessageStats(views: self.views, forwards: self.forwards, interactionsGraph: interactionsGraph, interactionsGraphDelta: self.interactionsGraphDelta)
}
}
@ -86,16 +86,24 @@ private func requestMessageStats(postbox: Postbox, network: Network, datacenterI
|> mapToSignal { result -> Signal<MessageStats?, MTRpcError> in
if case let .messageStats(apiViewsGraph) = result {
let interactionsGraph = StatsGraph(apiStatsGraph: apiViewsGraph)
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if case let .Loaded(tokenValue, _) = interactionsGraph, let token = tokenValue, Int64(message.timestamp + 60 * 60 * 24 * 2) > Int64(timestamp) {
return requestGraph(network: network, datacenterId: datacenterId, token: token, x: 1601596800000)
|> castError(MTRpcError.self)
|> map { detailedGraph -> MessageStats? in
return MessageStats(views: views, forwards: forwards, interactionsGraph: interactionsGraph, detailedInteractionsGraph: detailedGraph)
var interactionsGraphDelta: Int64 = 86400
if case let .Loaded(_, data) = interactionsGraph {
if let start = data.range(of: "[\"x\",") {
let substring = data.suffix(from: start.upperBound)
if let end = substring.range(of: "],") {
let valuesString = substring.prefix(through: substring.index(before: end.lowerBound))
let values = valuesString.components(separatedBy: ",").compactMap { Int64($0) }
if values.count > 1 {
let first = values[0]
let second = values[1]
let delta = abs(second - first) / 1000
interactionsGraphDelta = delta
}
}
}
} else {
return .single(MessageStats(views: views, forwards: forwards, interactionsGraph: interactionsGraph, detailedInteractionsGraph: nil))
}
return .single(MessageStats(views: views, forwards: forwards, interactionsGraph: interactionsGraph, interactionsGraphDelta: interactionsGraphDelta))
} else {
return .single(nil)
}

View File

@ -302,6 +302,32 @@ public struct ApplicationSpecificNotice {
}
}
public static func inlineBotLocationRequestStatus(accountManager: AccountManager, peerId: PeerId) -> Signal<Bool, NoError> {
return accountManager.noticeEntry(key: ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId))
|> map { view -> Bool in
guard let value = view.value as? ApplicationSpecificTimestampNotice else {
return false
}
if value.value == 0 {
return true
} else {
return false
}
}
}
public static func updateInlineBotLocationRequestState(accountManager: AccountManager, peerId: PeerId, timestamp: Int32) -> Signal<Bool, NoError> {
return accountManager.transaction { transaction -> Bool in
if let notice = transaction.getNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId)) as? ApplicationSpecificTimestampNotice, (notice.value == 0 || timestamp <= notice.value + 10 * 60) {
return false
}
transaction.setNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId), ApplicationSpecificTimestampNotice(value: timestamp))
return true
}
}
public static func setInlineBotLocationRequest(accountManager: AccountManager, peerId: PeerId, value: Int32) -> Signal<Void, NoError> {
return accountManager.transaction { transaction -> Void in
transaction.setNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId), ApplicationSpecificTimestampNotice(value: value))

View File

@ -442,12 +442,12 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
attributedString = addAttributesToStringWithRanges(strings.Notification_Joined(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
case .phoneNumberRequest:
attributedString = nil
case let .geoProximityReached(_, toId, distance):
case let .geoProximityReached(fromId, toId, distance):
let distanceString = stringForDistance(strings: strings, distance: Double(distance))
if toId == accountPeerId {
attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReachedYou(authorName, distanceString), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReachedYou(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId)]))
} else {
attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReached(authorName, distanceString, message.peers[toId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id), (2, toId)]))
attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReached(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString, message.peers[toId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId), (2, toId)]))
}
case .unknown:
attributedString = nil

View File

@ -8,25 +8,6 @@ import ContextUI
private let normalFont = avatarPlaceholderFont(size: 16.0)
private let smallFont = avatarPlaceholderFont(size: 12.0)
final class ChatAvatarNavigationNodeView: UIView, PreviewingHostView {
var previewingDelegate: PreviewingHostViewDelegate? {
return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in
return self?.chatController?.avatarPreviewingController(from: sourceView)
}, commitController: { [weak self] controller in
self?.chatController?.previewingCommit(controller)
})
}
weak var chatController: ChatControllerImpl?
weak var targetNode: ChatAvatarNavigationNode?
override func layoutSubviews() {
super.layoutSubviews()
self.targetNode?.onLayout()
}
}
final class ChatAvatarNavigationNode: ASDisplayNode {
private let containerNode: ContextControllerSourceNode
let avatarNode: AvatarNode
@ -40,14 +21,6 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
}
}
weak var chatController: ChatControllerImpl? {
didSet {
if self.isNodeLoaded {
(self.view as? ChatAvatarNavigationNodeView)?.chatController = self.chatController
}
}
}
var tapped: (() -> Void)?
override init() {
@ -56,10 +29,6 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
super.init()
self.setViewBlock({
return ChatAvatarNavigationNodeView()
})
self.containerNode.addSubnode(self.avatarNode)
self.addSubnode(self.containerNode)
@ -80,11 +49,6 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
override func didLoad() {
super.didLoad()
self.view.isOpaque = false
(self.view as? ChatAvatarNavigationNodeView)?.targetNode = self
(self.view as? ChatAvatarNavigationNodeView)?.chatController = self.chatController
/*let tapRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.avatarTapGesture(_:)))
self.avatarNode.view.addGestureRecognizer(tapRecognizer)*/
}
@objc private func avatarTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {

View File

@ -2341,7 +2341,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
switch chatLocation {
case .peer, .replyThread:
let avatarNode = ChatAvatarNavigationNode()
avatarNode.chatController = self
avatarNode.contextAction = { [weak self] node, gesture in
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil else {
return
@ -6569,7 +6568,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let inputTextPanelState = inputTextPanelStateForChatPresentationInterfaceState(temporaryChatPresentationInterfaceState, context: self.context)
var updatedChatPresentationInterfaceState = temporaryChatPresentationInterfaceState.updatedInputTextPanelState({ _ in return inputTextPanelState })
let contextQueryUpdates = contextQueryResultStateForChatInterfacePresentationState(updatedChatPresentationInterfaceState, context: self.context, currentQueryStates: &self.contextQueryStates)
let contextQueryUpdates = contextQueryResultStateForChatInterfacePresentationState(updatedChatPresentationInterfaceState, context: self.context, currentQueryStates: &self.contextQueryStates, requestBotLocationStatus: { [weak self] peerId in
guard let strongSelf = self else {
return
}
let _ = (ApplicationSpecificNotice.updateInlineBotLocationRequestState(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peerId, timestamp: Int32(Date().timeIntervalSince1970 + 10 * 60))
|> deliverOnMainQueue).start(next: { value in
guard let strongSelf = self, value else {
return
}
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Conversation_ShareInlineBotLocationConfirmation, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
let _ = ApplicationSpecificNotice.setInlineBotLocationRequest(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peerId, value: 0).start()
})]), in: .window(.root))
})
})
for (kind, update) in contextQueryUpdates {
switch update {
@ -7858,6 +7871,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let selfPeerId: PeerId
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
selfPeerId = peer.id
} else if let peer = peer as? TelegramChannel, case .group = peer.info, peer.hasPermission(.canBeAnonymous) {
selfPeerId = peer.id
} else {
selfPeerId = self.context.account.peerId
}
@ -8306,6 +8321,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
controller.dismissWithCommitAction()
}
})
self.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitAction()
}
return true
})
let value: String?
let emoji = dice.emoji.strippedEmoji

View File

@ -24,20 +24,10 @@ final class VideoNavigationControllerDropContentItem: NavigationControllerDropCo
}
}
private final class ChatControllerNodeView: UITracingLayerView, WindowInputAccessoryHeightProvider, PreviewingHostView {
private final class ChatControllerNodeView: UITracingLayerView, WindowInputAccessoryHeightProvider {
var inputAccessoryHeight: (() -> CGFloat)?
var hitTestImpl: ((CGPoint, UIEvent?) -> UIView?)?
var previewingDelegate: PreviewingHostViewDelegate? {
return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in
return self?.controller?.previewingController(from: sourceView, for: point)
}, commitController: { [weak self] controller in
self?.controller?.previewingCommit(controller)
})
}
weak var controller: ChatControllerImpl?
func getWindowInputAccessoryHeight() -> CGFloat {
return self.inputAccessoryHeight?() ?? 0.0
}
@ -680,8 +670,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
return false
}
(self.view as? ChatControllerNodeView)?.controller = self.controller
self.displayVideoUnmuteTipDisposable = (combineLatest(queue: Queue.mainQueue(), ApplicationSpecificNotice.getVolumeButtonToUnmute(accountManager: self.context.sharedContext.accountManager), self.historyNode.hasVisiblePlayableItemNodes, self.historyNode.isInteractivelyScrolling)
|> mapToSignal { notice, hasVisiblePlayableItemNodes, isInteractivelyScrolling -> Signal<Bool, NoError> in
let display = !notice && hasVisiblePlayableItemNodes && !isInteractivelyScrolling

View File

@ -601,9 +601,18 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
var threadId: Int64?
var threadMessageCount: Int = 0
if case .peer = chatPresentationInterfaceState.chatLocation, let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .group = channel.info, let cachedData = cachedData as? CachedChannelData, case let .known(maybeValue) = cachedData.linkedDiscussionPeerId, let _ = maybeValue {
if let value = messages[0].threadId {
threadId = value
if case .peer = chatPresentationInterfaceState.chatLocation, let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .group = channel.info {
if let cachedData = cachedData as? CachedChannelData, case let .known(maybeValue) = cachedData.linkedDiscussionPeerId, let _ = maybeValue {
if let value = messages[0].threadId {
threadId = value
} else {
for attribute in messages[0].attributes {
if let attribute = attribute as? ReplyThreadMessageAttribute, attribute.count > 0 {
threadId = makeMessageThreadId(messages[0].id)
threadMessageCount = Int(attribute.count)
}
}
}
} else {
for attribute in messages[0].attributes {
if let attribute = attribute as? ReplyThreadMessageAttribute, attribute.count > 0 {
@ -612,13 +621,6 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
}
}
}
} else {
for attribute in messages[0].attributes {
if let attribute = attribute as? ReplyThreadMessageAttribute, attribute.count > 0 {
threadId = makeMessageThreadId(messages[0].id)
threadMessageCount = Int(attribute.count)
}
}
}
if let _ = threadId, !isPinnedMessages {
@ -853,7 +855,8 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
views = attribute.count
}
}
if views >= 100 {
if let cachedData = cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats), views >= 100 {
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextViewStats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in
@ -1139,7 +1142,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
if canDeleteGlobally {
optionsMap[id]!.insert(.deleteGlobally)
}
if user.botInfo != nil && !user.id.isReplies {
if user.botInfo != nil && !user.id.isReplies && !isAction {
optionsMap[id]!.insert(.report)
}
} else if let _ = peer as? TelegramSecretChat {

View File

@ -11,6 +11,7 @@ import AccountContext
import Emoji
import SearchPeerMembers
import DeviceLocationManager
import TelegramNotices
enum ChatContextQueryError {
case inlineBotLocationRequest(PeerId)
@ -21,7 +22,7 @@ enum ChatContextQueryUpdate {
case update(ChatPresentationInputQuery, Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, ChatContextQueryError>)
}
func contextQueryResultStateForChatInterfacePresentationState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentQueryStates: inout [ChatPresentationInputQueryKind: (ChatPresentationInputQuery, Disposable)]) -> [ChatPresentationInputQueryKind: ChatContextQueryUpdate] {
func contextQueryResultStateForChatInterfacePresentationState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentQueryStates: inout [ChatPresentationInputQueryKind: (ChatPresentationInputQuery, Disposable)], requestBotLocationStatus: @escaping (PeerId) -> Void) -> [ChatPresentationInputQueryKind: ChatContextQueryUpdate] {
guard let peer = chatPresentationInterfaceState.renderedPeer?.peer else {
return [:]
}
@ -43,7 +44,7 @@ func contextQueryResultStateForChatInterfacePresentationState(_ chatPresentation
for query in inputQueries {
let previousQuery = currentQueryStates[query.kind]?.0
if previousQuery != query {
let signal = updatedContextQueryResultStateForQuery(context: context, peer: peer, chatLocation: chatPresentationInterfaceState.chatLocation, inputQuery: query, previousQuery: previousQuery)
let signal = updatedContextQueryResultStateForQuery(context: context, peer: peer, chatLocation: chatPresentationInterfaceState.chatLocation, inputQuery: query, previousQuery: previousQuery, requestBotLocationStatus: requestBotLocationStatus)
updates[query.kind] = .update(query, signal)
}
}
@ -64,7 +65,7 @@ func contextQueryResultStateForChatInterfacePresentationState(_ chatPresentation
return updates
}
private func updatedContextQueryResultStateForQuery(context: AccountContext, peer: Peer, chatLocation: ChatLocation, inputQuery: ChatPresentationInputQuery, previousQuery: ChatPresentationInputQuery?) -> Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, ChatContextQueryError> {
private func updatedContextQueryResultStateForQuery(context: AccountContext, peer: Peer, chatLocation: ChatLocation, inputQuery: ChatPresentationInputQuery, previousQuery: ChatPresentationInputQuery?, requestBotLocationStatus: @escaping (PeerId) -> Void) -> Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, ChatContextQueryError> {
switch inputQuery {
case let .emoji(query):
var signal: Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, ChatContextQueryError> = .complete()
@ -245,10 +246,21 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
|> castError(ChatContextQueryError.self)
|> mapToSignal { peer -> Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, ChatContextQueryError> in
if let user = peer as? TelegramUser, let botInfo = user.botInfo, let _ = botInfo.inlinePlaceholder {
let contextResults = requestChatContextResults(account: context.account, botId: user.id, peerId: chatPeer.id, query: query, location: context.sharedContext.locationManager.flatMap { locationManager in
return currentLocationManagerCoordinate(manager: locationManager, timeout: 5.0)
|> flatMap { coordinate -> (Double, Double) in
return (coordinate.latitude, coordinate.longitude)
let contextResults = requestChatContextResults(account: context.account, botId: user.id, peerId: chatPeer.id, query: query, location: context.sharedContext.locationManager.flatMap { locationManager -> Signal<(Double, Double)?, NoError> in
return `deferred` {
Queue.mainQueue().async {
requestBotLocationStatus(user.id)
}
return ApplicationSpecificNotice.inlineBotLocationRequestStatus(accountManager: context.sharedContext.accountManager, peerId: user.id)
|> filter { $0 }
|> take(1)
|> mapToSignal { _ -> Signal<(Double, Double)?, NoError> in
return currentLocationManagerCoordinate(manager: locationManager, timeout: 5.0)
|> flatMap { coordinate -> (Double, Double) in
return (coordinate.latitude, coordinate.longitude)
}
}
}
} ?? .single(nil), offset: "")
|> mapError { error -> ChatContextQueryError in

View File

@ -37,7 +37,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
required init() {
self.labelNode = TextNode()
self.labelNode.isUserInteractionEnabled = false
self.labelNode.displaysAsynchronously = true
self.labelNode.displaysAsynchronously = false
self.filledBackgroundNode = LinkHighlightingNode(color: .clear)

View File

@ -20,6 +20,7 @@ import Emoji
import Markdown
import ManagedAnimationNode
import SlotMachineAnimationNode
import UniversalMediaPlayer
private let nameFont = Font.medium(14.0)
private let inlineBotPrefixFont = Font.regular(14.0)
@ -445,7 +446,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
}
func updateVisibility() {
private func updateVisibility() {
guard let item = self.item else {
return
}
@ -1104,7 +1105,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
}
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
switch recognizer.state {
case .ended:
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
@ -1217,7 +1218,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} else if let _ = self.emojiFile {
if let animationNode = self.animationNode as? AnimatedStickerNode {
var startTime: Signal<Double, NoError>
if animationNode.playIfNeeded() {
var shouldPlay = false
if !animationNode.isPlaying {
shouldPlay = true
startTime = .single(0.0)
} else {
startTime = animationNode.status
@ -1229,30 +1232,62 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F499, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D]
let peach = 0x1F351
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, beatingHearts.contains(firstScalar.value) || firstScalar.value == peach {
return .optionalAction({
let _ = startTime.start(next: { [weak self] time in
guard let strongSelf = self else {
return
}
var haptic: EmojiHaptic
if let current = strongSelf.haptic {
haptic = current
} else {
if beatingHearts.contains(firstScalar.value) {
haptic = HeartbeatHaptic()
} else {
haptic = PeachHaptic()
let appConfiguration = item.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> take(1)
|> map { view in
return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue
}
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first {
if beatingHearts.contains(firstScalar.value) || firstScalar.value == peach {
if shouldPlay {
animationNode.play()
}
return .optionalAction({
let _ = startTime.start(next: { [weak self] time in
guard let strongSelf = self else {
return
}
haptic.enabled = true
strongSelf.haptic = haptic
}
if !haptic.active {
haptic.start(time: time)
var haptic: EmojiHaptic
if let current = strongSelf.haptic {
haptic = current
} else {
if beatingHearts.contains(firstScalar.value) {
haptic = HeartbeatHaptic()
} else {
haptic = PeachHaptic()
}
haptic.enabled = true
strongSelf.haptic = haptic
}
if !haptic.active {
haptic.start(time: time)
}
})
})
} else {
return .optionalAction({
if shouldPlay {
let _ = (appConfiguration
|> deliverOnMainQueue).start(next: { [weak self] appConfiguration in
let emojiSounds = AnimatedEmojiSoundsConfiguration.with(appConfiguration: appConfiguration, account: item.context.account)
for (emoji, file) in emojiSounds.sounds {
if emoji.unicodeScalars.first == firstScalar {
let mediaManager = item.context.sharedContext.mediaManager
let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: item.context.account.postbox, resourceReference: .standalone(resource: file.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true)
mediaPlayer.togglePlayPause()
self?.mediaPlayer = mediaPlayer
animationNode.play()
break
}
}
})
}
})
})
}
}
}
}
@ -1268,7 +1303,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
return nil
}
@objc func shareButtonPressed() {
private var mediaPlayer: MediaPlayer?
@objc private func shareButtonPressed() {
if let item = self.item {
if case .pinnedMessages = item.associatedData.subject {
item.controllerInteraction.navigateToMessageStandalone(item.content.firstMessage.id)
@ -1299,7 +1336,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
}
@objc func swipeToReplyGesture(_ recognizer: ChatSwipeToReplyRecognizer) {
@objc private func swipeToReplyGesture(_ recognizer: ChatSwipeToReplyRecognizer) {
switch recognizer.state {
case .began:
self.currentSwipeToReplyTranslation = 0.0
@ -1512,3 +1549,39 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
self.contextSourceNode.contentNode.addSubnode(accessoryItemNode)
}
}
struct AnimatedEmojiSoundsConfiguration {
static var defaultValue: AnimatedEmojiSoundsConfiguration {
return AnimatedEmojiSoundsConfiguration(sounds: [:])
}
public let sounds: [String: TelegramMediaFile]
fileprivate init(sounds: [String: TelegramMediaFile]) {
self.sounds = sounds
}
static func with(appConfiguration: AppConfiguration, account: Account) -> AnimatedEmojiSoundsConfiguration {
if let data = appConfiguration.data, let values = data["emojies_sounds"] as? [String: Any] {
var sounds: [String: TelegramMediaFile] = [:]
for (key, value) in values {
if let dict = value as? [String: String], var fileReferenceString = dict["file_reference_base64"] {
fileReferenceString = fileReferenceString.replacingOccurrences(of: "-", with: "+")
fileReferenceString = fileReferenceString.replacingOccurrences(of: "_", with: "/")
while fileReferenceString.count % 4 != 0 {
fileReferenceString.append("=")
}
if let idString = dict["id"], let id = Int64(idString), let accessHashString = dict["access_hash"], let accessHash = Int64(accessHashString), let fileReference = Data(base64Encoded: fileReferenceString) {
let resource = CloudDocumentMediaResource(datacenterId: 1, fileId: id, accessHash: accessHash, size: nil, fileReference: fileReference, fileName: nil)
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: nil, attributes: [])
sounds[key] = file
}
}
}
return AnimatedEmojiSoundsConfiguration(sounds: sounds)
} else {
return .defaultValue
}
}
}

View File

@ -252,7 +252,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
self.textNode = TextNode()
self.textNode.isUserInteractionEnabled = false
self.textNode.displaysAsynchronously = true
self.textNode.displaysAsynchronously = false
self.textNode.contentsScale = UIScreenScale
self.textNode.contentMode = .topLeft

View File

@ -39,13 +39,13 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
self.titleNode.isUserInteractionEnabled = false
self.titleNode.contentMode = .topLeft
self.titleNode.contentsScale = UIScreenScale
self.titleNode.displaysAsynchronously = true
self.titleNode.displaysAsynchronously = false
self.addSubnode(self.titleNode)
self.labelNode.isUserInteractionEnabled = false
self.labelNode.contentMode = .topLeft
self.labelNode.contentsScale = UIScreenScale
self.labelNode.displaysAsynchronously = true
self.labelNode.displaysAsynchronously = false
self.addSubnode(self.labelNode)
self.addSubnode(self.iconNode)

View File

@ -173,7 +173,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
override init() {
self.dateNode = TextNode()
self.dateNode.isUserInteractionEnabled = false
self.dateNode.displaysAsynchronously = true
self.dateNode.displaysAsynchronously = false
super.init()

View File

@ -94,17 +94,17 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
override init() {
self.titleNode = TextNode()
self.titleNode.displaysAsynchronously = true
self.titleNode.displaysAsynchronously = false
self.titleNode.isUserInteractionEnabled = false
self.descriptionNode = TextNode()
self.descriptionNode.displaysAsynchronously = true
self.descriptionNode.displaysAsynchronously = false
self.descriptionNode.isUserInteractionEnabled = false
self.descriptionMeasuringNode = TextNode()
self.fetchingTextNode = ImmediateTextNode()
self.fetchingTextNode.displaysAsynchronously = true
self.fetchingTextNode.displaysAsynchronously = false
self.fetchingTextNode.isUserInteractionEnabled = false
self.fetchingTextNode.maximumNumberOfLines = 1
self.fetchingTextNode.contentMode = .left
@ -112,7 +112,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
self.fetchingTextNode.isHidden = true
self.fetchingCompactTextNode = ImmediateTextNode()
self.fetchingCompactTextNode.displaysAsynchronously = true
self.fetchingCompactTextNode.displaysAsynchronously = false
self.fetchingCompactTextNode.isUserInteractionEnabled = false
self.fetchingCompactTextNode.maximumNumberOfLines = 1
self.fetchingCompactTextNode.contentMode = .left
@ -829,10 +829,14 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
wasCheck = true
}
if adjustedProgress.isEqual(to: 1.0), (message.flags.contains(.Unsent) || wasCheck) {
state = .check(appearance: nil)
if isAudio && !isVoice {
state = .play
} else {
state = .progress(value: CGFloat(adjustedProgress), cancelEnabled: true, appearance: nil)
if adjustedProgress.isEqual(to: 1.0), (message.flags.contains(.Unsent) || wasCheck) {
state = .check(appearance: nil)
} else {
state = .progress(value: CGFloat(adjustedProgress), cancelEnabled: true, appearance: nil)
}
}
case .Local:
if isAudio {
@ -897,7 +901,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
}
}
image = playerAlbumArt(postbox: context.account.postbox, fileReference: .message(message: MessageReference(message), media: file), albumArt: .init(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: false)), thumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3), drawPlaceholderWhenEmpty: false)
image = playerAlbumArt(postbox: context.account.postbox, fileReference: .message(message: MessageReference(message), media: file), albumArt: .init(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: false)), thumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3), drawPlaceholderWhenEmpty: false, attemptSynchronously: !animated)
}
let statusNode = SemanticStatusNode(backgroundNodeColor: backgroundNodeColor, foregroundNodeColor: foregroundNodeColor, image: image, overlayForegroundNodeColor: presentationData.theme.theme.chat.message.mediaOverlayControlColors.foregroundColor)
self.statusNode = statusNode
@ -975,11 +979,10 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
let cutoutFrame = streamingCacheStatusFrame.insetBy(dx: -(1.0 + UIScreenPixel), dy: -(1.0 + UIScreenPixel)).offsetBy(dx: progressFrame.minX - 6.0, dy: progressFrame.minY)
if streamingState == .none && self.selectionNode == nil {
self.statusNode?.cutout = nil
self.statusNode?.setCutout(nil, animated: animated)
} else if let statusNode = self.statusNode, (self.iconNode?.isHidden ?? true) {
self.statusNode?.cutout = cutoutFrame
statusNode.setCutout(cutoutFrame, animated: true)
}
if let (expandedString, compactString, font) = downloadingStrings {

View File

@ -862,13 +862,13 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
self.textNode.isUserInteractionEnabled = false
self.textNode.contentMode = .topLeft
self.textNode.contentsScale = UIScreenScale
self.textNode.displaysAsynchronously = true
self.textNode.displaysAsynchronously = false
self.typeNode = TextNode()
self.typeNode.isUserInteractionEnabled = false
self.typeNode.contentMode = .topLeft
self.typeNode.contentsScale = UIScreenScale
self.typeNode.displaysAsynchronously = true
self.typeNode.displaysAsynchronously = false
self.avatarsNode = MergedAvatarsNode()
@ -876,7 +876,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
self.votersNode.isUserInteractionEnabled = false
self.votersNode.contentMode = .topLeft
self.votersNode.contentsScale = UIScreenScale
self.votersNode.displaysAsynchronously = true
self.votersNode.displaysAsynchronously = false
var displaySolution: (() -> Void)?
self.solutionButtonNode = SolutionButtonNode(pressed: {
@ -888,19 +888,19 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
self.buttonSubmitInactiveTextNode.isUserInteractionEnabled = false
self.buttonSubmitInactiveTextNode.contentMode = .topLeft
self.buttonSubmitInactiveTextNode.contentsScale = UIScreenScale
self.buttonSubmitInactiveTextNode.displaysAsynchronously = true
self.buttonSubmitInactiveTextNode.displaysAsynchronously = false
self.buttonSubmitActiveTextNode = TextNode()
self.buttonSubmitActiveTextNode.isUserInteractionEnabled = false
self.buttonSubmitActiveTextNode.contentMode = .topLeft
self.buttonSubmitActiveTextNode.contentsScale = UIScreenScale
self.buttonSubmitActiveTextNode.displaysAsynchronously = true
self.buttonSubmitActiveTextNode.displaysAsynchronously = false
self.buttonViewResultsTextNode = TextNode()
self.buttonViewResultsTextNode.isUserInteractionEnabled = false
self.buttonViewResultsTextNode.contentMode = .topLeft
self.buttonViewResultsTextNode.contentsScale = UIScreenScale
self.buttonViewResultsTextNode.displaysAsynchronously = true
self.buttonViewResultsTextNode.displaysAsynchronously = false
self.buttonNode = HighlightableButtonNode()

View File

@ -28,7 +28,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
override init() {
self.contentNode = ASDisplayNode()
self.contentNode.isUserInteractionEnabled = false
self.contentNode.displaysAsynchronously = true
self.contentNode.displaysAsynchronously = false
self.contentNode.contentMode = .left
self.contentNode.contentsScale = UIScreenScale

View File

@ -22,7 +22,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
self.textNode.isUserInteractionEnabled = false
self.textNode.contentMode = .topLeft
self.textNode.contentsScale = UIScreenScale
self.textNode.displaysAsynchronously = true
self.textNode.displaysAsynchronously = false
self.addSubnode(self.textNode)
}

View File

@ -59,7 +59,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
self.textNode.isUserInteractionEnabled = false
self.textNode.contentMode = .topLeft
self.textNode.contentsScale = UIScreenScale
self.textNode.displaysAsynchronously = true
self.textNode.displaysAsynchronously = false
self.addSubnode(self.textNode)
self.addSubnode(self.textAccessibilityOverlayNode)

View File

@ -317,7 +317,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
} else {
titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedMessage) ", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
}
} else if pinnedMessage.totalCount > 1 || pinnedMessage.index == pinnedMessage.totalCount - 1 {
} else if pinnedMessage.totalCount > 1 && pinnedMessage.index != pinnedMessage.totalCount - 1 {
titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedMessage)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
titleStrings.append(.text(1, NSAttributedString(string: " #", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
titleStrings.append(.number(pinnedMessage.index + 1, NSAttributedString(string: "\(pinnedMessage.index + 1)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))

View File

@ -414,10 +414,22 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
var nextButtonOrigin = maxInset + floor((areaWidth - updatedButtonsWidth) / 2.0)
let buttonWidth = floor(updatedButtonsWidth / CGFloat(self.buttons.count))
for (_, view) in self.buttons {
view.frame = CGRect(origin: CGPoint(x: nextButtonOrigin, y: 0.0), size: CGSize(width: buttonWidth, height: panelHeight))
var buttonFrames: [CGRect] = []
for _ in 0 ..< self.buttons.count {
buttonFrames.append(CGRect(origin: CGPoint(x: nextButtonOrigin, y: 0.0), size: CGSize(width: buttonWidth, height: panelHeight)))
nextButtonOrigin += buttonWidth
}
if buttonFrames[buttonFrames.count - 1].maxX >= width - 20.0 {
for i in 0 ..< buttonFrames.count {
buttonFrames[i].origin.x -= 16.0
}
}
for i in 0 ..< self.buttons.count {
self.buttons[i].1.frame = buttonFrames[i]
}
}
}

View File

@ -931,7 +931,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
interaction.requestLayout()
}))
} else if let about = cachedData.about, !about.isEmpty {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: []), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Profile_BotInfo, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
interaction.requestLayout()
}))
}
@ -3159,9 +3159,6 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
self.controller?.present(shareController, in: .window(.root))
}
private let groupCallDisposable = MetaDisposable()
private var groupCall: GroupCallContext?
private func requestCall(isVideo: Bool) {
guard let peer = self.data?.peer as? TelegramUser, let cachedUserData = self.data?.cachedData as? CachedUserData else {
return

View File

@ -108,7 +108,12 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}
self.chatListNode.contentOffsetChanged = { [weak self] offset in
self?.contentOffsetChanged?(offset)
guard let strongSelf = self else {
return
}
if strongSelf.chatListNode.supernode != nil {
strongSelf.contentOffsetChanged?(offset)
}
}
self.chatListNode.contentScrollingEnded = { [weak self] listView in
@ -293,7 +298,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
if self.chatListNode.supernode != nil {
self.chatListNode.scrollToPosition(.top)
} else if let contactListNode = self.contactListNode, contactListNode.supernode != nil {
contactListNode.scrollToTop()
//contactListNode.scrollToTop()
}
}
@ -331,7 +336,12 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}
}
contactListNode.contentOffsetChanged = { [weak self] offset in
self?.contentOffsetChanged?(offset)
guard let strongSelf = self else {
return
}
if strongSelf.contactListNode?.supernode != nil {
strongSelf.contentOffsetChanged?(offset)
}
}
contactListNode.contentScrollingEnded = { [weak self] listView in

View File

@ -45,34 +45,45 @@ private final class PrefetchManagerImpl {
}
|> distinctUntilChanged
let orderedPreloadMedia = account.viewTracker.orderedPreloadMedia
|> mapToSignal { orderedPreloadMedia in
return loadedStickerPack(postbox: account.postbox, network: account.network, reference: .animatedEmoji, forceActualized: false)
|> map { result -> [PrefetchMediaItem] in
let chatHistoryMediaItems = orderedPreloadMedia.map { PrefetchMediaItem.chatHistory($0) }
switch result {
case let .result(_, items, _):
var animatedEmojiStickers: [String: StickerPackItem] = [:]
for case let item as StickerPackItem in items {
if let emoji = item.getStringRepresentationsOfIndexKeys().first {
animatedEmojiStickers[emoji.basicEmoji.0] = item
let appConfiguration = account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> take(1)
|> map { view in
return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue
}
let orderedPreloadMedia = combineLatest(account.viewTracker.orderedPreloadMedia, loadedStickerPack(postbox: account.postbox, network: account.network, reference: .animatedEmoji, forceActualized: false), appConfiguration)
|> map { orderedPreloadMedia, stickerPack, appConfiguration -> [PrefetchMediaItem] in
let emojiSounds = AnimatedEmojiSoundsConfiguration.with(appConfiguration: appConfiguration, account: account)
let chatHistoryMediaItems = orderedPreloadMedia.map { PrefetchMediaItem.chatHistory($0) }
var stickerItems: [PrefetchMediaItem] = []
switch stickerPack {
case let .result(_, items, _):
var animatedEmojiStickers: [String: StickerPackItem] = [:]
for case let item as StickerPackItem in items {
if let emoji = item.getStringRepresentationsOfIndexKeys().first {
animatedEmojiStickers[emoji.basicEmoji.0] = item
}
}
let popularEmoji = ["\u{2764}", "👍", "😳", "😒", "🥳"]
for emoji in popularEmoji {
if let sticker = animatedEmojiStickers[emoji] {
if let _ = account.postbox.mediaBox.completedResourcePath(sticker.file.resource) {
} else {
stickerItems.append(.animatedEmojiSticker(sticker.file))
}
}
var stickerItems: [PrefetchMediaItem] = []
let popularEmoji = ["\u{2764}", "👍", "😳", "😒", "🥳"]
for emoji in popularEmoji {
if let sticker = animatedEmojiStickers[emoji] {
if let _ = account.postbox.mediaBox.completedResourcePath(sticker.file.resource) {
} else {
stickerItems.append(.animatedEmojiSticker(sticker.file))
}
}
}
return stickerItems + chatHistoryMediaItems
default:
return chatHistoryMediaItems
}
}
default:
break
}
var prefetchItems: [PrefetchMediaItem] = []
prefetchItems.append(contentsOf: chatHistoryMediaItems)
prefetchItems.append(contentsOf: stickerItems)
prefetchItems.append(contentsOf: emojiSounds.sounds.values.map { .animatedEmojiSticker($0) })
return prefetchItems
}
self.listDisposable = (combineLatest(orderedPreloadMedia, sharedContext.automaticMediaDownloadSettings, networkType)

View File

@ -61,7 +61,9 @@ final class WidgetDataContext {
}
if #available(iOSApplicationExtension 14.0, iOS 14.0, *) {
#if arch(arm64) || arch(i386) || arch(x86_64)
WidgetCenter.shared.reloadAllTimelines()
#endif
}
})
@ -78,7 +80,9 @@ final class WidgetDataContext {
}
if #available(iOSApplicationExtension 14.0, iOS 14.0, *) {
#if arch(arm64) || arch(i386) || arch(x86_64)
WidgetCenter.shared.reloadAllTimelines()
#endif
}
})

View File

@ -2,7 +2,7 @@ import Foundation
import SwiftSignalKit
import TgVoipWebrtc
private final class ContextQueueImpl: NSObject, OngoingCallThreadLocalContextQueueWebrtc {
/*private final class ContextQueueImpl: NSObject, OngoingCallThreadLocalContextQueueWebrtc {
private let queue: Queue
init(queue: Queue) {
@ -1467,3 +1467,4 @@ public final class GroupCallContext {
}
}
}
*/

View File

@ -1,7 +1,7 @@
#import <TgVoipWebrtc/GroupCallThreadLocalContext.h>
#import "group/GroupInstanceImpl.h"
/*#import "group/GroupInstanceImpl.h"
@interface GroupCallThreadLocalContext () {
id<OngoingCallThreadLocalContextQueueWebrtc> _queue;
@ -55,3 +55,4 @@
}
@end
*/

@ -1 +1 @@
Subproject commit 4f7501d281b851e6302b2a2d7298c733eee82414
Subproject commit 64f96a1b4fcfb8afdb0fb7749082cb42cdad7901