diff --git a/Telegram_Buck.xcworkspace/buck-project.meta.json b/Telegram_Buck.xcworkspace/buck-project.meta.json index ea47a3d535..19305fd247 100644 --- a/Telegram_Buck.xcworkspace/buck-project.meta.json +++ b/Telegram_Buck.xcworkspace/buck-project.meta.json @@ -1 +1 @@ -{"required-targets":["//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_ac3_parser.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_adts_parser.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_avcodec.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_avdct.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_avfft.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_d3d11va.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_dirac.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_dv_profile.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_dxva2.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_jni.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_mediacodec.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_qsv.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_vaapi.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_vdpau.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_version.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_videotoolbox.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_vorbis_parser.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_xvmc.h","//submodules/FFMpeg:ffmpeg_header_libavformat_sub_avformat.h","//submodules/FFMpeg:ffmpeg_header_libavformat_sub_avio.h","//submodules/FFMpeg:ffmpeg_header_libavformat_sub_version.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_adler32.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_aes.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_aes_ctr.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_attributes.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_audio_fifo.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avassert.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avconfig.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avstring.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avutil.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_base64.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_blowfish.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_bprint.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_bswap.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_buffer.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_camellia.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_cast5.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_channel_layout.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_common.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_cpu.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_crc.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_des.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_dict.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_display.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_downmix_info.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_encryption_info.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_error.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_eval.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_ffversion.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_fifo.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_file.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_frame.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hash.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hmac.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_cuda.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_d3d11va.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_drm.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_dxva2.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_mediacodec.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_qsv.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_vaapi.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_vdpau.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_videotoolbox.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_imgutils.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_intfloat.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_intreadwrite.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_lfg.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_log.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_lzo.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_macros.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_mastering_display_metadata.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_mathematics.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_md5.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_mem.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_motion_vector.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_murmur3.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_opt.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_parseutils.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_pixdesc.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_pixelutils.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_pixfmt.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_random_seed.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_rational.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_rc4.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_replaygain.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_ripemd.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_samplefmt.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_sha.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_sha512.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_spherical.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_stereo3d.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_tea.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_threadmessage.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_time.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_timecode.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_timestamp.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_tree.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_twofish.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_version.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_xtea.h","//submodules/FFMpeg:ffmpeg_header_libswresample_sub_swresample.h","//submodules/FFMpeg:ffmpeg_header_libswresample_sub_version.h","//submodules/FFMpeg:libffmpeg_build","//submodules/Opus:opus_lib_file","//submodules/WebP:WebP_lib_file","//submodules/openssl:openssl_build_merged","//submodules/openssl:openssl_header_openssl_sub_aes.h","//submodules/openssl:openssl_header_openssl_sub_asn1.h","//submodules/openssl:openssl_header_openssl_sub_asn1_mac.h","//submodules/openssl:openssl_header_openssl_sub_asn1err.h","//submodules/openssl:openssl_header_openssl_sub_asn1t.h","//submodules/openssl:openssl_header_openssl_sub_async.h","//submodules/openssl:openssl_header_openssl_sub_asyncerr.h","//submodules/openssl:openssl_header_openssl_sub_bio.h","//submodules/openssl:openssl_header_openssl_sub_bioerr.h","//submodules/openssl:openssl_header_openssl_sub_blowfish.h","//submodules/openssl:openssl_header_openssl_sub_bn.h","//submodules/openssl:openssl_header_openssl_sub_bnerr.h","//submodules/openssl:openssl_header_openssl_sub_buffer.h","//submodules/openssl:openssl_header_openssl_sub_buffererr.h","//submodules/openssl:openssl_header_openssl_sub_camellia.h","//submodules/openssl:openssl_header_openssl_sub_cast.h","//submodules/openssl:openssl_header_openssl_sub_cmac.h","//submodules/openssl:openssl_header_openssl_sub_cms.h","//submodules/openssl:openssl_header_openssl_sub_cmserr.h","//submodules/openssl:openssl_header_openssl_sub_comp.h","//submodules/openssl:openssl_header_openssl_sub_comperr.h","//submodules/openssl:openssl_header_openssl_sub_conf.h","//submodules/openssl:openssl_header_openssl_sub_conf_api.h","//submodules/openssl:openssl_header_openssl_sub_conferr.h","//submodules/openssl:openssl_header_openssl_sub_crypto.h","//submodules/openssl:openssl_header_openssl_sub_cryptoerr.h","//submodules/openssl:openssl_header_openssl_sub_ct.h","//submodules/openssl:openssl_header_openssl_sub_cterr.h","//submodules/openssl:openssl_header_openssl_sub_des.h","//submodules/openssl:openssl_header_openssl_sub_dh.h","//submodules/openssl:openssl_header_openssl_sub_dherr.h","//submodules/openssl:openssl_header_openssl_sub_dsa.h","//submodules/openssl:openssl_header_openssl_sub_dsaerr.h","//submodules/openssl:openssl_header_openssl_sub_dtls1.h","//submodules/openssl:openssl_header_openssl_sub_e_os2.h","//submodules/openssl:openssl_header_openssl_sub_ebcdic.h","//submodules/openssl:openssl_header_openssl_sub_ec.h","//submodules/openssl:openssl_header_openssl_sub_ecdh.h","//submodules/openssl:openssl_header_openssl_sub_ecdsa.h","//submodules/openssl:openssl_header_openssl_sub_ecerr.h","//submodules/openssl:openssl_header_openssl_sub_engine.h","//submodules/openssl:openssl_header_openssl_sub_engineerr.h","//submodules/openssl:openssl_header_openssl_sub_err.h","//submodules/openssl:openssl_header_openssl_sub_evp.h","//submodules/openssl:openssl_header_openssl_sub_evperr.h","//submodules/openssl:openssl_header_openssl_sub_hmac.h","//submodules/openssl:openssl_header_openssl_sub_idea.h","//submodules/openssl:openssl_header_openssl_sub_kdf.h","//submodules/openssl:openssl_header_openssl_sub_kdferr.h","//submodules/openssl:openssl_header_openssl_sub_lhash.h","//submodules/openssl:openssl_header_openssl_sub_md2.h","//submodules/openssl:openssl_header_openssl_sub_md4.h","//submodules/openssl:openssl_header_openssl_sub_md5.h","//submodules/openssl:openssl_header_openssl_sub_mdc2.h","//submodules/openssl:openssl_header_openssl_sub_modes.h","//submodules/openssl:openssl_header_openssl_sub_obj_mac.h","//submodules/openssl:openssl_header_openssl_sub_objects.h","//submodules/openssl:openssl_header_openssl_sub_objectserr.h","//submodules/openssl:openssl_header_openssl_sub_ocsp.h","//submodules/openssl:openssl_header_openssl_sub_ocsperr.h","//submodules/openssl:openssl_header_openssl_sub_opensslconf.h","//submodules/openssl:openssl_header_openssl_sub_opensslv.h","//submodules/openssl:openssl_header_openssl_sub_ossl_typ.h","//submodules/openssl:openssl_header_openssl_sub_pem.h","//submodules/openssl:openssl_header_openssl_sub_pem2.h","//submodules/openssl:openssl_header_openssl_sub_pemerr.h","//submodules/openssl:openssl_header_openssl_sub_pkcs12.h","//submodules/openssl:openssl_header_openssl_sub_pkcs12err.h","//submodules/openssl:openssl_header_openssl_sub_pkcs7.h","//submodules/openssl:openssl_header_openssl_sub_pkcs7err.h","//submodules/openssl:openssl_header_openssl_sub_rand.h","//submodules/openssl:openssl_header_openssl_sub_rand_drbg.h","//submodules/openssl:openssl_header_openssl_sub_randerr.h","//submodules/openssl:openssl_header_openssl_sub_rc2.h","//submodules/openssl:openssl_header_openssl_sub_rc4.h","//submodules/openssl:openssl_header_openssl_sub_rc5.h","//submodules/openssl:openssl_header_openssl_sub_ripemd.h","//submodules/openssl:openssl_header_openssl_sub_rsa.h","//submodules/openssl:openssl_header_openssl_sub_rsaerr.h","//submodules/openssl:openssl_header_openssl_sub_safestack.h","//submodules/openssl:openssl_header_openssl_sub_seed.h","//submodules/openssl:openssl_header_openssl_sub_sha.h","//submodules/openssl:openssl_header_openssl_sub_srp.h","//submodules/openssl:openssl_header_openssl_sub_srtp.h","//submodules/openssl:openssl_header_openssl_sub_ssl.h","//submodules/openssl:openssl_header_openssl_sub_ssl2.h","//submodules/openssl:openssl_header_openssl_sub_ssl3.h","//submodules/openssl:openssl_header_openssl_sub_sslerr.h","//submodules/openssl:openssl_header_openssl_sub_stack.h","//submodules/openssl:openssl_header_openssl_sub_store.h","//submodules/openssl:openssl_header_openssl_sub_storeerr.h","//submodules/openssl:openssl_header_openssl_sub_symhacks.h","//submodules/openssl:openssl_header_openssl_sub_tls1.h","//submodules/openssl:openssl_header_openssl_sub_ts.h","//submodules/openssl:openssl_header_openssl_sub_tserr.h","//submodules/openssl:openssl_header_openssl_sub_txt_db.h","//submodules/openssl:openssl_header_openssl_sub_ui.h","//submodules/openssl:openssl_header_openssl_sub_uierr.h","//submodules/openssl:openssl_header_openssl_sub_whrlpool.h","//submodules/openssl:openssl_header_openssl_sub_x509.h","//submodules/openssl:openssl_header_openssl_sub_x509_vfy.h","//submodules/openssl:openssl_header_openssl_sub_x509err.h","//submodules/openssl:openssl_header_openssl_sub_x509v3.h","//submodules/openssl:openssl_header_openssl_sub_x509v3err.h","//submodules/ton:ton_build","//submodules/ton:ton_header_auto_sub_tl_sub_tonlib_api.h","//submodules/ton:ton_header_td_sub_utils_sub_SharedSlice.h","//submodules/ton:ton_header_td_sub_utils_sub_Slice-decl.h","//submodules/ton:ton_header_td_sub_utils_sub_Slice.h","//submodules/ton:ton_header_td_sub_utils_sub_check.h","//submodules/ton:ton_header_td_sub_utils_sub_common.h","//submodules/ton:ton_header_td_sub_utils_sub_config.h","//submodules/ton:ton_header_td_sub_utils_sub_int_types.h","//submodules/ton:ton_header_td_sub_utils_sub_port_sub_platform.h","//submodules/ton:ton_header_td_sub_utils_sub_unique_ptr.h","//submodules/ton:ton_header_tl_sub_TlObject.h","//submodules/ton:ton_header_tonlib_sub_Client.h","//submodules/ton:ton_header_tonlib_sub_tonlib_client_json.h","//submodules/ton:ton_header_tonlib_sub_tonlibjson_export.h"],"xcconfig-paths":["buck-out/gen/AppLibrary-Debug.xcconfig","buck-out/gen/AppLibrary-Profile.xcconfig","buck-out/gen/AppLibrary-Release.xcconfig","buck-out/gen/IntentsExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/IntentsExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/IntentsExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/NotificationContentExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/NotificationContentExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/NotificationContentExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/NotificationServiceExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/NotificationServiceExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/NotificationServiceExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/ShareExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/ShareExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/ShareExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/Telegram-Debug.xcconfig","buck-out/gen/Telegram-Profile.xcconfig","buck-out/gen/Telegram-Release.xcconfig","buck-out/gen/WatchApp#watchsimulator-i386-Debug.xcconfig","buck-out/gen/WatchApp#watchsimulator-i386-Profile.xcconfig","buck-out/gen/WatchApp#watchsimulator-i386-Release.xcconfig","buck-out/gen/WatchAppExtension#watchsimulator-i386-Debug.xcconfig","buck-out/gen/WatchAppExtension#watchsimulator-i386-Profile.xcconfig","buck-out/gen/WatchAppExtension#watchsimulator-i386-Release.xcconfig","buck-out/gen/WidgetExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/WidgetExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/WidgetExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/submodules/AccountContext/AccountContext-Debug.xcconfig","buck-out/gen/submodules/AccountContext/AccountContext-Profile.xcconfig","buck-out/gen/submodules/AccountContext/AccountContext-Release.xcconfig","buck-out/gen/submodules/ActionSheetPeerItem/ActionSheetPeerItem-Debug.xcconfig","buck-out/gen/submodules/ActionSheetPeerItem/ActionSheetPeerItem-Profile.xcconfig","buck-out/gen/submodules/ActionSheetPeerItem/ActionSheetPeerItem-Release.xcconfig","buck-out/gen/submodules/ActivityIndicator/ActivityIndicator-Debug.xcconfig","buck-out/gen/submodules/ActivityIndicator/ActivityIndicator-Profile.xcconfig","buck-out/gen/submodules/ActivityIndicator/ActivityIndicator-Release.xcconfig","buck-out/gen/submodules/AlertUI/AlertUI-Debug.xcconfig","buck-out/gen/submodules/AlertUI/AlertUI-Profile.xcconfig","buck-out/gen/submodules/AlertUI/AlertUI-Release.xcconfig","buck-out/gen/submodules/AnimationUI/AnimationUI-Debug.xcconfig","buck-out/gen/submodules/AnimationUI/AnimationUI-Profile.xcconfig","buck-out/gen/submodules/AnimationUI/AnimationUI-Release.xcconfig","buck-out/gen/submodules/AppBundle/AppBundle-Debug.xcconfig","buck-out/gen/submodules/AppBundle/AppBundle-Profile.xcconfig","buck-out/gen/submodules/AppBundle/AppBundle-Release.xcconfig","buck-out/gen/submodules/AsyncDisplayKit/AsyncDisplayKit#shared-Debug.xcconfig","buck-out/gen/submodules/AsyncDisplayKit/AsyncDisplayKit#shared-Profile.xcconfig","buck-out/gen/submodules/AsyncDisplayKit/AsyncDisplayKit#shared-Release.xcconfig","buck-out/gen/submodules/AuthorizationUI/AuthorizationUI-Debug.xcconfig","buck-out/gen/submodules/AuthorizationUI/AuthorizationUI-Profile.xcconfig","buck-out/gen/submodules/AuthorizationUI/AuthorizationUI-Release.xcconfig","buck-out/gen/submodules/AvatarNode/AvatarNode-Debug.xcconfig","buck-out/gen/submodules/AvatarNode/AvatarNode-Profile.xcconfig","buck-out/gen/submodules/AvatarNode/AvatarNode-Release.xcconfig","buck-out/gen/submodules/BotPaymentsUI/BotPaymentsUI-Debug.xcconfig","buck-out/gen/submodules/BotPaymentsUI/BotPaymentsUI-Profile.xcconfig","buck-out/gen/submodules/BotPaymentsUI/BotPaymentsUI-Release.xcconfig","buck-out/gen/submodules/BuildConfig/BuildConfig-Debug.xcconfig","buck-out/gen/submodules/BuildConfig/BuildConfig-Profile.xcconfig","buck-out/gen/submodules/BuildConfig/BuildConfig-Release.xcconfig","buck-out/gen/submodules/CallListUI/CallListUI-Debug.xcconfig","buck-out/gen/submodules/CallListUI/CallListUI-Profile.xcconfig","buck-out/gen/submodules/CallListUI/CallListUI-Release.xcconfig","buck-out/gen/submodules/Camera/Camera-Debug.xcconfig","buck-out/gen/submodules/Camera/Camera-Profile.xcconfig","buck-out/gen/submodules/Camera/Camera-Release.xcconfig","buck-out/gen/submodules/ChatListSearchItemHeader/ChatListSearchItemHeader-Debug.xcconfig","buck-out/gen/submodules/ChatListSearchItemHeader/ChatListSearchItemHeader-Profile.xcconfig","buck-out/gen/submodules/ChatListSearchItemHeader/ChatListSearchItemHeader-Release.xcconfig","buck-out/gen/submodules/ChatListSearchItemNode/ChatListSearchItemNode-Debug.xcconfig","buck-out/gen/submodules/ChatListSearchItemNode/ChatListSearchItemNode-Profile.xcconfig","buck-out/gen/submodules/ChatListSearchItemNode/ChatListSearchItemNode-Release.xcconfig","buck-out/gen/submodules/ChatListSearchRecentPeersNode/ChatListSearchRecentPeersNode-Debug.xcconfig","buck-out/gen/submodules/ChatListSearchRecentPeersNode/ChatListSearchRecentPeersNode-Profile.xcconfig","buck-out/gen/submodules/ChatListSearchRecentPeersNode/ChatListSearchRecentPeersNode-Release.xcconfig","buck-out/gen/submodules/ChatListUI/ChatListUI-Debug.xcconfig","buck-out/gen/submodules/ChatListUI/ChatListUI-Profile.xcconfig","buck-out/gen/submodules/ChatListUI/ChatListUI-Release.xcconfig","buck-out/gen/submodules/ChatTitleActivityNode/ChatTitleActivityNode-Debug.xcconfig","buck-out/gen/submodules/ChatTitleActivityNode/ChatTitleActivityNode-Profile.xcconfig","buck-out/gen/submodules/ChatTitleActivityNode/ChatTitleActivityNode-Release.xcconfig","buck-out/gen/submodules/CheckNode/CheckNode-Debug.xcconfig","buck-out/gen/submodules/CheckNode/CheckNode-Profile.xcconfig","buck-out/gen/submodules/CheckNode/CheckNode-Release.xcconfig","buck-out/gen/submodules/ComposePollUI/ComposePollUI-Debug.xcconfig","buck-out/gen/submodules/ComposePollUI/ComposePollUI-Profile.xcconfig","buck-out/gen/submodules/ComposePollUI/ComposePollUI-Release.xcconfig","buck-out/gen/submodules/ContactListUI/ContactListUI-Debug.xcconfig","buck-out/gen/submodules/ContactListUI/ContactListUI-Profile.xcconfig","buck-out/gen/submodules/ContactListUI/ContactListUI-Release.xcconfig","buck-out/gen/submodules/ContactsPeerItem/ContactsPeerItem-Debug.xcconfig","buck-out/gen/submodules/ContactsPeerItem/ContactsPeerItem-Profile.xcconfig","buck-out/gen/submodules/ContactsPeerItem/ContactsPeerItem-Release.xcconfig","buck-out/gen/submodules/ContextUI/ContextUI-Debug.xcconfig","buck-out/gen/submodules/ContextUI/ContextUI-Profile.xcconfig","buck-out/gen/submodules/ContextUI/ContextUI-Release.xcconfig","buck-out/gen/submodules/CounterContollerTitleView/CounterContollerTitleView-Debug.xcconfig","buck-out/gen/submodules/CounterContollerTitleView/CounterContollerTitleView-Profile.xcconfig","buck-out/gen/submodules/CounterContollerTitleView/CounterContollerTitleView-Release.xcconfig","buck-out/gen/submodules/CountrySelectionUI/CountrySelectionUI-Debug.xcconfig","buck-out/gen/submodules/CountrySelectionUI/CountrySelectionUI-Profile.xcconfig","buck-out/gen/submodules/CountrySelectionUI/CountrySelectionUI-Release.xcconfig","buck-out/gen/submodules/Crc32/Crc32-Debug.xcconfig","buck-out/gen/submodules/Crc32/Crc32-Profile.xcconfig","buck-out/gen/submodules/Crc32/Crc32-Release.xcconfig","buck-out/gen/submodules/DateSelectionUI/DateSelectionUI-Debug.xcconfig","buck-out/gen/submodules/DateSelectionUI/DateSelectionUI-Profile.xcconfig","buck-out/gen/submodules/DateSelectionUI/DateSelectionUI-Release.xcconfig","buck-out/gen/submodules/DeleteChatPeerActionSheetItem/DeleteChatPeerActionSheetItem-Debug.xcconfig","buck-out/gen/submodules/DeleteChatPeerActionSheetItem/DeleteChatPeerActionSheetItem-Profile.xcconfig","buck-out/gen/submodules/DeleteChatPeerActionSheetItem/DeleteChatPeerActionSheetItem-Release.xcconfig","buck-out/gen/submodules/DeviceAccess/DeviceAccess-Debug.xcconfig","buck-out/gen/submodules/DeviceAccess/DeviceAccess-Profile.xcconfig","buck-out/gen/submodules/DeviceAccess/DeviceAccess-Release.xcconfig","buck-out/gen/submodules/DeviceLocationManager/DeviceLocationManager-Debug.xcconfig","buck-out/gen/submodules/DeviceLocationManager/DeviceLocationManager-Profile.xcconfig","buck-out/gen/submodules/DeviceLocationManager/DeviceLocationManager-Release.xcconfig","buck-out/gen/submodules/DeviceProximity/DeviceProximity-Debug.xcconfig","buck-out/gen/submodules/DeviceProximity/DeviceProximity-Profile.xcconfig","buck-out/gen/submodules/DeviceProximity/DeviceProximity-Release.xcconfig","buck-out/gen/submodules/DirectionalPanGesture/DirectionalPanGesture-Debug.xcconfig","buck-out/gen/submodules/DirectionalPanGesture/DirectionalPanGesture-Profile.xcconfig","buck-out/gen/submodules/DirectionalPanGesture/DirectionalPanGesture-Release.xcconfig","buck-out/gen/submodules/Display/Display#shared-Debug.xcconfig","buck-out/gen/submodules/Display/Display#shared-Profile.xcconfig","buck-out/gen/submodules/Display/Display#shared-Release.xcconfig","buck-out/gen/submodules/Emoji/Emoji-Debug.xcconfig","buck-out/gen/submodules/Emoji/Emoji-Profile.xcconfig","buck-out/gen/submodules/Emoji/Emoji-Release.xcconfig","buck-out/gen/submodules/EncryptionKeyVisualization/EncryptionKeyVisualization-Debug.xcconfig","buck-out/gen/submodules/EncryptionKeyVisualization/EncryptionKeyVisualization-Profile.xcconfig","buck-out/gen/submodules/EncryptionKeyVisualization/EncryptionKeyVisualization-Release.xcconfig","buck-out/gen/submodules/FFMpeg/FFMpeg-Debug.xcconfig","buck-out/gen/submodules/FFMpeg/FFMpeg-Profile.xcconfig","buck-out/gen/submodules/FFMpeg/FFMpeg-Release.xcconfig","buck-out/gen/submodules/FFMpeg/libffmpeg-Debug.xcconfig","buck-out/gen/submodules/FFMpeg/libffmpeg-Profile.xcconfig","buck-out/gen/submodules/FFMpeg/libffmpeg-Release.xcconfig","buck-out/gen/submodules/GZip/GZip-Debug.xcconfig","buck-out/gen/submodules/GZip/GZip-Profile.xcconfig","buck-out/gen/submodules/GZip/GZip-Release.xcconfig","buck-out/gen/submodules/GalleryUI/GalleryUI-Debug.xcconfig","buck-out/gen/submodules/GalleryUI/GalleryUI-Profile.xcconfig","buck-out/gen/submodules/GalleryUI/GalleryUI-Release.xcconfig","buck-out/gen/submodules/GameUI/GameUI-Debug.xcconfig","buck-out/gen/submodules/GameUI/GameUI-Profile.xcconfig","buck-out/gen/submodules/GameUI/GameUI-Release.xcconfig","buck-out/gen/submodules/Geocoding/Geocoding-Debug.xcconfig","buck-out/gen/submodules/Geocoding/Geocoding-Profile.xcconfig","buck-out/gen/submodules/Geocoding/Geocoding-Release.xcconfig","buck-out/gen/submodules/GridMessageSelectionNode/GridMessageSelectionNode-Debug.xcconfig","buck-out/gen/submodules/GridMessageSelectionNode/GridMessageSelectionNode-Profile.xcconfig","buck-out/gen/submodules/GridMessageSelectionNode/GridMessageSelectionNode-Release.xcconfig","buck-out/gen/submodules/HashtagSearchUI/HashtagSearchUI-Debug.xcconfig","buck-out/gen/submodules/HashtagSearchUI/HashtagSearchUI-Profile.xcconfig","buck-out/gen/submodules/HashtagSearchUI/HashtagSearchUI-Release.xcconfig","buck-out/gen/submodules/HexColor/HexColor-Debug.xcconfig","buck-out/gen/submodules/HexColor/HexColor-Profile.xcconfig","buck-out/gen/submodules/HexColor/HexColor-Release.xcconfig","buck-out/gen/submodules/HockeySDK-iOS/HockeySDK-Debug.xcconfig","buck-out/gen/submodules/HockeySDK-iOS/HockeySDK-Profile.xcconfig","buck-out/gen/submodules/HockeySDK-iOS/HockeySDK-Release.xcconfig","buck-out/gen/submodules/HorizontalPeerItem/HorizontalPeerItem-Debug.xcconfig","buck-out/gen/submodules/HorizontalPeerItem/HorizontalPeerItem-Profile.xcconfig","buck-out/gen/submodules/HorizontalPeerItem/HorizontalPeerItem-Release.xcconfig","buck-out/gen/submodules/ImageBlur/ImageBlur-Debug.xcconfig","buck-out/gen/submodules/ImageBlur/ImageBlur-Profile.xcconfig","buck-out/gen/submodules/ImageBlur/ImageBlur-Release.xcconfig","buck-out/gen/submodules/ImageCompression/ImageCompression-Debug.xcconfig","buck-out/gen/submodules/ImageCompression/ImageCompression-Profile.xcconfig","buck-out/gen/submodules/ImageCompression/ImageCompression-Release.xcconfig","buck-out/gen/submodules/ImageTransparency/ImageTransparency-Debug.xcconfig","buck-out/gen/submodules/ImageTransparency/ImageTransparency-Profile.xcconfig","buck-out/gen/submodules/ImageTransparency/ImageTransparency-Release.xcconfig","buck-out/gen/submodules/InstantPageCache/InstantPageCache-Debug.xcconfig","buck-out/gen/submodules/InstantPageCache/InstantPageCache-Profile.xcconfig","buck-out/gen/submodules/InstantPageCache/InstantPageCache-Release.xcconfig","buck-out/gen/submodules/InstantPageUI/InstantPageUI-Debug.xcconfig","buck-out/gen/submodules/InstantPageUI/InstantPageUI-Profile.xcconfig","buck-out/gen/submodules/InstantPageUI/InstantPageUI-Release.xcconfig","buck-out/gen/submodules/ItemListAddressItem/ItemListAddressItem-Debug.xcconfig","buck-out/gen/submodules/ItemListAddressItem/ItemListAddressItem-Profile.xcconfig","buck-out/gen/submodules/ItemListAddressItem/ItemListAddressItem-Release.xcconfig","buck-out/gen/submodules/ItemListAvatarAndNameInfoItem/ItemListAvatarAndNameInfoItem-Debug.xcconfig","buck-out/gen/submodules/ItemListAvatarAndNameInfoItem/ItemListAvatarAndNameInfoItem-Profile.xcconfig","buck-out/gen/submodules/ItemListAvatarAndNameInfoItem/ItemListAvatarAndNameInfoItem-Release.xcconfig","buck-out/gen/submodules/ItemListPeerActionItem/ItemListPeerActionItem-Debug.xcconfig","buck-out/gen/submodules/ItemListPeerActionItem/ItemListPeerActionItem-Profile.xcconfig","buck-out/gen/submodules/ItemListPeerActionItem/ItemListPeerActionItem-Release.xcconfig","buck-out/gen/submodules/ItemListPeerItem/ItemListPeerItem-Debug.xcconfig","buck-out/gen/submodules/ItemListPeerItem/ItemListPeerItem-Profile.xcconfig","buck-out/gen/submodules/ItemListPeerItem/ItemListPeerItem-Release.xcconfig","buck-out/gen/submodules/ItemListStickerPackItem/ItemListStickerPackItem-Debug.xcconfig","buck-out/gen/submodules/ItemListStickerPackItem/ItemListStickerPackItem-Profile.xcconfig","buck-out/gen/submodules/ItemListStickerPackItem/ItemListStickerPackItem-Release.xcconfig","buck-out/gen/submodules/ItemListUI/ItemListUI-Debug.xcconfig","buck-out/gen/submodules/ItemListUI/ItemListUI-Profile.xcconfig","buck-out/gen/submodules/ItemListUI/ItemListUI-Release.xcconfig","buck-out/gen/submodules/JoinLinkPreviewUI/JoinLinkPreviewUI-Debug.xcconfig","buck-out/gen/submodules/JoinLinkPreviewUI/JoinLinkPreviewUI-Profile.xcconfig","buck-out/gen/submodules/JoinLinkPreviewUI/JoinLinkPreviewUI-Release.xcconfig","buck-out/gen/submodules/LanguageLinkPreviewUI/LanguageLinkPreviewUI-Debug.xcconfig","buck-out/gen/submodules/LanguageLinkPreviewUI/LanguageLinkPreviewUI-Profile.xcconfig","buck-out/gen/submodules/LanguageLinkPreviewUI/LanguageLinkPreviewUI-Release.xcconfig","buck-out/gen/submodules/LanguageSuggestionUI/LanguageSuggestionUI-Debug.xcconfig","buck-out/gen/submodules/LanguageSuggestionUI/LanguageSuggestionUI-Profile.xcconfig","buck-out/gen/submodules/LanguageSuggestionUI/LanguageSuggestionUI-Release.xcconfig","buck-out/gen/submodules/LegacyComponents/LegacyComponents-Debug.xcconfig","buck-out/gen/submodules/LegacyComponents/LegacyComponents-Profile.xcconfig","buck-out/gen/submodules/LegacyComponents/LegacyComponents-Release.xcconfig","buck-out/gen/submodules/LegacyDataImport/LegacyDataImport-Debug.xcconfig","buck-out/gen/submodules/LegacyDataImport/LegacyDataImport-Profile.xcconfig","buck-out/gen/submodules/LegacyDataImport/LegacyDataImport-Release.xcconfig","buck-out/gen/submodules/LegacyMediaPickerUI/LegacyMediaPickerUI-Debug.xcconfig","buck-out/gen/submodules/LegacyMediaPickerUI/LegacyMediaPickerUI-Profile.xcconfig","buck-out/gen/submodules/LegacyMediaPickerUI/LegacyMediaPickerUI-Release.xcconfig","buck-out/gen/submodules/LegacyUI/LegacyUI-Debug.xcconfig","buck-out/gen/submodules/LegacyUI/LegacyUI-Profile.xcconfig","buck-out/gen/submodules/LegacyUI/LegacyUI-Release.xcconfig","buck-out/gen/submodules/LightweightAccountData/LightweightAccountData-Debug.xcconfig","buck-out/gen/submodules/LightweightAccountData/LightweightAccountData-Profile.xcconfig","buck-out/gen/submodules/LightweightAccountData/LightweightAccountData-Release.xcconfig","buck-out/gen/submodules/ListSectionHeaderNode/ListSectionHeaderNode-Debug.xcconfig","buck-out/gen/submodules/ListSectionHeaderNode/ListSectionHeaderNode-Profile.xcconfig","buck-out/gen/submodules/ListSectionHeaderNode/ListSectionHeaderNode-Release.xcconfig","buck-out/gen/submodules/LiveLocationManager/LiveLocationManager-Debug.xcconfig","buck-out/gen/submodules/LiveLocationManager/LiveLocationManager-Profile.xcconfig","buck-out/gen/submodules/LiveLocationManager/LiveLocationManager-Release.xcconfig","buck-out/gen/submodules/LiveLocationPositionNode/LiveLocationPositionNode-Debug.xcconfig","buck-out/gen/submodules/LiveLocationPositionNode/LiveLocationPositionNode-Profile.xcconfig","buck-out/gen/submodules/LiveLocationPositionNode/LiveLocationPositionNode-Release.xcconfig","buck-out/gen/submodules/LiveLocationTimerNode/LiveLocationTimerNode-Debug.xcconfig","buck-out/gen/submodules/LiveLocationTimerNode/LiveLocationTimerNode-Profile.xcconfig","buck-out/gen/submodules/LiveLocationTimerNode/LiveLocationTimerNode-Release.xcconfig","buck-out/gen/submodules/LocalAuth/LocalAuth-Debug.xcconfig","buck-out/gen/submodules/LocalAuth/LocalAuth-Profile.xcconfig","buck-out/gen/submodules/LocalAuth/LocalAuth-Release.xcconfig","buck-out/gen/submodules/LocalMediaResources/LocalMediaResources-Debug.xcconfig","buck-out/gen/submodules/LocalMediaResources/LocalMediaResources-Profile.xcconfig","buck-out/gen/submodules/LocalMediaResources/LocalMediaResources-Release.xcconfig","buck-out/gen/submodules/LocalizedPeerData/LocalizedPeerData-Debug.xcconfig","buck-out/gen/submodules/LocalizedPeerData/LocalizedPeerData-Profile.xcconfig","buck-out/gen/submodules/LocalizedPeerData/LocalizedPeerData-Release.xcconfig","buck-out/gen/submodules/LocationUI/LocationUI-Debug.xcconfig","buck-out/gen/submodules/LocationUI/LocationUI-Profile.xcconfig","buck-out/gen/submodules/LocationUI/LocationUI-Release.xcconfig","buck-out/gen/submodules/MapResourceToAvatarSizes/MapResourceToAvatarSizes-Debug.xcconfig","buck-out/gen/submodules/MapResourceToAvatarSizes/MapResourceToAvatarSizes-Profile.xcconfig","buck-out/gen/submodules/MapResourceToAvatarSizes/MapResourceToAvatarSizes-Release.xcconfig","buck-out/gen/submodules/MediaPlayer/UniversalMediaPlayer-Debug.xcconfig","buck-out/gen/submodules/MediaPlayer/UniversalMediaPlayer-Profile.xcconfig","buck-out/gen/submodules/MediaPlayer/UniversalMediaPlayer-Release.xcconfig","buck-out/gen/submodules/MediaResources/MediaResources-Debug.xcconfig","buck-out/gen/submodules/MediaResources/MediaResources-Profile.xcconfig","buck-out/gen/submodules/MediaResources/MediaResources-Release.xcconfig","buck-out/gen/submodules/MergeLists/MergeLists-Debug.xcconfig","buck-out/gen/submodules/MergeLists/MergeLists-Profile.xcconfig","buck-out/gen/submodules/MergeLists/MergeLists-Release.xcconfig","buck-out/gen/submodules/MessageReactionListUI/MessageReactionListUI-Debug.xcconfig","buck-out/gen/submodules/MessageReactionListUI/MessageReactionListUI-Profile.xcconfig","buck-out/gen/submodules/MessageReactionListUI/MessageReactionListUI-Release.xcconfig","buck-out/gen/submodules/MimeTypes/MimeTypes-Debug.xcconfig","buck-out/gen/submodules/MimeTypes/MimeTypes-Profile.xcconfig","buck-out/gen/submodules/MimeTypes/MimeTypes-Release.xcconfig","buck-out/gen/submodules/MosaicLayout/MosaicLayout-Debug.xcconfig","buck-out/gen/submodules/MosaicLayout/MosaicLayout-Profile.xcconfig","buck-out/gen/submodules/MosaicLayout/MosaicLayout-Release.xcconfig","buck-out/gen/submodules/MtProtoKit/MtProtoKit#shared-Debug.xcconfig","buck-out/gen/submodules/MtProtoKit/MtProtoKit#shared-Profile.xcconfig","buck-out/gen/submodules/MtProtoKit/MtProtoKit#shared-Release.xcconfig","buck-out/gen/submodules/MusicAlbumArtResources/MusicAlbumArtResources-Debug.xcconfig","buck-out/gen/submodules/MusicAlbumArtResources/MusicAlbumArtResources-Profile.xcconfig","buck-out/gen/submodules/MusicAlbumArtResources/MusicAlbumArtResources-Release.xcconfig","buck-out/gen/submodules/NotificationMuteSettingsUI/NotificationMuteSettingsUI-Debug.xcconfig","buck-out/gen/submodules/NotificationMuteSettingsUI/NotificationMuteSettingsUI-Profile.xcconfig","buck-out/gen/submodules/NotificationMuteSettingsUI/NotificationMuteSettingsUI-Release.xcconfig","buck-out/gen/submodules/NotificationSoundSelectionUI/NotificationSoundSelectionUI-Debug.xcconfig","buck-out/gen/submodules/NotificationSoundSelectionUI/NotificationSoundSelectionUI-Profile.xcconfig","buck-out/gen/submodules/NotificationSoundSelectionUI/NotificationSoundSelectionUI-Release.xcconfig","buck-out/gen/submodules/OpenInExternalAppUI/OpenInExternalAppUI-Debug.xcconfig","buck-out/gen/submodules/OpenInExternalAppUI/OpenInExternalAppUI-Profile.xcconfig","buck-out/gen/submodules/OpenInExternalAppUI/OpenInExternalAppUI-Release.xcconfig","buck-out/gen/submodules/Opus/opus-Debug.xcconfig","buck-out/gen/submodules/Opus/opus-Profile.xcconfig","buck-out/gen/submodules/Opus/opus-Release.xcconfig","buck-out/gen/submodules/Opus/opus_lib-Debug.xcconfig","buck-out/gen/submodules/Opus/opus_lib-Profile.xcconfig","buck-out/gen/submodules/Opus/opus_lib-Release.xcconfig","buck-out/gen/submodules/OpusBinding/OpusBinding-Debug.xcconfig","buck-out/gen/submodules/OpusBinding/OpusBinding-Profile.xcconfig","buck-out/gen/submodules/OpusBinding/OpusBinding-Release.xcconfig","buck-out/gen/submodules/OverlayStatusController/OverlayStatusController-Debug.xcconfig","buck-out/gen/submodules/OverlayStatusController/OverlayStatusController-Profile.xcconfig","buck-out/gen/submodules/OverlayStatusController/OverlayStatusController-Release.xcconfig","buck-out/gen/submodules/PasscodeInputFieldNode/PasscodeInputFieldNode-Debug.xcconfig","buck-out/gen/submodules/PasscodeInputFieldNode/PasscodeInputFieldNode-Profile.xcconfig","buck-out/gen/submodules/PasscodeInputFieldNode/PasscodeInputFieldNode-Release.xcconfig","buck-out/gen/submodules/PasscodeUI/PasscodeUI-Debug.xcconfig","buck-out/gen/submodules/PasscodeUI/PasscodeUI-Profile.xcconfig","buck-out/gen/submodules/PasscodeUI/PasscodeUI-Release.xcconfig","buck-out/gen/submodules/PassportUI/PassportUI-Debug.xcconfig","buck-out/gen/submodules/PassportUI/PassportUI-Profile.xcconfig","buck-out/gen/submodules/PassportUI/PassportUI-Release.xcconfig","buck-out/gen/submodules/PasswordSetupUI/PasswordSetupUI-Debug.xcconfig","buck-out/gen/submodules/PasswordSetupUI/PasswordSetupUI-Profile.xcconfig","buck-out/gen/submodules/PasswordSetupUI/PasswordSetupUI-Release.xcconfig","buck-out/gen/submodules/Pdf/Pdf-Debug.xcconfig","buck-out/gen/submodules/Pdf/Pdf-Profile.xcconfig","buck-out/gen/submodules/Pdf/Pdf-Release.xcconfig","buck-out/gen/submodules/PeerAvatarGalleryUI/PeerAvatarGalleryUI-Debug.xcconfig","buck-out/gen/submodules/PeerAvatarGalleryUI/PeerAvatarGalleryUI-Profile.xcconfig","buck-out/gen/submodules/PeerAvatarGalleryUI/PeerAvatarGalleryUI-Release.xcconfig","buck-out/gen/submodules/PeerInfoUI/PeerInfoUI-Debug.xcconfig","buck-out/gen/submodules/PeerInfoUI/PeerInfoUI-Profile.xcconfig","buck-out/gen/submodules/PeerInfoUI/PeerInfoUI-Release.xcconfig","buck-out/gen/submodules/PeerOnlineMarkerNode/PeerOnlineMarkerNode-Debug.xcconfig","buck-out/gen/submodules/PeerOnlineMarkerNode/PeerOnlineMarkerNode-Profile.xcconfig","buck-out/gen/submodules/PeerOnlineMarkerNode/PeerOnlineMarkerNode-Release.xcconfig","buck-out/gen/submodules/PeerPresenceStatusManager/PeerPresenceStatusManager-Debug.xcconfig","buck-out/gen/submodules/PeerPresenceStatusManager/PeerPresenceStatusManager-Profile.xcconfig","buck-out/gen/submodules/PeerPresenceStatusManager/PeerPresenceStatusManager-Release.xcconfig","buck-out/gen/submodules/PeersNearbyIconNode/PeersNearbyIconNode-Debug.xcconfig","buck-out/gen/submodules/PeersNearbyIconNode/PeersNearbyIconNode-Profile.xcconfig","buck-out/gen/submodules/PeersNearbyIconNode/PeersNearbyIconNode-Release.xcconfig","buck-out/gen/submodules/PeersNearbyUI/PeersNearbyUI-Debug.xcconfig","buck-out/gen/submodules/PeersNearbyUI/PeersNearbyUI-Profile.xcconfig","buck-out/gen/submodules/PeersNearbyUI/PeersNearbyUI-Release.xcconfig","buck-out/gen/submodules/PersistentStringHash/PersistentStringHash-Debug.xcconfig","buck-out/gen/submodules/PersistentStringHash/PersistentStringHash-Profile.xcconfig","buck-out/gen/submodules/PersistentStringHash/PersistentStringHash-Release.xcconfig","buck-out/gen/submodules/PhoneInputNode/PhoneInputNode-Debug.xcconfig","buck-out/gen/submodules/PhoneInputNode/PhoneInputNode-Profile.xcconfig","buck-out/gen/submodules/PhoneInputNode/PhoneInputNode-Release.xcconfig","buck-out/gen/submodules/PhotoResources/PhotoResources-Debug.xcconfig","buck-out/gen/submodules/PhotoResources/PhotoResources-Profile.xcconfig","buck-out/gen/submodules/PhotoResources/PhotoResources-Release.xcconfig","buck-out/gen/submodules/PlatformRestrictionMatching/PlatformRestrictionMatching-Debug.xcconfig","buck-out/gen/submodules/PlatformRestrictionMatching/PlatformRestrictionMatching-Profile.xcconfig","buck-out/gen/submodules/PlatformRestrictionMatching/PlatformRestrictionMatching-Release.xcconfig","buck-out/gen/submodules/Postbox/Postbox#shared-Debug.xcconfig","buck-out/gen/submodules/Postbox/Postbox#shared-Profile.xcconfig","buck-out/gen/submodules/Postbox/Postbox#shared-Release.xcconfig","buck-out/gen/submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode-Debug.xcconfig","buck-out/gen/submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode-Profile.xcconfig","buck-out/gen/submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode-Release.xcconfig","buck-out/gen/submodules/QrCode/QrCode-Debug.xcconfig","buck-out/gen/submodules/QrCode/QrCode-Profile.xcconfig","buck-out/gen/submodules/QrCode/QrCode-Release.xcconfig","buck-out/gen/submodules/RMIntro/RMIntro-Debug.xcconfig","buck-out/gen/submodules/RMIntro/RMIntro-Profile.xcconfig","buck-out/gen/submodules/RMIntro/RMIntro-Release.xcconfig","buck-out/gen/submodules/RadialStatusNode/RadialStatusNode-Debug.xcconfig","buck-out/gen/submodules/RadialStatusNode/RadialStatusNode-Profile.xcconfig","buck-out/gen/submodules/RadialStatusNode/RadialStatusNode-Release.xcconfig","buck-out/gen/submodules/RaiseToListen/RaiseToListen-Debug.xcconfig","buck-out/gen/submodules/RaiseToListen/RaiseToListen-Profile.xcconfig","buck-out/gen/submodules/RaiseToListen/RaiseToListen-Release.xcconfig","buck-out/gen/submodules/ReactionSelectionNode/ReactionSelectionNode-Debug.xcconfig","buck-out/gen/submodules/ReactionSelectionNode/ReactionSelectionNode-Profile.xcconfig","buck-out/gen/submodules/ReactionSelectionNode/ReactionSelectionNode-Release.xcconfig","buck-out/gen/submodules/SSignalKit/SSignalKit/SSignalKit-Debug.xcconfig","buck-out/gen/submodules/SSignalKit/SSignalKit/SSignalKit-Profile.xcconfig","buck-out/gen/submodules/SSignalKit/SSignalKit/SSignalKit-Release.xcconfig","buck-out/gen/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit#shared-Debug.xcconfig","buck-out/gen/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit#shared-Profile.xcconfig","buck-out/gen/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit#shared-Release.xcconfig","buck-out/gen/submodules/SaveToCameraRoll/SaveToCameraRoll-Debug.xcconfig","buck-out/gen/submodules/SaveToCameraRoll/SaveToCameraRoll-Profile.xcconfig","buck-out/gen/submodules/SaveToCameraRoll/SaveToCameraRoll-Release.xcconfig","buck-out/gen/submodules/ScreenCaptureDetection/ScreenCaptureDetection-Debug.xcconfig","buck-out/gen/submodules/ScreenCaptureDetection/ScreenCaptureDetection-Profile.xcconfig","buck-out/gen/submodules/ScreenCaptureDetection/ScreenCaptureDetection-Release.xcconfig","buck-out/gen/submodules/SearchBarNode/SearchBarNode-Debug.xcconfig","buck-out/gen/submodules/SearchBarNode/SearchBarNode-Profile.xcconfig","buck-out/gen/submodules/SearchBarNode/SearchBarNode-Release.xcconfig","buck-out/gen/submodules/SearchUI/SearchUI-Debug.xcconfig","buck-out/gen/submodules/SearchUI/SearchUI-Profile.xcconfig","buck-out/gen/submodules/SearchUI/SearchUI-Release.xcconfig","buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Debug.xcconfig","buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Profile.xcconfig","buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Release.xcconfig","buck-out/gen/submodules/SelectablePeerNode/SelectablePeerNode-Debug.xcconfig","buck-out/gen/submodules/SelectablePeerNode/SelectablePeerNode-Profile.xcconfig","buck-out/gen/submodules/SelectablePeerNode/SelectablePeerNode-Release.xcconfig","buck-out/gen/submodules/SettingsUI/SettingsUI-Debug.xcconfig","buck-out/gen/submodules/SettingsUI/SettingsUI-Profile.xcconfig","buck-out/gen/submodules/SettingsUI/SettingsUI-Release.xcconfig","buck-out/gen/submodules/ShareController/ShareController-Debug.xcconfig","buck-out/gen/submodules/ShareController/ShareController-Profile.xcconfig","buck-out/gen/submodules/ShareController/ShareController-Release.xcconfig","buck-out/gen/submodules/ShareItems/ShareItems-Debug.xcconfig","buck-out/gen/submodules/ShareItems/ShareItems-Profile.xcconfig","buck-out/gen/submodules/ShareItems/ShareItems-Release.xcconfig","buck-out/gen/submodules/SinglePhoneInputNode/SinglePhoneInputNode-Debug.xcconfig","buck-out/gen/submodules/SinglePhoneInputNode/SinglePhoneInputNode-Profile.xcconfig","buck-out/gen/submodules/SinglePhoneInputNode/SinglePhoneInputNode-Release.xcconfig","buck-out/gen/submodules/SolidRoundedButtonNode/SolidRoundedButtonNode-Debug.xcconfig","buck-out/gen/submodules/SolidRoundedButtonNode/SolidRoundedButtonNode-Profile.xcconfig","buck-out/gen/submodules/SolidRoundedButtonNode/SolidRoundedButtonNode-Release.xcconfig","buck-out/gen/submodules/StickerPackPreviewUI/StickerPackPreviewUI-Debug.xcconfig","buck-out/gen/submodules/StickerPackPreviewUI/StickerPackPreviewUI-Profile.xcconfig","buck-out/gen/submodules/StickerPackPreviewUI/StickerPackPreviewUI-Release.xcconfig","buck-out/gen/submodules/StickerResources/StickerResources-Debug.xcconfig","buck-out/gen/submodules/StickerResources/StickerResources-Profile.xcconfig","buck-out/gen/submodules/StickerResources/StickerResources-Release.xcconfig","buck-out/gen/submodules/Stripe/Stripe-Debug.xcconfig","buck-out/gen/submodules/Stripe/Stripe-Profile.xcconfig","buck-out/gen/submodules/Stripe/Stripe-Release.xcconfig","buck-out/gen/submodules/SwipeToDismissGesture/SwipeToDismissGesture-Debug.xcconfig","buck-out/gen/submodules/SwipeToDismissGesture/SwipeToDismissGesture-Profile.xcconfig","buck-out/gen/submodules/SwipeToDismissGesture/SwipeToDismissGesture-Release.xcconfig","buck-out/gen/submodules/SwitchNode/SwitchNode-Debug.xcconfig","buck-out/gen/submodules/SwitchNode/SwitchNode-Profile.xcconfig","buck-out/gen/submodules/SwitchNode/SwitchNode-Release.xcconfig","buck-out/gen/submodules/TelegramApi/TelegramApi-Debug.xcconfig","buck-out/gen/submodules/TelegramApi/TelegramApi-Profile.xcconfig","buck-out/gen/submodules/TelegramApi/TelegramApi-Release.xcconfig","buck-out/gen/submodules/TelegramAudio/TelegramAudio-Debug.xcconfig","buck-out/gen/submodules/TelegramAudio/TelegramAudio-Profile.xcconfig","buck-out/gen/submodules/TelegramAudio/TelegramAudio-Release.xcconfig","buck-out/gen/submodules/TelegramBaseController/TelegramBaseController-Debug.xcconfig","buck-out/gen/submodules/TelegramBaseController/TelegramBaseController-Profile.xcconfig","buck-out/gen/submodules/TelegramBaseController/TelegramBaseController-Release.xcconfig","buck-out/gen/submodules/TelegramCallsUI/TelegramCallsUI-Debug.xcconfig","buck-out/gen/submodules/TelegramCallsUI/TelegramCallsUI-Profile.xcconfig","buck-out/gen/submodules/TelegramCallsUI/TelegramCallsUI-Release.xcconfig","buck-out/gen/submodules/TelegramCore/TelegramCore#shared-Debug.xcconfig","buck-out/gen/submodules/TelegramCore/TelegramCore#shared-Profile.xcconfig","buck-out/gen/submodules/TelegramCore/TelegramCore#shared-Release.xcconfig","buck-out/gen/submodules/TelegramNotices/TelegramNotices-Debug.xcconfig","buck-out/gen/submodules/TelegramNotices/TelegramNotices-Profile.xcconfig","buck-out/gen/submodules/TelegramNotices/TelegramNotices-Release.xcconfig","buck-out/gen/submodules/TelegramPermissions/TelegramPermissions-Debug.xcconfig","buck-out/gen/submodules/TelegramPermissions/TelegramPermissions-Profile.xcconfig","buck-out/gen/submodules/TelegramPermissions/TelegramPermissions-Release.xcconfig","buck-out/gen/submodules/TelegramPermissionsUI/TelegramPermissionsUI-Debug.xcconfig","buck-out/gen/submodules/TelegramPermissionsUI/TelegramPermissionsUI-Profile.xcconfig","buck-out/gen/submodules/TelegramPermissionsUI/TelegramPermissionsUI-Release.xcconfig","buck-out/gen/submodules/TelegramPresentationData/TelegramPresentationData-Debug.xcconfig","buck-out/gen/submodules/TelegramPresentationData/TelegramPresentationData-Profile.xcconfig","buck-out/gen/submodules/TelegramPresentationData/TelegramPresentationData-Release.xcconfig","buck-out/gen/submodules/TelegramStringFormatting/TelegramStringFormatting-Debug.xcconfig","buck-out/gen/submodules/TelegramStringFormatting/TelegramStringFormatting-Profile.xcconfig","buck-out/gen/submodules/TelegramStringFormatting/TelegramStringFormatting-Release.xcconfig","buck-out/gen/submodules/TelegramUI/TelegramUI#shared-Debug.xcconfig","buck-out/gen/submodules/TelegramUI/TelegramUI#shared-Profile.xcconfig","buck-out/gen/submodules/TelegramUI/TelegramUI#shared-Release.xcconfig","buck-out/gen/submodules/TelegramUIPreferences/TelegramUIPreferences-Debug.xcconfig","buck-out/gen/submodules/TelegramUIPreferences/TelegramUIPreferences-Profile.xcconfig","buck-out/gen/submodules/TelegramUIPreferences/TelegramUIPreferences-Release.xcconfig","buck-out/gen/submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent-Debug.xcconfig","buck-out/gen/submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent-Profile.xcconfig","buck-out/gen/submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent-Release.xcconfig","buck-out/gen/submodules/TelegramUpdateUI/TelegramUpdateUI-Debug.xcconfig","buck-out/gen/submodules/TelegramUpdateUI/TelegramUpdateUI-Profile.xcconfig","buck-out/gen/submodules/TelegramUpdateUI/TelegramUpdateUI-Release.xcconfig","buck-out/gen/submodules/TelegramVoip/TelegramVoip-Debug.xcconfig","buck-out/gen/submodules/TelegramVoip/TelegramVoip-Profile.xcconfig","buck-out/gen/submodules/TelegramVoip/TelegramVoip-Release.xcconfig","buck-out/gen/submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager-Debug.xcconfig","buck-out/gen/submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager-Profile.xcconfig","buck-out/gen/submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager-Release.xcconfig","buck-out/gen/submodules/TextFormat/TextFormat-Debug.xcconfig","buck-out/gen/submodules/TextFormat/TextFormat-Profile.xcconfig","buck-out/gen/submodules/TextFormat/TextFormat-Release.xcconfig","buck-out/gen/submodules/TextSelectionNode/TextSelectionNode-Debug.xcconfig","buck-out/gen/submodules/TextSelectionNode/TextSelectionNode-Profile.xcconfig","buck-out/gen/submodules/TextSelectionNode/TextSelectionNode-Release.xcconfig","buck-out/gen/submodules/TinyThumbnail/TinyThumbnail-Debug.xcconfig","buck-out/gen/submodules/TinyThumbnail/TinyThumbnail-Profile.xcconfig","buck-out/gen/submodules/TinyThumbnail/TinyThumbnail-Release.xcconfig","buck-out/gen/submodules/TouchDownGesture/TouchDownGesture-Debug.xcconfig","buck-out/gen/submodules/TouchDownGesture/TouchDownGesture-Profile.xcconfig","buck-out/gen/submodules/TouchDownGesture/TouchDownGesture-Release.xcconfig","buck-out/gen/submodules/Tuples/Tuples-Debug.xcconfig","buck-out/gen/submodules/Tuples/Tuples-Profile.xcconfig","buck-out/gen/submodules/Tuples/Tuples-Release.xcconfig","buck-out/gen/submodules/UndoUI/UndoUI-Debug.xcconfig","buck-out/gen/submodules/UndoUI/UndoUI-Profile.xcconfig","buck-out/gen/submodules/UndoUI/UndoUI-Release.xcconfig","buck-out/gen/submodules/UrlEscaping/UrlEscaping-Debug.xcconfig","buck-out/gen/submodules/UrlEscaping/UrlEscaping-Profile.xcconfig","buck-out/gen/submodules/UrlEscaping/UrlEscaping-Release.xcconfig","buck-out/gen/submodules/UrlHandling/UrlHandling-Debug.xcconfig","buck-out/gen/submodules/UrlHandling/UrlHandling-Profile.xcconfig","buck-out/gen/submodules/UrlHandling/UrlHandling-Release.xcconfig","buck-out/gen/submodules/WalletUI/WalletUI-Debug.xcconfig","buck-out/gen/submodules/WalletUI/WalletUI-Profile.xcconfig","buck-out/gen/submodules/WalletUI/WalletUI-Release.xcconfig","buck-out/gen/submodules/WallpaperResources/WallpaperResources-Debug.xcconfig","buck-out/gen/submodules/WallpaperResources/WallpaperResources-Profile.xcconfig","buck-out/gen/submodules/WallpaperResources/WallpaperResources-Release.xcconfig","buck-out/gen/submodules/WatchBridge/WatchBridge-Debug.xcconfig","buck-out/gen/submodules/WatchBridge/WatchBridge-Profile.xcconfig","buck-out/gen/submodules/WatchBridge/WatchBridge-Release.xcconfig","buck-out/gen/submodules/WatchBridgeAudio/WatchBridgeAudio-Debug.xcconfig","buck-out/gen/submodules/WatchBridgeAudio/WatchBridgeAudio-Profile.xcconfig","buck-out/gen/submodules/WatchBridgeAudio/WatchBridgeAudio-Release.xcconfig","buck-out/gen/submodules/WatchCommon/Host/WatchCommon-Debug.xcconfig","buck-out/gen/submodules/WatchCommon/Host/WatchCommon-Profile.xcconfig","buck-out/gen/submodules/WatchCommon/Host/WatchCommon-Release.xcconfig","buck-out/gen/submodules/WebP/WebPImage-Debug.xcconfig","buck-out/gen/submodules/WebP/WebPImage-Profile.xcconfig","buck-out/gen/submodules/WebP/WebPImage-Release.xcconfig","buck-out/gen/submodules/WebP/WebP_lib-Debug.xcconfig","buck-out/gen/submodules/WebP/WebP_lib-Profile.xcconfig","buck-out/gen/submodules/WebP/WebP_lib-Release.xcconfig","buck-out/gen/submodules/WebSearchUI/WebSearchUI-Debug.xcconfig","buck-out/gen/submodules/WebSearchUI/WebSearchUI-Profile.xcconfig","buck-out/gen/submodules/WebSearchUI/WebSearchUI-Release.xcconfig","buck-out/gen/submodules/WebUI/WebUI-Debug.xcconfig","buck-out/gen/submodules/WebUI/WebUI-Profile.xcconfig","buck-out/gen/submodules/WebUI/WebUI-Release.xcconfig","buck-out/gen/submodules/WebsiteType/WebsiteType-Debug.xcconfig","buck-out/gen/submodules/WebsiteType/WebsiteType-Profile.xcconfig","buck-out/gen/submodules/WebsiteType/WebsiteType-Release.xcconfig","buck-out/gen/submodules/YuvConversion/YuvConversion-Debug.xcconfig","buck-out/gen/submodules/YuvConversion/YuvConversion-Profile.xcconfig","buck-out/gen/submodules/YuvConversion/YuvConversion-Release.xcconfig","buck-out/gen/submodules/libphonenumber/libphonenumber-Debug.xcconfig","buck-out/gen/submodules/libphonenumber/libphonenumber-Profile.xcconfig","buck-out/gen/submodules/libphonenumber/libphonenumber-Release.xcconfig","buck-out/gen/submodules/libtgvoip/libtgvoip-Debug.xcconfig","buck-out/gen/submodules/libtgvoip/libtgvoip-Profile.xcconfig","buck-out/gen/submodules/libtgvoip/libtgvoip-Release.xcconfig","buck-out/gen/submodules/lottie-ios/Lottie-Debug.xcconfig","buck-out/gen/submodules/lottie-ios/Lottie-Profile.xcconfig","buck-out/gen/submodules/lottie-ios/Lottie-Release.xcconfig","buck-out/gen/submodules/openssl/openssl-Debug.xcconfig","buck-out/gen/submodules/openssl/openssl-Profile.xcconfig","buck-out/gen/submodules/openssl/openssl-Release.xcconfig","buck-out/gen/submodules/rlottie/RLottieBinding-Debug.xcconfig","buck-out/gen/submodules/rlottie/RLottieBinding-Profile.xcconfig","buck-out/gen/submodules/rlottie/RLottieBinding-Release.xcconfig","buck-out/gen/submodules/sqlcipher/sqlcipher-Debug.xcconfig","buck-out/gen/submodules/sqlcipher/sqlcipher-Profile.xcconfig","buck-out/gen/submodules/sqlcipher/sqlcipher-Release.xcconfig","buck-out/gen/submodules/ton/ton-Debug.xcconfig","buck-out/gen/submodules/ton/ton-Profile.xcconfig","buck-out/gen/submodules/ton/ton-Release.xcconfig"],"copy-in-xcode":[]} \ No newline at end of file +{"required-targets":["//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_ac3_parser.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_adts_parser.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_avcodec.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_avdct.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_avfft.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_d3d11va.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_dirac.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_dv_profile.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_dxva2.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_jni.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_mediacodec.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_qsv.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_vaapi.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_vdpau.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_version.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_videotoolbox.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_vorbis_parser.h","//submodules/FFMpeg:ffmpeg_header_libavcodec_sub_xvmc.h","//submodules/FFMpeg:ffmpeg_header_libavformat_sub_avformat.h","//submodules/FFMpeg:ffmpeg_header_libavformat_sub_avio.h","//submodules/FFMpeg:ffmpeg_header_libavformat_sub_version.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_adler32.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_aes.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_aes_ctr.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_attributes.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_audio_fifo.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avassert.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avconfig.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avstring.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_avutil.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_base64.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_blowfish.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_bprint.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_bswap.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_buffer.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_camellia.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_cast5.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_channel_layout.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_common.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_cpu.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_crc.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_des.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_dict.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_display.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_downmix_info.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_encryption_info.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_error.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_eval.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_ffversion.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_fifo.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_file.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_frame.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hash.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hmac.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_cuda.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_d3d11va.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_drm.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_dxva2.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_mediacodec.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_qsv.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_vaapi.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_vdpau.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_hwcontext_videotoolbox.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_imgutils.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_intfloat.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_intreadwrite.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_lfg.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_log.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_lzo.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_macros.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_mastering_display_metadata.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_mathematics.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_md5.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_mem.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_motion_vector.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_murmur3.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_opt.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_parseutils.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_pixdesc.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_pixelutils.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_pixfmt.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_random_seed.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_rational.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_rc4.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_replaygain.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_ripemd.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_samplefmt.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_sha.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_sha512.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_spherical.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_stereo3d.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_tea.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_threadmessage.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_time.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_timecode.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_timestamp.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_tree.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_twofish.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_version.h","//submodules/FFMpeg:ffmpeg_header_libavutil_sub_xtea.h","//submodules/FFMpeg:ffmpeg_header_libswresample_sub_swresample.h","//submodules/FFMpeg:ffmpeg_header_libswresample_sub_version.h","//submodules/FFMpeg:libffmpeg_build","//submodules/Opus:opus_lib_file","//submodules/WebP:WebP_lib_file","//submodules/openssl:openssl_build_merged","//submodules/openssl:openssl_header_openssl_sub_aes.h","//submodules/openssl:openssl_header_openssl_sub_asn1.h","//submodules/openssl:openssl_header_openssl_sub_asn1_mac.h","//submodules/openssl:openssl_header_openssl_sub_asn1err.h","//submodules/openssl:openssl_header_openssl_sub_asn1t.h","//submodules/openssl:openssl_header_openssl_sub_async.h","//submodules/openssl:openssl_header_openssl_sub_asyncerr.h","//submodules/openssl:openssl_header_openssl_sub_bio.h","//submodules/openssl:openssl_header_openssl_sub_bioerr.h","//submodules/openssl:openssl_header_openssl_sub_blowfish.h","//submodules/openssl:openssl_header_openssl_sub_bn.h","//submodules/openssl:openssl_header_openssl_sub_bnerr.h","//submodules/openssl:openssl_header_openssl_sub_buffer.h","//submodules/openssl:openssl_header_openssl_sub_buffererr.h","//submodules/openssl:openssl_header_openssl_sub_camellia.h","//submodules/openssl:openssl_header_openssl_sub_cast.h","//submodules/openssl:openssl_header_openssl_sub_cmac.h","//submodules/openssl:openssl_header_openssl_sub_cms.h","//submodules/openssl:openssl_header_openssl_sub_cmserr.h","//submodules/openssl:openssl_header_openssl_sub_comp.h","//submodules/openssl:openssl_header_openssl_sub_comperr.h","//submodules/openssl:openssl_header_openssl_sub_conf.h","//submodules/openssl:openssl_header_openssl_sub_conf_api.h","//submodules/openssl:openssl_header_openssl_sub_conferr.h","//submodules/openssl:openssl_header_openssl_sub_crypto.h","//submodules/openssl:openssl_header_openssl_sub_cryptoerr.h","//submodules/openssl:openssl_header_openssl_sub_ct.h","//submodules/openssl:openssl_header_openssl_sub_cterr.h","//submodules/openssl:openssl_header_openssl_sub_des.h","//submodules/openssl:openssl_header_openssl_sub_dh.h","//submodules/openssl:openssl_header_openssl_sub_dherr.h","//submodules/openssl:openssl_header_openssl_sub_dsa.h","//submodules/openssl:openssl_header_openssl_sub_dsaerr.h","//submodules/openssl:openssl_header_openssl_sub_dtls1.h","//submodules/openssl:openssl_header_openssl_sub_e_os2.h","//submodules/openssl:openssl_header_openssl_sub_ebcdic.h","//submodules/openssl:openssl_header_openssl_sub_ec.h","//submodules/openssl:openssl_header_openssl_sub_ecdh.h","//submodules/openssl:openssl_header_openssl_sub_ecdsa.h","//submodules/openssl:openssl_header_openssl_sub_ecerr.h","//submodules/openssl:openssl_header_openssl_sub_engine.h","//submodules/openssl:openssl_header_openssl_sub_engineerr.h","//submodules/openssl:openssl_header_openssl_sub_err.h","//submodules/openssl:openssl_header_openssl_sub_evp.h","//submodules/openssl:openssl_header_openssl_sub_evperr.h","//submodules/openssl:openssl_header_openssl_sub_hmac.h","//submodules/openssl:openssl_header_openssl_sub_idea.h","//submodules/openssl:openssl_header_openssl_sub_kdf.h","//submodules/openssl:openssl_header_openssl_sub_kdferr.h","//submodules/openssl:openssl_header_openssl_sub_lhash.h","//submodules/openssl:openssl_header_openssl_sub_md2.h","//submodules/openssl:openssl_header_openssl_sub_md4.h","//submodules/openssl:openssl_header_openssl_sub_md5.h","//submodules/openssl:openssl_header_openssl_sub_mdc2.h","//submodules/openssl:openssl_header_openssl_sub_modes.h","//submodules/openssl:openssl_header_openssl_sub_obj_mac.h","//submodules/openssl:openssl_header_openssl_sub_objects.h","//submodules/openssl:openssl_header_openssl_sub_objectserr.h","//submodules/openssl:openssl_header_openssl_sub_ocsp.h","//submodules/openssl:openssl_header_openssl_sub_ocsperr.h","//submodules/openssl:openssl_header_openssl_sub_opensslconf.h","//submodules/openssl:openssl_header_openssl_sub_opensslv.h","//submodules/openssl:openssl_header_openssl_sub_ossl_typ.h","//submodules/openssl:openssl_header_openssl_sub_pem.h","//submodules/openssl:openssl_header_openssl_sub_pem2.h","//submodules/openssl:openssl_header_openssl_sub_pemerr.h","//submodules/openssl:openssl_header_openssl_sub_pkcs12.h","//submodules/openssl:openssl_header_openssl_sub_pkcs12err.h","//submodules/openssl:openssl_header_openssl_sub_pkcs7.h","//submodules/openssl:openssl_header_openssl_sub_pkcs7err.h","//submodules/openssl:openssl_header_openssl_sub_rand.h","//submodules/openssl:openssl_header_openssl_sub_rand_drbg.h","//submodules/openssl:openssl_header_openssl_sub_randerr.h","//submodules/openssl:openssl_header_openssl_sub_rc2.h","//submodules/openssl:openssl_header_openssl_sub_rc4.h","//submodules/openssl:openssl_header_openssl_sub_rc5.h","//submodules/openssl:openssl_header_openssl_sub_ripemd.h","//submodules/openssl:openssl_header_openssl_sub_rsa.h","//submodules/openssl:openssl_header_openssl_sub_rsaerr.h","//submodules/openssl:openssl_header_openssl_sub_safestack.h","//submodules/openssl:openssl_header_openssl_sub_seed.h","//submodules/openssl:openssl_header_openssl_sub_sha.h","//submodules/openssl:openssl_header_openssl_sub_srp.h","//submodules/openssl:openssl_header_openssl_sub_srtp.h","//submodules/openssl:openssl_header_openssl_sub_ssl.h","//submodules/openssl:openssl_header_openssl_sub_ssl2.h","//submodules/openssl:openssl_header_openssl_sub_ssl3.h","//submodules/openssl:openssl_header_openssl_sub_sslerr.h","//submodules/openssl:openssl_header_openssl_sub_stack.h","//submodules/openssl:openssl_header_openssl_sub_store.h","//submodules/openssl:openssl_header_openssl_sub_storeerr.h","//submodules/openssl:openssl_header_openssl_sub_symhacks.h","//submodules/openssl:openssl_header_openssl_sub_tls1.h","//submodules/openssl:openssl_header_openssl_sub_ts.h","//submodules/openssl:openssl_header_openssl_sub_tserr.h","//submodules/openssl:openssl_header_openssl_sub_txt_db.h","//submodules/openssl:openssl_header_openssl_sub_ui.h","//submodules/openssl:openssl_header_openssl_sub_uierr.h","//submodules/openssl:openssl_header_openssl_sub_whrlpool.h","//submodules/openssl:openssl_header_openssl_sub_x509.h","//submodules/openssl:openssl_header_openssl_sub_x509_vfy.h","//submodules/openssl:openssl_header_openssl_sub_x509err.h","//submodules/openssl:openssl_header_openssl_sub_x509v3.h","//submodules/openssl:openssl_header_openssl_sub_x509v3err.h","//submodules/ton:ton_build","//submodules/ton:ton_header_auto_sub_tl_sub_tonlib_api.h","//submodules/ton:ton_header_td_sub_utils_sub_SharedSlice.h","//submodules/ton:ton_header_td_sub_utils_sub_Slice-decl.h","//submodules/ton:ton_header_td_sub_utils_sub_Slice.h","//submodules/ton:ton_header_td_sub_utils_sub_check.h","//submodules/ton:ton_header_td_sub_utils_sub_common.h","//submodules/ton:ton_header_td_sub_utils_sub_config.h","//submodules/ton:ton_header_td_sub_utils_sub_int_types.h","//submodules/ton:ton_header_td_sub_utils_sub_port_sub_platform.h","//submodules/ton:ton_header_td_sub_utils_sub_unique_ptr.h","//submodules/ton:ton_header_tl_sub_TlObject.h","//submodules/ton:ton_header_tonlib_sub_Client.h","//submodules/ton:ton_header_tonlib_sub_tonlib_client_json.h","//submodules/ton:ton_header_tonlib_sub_tonlibjson_export.h"],"xcconfig-paths":["buck-out/gen/AppLibrary-Debug.xcconfig","buck-out/gen/AppLibrary-Profile.xcconfig","buck-out/gen/AppLibrary-Release.xcconfig","buck-out/gen/IntentsExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/IntentsExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/IntentsExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/NotificationContentExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/NotificationContentExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/NotificationContentExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/NotificationServiceExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/NotificationServiceExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/NotificationServiceExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/ShareExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/ShareExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/ShareExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/Telegram-Debug.xcconfig","buck-out/gen/Telegram-Profile.xcconfig","buck-out/gen/Telegram-Release.xcconfig","buck-out/gen/WatchApp#watchsimulator-i386-Debug.xcconfig","buck-out/gen/WatchApp#watchsimulator-i386-Profile.xcconfig","buck-out/gen/WatchApp#watchsimulator-i386-Release.xcconfig","buck-out/gen/WatchAppExtension#watchsimulator-i386-Debug.xcconfig","buck-out/gen/WatchAppExtension#watchsimulator-i386-Profile.xcconfig","buck-out/gen/WatchAppExtension#watchsimulator-i386-Release.xcconfig","buck-out/gen/WidgetExtension#iphonesimulator-x86_64-Debug.xcconfig","buck-out/gen/WidgetExtension#iphonesimulator-x86_64-Profile.xcconfig","buck-out/gen/WidgetExtension#iphonesimulator-x86_64-Release.xcconfig","buck-out/gen/submodules/AccountContext/AccountContext-Debug.xcconfig","buck-out/gen/submodules/AccountContext/AccountContext-Profile.xcconfig","buck-out/gen/submodules/AccountContext/AccountContext-Release.xcconfig","buck-out/gen/submodules/ActionSheetPeerItem/ActionSheetPeerItem-Debug.xcconfig","buck-out/gen/submodules/ActionSheetPeerItem/ActionSheetPeerItem-Profile.xcconfig","buck-out/gen/submodules/ActionSheetPeerItem/ActionSheetPeerItem-Release.xcconfig","buck-out/gen/submodules/ActivityIndicator/ActivityIndicator-Debug.xcconfig","buck-out/gen/submodules/ActivityIndicator/ActivityIndicator-Profile.xcconfig","buck-out/gen/submodules/ActivityIndicator/ActivityIndicator-Release.xcconfig","buck-out/gen/submodules/AlertUI/AlertUI-Debug.xcconfig","buck-out/gen/submodules/AlertUI/AlertUI-Profile.xcconfig","buck-out/gen/submodules/AlertUI/AlertUI-Release.xcconfig","buck-out/gen/submodules/AnimationUI/AnimationUI-Debug.xcconfig","buck-out/gen/submodules/AnimationUI/AnimationUI-Profile.xcconfig","buck-out/gen/submodules/AnimationUI/AnimationUI-Release.xcconfig","buck-out/gen/submodules/AppBundle/AppBundle-Debug.xcconfig","buck-out/gen/submodules/AppBundle/AppBundle-Profile.xcconfig","buck-out/gen/submodules/AppBundle/AppBundle-Release.xcconfig","buck-out/gen/submodules/AsyncDisplayKit/AsyncDisplayKit#shared-Debug.xcconfig","buck-out/gen/submodules/AsyncDisplayKit/AsyncDisplayKit#shared-Profile.xcconfig","buck-out/gen/submodules/AsyncDisplayKit/AsyncDisplayKit#shared-Release.xcconfig","buck-out/gen/submodules/AuthorizationUI/AuthorizationUI-Debug.xcconfig","buck-out/gen/submodules/AuthorizationUI/AuthorizationUI-Profile.xcconfig","buck-out/gen/submodules/AuthorizationUI/AuthorizationUI-Release.xcconfig","buck-out/gen/submodules/AvatarNode/AvatarNode-Debug.xcconfig","buck-out/gen/submodules/AvatarNode/AvatarNode-Profile.xcconfig","buck-out/gen/submodules/AvatarNode/AvatarNode-Release.xcconfig","buck-out/gen/submodules/BotPaymentsUI/BotPaymentsUI-Debug.xcconfig","buck-out/gen/submodules/BotPaymentsUI/BotPaymentsUI-Profile.xcconfig","buck-out/gen/submodules/BotPaymentsUI/BotPaymentsUI-Release.xcconfig","buck-out/gen/submodules/BuildConfig/BuildConfig-Debug.xcconfig","buck-out/gen/submodules/BuildConfig/BuildConfig-Profile.xcconfig","buck-out/gen/submodules/BuildConfig/BuildConfig-Release.xcconfig","buck-out/gen/submodules/CallListUI/CallListUI-Debug.xcconfig","buck-out/gen/submodules/CallListUI/CallListUI-Profile.xcconfig","buck-out/gen/submodules/CallListUI/CallListUI-Release.xcconfig","buck-out/gen/submodules/Camera/Camera-Debug.xcconfig","buck-out/gen/submodules/Camera/Camera-Profile.xcconfig","buck-out/gen/submodules/Camera/Camera-Release.xcconfig","buck-out/gen/submodules/ChatListSearchItemHeader/ChatListSearchItemHeader-Debug.xcconfig","buck-out/gen/submodules/ChatListSearchItemHeader/ChatListSearchItemHeader-Profile.xcconfig","buck-out/gen/submodules/ChatListSearchItemHeader/ChatListSearchItemHeader-Release.xcconfig","buck-out/gen/submodules/ChatListSearchItemNode/ChatListSearchItemNode-Debug.xcconfig","buck-out/gen/submodules/ChatListSearchItemNode/ChatListSearchItemNode-Profile.xcconfig","buck-out/gen/submodules/ChatListSearchItemNode/ChatListSearchItemNode-Release.xcconfig","buck-out/gen/submodules/ChatListSearchRecentPeersNode/ChatListSearchRecentPeersNode-Debug.xcconfig","buck-out/gen/submodules/ChatListSearchRecentPeersNode/ChatListSearchRecentPeersNode-Profile.xcconfig","buck-out/gen/submodules/ChatListSearchRecentPeersNode/ChatListSearchRecentPeersNode-Release.xcconfig","buck-out/gen/submodules/ChatListUI/ChatListUI-Debug.xcconfig","buck-out/gen/submodules/ChatListUI/ChatListUI-Profile.xcconfig","buck-out/gen/submodules/ChatListUI/ChatListUI-Release.xcconfig","buck-out/gen/submodules/ChatTitleActivityNode/ChatTitleActivityNode-Debug.xcconfig","buck-out/gen/submodules/ChatTitleActivityNode/ChatTitleActivityNode-Profile.xcconfig","buck-out/gen/submodules/ChatTitleActivityNode/ChatTitleActivityNode-Release.xcconfig","buck-out/gen/submodules/CheckNode/CheckNode-Debug.xcconfig","buck-out/gen/submodules/CheckNode/CheckNode-Profile.xcconfig","buck-out/gen/submodules/CheckNode/CheckNode-Release.xcconfig","buck-out/gen/submodules/ComposePollUI/ComposePollUI-Debug.xcconfig","buck-out/gen/submodules/ComposePollUI/ComposePollUI-Profile.xcconfig","buck-out/gen/submodules/ComposePollUI/ComposePollUI-Release.xcconfig","buck-out/gen/submodules/ContactListUI/ContactListUI-Debug.xcconfig","buck-out/gen/submodules/ContactListUI/ContactListUI-Profile.xcconfig","buck-out/gen/submodules/ContactListUI/ContactListUI-Release.xcconfig","buck-out/gen/submodules/ContactsPeerItem/ContactsPeerItem-Debug.xcconfig","buck-out/gen/submodules/ContactsPeerItem/ContactsPeerItem-Profile.xcconfig","buck-out/gen/submodules/ContactsPeerItem/ContactsPeerItem-Release.xcconfig","buck-out/gen/submodules/ContextUI/ContextUI-Debug.xcconfig","buck-out/gen/submodules/ContextUI/ContextUI-Profile.xcconfig","buck-out/gen/submodules/ContextUI/ContextUI-Release.xcconfig","buck-out/gen/submodules/CounterContollerTitleView/CounterContollerTitleView-Debug.xcconfig","buck-out/gen/submodules/CounterContollerTitleView/CounterContollerTitleView-Profile.xcconfig","buck-out/gen/submodules/CounterContollerTitleView/CounterContollerTitleView-Release.xcconfig","buck-out/gen/submodules/CountrySelectionUI/CountrySelectionUI-Debug.xcconfig","buck-out/gen/submodules/CountrySelectionUI/CountrySelectionUI-Profile.xcconfig","buck-out/gen/submodules/CountrySelectionUI/CountrySelectionUI-Release.xcconfig","buck-out/gen/submodules/Crc32/Crc32-Debug.xcconfig","buck-out/gen/submodules/Crc32/Crc32-Profile.xcconfig","buck-out/gen/submodules/Crc32/Crc32-Release.xcconfig","buck-out/gen/submodules/DateSelectionUI/DateSelectionUI-Debug.xcconfig","buck-out/gen/submodules/DateSelectionUI/DateSelectionUI-Profile.xcconfig","buck-out/gen/submodules/DateSelectionUI/DateSelectionUI-Release.xcconfig","buck-out/gen/submodules/DeleteChatPeerActionSheetItem/DeleteChatPeerActionSheetItem-Debug.xcconfig","buck-out/gen/submodules/DeleteChatPeerActionSheetItem/DeleteChatPeerActionSheetItem-Profile.xcconfig","buck-out/gen/submodules/DeleteChatPeerActionSheetItem/DeleteChatPeerActionSheetItem-Release.xcconfig","buck-out/gen/submodules/DeviceAccess/DeviceAccess-Debug.xcconfig","buck-out/gen/submodules/DeviceAccess/DeviceAccess-Profile.xcconfig","buck-out/gen/submodules/DeviceAccess/DeviceAccess-Release.xcconfig","buck-out/gen/submodules/DeviceLocationManager/DeviceLocationManager-Debug.xcconfig","buck-out/gen/submodules/DeviceLocationManager/DeviceLocationManager-Profile.xcconfig","buck-out/gen/submodules/DeviceLocationManager/DeviceLocationManager-Release.xcconfig","buck-out/gen/submodules/DeviceProximity/DeviceProximity-Debug.xcconfig","buck-out/gen/submodules/DeviceProximity/DeviceProximity-Profile.xcconfig","buck-out/gen/submodules/DeviceProximity/DeviceProximity-Release.xcconfig","buck-out/gen/submodules/DirectionalPanGesture/DirectionalPanGesture-Debug.xcconfig","buck-out/gen/submodules/DirectionalPanGesture/DirectionalPanGesture-Profile.xcconfig","buck-out/gen/submodules/DirectionalPanGesture/DirectionalPanGesture-Release.xcconfig","buck-out/gen/submodules/Display/Display#shared-Debug.xcconfig","buck-out/gen/submodules/Display/Display#shared-Profile.xcconfig","buck-out/gen/submodules/Display/Display#shared-Release.xcconfig","buck-out/gen/submodules/Emoji/Emoji-Debug.xcconfig","buck-out/gen/submodules/Emoji/Emoji-Profile.xcconfig","buck-out/gen/submodules/Emoji/Emoji-Release.xcconfig","buck-out/gen/submodules/EncryptionKeyVisualization/EncryptionKeyVisualization-Debug.xcconfig","buck-out/gen/submodules/EncryptionKeyVisualization/EncryptionKeyVisualization-Profile.xcconfig","buck-out/gen/submodules/EncryptionKeyVisualization/EncryptionKeyVisualization-Release.xcconfig","buck-out/gen/submodules/FFMpeg/FFMpeg-Debug.xcconfig","buck-out/gen/submodules/FFMpeg/FFMpeg-Profile.xcconfig","buck-out/gen/submodules/FFMpeg/FFMpeg-Release.xcconfig","buck-out/gen/submodules/FFMpeg/libffmpeg-Debug.xcconfig","buck-out/gen/submodules/FFMpeg/libffmpeg-Profile.xcconfig","buck-out/gen/submodules/FFMpeg/libffmpeg-Release.xcconfig","buck-out/gen/submodules/GZip/GZip-Debug.xcconfig","buck-out/gen/submodules/GZip/GZip-Profile.xcconfig","buck-out/gen/submodules/GZip/GZip-Release.xcconfig","buck-out/gen/submodules/GalleryUI/GalleryUI-Debug.xcconfig","buck-out/gen/submodules/GalleryUI/GalleryUI-Profile.xcconfig","buck-out/gen/submodules/GalleryUI/GalleryUI-Release.xcconfig","buck-out/gen/submodules/GameUI/GameUI-Debug.xcconfig","buck-out/gen/submodules/GameUI/GameUI-Profile.xcconfig","buck-out/gen/submodules/GameUI/GameUI-Release.xcconfig","buck-out/gen/submodules/Geocoding/Geocoding-Debug.xcconfig","buck-out/gen/submodules/Geocoding/Geocoding-Profile.xcconfig","buck-out/gen/submodules/Geocoding/Geocoding-Release.xcconfig","buck-out/gen/submodules/GlassButtonNode/GlassButtonNode-Debug.xcconfig","buck-out/gen/submodules/GlassButtonNode/GlassButtonNode-Profile.xcconfig","buck-out/gen/submodules/GlassButtonNode/GlassButtonNode-Release.xcconfig","buck-out/gen/submodules/GridMessageSelectionNode/GridMessageSelectionNode-Debug.xcconfig","buck-out/gen/submodules/GridMessageSelectionNode/GridMessageSelectionNode-Profile.xcconfig","buck-out/gen/submodules/GridMessageSelectionNode/GridMessageSelectionNode-Release.xcconfig","buck-out/gen/submodules/HashtagSearchUI/HashtagSearchUI-Debug.xcconfig","buck-out/gen/submodules/HashtagSearchUI/HashtagSearchUI-Profile.xcconfig","buck-out/gen/submodules/HashtagSearchUI/HashtagSearchUI-Release.xcconfig","buck-out/gen/submodules/HexColor/HexColor-Debug.xcconfig","buck-out/gen/submodules/HexColor/HexColor-Profile.xcconfig","buck-out/gen/submodules/HexColor/HexColor-Release.xcconfig","buck-out/gen/submodules/HockeySDK-iOS/HockeySDK-Debug.xcconfig","buck-out/gen/submodules/HockeySDK-iOS/HockeySDK-Profile.xcconfig","buck-out/gen/submodules/HockeySDK-iOS/HockeySDK-Release.xcconfig","buck-out/gen/submodules/HorizontalPeerItem/HorizontalPeerItem-Debug.xcconfig","buck-out/gen/submodules/HorizontalPeerItem/HorizontalPeerItem-Profile.xcconfig","buck-out/gen/submodules/HorizontalPeerItem/HorizontalPeerItem-Release.xcconfig","buck-out/gen/submodules/ImageBlur/ImageBlur-Debug.xcconfig","buck-out/gen/submodules/ImageBlur/ImageBlur-Profile.xcconfig","buck-out/gen/submodules/ImageBlur/ImageBlur-Release.xcconfig","buck-out/gen/submodules/ImageCompression/ImageCompression-Debug.xcconfig","buck-out/gen/submodules/ImageCompression/ImageCompression-Profile.xcconfig","buck-out/gen/submodules/ImageCompression/ImageCompression-Release.xcconfig","buck-out/gen/submodules/ImageTransparency/ImageTransparency-Debug.xcconfig","buck-out/gen/submodules/ImageTransparency/ImageTransparency-Profile.xcconfig","buck-out/gen/submodules/ImageTransparency/ImageTransparency-Release.xcconfig","buck-out/gen/submodules/InstantPageCache/InstantPageCache-Debug.xcconfig","buck-out/gen/submodules/InstantPageCache/InstantPageCache-Profile.xcconfig","buck-out/gen/submodules/InstantPageCache/InstantPageCache-Release.xcconfig","buck-out/gen/submodules/InstantPageUI/InstantPageUI-Debug.xcconfig","buck-out/gen/submodules/InstantPageUI/InstantPageUI-Profile.xcconfig","buck-out/gen/submodules/InstantPageUI/InstantPageUI-Release.xcconfig","buck-out/gen/submodules/ItemListAddressItem/ItemListAddressItem-Debug.xcconfig","buck-out/gen/submodules/ItemListAddressItem/ItemListAddressItem-Profile.xcconfig","buck-out/gen/submodules/ItemListAddressItem/ItemListAddressItem-Release.xcconfig","buck-out/gen/submodules/ItemListAvatarAndNameInfoItem/ItemListAvatarAndNameInfoItem-Debug.xcconfig","buck-out/gen/submodules/ItemListAvatarAndNameInfoItem/ItemListAvatarAndNameInfoItem-Profile.xcconfig","buck-out/gen/submodules/ItemListAvatarAndNameInfoItem/ItemListAvatarAndNameInfoItem-Release.xcconfig","buck-out/gen/submodules/ItemListPeerActionItem/ItemListPeerActionItem-Debug.xcconfig","buck-out/gen/submodules/ItemListPeerActionItem/ItemListPeerActionItem-Profile.xcconfig","buck-out/gen/submodules/ItemListPeerActionItem/ItemListPeerActionItem-Release.xcconfig","buck-out/gen/submodules/ItemListPeerItem/ItemListPeerItem-Debug.xcconfig","buck-out/gen/submodules/ItemListPeerItem/ItemListPeerItem-Profile.xcconfig","buck-out/gen/submodules/ItemListPeerItem/ItemListPeerItem-Release.xcconfig","buck-out/gen/submodules/ItemListStickerPackItem/ItemListStickerPackItem-Debug.xcconfig","buck-out/gen/submodules/ItemListStickerPackItem/ItemListStickerPackItem-Profile.xcconfig","buck-out/gen/submodules/ItemListStickerPackItem/ItemListStickerPackItem-Release.xcconfig","buck-out/gen/submodules/ItemListUI/ItemListUI-Debug.xcconfig","buck-out/gen/submodules/ItemListUI/ItemListUI-Profile.xcconfig","buck-out/gen/submodules/ItemListUI/ItemListUI-Release.xcconfig","buck-out/gen/submodules/JoinLinkPreviewUI/JoinLinkPreviewUI-Debug.xcconfig","buck-out/gen/submodules/JoinLinkPreviewUI/JoinLinkPreviewUI-Profile.xcconfig","buck-out/gen/submodules/JoinLinkPreviewUI/JoinLinkPreviewUI-Release.xcconfig","buck-out/gen/submodules/LanguageLinkPreviewUI/LanguageLinkPreviewUI-Debug.xcconfig","buck-out/gen/submodules/LanguageLinkPreviewUI/LanguageLinkPreviewUI-Profile.xcconfig","buck-out/gen/submodules/LanguageLinkPreviewUI/LanguageLinkPreviewUI-Release.xcconfig","buck-out/gen/submodules/LanguageSuggestionUI/LanguageSuggestionUI-Debug.xcconfig","buck-out/gen/submodules/LanguageSuggestionUI/LanguageSuggestionUI-Profile.xcconfig","buck-out/gen/submodules/LanguageSuggestionUI/LanguageSuggestionUI-Release.xcconfig","buck-out/gen/submodules/LegacyComponents/LegacyComponents-Debug.xcconfig","buck-out/gen/submodules/LegacyComponents/LegacyComponents-Profile.xcconfig","buck-out/gen/submodules/LegacyComponents/LegacyComponents-Release.xcconfig","buck-out/gen/submodules/LegacyDataImport/LegacyDataImport-Debug.xcconfig","buck-out/gen/submodules/LegacyDataImport/LegacyDataImport-Profile.xcconfig","buck-out/gen/submodules/LegacyDataImport/LegacyDataImport-Release.xcconfig","buck-out/gen/submodules/LegacyMediaPickerUI/LegacyMediaPickerUI-Debug.xcconfig","buck-out/gen/submodules/LegacyMediaPickerUI/LegacyMediaPickerUI-Profile.xcconfig","buck-out/gen/submodules/LegacyMediaPickerUI/LegacyMediaPickerUI-Release.xcconfig","buck-out/gen/submodules/LegacyUI/LegacyUI-Debug.xcconfig","buck-out/gen/submodules/LegacyUI/LegacyUI-Profile.xcconfig","buck-out/gen/submodules/LegacyUI/LegacyUI-Release.xcconfig","buck-out/gen/submodules/LightweightAccountData/LightweightAccountData-Debug.xcconfig","buck-out/gen/submodules/LightweightAccountData/LightweightAccountData-Profile.xcconfig","buck-out/gen/submodules/LightweightAccountData/LightweightAccountData-Release.xcconfig","buck-out/gen/submodules/ListSectionHeaderNode/ListSectionHeaderNode-Debug.xcconfig","buck-out/gen/submodules/ListSectionHeaderNode/ListSectionHeaderNode-Profile.xcconfig","buck-out/gen/submodules/ListSectionHeaderNode/ListSectionHeaderNode-Release.xcconfig","buck-out/gen/submodules/LiveLocationManager/LiveLocationManager-Debug.xcconfig","buck-out/gen/submodules/LiveLocationManager/LiveLocationManager-Profile.xcconfig","buck-out/gen/submodules/LiveLocationManager/LiveLocationManager-Release.xcconfig","buck-out/gen/submodules/LiveLocationPositionNode/LiveLocationPositionNode-Debug.xcconfig","buck-out/gen/submodules/LiveLocationPositionNode/LiveLocationPositionNode-Profile.xcconfig","buck-out/gen/submodules/LiveLocationPositionNode/LiveLocationPositionNode-Release.xcconfig","buck-out/gen/submodules/LiveLocationTimerNode/LiveLocationTimerNode-Debug.xcconfig","buck-out/gen/submodules/LiveLocationTimerNode/LiveLocationTimerNode-Profile.xcconfig","buck-out/gen/submodules/LiveLocationTimerNode/LiveLocationTimerNode-Release.xcconfig","buck-out/gen/submodules/LocalAuth/LocalAuth-Debug.xcconfig","buck-out/gen/submodules/LocalAuth/LocalAuth-Profile.xcconfig","buck-out/gen/submodules/LocalAuth/LocalAuth-Release.xcconfig","buck-out/gen/submodules/LocalMediaResources/LocalMediaResources-Debug.xcconfig","buck-out/gen/submodules/LocalMediaResources/LocalMediaResources-Profile.xcconfig","buck-out/gen/submodules/LocalMediaResources/LocalMediaResources-Release.xcconfig","buck-out/gen/submodules/LocalizedPeerData/LocalizedPeerData-Debug.xcconfig","buck-out/gen/submodules/LocalizedPeerData/LocalizedPeerData-Profile.xcconfig","buck-out/gen/submodules/LocalizedPeerData/LocalizedPeerData-Release.xcconfig","buck-out/gen/submodules/LocationUI/LocationUI-Debug.xcconfig","buck-out/gen/submodules/LocationUI/LocationUI-Profile.xcconfig","buck-out/gen/submodules/LocationUI/LocationUI-Release.xcconfig","buck-out/gen/submodules/MapResourceToAvatarSizes/MapResourceToAvatarSizes-Debug.xcconfig","buck-out/gen/submodules/MapResourceToAvatarSizes/MapResourceToAvatarSizes-Profile.xcconfig","buck-out/gen/submodules/MapResourceToAvatarSizes/MapResourceToAvatarSizes-Release.xcconfig","buck-out/gen/submodules/MediaPlayer/UniversalMediaPlayer-Debug.xcconfig","buck-out/gen/submodules/MediaPlayer/UniversalMediaPlayer-Profile.xcconfig","buck-out/gen/submodules/MediaPlayer/UniversalMediaPlayer-Release.xcconfig","buck-out/gen/submodules/MediaResources/MediaResources-Debug.xcconfig","buck-out/gen/submodules/MediaResources/MediaResources-Profile.xcconfig","buck-out/gen/submodules/MediaResources/MediaResources-Release.xcconfig","buck-out/gen/submodules/MergeLists/MergeLists-Debug.xcconfig","buck-out/gen/submodules/MergeLists/MergeLists-Profile.xcconfig","buck-out/gen/submodules/MergeLists/MergeLists-Release.xcconfig","buck-out/gen/submodules/MessageReactionListUI/MessageReactionListUI-Debug.xcconfig","buck-out/gen/submodules/MessageReactionListUI/MessageReactionListUI-Profile.xcconfig","buck-out/gen/submodules/MessageReactionListUI/MessageReactionListUI-Release.xcconfig","buck-out/gen/submodules/MimeTypes/MimeTypes-Debug.xcconfig","buck-out/gen/submodules/MimeTypes/MimeTypes-Profile.xcconfig","buck-out/gen/submodules/MimeTypes/MimeTypes-Release.xcconfig","buck-out/gen/submodules/MosaicLayout/MosaicLayout-Debug.xcconfig","buck-out/gen/submodules/MosaicLayout/MosaicLayout-Profile.xcconfig","buck-out/gen/submodules/MosaicLayout/MosaicLayout-Release.xcconfig","buck-out/gen/submodules/MtProtoKit/MtProtoKit#shared-Debug.xcconfig","buck-out/gen/submodules/MtProtoKit/MtProtoKit#shared-Profile.xcconfig","buck-out/gen/submodules/MtProtoKit/MtProtoKit#shared-Release.xcconfig","buck-out/gen/submodules/MusicAlbumArtResources/MusicAlbumArtResources-Debug.xcconfig","buck-out/gen/submodules/MusicAlbumArtResources/MusicAlbumArtResources-Profile.xcconfig","buck-out/gen/submodules/MusicAlbumArtResources/MusicAlbumArtResources-Release.xcconfig","buck-out/gen/submodules/NotificationMuteSettingsUI/NotificationMuteSettingsUI-Debug.xcconfig","buck-out/gen/submodules/NotificationMuteSettingsUI/NotificationMuteSettingsUI-Profile.xcconfig","buck-out/gen/submodules/NotificationMuteSettingsUI/NotificationMuteSettingsUI-Release.xcconfig","buck-out/gen/submodules/NotificationSoundSelectionUI/NotificationSoundSelectionUI-Debug.xcconfig","buck-out/gen/submodules/NotificationSoundSelectionUI/NotificationSoundSelectionUI-Profile.xcconfig","buck-out/gen/submodules/NotificationSoundSelectionUI/NotificationSoundSelectionUI-Release.xcconfig","buck-out/gen/submodules/OpenInExternalAppUI/OpenInExternalAppUI-Debug.xcconfig","buck-out/gen/submodules/OpenInExternalAppUI/OpenInExternalAppUI-Profile.xcconfig","buck-out/gen/submodules/OpenInExternalAppUI/OpenInExternalAppUI-Release.xcconfig","buck-out/gen/submodules/Opus/opus-Debug.xcconfig","buck-out/gen/submodules/Opus/opus-Profile.xcconfig","buck-out/gen/submodules/Opus/opus-Release.xcconfig","buck-out/gen/submodules/Opus/opus_lib-Debug.xcconfig","buck-out/gen/submodules/Opus/opus_lib-Profile.xcconfig","buck-out/gen/submodules/Opus/opus_lib-Release.xcconfig","buck-out/gen/submodules/OpusBinding/OpusBinding-Debug.xcconfig","buck-out/gen/submodules/OpusBinding/OpusBinding-Profile.xcconfig","buck-out/gen/submodules/OpusBinding/OpusBinding-Release.xcconfig","buck-out/gen/submodules/OverlayStatusController/OverlayStatusController-Debug.xcconfig","buck-out/gen/submodules/OverlayStatusController/OverlayStatusController-Profile.xcconfig","buck-out/gen/submodules/OverlayStatusController/OverlayStatusController-Release.xcconfig","buck-out/gen/submodules/PasscodeInputFieldNode/PasscodeInputFieldNode-Debug.xcconfig","buck-out/gen/submodules/PasscodeInputFieldNode/PasscodeInputFieldNode-Profile.xcconfig","buck-out/gen/submodules/PasscodeInputFieldNode/PasscodeInputFieldNode-Release.xcconfig","buck-out/gen/submodules/PasscodeUI/PasscodeUI-Debug.xcconfig","buck-out/gen/submodules/PasscodeUI/PasscodeUI-Profile.xcconfig","buck-out/gen/submodules/PasscodeUI/PasscodeUI-Release.xcconfig","buck-out/gen/submodules/PassportUI/PassportUI-Debug.xcconfig","buck-out/gen/submodules/PassportUI/PassportUI-Profile.xcconfig","buck-out/gen/submodules/PassportUI/PassportUI-Release.xcconfig","buck-out/gen/submodules/PasswordSetupUI/PasswordSetupUI-Debug.xcconfig","buck-out/gen/submodules/PasswordSetupUI/PasswordSetupUI-Profile.xcconfig","buck-out/gen/submodules/PasswordSetupUI/PasswordSetupUI-Release.xcconfig","buck-out/gen/submodules/Pdf/Pdf-Debug.xcconfig","buck-out/gen/submodules/Pdf/Pdf-Profile.xcconfig","buck-out/gen/submodules/Pdf/Pdf-Release.xcconfig","buck-out/gen/submodules/PeerAvatarGalleryUI/PeerAvatarGalleryUI-Debug.xcconfig","buck-out/gen/submodules/PeerAvatarGalleryUI/PeerAvatarGalleryUI-Profile.xcconfig","buck-out/gen/submodules/PeerAvatarGalleryUI/PeerAvatarGalleryUI-Release.xcconfig","buck-out/gen/submodules/PeerInfoUI/PeerInfoUI-Debug.xcconfig","buck-out/gen/submodules/PeerInfoUI/PeerInfoUI-Profile.xcconfig","buck-out/gen/submodules/PeerInfoUI/PeerInfoUI-Release.xcconfig","buck-out/gen/submodules/PeerOnlineMarkerNode/PeerOnlineMarkerNode-Debug.xcconfig","buck-out/gen/submodules/PeerOnlineMarkerNode/PeerOnlineMarkerNode-Profile.xcconfig","buck-out/gen/submodules/PeerOnlineMarkerNode/PeerOnlineMarkerNode-Release.xcconfig","buck-out/gen/submodules/PeerPresenceStatusManager/PeerPresenceStatusManager-Debug.xcconfig","buck-out/gen/submodules/PeerPresenceStatusManager/PeerPresenceStatusManager-Profile.xcconfig","buck-out/gen/submodules/PeerPresenceStatusManager/PeerPresenceStatusManager-Release.xcconfig","buck-out/gen/submodules/PeersNearbyIconNode/PeersNearbyIconNode-Debug.xcconfig","buck-out/gen/submodules/PeersNearbyIconNode/PeersNearbyIconNode-Profile.xcconfig","buck-out/gen/submodules/PeersNearbyIconNode/PeersNearbyIconNode-Release.xcconfig","buck-out/gen/submodules/PeersNearbyUI/PeersNearbyUI-Debug.xcconfig","buck-out/gen/submodules/PeersNearbyUI/PeersNearbyUI-Profile.xcconfig","buck-out/gen/submodules/PeersNearbyUI/PeersNearbyUI-Release.xcconfig","buck-out/gen/submodules/PersistentStringHash/PersistentStringHash-Debug.xcconfig","buck-out/gen/submodules/PersistentStringHash/PersistentStringHash-Profile.xcconfig","buck-out/gen/submodules/PersistentStringHash/PersistentStringHash-Release.xcconfig","buck-out/gen/submodules/PhoneInputNode/PhoneInputNode-Debug.xcconfig","buck-out/gen/submodules/PhoneInputNode/PhoneInputNode-Profile.xcconfig","buck-out/gen/submodules/PhoneInputNode/PhoneInputNode-Release.xcconfig","buck-out/gen/submodules/PhotoResources/PhotoResources-Debug.xcconfig","buck-out/gen/submodules/PhotoResources/PhotoResources-Profile.xcconfig","buck-out/gen/submodules/PhotoResources/PhotoResources-Release.xcconfig","buck-out/gen/submodules/PlatformRestrictionMatching/PlatformRestrictionMatching-Debug.xcconfig","buck-out/gen/submodules/PlatformRestrictionMatching/PlatformRestrictionMatching-Profile.xcconfig","buck-out/gen/submodules/PlatformRestrictionMatching/PlatformRestrictionMatching-Release.xcconfig","buck-out/gen/submodules/Postbox/Postbox#shared-Debug.xcconfig","buck-out/gen/submodules/Postbox/Postbox#shared-Profile.xcconfig","buck-out/gen/submodules/Postbox/Postbox#shared-Release.xcconfig","buck-out/gen/submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode-Debug.xcconfig","buck-out/gen/submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode-Profile.xcconfig","buck-out/gen/submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode-Release.xcconfig","buck-out/gen/submodules/QrCode/QrCode-Debug.xcconfig","buck-out/gen/submodules/QrCode/QrCode-Profile.xcconfig","buck-out/gen/submodules/QrCode/QrCode-Release.xcconfig","buck-out/gen/submodules/RMIntro/RMIntro-Debug.xcconfig","buck-out/gen/submodules/RMIntro/RMIntro-Profile.xcconfig","buck-out/gen/submodules/RMIntro/RMIntro-Release.xcconfig","buck-out/gen/submodules/RadialStatusNode/RadialStatusNode-Debug.xcconfig","buck-out/gen/submodules/RadialStatusNode/RadialStatusNode-Profile.xcconfig","buck-out/gen/submodules/RadialStatusNode/RadialStatusNode-Release.xcconfig","buck-out/gen/submodules/RaiseToListen/RaiseToListen-Debug.xcconfig","buck-out/gen/submodules/RaiseToListen/RaiseToListen-Profile.xcconfig","buck-out/gen/submodules/RaiseToListen/RaiseToListen-Release.xcconfig","buck-out/gen/submodules/ReactionSelectionNode/ReactionSelectionNode-Debug.xcconfig","buck-out/gen/submodules/ReactionSelectionNode/ReactionSelectionNode-Profile.xcconfig","buck-out/gen/submodules/ReactionSelectionNode/ReactionSelectionNode-Release.xcconfig","buck-out/gen/submodules/SSignalKit/SSignalKit/SSignalKit-Debug.xcconfig","buck-out/gen/submodules/SSignalKit/SSignalKit/SSignalKit-Profile.xcconfig","buck-out/gen/submodules/SSignalKit/SSignalKit/SSignalKit-Release.xcconfig","buck-out/gen/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit#shared-Debug.xcconfig","buck-out/gen/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit#shared-Profile.xcconfig","buck-out/gen/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit#shared-Release.xcconfig","buck-out/gen/submodules/SaveToCameraRoll/SaveToCameraRoll-Debug.xcconfig","buck-out/gen/submodules/SaveToCameraRoll/SaveToCameraRoll-Profile.xcconfig","buck-out/gen/submodules/SaveToCameraRoll/SaveToCameraRoll-Release.xcconfig","buck-out/gen/submodules/ScreenCaptureDetection/ScreenCaptureDetection-Debug.xcconfig","buck-out/gen/submodules/ScreenCaptureDetection/ScreenCaptureDetection-Profile.xcconfig","buck-out/gen/submodules/ScreenCaptureDetection/ScreenCaptureDetection-Release.xcconfig","buck-out/gen/submodules/SearchBarNode/SearchBarNode-Debug.xcconfig","buck-out/gen/submodules/SearchBarNode/SearchBarNode-Profile.xcconfig","buck-out/gen/submodules/SearchBarNode/SearchBarNode-Release.xcconfig","buck-out/gen/submodules/SearchUI/SearchUI-Debug.xcconfig","buck-out/gen/submodules/SearchUI/SearchUI-Profile.xcconfig","buck-out/gen/submodules/SearchUI/SearchUI-Release.xcconfig","buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Debug.xcconfig","buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Profile.xcconfig","buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Release.xcconfig","buck-out/gen/submodules/SelectablePeerNode/SelectablePeerNode-Debug.xcconfig","buck-out/gen/submodules/SelectablePeerNode/SelectablePeerNode-Profile.xcconfig","buck-out/gen/submodules/SelectablePeerNode/SelectablePeerNode-Release.xcconfig","buck-out/gen/submodules/SettingsUI/SettingsUI-Debug.xcconfig","buck-out/gen/submodules/SettingsUI/SettingsUI-Profile.xcconfig","buck-out/gen/submodules/SettingsUI/SettingsUI-Release.xcconfig","buck-out/gen/submodules/ShareController/ShareController-Debug.xcconfig","buck-out/gen/submodules/ShareController/ShareController-Profile.xcconfig","buck-out/gen/submodules/ShareController/ShareController-Release.xcconfig","buck-out/gen/submodules/ShareItems/ShareItems-Debug.xcconfig","buck-out/gen/submodules/ShareItems/ShareItems-Profile.xcconfig","buck-out/gen/submodules/ShareItems/ShareItems-Release.xcconfig","buck-out/gen/submodules/SinglePhoneInputNode/SinglePhoneInputNode-Debug.xcconfig","buck-out/gen/submodules/SinglePhoneInputNode/SinglePhoneInputNode-Profile.xcconfig","buck-out/gen/submodules/SinglePhoneInputNode/SinglePhoneInputNode-Release.xcconfig","buck-out/gen/submodules/SolidRoundedButtonNode/SolidRoundedButtonNode-Debug.xcconfig","buck-out/gen/submodules/SolidRoundedButtonNode/SolidRoundedButtonNode-Profile.xcconfig","buck-out/gen/submodules/SolidRoundedButtonNode/SolidRoundedButtonNode-Release.xcconfig","buck-out/gen/submodules/StickerPackPreviewUI/StickerPackPreviewUI-Debug.xcconfig","buck-out/gen/submodules/StickerPackPreviewUI/StickerPackPreviewUI-Profile.xcconfig","buck-out/gen/submodules/StickerPackPreviewUI/StickerPackPreviewUI-Release.xcconfig","buck-out/gen/submodules/StickerResources/StickerResources-Debug.xcconfig","buck-out/gen/submodules/StickerResources/StickerResources-Profile.xcconfig","buck-out/gen/submodules/StickerResources/StickerResources-Release.xcconfig","buck-out/gen/submodules/Stripe/Stripe-Debug.xcconfig","buck-out/gen/submodules/Stripe/Stripe-Profile.xcconfig","buck-out/gen/submodules/Stripe/Stripe-Release.xcconfig","buck-out/gen/submodules/SwipeToDismissGesture/SwipeToDismissGesture-Debug.xcconfig","buck-out/gen/submodules/SwipeToDismissGesture/SwipeToDismissGesture-Profile.xcconfig","buck-out/gen/submodules/SwipeToDismissGesture/SwipeToDismissGesture-Release.xcconfig","buck-out/gen/submodules/SwitchNode/SwitchNode-Debug.xcconfig","buck-out/gen/submodules/SwitchNode/SwitchNode-Profile.xcconfig","buck-out/gen/submodules/SwitchNode/SwitchNode-Release.xcconfig","buck-out/gen/submodules/TelegramApi/TelegramApi-Debug.xcconfig","buck-out/gen/submodules/TelegramApi/TelegramApi-Profile.xcconfig","buck-out/gen/submodules/TelegramApi/TelegramApi-Release.xcconfig","buck-out/gen/submodules/TelegramAudio/TelegramAudio-Debug.xcconfig","buck-out/gen/submodules/TelegramAudio/TelegramAudio-Profile.xcconfig","buck-out/gen/submodules/TelegramAudio/TelegramAudio-Release.xcconfig","buck-out/gen/submodules/TelegramBaseController/TelegramBaseController-Debug.xcconfig","buck-out/gen/submodules/TelegramBaseController/TelegramBaseController-Profile.xcconfig","buck-out/gen/submodules/TelegramBaseController/TelegramBaseController-Release.xcconfig","buck-out/gen/submodules/TelegramCallsUI/TelegramCallsUI-Debug.xcconfig","buck-out/gen/submodules/TelegramCallsUI/TelegramCallsUI-Profile.xcconfig","buck-out/gen/submodules/TelegramCallsUI/TelegramCallsUI-Release.xcconfig","buck-out/gen/submodules/TelegramCore/TelegramCore#shared-Debug.xcconfig","buck-out/gen/submodules/TelegramCore/TelegramCore#shared-Profile.xcconfig","buck-out/gen/submodules/TelegramCore/TelegramCore#shared-Release.xcconfig","buck-out/gen/submodules/TelegramNotices/TelegramNotices-Debug.xcconfig","buck-out/gen/submodules/TelegramNotices/TelegramNotices-Profile.xcconfig","buck-out/gen/submodules/TelegramNotices/TelegramNotices-Release.xcconfig","buck-out/gen/submodules/TelegramPermissions/TelegramPermissions-Debug.xcconfig","buck-out/gen/submodules/TelegramPermissions/TelegramPermissions-Profile.xcconfig","buck-out/gen/submodules/TelegramPermissions/TelegramPermissions-Release.xcconfig","buck-out/gen/submodules/TelegramPermissionsUI/TelegramPermissionsUI-Debug.xcconfig","buck-out/gen/submodules/TelegramPermissionsUI/TelegramPermissionsUI-Profile.xcconfig","buck-out/gen/submodules/TelegramPermissionsUI/TelegramPermissionsUI-Release.xcconfig","buck-out/gen/submodules/TelegramPresentationData/TelegramPresentationData-Debug.xcconfig","buck-out/gen/submodules/TelegramPresentationData/TelegramPresentationData-Profile.xcconfig","buck-out/gen/submodules/TelegramPresentationData/TelegramPresentationData-Release.xcconfig","buck-out/gen/submodules/TelegramStringFormatting/TelegramStringFormatting-Debug.xcconfig","buck-out/gen/submodules/TelegramStringFormatting/TelegramStringFormatting-Profile.xcconfig","buck-out/gen/submodules/TelegramStringFormatting/TelegramStringFormatting-Release.xcconfig","buck-out/gen/submodules/TelegramUI/TelegramUI#shared-Debug.xcconfig","buck-out/gen/submodules/TelegramUI/TelegramUI#shared-Profile.xcconfig","buck-out/gen/submodules/TelegramUI/TelegramUI#shared-Release.xcconfig","buck-out/gen/submodules/TelegramUIPreferences/TelegramUIPreferences-Debug.xcconfig","buck-out/gen/submodules/TelegramUIPreferences/TelegramUIPreferences-Profile.xcconfig","buck-out/gen/submodules/TelegramUIPreferences/TelegramUIPreferences-Release.xcconfig","buck-out/gen/submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent-Debug.xcconfig","buck-out/gen/submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent-Profile.xcconfig","buck-out/gen/submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent-Release.xcconfig","buck-out/gen/submodules/TelegramUpdateUI/TelegramUpdateUI-Debug.xcconfig","buck-out/gen/submodules/TelegramUpdateUI/TelegramUpdateUI-Profile.xcconfig","buck-out/gen/submodules/TelegramUpdateUI/TelegramUpdateUI-Release.xcconfig","buck-out/gen/submodules/TelegramVoip/TelegramVoip-Debug.xcconfig","buck-out/gen/submodules/TelegramVoip/TelegramVoip-Profile.xcconfig","buck-out/gen/submodules/TelegramVoip/TelegramVoip-Release.xcconfig","buck-out/gen/submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager-Debug.xcconfig","buck-out/gen/submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager-Profile.xcconfig","buck-out/gen/submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager-Release.xcconfig","buck-out/gen/submodules/TextFormat/TextFormat-Debug.xcconfig","buck-out/gen/submodules/TextFormat/TextFormat-Profile.xcconfig","buck-out/gen/submodules/TextFormat/TextFormat-Release.xcconfig","buck-out/gen/submodules/TextSelectionNode/TextSelectionNode-Debug.xcconfig","buck-out/gen/submodules/TextSelectionNode/TextSelectionNode-Profile.xcconfig","buck-out/gen/submodules/TextSelectionNode/TextSelectionNode-Release.xcconfig","buck-out/gen/submodules/TinyThumbnail/TinyThumbnail-Debug.xcconfig","buck-out/gen/submodules/TinyThumbnail/TinyThumbnail-Profile.xcconfig","buck-out/gen/submodules/TinyThumbnail/TinyThumbnail-Release.xcconfig","buck-out/gen/submodules/TouchDownGesture/TouchDownGesture-Debug.xcconfig","buck-out/gen/submodules/TouchDownGesture/TouchDownGesture-Profile.xcconfig","buck-out/gen/submodules/TouchDownGesture/TouchDownGesture-Release.xcconfig","buck-out/gen/submodules/Tuples/Tuples-Debug.xcconfig","buck-out/gen/submodules/Tuples/Tuples-Profile.xcconfig","buck-out/gen/submodules/Tuples/Tuples-Release.xcconfig","buck-out/gen/submodules/UndoUI/UndoUI-Debug.xcconfig","buck-out/gen/submodules/UndoUI/UndoUI-Profile.xcconfig","buck-out/gen/submodules/UndoUI/UndoUI-Release.xcconfig","buck-out/gen/submodules/UrlEscaping/UrlEscaping-Debug.xcconfig","buck-out/gen/submodules/UrlEscaping/UrlEscaping-Profile.xcconfig","buck-out/gen/submodules/UrlEscaping/UrlEscaping-Release.xcconfig","buck-out/gen/submodules/UrlHandling/UrlHandling-Debug.xcconfig","buck-out/gen/submodules/UrlHandling/UrlHandling-Profile.xcconfig","buck-out/gen/submodules/UrlHandling/UrlHandling-Release.xcconfig","buck-out/gen/submodules/WalletUI/WalletUI-Debug.xcconfig","buck-out/gen/submodules/WalletUI/WalletUI-Profile.xcconfig","buck-out/gen/submodules/WalletUI/WalletUI-Release.xcconfig","buck-out/gen/submodules/WallpaperResources/WallpaperResources-Debug.xcconfig","buck-out/gen/submodules/WallpaperResources/WallpaperResources-Profile.xcconfig","buck-out/gen/submodules/WallpaperResources/WallpaperResources-Release.xcconfig","buck-out/gen/submodules/WatchBridge/WatchBridge-Debug.xcconfig","buck-out/gen/submodules/WatchBridge/WatchBridge-Profile.xcconfig","buck-out/gen/submodules/WatchBridge/WatchBridge-Release.xcconfig","buck-out/gen/submodules/WatchBridgeAudio/WatchBridgeAudio-Debug.xcconfig","buck-out/gen/submodules/WatchBridgeAudio/WatchBridgeAudio-Profile.xcconfig","buck-out/gen/submodules/WatchBridgeAudio/WatchBridgeAudio-Release.xcconfig","buck-out/gen/submodules/WatchCommon/Host/WatchCommon-Debug.xcconfig","buck-out/gen/submodules/WatchCommon/Host/WatchCommon-Profile.xcconfig","buck-out/gen/submodules/WatchCommon/Host/WatchCommon-Release.xcconfig","buck-out/gen/submodules/WebP/WebPImage-Debug.xcconfig","buck-out/gen/submodules/WebP/WebPImage-Profile.xcconfig","buck-out/gen/submodules/WebP/WebPImage-Release.xcconfig","buck-out/gen/submodules/WebP/WebP_lib-Debug.xcconfig","buck-out/gen/submodules/WebP/WebP_lib-Profile.xcconfig","buck-out/gen/submodules/WebP/WebP_lib-Release.xcconfig","buck-out/gen/submodules/WebSearchUI/WebSearchUI-Debug.xcconfig","buck-out/gen/submodules/WebSearchUI/WebSearchUI-Profile.xcconfig","buck-out/gen/submodules/WebSearchUI/WebSearchUI-Release.xcconfig","buck-out/gen/submodules/WebUI/WebUI-Debug.xcconfig","buck-out/gen/submodules/WebUI/WebUI-Profile.xcconfig","buck-out/gen/submodules/WebUI/WebUI-Release.xcconfig","buck-out/gen/submodules/WebsiteType/WebsiteType-Debug.xcconfig","buck-out/gen/submodules/WebsiteType/WebsiteType-Profile.xcconfig","buck-out/gen/submodules/WebsiteType/WebsiteType-Release.xcconfig","buck-out/gen/submodules/YuvConversion/YuvConversion-Debug.xcconfig","buck-out/gen/submodules/YuvConversion/YuvConversion-Profile.xcconfig","buck-out/gen/submodules/YuvConversion/YuvConversion-Release.xcconfig","buck-out/gen/submodules/libphonenumber/libphonenumber-Debug.xcconfig","buck-out/gen/submodules/libphonenumber/libphonenumber-Profile.xcconfig","buck-out/gen/submodules/libphonenumber/libphonenumber-Release.xcconfig","buck-out/gen/submodules/libtgvoip/libtgvoip-Debug.xcconfig","buck-out/gen/submodules/libtgvoip/libtgvoip-Profile.xcconfig","buck-out/gen/submodules/libtgvoip/libtgvoip-Release.xcconfig","buck-out/gen/submodules/lottie-ios/Lottie-Debug.xcconfig","buck-out/gen/submodules/lottie-ios/Lottie-Profile.xcconfig","buck-out/gen/submodules/lottie-ios/Lottie-Release.xcconfig","buck-out/gen/submodules/openssl/openssl-Debug.xcconfig","buck-out/gen/submodules/openssl/openssl-Profile.xcconfig","buck-out/gen/submodules/openssl/openssl-Release.xcconfig","buck-out/gen/submodules/rlottie/RLottieBinding-Debug.xcconfig","buck-out/gen/submodules/rlottie/RLottieBinding-Profile.xcconfig","buck-out/gen/submodules/rlottie/RLottieBinding-Release.xcconfig","buck-out/gen/submodules/sqlcipher/sqlcipher-Debug.xcconfig","buck-out/gen/submodules/sqlcipher/sqlcipher-Profile.xcconfig","buck-out/gen/submodules/sqlcipher/sqlcipher-Release.xcconfig","buck-out/gen/submodules/ton/ton-Debug.xcconfig","buck-out/gen/submodules/ton/ton-Profile.xcconfig","buck-out/gen/submodules/ton/ton-Release.xcconfig"],"copy-in-xcode":[]} \ No newline at end of file diff --git a/Telegram_Buck.xcworkspace/contents.xcworkspacedata b/Telegram_Buck.xcworkspace/contents.xcworkspacedata index 149ca31975..a3f93af764 100644 --- a/Telegram_Buck.xcworkspace/contents.xcworkspacedata +++ b/Telegram_Buck.xcworkspace/contents.xcworkspacedata @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme b/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme index 4a01a62522..e009a59b64 100644 --- a/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme +++ b/Telegram_Buck.xcworkspace/xcshareddata/xcschemes/Telegram_Buck.xcscheme @@ -2246,6 +2246,20 @@ ReferencedContainer = "container:submodules/Camera/Camera.xcodeproj"> + + + + Void)? + + private let detectedCodesPipe = ValuePipe<[CameraCode]>() var previewNode: CameraPreviewNode? { didSet { @@ -17,11 +23,6 @@ private final class CameraContext { } } - var previousSampleBuffer: CMSampleBuffer? - var processSampleBuffer: ((CMSampleBuffer) -> Void)? - - private var invalidated = false - init(queue: Queue, configuration: Camera.Configuration) { self.queue = queue self.initialConfiguration = configuration @@ -45,6 +46,10 @@ private final class CameraContext { self?.processSampleBuffer?(sampleBuffer) } } + + self.output.processCodes = { [weak self] codes in + self?.detectedCodesPipe.putNext(codes) + } } func startCapture() { @@ -85,24 +90,38 @@ private final class CameraContext { self.input.configure(for: self.session, device: self.device, audio: self.initialConfiguration.audio) self.session.commitConfiguration() } + + func setTorchActive(_ active: Bool) { + self.device.setTorchActive(active) + } + + var detectedCodes: Signal<[CameraCode], NoError> { + return self.detectedCodesPipe.signal() + } } -final class Camera { - typealias Preset = AVCaptureSession.Preset - typealias Position = AVCaptureDevice.Position - typealias FocusMode = AVCaptureDevice.FocusMode - typealias ExposureMode = AVCaptureDevice.ExposureMode +public final class Camera { + public typealias Preset = AVCaptureSession.Preset + public typealias Position = AVCaptureDevice.Position + public typealias FocusMode = AVCaptureDevice.FocusMode + public typealias ExposureMode = AVCaptureDevice.ExposureMode - struct Configuration { + public struct Configuration { let preset: Preset let position: Position let audio: Bool + + public init(preset: Preset, position: Position, audio: Bool) { + self.preset = preset + self.position = position + self.audio = audio + } } private let queue = Queue() private var contextRef: Unmanaged? - init(configuration: Camera.Configuration = Configuration(preset: .hd1920x1080, position: .back, audio: true)) { + public init(configuration: Camera.Configuration = Configuration(preset: .hd1920x1080, position: .back, audio: true)) { self.queue.async { let context = CameraContext(queue: self.queue, configuration: configuration) self.contextRef = Unmanaged.passRetained(context) @@ -116,7 +135,7 @@ final class Camera { } } - func startCapture() { + public func startCapture() { self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { context.startCapture() @@ -124,14 +143,15 @@ final class Camera { } } - func stopCapture() { + public func stopCapture() { self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { context.stopCapture() } } } - func togglePosition() { + + public func togglePosition() { self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { context.togglePosition() @@ -139,11 +159,11 @@ final class Camera { } } - func takePhoto() -> Signal { + public func takePhoto() -> Signal { return .never() } - func focus(at point: CGPoint) { + public func focus(at point: CGPoint) { self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { context.focus(at: point) @@ -151,7 +171,7 @@ final class Camera { } } - func setFPS(_ fps: Double) { + public func setFPS(_ fps: Double) { self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { context.setFPS(fps) @@ -159,7 +179,15 @@ final class Camera { } } - func attachPreviewNode(_ node: CameraPreviewNode) { + public func setTorchActive(_ active: Bool) { + self.queue.async { + if let context = self.contextRef?.takeUnretainedValue() { + context.setTorchActive(active) + } + } + } + + public func attachPreviewNode(_ node: CameraPreviewNode) { let nodeRef: Unmanaged = Unmanaged.passRetained(node) self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { @@ -173,11 +201,25 @@ final class Camera { } } - func setProcessSampleBuffer(_ block: ((CMSampleBuffer) -> Void)?) { + public func setProcessSampleBuffer(_ block: ((CMSampleBuffer) -> Void)?) { self.queue.async { if let context = self.contextRef?.takeUnretainedValue() { context.processSampleBuffer = block } } } + + public var detectedCodes: Signal<[CameraCode], NoError> { + return Signal { subscriber in + let disposable = MetaDisposable() + self.queue.async { + if let context = self.contextRef?.takeUnretainedValue() { + disposable.set(context.detectedCodes.start(next: { codes in + subscriber.putNext(codes) + })) + } + } + return disposable + } + } } diff --git a/submodules/Camera/Sources/CameraDevice.swift b/submodules/Camera/Sources/CameraDevice.swift index 90d110db6f..5cbf8ff7e1 100644 --- a/submodules/Camera/Sources/CameraDevice.swift +++ b/submodules/Camera/Sources/CameraDevice.swift @@ -135,4 +135,13 @@ final class CameraDevice { device.setExposureTargetBias(value, completionHandler: nil) } } + + func setTorchActive(_ active: Bool) { + guard let device = self.videoDevice else { + return + } + self.transaction(device) { device in + device.torchMode = active ? .on : .off + } + } } diff --git a/submodules/Camera/Sources/CameraOutput.swift b/submodules/Camera/Sources/CameraOutput.swift index a7cb2258c5..d2c4203b6a 100644 --- a/submodules/Camera/Sources/CameraOutput.swift +++ b/submodules/Camera/Sources/CameraOutput.swift @@ -1,5 +1,43 @@ import AVFoundation +public struct CameraCode: Equatable { + public enum CodeType { + case qr + } + + public let type: CodeType + public let message: String + public let corners: [CGPoint] + + public init(type: CameraCode.CodeType, message: String, corners: [CGPoint]) { + self.type = type + self.message = message + self.corners = corners + } + + public var boundingBox: CGRect { + let x = self.corners.map { $0.x } + let y = self.corners.map { $0.y } + if let minX = x.min(), let minY = y.min(), let maxX = x.max(), let maxY = y.max() { + return CGRect(x: minX, y: minY, width: abs(maxX - minX), height: abs(maxY - minY)) + } + return CGRect.null + } + + public static func == (lhs: CameraCode, rhs: CameraCode) -> Bool { + if lhs.type != rhs.type { + return false + } + if lhs.message != rhs.message { + return false + } + if lhs.corners != rhs.corners { + return false + } + return true + } +} + final class CameraOutput: NSObject { //private let photoOutput = CameraPhotoOutput() private let videoOutput = AVCaptureVideoDataOutput() @@ -7,9 +45,10 @@ final class CameraOutput: NSObject { private let metadataOutput = AVCaptureMetadataOutput() private let queue = DispatchQueue(label: "") + private let metadataQueue = DispatchQueue(label: "") var processSampleBuffer: ((CMSampleBuffer, AVCaptureConnection) -> Void)? - var processQRCode: ((String, AVMetadataMachineReadableCodeObject) -> Void)? + var processCodes: (([CameraCode]) -> Void)? override init() { super.init() @@ -34,6 +73,11 @@ final class CameraOutput: NSObject { } if session.canAddOutput(self.metadataOutput) { session.addOutput(self.metadataOutput) + + self.metadataOutput.setMetadataObjectsDelegate(self, queue: self.metadataQueue) + if self.metadataOutput.availableMetadataObjectTypes.contains(.qr) { + self.metadataOutput.metadataObjectTypes = [.qr] + } } } @@ -60,8 +104,13 @@ extension CameraOutput: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureA extension CameraOutput: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { - if let object = metadataObjects.first as? AVMetadataMachineReadableCodeObject, object.type == .qr, let stringValue = object.stringValue, !stringValue.isEmpty { - self.processQRCode?(stringValue, object) + let codes: [CameraCode] = metadataObjects.filter { $0.type == .qr }.compactMap { object in + if let object = object as? AVMetadataMachineReadableCodeObject, let stringValue = object.stringValue, !stringValue.isEmpty { + return CameraCode(type: .qr, message: stringValue, corners: object.corners) + } else { + return nil + } } + self.processCodes?(codes) } } diff --git a/submodules/Camera/Sources/CameraPreviewNode.swift b/submodules/Camera/Sources/CameraPreviewNode.swift index 9f18fa7e21..9e88730a71 100644 --- a/submodules/Camera/Sources/CameraPreviewNode.swift +++ b/submodules/Camera/Sources/CameraPreviewNode.swift @@ -14,10 +14,10 @@ private final class CameraPreviewNodeLayer: AVSampleBufferDisplayLayer { } } -class CameraPreviewNode: ASDisplayNode { +public final class CameraPreviewNode: ASDisplayNode { private var displayLayer: AVSampleBufferDisplayLayer - override init() { + public override init() { self.displayLayer = AVSampleBufferDisplayLayer() self.displayLayer.videoGravity = .resizeAspectFill @@ -38,11 +38,11 @@ class CameraPreviewNode: ASDisplayNode { self.displayLayer.enqueue(sampleBuffer) } - override func layout() { + override public func layout() { super.layout() var transform = CGAffineTransform(rotationAngle: CGFloat.pi / 2.0) - transform = transform.scaledBy(x: 1.0, y: -1.0) + transform = transform.scaledBy(x: 1.0, y: 1.0) self.displayLayer.setAffineTransform(transform) self.displayLayer.frame = self.bounds diff --git a/submodules/GlassButtonNode/BUCK b/submodules/GlassButtonNode/BUCK new file mode 100644 index 0000000000..4127cf308e --- /dev/null +++ b/submodules/GlassButtonNode/BUCK @@ -0,0 +1,16 @@ +load("//Config:buck_rule_macros.bzl", "static_library") + +static_library( + name = "GlassButtonNode", + srcs = glob([ + "Sources/**/*.swift", + ]), + deps = [ + "//submodules/AsyncDisplayKit:AsyncDisplayKit#shared", + "//submodules/Display:Display#shared", + ], + frameworks = [ + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + "$SDKROOT/System/Library/Frameworks/UIKit.framework", + ], +) diff --git a/submodules/GlassButtonNode/GlassButtonNode.xcodeproj/project.pbxproj b/submodules/GlassButtonNode/GlassButtonNode.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..19233389ae --- /dev/null +++ b/submodules/GlassButtonNode/GlassButtonNode.xcodeproj/project.pbxproj @@ -0,0 +1,379 @@ + + + + + archiveVersion + 1 + classes + + + objectVersion + 46 + objects + + 1DD70E294F632DE500000000 + + isa + PBXFileReference + name + GlassButtonNode-Debug.xcconfig + path + ../../buck-out/gen/submodules/GlassButtonNode/GlassButtonNode-Debug.xcconfig + sourceTree + SOURCE_ROOT + explicitFileType + text.xcconfig + + 1DD70E29E871E00F00000000 + + isa + PBXFileReference + name + GlassButtonNode-Profile.xcconfig + path + ../../buck-out/gen/submodules/GlassButtonNode/GlassButtonNode-Profile.xcconfig + sourceTree + SOURCE_ROOT + explicitFileType + text.xcconfig + + 1DD70E295C088B7100000000 + + isa + PBXFileReference + name + GlassButtonNode-Release.xcconfig + path + ../../buck-out/gen/submodules/GlassButtonNode/GlassButtonNode-Release.xcconfig + sourceTree + SOURCE_ROOT + explicitFileType + text.xcconfig + + B401C9792F7F325000000000 + + isa + PBXGroup + name + Buck (Do Not Modify) + sourceTree + ]]> + children + + 1DD70E294F632DE500000000 + 1DD70E29E871E00F00000000 + 1DD70E295C088B7100000000 + + + B401C979B781F65D00000000 + + isa + PBXGroup + name + Configurations + sourceTree + ]]> + children + + B401C9792F7F325000000000 + + + 1DD70E29FF334B1F00000000 + + isa + PBXFileReference + name + libDisplay.dylib + path + libDisplay.dylib + sourceTree + BUILT_PRODUCTS_DIR + explicitFileType + compiled.mach-o.dylib + + B401C97968022A5500000000 + + isa + PBXGroup + name + Frameworks + sourceTree + ]]> + children + + 1DD70E29FF334B1F00000000 + + + 1DD70E29001F47FB00000000 + + isa + PBXFileReference + name + BUCK + path + BUCK + sourceTree + SOURCE_ROOT + explicitFileType + text.script.python + + 1DD70E2923081F7500000000 + + isa + PBXFileReference + name + GlassButtonNode.swift + path + Sources/GlassButtonNode.swift + sourceTree + SOURCE_ROOT + + B401C979EAB5339800000000 + + isa + PBXGroup + name + Sources + sourceTree + ]]> + children + + 1DD70E2923081F7500000000 + + + B401C97978C8D0D000000000 + + isa + PBXGroup + name + GlassButtonNode + sourceTree + ]]> + children + + 1DD70E29001F47FB00000000 + B401C979EAB5339800000000 + + + 1DD70E29BCD8FADE00000000 + + isa + PBXFileReference + name + libGlassButtonNode.a + path + libGlassButtonNode.a + sourceTree + BUILT_PRODUCTS_DIR + explicitFileType + archive.ar + + B401C979C806358400000000 + + isa + PBXGroup + name + Products + sourceTree + ]]> + children + + 1DD70E29BCD8FADE00000000 + + + B401C979EFB6AC4600000000 + + isa + PBXGroup + name + mainGroup + sourceTree + ]]> + children + + B401C979B781F65D00000000 + B401C97968022A5500000000 + B401C97978C8D0D000000000 + B401C979C806358400000000 + + + E7A30F0423081F7500000000 + + isa + PBXBuildFile + fileRef + 1DD70E2923081F7500000000 + + 1870857F0000000000000000 + + isa + PBXSourcesBuildPhase + files + + E7A30F0423081F7500000000 + + + E7A30F04FF334B1F00000000 + + isa + PBXBuildFile + fileRef + 1DD70E29FF334B1F00000000 + + FAF5FAC90000000000000000 + + isa + PBXCopyFilesBuildPhase + files + + E7A30F04FF334B1F00000000 + + name + Fake Swift Dependencies (Copy Files Phase) + runOnlyForDeploymentPostprocessing + 1 + dstSubfolderSpec + 16 + dstPath + + + 4952437303EDA63300000000 + + isa + XCBuildConfiguration + name + Debug + buildSettings + + + baseConfigurationReference + 1DD70E294F632DE500000000 + + 4952437350C7218900000000 + + isa + XCBuildConfiguration + name + Profile + buildSettings + + + baseConfigurationReference + 1DD70E29E871E00F00000000 + + 49524373A439BFE700000000 + + isa + XCBuildConfiguration + name + Release + buildSettings + + + baseConfigurationReference + 1DD70E295C088B7100000000 + + 218C37090000000000000000 + + isa + XCConfigurationList + buildConfigurations + + 4952437303EDA63300000000 + 4952437350C7218900000000 + 49524373A439BFE700000000 + + defaultConfigurationIsVisible + + + E66DC04E78C8D0D000000000 + + isa + PBXNativeTarget + name + GlassButtonNode + productName + GlassButtonNode + productReference + 1DD70E29BCD8FADE00000000 + productType + com.apple.product-type.library.static + dependencies + + + buildPhases + + 1870857F0000000000000000 + FAF5FAC90000000000000000 + + buildConfigurationList + 218C37090000000000000000 + + 4952437303EDA63300000001 + + isa + XCBuildConfiguration + name + Debug + buildSettings + + + + 4952437350C7218900000001 + + isa + XCBuildConfiguration + name + Profile + buildSettings + + + + 49524373A439BFE700000001 + + isa + XCBuildConfiguration + name + Release + buildSettings + + + + 218C37090000000000000001 + + isa + XCConfigurationList + buildConfigurations + + 4952437303EDA63300000001 + 4952437350C7218900000001 + 49524373A439BFE700000001 + + defaultConfigurationIsVisible + + + 96C8479378C8D0D000000000 + + isa + PBXProject + mainGroup + B401C979EFB6AC4600000000 + targets + + E66DC04E78C8D0D000000000 + + buildConfigurationList + 218C37090000000000000001 + compatibilityVersion + Xcode 3.2 + attributes + + LastUpgradeCheck + 9999 + + + + rootObject + 96C8479378C8D0D000000000 + + \ No newline at end of file diff --git a/submodules/GlassButtonNode/GlassButtonNode.xcodeproj/xcshareddata/xcschemes/GlassButtonNode.xcscheme b/submodules/GlassButtonNode/GlassButtonNode.xcodeproj/xcshareddata/xcschemes/GlassButtonNode.xcscheme new file mode 100644 index 0000000000..3a6a3325bb --- /dev/null +++ b/submodules/GlassButtonNode/GlassButtonNode.xcodeproj/xcshareddata/xcschemes/GlassButtonNode.xcscheme @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/submodules/GlassButtonNode/Info.plist b/submodules/GlassButtonNode/Info.plist new file mode 100644 index 0000000000..e1fe4cfb7b --- /dev/null +++ b/submodules/GlassButtonNode/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/submodules/GlassButtonNode/QrCode.xcodeproj/project.pbxproj b/submodules/GlassButtonNode/QrCode.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..cd6b029c10 --- /dev/null +++ b/submodules/GlassButtonNode/QrCode.xcodeproj/project.pbxproj @@ -0,0 +1,545 @@ + + + + + archiveVersion + 1 + classes + + + objectVersion + 46 + objects + + 1DD70E295898BF2700000000 + + isa + PBXFileReference + name + QrCode-Debug.xcconfig + path + ../../buck-out/gen/submodules/QrCode/QrCode-Debug.xcconfig + sourceTree + SOURCE_ROOT + explicitFileType + text.xcconfig + + 1DD70E297A8828D100000000 + + isa + PBXFileReference + name + QrCode-Profile.xcconfig + path + ../../buck-out/gen/submodules/QrCode/QrCode-Profile.xcconfig + sourceTree + SOURCE_ROOT + explicitFileType + text.xcconfig + + 1DD70E29EE1ED43300000000 + + isa + PBXFileReference + name + QrCode-Release.xcconfig + path + ../../buck-out/gen/submodules/QrCode/QrCode-Release.xcconfig + sourceTree + SOURCE_ROOT + explicitFileType + text.xcconfig + + B401C9792F7F325000000000 + + isa + PBXGroup + name + Buck (Do Not Modify) + sourceTree + ]]> + children + + 1DD70E295898BF2700000000 + 1DD70E297A8828D100000000 + 1DD70E29EE1ED43300000000 + + + B401C979B781F65D00000000 + + isa + PBXGroup + name + Configurations + sourceTree + ]]> + children + + B401C9792F7F325000000000 + + + 1DD70E29FF334B1F00000000 + + isa + PBXFileReference + name + libDisplay.dylib + path + libDisplay.dylib + sourceTree + BUILT_PRODUCTS_DIR + explicitFileType + compiled.mach-o.dylib + + 1DD70E29D65BA68200000000 + + isa + PBXFileReference + name + libSwiftSignalKit.dylib + path + libSwiftSignalKit.dylib + sourceTree + BUILT_PRODUCTS_DIR + explicitFileType + compiled.mach-o.dylib + + B401C97968022A5500000000 + + isa + PBXGroup + name + Frameworks + sourceTree + ]]> + children + + 1DD70E29FF334B1F00000000 + 1DD70E29D65BA68200000000 + + + 1DD70E29AA32BBC600000000 + + isa + PBXFileReference + name + libQrCode.a + path + libQrCode.a + sourceTree + BUILT_PRODUCTS_DIR + explicitFileType + archive.ar + + B401C979C806358400000000 + + isa + PBXGroup + name + Products + sourceTree + ]]> + children + + 1DD70E29AA32BBC600000000 + + + 1DD70E29001F47FB00000000 + + isa + PBXFileReference + name + BUCK + path + BUCK + sourceTree + SOURCE_ROOT + explicitFileType + text.script.python + + 1DD70E2905A53BC200000000 + + isa + PBXFileReference + name + BitBuffer.cpp + path + Sources/BitBuffer.cpp + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.cpp.cpp + + 1DD70E2905A54E8700000000 + + isa + PBXFileReference + name + BitBuffer.hpp + path + Sources/BitBuffer.hpp + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.cpp.h + + 1DD70E2921C2F78300000000 + + isa + PBXFileReference + name + QrCode.cpp + path + Sources/QrCode.cpp + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.cpp.cpp + + 1DD70E2921C30A4800000000 + + isa + PBXFileReference + name + QrCode.hpp + path + Sources/QrCode.hpp + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.cpp.h + + 1DD70E29BDC7BBF300000000 + + isa + PBXFileReference + name + QrCode.swift + path + Sources/QrCode.swift + sourceTree + SOURCE_ROOT + + 1DD70E2956ECDFBD00000000 + + isa + PBXFileReference + name + QrCodeInstance.h + path + Sources/QrCodeInstance.h + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.c.h + + 1DD70E2986AF18EB00000000 + + isa + PBXFileReference + name + QrCodeInstance.mm + path + Sources/QrCodeInstance.mm + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.cpp.objcpp + + 1DD70E290F1C936700000000 + + isa + PBXFileReference + name + QrSegment.cpp + path + Sources/QrSegment.cpp + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.cpp.cpp + + 1DD70E290F1CA62C00000000 + + isa + PBXFileReference + name + QrSegment.hpp + path + Sources/QrSegment.hpp + sourceTree + SOURCE_ROOT + lastKnownFileType + sourcecode.cpp.h + + B401C979EAB5339800000000 + + isa + PBXGroup + name + Sources + sourceTree + ]]> + children + + 1DD70E2905A53BC200000000 + 1DD70E2905A54E8700000000 + 1DD70E2921C2F78300000000 + 1DD70E2921C30A4800000000 + 1DD70E29BDC7BBF300000000 + 1DD70E2956ECDFBD00000000 + 1DD70E2986AF18EB00000000 + 1DD70E290F1C936700000000 + 1DD70E290F1CA62C00000000 + + + B401C979909F23CE00000000 + + isa + PBXGroup + name + QrCode + sourceTree + ]]> + children + + 1DD70E29001F47FB00000000 + B401C979EAB5339800000000 + + + B401C979EFB6AC4600000000 + + isa + PBXGroup + name + mainGroup + sourceTree + ]]> + children + + B401C979B781F65D00000000 + B401C97968022A5500000000 + B401C979C806358400000000 + B401C979909F23CE00000000 + + + E7A30F0405A53BC200000000 + + isa + PBXBuildFile + fileRef + 1DD70E2905A53BC200000000 + + E7A30F0421C2F78300000000 + + isa + PBXBuildFile + fileRef + 1DD70E2921C2F78300000000 + + E7A30F04BDC7BBF300000000 + + isa + PBXBuildFile + fileRef + 1DD70E29BDC7BBF300000000 + + E7A30F0486AF18EB00000000 + + isa + PBXBuildFile + fileRef + 1DD70E2986AF18EB00000000 + + E7A30F040F1C936700000000 + + isa + PBXBuildFile + fileRef + 1DD70E290F1C936700000000 + + 1870857F0000000000000000 + + isa + PBXSourcesBuildPhase + files + + E7A30F0405A53BC200000000 + E7A30F0421C2F78300000000 + E7A30F04BDC7BBF300000000 + E7A30F0486AF18EB00000000 + E7A30F040F1C936700000000 + + + E7A30F04FF334B1F00000000 + + isa + PBXBuildFile + fileRef + 1DD70E29FF334B1F00000000 + + E7A30F04D65BA68200000000 + + isa + PBXBuildFile + fileRef + 1DD70E29D65BA68200000000 + + FAF5FAC90000000000000000 + + isa + PBXCopyFilesBuildPhase + files + + E7A30F04FF334B1F00000000 + E7A30F04D65BA68200000000 + + name + Fake Swift Dependencies (Copy Files Phase) + runOnlyForDeploymentPostprocessing + 1 + dstSubfolderSpec + 16 + dstPath + + + 4952437303EDA63300000000 + + isa + XCBuildConfiguration + name + Debug + buildSettings + + + baseConfigurationReference + 1DD70E295898BF2700000000 + + 4952437350C7218900000000 + + isa + XCBuildConfiguration + name + Profile + buildSettings + + + baseConfigurationReference + 1DD70E297A8828D100000000 + + 49524373A439BFE700000000 + + isa + XCBuildConfiguration + name + Release + buildSettings + + + baseConfigurationReference + 1DD70E29EE1ED43300000000 + + 218C37090000000000000000 + + isa + XCConfigurationList + buildConfigurations + + 4952437303EDA63300000000 + 4952437350C7218900000000 + 49524373A439BFE700000000 + + defaultConfigurationIsVisible + + + E66DC04E909F23CE00000000 + + isa + PBXNativeTarget + name + QrCode + productName + QrCode + productReference + 1DD70E29AA32BBC600000000 + productType + com.apple.product-type.library.static + dependencies + + + buildPhases + + 1870857F0000000000000000 + FAF5FAC90000000000000000 + + buildConfigurationList + 218C37090000000000000000 + + 4952437303EDA63300000001 + + isa + XCBuildConfiguration + name + Debug + buildSettings + + + + 4952437350C7218900000001 + + isa + XCBuildConfiguration + name + Profile + buildSettings + + + + 49524373A439BFE700000001 + + isa + XCBuildConfiguration + name + Release + buildSettings + + + + 218C37090000000000000001 + + isa + XCConfigurationList + buildConfigurations + + 4952437303EDA63300000001 + 4952437350C7218900000001 + 49524373A439BFE700000001 + + defaultConfigurationIsVisible + + + 96C84793909F23CE00000000 + + isa + PBXProject + mainGroup + B401C979EFB6AC4600000000 + targets + + E66DC04E909F23CE00000000 + + buildConfigurationList + 218C37090000000000000001 + compatibilityVersion + Xcode 3.2 + attributes + + LastUpgradeCheck + 9999 + + + + rootObject + 96C84793909F23CE00000000 + + \ No newline at end of file diff --git a/submodules/GlassButtonNode/QrCode.xcodeproj/xcshareddata/xcschemes/QrCode.xcscheme b/submodules/GlassButtonNode/QrCode.xcodeproj/xcshareddata/xcschemes/QrCode.xcscheme new file mode 100644 index 0000000000..9365080e82 --- /dev/null +++ b/submodules/GlassButtonNode/QrCode.xcodeproj/xcshareddata/xcschemes/QrCode.xcscheme @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/submodules/GlassButtonNode/Sources/GlassButtonNode.swift b/submodules/GlassButtonNode/Sources/GlassButtonNode.swift new file mode 100644 index 0000000000..f9fd932c6a --- /dev/null +++ b/submodules/GlassButtonNode/Sources/GlassButtonNode.swift @@ -0,0 +1,178 @@ +import Foundation +import Display +import AsyncDisplayKit +import SwiftSignalKit + +private let largeButtonSize = CGSize(width: 72.0, height: 72.0) +private let smallButtonSize = CGSize(width: 60.0, height: 60.0) + +private func generateEmptyButtonImage(icon: UIImage?, strokeColor: UIColor?, fillColor: UIColor, knockout: Bool = false, angle: CGFloat = 0.0, buttonSize: CGSize = smallButtonSize) -> UIImage? { + return generateImage(buttonSize, contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setBlendMode(.copy) + if let strokeColor = strokeColor { + context.setFillColor(strokeColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) + context.setFillColor(fillColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(x: 1.5, y: 1.5), size: CGSize(width: size.width - 3.0, height: size.height - 3.0))) + } else { + context.setFillColor(fillColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height))) + } + + if let icon = icon { + if !angle.isZero { + context.translateBy(x: size.width / 2.0, y: size.height / 2.0) + context.rotate(by: angle) + context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0) + } + let imageSize = icon.size + let imageRect = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: floor((size.width - imageSize.height) / 2.0)), size: imageSize) + if knockout { + context.setBlendMode(.copy) + context.clip(to: imageRect, mask: icon.cgImage!) + context.setFillColor(UIColor.clear.cgColor) + context.fill(imageRect) + } else { + context.setBlendMode(.normal) + context.draw(icon.cgImage!, in: imageRect) + } + } + }) +} + +private func generateFilledButtonImage(color: UIColor, icon: UIImage?, angle: CGFloat = 0.0, buttonSize: CGSize = smallButtonSize) -> UIImage? { + return generateImage(buttonSize, contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setBlendMode(.normal) + context.setFillColor(color.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) + + if let icon = icon { + if !angle.isZero { + context.translateBy(x: size.width / 2.0, y: size.height / 2.0) + context.rotate(by: angle) + context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0) + } + context.draw(icon.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - icon.size.width) / 2.0), y: floor((size.height - icon.size.height) / 2.0)), size: icon.size)) + } + }) +} + +private let emptyHighlightedFill = UIColor(white: 1.0, alpha: 0.3) +private let invertedFill = UIColor(white: 1.0, alpha: 1.0) + +private let largeLabelFont = Font.regular(14.5) +private let smallLabelFont = Font.regular(11.5) + +public final class GlassButtonNode: HighlightTrackingButtonNode { + private var regularImage: UIImage? + private var highlightedImage: UIImage? + private var filledImage: UIImage? + + private let blurView: UIVisualEffectView + private let iconNode: ASImageNode + private var labelNode: ASTextNode? + + public init(icon: UIImage, label: String?) { + let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .light)) + blurView.clipsToBounds = true + blurView.isUserInteractionEnabled = false + self.blurView = blurView + + self.iconNode = ASImageNode() + self.iconNode.isLayerBacked = true + self.iconNode.displayWithoutProcessing = false + self.iconNode.displaysAsynchronously = false + + self.regularImage = generateEmptyButtonImage(icon: icon, strokeColor: nil, fillColor: .clear, buttonSize: largeButtonSize) + self.highlightedImage = generateEmptyButtonImage(icon: icon, strokeColor: nil, fillColor: emptyHighlightedFill, buttonSize: largeButtonSize) + self.filledImage = generateEmptyButtonImage(icon: icon, strokeColor: nil, fillColor: invertedFill, knockout: true, buttonSize: largeButtonSize) + + if let label = label { + let labelNode = ASTextNode() + let labelFont: UIFont + if let image = regularImage, image.size.width < 70.0 { + labelFont = smallLabelFont + } else { + labelFont = largeLabelFont + } + labelNode.attributedText = NSAttributedString(string: label, font: labelFont, textColor: .white) + self.labelNode = labelNode + } else { + self.labelNode = nil + } + + super.init() + + self.view.addSubview(blurView) + self.addSubnode(self.iconNode) + if let labelNode = self.labelNode { + self.addSubnode(labelNode) + } + self.iconNode.image = regularImage + self.currentImage = regularImage + + self.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + strongSelf.internalHighlighted = highlighted + strongSelf.updateState(highlighted: highlighted, selected: strongSelf.isSelected) + } + } + } + + private var internalHighlighted = false + + override public var isSelected: Bool { + didSet { + self.updateState(highlighted: self.internalHighlighted, selected: self.isSelected) + } + } + + private var currentImage: UIImage? + + private func updateState(highlighted: Bool, selected: Bool) { + let image: UIImage? + if selected { + image = self.filledImage + } else if highlighted { + image = self.highlightedImage + } else { + image = self.regularImage + } + + if self.currentImage !== image { + let currentContents = self.iconNode.layer.contents + self.iconNode.layer.removeAnimation(forKey: "contents") + if let currentContents = currentContents, let image = image { + self.iconNode.image = image + self.iconNode.layer.animate(from: currentContents as AnyObject, to: image.cgImage!, keyPath: "contents", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: image === self.currentImage || image === self.filledImage ? 0.25 : 0.15) + } else { + self.iconNode.image = image + } + self.currentImage = image + } + } + + override public func layout() { + super.layout() + + let size = self.bounds.size + + self.blurView.layer.cornerRadius = size.width / 2.0 + blurView.frame = self.bounds + + self.iconNode.frame = self.bounds + + if let labelNode = self.labelNode { + let labelSize = labelNode.measure(CGSize(width: 200.0, height: 100.0)) + let offset: CGFloat + if size.width < 70.0 { + offset = 65.0 + } else { + offset = 81.0 + } + labelNode.frame = CGRect(origin: CGPoint(x: floor((size.width - labelSize.width) / 2.0), y: offset), size: labelSize) + } + } +} diff --git a/submodules/ItemListUI/Sources/Items/ItemListMultilineInputItem.swift b/submodules/ItemListUI/Sources/Items/ItemListMultilineInputItem.swift index 3d131bfeac..742e363123 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListMultilineInputItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListMultilineInputItem.swift @@ -15,6 +15,16 @@ public struct ItemListMultilineInputItemTextLimit { } } +public struct ItemListMultilineInputInlineAction { + public let icon: UIImage + public let action: (() -> Void)? + + public init(icon: UIImage, action: (() -> Void)?) { + self.icon = icon + self.action = action + } +} + public class ItemListMultilineInputItem: ListViewItem, ItemListItem { let theme: PresentationTheme let text: String @@ -27,11 +37,12 @@ public class ItemListMultilineInputItem: ListViewItem, ItemListItem { let action: (() -> Void)? let textUpdated: (String) -> Void let shouldUpdateText: (String) -> Bool - public let tag: ItemListItemTag? let maxLength: ItemListMultilineInputItemTextLimit? let minimalHeight: CGFloat? + let inlineAction: ItemListMultilineInputInlineAction? + public let tag: ItemListItemTag? - public init(theme: PresentationTheme, text: String, placeholder: String, maxLength: ItemListMultilineInputItemTextLimit?, sectionId: ItemListSectionId, style: ItemListStyle, capitalization: Bool = true, autocorrection: Bool = true, returnKeyType: UIReturnKeyType = .default, minimalHeight: CGFloat? = nil, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, tag: ItemListItemTag? = nil, action: (() -> Void)? = nil) { + public init(theme: PresentationTheme, text: String, placeholder: String, maxLength: ItemListMultilineInputItemTextLimit?, sectionId: ItemListSectionId, style: ItemListStyle, capitalization: Bool = true, autocorrection: Bool = true, returnKeyType: UIReturnKeyType = .default, minimalHeight: CGFloat? = nil, textUpdated: @escaping (String) -> Void, shouldUpdateText: @escaping (String) -> Bool = { _ in return true }, tag: ItemListItemTag? = nil, action: (() -> Void)? = nil, inlineAction: ItemListMultilineInputInlineAction? = nil) { self.theme = theme self.text = text self.placeholder = placeholder @@ -46,6 +57,7 @@ public class ItemListMultilineInputItem: ListViewItem, ItemListItem { self.shouldUpdateText = shouldUpdateText self.tag = tag self.action = action + self.inlineAction = inlineAction } public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { @@ -94,6 +106,7 @@ public class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNod private let measureTextNode: TextNode private let limitTextNode: TextNode + private var inlineActionButtonNode: HighlightableButtonNode? private var item: ItemListMultilineInputItem? private var layoutParams: ListViewItemLayoutParams? @@ -185,6 +198,10 @@ public class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNod rightInset += 30.0 } + if let inlineAction = item.inlineAction { + rightInset += inlineAction.icon.size.width + 8.0 + } + var measureText = item.text if measureText.hasSuffix("\n") || measureText.isEmpty { measureText += "|" @@ -225,6 +242,10 @@ public class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNod strongSelf.textNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(17.0), NSAttributedString.Key.foregroundColor.rawValue: item.theme.list.itemPrimaryTextColor] strongSelf.textNode.tintColor = item.theme.list.itemAccentColor } + + if let inlineAction = item.inlineAction { + strongSelf.inlineActionButtonNode?.setImage(generateTintedImage(image: inlineAction.icon, color: item.theme.list.itemAccentColor), for: .normal) + } } let capitalizationType: UITextAutocapitalizationType = item.capitalization ? .sentences : .none @@ -293,6 +314,23 @@ public class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNod } else if strongSelf.limitTextNode.supernode != nil { strongSelf.limitTextNode.removeFromSupernode() } + + if let inlineAction = item.inlineAction { + let inlineActionButtonNode: HighlightableButtonNode + if let currentInlineActionButtonNode = strongSelf.inlineActionButtonNode { + inlineActionButtonNode = currentInlineActionButtonNode + } else { + inlineActionButtonNode = HighlightableButtonNode() + inlineActionButtonNode.setImage(generateTintedImage(image: inlineAction.icon, color: item.theme.list.itemAccentColor), for: .normal) + inlineActionButtonNode.addTarget(strongSelf, action: #selector(strongSelf.inlineActionPressed), forControlEvents: .touchUpInside) + strongSelf.addSubnode(inlineActionButtonNode) + strongSelf.inlineActionButtonNode = inlineActionButtonNode + } + inlineActionButtonNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - inlineAction.icon.size.width - 11.0, y: 7.0), size: inlineAction.icon.size) + } else if let inlineActionButtonNode = strongSelf.inlineActionButtonNode { + inlineActionButtonNode.removeFromSupernode() + strongSelf.inlineActionButtonNode = nil + } } }) } @@ -377,4 +415,10 @@ public class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNod public func animateError() { self.textNode.layer.addShakeAnimation() } + + @objc private func inlineActionPressed() { + if let action = self.item?.inlineAction?.action { + action() + } + } } diff --git a/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift b/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift index 452182202f..18d396b2b8 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift @@ -14,10 +14,27 @@ public enum ItemListSectionHeaderAccessoryTextColor { public struct ItemListSectionHeaderAccessoryText: Equatable { public let value: String public let color: ItemListSectionHeaderAccessoryTextColor + public let icon: UIImage? - public init(value: String, color: ItemListSectionHeaderAccessoryTextColor) { + public init(value: String, color: ItemListSectionHeaderAccessoryTextColor, icon: UIImage? = nil) { self.value = value self.color = color + self.icon = icon + } +} + +public enum ItemListSectionHeaderActivityIndicator { + case none + case left + case right + + fileprivate var hasActivity: Bool { + switch self { + case .left, .right: + return true + default: + return false + } } } @@ -25,13 +42,13 @@ public class ItemListSectionHeaderItem: ListViewItem, ItemListItem { let theme: PresentationTheme let text: String let multiline: Bool - let activityIndicator: Bool + let activityIndicator: ItemListSectionHeaderActivityIndicator let accessoryText: ItemListSectionHeaderAccessoryText? public let sectionId: ItemListSectionId public let isAlwaysPlain: Bool = true - public init(theme: PresentationTheme, text: String, multiline: Bool = false, activityIndicator: Bool = false, accessoryText: ItemListSectionHeaderAccessoryText? = nil, sectionId: ItemListSectionId) { + public init(theme: PresentationTheme, text: String, multiline: Bool = false, activityIndicator: ItemListSectionHeaderActivityIndicator = .none, accessoryText: ItemListSectionHeaderAccessoryText? = nil, sectionId: ItemListSectionId) { self.theme = theme self.text = text self.multiline = multiline @@ -64,7 +81,6 @@ public class ItemListSectionHeaderItem: ListViewItem, ItemListItem { } let makeLayout = nodeValue.asyncLayout() - async { let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) Queue.mainQueue().async { @@ -84,8 +100,9 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode { private let titleNode: TextNode private let accessoryTextNode: TextNode + private var accessoryImageNode: ASImageNode? private var activityIndicator: ActivityIndicator? - + private let activateArea: AccessibilityAreaNode public init() { @@ -120,6 +137,7 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode { let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.text, font: titleFont, textColor: item.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: item.multiline ? 0 : 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) var accessoryTextString: NSAttributedString? + var accessoryIcon: UIImage? if let accessoryText = item.accessoryText { let color: UIColor switch accessoryText.color { @@ -129,6 +147,7 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode { color = item.theme.list.freeTextErrorColor } accessoryTextString = NSAttributedString(string: accessoryText.value, font: titleFont, textColor: color) + accessoryIcon = accessoryText.icon } let (accessoryLayout, accessoryApply) = makeAccessoryTextLayout(TextNodeLayoutArguments(attributedString: accessoryTextString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) @@ -158,10 +177,33 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode { strongSelf.activateArea.accessibilityLabel = item.text strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 7.0), size: titleLayout.size) - strongSelf.accessoryTextNode.frame = CGRect(origin: CGPoint(x: params.width - leftInset - accessoryLayout.size.width, y: 7.0), size: accessoryLayout.size) + + var accessoryTextOffset: CGFloat = 0.0 + if let accessoryIcon = accessoryIcon { + accessoryTextOffset += accessoryIcon.size.width + 3.0 + } + strongSelf.accessoryTextNode.frame = CGRect(origin: CGPoint(x: params.width - leftInset - accessoryLayout.size.width - accessoryTextOffset, y: 7.0), size: accessoryLayout.size) + + if let accessoryIcon = accessoryIcon { + let accessoryImageNode: ASImageNode + if let currentAccessoryImageNode = strongSelf.accessoryImageNode { + accessoryImageNode = currentAccessoryImageNode + } else { + accessoryImageNode = ASImageNode() + accessoryImageNode.displaysAsynchronously = false + accessoryImageNode.displayWithoutProcessing = true + strongSelf.addSubnode(accessoryImageNode) + strongSelf.accessoryImageNode = accessoryImageNode + } + accessoryImageNode.image = accessoryIcon + accessoryImageNode.frame = CGRect(origin: CGPoint(x: params.width - leftInset - accessoryIcon.size.width, y: 7.0), size: accessoryIcon.size) + } else if let accessoryImageNode = strongSelf.accessoryImageNode { + accessoryImageNode.removeFromSupernode() + strongSelf.accessoryImageNode = nil + } if previousItem?.activityIndicator != item.activityIndicator { - if item.activityIndicator { + if item.activityIndicator.hasActivity { let activityIndicator: ActivityIndicator if let currentActivityIndicator = strongSelf.activityIndicator { activityIndicator = currentActivityIndicator @@ -183,7 +225,18 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode { } } - strongSelf.activityIndicator?.frame = CGRect(origin: CGPoint(x: strongSelf.titleNode.frame.maxX + 6.0, y: 7.0 - UIScreenPixel), size: CGSize(width: 18.0, height: 18.0)) + var activityIndicatorOrigin: CGPoint? + switch item.activityIndicator { + case .left: + activityIndicatorOrigin = CGPoint(x: strongSelf.titleNode.frame.maxX + 6.0, y: 7.0 - UIScreenPixel) + case .right: + activityIndicatorOrigin = CGPoint(x: params.width - leftInset - 18.0, y: 7.0 - UIScreenPixel) + default: + break + } + if let activityIndicatorOrigin = activityIndicatorOrigin { + strongSelf.activityIndicator?.frame = CGRect(origin: activityIndicatorOrigin, size: CGSize(width: 18.0, height: 18.0)) + } } }) } diff --git a/submodules/MtProtoKit/TON/TON.h b/submodules/MtProtoKit/TON/TON.h index 21051e8dee..17c500e573 100644 --- a/submodules/MtProtoKit/TON/TON.h +++ b/submodules/MtProtoKit/TON/TON.h @@ -43,8 +43,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) int64_t value; @property (nonatomic, strong, readonly) NSString * _Nonnull source; @property (nonatomic, strong, readonly) NSString * _Nonnull destination; +@property (nonatomic, strong, readonly) NSString * _Nonnull textMessage; -- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination; +- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination textMessage:(NSString * _Nonnull)textMessage; @end @@ -80,7 +81,7 @@ NS_ASSUME_NONNULL_BEGIN - (MTSignal *)getTestGiverAddress; - (MTSignal *)testGiverSendGramsWithAccountState:(TONAccountState *)accountState accountAddress:(NSString *)accountAddress amount:(int64_t)amount; - (MTSignal *)getAccountStateWithAddress:(NSString *)accountAddress; -- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount; +- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSString *)textMessage; - (MTSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword; - (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray *)wordList; - (MTSignal *)deleteKeyWithPublicKey:(NSString *)publicKey; diff --git a/submodules/MtProtoKit/TON/TON.mm b/submodules/MtProtoKit/TON/TON.mm index a1d75df6eb..a1da48eb10 100644 --- a/submodules/MtProtoKit/TON/TON.mm +++ b/submodules/MtProtoKit/TON/TON.mm @@ -42,11 +42,15 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj return nil; } NSString *source = readString(message->source_); - NSString *destination = readString(message->source_); + NSString *destination = readString(message->destination_); + NSString *textMessage = readString(message->message_); if (source == nil || destination == nil) { return nil; } - return [[TONTransactionMessage alloc] initWithValue:message->value_ source:source destination:destination]; + if (textMessage == nil) { + textMessage = @""; + } + return [[TONTransactionMessage alloc] initWithValue:message->value_ source:source destination:destination textMessage:textMessage]; } @implementation TONKey @@ -91,12 +95,13 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj @implementation TONTransactionMessage -- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination { +- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination textMessage:(NSString * _Nonnull)textMessage { self = [super init]; if (self != nil) { _value = value; _source = source; _destination = destination; + _textMessage = textMessage; } return self; } @@ -449,7 +454,12 @@ typedef enum { } }]; - auto query = make_object(make_object(accountAddress.UTF8String), accountState.seqno, amount); + auto query = make_object(make_object( + accountAddress.UTF8String), + accountState.seqno, + amount, + std::string() + ); _client->send({ requestId, std::move(query) }); return [[MTBlockDisposable alloc] initWithBlock:^{ @@ -493,13 +503,18 @@ typedef enum { }] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; } -- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount { +- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSString * _Nonnull)textMessage { return [[[[MTSignal alloc] initWithGenerator:^id(MTSubscriber *subscriber) { NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding]; if (publicKeyData == nil) { [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]]; return [[MTBlockDisposable alloc] initWithBlock:^{}]; } + NSData *textMessageData = [textMessage dataUsingEncoding:NSUTF8StringEncoding]; + if (textMessageData == nil) { + [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]]; + return [[MTBlockDisposable alloc] initWithBlock:^{}]; + } uint64_t requestId = _nextRequestId; _nextRequestId += 1; @@ -523,7 +538,8 @@ typedef enum { ), make_object(fromAddress.UTF8String), make_object(address.UTF8String), - amount + amount, + makeString(textMessageData) ); _client->send({ requestId, std::move(query) }); diff --git a/submodules/PeerInfoUI/Sources/SecretChatKeyController.swift b/submodules/PeerInfoUI/Sources/SecretChatKeyController.swift index 40dc5a7f67..6a10c006f6 100644 --- a/submodules/PeerInfoUI/Sources/SecretChatKeyController.swift +++ b/submodules/PeerInfoUI/Sources/SecretChatKeyController.swift @@ -27,6 +27,8 @@ final class SecretChatKeyController: ViewController { super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) + self.navigationPresentation = .modal + self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style self.title = self.presentationData.strings.EncryptionKey_Title } diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index cd5c41fe47..2080e27999 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -192,7 +192,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { case let .header(theme, text): return PeersNearbyHeaderItem(theme: theme, text: text, sectionId: self.section) case let .usersHeader(theme, text, loading): - return ItemListSectionHeaderItem(theme: theme, text: text, activityIndicator: loading, sectionId: self.section) + return ItemListSectionHeaderItem(theme: theme, text: text, activityIndicator: loading ? .left : .none, sectionId: self.section) case let .empty(theme, text): return ItemListPlaceholderItem(theme: theme, text: text, sectionId: self.section, style: .blocks) case let .user(_, theme, strings, dateTimeFormat, nameDisplayOrder, peer): @@ -200,7 +200,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { arguments.openChat(peer.peer.0) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, hasTopGroupInset: false, tag: nil) case let .groupsHeader(theme, text, loading): - return ItemListSectionHeaderItem(theme: theme, text: text, activityIndicator: loading, sectionId: self.section) + return ItemListSectionHeaderItem(theme: theme, text: text, activityIndicator: loading ? .left : .none, sectionId: self.section) case let .createGroup(theme, title, latitude, longitude, address): return ItemListPeerActionItem(theme: theme, icon: PresentationResourcesItemList.createGroupIcon(theme), title: title, alwaysPlain: false, sectionId: self.section, editing: false, action: { if let latitude = latitude, let longitude = longitude { diff --git a/submodules/SettingsUI/SettingsUI.xcodeproj/project.pbxproj b/submodules/SettingsUI/SettingsUI.xcodeproj/project.pbxproj index 4a3bb76ff3..cf28f35d43 100644 --- a/submodules/SettingsUI/SettingsUI.xcodeproj/project.pbxproj +++ b/submodules/SettingsUI/SettingsUI.xcodeproj/project.pbxproj @@ -429,6 +429,19 @@ explicitFileType archive.ar + 1DD70E29BCD8FADE00000000 + + isa + PBXFileReference + name + libGlassButtonNode.a + path + libGlassButtonNode.a + sourceTree + BUILT_PRODUCTS_DIR + explicitFileType + archive.ar + 1DD70E29F8FF5A6500000000 isa @@ -1584,6 +1597,7 @@ 1DD70E29FF334B1F00000000 1DD70E29F29DEA1400000000 1DD70E29D1EB356900000000 + 1DD70E29BCD8FADE00000000 1DD70E29F8FF5A6500000000 1DD70E2947B6256000000000 1DD70E2971ED41B100000000 @@ -4796,6 +4810,13 @@ fileRef 1DD70E29BFBD457D00000000 + E7A30F04BCD8FADE00000000 + + isa + PBXBuildFile + fileRef + 1DD70E29BCD8FADE00000000 + E7A30F04D097476500000000 isa @@ -4933,6 +4954,7 @@ E7A30F04DA3FBAD600000000 E7A30F04D81471E200000000 E7A30F04BFBD457D00000000 + E7A30F04BCD8FADE00000000 E7A30F04D097476500000000 E7A30F04A7E1559B00000000 E7A30F04DF12291E00000000 diff --git a/submodules/SettingsUI/Sources/DebugController.swift b/submodules/SettingsUI/Sources/DebugController.swift index bba8987083..aa7b247e47 100644 --- a/submodules/SettingsUI/Sources/DebugController.swift +++ b/submodules/SettingsUI/Sources/DebugController.swift @@ -479,6 +479,8 @@ private enum DebugControllerEntry: ItemListNodeEntry { guard let context = arguments.context else { return } + let _ = debugDeleteWallets(postbox: context.account.postbox).start() + return let _ = (availableWallets(postbox: context.account.postbox) |> deliverOnMainQueue).start(next: { wallets in if let tonContext = context.tonContext { diff --git a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift index 2bae821282..96802ba9f2 100644 --- a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift +++ b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift @@ -808,8 +808,17 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList } } - return combineLatest(watchAppInstalled, canAddAccount, localizations, notificationSettings, notificationExceptionsList, archivedStickerPacks, proxyServers, privacySettings) - |> map { watchAppInstalled, canAddAccount, localizations, notificationSettings, notificationExceptionsList, archivedStickerPacks, proxyServers, privacySettings in + let hasWallet = context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) + |> take(1) + |> map { view -> Bool in + let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let configuration = WalletConfiguration.with(appConfiguration: appConfiguration) + return configuration.enabled + } + + + return combineLatest(watchAppInstalled, hasWallet, canAddAccount, localizations, notificationSettings, notificationExceptionsList, archivedStickerPacks, proxyServers, privacySettings) + |> map { watchAppInstalled, hasWallet, canAddAccount, localizations, notificationSettings, notificationExceptionsList, archivedStickerPacks, proxyServers, privacySettings in let strings = context.sharedContext.currentPresentationData.with { $0 }.strings var allItems: [SettingsSearchableItem] = [] @@ -858,12 +867,14 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList }) allItems.append(passport) - let wallet = SettingsSearchableItem(id: .wallet(0), title: "Wallet", alternate: synonyms("Wallet"), icon: .passport, breadcrumbs: [], present: { context, _, present in - openWallet(context: context, push: { c in - present(.push, c) + if hasWallet { + let wallet = SettingsSearchableItem(id: .wallet(0), title: "Wallet", alternate: synonyms("Wallet"), icon: .passport, breadcrumbs: [], present: { context, _, present in + openWallet(context: context, push: { c in + present(.push, c) + }) }) - }) - allItems.append(wallet) + allItems.append(wallet) + } let support = SettingsSearchableItem(id: .support(0), title: strings.Settings_Support, alternate: synonyms(strings.SettingsSearch_Synonyms_Support), icon: .support, breadcrumbs: [], present: { context, _, present in let _ = (supportPeerId(account: context.account) diff --git a/submodules/SettingsUI/Sources/SettingsController.swift b/submodules/SettingsUI/Sources/SettingsController.swift index fa38b0f10b..cf7b3e3846 100644 --- a/submodules/SettingsUI/Sources/SettingsController.swift +++ b/submodules/SettingsUI/Sources/SettingsController.swift @@ -453,7 +453,7 @@ private enum SettingsEntry: ItemListNodeEntry { case let .proxy(theme, image, text, value): return ItemListDisclosureItem(theme: theme, icon: image, title: text, label: value, sectionId: ItemListSectionId(self.section), style: .blocks, action: { arguments.openProxy() - }, clearHighlightAutomatically: false) + }) case let .savedMessages(theme, image, text): return ItemListDisclosureItem(theme: theme, icon: image, title: text, label: "", sectionId: ItemListSectionId(self.section), style: .blocks, action: { arguments.openSavedMessages() @@ -516,7 +516,7 @@ private struct SettingsState: Equatable { var isSearching: Bool } -private func settingsEntries(account: Account, presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, notifyExceptions: NotificationExceptionsList?, notificationsAuthorizationStatus: AccessType, notificationsWarningSuppressed: Bool, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?, privacySettings: AccountPrivacySettings?, hasPassport: Bool, hasWatchApp: Bool, accountsAndPeers: [(Account, Peer, Int32)], inAppNotificationSettings: InAppNotificationSettings, experimentalUISettings: ExperimentalUISettings, displayPhoneNumberConfirmation: Bool) -> [SettingsEntry] { +private func settingsEntries(account: Account, presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, notifyExceptions: NotificationExceptionsList?, notificationsAuthorizationStatus: AccessType, notificationsWarningSuppressed: Bool, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?, privacySettings: AccountPrivacySettings?, hasWallet: Bool, hasPassport: Bool, hasWatchApp: Bool, accountsAndPeers: [(Account, Peer, Int32)], inAppNotificationSettings: InAppNotificationSettings, experimentalUISettings: ExperimentalUISettings, displayPhoneNumberConfirmation: Bool) -> [SettingsEntry] { var entries: [SettingsEntry] = [] if let peer = peerViewMainPeer(view) as? TelegramUser { @@ -577,7 +577,7 @@ private func settingsEntries(account: Account, presentationData: PresentationDat if hasPassport { entries.append(.passport(presentationData.theme, PresentationResourcesSettings.passport, presentationData.strings.Settings_Passport, "")) } - if experimentalUISettings.wallets { + if hasWallet || experimentalUISettings.wallets { entries.append(.wallet(presentationData.theme, PresentationResourcesSettings.passport, "Wallet", "")) } @@ -1098,6 +1098,17 @@ public func settingsController(context: AccountContext, accountManager: AccountM ) ) + let hasWallet = .single(false) + |> then(contextValue.get() + |> mapToSignal { context in + return context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) + |> map { view -> Bool in + let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let configuration = WalletConfiguration.with(appConfiguration: appConfiguration) + return configuration.enabled + } + }) + let hasPassport = ValuePromise(false) let updatePassport: () -> Void = { updatePassportDisposable.set(( @@ -1206,8 +1217,8 @@ public func settingsController(context: AccountContext, accountManager: AccountM return context.account.viewTracker.featuredStickerPacks() } - let signal = combineLatest(queue: Queue.mainQueue(), contextValue.get(), updatedPresentationData, statePromise.get(), peerView, combineLatest(queue: Queue.mainQueue(), preferences, notifyExceptions.get(), notificationsAuthorizationStatus.get(), notificationsWarningSuppressed.get(), privacySettings.get(), displayPhoneNumberConfirmation.get()), combineLatest(featuredStickerPacks, archivedPacks.get()), combineLatest(hasPassport.get(), hasWatchApp.get()), accountsAndPeers.get()) - |> map { context, presentationData, state, view, preferencesAndExceptions, featuredAndArchived, hasPassportAndWatch, accountsAndPeers -> (ItemListControllerState, (ItemListNodeState, SettingsEntry.ItemGenerationArguments)) in + let signal = combineLatest(queue: Queue.mainQueue(), contextValue.get(), updatedPresentationData, statePromise.get(), peerView, combineLatest(queue: Queue.mainQueue(), preferences, notifyExceptions.get(), notificationsAuthorizationStatus.get(), notificationsWarningSuppressed.get(), privacySettings.get(), displayPhoneNumberConfirmation.get()), combineLatest(featuredStickerPacks, archivedPacks.get()), combineLatest(hasWallet, hasPassport.get(), hasWatchApp.get()), accountsAndPeers.get()) + |> map { context, presentationData, state, view, preferencesAndExceptions, featuredAndArchived, hasWalletPassportAndWatch, accountsAndPeers -> (ItemListControllerState, (ItemListNodeState, SettingsEntry.ItemGenerationArguments)) in let proxySettings: ProxySettings = preferencesAndExceptions.0.entries[SharedDataKeys.proxySettings] as? ProxySettings ?? ProxySettings.defaultSettings let inAppNotificationSettings: InAppNotificationSettings = preferencesAndExceptions.0.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings let experimentalUISettings: ExperimentalUISettings = preferencesAndExceptions.0.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings @@ -1244,8 +1255,8 @@ public func settingsController(context: AccountContext, accountManager: AccountM pushControllerImpl?(c) }, getNavigationController: getNavigationControllerImpl, exceptionsList: notifyExceptions.get(), archivedStickerPacks: archivedPacks.get(), privacySettings: privacySettings.get()) - let (hasPassport, hasWatchApp) = hasPassportAndWatch - let listState = ItemListNodeState(entries: settingsEntries(account: context.account, presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, notifyExceptions: preferencesAndExceptions.1, notificationsAuthorizationStatus: preferencesAndExceptions.2, notificationsWarningSuppressed: preferencesAndExceptions.3, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, privacySettings: preferencesAndExceptions.4, hasPassport: hasPassport, hasWatchApp: hasWatchApp, accountsAndPeers: accountsAndPeers.1, inAppNotificationSettings: inAppNotificationSettings, experimentalUISettings: experimentalUISettings, displayPhoneNumberConfirmation: preferencesAndExceptions.5), style: .blocks, searchItem: searchItem, initialScrollToItem: ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up)) + let (hasWallet, hasPassport, hasWatchApp) = hasWalletPassportAndWatch + let listState = ItemListNodeState(entries: settingsEntries(account: context.account, presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, notifyExceptions: preferencesAndExceptions.1, notificationsAuthorizationStatus: preferencesAndExceptions.2, notificationsWarningSuppressed: preferencesAndExceptions.3, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, privacySettings: preferencesAndExceptions.4, hasWallet: hasWallet, hasPassport: hasPassport, hasWatchApp: hasWatchApp, accountsAndPeers: accountsAndPeers.1, inAppNotificationSettings: inAppNotificationSettings, experimentalUISettings: experimentalUISettings, displayPhoneNumberConfirmation: preferencesAndExceptions.5), style: .blocks, searchItem: searchItem, initialScrollToItem: ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up)) return (controllerState, (listState, arguments)) } diff --git a/submodules/TelegramCore/TelegramCore/Wallets.swift b/submodules/TelegramCore/TelegramCore/Wallets.swift index d299929367..4a112da79f 100644 --- a/submodules/TelegramCore/TelegramCore/Wallets.swift +++ b/submodules/TelegramCore/TelegramCore/Wallets.swift @@ -69,10 +69,33 @@ public final class TonInstance { }) } - fileprivate func createWallet(keychain: TonKeychain, serverSalt: Data) -> Signal<(WalletInfo, [String]), NoError> { + fileprivate func exportKey(key: TONKey, serverSalt: Data) -> Signal<[String], NoError> { return Signal { subscriber in let disposable = MetaDisposable() + self.impl.with { impl in + impl.withInstance { ton in + let cancel = ton.export(key, localPassword: serverSalt).start(next: { wordList in + guard let wordList = wordList as? [String] else { + assertionFailure() + return + } + subscriber.putNext(wordList) + subscriber.putCompletion() + }) + disposable.set(ActionDisposable { + cancel?.dispose() + }) + } + } + + return disposable + } + } + + fileprivate func createWallet(keychain: TonKeychain, serverSalt: Data) -> Signal<(WalletInfo, [String]), NoError> { + return Signal { subscriber in + let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in let cancel = ton.createKey(withLocalPassword: serverSalt, mnemonicPassword: Data()).start(next: { key in @@ -85,13 +108,11 @@ public final class TonInstance { assertionFailure() return } - let cancel = ton.export(key, localPassword: serverSalt).start(next: { wordList in - guard let wordList = wordList as? [String] else { - assertionFailure() - return - } + let _ = self.exportKey(key: key, serverSalt: serverSalt).start(next: { wordList in subscriber.putNext((WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: EncryptedWalletSecret(rawValue: encryptedSecretData)), wordList)) subscriber.putCompletion() + }, error: { _ in + preconditionFailure() }) }, error: { _ in }, completed: { @@ -195,30 +216,20 @@ public final class TonInstance { } } - fileprivate func walletBalance(publicKey: WalletPublicKey) -> Signal { + fileprivate func getWalletState(address: String) -> Signal { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.getTestWalletAccountAddress(withPublicKey: publicKey.rawValue).start(next: { address in - guard let address = address as? String else { + let cancel = ton.getAccountState(withAddress: address).start(next: { state in + guard let state = state as? TONAccountState else { return } - let cancel = ton.getAccountState(withAddress: address).start(next: { state in - guard let state = state as? TONAccountState else { - return - } - subscriber.putNext(WalletBalance(rawValue: state.balance)) - }, error: { _ in - }, completed: { - subscriber.putCompletion() - }) - disposable.set(ActionDisposable { - cancel?.dispose() - }) + subscriber.putNext(WalletState(balance: state.balance, lastTransactionId: state.lastTransactionId.flatMap(WalletTransactionId.init(tonTransactionId:)))) }, error: { _ in }, completed: { + subscriber.putCompletion() }) disposable.set(ActionDisposable { cancel?.dispose() @@ -282,17 +293,39 @@ public final class TonInstance { } } - fileprivate func getGramsFromTestGiver(address: String, amount: Int64) -> Signal { + fileprivate func getTestGiverAccountState() -> Signal { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in let cancel = ton.getTestGiverAccountState().start(next: { state in - guard let state = state as? TONAccountState else { - subscriber.putError(.generic) - return - } + subscriber.putNext(state as? TONAccountState) + subscriber.putCompletion() + }, error: { _ in + subscriber.putNext(nil) + subscriber.putCompletion() + }, completed: { + }) + } + } + + return disposable + } + } + + fileprivate func getGramsFromTestGiver(address: String, amount: Int64) -> Signal { + return self.getTestGiverAccountState() + |> introduceError(GetGramsFromTestGiverError.self) + |> mapToSignal { state in + guard let state = state else { + return .fail(.generic) + } + return Signal { subscriber in + let disposable = MetaDisposable() + + self.impl.with { impl in + impl.withInstance { ton in let cancel = ton.testGiverSendGrams(with: state, accountAddress: address, amount: amount).start(next: { _ in }, error: { _ in subscriber.putError(.generic) @@ -302,17 +335,11 @@ public final class TonInstance { disposable.set(ActionDisposable { cancel?.dispose() }) - }, error: { _ in - subscriber.putError(.generic) - }, completed: { - }) - disposable.set(ActionDisposable { - cancel?.dispose() - }) + } } + + return disposable } - - return disposable } } @@ -368,7 +395,7 @@ public final class TonInstance { } } - fileprivate func sendGramsFromWallet(keychain: TonKeychain, serverSalt: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64) -> Signal { + fileprivate func sendGramsFromWallet(keychain: TonKeychain, serverSalt: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, textMessage: String) -> Signal { return keychain.decrypt(walletInfo.encryptedSecret.rawValue) |> introduceError(SendGramsFromWalletError.self) |> mapToSignal { decryptedSecret -> Signal in @@ -380,9 +407,9 @@ public final class TonInstance { self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.sendGrams(from: TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret), localPassword: serverSalt, fromAddress: fromAddress, toAddress: toAddress, amount: amount).start(next: { _ in + let cancel = ton.sendGrams(from: TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret), localPassword: serverSalt, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage).start(next: { _ in preconditionFailure() - }, error: { _ in + }, error: { error in subscriber.putError(.generic) }, completed: { subscriber.putCompletion() @@ -578,11 +605,13 @@ public func walletRestoreWords(network: Network, walletInfo: WalletInfo, tonInst } } -public struct WalletBalance: Hashable { - public var rawValue: Int64 +public struct WalletState: Equatable { + public let balance: Int64 + public let lastTransactionId: WalletTransactionId? - public init(rawValue: Int64) { - self.rawValue = rawValue + public init(balance: Int64, lastTransactionId: WalletTransactionId?) { + self.balance = balance + self.lastTransactionId = lastTransactionId } } @@ -594,8 +623,8 @@ public func testGiverWalletAddress(tonInstance: TonInstance) -> Signal Signal { - return tonInstance.walletBalance(publicKey: publicKey) +public func getWalletState(address: String, tonInstance: TonInstance) -> Signal { + return tonInstance.getWalletState(address: address) } public enum GetGramsFromTestGiverError { @@ -611,7 +640,7 @@ public enum SendGramsFromWalletError { case secretDecryptionFailed } -public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo, toAddress: String, amount: Int64) -> Signal { +public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo, toAddress: String, amount: Int64, textMessage: String) -> Signal { return getServerWalletSalt(network: network) |> mapError { _ -> SendGramsFromWalletError in return .generic @@ -620,7 +649,7 @@ public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keyc return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance) |> introduceError(SendGramsFromWalletError.self) |> mapToSignal { fromAddress in - return tonInstance.sendGramsFromWallet(keychain: keychain, serverSalt: serverSalt, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount) + return tonInstance.sendGramsFromWallet(keychain: keychain, serverSalt: serverSalt, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage) } } } @@ -655,11 +684,13 @@ public final class WalletTransactionMessage: Equatable { public let value: Int64 public let source: String public let destination: String + public let textMessage: String - init(value: Int64, source: String, destination: String) { + init(value: Int64, source: String, destination: String, textMessage: String) { self.value = value self.source = source self.destination = destination + self.textMessage = textMessage } public static func ==(lhs: WalletTransactionMessage, rhs: WalletTransactionMessage) -> Bool { @@ -670,7 +701,10 @@ public final class WalletTransactionMessage: Equatable { return false } if lhs.destination != rhs.destination { - return false; + return false + } + if lhs.textMessage != rhs.textMessage { + return false } return true } @@ -678,7 +712,7 @@ public final class WalletTransactionMessage: Equatable { private extension WalletTransactionMessage { convenience init(tonTransactionMessage: TONTransactionMessage) { - self.init(value: tonTransactionMessage.value, source: tonTransactionMessage.source, destination: tonTransactionMessage.destination) + self.init(value: tonTransactionMessage.value, source: tonTransactionMessage.source, destination: tonTransactionMessage.destination, textMessage: tonTransactionMessage.textMessage) } } diff --git a/submodules/TelegramUI/Images.xcassets/Wallet/CameraFlashIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Wallet/CameraFlashIcon.imageset/Contents.json new file mode 100644 index 0000000000..39f252e34f --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Wallet/CameraFlashIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_flash.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Wallet/CameraFlashIcon.imageset/ic_flash.pdf b/submodules/TelegramUI/Images.xcassets/Wallet/CameraFlashIcon.imageset/ic_flash.pdf new file mode 100644 index 0000000000..68f60cae43 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Wallet/CameraFlashIcon.imageset/ic_flash.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Wallet/QrIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Wallet/QrIcon.imageset/Contents.json new file mode 100644 index 0000000000..9bead22d1f --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Wallet/QrIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_qrcode.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Wallet/QrIcon.imageset/ic_qrcode.pdf b/submodules/TelegramUI/Images.xcassets/Wallet/QrIcon.imageset/ic_qrcode.pdf new file mode 100644 index 0000000000..cf234b8223 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Wallet/QrIcon.imageset/ic_qrcode.pdf differ diff --git a/submodules/TelegramUI/TelegramUI/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/TelegramUI/ChatInterfaceStateContextMenus.swift index f5188ec19f..908a150212 100644 --- a/submodules/TelegramUI/TelegramUI/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/TelegramUI/ChatInterfaceStateContextMenus.swift @@ -400,47 +400,55 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: if !messages[0].text.isEmpty || resourceAvailable { let message = messages[0] - actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) - }, action: { _, f in - if resourceAvailable { - for media in message.media { - if let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) { - let _ = (context.account.postbox.mediaBox.resourceData(largest.resource, option: .incremental(waitUntilFetchStatus: false)) - |> take(1) - |> deliverOnMainQueue).start(next: { data in - if data.complete, let imageData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) { - if let image = UIImage(data: imageData) { - if !message.text.isEmpty { - UIPasteboard.general.string = message.text - /*UIPasteboard.general.items = [ - [kUTTypeUTF8PlainText as String: message.text], - [kUTTypePNG as String: image] - ]*/ + var isExpired = false + for media in message.media { + if let _ = media as? TelegramMediaExpiredContent { + isExpired = true + } + } + if !isExpired { + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) + }, action: { _, f in + if resourceAvailable { + for media in message.media { + if let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) { + let _ = (context.account.postbox.mediaBox.resourceData(largest.resource, option: .incremental(waitUntilFetchStatus: false)) + |> take(1) + |> deliverOnMainQueue).start(next: { data in + if data.complete, let imageData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) { + if let image = UIImage(data: imageData) { + if !message.text.isEmpty { + UIPasteboard.general.string = message.text + /*UIPasteboard.general.items = [ + [kUTTypeUTF8PlainText as String: message.text], + [kUTTypePNG as String: image] + ]*/ + } else { + UIPasteboard.general.image = image + } } else { - UIPasteboard.general.image = image + UIPasteboard.general.string = message.text } } else { UIPasteboard.general.string = message.text } - } else { - UIPasteboard.general.string = message.text - } - }) + }) + } } - } - } else { - var messageEntities: [MessageTextEntity]? - for attribute in message.attributes { - if let attribute = attribute as? TextEntitiesMessageAttribute { - messageEntities = attribute.entities - break + } else { + var messageEntities: [MessageTextEntity]? + for attribute in message.attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + messageEntities = attribute.entities + break + } } + storeMessageTextInPasteboard(message.text, entities: messageEntities) } - storeMessageTextInPasteboard(message.text, entities: messageEntities) - } - f(.default) - }))) + f(.default) + }))) + } if resourceAvailable, !message.containsSecretMedia { var mediaReference: AnyMediaReference? for media in message.media { diff --git a/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift b/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift index a280fae0b8..ccd3d27004 100644 --- a/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift +++ b/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift @@ -328,6 +328,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { })) return true case let .other(otherMedia): + params.dismissInput() if let contact = otherMedia as? TelegramMediaContact { let _ = (params.context.account.postbox.transaction { transaction -> (Peer?, Bool?) in if let peerId = contact.peerId { diff --git a/submodules/TelegramUI/TelegramUI/OpenUrl.swift b/submodules/TelegramUI/TelegramUI/OpenUrl.swift index 43ed376890..03aaf8d49d 100644 --- a/submodules/TelegramUI/TelegramUI/OpenUrl.swift +++ b/submodules/TelegramUI/TelegramUI/OpenUrl.swift @@ -139,6 +139,10 @@ func formattedConfirmationCode(_ code: Int) -> String { } func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void) { + if url.hasPrefix("ton://") { + return + } + if forceExternal || url.lowercased().hasPrefix("tel:") || url.lowercased().hasPrefix("calshow:") { context.sharedContext.applicationBindings.openUrl(url) return diff --git a/submodules/TelegramUI/TelegramUI/PeerSelectionControllerNode.swift b/submodules/TelegramUI/TelegramUI/PeerSelectionControllerNode.swift index c9b216e987..b29f5fae37 100644 --- a/submodules/TelegramUI/TelegramUI/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerSelectionControllerNode.swift @@ -159,7 +159,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { var toolbarHeight: CGFloat = cleanInsets.bottom if let segmentedControlNode = self.segmentedControlNode, let toolbarBackgroundNode = self.toolbarBackgroundNode, let toolbarSeparatorNode = self.toolbarSeparatorNode { - toolbarHeight += 44 + toolbarHeight += 44.0 transition.updateFrame(node: toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight))) transition.updateFrame(node: toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel))) @@ -169,7 +169,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { var insets = layout.insets(options: [.input]) insets.top += navigationBarHeight - insets.bottom = max(insets.bottom, cleanInsets.bottom) + insets.bottom = max(insets.bottom, cleanInsets.bottom + 44.0) insets.left += layout.safeInsets.left insets.right += layout.safeInsets.right diff --git a/submodules/WalletUI/BUCK b/submodules/WalletUI/BUCK index e4ba0f4f53..b9422a5863 100644 --- a/submodules/WalletUI/BUCK +++ b/submodules/WalletUI/BUCK @@ -26,6 +26,7 @@ static_library( "//submodules/QrCode:QrCode", "//submodules/MergeLists:MergeLists", "//submodules/TelegramStringFormatting:TelegramStringFormatting", + "//submodules/GlassButtonNode:GlassButtonNode", ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", diff --git a/submodules/WalletUI/Sources/WalletConfiguration.swift b/submodules/WalletUI/Sources/WalletConfiguration.swift new file mode 100644 index 0000000000..5dc047a74b --- /dev/null +++ b/submodules/WalletUI/Sources/WalletConfiguration.swift @@ -0,0 +1,22 @@ +import Foundation +import TelegramCore + +public struct WalletConfiguration { + static var defaultValue: WalletConfiguration { + return WalletConfiguration(enabled: false) + } + + public let enabled: Bool + + fileprivate init(enabled: Bool) { + self.enabled = enabled + } + + public static func with(appConfiguration: AppConfiguration) -> WalletConfiguration { + if let data = appConfiguration.data, let enabled = data["wallet_enabled"] as? Bool { + return WalletConfiguration(enabled: enabled) + } else { + return .defaultValue + } + } +} diff --git a/submodules/WalletUI/Sources/WalletInfoScreen.swift b/submodules/WalletUI/Sources/WalletInfoScreen.swift index ebb092dcb5..b6698ec221 100644 --- a/submodules/WalletUI/Sources/WalletInfoScreen.swift +++ b/submodules/WalletUI/Sources/WalletInfoScreen.swift @@ -17,6 +17,7 @@ public final class WalletInfoScreen: ViewController { private let tonContext: TonContext private let walletInfo: WalletInfo private let address: String + private let walletState = Promise() private var presentationData: PresentationData @@ -44,6 +45,8 @@ public final class WalletInfoScreen: ViewController { self.scrollToTop = { [weak self] in (self?.displayNode as? WalletInfoScreenNode)?.scrollToTop() } + + self.walletState.set(Signal.single(nil) |> then(getWalletState(address: address, tonInstance: tonContext.instance) |> map(Optional.init))) } required init(coder aDecoder: NSCoder) { @@ -59,11 +62,18 @@ public final class WalletInfoScreen: ViewController { } override public func loadDisplayNode() { - self.displayNode = WalletInfoScreenNode(account: self.context.account, tonContext: self.tonContext, presentationData: self.presentationData, walletInfo: self.walletInfo, address: self.address, sendAction: { [weak self] in + self.displayNode = WalletInfoScreenNode(account: self.context.account, tonContext: self.tonContext, presentationData: self.presentationData, walletInfo: self.walletInfo, address: self.address, walletState: self.walletState.get(), sendAction: { [weak self] in guard let strongSelf = self else { return } - strongSelf.push(walletSendScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, walletInfo: strongSelf.walletInfo)) + let _ = (strongSelf.walletState.get() + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] walletState in + guard let strongSelf = self else { + return + } + strongSelf.push(walletSendScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, walletInfo: strongSelf.walletInfo, walletState: walletState)) + }) }, receiveAction: { [weak self] in guard let strongSelf = self else { return @@ -87,8 +97,8 @@ public final class WalletInfoScreen: ViewController { } private final class WalletInfoBalanceNode: ASDisplayNode { - private let balanceTextNode: ImmediateTextNode - private let balanceIconNode: ASImageNode + let balanceTextNode: ImmediateTextNode + let balanceIconNode: ASImageNode var balance: String = " " { didSet { @@ -96,6 +106,8 @@ private final class WalletInfoBalanceNode: ASDisplayNode { } } + var isLoading: Bool = true + init(theme: PresentationTheme) { self.balanceTextNode = ImmediateTextNode() self.balanceTextNode.displaysAsynchronously = false @@ -123,9 +135,14 @@ private final class WalletInfoBalanceNode: ASDisplayNode { let balanceOrigin = CGPoint(x: floor((width - balanceTextSize.width - balanceIconSpacing - balanceIconSize.width / 2.0) / 2.0), y: 0.0) let balanceTextFrame = CGRect(origin: balanceOrigin, size: balanceTextSize) - let balanceIconFrame = CGRect(origin: CGPoint(x: balanceTextFrame.maxX + balanceIconSpacing, y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize) + let balanceIconFrame: CGRect + if self.isLoading { + balanceIconFrame = CGRect(origin: CGPoint(x: floor((width - balanceIconSize.width) / 2.0), y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize) + } else { + balanceIconFrame = CGRect(origin: CGPoint(x: balanceTextFrame.maxX + balanceIconSpacing, y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize) + } transition.updateFrameAdditive(node: self.balanceTextNode, frame: balanceTextFrame) - transition.updateFrameAdditive(node: self.balanceIconNode, frame: balanceIconFrame) + transition.updateFrame(node: self.balanceIconNode, frame: balanceIconFrame) return balanceTextSize.height } @@ -245,10 +262,10 @@ private final class WalletInfoHeaderNode: ASDisplayNode { } } if self.balance == nil { - self.balanceNode.isHidden = true + self.balanceNode.balanceTextNode.isHidden = true self.balanceSubtitleNode.isHidden = true } else { - self.balanceNode.isHidden = false + self.balanceNode.balanceTextNode.isHidden = false self.balanceSubtitleNode.isHidden = false } transition.updateFrame(node: self.receiveButtonNode, frame: receiveButtonFrame) @@ -272,7 +289,8 @@ private final class WalletInfoHeaderNode: ASDisplayNode { func animateIn() { self.sendButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.receiveButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - self.balanceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + self.balanceNode.isLoading = false + self.balanceNode.balanceTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.balanceSubtitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } } @@ -348,6 +366,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { private var presentationData: PresentationData private let walletInfo: WalletInfo private let address: String + private let openTransaction: (WalletTransaction) -> Void private let headerNode: WalletInfoHeaderNode @@ -366,7 +385,9 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { private var currentEntries: [WalletInfoListEntry]? - init(account: Account, tonContext: TonContext, presentationData: PresentationData, walletInfo: WalletInfo, address: String, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void, openTransaction: @escaping (WalletTransaction) -> Void) { + private var isReady: Bool = false + + init(account: Account, tonContext: TonContext, presentationData: PresentationData, walletInfo: WalletInfo, address: String, walletState: Signal, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void, openTransaction: @escaping (WalletTransaction) -> Void) { self.account = account self.tonContext = tonContext self.presentationData = presentationData @@ -379,24 +400,29 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { self.listNode = ListView() self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor self.listNode.verticalScrollIndicatorFollowsOverscroll = true + self.listNode.isHidden = true super.init() self.backgroundColor = .white - self.balanceDisposable.set((currentWalletBalance(publicKey: walletInfo.publicKey, tonInstance: tonContext.instance) + self.balanceDisposable.set((walletState |> deliverOnMainQueue).start(next: { [weak self] value in - guard let strongSelf = self else { + guard let strongSelf = self, let value = value else { return } - let firstTime = strongSelf.headerNode.balance == nil - strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, value.rawValue), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) - strongSelf.headerNode.balance = max(0, value.rawValue) + + strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, value.balance), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) + strongSelf.headerNode.balance = max(0, value.balance) + if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate) } - if firstTime { - strongSelf.headerNode.animateIn() + + let wasReady = strongSelf.isReady + strongSelf.isReady = strongSelf.headerNode.balance != nil && strongSelf.currentEntries != nil + if strongSelf.isReady && !wasReady { + strongSelf.animateReadyIn() } })) @@ -412,7 +438,9 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { strongSelf.listOffset = offset - strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: offset, transition: listTransition) + if strongSelf.isReady { + strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: offset, transition: listTransition) + } } self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in @@ -448,6 +476,11 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { self.refreshTransactions() } + deinit { + self.balanceDisposable.dispose() + self.transactionListDisposable.dispose() + } + func scrollToHideHeader() { guard let (_, navigationHeight) = self.validLayout else { return @@ -466,11 +499,22 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { let headerHeight: CGFloat = navigationHeight + 260.0 let topInset: CGFloat = headerHeight - let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: headerHeight)) - transition.updateFrame(node: self.headerNode, frame: headerFrame) - self.headerNode.update(size: headerFrame.size, navigationHeight: navigationHeight, offset: self.listOffset ?? 0.0, transition: transition) + let visualHeaderHeight: CGFloat + let visualHeaderOffset: CGFloat + if !self.isReady { + visualHeaderHeight = layout.size.height + visualHeaderOffset = visualHeaderHeight + } else { + visualHeaderHeight = headerHeight + visualHeaderOffset = self.listOffset ?? 0.0 + } + let visualListOffset = visualHeaderHeight - headerHeight - transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: layout.size)) + let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: visualHeaderHeight)) + transition.updateFrame(node: self.headerNode, frame: headerFrame) + self.headerNode.update(size: headerFrame.size, navigationHeight: navigationHeight, offset: visualHeaderOffset, transition: transition) + + transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: visualListOffset), size: layout.size)) var duration: Double = 0.0 var curve: UInt = 0 @@ -601,8 +645,11 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { self.enqueuedTransactions.append(transaction) self.dequeueTransaction() - if isFirst { - self.listNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + let wasReady = self.isReady + self.isReady = self.headerNode.balance != nil && self.currentEntries != nil + + if self.isReady && !wasReady { + self.animateReadyIn() } } @@ -621,6 +668,14 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { self.listNode.transaction(deleteIndices: transaction.deletions, insertIndicesAndItems: transaction.insertions, updateIndicesAndItems: transaction.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in }) } + + private func animateReadyIn() { + self.listNode.isHidden = false + self.headerNode.animateIn() + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring)) + } + } } func formatBalanceText(_ value: Int64, decimalSeparator: String) -> String { diff --git a/submodules/WalletUI/Sources/WalletQrScanScreen.swift b/submodules/WalletUI/Sources/WalletQrScanScreen.swift index 54522f7c85..acab010687 100644 --- a/submodules/WalletUI/Sources/WalletQrScanScreen.swift +++ b/submodules/WalletUI/Sources/WalletQrScanScreen.swift @@ -5,26 +5,66 @@ import AccountContext import TelegramPresentationData import AsyncDisplayKit import Display -import Postbox +import SwiftSignalKit import TelegramCore -import AlertUI +import Camera +import GlassButtonNode + +private func generateFrameImage() -> UIImage? { + return generateImage(CGSize(width: 64.0, height: 64.0), contextGenerator: { size, context in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + context.setStrokeColor(UIColor.white.cgColor) + context.setLineWidth(4.0) + context.setLineCap(.round) + + var path = CGMutablePath(); + path.move(to: CGPoint(x: 2.0, y: 2.0 + 26.0)) + path.addArc(tangent1End: CGPoint(x: 2.0, y: 2.0), tangent2End: CGPoint(x: 2.0 + 26.0, y: 2.0), radius: 6.0) + path.addLine(to: CGPoint(x: 2.0 + 26.0, y: 2.0)) + context.addPath(path) + context.strokePath() + + path.move(to: CGPoint(x: size.width - 2.0, y: 2.0 + 26.0)) + path.addArc(tangent1End: CGPoint(x: size.width - 2.0, y: 2.0), tangent2End: CGPoint(x: 2.0 + 26.0, y: 2.0), radius: 6.0) + path.addLine(to: CGPoint(x: size.width - 2.0 - 26.0, y: 2.0)) + context.addPath(path) + context.strokePath() + + path.move(to: CGPoint(x: 2.0, y: size.height - 2.0 - 26.0)) + path.addArc(tangent1End: CGPoint(x: 2.0, y: size.height - 2.0), tangent2End: CGPoint(x: 2.0 + 26.0, y: size.height - 2.0), radius: 6.0) + path.addLine(to: CGPoint(x: 2.0 + 26.0, y: size.height - 2.0)) + context.addPath(path) + context.strokePath() + + path.move(to: CGPoint(x: size.width - 2.0, y: size.height - 2.0 - 26.0)) + path.addArc(tangent1End: CGPoint(x: size.width - 2.0, y: size.height - 2.0), tangent2End: CGPoint(x: 2.0 + 26.0, y: size.height - 2.0), radius: 6.0) + path.addLine(to: CGPoint(x: size.width - 2.0 - 26.0, y: size.height - 2.0)) + context.addPath(path) + context.strokePath() + })?.stretchableImage(withLeftCapWidth: 32, topCapHeight: 32) +} public final class WalletQrScanScreen: ViewController { private let context: AccountContext - private let tonContext: TonContext + private let completion: (String, Int64?, String?) -> Void private var presentationData: PresentationData - public init(context: AccountContext, tonContext: TonContext) { + private var disposable: Disposable? + + public init(context: AccountContext, completion: @escaping (String, Int64?, String?) -> Void) { self.context = context - self.tonContext = tonContext + self.completion = completion self.presentationData = context.sharedContext.currentPresentationData.with { $0 } let defaultNavigationPresentationData = NavigationBarPresentationData(presentationTheme: self.presentationData.theme, presentationStrings: self.presentationData.strings) - let navigationBarTheme = NavigationBarTheme(buttonColor: defaultNavigationPresentationData.theme.buttonColor, disabledButtonColor: defaultNavigationPresentationData.theme.disabledButtonColor, primaryTextColor: defaultNavigationPresentationData.theme.primaryTextColor, backgroundColor: .clear, separatorColor: .clear, badgeBackgroundColor: defaultNavigationPresentationData.theme.badgeBackgroundColor, badgeStrokeColor: defaultNavigationPresentationData.theme.badgeStrokeColor, badgeTextColor: defaultNavigationPresentationData.theme.badgeTextColor) + let navigationBarTheme = NavigationBarTheme(buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear) super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: defaultNavigationPresentationData.strings)) + self.statusBar.statusBarStyle = .White + self.navigationPresentation = .modalInLargeLayout self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) self.navigationBar?.intrinsicCanTransitionInline = false @@ -36,6 +76,10 @@ public final class WalletQrScanScreen: ViewController { fatalError("init(coder:) has not been implemented") } + deinit { + self.disposable?.dispose() + } + @objc private func backPressed() { self.dismiss() } @@ -44,6 +88,27 @@ public final class WalletQrScanScreen: ViewController { self.displayNode = WalletQrScanScreenNode(presentationData: self.presentationData) self.displayNodeDidLoad() + +// (self.displayNode as! WalletQrScanScreenNode).focusedCode.get() +// |> map { code -> String? in +// return code?.message +// } |> distinctUntilChanged + + self.disposable = (((self.displayNode as! WalletQrScanScreenNode).focusedCode.get() + |> map { code -> String? in + return code?.message + } + |> distinctUntilChanged + |> delay(2.5, queue: Queue.mainQueue())) + |> mapToSignal { code -> Signal in + return .single(code) + }).start(next: { [weak self] code in + guard let strongSelf = self, let code = code else { + return + } + let cleanString = code.replacingOccurrences(of: "ton://", with: "") + strongSelf.completion(cleanString, nil, nil) + }) } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { @@ -55,59 +120,168 @@ public final class WalletQrScanScreen: ViewController { private final class WalletQrScanScreenNode: ViewControllerTracingNode, UIScrollViewDelegate { private var presentationData: PresentationData - + + private let previewNode: CameraPreviewNode + private let fadeNode: ASDisplayNode + private let topDimNode: ASDisplayNode + private let bottomDimNode: ASDisplayNode + private let leftDimNode: ASDisplayNode + private let rightDimNode: ASDisplayNode + private let frameNode: ASImageNode + private let torchButtonNode: GlassButtonNode private let titleNode: ImmediateTextNode - private let textNode: ImmediateTextNode - private var navigationHeight: CGFloat? + private let camera: Camera + private let codeDisposable = MetaDisposable() + + fileprivate let focusedCode = ValuePromise(ignoreRepeated: true) + private var focusedRect: CGRect? + + private var validLayout: (ContainerViewLayout, CGFloat)? init(presentationData: PresentationData) { self.presentationData = presentationData - - let title: String = "" - let text: String = "" + self.previewNode = CameraPreviewNode() + self.previewNode.backgroundColor = .black + + self.fadeNode = ASDisplayNode() + self.fadeNode.alpha = 0.0 + self.fadeNode.backgroundColor = .black + + self.topDimNode = ASDisplayNode() + self.topDimNode.alpha = 0.625 + self.topDimNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.8) + + self.bottomDimNode = ASDisplayNode() + self.bottomDimNode.alpha = 0.625 + self.bottomDimNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.8) + + self.leftDimNode = ASDisplayNode() + self.leftDimNode.alpha = 0.625 + self.leftDimNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.8) + + self.rightDimNode = ASDisplayNode() + self.rightDimNode.alpha = 0.625 + self.rightDimNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.8) + + self.frameNode = ASImageNode() + self.frameNode.image = generateFrameImage() + + self.torchButtonNode = GlassButtonNode(icon: UIImage(bundleImageName: "Wallet/CameraFlashIcon")!, label: nil) self.titleNode = ImmediateTextNode() self.titleNode.displaysAsynchronously = false - self.titleNode.attributedText = NSAttributedString(string: title, font: Font.bold(32.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: "Scan QR Code", font: Font.bold(32.0), textColor: .white) self.titleNode.maximumNumberOfLines = 0 self.titleNode.textAlignment = .center - self.textNode = ImmediateTextNode() - self.textNode.displaysAsynchronously = false - self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(16.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor) - self.textNode.maximumNumberOfLines = 0 - self.textNode.lineSpacing = 0.1 - self.textNode.textAlignment = .center + self.camera = Camera(configuration: .init(preset: .hd1920x1080, position: .back, audio: false)) super.init() self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor + self.addSubnode(self.previewNode) + self.addSubnode(self.fadeNode) + self.addSubnode(self.topDimNode) + self.addSubnode(self.bottomDimNode) + self.addSubnode(self.leftDimNode) + self.addSubnode(self.rightDimNode) + self.addSubnode(self.frameNode) + self.addSubnode(self.torchButtonNode) self.addSubnode(self.titleNode) - self.addSubnode(self.textNode) + + self.torchButtonNode.addTarget(self, action: #selector(self.torchPressed), forControlEvents: .touchUpInside) + } + + deinit { + self.codeDisposable.dispose() + } + + override func didLoad() { + super.didLoad() + + self.camera.attachPreviewNode(self.previewNode) + self.camera.startCapture() + + let throttledSignal = self.camera.detectedCodes + |> mapToThrottled { next -> Signal<[CameraCode], NoError> in + return .single(next) |> then(.complete() |> delay(0.3, queue: Queue.concurrentDefaultQueue())) + } + + self.codeDisposable.set((throttledSignal + |> deliverOnMainQueue).start(next: { [weak self] codes in + guard let strongSelf = self else { + return + } + let filteredCodes = codes.filter { $0.message.hasPrefix("ton://") } + if let code = filteredCodes.first, CGRect(x: 0.3, y: 0.3, width: 0.4, height: 0.4).contains(code.boundingBox.center) { + strongSelf.focusedCode.set(code) + strongSelf.updateFocusedRect(code.boundingBox) + } else { + strongSelf.focusedCode.set(nil) + strongSelf.updateFocusedRect(nil) + } + })) + } + + private func updateFocusedRect(_ rect: CGRect?) { + self.focusedRect = rect + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring)) + } } func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) { - self.navigationHeight = navigationHeight + self.validLayout = (layout, navigationHeight) - let sideInset: CGFloat = 32.0 - let titleSpacing: CGFloat = 19.0 - let textSpacing: CGFloat = 37.0 + let sideInset: CGFloat = 66.0 + let titleSpacing: CGFloat = 48.0 + + let bounds = CGRect(origin: CGPoint(), size: layout.size) + + transition.updateFrame(node: self.previewNode, frame: bounds) + transition.updateFrame(node: self.fadeNode, frame: bounds) + + let frameSide = max(240.0, layout.size.width - sideInset * 2.0) + let dimHeight = ceil((layout.size.height - frameSide) / 2.0) + let dimInset = (layout.size.width - frameSide) / 2.0 + + let dimAlpha: CGFloat + let dimRect: CGRect + if let focusedRect = self.focusedRect { + dimAlpha = 1.0 + let side = max(bounds.width * focusedRect.width, bounds.height * focusedRect.height) * 0.6 + let center = CGPoint(x: (1.0 - focusedRect.center.y) * bounds.width, y: focusedRect.center.x * bounds.height) + dimRect = CGRect(x: center.x - side / 2.0, y: center.y - side / 2.0, width: side, height: side) + } else { + dimAlpha = 0.625 + dimRect = CGRect(x: dimInset, y: dimHeight, width: layout.size.width - dimInset * 2.0, height: layout.size.height - dimHeight * 2.0) + } + + transition.updateFrame(node: self.topDimNode, frame: CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: dimRect.minY)) + transition.updateFrame(node: self.bottomDimNode, frame: CGRect(x: 0.0, y: dimRect.maxY, width: layout.size.width, height: max(0.0, layout.size.height - dimRect.maxY))) + transition.updateFrame(node: self.leftDimNode, frame: CGRect(x: 0.0, y: dimRect.minY, width: max(0.0, dimRect.minX), height: dimRect.height)) + transition.updateFrame(node: self.rightDimNode, frame: CGRect(x: dimRect.maxX, y: dimRect.minY, width: max(0.0, layout.size.width - dimRect.maxX), height: dimRect.height)) + + transition.updateAlpha(node: self.topDimNode, alpha: dimAlpha) + transition.updateAlpha(node: self.bottomDimNode, alpha: dimAlpha) + transition.updateAlpha(node: self.leftDimNode, alpha: dimAlpha) + transition.updateAlpha(node: self.rightDimNode, alpha: dimAlpha) + + transition.updateFrame(node: self.frameNode, frame: dimRect.insetBy(dx: -2.0, dy: -2.0)) + + let torchButtonSize = CGSize(width: 72.0, height: 72.0) + transition.updateFrame(node: self.torchButtonNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - torchButtonSize.width) / 2.0), y: dimHeight + frameSide + 50.0), size: torchButtonSize)) let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height)) - let textSize = self.textNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height)) - - var contentHeight: CGFloat = 0.0 - - let contentVerticalOrigin = navigationHeight + 10.0 - - let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: contentVerticalOrigin), size: titleSize) + let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: dimHeight - titleSize.height - titleSpacing), size: titleSize) transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame) - let textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize) - transition.updateFrameAdditive(node: self.textNode, frame: textFrame) - - contentHeight = textFrame.maxY + textSpacing + } + + @objc private func torchPressed() { + self.torchButtonNode.isSelected = !self.torchButtonNode.isSelected + self.camera.setTorchActive(self.torchButtonNode.isSelected) } } diff --git a/submodules/WalletUI/Sources/WalletReceiveScreen.swift b/submodules/WalletUI/Sources/WalletReceiveScreen.swift index 1c2ceb6b88..cb93773439 100644 --- a/submodules/WalletUI/Sources/WalletReceiveScreen.swift +++ b/submodules/WalletUI/Sources/WalletReceiveScreen.swift @@ -131,9 +131,9 @@ private func walletReceiveScreenEntries(presentationData: PresentationData, addr var entries: [WalletReceiveScreenEntry] = [] entries.append(.addressHeader(presentationData.theme, "YOUR WALLET ADDRESS")) - let address = String(address[address.startIndex.. WalletSendScreenState) -> Void let selectNextInputItem: (WalletSendScreenEntryTag) -> Void + let openQrScanner: () -> Void let proceed: () -> Void - init(context: AccountContext, updateState: @escaping ((WalletSendScreenState) -> WalletSendScreenState) -> Void, selectNextInputItem: @escaping (WalletSendScreenEntryTag) -> Void, proceed: @escaping () -> Void) { + init(context: AccountContext, updateState: @escaping ((WalletSendScreenState) -> WalletSendScreenState) -> Void, selectNextInputItem: @escaping (WalletSendScreenEntryTag) -> Void, openQrScanner: @escaping () -> Void, proceed: @escaping () -> Void) { self.context = context self.updateState = updateState self.selectNextInputItem = selectNextInputItem + self.openQrScanner = openQrScanner self.proceed = proceed } } @@ -93,8 +96,8 @@ private func isValidAmount(_ amount: String) -> Bool { } private func formatAmountText(_ amount: Int64, decimalSeparator: String = ".") -> String { - if amount < 10000000000 { - return "0\(decimalSeparator)\(String(amount).rightJustified(width: 10, pad: "0"))" + if amount < 1000000000 { + return "0\(decimalSeparator)\(String(amount).rightJustified(width: 9, pad: "0"))" } else { var string = String(amount) string.insert(contentsOf: decimalSeparator, at: string.index(string.endIndex, offsetBy: -9)) @@ -103,7 +106,7 @@ private func formatAmountText(_ amount: Int64, decimalSeparator: String = ".") - } private func amountValue(_ string: String) -> Int64 { - return Int64((Double(string) ?? 0.0) * 1000.0) + return Int64((Double(string.replacingOccurrences(of: ",", with: ".")) ?? 0.0) * 1000000000.0) } private func normalizedStringForGramsString(_ string: String, decimalSeparator: String = ".") -> String { @@ -115,7 +118,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry { case address(PresentationTheme, String, String) case addressInfo(PresentationTheme, String) - case amountHeader(PresentationTheme, String, String, Bool) + case amountHeader(PresentationTheme, String, String?, Bool) case amount(PresentationTheme, PresentationStrings, String, String) case commentHeader(PresentationTheme, String) @@ -207,21 +210,23 @@ private enum WalletSendScreenEntry: ItemListNodeEntry { case let .addressHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) case let .address(theme, placeholder, address): - return ItemListMultilineInputItem(theme: theme, text: address, placeholder: "Enter wallet address...", maxLength: .init(value: walletAddressLength, display: false), sectionId: self.section, style: .blocks, capitalization: false, autocorrection: false, returnKeyType: .next, minimalHeight: 68.0, textUpdated: { address in + return ItemListMultilineInputItem(theme: theme, text: address, placeholder: placeholder, maxLength: .init(value: walletAddressLength, display: false), sectionId: self.section, style: .blocks, capitalization: false, autocorrection: false, returnKeyType: .next, minimalHeight: 68.0, textUpdated: { address in arguments.updateState { state in var state = state - state.address = address + state.address = address.replacingOccurrences(of: "\n", with: "") return state } }, shouldUpdateText: { text in return isValidAddress(text) }, tag: WalletSendScreenEntryTag.address, action: { arguments.selectNextInputItem(WalletSendScreenEntryTag.address) - }) + }, inlineAction: ItemListMultilineInputInlineAction(icon: UIImage(bundleImageName: "Wallet/QrIcon")!, action: { + arguments.openQrScanner() + })) case let .addressInfo(theme, text): return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section) case let .amountHeader(theme, text, balance, insufficient): - return ItemListSectionHeaderItem(theme: theme, text: text, accessoryText: ItemListSectionHeaderAccessoryText(value: balance, color: insufficient ? .destructive : .generic), sectionId: self.section) + return ItemListSectionHeaderItem(theme: theme, text: text, activityIndicator: balance == nil ? .right : .none, accessoryText: balance.flatMap { ItemListSectionHeaderAccessoryText(value: $0, color: insufficient ? .destructive : .generic, icon: balanceIcon) }, sectionId: self.section) case let .amount(theme, strings, placeholder, text): return ItemListSingleLineInputItem(theme: theme, strings: strings, title: NSAttributedString(string: ""), text: text, placeholder: placeholder, type: .decimal, returnKeyType: .next, tag: WalletSendScreenEntryTag.amount, sectionId: self.section, textUpdated: { text in arguments.updateState { state in @@ -271,16 +276,18 @@ private struct WalletSendScreenState: Equatable { var address: String var amount: String var comment: String + var qrScanAvailable: Bool } private func walletSendScreenEntries(presentationData: PresentationData, balance: Int64?, state: WalletSendScreenState) -> [WalletSendScreenEntry] { var entries: [WalletSendScreenEntry] = [] + entries.append(.addressHeader(presentationData.theme, "RECIPIENT WALLET ADDRESS")) entries.append(.address(presentationData.theme, "Enter wallet address...", state.address)) entries.append(.addressInfo(presentationData.theme, "Copy the 48-letter address of the recipient here or ask them to send you a ton:// link.")) let amount = amountValue(state.amount) - entries.append(.amountHeader(presentationData.theme, "AMOUNT", "BALANCE: \(formatBalanceText(balance ?? 0, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))💎", amount > 0 && (balance ?? 0) < amount)) + entries.append(.amountHeader(presentationData.theme, "AMOUNT", balance.flatMap { "BALANCE: \(formatBalanceText($0, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))" }, amount > 0 && (balance ?? 0) < amount)) entries.append(.amount(presentationData.theme, presentationData.strings, "Grams to send", state.amount ?? "")) entries.append(.commentHeader(presentationData.theme, "COMMENT")) @@ -296,9 +303,9 @@ private final class WalletSendScreenImpl: ItemListController ViewController { +func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInfo: WalletInfo, walletState: WalletState? = nil, address: String? = nil, amount: Int64? = nil) -> ViewController { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let initialState = WalletSendScreenState(address: address ?? "", amount: amount.flatMap { formatAmountText($0, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) } ?? "", comment: "") + let initialState = WalletSendScreenState(address: address ?? "", amount: amount.flatMap { formatAmountText($0, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) } ?? "", comment: "", qrScanAvailable: address == nil) let statePromise = ValuePromise(initialState, ignoreRepeated: true) let stateValue = Atomic(value: initialState) @@ -309,13 +316,41 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf var presentControllerImpl: ((ViewController, Any?) -> Void)? var presentInGlobalOverlayImpl: ((ViewController, Any?) -> Void)? var pushImpl: ((ViewController) -> Void)? + var popImpl: (() -> Void)? var dismissImpl: (() -> Void)? + var dismissInputImpl: (() -> Void)? var selectNextInputItemImpl: ((WalletSendScreenEntryTag) -> Void)? let arguments = WalletSendScreenArguments(context: context, updateState: { f in updateState(f) }, selectNextInputItem: { tag in selectNextInputItemImpl?(tag) + }, openQrScanner: { + dismissInputImpl?() + pushImpl?(WalletQrScanScreen(context: context, completion: { address, amount, comment in + var updatedState: WalletSendScreenState? + updateState { state in + var state = state + state.address = address + if let amount = amount { + state.amount = formatAmountText(amount, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) + } + if let comment = comment { + state.comment = comment + } + state.qrScanAvailable = false + updatedState = state + return state + } + popImpl?() + if let updatedState = updatedState { + if updatedState.amount.isEmpty { + selectNextInputItemImpl?(WalletSendScreenEntryTag.address) + } else if updatedState.comment.isEmpty { + selectNextInputItemImpl?(WalletSendScreenEntryTag.amount) + } + } + })) }, proceed: { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let state = stateValue.with { $0 } @@ -331,7 +366,7 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf let address = state.address[state.address.startIndex.. = Signal.single(WalletBalance(rawValue: 2500)) - + let balance: Signal = .single(walletState) + |> then(walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonContext.instance) + |> mapToSignal { address in + return getWalletState(address: address, tonInstance: tonContext.instance) + |> map(Optional.init) + }) + var focusItemTag: ItemListItemTag? if address == nil { focusItemTag = WalletSendScreenEntryTag.address @@ -373,14 +413,14 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf let amount = amountValue(state.amount) var sendEnabled = false if let balance = balance { - sendEnabled = isValidAddress(state.address, exactLength: true) && amount > 0 && amount <= balance.rawValue + sendEnabled = isValidAddress(state.address, exactLength: true) && amount > 0 && amount <= balance.balance } let rightNavigationButton = ItemListNavigationButton(content: .text("Send"), style: .bold, enabled: sendEnabled, action: { arguments.proceed() }) let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text("Send Grams"), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) - let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: balance?.rawValue, state: state), style: .blocks, focusItemTag: focusItemTag, animateChanges: false) + let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: balance?.balance, state: state), style: .blocks, focusItemTag: focusItemTag, animateChanges: false) return (controllerState, (listState, arguments)) } @@ -396,10 +436,16 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf pushImpl = { [weak controller] c in controller?.push(c) } + popImpl = { [weak controller] in + (controller?.navigationController as? NavigationController)?.popViewController(animated: true) + } dismissImpl = { [weak controller] in controller?.view.endEditing(true) let _ = controller?.dismiss() } + dismissInputImpl = { [weak controller] in + controller?.view.endEditing(true) + } selectNextInputItemImpl = { [weak controller] currentTag in guard let controller = controller else { return diff --git a/submodules/WalletUI/Sources/WalletSplashScreen.swift b/submodules/WalletUI/Sources/WalletSplashScreen.swift index 3e79e1c96a..d2239588ae 100644 --- a/submodules/WalletUI/Sources/WalletSplashScreen.swift +++ b/submodules/WalletUI/Sources/WalletSplashScreen.swift @@ -13,6 +13,7 @@ import SwiftSignalKit import OverlayStatusController import ItemListUI import AlertUI +import TextFormat public enum WalletSplashMode { case intro @@ -49,10 +50,10 @@ public final class WalletSplashScreen: ViewController { case .intro: self.navigationItem.setLeftBarButton(UIBarButtonItem(title: "Not Now", style: .plain, target: self, action: #selector(self.backPressed)), animated: false) self.navigationItem.setRightBarButton(UIBarButtonItem(title: "Import existing wallet", style: .plain, target: self, action: #selector(self.importPressed)), animated: false) - case let .sending(walletInfo, address, amount, comment): + case let .sending(walletInfo, address, amount, textMessage): self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false) - let _ = (sendGramsFromWallet(network: self.context.account.network, tonInstance: self.tonContext.instance, keychain: self.tonContext.keychain, walletInfo: walletInfo, toAddress: address, amount: amount) + let _ = (sendGramsFromWallet(network: self.context.account.network, tonInstance: self.tonContext.instance, keychain: self.tonContext.keychain, walletInfo: walletInfo, toAddress: address, amount: amount, textMessage: textMessage) |> deliverOnMainQueue).start(error: { [weak self] error in guard let strongSelf = self else { return @@ -223,29 +224,32 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode { self.animationNode = AnimatedStickerNode() let title: String - let text: String + let text: NSAttributedString let buttonText: String let termsText: String let secondaryActionText: String - + + let textFont = Font.regular(16.0) + let textColor = self.presentationData.theme.list.itemPrimaryTextColor + switch mode { case .intro: title = "Gram Wallet" - text = "Gram wallet allows you to make fast and secure blockchain-based payments without intermediaries." + text = NSAttributedString(string: "Gram wallet allows you to make fast and secure blockchain-based payments without intermediaries.", font: textFont, textColor: textColor) buttonText = "Create My Wallet" termsText = "By creating the wallet you accept\nTerms of Conditions." self.iconNode.image = UIImage(bundleImageName: "Settings/Wallet/IntroIcon") secondaryActionText = "" case .created: title = "Congratulations" - text = "Your Gram wallet has just been created. Only you control it.\n\nTo be able to always have access to it, please write down secret words and\nset up a secure passcode." + text = NSAttributedString(string: "Your Gram wallet has just been created. Only you control it.\n\nTo be able to always have access to it, please write down secret words and\nset up a secure passcode.", font: textFont, textColor: textColor) buttonText = "Proceed" termsText = "" self.iconNode.image = UIImage(bundleImageName: "Settings/Wallet/CreatedIcon") secondaryActionText = "" case .success: title = "Ready to go!" - text = "You’re all set. Now you have a wallet that only you control - directly, without middlemen or bankers. " + text = NSAttributedString(string: "You’re all set. Now you have a wallet that only you control - directly, without middlemen or bankers. ", font: textFont, textColor: textColor) buttonText = "View My Wallet" termsText = "" self.iconNode.image = nil @@ -256,7 +260,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode { secondaryActionText = "" case .restoreFailed: title = "Too Bad" - text = "Without the secret words, you can't'nrestore access to the wallet." + text = NSAttributedString(string: "Without the secret words, you can't'nrestore access to the wallet.", font: textFont, textColor: textColor) buttonText = "Create a New Wallet" termsText = "" self.iconNode.image = nil @@ -267,14 +271,16 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode { secondaryActionText = "Enter 24 words" case .sending: title = "Sending Grams" - text = "Please wait a few seconds for your transaction to be processed..." + text = NSAttributedString(string: "Please wait a few seconds for your transaction to be processed...", font: textFont, textColor: textColor) buttonText = "" termsText = "" self.iconNode.image = UIImage(bundleImageName: "Settings/Wallet/SendingIcon") secondaryActionText = "" case let .sent(_, amount): title = "Done!" - text = "\(amount) Grams have been sent." + let bodyAttributes = MarkdownAttributeSet(font: textFont, textColor: textColor) + let boldAttributes = MarkdownAttributeSet(font: Font.semibold(16.0), textColor: textColor) + text = parseMarkdownIntoAttributedString("**\(formatBalanceText(amount, decimalSeparator: self.presentationData.dateTimeFormat.decimalSeparator)) Grams** have been sent.", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }), textAlignment: .center) buttonText = "View My Wallet" termsText = "" self.iconNode.image = nil @@ -293,7 +299,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode { self.textNode = ImmediateTextNode() self.textNode.displaysAsynchronously = false - self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(16.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor) + self.textNode.attributedText = text self.textNode.maximumNumberOfLines = 0 self.textNode.lineSpacing = 0.1 self.textNode.textAlignment = .center diff --git a/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift b/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift index 65300e0fbc..15689dc300 100644 --- a/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift +++ b/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift @@ -142,7 +142,7 @@ private func walletTransactionInfoControllerEntries(presentationData: Presentati } entries.append(.infoAddress(presentationData.theme, text)) if case .list = address { - entries.append(.infoCopyAddress(presentationData.theme, "Copy Address")) + entries.append(.infoCopyAddress(presentationData.theme, "Copy Wallet Address")) entries.append(.infoSendGrams(presentationData.theme, "Send Grams")) } @@ -170,6 +170,7 @@ func walletTransactionInfoController(context: AccountContext, tonContext: TonCon }, sendGrams: { let address = extractAddress(walletTransaction) if case let .list(addresses) = address, let address = addresses.first { + dismissImpl?() pushImpl?(walletSendScreen(context: context, tonContext: tonContext, walletInfo: walletInfo, address: address)) } }) diff --git a/submodules/WalletUI/WalletUI.xcodeproj/project.pbxproj b/submodules/WalletUI/WalletUI.xcodeproj/project.pbxproj index 0bc91d1cfb..66750110b2 100644 --- a/submodules/WalletUI/WalletUI.xcodeproj/project.pbxproj +++ b/submodules/WalletUI/WalletUI.xcodeproj/project.pbxproj @@ -247,6 +247,19 @@ explicitFileType compiled.mach-o.dylib + 1DD70E29BCD8FADE00000000 + + isa + PBXFileReference + name + libGlassButtonNode.a + path + libGlassButtonNode.a + sourceTree + BUILT_PRODUCTS_DIR + explicitFileType + archive.ar + 1DD70E2971ED41B100000000 isa @@ -751,6 +764,7 @@ 1DD70E292417E0B200000000 1DD70E295915423000000000 1DD70E29FF334B1F00000000 + 1DD70E29BCD8FADE00000000 1DD70E2971ED41B100000000 1DD70E29D6F14E1000000000 1DD70E295A26607D00000000 @@ -829,6 +843,17 @@ explicitFileType text.script.python + 1DD70E292CCF064200000000 + + isa + PBXFileReference + name + WalletConfiguration.swift + path + Sources/WalletConfiguration.swift + sourceTree + SOURCE_ROOT + 1DD70E298B98CCED00000000 isa @@ -982,6 +1007,7 @@ ]]> children + 1DD70E292CCF064200000000 1DD70E298B98CCED00000000 1DD70E29D2B1401800000000 1DD70E2900657ECF00000000 @@ -1027,6 +1053,13 @@ B401C979172FA86D00000000 + E7A30F042CCF064200000000 + + isa + PBXBuildFile + fileRef + 1DD70E292CCF064200000000 + E7A30F048B98CCED00000000 isa @@ -1124,6 +1157,7 @@ PBXSourcesBuildPhase files + E7A30F042CCF064200000000 E7A30F048B98CCED00000000 E7A30F04D2B1401800000000 E7A30F0400657ECF00000000 @@ -1265,6 +1299,13 @@ fileRef 1DD70E29BFBD457D00000000 + E7A30F04BCD8FADE00000000 + + isa + PBXBuildFile + fileRef + 1DD70E29BCD8FADE00000000 + E7A30F04D6F14E1000000000 isa @@ -1513,6 +1554,7 @@ E7A30F049D2580DA00000000 E7A30F04F523B9DE00000000 E7A30F04BFBD457D00000000 + E7A30F04BCD8FADE00000000 E7A30F04D6F14E1000000000 E7A30F04CD296A8300000000 E7A30F043594DCC000000000 diff --git a/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp b/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp index efc71e6f27..d7a39d417e 100644 --- a/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp +++ b/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp @@ -176,6 +176,113 @@ td::Status AdnlOutboundConnection::process_packet(td::BufferSlice data) { return td::Status::OK(); } +void AdnlExtMultiClientImpl::start_up() { + for (auto &id : ids_) { + add_server(id.first, id.second, [](td::Result R) {}); + } + ids_.clear(); +} + +void AdnlExtMultiClientImpl::add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise promise) { + for (auto &c : clients_) { + if (c.second->addr == dst_addr) { + promise.set_error(td::Status::Error(ErrorCode::error, "duplicate ip")); + return; + } + } + + auto g = ++generation_; + auto cli = std::make_unique(AdnlExtClient::create(dst, dst_addr, make_callback(g)), dst, dst_addr, g); + clients_[g] = std::move(cli); +} + +void AdnlExtMultiClientImpl::del_server(td::IPAddress dst_addr, td::Promise promise) { + for (auto &c : clients_) { + if (c.second->addr == dst_addr) { + if (c.second->ready) { + total_ready_--; + if (!total_ready_) { + callback_->on_stop_ready(); + } + } + clients_.erase(c.first); + promise.set_value(td::Unit()); + return; + } + } + promise.set_error(td::Status::Error(ErrorCode::error, "ip not found")); +} + +void AdnlExtMultiClientImpl::send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, + td::Promise promise) { + if (total_ready_ == 0) { + promise.set_error(td::Status::Error(ErrorCode::notready, "conn not ready")); + return; + } + + std::vector vec; + for (auto &c : clients_) { + if (c.second->ready) { + vec.push_back(c.first); + } + } + CHECK(vec.size() == total_ready_); + + auto &c = clients_[vec[td::Random::fast(0, td::narrow_cast(vec.size() - 1))]]; + + td::actor::send_closure(c->client, &AdnlExtClient::send_query, std::move(name), std::move(data), timeout, + std::move(promise)); +} + +void AdnlExtMultiClientImpl::client_ready(td::uint32 idx, bool value) { + auto it = clients_.find(idx); + if (it == clients_.end()) { + return; + } + auto &c = it->second; + if (c->ready == value) { + return; + } + c->ready = value; + if (value) { + total_ready_++; + if (total_ready_ == 1) { + callback_->on_ready(); + } + } else { + total_ready_--; + if (total_ready_ == 0) { + callback_->on_stop_ready(); + } + } +} + +std::unique_ptr AdnlExtMultiClientImpl::make_callback(td::uint32 g) { + class Cb : public Callback { + public: + Cb(td::actor::ActorId id, td::uint32 idx) : id_(id), idx_(idx) { + } + + void on_ready() override { + td::actor::send_closure(id_, &AdnlExtMultiClientImpl::client_ready, idx_, true); + } + + void on_stop_ready() override { + td::actor::send_closure(id_, &AdnlExtMultiClientImpl::client_ready, idx_, false); + } + + private: + td::actor::ActorId id_; + td::uint32 idx_; + }; + return std::make_unique(actor_id(this), g); +} + +td::actor::ActorOwn AdnlExtMultiClient::create( + std::vector> ids, std::unique_ptr callback) { + return td::actor::create_actor("extmulticlient", std::move(ids), std::move(callback)); +} + } // namespace adnl } // namespace ton diff --git a/submodules/ton/tonlib-src/adnl/adnl-ext-client.h b/submodules/ton/tonlib-src/adnl/adnl-ext-client.h index babccced5e..bd60f202d6 100644 --- a/submodules/ton/tonlib-src/adnl/adnl-ext-client.h +++ b/submodules/ton/tonlib-src/adnl/adnl-ext-client.h @@ -43,6 +43,14 @@ class AdnlExtClient : public td::actor::Actor { std::unique_ptr callback); }; +class AdnlExtMultiClient : public AdnlExtClient { + public: + virtual void add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise promise) = 0; + virtual void del_server(td::IPAddress dst_addr, td::Promise promise) = 0; + static td::actor::ActorOwn create(std::vector> ids, + std::unique_ptr callback); +}; + } // namespace adnl } // namespace ton diff --git a/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp b/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp index 95348135ca..d58247fcc4 100644 --- a/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp +++ b/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp @@ -140,6 +140,52 @@ class AdnlExtClientImpl : public AdnlExtClient { void try_stop(); }; +class AdnlExtMultiClientImpl : public AdnlExtMultiClient { + public: + AdnlExtMultiClientImpl(std::vector> ids, + std::unique_ptr callback) + : ids_(std::move(ids)), callback_(std::move(callback)) { + } + + void start_up() override; + + void add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise promise) override; + void del_server(td::IPAddress dst_addr, td::Promise promise) override; + + void check_ready(td::Promise promise) override { + if (total_ready_ > 0) { + promise.set_value(td::Unit()); + } else { + promise.set_error(td::Status::Error(ErrorCode::notready, "conn not ready")); + } + } + void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, + td::Promise promise) override; + + void client_ready(td::uint32 idx, bool value); + + private: + std::unique_ptr make_callback(td::uint32 g); + + struct Client { + Client(td::actor::ActorOwn client, AdnlNodeIdFull pubkey, td::IPAddress addr, td::uint32 generation) + : client(std::move(client)), pubkey(std::move(pubkey)), addr(addr), generation(generation), ready(false) { + } + td::actor::ActorOwn client; + AdnlNodeIdFull pubkey; + td::IPAddress addr; + td::uint32 generation; + bool ready = false; + }; + td::uint32 total_ready_ = 0; + + td::uint32 generation_ = 0; + std::map> clients_; + + std::vector> ids_; + std::unique_ptr callback_; +}; + } // namespace adnl } // namespace ton diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp index 27e5d985ce..dd2a3a618a 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp @@ -25,15 +25,40 @@ namespace td { -Timer::Timer() : start_time_(Time::now()) { +Timer::Timer(bool is_paused) : is_paused_(is_paused) { + if (is_paused_) { + start_time_ = 0; + } else { + start_time_ = Time::now(); + } +} + +void Timer::pause() { + if (is_paused_) { + return; + } + elapsed_ += Time::now() - start_time_; + is_paused_ = true; +} + +void Timer::resume() { + if (!is_paused_) { + return; + } + start_time_ = Time::now(); + is_paused_ = false; } double Timer::elapsed() const { - return Time::now() - start_time_; + double res = elapsed_; + if (!is_paused_) { + res += Time::now() - start_time_; + } + return res; } StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer) { - return string_builder << "in " << Time::now() - timer.start_time_; + return string_builder << format::as_time(timer.elapsed()); } PerfWarningTimer::PerfWarningTimer(string name, double max_duration) diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h index 1b84b7daba..ed5afa7468 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h @@ -24,14 +24,22 @@ namespace td { class Timer { public: - Timer(); + Timer() : Timer(false) { + } + explicit Timer(bool is_paused); + Timer(const Timer &other) = default; + Timer &operator=(const Timer &other) = default; double elapsed() const; + void pause(); + void resume(); private: friend StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer); + double elapsed_{0}; double start_time_; + bool is_paused_{false}; }; class PerfWarningTimer { diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp index 9ee0cf615f..0d6a21a832 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp @@ -53,17 +53,20 @@ SecureString create_empty(size_t size) { template Result read_file_impl(CSlice path, int64 size, int64 offset) { TRY_RESULT(from_file, FileFd::open(path, FileFd::Read)); + TRY_RESULT(file_size, from_file.get_size()); + if (offset < 0 || offset > file_size) { + return Status::Error("Failed to read file: invalid offset"); + } if (size == -1) { - TRY_RESULT(file_size, from_file.get_size()); - size = file_size; + size = file_size - offset; + } else if (size >= 0) { + if (size + offset > file_size) { + size = file_size - offset; + } } if (size < 0) { return Status::Error("Failed to read file: invalid size"); } - if (offset < 0 || offset > size) { - return Status::Error("Failed to read file: invalid offset"); - } - size -= offset; auto content = create_empty(narrow_cast(size)); TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset)); if (got_size != static_cast(size)) { diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp index 8d4a3f1c23..bfbdee4ed8 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp @@ -7643,21 +7643,21 @@ engine_validator_config::engine_validator_config() , dht_() , validators_() , fullnode_() - , fullnodeslave_() + , fullnodeslaves_() , fullnodemasters_() , liteservers_() , control_() , gc_() {} -engine_validator_config::engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, object_ptr &&fullnodeslave_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_) +engine_validator_config::engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, std::vector> &&fullnodeslaves_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_) : out_port_(out_port_) , addrs_(std::move(addrs_)) , adnl_(std::move(adnl_)) , dht_(std::move(dht_)) , validators_(std::move(validators_)) , fullnode_(fullnode_) - , fullnodeslave_(std::move(fullnodeslave_)) + , fullnodeslaves_(std::move(fullnodeslaves_)) , fullnodemasters_(std::move(fullnodemasters_)) , liteservers_(std::move(liteservers_)) , control_(std::move(control_)) @@ -7678,7 +7678,7 @@ engine_validator_config::engine_validator_config(td::TlParser &p) , dht_(TlFetchVector>::parse(p)) , validators_(TlFetchVector>::parse(p)) , fullnode_(TlFetchInt256::parse(p)) - , fullnodeslave_(TlFetchObject::parse(p)) + , fullnodeslaves_(TlFetchVector>::parse(p)) , fullnodemasters_(TlFetchVector>::parse(p)) , liteservers_(TlFetchVector>::parse(p)) , control_(TlFetchVector>::parse(p)) @@ -7694,7 +7694,7 @@ void engine_validator_config::store(td::TlStorerCalcLength &s) const { TlStoreVector::store(dht_, s); TlStoreVector::store(validators_, s); TlStoreBinary::store(fullnode_, s); - TlStoreObject::store(fullnodeslave_, s); + TlStoreVector::store(fullnodeslaves_, s); TlStoreVector::store(fullnodemasters_, s); TlStoreVector::store(liteservers_, s); TlStoreVector::store(control_, s); @@ -7709,7 +7709,7 @@ void engine_validator_config::store(td::TlStorerUnsafe &s) const { TlStoreVector::store(dht_, s); TlStoreVector::store(validators_, s); TlStoreBinary::store(fullnode_, s); - TlStoreObject::store(fullnodeslave_, s); + TlStoreVector::store(fullnodeslaves_, s); TlStoreVector::store(fullnodemasters_, s); TlStoreVector::store(liteservers_, s); TlStoreVector::store(control_, s); @@ -7725,7 +7725,7 @@ void engine_validator_config::store(td::TlStorerToString &s, const char *field_n { const std::vector> &v = dht_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("dht", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = validators_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("validators", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } s.store_field("fullnode", fullnode_); - if (fullnodeslave_ == nullptr) { s.store_field("fullnodeslave", "null"); } else { fullnodeslave_->store(s, "fullnodeslave"); } + { const std::vector> &v = fullnodeslaves_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("fullnodeslaves", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = fullnodemasters_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("fullnodemasters", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = liteservers_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("liteservers", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = control_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("control", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h index 3387d77f77..41eec24536 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h @@ -4214,7 +4214,7 @@ class engine_validator_config final : public Object { std::vector> dht_; std::vector> validators_; td::Bits256 fullnode_; - object_ptr fullnodeslave_; + std::vector> fullnodeslaves_; std::vector> fullnodemasters_; std::vector> liteservers_; std::vector> control_; @@ -4222,9 +4222,9 @@ class engine_validator_config final : public Object { engine_validator_config(); - engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, object_ptr &&fullnodeslave_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_); + engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, std::vector> &&fullnodeslaves_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_); - static const std::int32_t ID = 17126390; + static const std::int32_t ID = -826140252; std::int32_t get_id() const final { return ID; } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp index 58e145707d..d08d906c9d 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp @@ -625,7 +625,7 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"engine.adnlProxy.config", 1848000769}, {"engine.adnlProxy.port", -117344950}, {"engine.dht.config", -197295930}, - {"engine.validator.config", 17126390}, + {"engine.validator.config", -826140252}, {"engine.validator.controlQueryError", 1999018527}, {"engine.validator.dhtServerStatus", -1323440290}, {"engine.validator.dhtServersStatus", 725155112}, @@ -3099,9 +3099,9 @@ Status from_json(ton_api::engine_validator_config &to, JsonObject &from) { } } { - TRY_RESULT(value, get_json_object_field(from, "fullnodeslave", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "fullnodeslaves", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.fullnodeslave_, value)); + TRY_STATUS(from_json(to.fullnodeslaves_, value)); } } { @@ -6711,9 +6711,7 @@ void to_json(JsonValueScope &jv, const ton_api::engine_validator_config &object) jo << ctie("dht", ToJson(object.dht_)); jo << ctie("validators", ToJson(object.validators_)); jo << ctie("fullnode", ToJson(object.fullnode_)); - if (object.fullnodeslave_) { - jo << ctie("fullnodeslave", ToJson(object.fullnodeslave_)); - } + jo << ctie("fullnodeslaves", ToJson(object.fullnodeslaves_)); jo << ctie("fullnodemasters", ToJson(object.fullnodemasters_)); jo << ctie("liteservers", ToJson(object.liteservers_)); jo << ctie("control", ToJson(object.control_)); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp index 8deb110d68..0a6d3b95d8 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp @@ -413,12 +413,14 @@ raw_message::raw_message() : source_() , destination_() , value_() + , message_() {} -raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_) +raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_) : source_(std::move(source_)) , destination_(std::move(destination_)) , value_(value_) + , message_(std::move(message_)) {} const std::int32_t raw_message::ID; @@ -429,6 +431,7 @@ void raw_message::store(td::TlStorerToString &s, const char *field_name) const { s.store_field("source", source_); s.store_field("destination", destination_); s.store_field("value", value_); + s.store_bytes_field("message", message_); s.store_class_end(); } } @@ -741,13 +744,15 @@ generic_sendGrams::generic_sendGrams() , source_() , destination_() , amount_() + , message_() {} -generic_sendGrams::generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_) +generic_sendGrams::generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::string const &message_) : private_key_(std::move(private_key_)) , source_(std::move(source_)) , destination_(std::move(destination_)) , amount_(amount_) + , message_(std::move(message_)) {} const std::int32_t generic_sendGrams::ID; @@ -759,6 +764,7 @@ void generic_sendGrams::store(td::TlStorerToString &s, const char *field_name) c if (source_ == nullptr) { s.store_field("source", "null"); } else { source_->store(s, "source"); } if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } s.store_field("amount", amount_); + s.store_bytes_field("message", message_); s.store_class_end(); } } @@ -1058,12 +1064,14 @@ testGiver_sendGrams::testGiver_sendGrams() : destination_() , seqno_() , amount_() + , message_() {} -testGiver_sendGrams::testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_) +testGiver_sendGrams::testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_) : destination_(std::move(destination_)) , seqno_(seqno_) , amount_(amount_) + , message_(std::move(message_)) {} const std::int32_t testGiver_sendGrams::ID; @@ -1074,6 +1082,7 @@ void testGiver_sendGrams::store(td::TlStorerToString &s, const char *field_name) if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } s.store_field("seqno", seqno_); s.store_field("amount", amount_); + s.store_bytes_field("message", message_); s.store_class_end(); } } @@ -1137,13 +1146,15 @@ testWallet_sendGrams::testWallet_sendGrams() , destination_() , seqno_() , amount_() + , message_() {} -testWallet_sendGrams::testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_) +testWallet_sendGrams::testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_) : private_key_(std::move(private_key_)) , destination_(std::move(destination_)) , seqno_(seqno_) , amount_(amount_) + , message_(std::move(message_)) {} const std::int32_t testWallet_sendGrams::ID; @@ -1155,6 +1166,7 @@ void testWallet_sendGrams::store(td::TlStorerToString &s, const char *field_name if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } s.store_field("seqno", seqno_); s.store_field("amount", amount_); + s.store_bytes_field("message", message_); s.store_class_end(); } } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h index bbca471746..36277cd3a0 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h @@ -442,12 +442,13 @@ class raw_message final : public Object { std::string source_; std::string destination_; std::int64_t value_; + std::string message_; raw_message(); - raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_); + raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_); - static const std::int32_t ID = -1131081640; + static const std::int32_t ID = -259956097; std::int32_t get_id() const final { return ID; } @@ -717,12 +718,13 @@ class generic_sendGrams final : public Function { object_ptr source_; object_ptr destination_; std::int64_t amount_; + std::string message_; generic_sendGrams(); - generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_); + generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::string const &message_); - static const std::int32_t ID = 799772985; + static const std::int32_t ID = 1523427648; std::int32_t get_id() const final { return ID; } @@ -1012,12 +1014,13 @@ class testGiver_sendGrams final : public Function { object_ptr destination_; std::int32_t seqno_; std::int64_t amount_; + std::string message_; testGiver_sendGrams(); - testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_); + testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_); - static const std::int32_t ID = -178493799; + static const std::int32_t ID = -1361914347; std::int32_t get_id() const final { return ID; } @@ -1087,12 +1090,13 @@ class testWallet_sendGrams final : public Function { object_ptr destination_; std::int32_t seqno_; std::int64_t amount_; + std::string message_; testWallet_sendGrams(); - testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_); + testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_); - static const std::int32_t ID = -1716705044; + static const std::int32_t ID = 43200674; std::int32_t get_id() const final { return ID; } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp index 1b35ee3e61..3c1402d996 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp @@ -60,7 +60,7 @@ Result tl_constructor_from_string(tonlib_api::Object *object, const std:: {"internal.transactionId", -989527262}, {"raw.accountState", 461615898}, {"raw.initialAccountState", 777456197}, - {"raw.message", -1131081640}, + {"raw.message", -259956097}, {"raw.transaction", -1159530820}, {"raw.transactions", 240548986}, {"testGiver.accountState", 860930426}, @@ -84,7 +84,7 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"exportKey", 399723440}, {"exportPemKey", -2047752448}, {"generic.getAccountState", -657000446}, - {"generic.sendGrams", 799772985}, + {"generic.sendGrams", 1523427648}, {"getBip39Hints", -1889640982}, {"importEncryptedKey", 656724958}, {"importKey", -1607900903}, @@ -100,11 +100,11 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"runTests", -2039925427}, {"testGiver.getAccountAddress", -540100768}, {"testGiver.getAccountState", 267738275}, - {"testGiver.sendGrams", -178493799}, + {"testGiver.sendGrams", -1361914347}, {"testWallet.getAccountAddress", -1557748223}, {"testWallet.getAccountState", 654082364}, {"testWallet.init", 419055225}, - {"testWallet.sendGrams", -1716705044} + {"testWallet.sendGrams", 43200674} }; auto it = m.find(str); if (it == m.end()) { @@ -377,6 +377,12 @@ Status from_json(tonlib_api::raw_message &to, JsonObject &from) { TRY_STATUS(from_json(to.value_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } Status from_json(tonlib_api::raw_transaction &to, JsonObject &from) { @@ -638,6 +644,12 @@ Status from_json(tonlib_api::generic_sendGrams &to, JsonObject &from) { TRY_STATUS(from_json(to.amount_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } Status from_json(tonlib_api::getBip39Hints &to, JsonObject &from) { @@ -848,6 +860,12 @@ Status from_json(tonlib_api::testGiver_sendGrams &to, JsonObject &from) { TRY_STATUS(from_json(to.amount_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } Status from_json(tonlib_api::testWallet_getAccountAddress &to, JsonObject &from) { @@ -902,6 +920,12 @@ Status from_json(tonlib_api::testWallet_sendGrams &to, JsonObject &from) { TRY_STATUS(from_json(to.amount_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } void to_json(JsonValueScope &jv, const tonlib_api::accountAddress &object) { @@ -1043,6 +1067,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_message &object) { jo << ctie("source", ToJson(object.source_)); jo << ctie("destination", ToJson(object.destination_)); jo << ctie("value", ToJson(JsonInt64{object.value_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) { auto jo = jv.enter_object(); @@ -1167,6 +1192,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::generic_sendGrams &object) { jo << ctie("destination", ToJson(object.destination_)); } jo << ctie("amount", ToJson(JsonInt64{object.amount_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } void to_json(JsonValueScope &jv, const tonlib_api::getBip39Hints &object) { auto jo = jv.enter_object(); @@ -1280,6 +1306,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::testGiver_sendGrams &object) } jo << ctie("seqno", ToJson(object.seqno_)); jo << ctie("amount", ToJson(JsonInt64{object.amount_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } void to_json(JsonValueScope &jv, const tonlib_api::testWallet_getAccountAddress &object) { auto jo = jv.enter_object(); @@ -1313,6 +1340,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::testWallet_sendGrams &object) } jo << ctie("seqno", ToJson(object.seqno_)); jo << ctie("amount", ToJson(JsonInt64{object.amount_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } } // namespace tonlib_api } // namespace ton diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl index 073595ce56..860ffd5d37 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl @@ -490,7 +490,7 @@ engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNode engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave; engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl) dht:(vector engine.dht) - validators:(vector engine.validator) fullnode:int256 fullnodeslave:engine.validator.fullNodeSlave + validators:(vector engine.validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave) fullnodemasters:(vector engine.validator.fullNodeMaster) liteservers:(vector engine.liteServer) control:(vector engine.controlInterface) gc:engine.gc = engine.validator.Config; diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo index 00dc97c4e0..7ad04d37e5 100644 Binary files a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo and b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo differ diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl index 9535f056fc..356f263c2d 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl @@ -32,7 +32,7 @@ internal.transactionId lt:int64 hash:bytes = internal.TransactionId; raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState; raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState; -raw.message source:string destination:string value:int64 = raw.Message; +raw.message source:string destination:string value:int64 message:bytes = raw.Message; raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; @@ -81,15 +81,15 @@ raw.getTransactions account_address:accountAddress from_transaction_id:internal. testWallet.init private_key:inputKey = Ok; testWallet.getAccountAddress initital_account_state:testWallet.initialAccountState = AccountAddress; testWallet.getAccountState account_address:accountAddress = testWallet.AccountState; -testWallet.sendGrams private_key:inputKey destination:accountAddress seqno:int32 amount:int64 = Ok; +testWallet.sendGrams private_key:inputKey destination:accountAddress seqno:int32 amount:int64 message:bytes = Ok; testGiver.getAccountState = testGiver.AccountState; testGiver.getAccountAddress = AccountAddress; -testGiver.sendGrams destination:accountAddress seqno:int32 amount:int64 = Ok; +testGiver.sendGrams destination:accountAddress seqno:int32 amount:int64 message:bytes = Ok; //generic.getAccountAddress initital_account_state:generic.InitialAccountState = AccountAddress; generic.getAccountState account_address:accountAddress = generic.AccountState; -generic.sendGrams private_key:inputKey source:accountAddress destination:accountAddress amount:int64 = Ok; +generic.sendGrams private_key:inputKey source:accountAddress destination:accountAddress amount:int64 message:bytes = Ok; onLiteServerQueryResult id:int64 bytes:bytes = Ok; onLiteServerQueryError id:int64 error:error = Ok; diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo index 7d87ccac80..40a4ccdce4 100644 Binary files a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo and b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo differ diff --git a/submodules/ton/tonlib-src/tonlib/CMakeLists.txt b/submodules/ton/tonlib-src/tonlib/CMakeLists.txt index 6c2f11a423..9b9b81da08 100644 --- a/submodules/ton/tonlib-src/tonlib/CMakeLists.txt +++ b/submodules/ton/tonlib-src/tonlib/CMakeLists.txt @@ -13,6 +13,7 @@ set(TONLIB_SOURCE tonlib/GenericAccount.cpp tonlib/KeyStorage.cpp tonlib/LastBlock.cpp + tonlib/LastBlockStorage.cpp tonlib/TestGiver.cpp tonlib/TestWallet.cpp tonlib/TonlibClient.cpp @@ -26,6 +27,7 @@ set(TONLIB_SOURCE tonlib/GenericAccount.h tonlib/KeyStorage.h tonlib/LastBlock.h + tonlib/LastBlockStorage.h tonlib/TestGiver.h tonlib/TestWallet.h tonlib/TonlibCallback.h diff --git a/submodules/ton/tonlib-src/tonlib/test/.online.cpp.swp b/submodules/ton/tonlib-src/tonlib/test/.online.cpp.swp deleted file mode 100644 index f03547aa93..0000000000 Binary files a/submodules/ton/tonlib-src/tonlib/test/.online.cpp.swp and /dev/null differ diff --git a/submodules/ton/tonlib-src/tonlib/test/offline.cpp b/submodules/ton/tonlib-src/tonlib/test/offline.cpp index d5d86dba24..e009adf7c7 100644 --- a/submodules/ton/tonlib-src/tonlib/test/offline.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/offline.cpp @@ -127,8 +127,8 @@ TEST(Tonlib, TestGiver) { auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; - auto res = GenericAccount::create_ext_message(TestGiver::address(), {}, - TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, address)); + auto res = GenericAccount::create_ext_message( + TestGiver::address(), {}, TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, "GIFT", address)); vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr); CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash()); } diff --git a/submodules/ton/tonlib-src/tonlib/test/online.cpp b/submodules/ton/tonlib-src/tonlib/test/online.cpp index 8f5a73e9a0..716f9153bc 100644 --- a/submodules/ton/tonlib-src/tonlib/test/online.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/online.cpp @@ -118,7 +118,7 @@ void transfer_grams(Client& client, std::string from, std::string to, td::int64 auto balance = get_balance(client, to); sync_send(client, tonlib_api::make_object( std::move(input_key), tonlib_api::make_object(from), - tonlib_api::make_object(to), amount)) + tonlib_api::make_object(to), amount, "GIFT")) .ensure(); while (balance == get_balance(client, to)) { client.receive(1); @@ -270,7 +270,7 @@ int main(int argc, char* argv[]) { { sync_send(client, make_object( make_object(wallet_addr.rserialize()), seqno, - 1000000000ll * 6666 / 1000)) + 1000000000ll * 6666 / 1000, "GIFT")) .ensure(); } @@ -307,9 +307,10 @@ int main(int argc, char* argv[]) { } { - sync_send(client, make_object( - create_input_key(), make_object(wallet_addr.rserialize()), - make_object(test_giver_address), 1000000000ll * 3333 / 1000)) + sync_send(client, + make_object( + create_input_key(), make_object(wallet_addr.rserialize()), + make_object(test_giver_address), 1000000000ll * 3333 / 1000, "GIFT")) .ensure(); } while (true) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.h b/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.h deleted file mode 100644 index 4a249cffa2..0000000000 --- a/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "tonlib/LastBlock.h" - -namespace tonlib { -class BlockchainInfoStorage { - td::Status set_directory(std::string directory); - td::Result get_state(ZeroStateIdExt); - void save_state(LastBlock::State state); -}; -} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp index 5633363dab..0ec942ed90 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp @@ -21,10 +21,10 @@ #include "tonlib/LastBlock.h" namespace tonlib { -void ExtClient::with_last_block(td::Promise promise) { +void ExtClient::with_last_block(td::Promise promise) { auto query_id = last_block_queries_.create(std::move(promise)); - td::Promise P = [query_id, self = this, - actor_id = td::actor::actor_id()](td::Result result) { + td::Promise P = [query_id, self = this, + actor_id = td::actor::actor_id()](td::Result result) { send_lambda(actor_id, [self, query_id, result = std::move(result)]() mutable { self->last_block_queries_.extract(query_id).set_result(std::move(result)); }); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h index 8f92ea9e1b..dca5cdfdd4 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h @@ -29,7 +29,7 @@ namespace tonlib { class LastBlock; -struct LastBlockInfo; +struct LastBlockState; struct ExtClientRef { td::actor::ActorId andl_ext_client_; td::actor::ActorId last_block_actor_; @@ -50,7 +50,7 @@ class ExtClient { return client_; } - void with_last_block(td::Promise promise); + void with_last_block(td::Promise promise); template void send_query(QueryT query, td::Promise promise) { @@ -75,7 +75,7 @@ class ExtClient { private: ExtClientRef client_; td::Container> queries_; - td::Container> last_block_queries_; + td::Container> last_block_queries_; void send_raw_query(td::BufferSlice query, td::Promise promise); }; diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp index ca02099400..330393c0e7 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp @@ -28,7 +28,7 @@ td::Ref GenericAccount::get_init_state(td::Ref code, td::Ref .finalize(); } block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref& init_state) { - return block::StdAddress(workchain_id, init_state->get_hash().bits()); + return block::StdAddress(workchain_id, init_state->get_hash().bits(), false); } td::Ref GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref new_state, td::Ref body) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp index f4754023c9..3593adc5ec 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp @@ -23,13 +23,23 @@ #include "lite-client/lite-client-common.h" namespace tonlib { -LastBlock::LastBlock(ExtClientRef client, State state, td::unique_ptr callback) + +td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) { + return sb << td::tag("last_block", state.last_block_id.to_str()) + << td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime); +} + +LastBlock::LastBlock(ExtClientRef client, LastBlockState state, td::unique_ptr callback) : state_(std::move(state)), callback_(std::move(callback)) { client_.set_client(client); } -void LastBlock::get_last_block(td::Promise promise) { +void LastBlock::get_last_block(td::Promise promise) { if (promises_.empty()) { + total_sync_ = td::Timer(); + validate_ = td::Timer(true); + queries_ = 0; + LOG(INFO) << "Begin last block synchronization " << state_; do_get_last_block(); } promises_.push_back(std::move(promise)); @@ -41,6 +51,7 @@ void LastBlock::do_get_last_block() { //return; //liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof; + queries_++; client_.send_query( ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr), [this, from = state_.last_key_block_id](auto r_block_proof) { @@ -51,21 +62,30 @@ void LastBlock::do_get_last_block() { td::Result LastBlock::process_block_proof( ton::BlockIdExt from, td::Result> r_block_proof) { + validate_.resume(); + SCOPE_EXIT { + validate_.pause(); + }; + TRY_RESULT(block_proof, std::move(r_block_proof)); - LOG(ERROR) << to_string(block_proof); + LOG(DEBUG) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_); TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof))); if (chain->from != from) { return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str() << ", not from requested block " << from.to_str()); } TRY_STATUS(chain->validate()); - update_mc_last_block(chain->to); + bool is_changed = false; + is_changed |= update_mc_last_block(chain->to); if (chain->has_key_block) { - update_mc_last_key_block(chain->key_blkid); + is_changed |= update_mc_last_key_block(chain->key_blkid); } if (chain->has_utime) { update_utime(chain->last_utime); } + if (is_changed) { + callback_->on_state_changed(state_); + } return chain->complete; } @@ -73,17 +93,20 @@ void LastBlock::on_block_proof( ton::BlockIdExt from, td::Result> r_block_proof) { auto r_is_ready = process_block_proof(from, std::move(r_block_proof)); + bool is_ready; if (r_is_ready.is_error()) { - LOG(WARNING) << "Failed liteServer_getBlockProof " << r_is_ready.error(); - return; + LOG(WARNING) << "Error during last block synchronization " << r_is_ready.error(); + is_ready = true; + } else { + is_ready = r_is_ready.move_as_ok(); } - auto is_ready = r_is_ready.move_as_ok(); if (is_ready) { + LOG(INFO) << "End last block synchronization " << state_ << "\n" + << " net queries: " << queries_ << "\n" + << " total: " << total_sync_ << " validation: " << validate_; for (auto& promise : promises_) { - LastBlockInfo res; - res.id = state_.last_block_id; - res.utime = state_.utime; - promise.set_value(std::move(res)); + auto state = state_; + promise.set_value(std::move(state)); } promises_.clear(); } else { @@ -101,10 +124,8 @@ void LastBlock::on_masterchain_info( LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error(); } for (auto& promise : promises_) { - LastBlockInfo res; - res.id = state_.last_block_id; - res.utime = state_.utime; - promise.set_value(std::move(res)); + auto state = state_; + promise.set_value(std::move(state)); } promises_.clear(); } @@ -131,25 +152,30 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) { // One will have to restart ton client } -void LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) { +bool LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) { if (!mc_block_id.is_valid()) { LOG(ERROR) << "Ignore invalid masterchain block"; - return; + return false; } if (!state_.last_block_id.is_valid() || state_.last_block_id.id.seqno < mc_block_id.id.seqno) { state_.last_block_id = mc_block_id; LOG(INFO) << "Update masterchain block id: " << state_.last_block_id.to_str(); + return true; } + return false; } -void LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) { + +bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) { if (!mc_key_block_id.is_valid()) { LOG(ERROR) << "Ignore invalid masterchain block"; - return; + return false; } if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) { state_.last_key_block_id = mc_key_block_id; LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str(); + return true; } + return false; } void LastBlock::update_utime(td::int64 utime) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h index 968f21bddb..bb250d749e 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h @@ -22,35 +22,114 @@ #include "tonlib/ExtClient.h" namespace tonlib { -struct LastBlockInfo { - ton::BlockIdExt id; +td::StringBuilder &operator<<(td::StringBuilder &sb, const LastBlockState &state); +template +void store(const td::BitArray &arr, StorerT &storer) { + storer.store_binary(arr); +} +template +void parse(td::BitArray &arr, ParserT &parser) { + arr = parser.template fetch_binary>(); +} + +template +void store(const ton::ZeroStateIdExt &zero_state_id, StorerT &storer) { + using td::store; + using tonlib::store; + store(zero_state_id.workchain, storer); + store(zero_state_id.root_hash, storer); + store(zero_state_id.file_hash, storer); +} +template +void parse(ton::ZeroStateIdExt &zero_state_id, ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(zero_state_id.workchain, parser); + parse(zero_state_id.root_hash, parser); + parse(zero_state_id.file_hash, parser); +} +template +void store(const ton::BlockId &block_id, StorerT &storer) { + using td::store; + using tonlib::store; + store(block_id.workchain, storer); + store(block_id.shard, storer); + store(block_id.seqno, storer); +} +template +void parse(ton::BlockId &block_id, ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(block_id.workchain, parser); + parse(block_id.shard, parser); + parse(block_id.seqno, parser); +} +template +void store(const ton::BlockIdExt &block_id, StorerT &storer) { + using td::store; + using tonlib::store; + store(block_id.id, storer); + store(block_id.root_hash, storer); + store(block_id.file_hash, storer); +} +template +void parse(ton::BlockIdExt &block_id, ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(block_id.id, parser); + parse(block_id.root_hash, parser); + parse(block_id.file_hash, parser); +} +struct LastBlockState { + ton::ZeroStateIdExt zero_state_id; + ton::BlockIdExt last_key_block_id; + ton::BlockIdExt last_block_id; td::int64 utime{0}; + + template + void store(StorerT &storer) const { + using td::store; + using tonlib::store; + store(zero_state_id, storer); + store(last_key_block_id, storer); + store(last_block_id, storer); + store(utime, storer); + } + + template + void parse(ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(zero_state_id, parser); + parse(last_key_block_id, parser); + parse(last_block_id, parser); + parse(utime, parser); + } }; + class LastBlock : public td::actor::Actor { public: - struct State { - ton::ZeroStateIdExt zero_state_id; - ton::BlockIdExt last_key_block_id; - ton::BlockIdExt last_block_id; - td::int64 utime{0}; - }; - class Callback { public: virtual ~Callback() { } - virtual void on_state_changes(State state) = 0; + virtual void on_state_changed(LastBlockState state) = 0; }; - explicit LastBlock(ExtClientRef client, State state, td::unique_ptr callback); - void get_last_block(td::Promise promise); + explicit LastBlock(ExtClientRef client, LastBlockState state, td::unique_ptr callback); + void get_last_block(td::Promise promise); private: ExtClient client_; - State state_; + LastBlockState state_; td::unique_ptr callback_; - std::vector> promises_; + // stats + td::Timer total_sync_; + td::Timer validate_; + td::uint32 queries_; + + std::vector> promises_; void do_get_last_block(); void on_masterchain_info(td::Result> r_info); @@ -62,8 +141,8 @@ class LastBlock : public td::actor::Actor { void update_zero_state(ton::ZeroStateIdExt zero_state_id); - void update_mc_last_block(ton::BlockIdExt mc_block_id); - void update_mc_last_key_block(ton::BlockIdExt mc_key_block_id); + bool update_mc_last_block(ton::BlockIdExt mc_block_id); + bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id); void update_utime(td::int64 utime); }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp new file mode 100644 index 0000000000..fa979a3ca3 --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp @@ -0,0 +1,44 @@ +#include "LastBlockStorage.h" + +#include "td/utils/as.h" +#include "td/utils/filesystem.h" +#include "td/utils/port/path.h" +#include "td/utils/tl_helpers.h" + +namespace tonlib { + +td::Status LastBlockStorage::set_directory(std::string directory) { + TRY_RESULT(path, td::realpath(directory)); + TRY_RESULT(stat, td::stat(path)); + if (!stat.is_dir_) { + return td::Status::Error("not a directory"); + } + directory_ = std::move(path); + return td::Status::OK(); +} + +std::string LastBlockStorage::get_file_name(td::Slice name) { + return directory_ + TD_DIR_SLASH + td::buffer_to_hex(name) + ".blkstate"; +} + +td::Result LastBlockStorage::get_state(td::Slice name) { + TRY_RESULT(data, td::read_file(get_file_name(name))); + if (data.size() < 8) { + return td::Status::Error("too short"); + } + if (td::as(data.data()) != td::crc64(td::Slice(data).substr(8))) { + return td::Status::Error("crc64 mismatch"); + } + LastBlockState res; + TRY_STATUS(td::unserialize(res, td::Slice(data).substr(8))); + return res; +} + +void LastBlockStorage::save_state(td::Slice name, LastBlockState state) { + auto x = td::serialize(state); + std::string y(x.size() + 8, 0); + td::MutableSlice(y).substr(8).copy_from(x); + td::as(td::MutableSlice(y).data()) = td::crc64(x); + td::atomic_write_file(get_file_name(name), y); +} +} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h new file mode 100644 index 0000000000..fa920ef6ed --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h @@ -0,0 +1,16 @@ +#pragma once + +#include "tonlib/LastBlock.h" + +namespace tonlib { +class LastBlockStorage { + public: + td::Status set_directory(std::string directory); + td::Result get_state(td::Slice name); + void save_state(td::Slice name, LastBlockState state); + + private: + std::string directory_; + std::string get_file_name(td::Slice name); +}; +} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp index c9ebbcc9df..9ea58e54e2 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp @@ -32,8 +32,9 @@ vm::CellHash TestGiver::get_init_code_hash() { return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok()); } -td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, +td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, const block::StdAddress& dest_address) { + CHECK(message.size() <= 128); td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -44,7 +45,7 @@ td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gr .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("GIFT").finalize(); + auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize(); return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); } } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h index 88ccd1b772..6859be8ff0 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h @@ -23,7 +23,7 @@ class TestGiver { public: static const block::StdAddress& address(); static vm::CellHash get_init_code_hash(); - static td::Ref make_a_gift_message(td::uint32 seqno, td::uint64 gramms, + static td::Ref make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, const block::StdAddress& dest_address); }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp index bda32c1752..c092bac29c 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp @@ -38,7 +38,9 @@ td::Ref TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr } td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::int64 gramms, const block::StdAddress& dest_address) { + td::int64 gramms, td::Slice message, + const block::StdAddress& dest_address) { + CHECK(message.size() <= 128); td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -46,11 +48,11 @@ td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& .store_long(dest_address.workchain, 8) .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("GIFT").finalize(); - auto message = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); + auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize(); + auto message_outer = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); std::string seq_no(4, 0); - auto signature = private_key.sign(message->get_hash().as_slice()).move_as_ok(); - return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message)).finalize(); + auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); + return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } td::Ref TestWallet::get_init_code() { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h index f4de1f6ae6..921e3b3afe 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h @@ -28,7 +28,8 @@ class TestWallet { static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key); static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key); static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::int64 gramms, const block::StdAddress& dest_address); + td::int64 gramms, td::Slice message, + const block::StdAddress& dest_address); static td::Ref get_init_code(); static vm::CellHash get_init_code_hash(); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp index 7b48876f93..ea0c6c81e9 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp @@ -41,8 +41,6 @@ #include "td/utils/tests.h" #include "td/utils/port/path.h" -namespace ton {} // namespace ton - namespace tonlib { template @@ -152,6 +150,11 @@ class GetTransactionHistory : public td::actor::Actor { } void start_up() override { + if (lt_ == 0) { + promise_.set_value(block::TransactionList::Info()); + stop(); + return; + } client_.send_query( ton::lite_api::liteServer_getTransactions( count_, ton::create_tl_object(address_.workchain, address_.addr), lt_, @@ -171,7 +174,7 @@ class GetRawAccountState : public td::actor::Actor { block::StdAddress address_; td::Promise promise_; ExtClient client_; - LastBlockInfo last_block_; + LastBlockState last_block_; void with_account_state(td::Result> r_account_state) { promise_.set_result(TRY_VM(do_with_account_state(std::move(r_account_state)))); @@ -182,7 +185,7 @@ class GetRawAccountState : public td::actor::Actor { td::Result> r_account_state) { TRY_RESULT(raw_account_state, std::move(r_account_state)); auto account_state = create_account_state(std::move(raw_account_state)); - TRY_RESULT(info, account_state.validate(last_block_.id, address_)); + TRY_RESULT(info, account_state.validate(last_block_.last_block_id, address_)); auto serialized_state = account_state.state.clone(); RawAccountState res; res.info = std::move(info); @@ -225,14 +228,14 @@ class GetRawAccountState : public td::actor::Actor { } void start_up() override { - client_.with_last_block([self = this](td::Result r_last_block) { + client_.with_last_block([self = this](td::Result r_last_block) { if (r_last_block.is_error()) { return self->check(r_last_block.move_as_error()); } self->last_block_ = r_last_block.move_as_ok(); self->client_.send_query( - ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.id), + ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.last_block_id), ton::create_tl_object( self->address_.workchain, self->address_.addr)), [self](auto r_state) { self->with_account_state(std::move(r_state)); }); @@ -307,24 +310,36 @@ void TonlibClient::init_ext_client() { td::make_unique(td::actor::actor_shared())); } } + +void TonlibClient::update_last_block_state(LastBlockState state) { + last_block_storage_.save_state("none", state); +} + void TonlibClient::init_last_block() { ref_cnt_++; class Callback : public LastBlock::Callback { public: Callback(td::actor::ActorShared client) : client_(std::move(client)) { } - void on_state_changes(LastBlock::State state) override { - //TODO + void on_state_changed(LastBlockState state) override { + send_closure(client_, &TonlibClient::update_last_block_state, std::move(state)); } private: td::actor::ActorShared client_; }; - LastBlock::State state; - //state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash, - //config_.zero_state_id.file_hash), - state.last_block_id = config_.zero_state_id; - state.last_key_block_id = config_.zero_state_id; + LastBlockState state; + + auto r_state = last_block_storage_.get_state("none"); + if (r_state.is_error()) { + LOG(WARNING) << "Unknown LastBlockState: " << r_state.error(); + state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash, + config_.zero_state_id.file_hash), + state.last_block_id = config_.zero_state_id; + state.last_key_block_id = config_.zero_state_id; + } else { + state = r_state.move_as_ok(); + } raw_last_block_ = td::actor::create_actor("LastBlock", get_client_ref(), std::move(state), td::make_unique(td::actor::actor_shared(this))); @@ -469,6 +484,7 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request, return td::Status::Error(400, "Field options must not be empty"); } TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_)); + TRY_STATUS(last_block_storage_.set_directory(request.options_->keystore_directory_)); use_callbacks_for_network_ = request.options_->use_callbacks_for_network_; if (!request.options_->config_.empty()) { TRY_STATUS(set_config(std::move(request.options_->config_))); @@ -570,10 +586,25 @@ td::Result> to_raw_message_or_th if (!tlb::csr_unpack(message.info, msg_info)) { return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info"); } + TRY_RESULT(balance, to_balance(msg_info.value)); TRY_RESULT(src, to_std_address(msg_info.src)); TRY_RESULT(dest, to_std_address(msg_info.dest)); - return tonlib_api::make_object(std::move(src), std::move(dest), balance); + td::Ref body; + if (message.body->prefetch_long(1) == 0) { + body = std::move(message.body); + body.write().advance(1); + } else { + body = vm::load_cell_slice_ref(message.body->prefetch_ref()); + } + std::string body_message; + if (body->size() % 8 == 0) { + body_message = std::string(body->size() / 8, 0); + body->prefetch_bytes(td::MutableSlice(body_message).ubegin(), body->size() / 8); + } + + return tonlib_api::make_object(std::move(src), std::move(dest), balance, + std::move(body_message)); } case block::gen::CommonMsgInfo::ext_in_msg_info: { block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info; @@ -581,7 +612,7 @@ td::Result> to_raw_message_or_th return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info"); } TRY_RESULT(dest, to_std_address(msg_info.dest)); - return tonlib_api::make_object("", std::move(dest), 0); + return tonlib_api::make_object("", std::move(dest), 0, ""); } case block::gen::CommonMsgInfo::ext_out_msg_info: { block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info; @@ -589,7 +620,7 @@ td::Result> to_raw_message_or_th return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info"); } TRY_RESULT(src, to_std_address(msg_info.src)); - return tonlib_api::make_object(std::move(src), "", 0); + return tonlib_api::make_object(std::move(src), "", 0, ""); } } @@ -626,7 +657,7 @@ td::Result> to_raw_transacti if (is_just == trans.r1.in_msg->fetch_long_eof) { return td::Status::Error("Failed to parse long"); } - if (is_just == 1) { + if (is_just == -1) { auto msg = trans.r1.in_msg->prefetch_ref(); TRY_RESULT(in_msg_copy, to_raw_message(trans.r1.in_msg->prefetch_ref())); in_msg = std::move(in_msg_copy); @@ -702,7 +733,7 @@ td::Result> to_generic_ RawAccountState&& raw_state) { if (raw_state.code.is_null()) { return tonlib_api::make_object( - tonlib_api::make_object(raw_state.balance, empty_transaction_id(), + tonlib_api::make_object(raw_state.balance, to_transaction_id(raw_state.info), raw_state.sync_utime)); } @@ -827,21 +858,24 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ if (!request.private_key_) { return td::Status::Error(400, "Field private_key must not be empty"); } + if (request.message_.size() > 128) { + return td::Status::Error(400, "Message is too long"); + } TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); account_address.bounceable = false; TRY_RESULT(input_key, from_tonlib(*request.private_key_)); auto address = GenericAccount::get_address( 0 /*zerochain*/, TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key))); - return do_request( - tonlib_api::raw_sendMessage(tonlib_api::make_object(address.rserialize()), "", - vm::std_boc_serialize(TestWallet::make_a_gift_message( - td::Ed25519::PrivateKey(std::move(private_key.private_key)), - request.seqno_, request.amount_, account_address)) - .move_as_ok() - .as_slice() - .str()), - std::move(promise)); + return do_request(tonlib_api::raw_sendMessage( + tonlib_api::make_object(address.rserialize()), "", + vm::std_boc_serialize(TestWallet::make_a_gift_message( + td::Ed25519::PrivateKey(std::move(private_key.private_key)), + request.seqno_, request.amount_, request.message_, account_address)) + .move_as_ok() + .as_slice() + .str()), + std::move(promise)); } td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& request, @@ -868,16 +902,19 @@ td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& reque if (!request.destination_) { return td::Status::Error(400, "Field destination must not be empty"); } + if (request.message_.size() > 128) { + return td::Status::Error(400, "Message is too long"); + } TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); account_address.bounceable = false; - return do_request( - tonlib_api::raw_sendMessage( - tonlib_api::make_object(TestGiver::address().rserialize()), "", - vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, account_address)) - .move_as_ok() - .as_slice() - .str()), - std::move(promise)); + return do_request(tonlib_api::raw_sendMessage( + tonlib_api::make_object(TestGiver::address().rserialize()), "", + vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, + request.message_, account_address)) + .move_as_ok() + .as_slice() + .str()), + std::move(promise)); } td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountState& request, @@ -920,7 +957,7 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request, "GetAccountState", client_.get_client(), std::move(account_address), [promise = std::move(promise), self = this, actor_id = td::actor::actor_id(), private_key = std::move(request.private_key_), destination = std::move(request.destination_), - amount = request.amount_](td::Result r_state) mutable { + amount = request.amount_, message = std::move(request.message_)](td::Result r_state) mutable { if (r_state.is_error()) { return promise.set_error(r_state.move_as_error()); } @@ -930,40 +967,41 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request, } auto state = rr_state.move_as_ok(); - downcast_call(*state, - td::overloaded( - [&](tonlib_api::generic_accountStateTestGiver& test_giver_state) { - send_lambda(actor_id, [promise = std::move(promise), self, - query = tonlib_api::testGiver_sendGrams( - std::move(destination), test_giver_state.account_state_->seqno_, - amount)]() mutable { - LOG(INFO) << "Send " << to_string(query); - auto status = self->do_request(query, std::move(promise)); - if (status.is_error()) { - CHECK(promise); - promise.set_error(std::move(status)); - } - }); - return; - }, - [&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) { - send_lambda(actor_id, [promise = std::move(promise), self, - query = tonlib_api::testWallet_sendGrams( - std::move(private_key), std::move(destination), - test_wallet_state.account_state_->seqno_, amount)]() mutable { - auto status = self->do_request(query, std::move(promise)); - if (status.is_error()) { - CHECK(promise); - promise.set_error(std::move(status)); - } - }); - }, - [&](tonlib_api::generic_accountStateUninited&) { - promise.set_error(td::Status::Error(400, "Account is not inited")); - }, - [&](tonlib_api::generic_accountStateRaw&) { - promise.set_error(td::Status::Error(400, "Unknown account type")); - })); + downcast_call(*state, td::overloaded( + [&](tonlib_api::generic_accountStateTestGiver& test_giver_state) { + send_lambda(actor_id, + [promise = std::move(promise), self, + query = tonlib_api::testGiver_sendGrams( + std::move(destination), test_giver_state.account_state_->seqno_, + amount, std::move(message))]() mutable { + LOG(INFO) << "Send " << to_string(query); + auto status = self->do_request(query, std::move(promise)); + if (status.is_error()) { + CHECK(promise); + promise.set_error(std::move(status)); + } + }); + return; + }, + [&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) { + send_lambda(actor_id, [promise = std::move(promise), self, + query = tonlib_api::testWallet_sendGrams( + std::move(private_key), std::move(destination), + test_wallet_state.account_state_->seqno_, amount, + std::move(message))]() mutable { + auto status = self->do_request(query, std::move(promise)); + if (status.is_error()) { + CHECK(promise); + promise.set_error(std::move(status)); + } + }); + }, + [&](tonlib_api::generic_accountStateUninited&) { + promise.set_error(td::Status::Error(400, "Account is not inited")); + }, + [&](tonlib_api::generic_accountStateRaw&) { + promise.set_error(td::Status::Error(400, "Unknown account type")); + })); }) .release(); return td::Status::OK(); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h index 0e36a28921..a45fd6fdfc 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h @@ -24,6 +24,7 @@ #include "tonlib/ExtClient.h" #include "tonlib/ExtClientOutbound.h" #include "tonlib/KeyStorage.h" +#include "tonlib/LastBlockStorage.h" #include "td/actor/actor.h" @@ -50,6 +51,7 @@ class TonlibClient : public td::actor::Actor { // KeyStorage KeyStorage key_storage_; + LastBlockStorage last_block_storage_; // network td::actor::ActorOwn raw_client_; @@ -73,6 +75,7 @@ class TonlibClient : public td::actor::Actor { } } + void update_last_block_state(LastBlockState state); void on_result(td::uint64 id, object_ptr response); static bool is_static_request(td::int32 id); static bool is_uninited_request(td::int32 id); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp index cdbec51be9..f6ce8883a9 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp @@ -6,6 +6,7 @@ #include "td/utils/port/signals.h" #include "td/utils/port/path.h" #include "td/utils/Random.h" +#include "td/utils/as.h" #include "terminal/terminal.h" @@ -327,6 +328,8 @@ class TonlibCli : public td::actor::Actor { << "\n"; for (size_t i = 0; i < keys_.size(); i++) { td::TerminalIO::out() << " #" << i << ": " << keys_[i].public_key << "\n"; + td::TerminalIO::out() << " " << to_account_address(PSLICE() << i, false).move_as_ok().address->account_address_ + << "\n"; } } @@ -598,13 +601,21 @@ class TonlibCli : public td::actor::Actor { } void transfer(Address from, Address to, td::uint64 grams, td::Slice password) { + td::TerminalIO::out() << "Enter message (could be empty)"; + cont_ = [this, from = std::move(from), to = std::move(to), grams, + password = password.str()](td::Slice message) mutable { + this->transfer(std::move(from), std::move(to), grams, password, message); + }; + return; + } + void transfer(Address from, Address to, td::uint64 grams, td::Slice password, td::Slice message) { using tonlib_api::make_object; auto key = !from.secret.empty() ? make_object( make_object(from.public_key, from.secret.copy()), td::SecureString(password)) : nullptr; send_query(make_object(std::move(key), std::move(from.address), - std::move(to.address), grams), + std::move(to.address), grams, message.str()), [](auto r_res) { if (r_res.is_error()) { td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";