Compare commits
255 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b69cac3ed6 | ||
|
|
c4654f1ee8 | ||
|
|
c45122ab1e | ||
|
|
10e1feb40b | ||
|
|
4d99c1fd44 | ||
|
|
4276b6cce0 | ||
|
|
7e83088a84 | ||
|
|
47a4f4229d | ||
|
|
7cf5e6d94f | ||
|
|
5431541694 | ||
|
|
c1e86418c2 | ||
|
|
86db29cec7 | ||
|
|
19139a9a5f | ||
|
|
9509a00664 | ||
|
|
e2a85e3156 | ||
|
|
99353dcfba | ||
|
|
86a2a4d63a | ||
|
|
ab67aa28b5 | ||
|
|
db81638656 | ||
|
|
402729dc99 | ||
|
|
801c8b6220 | ||
|
|
881eb4510e | ||
|
|
cc013305ac | ||
|
|
f17fc0b670 | ||
|
|
5e2cdde2c8 | ||
|
|
eea48c7139 | ||
|
|
95a7ce4622 | ||
|
|
a0540e0486 | ||
|
|
e28fb1211e | ||
|
|
bae8335285 | ||
|
|
8fc7ba7ac1 | ||
|
|
8f5ac0420e | ||
|
|
b57255297c | ||
|
|
79cc797aff | ||
|
|
b6881022ce | ||
|
|
89765340c3 | ||
|
|
84b1fac0c8 | ||
|
|
a283049b34 | ||
|
|
8ecc98eb03 | ||
|
|
c53564cfdc | ||
|
|
cc7f569c77 | ||
|
|
7526964904 | ||
|
|
f1669674d8 | ||
|
|
cab8a52f8f | ||
|
|
6b93d8dc41 | ||
|
|
9be122710d | ||
|
|
1e3044fbf4 | ||
|
|
aef2148ed0 | ||
|
|
fb511c3e03 | ||
|
|
6acd9f18ad | ||
|
|
78b25c694e | ||
|
|
d2d97a3e47 | ||
|
|
bf8f3e42f4 | ||
|
|
fe8eae09c4 | ||
|
|
5bbf3a329d | ||
|
|
8ddbf08a97 | ||
|
|
d69090bf34 | ||
|
|
0c50fbf1b9 | ||
|
|
4206ff0483 | ||
|
|
62fd968409 | ||
|
|
2c6e4eed19 | ||
|
|
75090dedaa | ||
|
|
9dfb43d525 | ||
|
|
3b07785f87 | ||
|
|
f22e68fc32 | ||
|
|
878c890bc2 | ||
|
|
a74228acea | ||
|
|
5040c2e766 | ||
|
|
e34375405e | ||
|
|
2ffda9f240 | ||
|
|
8e73a6a6ff | ||
|
|
b642a80cd8 | ||
|
|
94bdae13d8 | ||
|
|
ee773a28bb | ||
|
|
caddb44a2c | ||
|
|
1b4216803d | ||
|
|
17cee8ec56 | ||
|
|
3cdd115317 | ||
|
|
bdd1d2484c | ||
|
|
d5a416d5ea | ||
|
|
46d393ea0f | ||
|
|
68e351b7c8 | ||
|
|
6f9c911faa | ||
|
|
dd381d9b56 | ||
|
|
8eedc7b2ba | ||
|
|
9ba1af2eb9 | ||
|
|
f567328a60 | ||
|
|
953fa52490 | ||
|
|
b1477260f0 | ||
|
|
038de9ef15 | ||
|
|
4701c5d6e3 | ||
|
|
8420b7dc17 | ||
|
|
9dacf69d41 | ||
|
|
a91efd9164 | ||
|
|
a631a28092 | ||
|
|
7bcb1fc8b2 | ||
|
|
cdafd8f171 | ||
|
|
116aa01e51 | ||
|
|
96b40f43e9 | ||
|
|
a93ec9c2c2 | ||
|
|
3ee3919d50 | ||
|
|
b4410c49b9 | ||
|
|
82bf6ca94f | ||
|
|
785ebfee34 | ||
|
|
a60f8d75a0 | ||
|
|
5976a7ed19 | ||
|
|
df7026b59c | ||
|
|
edfd9bedc1 | ||
|
|
f52c6a6daa | ||
|
|
af10b6d487 | ||
|
|
e30eacff41 | ||
|
|
18154e403a | ||
|
|
6975b04e6b | ||
|
|
948302cf02 | ||
|
|
e4cff8cb4b | ||
|
|
5bd17ae1b2 | ||
|
|
22213a71c1 | ||
|
|
e926e5f882 | ||
|
|
221d45b500 | ||
|
|
6bb7e2c2eb | ||
|
|
2a86ce596d | ||
|
|
f936e484cc | ||
|
|
b2a1c10036 | ||
|
|
2a58d01927 | ||
|
|
7cd6b821b3 | ||
|
|
de108c8efe | ||
|
|
e7104b5ebe | ||
|
|
2d17bd02a3 | ||
|
|
2a3115f461 | ||
|
|
8d62800e77 | ||
|
|
7e04bf9533 | ||
|
|
2bd3a8aaff | ||
|
|
70f92a7817 | ||
|
|
8e08f69508 | ||
|
|
abe62475cb | ||
|
|
1cdb83462e | ||
|
|
d9a29b6f15 | ||
|
|
1504f92a64 | ||
|
|
36e5056b59 | ||
|
|
c5c707f0fd | ||
|
|
832dd8d50c | ||
|
|
7d2b20e624 | ||
|
|
049945a9b9 | ||
|
|
808c9e3d2c | ||
|
|
fde7cef9c8 | ||
|
|
2791f89f30 | ||
|
|
858b5831e8 | ||
|
|
9166423598 | ||
|
|
184d984336 | ||
|
|
0b5044f064 | ||
|
|
274b66f74b | ||
|
|
e05343d721 | ||
|
|
bc316a2536 | ||
|
|
a6904be81d | ||
|
|
690a7d1608 | ||
|
|
a3e54fcd7c | ||
|
|
23c67bb2a2 | ||
|
|
75367f0488 | ||
|
|
216ffad80e | ||
|
|
c312607ff8 | ||
|
|
812d616f66 | ||
|
|
183408cb2d | ||
|
|
1a7d5b7c95 | ||
|
|
17465e1082 | ||
|
|
a996b14291 | ||
|
|
2045252cfd | ||
|
|
a2e674bdb6 | ||
|
|
cc4055a5e3 | ||
|
|
d1b6cf1fae | ||
|
|
671a06c407 | ||
|
|
3ce315111f | ||
|
|
09768ce28a | ||
|
|
c9affe0da5 | ||
|
|
4909ba5a1e | ||
|
|
e322733e20 | ||
|
|
dc7f440902 | ||
|
|
4849376347 | ||
|
|
8eca57f419 | ||
|
|
0adcd37030 | ||
|
|
2bdb9af146 | ||
|
|
5b6bddd7fc | ||
|
|
e1ea833ad6 | ||
|
|
85c21ba0e4 | ||
|
|
4d72d20398 | ||
|
|
9d3d16a725 | ||
|
|
99deaf6005 | ||
|
|
d8921c7cf5 | ||
|
|
f7fa36ca1d | ||
|
|
45f8e68203 | ||
|
|
2b47d6d63f | ||
|
|
aaefeed3f1 | ||
|
|
7f00065bd8 | ||
|
|
6f031a715e | ||
|
|
6981ae605a | ||
|
|
d91c21fb26 | ||
|
|
c95f052e60 | ||
|
|
c33be27b3c | ||
|
|
6be9b25e99 | ||
|
|
0bb391937e | ||
|
|
75ff7a6637 | ||
|
|
aece7c1096 | ||
|
|
d2e6e7adf2 | ||
|
|
b930bc0e6d | ||
|
|
93d99d6173 | ||
|
|
a8df3dcf91 | ||
|
|
b22e2ffe1d | ||
|
|
22d23c8be1 | ||
|
|
b335741f99 | ||
|
|
1261c775d4 | ||
|
|
01b4a24ac7 | ||
|
|
4124c2eb57 | ||
|
|
f09b91ebb5 | ||
|
|
57b147e0c8 | ||
|
|
551ea7d879 | ||
|
|
d3c9bb0bc6 | ||
|
|
c711b1f1df | ||
|
|
af7ea90246 | ||
|
|
348cf4829c | ||
|
|
4753a57091 | ||
|
|
1a93f4fa4c | ||
|
|
118fd187e3 | ||
|
|
baa47bde7f | ||
|
|
18b48df9ce | ||
|
|
e71fc60d22 | ||
|
|
148af59615 | ||
|
|
5b2db4112f | ||
|
|
7cedc1f7a5 | ||
|
|
6cea7d4a52 | ||
|
|
bd93aed393 | ||
|
|
348666de6d | ||
|
|
47e32bebe4 | ||
|
|
0b21c04489 | ||
|
|
85f013ebdb | ||
|
|
832cc6ac69 | ||
|
|
30ce049f51 | ||
|
|
d42fb6d1b9 | ||
|
|
cade53aa0a | ||
|
|
2fdcda7536 | ||
|
|
7e6439e4f8 | ||
|
|
f07ee7f590 | ||
|
|
02db4e01fa | ||
|
|
8d75078a42 | ||
|
|
0e25ef7524 | ||
|
|
8608d8aa4d | ||
|
|
c1a7332a5e | ||
|
|
c3fb392906 | ||
|
|
a59bfdb2f8 | ||
|
|
79f96480c2 | ||
|
|
60cbd96d91 | ||
|
|
ee0400f1ac | ||
|
|
b8a3746558 | ||
|
|
14f25fc997 | ||
|
|
27da6ee9eb | ||
|
|
48d482006a | ||
|
|
9afee2620a |
3
.github/workflows/linux.yml
vendored
@@ -93,6 +93,9 @@ jobs:
|
||||
DEFINE=""
|
||||
if [ -n "${{ matrix.defines }}" ]; then
|
||||
DEFINE="-D ${{ matrix.defines }}=ON"
|
||||
if [ "${{ matrix.defines }}" == "DESKTOP_APP_DISABLE_DBUS_INTEGRATION" ]; then
|
||||
DEFINE="$DEFINE -D DESKTOP_APP_DISABLE_GTK_INTEGRATION=ON"
|
||||
fi
|
||||
echo Define from matrix: $DEFINE
|
||||
echo "ARTIFACT_NAME=Telegram_${{ matrix.defines }}" >> $GITHUB_ENV
|
||||
else
|
||||
|
||||
62
.github/workflows/win.yml
vendored
@@ -104,6 +104,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
curl -o $LibrariesPath/tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
|
||||
curl -o $LibrariesPath/tg_angle-version.json https://api.github.com/repos/desktop-app/tg_angle/git/refs/heads/master
|
||||
echo $MANUAL_CACHING >> CACHE_KEY.txt
|
||||
if [ "$AUTO_CACHING" == "1" ]; then
|
||||
thisFile=$REPO_NAME/.github/workflows/win.yml
|
||||
@@ -316,6 +317,33 @@ jobs:
|
||||
|
||||
rmdir /S /Q .git
|
||||
|
||||
- name: Angle cache.
|
||||
id: cache-angle
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/tg_angle
|
||||
key: ${{ runner.OS }}-angle-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_angle-version.json') }}
|
||||
- name: Angle.
|
||||
if: steps.cache-angle.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone --recursive %GIT%/desktop-app/tg_angle.git
|
||||
mkdir tg_angle\out\Debug
|
||||
cd tg_angle\out\Debug
|
||||
cmake -G Ninja ^
|
||||
-DCMAKE_BUILD_TYPE=Debug ^
|
||||
-DTG_ANGLE_SPECIAL_TARGET=win64 ^
|
||||
-DTG_ANGLE_ZLIB_INCLUDE_PATH=%cd%/../../../zlib ../..
|
||||
ninja
|
||||
|
||||
:: Cleanup.
|
||||
cd %LibrariesPath%\tg_angle
|
||||
move out\Debug\tg_angle.lib tg_angle.lib
|
||||
rmdir /S /Q out
|
||||
mkdir out\Debug
|
||||
move tg_angle.lib out\Debug\tg_angle.lib
|
||||
|
||||
- name: Qt 5.15.2 cache.
|
||||
id: cache-qt
|
||||
uses: actions/cache@v2
|
||||
@@ -338,7 +366,12 @@ jobs:
|
||||
cd ..
|
||||
|
||||
SET SSL=%LibrariesPath%\openssl_%OPENSSL_VER%
|
||||
SET LIBS=libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib
|
||||
SET SSL_LIBS=libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib
|
||||
|
||||
SET ANGLE=%LibrariesPath%\tg_angle
|
||||
SET ANGLE_LIBS=d3d9.lib dxgi.lib dxguid.lib
|
||||
|
||||
SET ZLIB=%LibrariesPath%\zlib\contrib\vstudio\vc14\x86
|
||||
|
||||
configure ^
|
||||
-prefix "%LibrariesPath%\Qt-%QT_VER%" ^
|
||||
@@ -347,18 +380,29 @@ jobs:
|
||||
-opensource ^
|
||||
-confirm-license ^
|
||||
-static ^
|
||||
-static-runtime -I "%SSL%\include" ^
|
||||
-opengl dynamic ^
|
||||
-static-runtime ^
|
||||
-opengl es2 -no-angle ^
|
||||
-I "%ANGLE%\include" ^
|
||||
-D "GL_APICALL=" ^
|
||||
QMAKE_LIBS_OPENGL_ES2_DEBUG="%ANGLE%\out\Debug\tg_angle.lib %ZLIB%\ZlibStatDebug\zlibstat.lib %ANGLE_LIBS%" ^
|
||||
QMAKE_LIBS_OPENGL_ES2_RELEASE="%ANGLE%\out\Release\tg_angle.lib %ZLIB%\ZlibStatReleaseWithoutAsm\zlibstat.lib %ANGLE_LIBS%" ^
|
||||
-egl ^
|
||||
-D "EGLAPI=" ^
|
||||
-D "DESKTOP_APP_QT_STATIC_ANGLE=" ^
|
||||
QMAKE_LIBS_EGL_DEBUG="%ANGLE%\out\Debug\tg_angle.lib %ZLIB%\ZlibStatDebug\zlibstat.lib %ANGLE_LIBS% Gdi32.lib User32.lib" ^
|
||||
QMAKE_LIBS_EGL_RELEASE="%ANGLE%\out\Release\tg_angle.lib %ZLIB%\ZlibStatReleaseWithoutAsm\zlibstat.lib %ANGLE_LIBS% Gdi32.lib User32.lib" ^
|
||||
-openssl-linked ^
|
||||
OPENSSL_LIBS_DEBUG="%SSL%\out32.dbg\libssl.lib %SSL%\out32.dbg\%LIBS%" ^
|
||||
OPENSSL_LIBS_RELEASE="%SSL%\out32\libssl.lib %SSL%\out32\%LIBS%" ^
|
||||
-I "%SSL%\include" ^
|
||||
OPENSSL_LIBS_DEBUG="%SSL%\out32.dbg\libssl.lib %SSL%\out32.dbg\%SSL_LIBS%" ^
|
||||
OPENSSL_LIBS_RELEASE="%SSL%\out32\libssl.lib %SSL%\out32\%SSL_LIBS%" ^
|
||||
-I "%LibrariesPath%\mozjpeg" ^
|
||||
LIBJPEG_LIBS_DEBUG="%LibrariesPath%\mozjpeg\Debug\jpeg-static.lib" ^
|
||||
LIBJPEG_LIBS_RELEASE="%LibrariesPath%\mozjpeg\Release\jpeg-static.lib" ^
|
||||
-mp ^
|
||||
-nomake examples ^
|
||||
-nomake tests ^
|
||||
-platform win32-msvc ^
|
||||
-I "%LibrariesPath%\mozjpeg" ^
|
||||
LIBJPEG_LIBS_DEBUG="%LibrariesPath%\mozjpeg\Debug\jpeg-static.lib" ^
|
||||
LIBJPEG_LIBS_RELEASE="%LibrariesPath%\mozjpeg\Release\jpeg-static.lib"
|
||||
-platform win32-msvc
|
||||
|
||||
- name: Qt 5.15.2 build.
|
||||
if: steps.cache-qt.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
|
||||
6
.gitmodules
vendored
@@ -76,9 +76,6 @@
|
||||
[submodule "Telegram/ThirdParty/hime"]
|
||||
path = Telegram/ThirdParty/hime
|
||||
url = https://github.com/hime-ime/hime.git
|
||||
[submodule "Telegram/ThirdParty/qt5ct"]
|
||||
path = Telegram/ThirdParty/qt5ct
|
||||
url = https://github.com/desktop-app/qt5ct.git
|
||||
[submodule "Telegram/ThirdParty/fcitx5-qt"]
|
||||
path = Telegram/ThirdParty/fcitx5-qt
|
||||
url = https://github.com/fcitx/fcitx5-qt.git
|
||||
@@ -91,9 +88,6 @@
|
||||
[submodule "Telegram/lib_webview"]
|
||||
path = Telegram/lib_webview
|
||||
url = https://github.com/desktop-app/lib_webview.git
|
||||
[submodule "Telegram/ThirdParty/mallocng"]
|
||||
path = Telegram/ThirdParty/mallocng
|
||||
url = https://github.com/desktop-app/mallocng.git
|
||||
[submodule "Telegram/lib_waylandshells"]
|
||||
path = Telegram/lib_waylandshells
|
||||
url = https://github.com/desktop-app/lib_waylandshells.git
|
||||
|
||||
@@ -87,7 +87,6 @@ if (LINUX)
|
||||
PRIVATE
|
||||
desktop-app::external_glibmm
|
||||
desktop-app::external_glib
|
||||
desktop-app::external_mallocng
|
||||
)
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
||||
@@ -114,6 +113,7 @@ if (LINUX)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_GTK_INTEGRATION)
|
||||
target_link_libraries(Telegram PRIVATE rt)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if (DESKTOP_APP_USE_PACKAGED AND NOT DESKTOP_APP_USE_PACKAGED_LAZY)
|
||||
@@ -251,8 +251,6 @@ PRIVATE
|
||||
boxes/peer_lists_box.h
|
||||
boxes/passcode_box.cpp
|
||||
boxes/passcode_box.h
|
||||
boxes/photo_crop_box.cpp
|
||||
boxes/photo_crop_box.h
|
||||
boxes/rate_call_box.cpp
|
||||
boxes/rate_call_box.h
|
||||
boxes/self_destruction_box.cpp
|
||||
@@ -395,6 +393,7 @@ PRIVATE
|
||||
data/stickers/data_stickers_set.h
|
||||
data/stickers/data_stickers.cpp
|
||||
data/stickers/data_stickers.h
|
||||
data/data_abstract_sparse_ids.h
|
||||
data/data_abstract_structure.cpp
|
||||
data/data_abstract_structure.h
|
||||
data/data_auto_download.cpp
|
||||
@@ -507,6 +506,40 @@ PRIVATE
|
||||
dialogs/dialogs_search_from_controllers.h
|
||||
dialogs/dialogs_widget.cpp
|
||||
dialogs/dialogs_widget.h
|
||||
editor/color_picker.cpp
|
||||
editor/color_picker.h
|
||||
editor/controllers/controllers.h
|
||||
editor/controllers/stickers_panel_controller.cpp
|
||||
editor/controllers/stickers_panel_controller.h
|
||||
editor/controllers/undo_controller.cpp
|
||||
editor/controllers/undo_controller.h
|
||||
editor/editor_crop.cpp
|
||||
editor/editor_crop.h
|
||||
editor/editor_paint.cpp
|
||||
editor/editor_paint.h
|
||||
editor/photo_editor.cpp
|
||||
editor/photo_editor.h
|
||||
editor/photo_editor_common.cpp
|
||||
editor/photo_editor_common.h
|
||||
editor/photo_editor_content.cpp
|
||||
editor/photo_editor_content.h
|
||||
editor/photo_editor_controls.cpp
|
||||
editor/photo_editor_controls.h
|
||||
editor/photo_editor_inner_common.h
|
||||
editor/photo_editor_layer_widget.cpp
|
||||
editor/photo_editor_layer_widget.h
|
||||
editor/scene/scene.cpp
|
||||
editor/scene/scene.h
|
||||
editor/scene/scene_item_base.cpp
|
||||
editor/scene/scene_item_base.h
|
||||
editor/scene/scene_item_canvas.cpp
|
||||
editor/scene/scene_item_canvas.h
|
||||
editor/scene/scene_item_image.cpp
|
||||
editor/scene/scene_item_image.h
|
||||
editor/scene/scene_item_line.cpp
|
||||
editor/scene/scene_item_line.h
|
||||
editor/scene/scene_item_sticker.cpp
|
||||
editor/scene/scene_item_sticker.h
|
||||
export/export_manager.cpp
|
||||
export/export_manager.h
|
||||
export/view/export_view_content.cpp
|
||||
@@ -863,8 +896,6 @@ PRIVATE
|
||||
platform/linux/linux_gdk_helper.h
|
||||
platform/linux/linux_gsd_media_keys.cpp
|
||||
platform/linux/linux_gsd_media_keys.h
|
||||
platform/linux/linux_gtk_file_dialog.cpp
|
||||
platform/linux/linux_gtk_file_dialog.h
|
||||
platform/linux/linux_gtk_integration_dummy.cpp
|
||||
platform/linux/linux_gtk_integration_p.h
|
||||
platform/linux/linux_gtk_integration.cpp
|
||||
@@ -1038,6 +1069,10 @@ PRIVATE
|
||||
support/support_helper.h
|
||||
support/support_templates.cpp
|
||||
support/support_templates.h
|
||||
ui/chat/attach/attach_item_single_file_preview.cpp
|
||||
ui/chat/attach/attach_item_single_file_preview.h
|
||||
ui/chat/attach/attach_item_single_media_preview.cpp
|
||||
ui/chat/attach/attach_item_single_media_preview.h
|
||||
ui/effects/fireworks_animation.cpp
|
||||
ui/effects/fireworks_animation.h
|
||||
ui/effects/round_checkbox.cpp
|
||||
@@ -1196,8 +1231,6 @@ if (DESKTOP_APP_DISABLE_GTK_INTEGRATION)
|
||||
remove_target_sources(Telegram ${src_loc}
|
||||
platform/linux/linux_gdk_helper.cpp
|
||||
platform/linux/linux_gdk_helper.h
|
||||
platform/linux/linux_gtk_file_dialog.cpp
|
||||
platform/linux/linux_gtk_file_dialog.h
|
||||
platform/linux/linux_gtk_integration_p.h
|
||||
platform/linux/linux_gtk_integration.cpp
|
||||
platform/linux/linux_gtk_open_with_dialog.cpp
|
||||
@@ -1362,6 +1395,32 @@ endif()
|
||||
|
||||
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
|
||||
if (WIN32)
|
||||
target_link_options(Telegram
|
||||
PRIVATE
|
||||
/DELAYLOAD:secur32.dll
|
||||
/DELAYLOAD:winmm.dll
|
||||
/DELAYLOAD:ws2_32.dll
|
||||
/DELAYLOAD:user32.dll
|
||||
/DELAYLOAD:gdi32.dll
|
||||
/DELAYLOAD:advapi32.dll
|
||||
/DELAYLOAD:shell32.dll
|
||||
/DELAYLOAD:ole32.dll
|
||||
/DELAYLOAD:oleaut32.dll
|
||||
/DELAYLOAD:shlwapi.dll
|
||||
/DELAYLOAD:iphlpapi.dll
|
||||
/DELAYLOAD:gdiplus.dll
|
||||
/DELAYLOAD:version.dll
|
||||
/DELAYLOAD:dwmapi.dll
|
||||
/DELAYLOAD:crypt32.dll
|
||||
/DELAYLOAD:bcrypt.dll
|
||||
/DELAYLOAD:imm32.dll
|
||||
/DELAYLOAD:netapi32.dll
|
||||
/DELAYLOAD:userenv.dll
|
||||
/DELAYLOAD:wtsapi32.dll
|
||||
)
|
||||
endif()
|
||||
|
||||
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT build_winstore)
|
||||
add_executable(Updater WIN32)
|
||||
init_target(Updater)
|
||||
@@ -1378,8 +1437,26 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT
|
||||
|
||||
set_target_properties(Updater PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
|
||||
|
||||
if (WIN32 AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
target_link_options(Updater PRIVATE -municode)
|
||||
if (WIN32)
|
||||
get_filename_component(lib_base_loc lib_base REALPATH)
|
||||
nice_target_sources(Updater ${lib_base_loc}
|
||||
PRIVATE
|
||||
base/platform/win/base_windows_safe_library.cpp
|
||||
base/platform/win/base_windows_safe_library.h
|
||||
)
|
||||
target_include_directories(Updater PRIVATE ${lib_base_loc})
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
target_link_options(Updater
|
||||
PRIVATE
|
||||
/DELAYLOAD:user32.dll
|
||||
/DELAYLOAD:advapi32.dll
|
||||
/DELAYLOAD:shell32.dll
|
||||
/DELAYLOAD:ole32.dll
|
||||
/DELAYLOAD:shlwapi.dll
|
||||
)
|
||||
else()
|
||||
target_link_options(Updater PRIVATE -municode)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LINUX)
|
||||
|
||||
BIN
Telegram/Resources/icons/photo_editor/flip.png
Normal file
|
After Width: | Height: | Size: 456 B |
BIN
Telegram/Resources/icons/photo_editor/flip@2x.png
Normal file
|
After Width: | Height: | Size: 762 B |
BIN
Telegram/Resources/icons/photo_editor/flip@3x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/photo_editor/paint.png
Normal file
|
After Width: | Height: | Size: 947 B |
BIN
Telegram/Resources/icons/photo_editor/paint@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/photo_editor/paint@3x.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Telegram/Resources/icons/photo_editor/rotate.png
Normal file
|
After Width: | Height: | Size: 971 B |
BIN
Telegram/Resources/icons/photo_editor/rotate@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/photo_editor/rotate@3x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Telegram/Resources/icons/photo_editor/undo.png
Normal file
|
After Width: | Height: | Size: 554 B |
BIN
Telegram/Resources/icons/photo_editor/undo@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Telegram/Resources/icons/photo_editor/undo@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/send_media/send_media_delete.png
Normal file
|
After Width: | Height: | Size: 313 B |
BIN
Telegram/Resources/icons/send_media/send_media_delete@2x.png
Normal file
|
After Width: | Height: | Size: 463 B |
BIN
Telegram/Resources/icons/send_media/send_media_delete@3x.png
Normal file
|
After Width: | Height: | Size: 689 B |
BIN
Telegram/Resources/icons/send_media/send_media_replace.png
Normal file
|
After Width: | Height: | Size: 452 B |
BIN
Telegram/Resources/icons/send_media/send_media_replace@2x.png
Normal file
|
After Width: | Height: | Size: 769 B |
BIN
Telegram/Resources/icons/send_media/send_media_replace@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
@@ -184,6 +184,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_edit_media_album_error" = "This file cannot be saved as a part of an album.";
|
||||
"lng_edit_media_invalid_file" = "Sorry, no way to use this file.";
|
||||
"lng_edit_photo_editor_hint" = "Left-click on the photo to edit.";
|
||||
"lng_edit_caption_attach" = "Sorry, you can't attach a new media while you're editing your message.";
|
||||
"lng_edit_caption_voice" = "Sorry, you can't edit your message while you're having an unsent voice message.";
|
||||
|
||||
@@ -452,6 +453,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_performance" = "Performance";
|
||||
"lng_settings_enable_animations" = "Enable animations";
|
||||
"lng_settings_enable_opengl" = "Enable OpenGL rendering for media";
|
||||
"lng_settings_angle_backend" = "ANGLE graphics backend";
|
||||
"lng_settings_angle_backend_auto" = "Auto";
|
||||
"lng_settings_angle_backend_d3d9" = "Direct3D 9";
|
||||
"lng_settings_angle_backend_d3d11" = "Direct3D 11";
|
||||
"lng_settings_angle_backend_d3d11on12" = "D3D11on12";
|
||||
"lng_settings_angle_backend_opengl" = "OpenGL";
|
||||
"lng_settings_angle_backend_disabled" = "Disabled";
|
||||
"lng_settings_sensitive_title" = "Sensitive content";
|
||||
"lng_settings_sensitive_disable_filtering" = "Disable filtering";
|
||||
"lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices.";
|
||||
@@ -1372,6 +1380,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
"lng_switch_gifs" = "GIFs";
|
||||
"lng_switch_masks" = "Masks";
|
||||
"lng_stickers_featured_add" = "Add";
|
||||
"lng_gifs_search" = "Search GIFs";
|
||||
"lng_gifs_no_saved" = "You have no saved GIFs yet.";
|
||||
@@ -1382,11 +1391,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_box_remove" = "Remove";
|
||||
|
||||
"lng_stickers_installed_tab" = "Stickers";
|
||||
"lng_stickers_masks_tab" = "Masks";
|
||||
"lng_stickers_featured_tab" = "Trending";
|
||||
"lng_stickers_archived_tab" = "Archived";
|
||||
"lng_stickers_remove_pack" = "Remove «{sticker_pack}»?";
|
||||
"lng_stickers_add_pack" = "Add stickers";
|
||||
"lng_stickers_add_masks" = "Add masks";
|
||||
"lng_stickers_share_pack" = "Share Stickers";
|
||||
"lng_stickers_share_masks" = "Share Masks";
|
||||
"lng_stickers_not_found" = "Sticker pack not found.";
|
||||
"lng_stickers_packs_archived" = "Some of your unused stickers have been archived to make room for the sets you've activated.";
|
||||
"lng_stickers_copied" = "Sticker pack link copied to clipboard.";
|
||||
@@ -1395,7 +1407,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stickers_return" = "Undo";
|
||||
"lng_stickers_count#one" = "{count} sticker";
|
||||
"lng_stickers_count#other" = "{count} stickers";
|
||||
"lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps.";
|
||||
"lng_masks_count#one" = "{count} mask";
|
||||
"lng_masks_count#other" = "{count} masks";
|
||||
"lng_stickers_attached_sets" = "Sets of attached stickers";
|
||||
"lng_stickers_group_set" = "Group sticker set";
|
||||
"lng_stickers_remove_group_set" = "Remove group sticker set?";
|
||||
@@ -1406,6 +1419,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stickers_remove_pack_confirm" = "Remove";
|
||||
"lng_stickers_archive_pack" = "Archive Stickers";
|
||||
"lng_stickers_has_been_archived" = "Sticker pack has been archived.";
|
||||
"lng_masks_archive_pack" = "Archive Masks";
|
||||
"lng_masks_has_been_archived" = "Mask pack has been archived.";
|
||||
"lng_masks_installed" = "Mask pack has been installed.";
|
||||
|
||||
"lng_in_dlg_photo" = "Photo";
|
||||
"lng_in_dlg_album" = "Album";
|
||||
@@ -2005,6 +2021,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_screen_share_start" = "Share Screen";
|
||||
"lng_group_call_screen_share_stop" = "Stop Sharing";
|
||||
"lng_group_call_screen_title" = "Screen {index}";
|
||||
"lng_group_call_screen_share_audio" = "Share System Audio";
|
||||
"lng_group_call_unmute_small" = "Unmute";
|
||||
"lng_group_call_more" = "More";
|
||||
"lng_group_call_unmute" = "Unmute";
|
||||
@@ -2760,6 +2777,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_filters_remove_sure" = "This will remove the folder, your chats will not be deleted.";
|
||||
"lng_filters_remove_yes" = "Remove";
|
||||
|
||||
"lng_photo_editor_menu_delete" = "Delete";
|
||||
"lng_photo_editor_menu_flip" = "Flip";
|
||||
"lng_photo_editor_menu_duplicate" = "Duplicate";
|
||||
|
||||
// Wnd specific
|
||||
|
||||
"lng_wnd_choose_program_menu" = "Choose Default Program...";
|
||||
|
||||
@@ -376,6 +376,7 @@ updateChatParticipant#f3b3781f flags:# chat_id:int date:int actor_id:int user_id
|
||||
updateChannelParticipant#7fecb1ec flags:# channel_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
|
||||
updateBotStopped#7f9488a user_id:int date:int stopped:Bool qts:int = Update;
|
||||
updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update;
|
||||
updateBotCommands#cf7e0873 peer:Peer bot_id:int commands:Vector<BotCommand> = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@@ -534,7 +535,7 @@ authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true pa
|
||||
|
||||
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
|
||||
|
||||
account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password;
|
||||
account.password#185b184f flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int = account.Password;
|
||||
|
||||
account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings;
|
||||
|
||||
@@ -579,8 +580,8 @@ keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = Keybo
|
||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||
|
||||
replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
|
||||
replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup;
|
||||
replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup;
|
||||
replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup;
|
||||
replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> placeholder:flags.3?string = ReplyMarkup;
|
||||
replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup;
|
||||
|
||||
messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity;
|
||||
@@ -1205,7 +1206,7 @@ peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
|
||||
stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats;
|
||||
|
||||
groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall;
|
||||
groupCall#653dbaad flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int version:int = GroupCall;
|
||||
groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int = GroupCall;
|
||||
|
||||
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
|
||||
|
||||
@@ -1248,7 +1249,21 @@ phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvi
|
||||
|
||||
groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector<int> = GroupCallParticipantVideoSourceGroup;
|
||||
|
||||
groupCallParticipantVideo#78e41663 flags:# paused:flags.0?true endpoint:string source_groups:Vector<GroupCallParticipantVideoSourceGroup> = GroupCallParticipantVideo;
|
||||
groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector<GroupCallParticipantVideoSourceGroup> audio_source:flags.1?int = GroupCallParticipantVideo;
|
||||
|
||||
stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName;
|
||||
|
||||
botCommandScopeDefault#2f6cb2ab = BotCommandScope;
|
||||
botCommandScopeUsers#3c4f04d8 = BotCommandScope;
|
||||
botCommandScopeChats#6fe1a881 = BotCommandScope;
|
||||
botCommandScopeChatAdmins#b9aa606a = BotCommandScope;
|
||||
botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope;
|
||||
botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope;
|
||||
botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope;
|
||||
|
||||
account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult;
|
||||
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
||||
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
||||
|
||||
---functions---
|
||||
|
||||
@@ -1271,13 +1286,14 @@ auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int en
|
||||
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
|
||||
auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization;
|
||||
auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
|
||||
auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
|
||||
auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization;
|
||||
auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
|
||||
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
|
||||
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
|
||||
auth.exportLoginToken#b1b41517 api_id:int api_hash:string except_ids:Vector<int> = auth.LoginToken;
|
||||
auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
|
||||
auth.acceptLoginToken#e894ad4d token:bytes = Authorization;
|
||||
auth.checkRecoveryPassword#d36bf79 code:string = Bool;
|
||||
|
||||
account.registerDevice#68976c6f flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
|
||||
account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool;
|
||||
@@ -1347,6 +1363,8 @@ account.getMultiWallPapers#65ad71dc wallpapers:Vector<InputWallPaper> = Vector<W
|
||||
account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings;
|
||||
account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings;
|
||||
account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool;
|
||||
account.resetPassword#9308ce1b = account.ResetPasswordResult;
|
||||
account.declinePasswordReset#4c9409f6 = Bool;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
@@ -1596,7 +1614,9 @@ channels.convertToGigagroup#b290c69 channel:InputChannel = Updates;
|
||||
|
||||
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
||||
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||
bots.setBotCommands#805d46f6 commands:Vector<BotCommand> = Bool;
|
||||
bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector<BotCommand> = Bool;
|
||||
bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool;
|
||||
bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector<BotCommand>;
|
||||
|
||||
payments.getPaymentForm#8a333c8d flags:# peer:InputPeer msg_id:int theme_params:flags.0?DataJSON = payments.PaymentForm;
|
||||
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
|
||||
@@ -1606,11 +1626,13 @@ payments.getSavedInfo#227d824b = payments.SavedInfo;
|
||||
payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool;
|
||||
payments.getBankCardData#2e79d779 number:string = payments.BankCardData;
|
||||
|
||||
stickers.createStickerSet#f1036780 flags:# masks:flags.0?true animated:flags.1?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> = messages.StickerSet;
|
||||
stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
|
||||
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;
|
||||
stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet;
|
||||
stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
|
||||
stickers.setStickerSetThumb#9a364e30 stickerset:InputStickerSet thumb:InputDocument = messages.StickerSet;
|
||||
stickers.checkShortName#284b3639 short_name:string = Bool;
|
||||
stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName;
|
||||
|
||||
phone.getCallConfig#55451fa9 = DataJSON;
|
||||
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||
@@ -1656,4 +1678,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
|
||||
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
|
||||
|
||||
// LAYER 129
|
||||
// LAYER 131
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.8.0.0" />
|
||||
Version="2.8.8.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,8,0,0
|
||||
PRODUCTVERSION 2,8,0,0
|
||||
FILEVERSION 2,8,8,0
|
||||
PRODUCTVERSION 2,8,8,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "2.8.0.0"
|
||||
VALUE "FileVersion", "2.8.8.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.8.0.0"
|
||||
VALUE "ProductVersion", "2.8.8.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,8,0,0
|
||||
PRODUCTVERSION 2,8,0,0
|
||||
FILEVERSION 2,8,8,0
|
||||
PRODUCTVERSION 2,8,8,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "2.8.0.0"
|
||||
VALUE "FileVersion", "2.8.8.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.8.0.0"
|
||||
VALUE "ProductVersion", "2.8.8.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "updater.h"
|
||||
|
||||
#include "base/platform/win/base_windows_safe_library.h"
|
||||
|
||||
bool _debug = false;
|
||||
|
||||
wstring updaterName, updaterDir, updateTo, exeName, customWorkingDir, customKeyFile;
|
||||
@@ -329,6 +331,8 @@ void updateRegistry() {
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) {
|
||||
base::Platform::InitDynamicLibraries();
|
||||
|
||||
openLog();
|
||||
|
||||
_oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter);
|
||||
|
||||
@@ -52,8 +52,10 @@ void AttachedStickers::request(
|
||||
});
|
||||
|
||||
const auto setId = (setData->vid().v && setData->vaccess_hash().v)
|
||||
? MTP_inputStickerSetID(setData->vid(), setData->vaccess_hash())
|
||||
: MTP_inputStickerSetShortName(setData->vshort_name());
|
||||
? StickerSetIdentifier{
|
||||
.id = setData->vid().v,
|
||||
.accessHash = setData->vaccess_hash().v }
|
||||
: StickerSetIdentifier{ .shortName = qs(setData->vshort_name()) };
|
||||
strongController->show(
|
||||
Box<StickerSetBox>(strongController, setId),
|
||||
Ui::LayerOption::KeepOther);
|
||||
|
||||
@@ -156,7 +156,6 @@ void SendBotCallbackDataWithPassword(
|
||||
const auto session = &history->session();
|
||||
const auto owner = &history->owner();
|
||||
const auto api = &session->api();
|
||||
const auto bot = item->getMessageBot();
|
||||
const auto fullId = item->fullId();
|
||||
const auto getButton = [=] {
|
||||
return HistoryMessageMarkupButton::Get(
|
||||
|
||||
@@ -52,6 +52,10 @@ mtpRequestId EditMessage(
|
||||
ConvertOption::SkipLocal);
|
||||
const auto media = item->media();
|
||||
|
||||
const auto updateRecentStickers = inputMedia.has_value()
|
||||
? Api::HasAttachedStickers(*inputMedia)
|
||||
: false;
|
||||
|
||||
const auto emptyFlag = MTPmessages_EditMessage::Flag(0);
|
||||
const auto flags = emptyFlag
|
||||
| (!text.isEmpty() || media
|
||||
@@ -97,6 +101,10 @@ mtpRequestId EditMessage(
|
||||
} else {
|
||||
apply();
|
||||
}
|
||||
|
||||
if (updateRecentStickers) {
|
||||
api->requestRecentStickersForce(true);
|
||||
}
|
||||
}).fail(
|
||||
fail
|
||||
).send();
|
||||
@@ -165,22 +173,30 @@ void EditMessageWithUploadedDocument(
|
||||
HistoryItem *item,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
SendOptions options) {
|
||||
SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers) {
|
||||
if (!item || !item->media() || !item->media()->document()) {
|
||||
return;
|
||||
}
|
||||
const auto media = PrepareUploadedDocument(item, file, thumb);
|
||||
const auto media = PrepareUploadedDocument(
|
||||
item,
|
||||
file,
|
||||
thumb,
|
||||
std::move(attachedStickers));
|
||||
EditMessageWithUploadedMedia(item, options, media);
|
||||
}
|
||||
|
||||
void EditMessageWithUploadedPhoto(
|
||||
HistoryItem *item,
|
||||
const MTPInputFile &file,
|
||||
SendOptions options) {
|
||||
SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers) {
|
||||
if (!item || !item->media() || !item->media()->photo()) {
|
||||
return;
|
||||
}
|
||||
const auto media = PrepareUploadedPhoto(file);
|
||||
const auto media = PrepareUploadedPhoto(
|
||||
file,
|
||||
std::move(attachedStickers));
|
||||
EditMessageWithUploadedMedia(item, options, media);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,12 +31,14 @@ void EditMessageWithUploadedDocument(
|
||||
HistoryItem *item,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
SendOptions options);
|
||||
SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers);
|
||||
|
||||
void EditMessageWithUploadedPhoto(
|
||||
HistoryItem *item,
|
||||
const MTPInputFile &file,
|
||||
SendOptions options);
|
||||
SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers);
|
||||
|
||||
mtpRequestId EditCaption(
|
||||
not_null<HistoryItem*> item,
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace {
|
||||
int32 CountStickersHash(
|
||||
not_null<Main::Session*> session,
|
||||
bool checkOutdatedInfo) {
|
||||
using Flag = Data::StickersSetFlag;
|
||||
auto result = HashInit();
|
||||
bool foundOutdated = false;
|
||||
const auto &sets = session->data().stickers().sets();
|
||||
@@ -50,8 +51,8 @@ int32 CountStickersHash(
|
||||
const auto set = it->second.get();
|
||||
if (set->id == Data::Stickers::DefaultSetId) {
|
||||
foundOutdated = true;
|
||||
} else if (!(set->flags & MTPDstickerSet_ClientFlag::f_special)
|
||||
&& !(set->flags & MTPDstickerSet::Flag::f_archived)) {
|
||||
} else if (!(set->flags & Flag::Special)
|
||||
&& !(set->flags & Flag::Archived)) {
|
||||
HashUpdate(result, set->hash);
|
||||
}
|
||||
}
|
||||
@@ -61,10 +62,14 @@ int32 CountStickersHash(
|
||||
: 0;
|
||||
}
|
||||
|
||||
int32 CountRecentStickersHash(not_null<Main::Session*> session) {
|
||||
int32 CountRecentStickersHash(
|
||||
not_null<Main::Session*> session,
|
||||
bool attached) {
|
||||
return CountSpecialStickerSetHash(
|
||||
session,
|
||||
Data::Stickers::CloudRecentSetId);
|
||||
attached
|
||||
? Data::Stickers::CloudRecentAttachedSetId
|
||||
: Data::Stickers::CloudRecentSetId);
|
||||
}
|
||||
|
||||
int32 CountFavedStickersHash(not_null<Main::Session*> session) {
|
||||
@@ -80,7 +85,7 @@ int32 CountFeaturedStickersHash(not_null<Main::Session*> session) {
|
||||
|
||||
const auto it = sets.find(setId);
|
||||
if (it != sets.cend()
|
||||
&& (it->second->flags & MTPDstickerSet_ClientFlag::f_unread)) {
|
||||
&& (it->second->flags & Data::StickersSetFlag::Unread)) {
|
||||
HashUpdate(result, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace Api {
|
||||
not_null<Main::Session*> session,
|
||||
bool checkOutdatedInfo = false);
|
||||
[[nodiscard]] int32 CountRecentStickersHash(
|
||||
not_null<Main::Session*> session);
|
||||
not_null<Main::Session*> session,
|
||||
bool attached = false);
|
||||
[[nodiscard]] int32 CountFavedStickersHash(not_null<Main::Session*> session);
|
||||
[[nodiscard]] int32 CountFeaturedStickersHash(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_media.h"
|
||||
|
||||
#include "data/data_document.h"
|
||||
#include "data/stickers/data_stickers_set.h"
|
||||
#include "history/history_item.h"
|
||||
|
||||
namespace Api {
|
||||
@@ -47,7 +48,7 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
|
||||
attributes.push_back(MTP_documentAttributeSticker(
|
||||
MTP_flags(0),
|
||||
MTP_string(document->sticker()->alt),
|
||||
document->sticker()->set,
|
||||
Data::InputStickerSet(document->sticker()->set),
|
||||
MTPMaskCoords()));
|
||||
} else if (const auto song = document->song()) {
|
||||
const auto flags = MTPDdocumentAttributeAudio::Flag::f_title
|
||||
@@ -73,18 +74,24 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
|
||||
|
||||
} // namespace
|
||||
|
||||
MTPInputMedia PrepareUploadedPhoto(const MTPInputFile &file) {
|
||||
MTPInputMedia PrepareUploadedPhoto(
|
||||
const MTPInputFile &file,
|
||||
std::vector<MTPInputDocument> attachedStickers) {
|
||||
const auto flags = attachedStickers.empty()
|
||||
? MTPDinputMediaUploadedPhoto::Flags(0)
|
||||
: MTPDinputMediaUploadedPhoto::Flag::f_stickers;
|
||||
return MTP_inputMediaUploadedPhoto(
|
||||
MTP_flags(0),
|
||||
MTP_flags(flags),
|
||||
file,
|
||||
MTPVector<MTPInputDocument>(),
|
||||
MTP_vector<MTPInputDocument>(ranges::to<QVector>(attachedStickers)),
|
||||
MTP_int(0));
|
||||
}
|
||||
|
||||
MTPInputMedia PrepareUploadedDocument(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb) {
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
std::vector<MTPInputDocument> attachedStickers) {
|
||||
if (!item || !item->media() || !item->media()->document()) {
|
||||
return MTP_inputMediaEmpty();
|
||||
}
|
||||
@@ -92,7 +99,8 @@ MTPInputMedia PrepareUploadedDocument(
|
||||
using DocFlags = MTPDinputMediaUploadedDocument::Flag;
|
||||
const auto flags = emptyFlag
|
||||
| (thumb ? DocFlags::f_thumb : emptyFlag)
|
||||
| (item->groupId() ? DocFlags::f_nosound_video : emptyFlag);
|
||||
| (item->groupId() ? DocFlags::f_nosound_video : emptyFlag)
|
||||
| (attachedStickers.empty() ? DocFlags::f_stickers : emptyFlag);
|
||||
const auto document = item->media()->document();
|
||||
return MTP_inputMediaUploadedDocument(
|
||||
MTP_flags(flags),
|
||||
@@ -100,8 +108,20 @@ MTPInputMedia PrepareUploadedDocument(
|
||||
thumb.value_or(MTPInputFile()),
|
||||
MTP_string(document->mimeString()),
|
||||
ComposeSendingDocumentAttributes(document),
|
||||
MTPVector<MTPInputDocument>(),
|
||||
MTP_vector<MTPInputDocument>(ranges::to<QVector>(attachedStickers)),
|
||||
MTP_int(0));
|
||||
}
|
||||
|
||||
bool HasAttachedStickers(MTPInputMedia media) {
|
||||
return media.match([&](const MTPDinputMediaUploadedPhoto &photo) -> bool {
|
||||
return (photo.vflags().v
|
||||
& MTPDinputMediaUploadedPhoto::Flag::f_stickers);
|
||||
}, [&](const MTPDinputMediaUploadedDocument &document) -> bool {
|
||||
return (document.vflags().v
|
||||
& MTPDinputMediaUploadedDocument::Flag::f_stickers);
|
||||
}, [](const auto &d) {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -11,11 +11,16 @@ class HistoryItem;
|
||||
|
||||
namespace Api {
|
||||
|
||||
MTPInputMedia PrepareUploadedPhoto(const MTPInputFile &file);
|
||||
MTPInputMedia PrepareUploadedPhoto(
|
||||
const MTPInputFile &file,
|
||||
std::vector<MTPInputDocument> attachedStickers);
|
||||
|
||||
MTPInputMedia PrepareUploadedDocument(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb);
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
std::vector<MTPInputDocument> attachedStickers);
|
||||
|
||||
bool HasAttachedStickers(MTPInputMedia media);
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -474,7 +474,6 @@ void Updates::differenceDone(const MTPupdates_Difference &result) {
|
||||
stateDone(d.vstate());
|
||||
} break;
|
||||
case mtpc_updates_differenceTooLong: {
|
||||
auto &d = result.c_updates_differenceTooLong();
|
||||
LOG(("API Error: updates.differenceTooLong is not supported by Telegram Desktop!"));
|
||||
} break;
|
||||
};
|
||||
@@ -999,8 +998,8 @@ void Updates::handleSendActionUpdate(
|
||||
const auto chat = peer->asChat();
|
||||
const auto channel = peer->asChannel();
|
||||
const auto active = chat
|
||||
? (chat->flags() & MTPDchat::Flag::f_call_active)
|
||||
: (channel->flags() & MTPDchannel::Flag::f_call_active);
|
||||
? (chat->flags() & ChatDataFlag::CallActive)
|
||||
: (channel->flags() & ChannelDataFlag::CallActive);
|
||||
if (active) {
|
||||
_pendingSpeakingCallParticipants.emplace(
|
||||
peer).first->second[fromId] = now;
|
||||
@@ -1030,9 +1029,6 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
const auto &d = updates.c_updateShortMessage();
|
||||
const auto flags = mtpCastFlags(d.vflags().v)
|
||||
| MTPDmessage::Flag::f_from_id;
|
||||
const auto peerUserId = d.is_out()
|
||||
? d.vuser_id()
|
||||
: MTP_int(_session->userId().bare); // #TODO ids
|
||||
_session->data().addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
@@ -1250,7 +1246,6 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
||||
|
||||
case mtpc_updatePinnedMessages: {
|
||||
const auto &d = update.c_updatePinnedMessages();
|
||||
const auto peerId = peerFromMTP(d.vpeer());
|
||||
for (const auto &msgId : d.vmessages().v) {
|
||||
const auto item = session().data().message(0, msgId.v);
|
||||
if (item) {
|
||||
@@ -1607,7 +1602,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
history->setUnreadMark(data.is_unread());
|
||||
}
|
||||
}, [&](const MTPDdialogPeerFolder &dialog) {
|
||||
const auto id = dialog.vfolder_id().v; // #TODO archive
|
||||
//const auto id = dialog.vfolder_id().v; // #TODO archive
|
||||
//if (const auto folder = session().data().folderLoaded(id)) {
|
||||
// folder->setUnreadMark(data.is_unread());
|
||||
//}
|
||||
@@ -1817,11 +1812,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
const auto &d = update.c_updatePeerSettings();
|
||||
const auto peerId = peerFromMTP(d.vpeer());
|
||||
if (const auto peer = session().data().peerLoaded(peerId)) {
|
||||
const auto settings = d.vsettings().match([](
|
||||
const MTPDpeerSettings &data) {
|
||||
return data.vflags().v;
|
||||
});
|
||||
peer->setSettings(settings);
|
||||
peer->setSettings(d.vsettings());
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1872,19 +1863,15 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
} break;
|
||||
|
||||
case mtpc_updateNewEncryptedMessage: {
|
||||
auto &d = update.c_updateNewEncryptedMessage();
|
||||
} break;
|
||||
|
||||
case mtpc_updateEncryptedChatTyping: {
|
||||
auto &d = update.c_updateEncryptedChatTyping();
|
||||
} break;
|
||||
|
||||
case mtpc_updateEncryption: {
|
||||
auto &d = update.c_updateEncryption();
|
||||
} break;
|
||||
|
||||
case mtpc_updateEncryptedMessagesRead: {
|
||||
auto &d = update.c_updateEncryptedMessagesRead();
|
||||
} break;
|
||||
|
||||
case mtpc_updatePhoneCall:
|
||||
@@ -1902,6 +1889,26 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateBotCommands: {
|
||||
const auto &d = update.c_updateBotCommands();
|
||||
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer()))) {
|
||||
const auto botId = UserId(d.vbot_id().v);
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (user->isBot() && user->id == peerFromUser(botId)) {
|
||||
if (Data::UpdateBotCommands(user->botInfo->commands, d.vcommands())) {
|
||||
session().data().botCommandsChanged(user);
|
||||
}
|
||||
}
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
chat->setBotCommands(botId, d.vcommands());
|
||||
} else if (const auto megagroup = peer->asMegagroup()) {
|
||||
if (megagroup->mgInfo->updateBotCommands(botId, d.vcommands())) {
|
||||
session().data().botCommandsChanged(megagroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateServiceNotification: {
|
||||
const auto &d = update.c_updateServiceNotification();
|
||||
const auto text = TextWithEntities {
|
||||
@@ -2141,31 +2148,46 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
case mtpc_updateStickerSetsOrder: {
|
||||
auto &d = update.c_updateStickerSetsOrder();
|
||||
if (!d.is_masks()) {
|
||||
const auto &order = d.vorder().v;
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
Data::StickersSetsOrder result;
|
||||
for (const auto &item : order) {
|
||||
if (sets.find(item.v) == sets.cend()) {
|
||||
break;
|
||||
}
|
||||
result.push_back(item.v);
|
||||
auto &stickers = session().data().stickers();
|
||||
const auto isMasks = d.is_masks();
|
||||
const auto &order = d.vorder().v;
|
||||
const auto &sets = stickers.sets();
|
||||
Data::StickersSetsOrder result;
|
||||
for (const auto &item : order) {
|
||||
if (sets.find(item.v) == sets.cend()) {
|
||||
break;
|
||||
}
|
||||
if (result.size() != session().data().stickers().setsOrder().size()
|
||||
|| result.size() != order.size()) {
|
||||
session().data().stickers().setLastUpdate(0);
|
||||
session().api().updateStickers();
|
||||
result.push_back(item.v);
|
||||
}
|
||||
const auto localSize = isMasks
|
||||
? stickers.maskSetsOrder().size()
|
||||
: stickers.setsOrder().size();
|
||||
if ((result.size() != localSize) || (result.size() != order.size())) {
|
||||
if (isMasks) {
|
||||
stickers.setLastMasksUpdate(0);
|
||||
session().api().updateMasks();
|
||||
} else {
|
||||
session().data().stickers().setsOrderRef() = std::move(result);
|
||||
session().local().writeInstalledStickers();
|
||||
session().data().stickers().notifyUpdated();
|
||||
stickers.setLastUpdate(0);
|
||||
session().api().updateStickers();
|
||||
}
|
||||
} else {
|
||||
if (isMasks) {
|
||||
stickers.maskSetsOrderRef() = std::move(result);
|
||||
session().local().writeInstalledMasks();
|
||||
} else {
|
||||
stickers.setsOrderRef() = std::move(result);
|
||||
session().local().writeInstalledStickers();
|
||||
}
|
||||
stickers.notifyUpdated();
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_updateStickerSets: {
|
||||
// Can't determine is it masks or stickers, so update both.
|
||||
session().data().stickers().setLastUpdate(0);
|
||||
session().api().updateStickers();
|
||||
session().data().stickers().setLastMasksUpdate(0);
|
||||
session().api().updateMasks();
|
||||
} break;
|
||||
|
||||
case mtpc_updateRecentStickers: {
|
||||
|
||||
@@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_cloud_themes.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_wall_paper.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
@@ -62,7 +63,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_lock_widgets.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "inline_bots/inline_bot_result.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "ui/item_text_options.h"
|
||||
@@ -1224,9 +1224,7 @@ void ApiWrap::requestPeerSettings(not_null<PeerData*> peer) {
|
||||
request(MTPmessages_GetPeerSettings(
|
||||
peer->input
|
||||
)).done([=](const MTPPeerSettings &result) {
|
||||
peer->setSettings(result.match([&](const MTPDpeerSettings &data) {
|
||||
return data.vflags().v;
|
||||
}));
|
||||
peer->setSettings(result);
|
||||
_requestedPeerSettings.erase(peer);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestedPeerSettings.erase(peer);
|
||||
@@ -1526,7 +1524,6 @@ void ApiWrap::applyLastParticipantsList(
|
||||
| MegagroupInfo::LastParticipantsOnceReceived;
|
||||
|
||||
auto botStatus = channel->mgInfo->botStatus;
|
||||
const auto emptyAdminRights = MTP_chatAdminRights(MTP_flags(0));
|
||||
for (const auto &p : list) {
|
||||
const auto participantId = p.match([](
|
||||
const MTPDchannelParticipantBanned &data) {
|
||||
@@ -1547,13 +1544,14 @@ void ApiWrap::applyLastParticipantsList(
|
||||
? channel->amCreator()
|
||||
: false;
|
||||
const auto adminRights = (p.type() == mtpc_channelParticipantAdmin)
|
||||
? p.c_channelParticipantAdmin().vadmin_rights()
|
||||
? ChatAdminRightsInfo(p.c_channelParticipantAdmin().vadmin_rights())
|
||||
: (p.type() == mtpc_channelParticipantCreator)
|
||||
? p.c_channelParticipantCreator().vadmin_rights()
|
||||
: emptyAdminRights;
|
||||
? ChatAdminRightsInfo(p.c_channelParticipantCreator().vadmin_rights())
|
||||
: ChatAdminRightsInfo();
|
||||
const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned)
|
||||
? p.c_channelParticipantBanned().vbanned_rights()
|
||||
: ChannelData::EmptyRestrictedRights(participant);
|
||||
? ChatRestrictionsInfo(
|
||||
p.c_channelParticipantBanned().vbanned_rights())
|
||||
: ChatRestrictionsInfo();
|
||||
if (p.type() == mtpc_channelParticipantCreator) {
|
||||
Assert(user != nullptr);
|
||||
const auto &creator = p.c_channelParticipantCreator();
|
||||
@@ -1569,11 +1567,11 @@ void ApiWrap::applyLastParticipantsList(
|
||||
if (user
|
||||
&& !base::contains(channel->mgInfo->lastParticipants, user)) {
|
||||
channel->mgInfo->lastParticipants.push_back(user);
|
||||
if (adminRights.c_chatAdminRights().vflags().v) {
|
||||
if (adminRights.flags) {
|
||||
channel->mgInfo->lastAdmins.emplace(
|
||||
user,
|
||||
MegagroupInfo::Admin{ adminRights, adminCanEdit });
|
||||
} else if (Data::ChatBannedRightsFlags(restrictedRights) != 0) {
|
||||
} else if (restrictedRights.flags) {
|
||||
channel->mgInfo->lastRestricted.emplace(
|
||||
user,
|
||||
MegagroupInfo::Restricted{ restrictedRights });
|
||||
@@ -1731,7 +1729,7 @@ void ApiWrap::kickParticipant(
|
||||
void ApiWrap::kickParticipant(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights ¤tRights) {
|
||||
ChatRestrictionsInfo currentRights) {
|
||||
const auto kick = KickRequest(channel, participant);
|
||||
if (_kickRequests.contains(kick)) return;
|
||||
|
||||
@@ -1739,7 +1737,10 @@ void ApiWrap::kickParticipant(
|
||||
const auto requestId = request(MTPchannels_EditBanned(
|
||||
channel->inputChannel,
|
||||
participant->input,
|
||||
rights
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(
|
||||
MTPDchatBannedRights::Flags::from_raw(uint32(rights.flags))),
|
||||
MTP_int(rights.until))
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
|
||||
@@ -1763,7 +1764,7 @@ void ApiWrap::unblockParticipant(
|
||||
const auto requestId = request(MTPchannels_EditBanned(
|
||||
channel->inputChannel,
|
||||
participant->input,
|
||||
ChannelData::EmptyRestrictedRights(participant)
|
||||
MTP_chatBannedRights(MTP_flags(0), MTP_int(0))
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
|
||||
@@ -1857,9 +1858,14 @@ void ApiWrap::requestStickerSets() {
|
||||
if (i.value().second) continue;
|
||||
|
||||
auto waitMs = (j == e) ? 0 : kSmallDelayMs;
|
||||
i.value().second = request(MTPmessages_GetStickerSet(MTP_inputStickerSetID(MTP_long(i.key()), MTP_long(i.value().first)))).done([this, setId = i.key()](const MTPmessages_StickerSet &result) {
|
||||
const auto id = MTP_inputStickerSetID(
|
||||
MTP_long(i.key()),
|
||||
MTP_long(i.value().first));
|
||||
i.value().second = request(MTPmessages_GetStickerSet(
|
||||
id
|
||||
)).done([=, setId = i.key()](const MTPmessages_StickerSet &result) {
|
||||
gotStickerSet(setId, result);
|
||||
}).fail([this, setId = i.key()](const MTP::Error &error) {
|
||||
}).fail([=, setId = i.key()](const MTP::Error &error) {
|
||||
_stickerSetRequests.remove(setId);
|
||||
}).afterDelay(waitMs).send();
|
||||
}
|
||||
@@ -1867,23 +1873,89 @@ void ApiWrap::requestStickerSets() {
|
||||
|
||||
void ApiWrap::saveStickerSets(
|
||||
const Data::StickersSetsOrder &localOrder,
|
||||
const Data::StickersSetsOrder &localRemoved) {
|
||||
for (auto requestId : base::take(_stickerSetDisenableRequests)) {
|
||||
const Data::StickersSetsOrder &localRemoved,
|
||||
bool setsMasks) {
|
||||
auto &setDisenableRequests = setsMasks
|
||||
? _maskSetDisenableRequests
|
||||
: _stickerSetDisenableRequests;
|
||||
const auto reorderRequestId = [=]() -> mtpRequestId & {
|
||||
return setsMasks
|
||||
? _masksReorderRequestId
|
||||
: _stickersReorderRequestId;
|
||||
};
|
||||
for (auto requestId : base::take(setDisenableRequests)) {
|
||||
request(requestId).cancel();
|
||||
}
|
||||
request(base::take(_stickersReorderRequestId)).cancel();
|
||||
request(base::take(reorderRequestId())).cancel();
|
||||
request(base::take(_stickersClearRecentRequestId)).cancel();
|
||||
request(base::take(_stickersClearRecentAttachedRequestId)).cancel();
|
||||
|
||||
auto writeInstalled = true, writeRecent = false, writeCloudRecent = false, writeFaved = false, writeArchived = false;
|
||||
const auto stickersSaveOrder = [=] {
|
||||
if (localOrder.size() < 2) {
|
||||
return;
|
||||
}
|
||||
QVector<MTPlong> mtpOrder;
|
||||
mtpOrder.reserve(localOrder.size());
|
||||
for (const auto setId : std::as_const(localOrder)) {
|
||||
mtpOrder.push_back(MTP_long(setId));
|
||||
}
|
||||
|
||||
const auto flags = setsMasks
|
||||
? MTPmessages_ReorderStickerSets::Flag::f_masks
|
||||
: MTPmessages_ReorderStickerSets::Flags(0);
|
||||
reorderRequestId() = request(MTPmessages_ReorderStickerSets(
|
||||
MTP_flags(flags),
|
||||
MTP_vector<MTPlong>(mtpOrder)
|
||||
)).done([=](const MTPBool &result) {
|
||||
reorderRequestId() = 0;
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
reorderRequestId() = 0;
|
||||
if (setsMasks) {
|
||||
_session->data().stickers().setLastMasksUpdate(0);
|
||||
updateMasks();
|
||||
} else {
|
||||
_session->data().stickers().setLastUpdate(0);
|
||||
updateStickers();
|
||||
}
|
||||
}).send();
|
||||
};
|
||||
|
||||
const auto stickerSetDisenabled = [=](mtpRequestId requestId) {
|
||||
auto &setDisenableRequests = setsMasks
|
||||
? _maskSetDisenableRequests
|
||||
: _stickerSetDisenableRequests;
|
||||
setDisenableRequests.remove(requestId);
|
||||
if (setDisenableRequests.empty()) {
|
||||
stickersSaveOrder();
|
||||
}
|
||||
};
|
||||
|
||||
auto writeInstalled = true,
|
||||
writeRecent = false,
|
||||
writeCloudRecent = false,
|
||||
writeCloudRecentAttached = false,
|
||||
writeFaved = false,
|
||||
writeArchived = false;
|
||||
auto &recent = _session->data().stickers().getRecentPack();
|
||||
auto &sets = _session->data().stickers().setsRef();
|
||||
|
||||
_stickersOrder = localOrder;
|
||||
auto &order = setsMasks
|
||||
? _session->data().stickers().maskSetsOrder()
|
||||
: _session->data().stickers().setsOrder();
|
||||
auto &orderRef = setsMasks
|
||||
? _session->data().stickers().maskSetsOrderRef()
|
||||
: _session->data().stickers().setsOrderRef();
|
||||
|
||||
using Flag = Data::StickersSetFlag;
|
||||
for (const auto removedSetId : localRemoved) {
|
||||
if (removedSetId == Data::Stickers::CloudRecentSetId) {
|
||||
if ((removedSetId == Data::Stickers::CloudRecentSetId)
|
||||
|| (removedSetId == Data::Stickers::CloudRecentAttachedSetId)) {
|
||||
if (sets.remove(Data::Stickers::CloudRecentSetId) != 0) {
|
||||
writeCloudRecent = true;
|
||||
}
|
||||
if (sets.remove(Data::Stickers::CloudRecentAttachedSetId) != 0) {
|
||||
writeCloudRecentAttached = true;
|
||||
}
|
||||
if (sets.remove(Data::Stickers::CustomSetId)) {
|
||||
writeInstalled = true;
|
||||
}
|
||||
@@ -1892,12 +1964,25 @@ void ApiWrap::saveStickerSets(
|
||||
writeRecent = true;
|
||||
}
|
||||
|
||||
_stickersClearRecentRequestId = request(MTPmessages_ClearRecentStickers(
|
||||
MTP_flags(0)
|
||||
)).done([this](const MTPBool &result) {
|
||||
_stickersClearRecentRequestId = 0;
|
||||
}).fail([this](const MTP::Error &error) {
|
||||
_stickersClearRecentRequestId = 0;
|
||||
const auto isAttached =
|
||||
(removedSetId == Data::Stickers::CloudRecentAttachedSetId);
|
||||
const auto flags = isAttached
|
||||
? MTPmessages_ClearRecentStickers::Flag::f_attached
|
||||
: MTPmessages_ClearRecentStickers::Flags(0);
|
||||
auto &requestId = isAttached
|
||||
? _stickersClearRecentAttachedRequestId
|
||||
: _stickersClearRecentRequestId;
|
||||
const auto finish = [=] {
|
||||
(isAttached
|
||||
? _stickersClearRecentAttachedRequestId
|
||||
: _stickersClearRecentRequestId) = 0;
|
||||
};
|
||||
requestId = request(MTPmessages_ClearRecentStickers(
|
||||
MTP_flags(flags)
|
||||
)).done([=](const MTPBool &result) {
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
finish();
|
||||
}).send();
|
||||
continue;
|
||||
}
|
||||
@@ -1913,27 +1998,33 @@ void ApiWrap::saveStickerSets(
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
|
||||
const auto archived = !!(set->flags & Flag::Archived);
|
||||
if (!archived) {
|
||||
const auto featured = !!(set->flags & Flag::Featured);
|
||||
const auto special = !!(set->flags & Flag::Special);
|
||||
const auto setId = set->mtpInput();
|
||||
|
||||
auto requestId = request(MTPmessages_UninstallStickerSet(setId)).done([this](const MTPBool &result, mtpRequestId requestId) {
|
||||
auto requestId = request(MTPmessages_UninstallStickerSet(
|
||||
setId
|
||||
)).done([=](const MTPBool &result, mtpRequestId requestId) {
|
||||
stickerSetDisenabled(requestId);
|
||||
}).fail([this](const MTP::Error &error, mtpRequestId requestId) {
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||
stickerSetDisenabled(requestId);
|
||||
}).afterDelay(kSmallDelayMs).send();
|
||||
|
||||
_stickerSetDisenableRequests.insert(requestId);
|
||||
setDisenableRequests.insert(requestId);
|
||||
|
||||
int removeIndex = _session->data().stickers().setsOrder().indexOf(set->id);
|
||||
if (removeIndex >= 0) _session->data().stickers().setsOrderRef().removeAt(removeIndex);
|
||||
if (!(set->flags & MTPDstickerSet_ClientFlag::f_featured)
|
||||
&& !(set->flags & MTPDstickerSet_ClientFlag::f_special)) {
|
||||
const auto removeIndex = order.indexOf(set->id);
|
||||
if (removeIndex >= 0) {
|
||||
orderRef.removeAt(removeIndex);
|
||||
}
|
||||
if (!featured && !special) {
|
||||
sets.erase(it);
|
||||
} else {
|
||||
if (set->flags & MTPDstickerSet::Flag::f_archived) {
|
||||
if (archived) {
|
||||
writeArchived = true;
|
||||
}
|
||||
set->flags &= ~(MTPDstickerSet::Flag::f_installed_date | MTPDstickerSet::Flag::f_archived);
|
||||
set->flags &= ~(Flag::Installed | Flag::Archived);
|
||||
set->installDate = TimeId(0);
|
||||
}
|
||||
}
|
||||
@@ -1942,51 +2033,55 @@ void ApiWrap::saveStickerSets(
|
||||
|
||||
// Clear all installed flags, set only for sets from order.
|
||||
for (auto &[id, set] : sets) {
|
||||
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
|
||||
set->flags &= ~MTPDstickerSet::Flag::f_installed_date;
|
||||
const auto archived = !!(set->flags & Flag::Archived);
|
||||
const auto masks = !!(set->flags & Flag::Masks);
|
||||
if (!archived && (setsMasks == masks)) {
|
||||
set->flags &= ~Flag::Installed;
|
||||
}
|
||||
}
|
||||
|
||||
auto &order = _session->data().stickers().setsOrderRef();
|
||||
order.clear();
|
||||
for (const auto setId : std::as_const(_stickersOrder)) {
|
||||
orderRef.clear();
|
||||
for (const auto setId : std::as_const(localOrder)) {
|
||||
auto it = sets.find(setId);
|
||||
if (it != sets.cend()) {
|
||||
const auto set = it->second.get();
|
||||
if ((set->flags & MTPDstickerSet::Flag::f_archived) && !localRemoved.contains(set->id)) {
|
||||
const auto mtpSetId = set->mtpInput();
|
||||
if (it == sets.cend()) {
|
||||
continue;
|
||||
}
|
||||
const auto set = it->second.get();
|
||||
const auto archived = !!(set->flags & Flag::Archived);
|
||||
if (archived && !localRemoved.contains(set->id)) {
|
||||
const auto mtpSetId = set->mtpInput();
|
||||
|
||||
const auto requestId = request(MTPmessages_InstallStickerSet(
|
||||
mtpSetId,
|
||||
MTP_boolFalse()
|
||||
)).done([=](
|
||||
const MTPmessages_StickerSetInstallResult &result,
|
||||
mtpRequestId requestId) {
|
||||
stickerSetDisenabled(requestId);
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
mtpRequestId requestId) {
|
||||
stickerSetDisenabled(requestId);
|
||||
}).afterDelay(kSmallDelayMs).send();
|
||||
const auto requestId = request(MTPmessages_InstallStickerSet(
|
||||
mtpSetId,
|
||||
MTP_boolFalse()
|
||||
)).done([=](
|
||||
const MTPmessages_StickerSetInstallResult &result,
|
||||
mtpRequestId requestId) {
|
||||
stickerSetDisenabled(requestId);
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
mtpRequestId requestId) {
|
||||
stickerSetDisenabled(requestId);
|
||||
}).afterDelay(kSmallDelayMs).send();
|
||||
|
||||
_stickerSetDisenableRequests.insert(requestId);
|
||||
setDisenableRequests.insert(requestId);
|
||||
|
||||
set->flags &= ~MTPDstickerSet::Flag::f_archived;
|
||||
writeArchived = true;
|
||||
}
|
||||
order.push_back(setId);
|
||||
set->flags |= MTPDstickerSet::Flag::f_installed_date;
|
||||
if (!set->installDate) {
|
||||
set->installDate = base::unixtime::now();
|
||||
}
|
||||
set->flags &= ~Flag::Archived;
|
||||
writeArchived = true;
|
||||
}
|
||||
orderRef.push_back(setId);
|
||||
set->flags |= Flag::Installed;
|
||||
if (!set->installDate) {
|
||||
set->installDate = base::unixtime::now();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = sets.begin(); it != sets.cend();) {
|
||||
const auto set = it->second.get();
|
||||
if ((set->flags & MTPDstickerSet_ClientFlag::f_featured)
|
||||
|| (set->flags & MTPDstickerSet::Flag::f_installed_date)
|
||||
|| (set->flags & MTPDstickerSet::Flag::f_archived)
|
||||
|| (set->flags & MTPDstickerSet_ClientFlag::f_special)) {
|
||||
if ((set->flags & Flag::Featured)
|
||||
|| (set->flags & Flag::Installed)
|
||||
|| (set->flags & Flag::Archived)
|
||||
|| (set->flags & Flag::Special)) {
|
||||
++it;
|
||||
} else {
|
||||
it = sets.erase(it);
|
||||
@@ -1994,27 +2089,40 @@ void ApiWrap::saveStickerSets(
|
||||
}
|
||||
|
||||
auto &storage = local();
|
||||
if (writeInstalled) storage.writeInstalledStickers();
|
||||
if (writeRecent) session().saveSettings();
|
||||
if (writeArchived) storage.writeArchivedStickers();
|
||||
if (writeCloudRecent) storage.writeRecentStickers();
|
||||
if (writeFaved) storage.writeFavedStickers();
|
||||
if (writeInstalled && !setsMasks) {
|
||||
storage.writeInstalledStickers();
|
||||
}
|
||||
if (writeInstalled && setsMasks) {
|
||||
storage.writeInstalledMasks();
|
||||
}
|
||||
if (writeRecent) {
|
||||
session().saveSettings();
|
||||
}
|
||||
if (writeArchived) {
|
||||
if (setsMasks) {
|
||||
storage.writeArchivedMasks();
|
||||
} else {
|
||||
storage.writeArchivedStickers();
|
||||
}
|
||||
}
|
||||
if (writeCloudRecent) {
|
||||
storage.writeRecentStickers();
|
||||
}
|
||||
if (writeCloudRecentAttached) {
|
||||
storage.writeRecentMasks();
|
||||
}
|
||||
if (writeFaved) {
|
||||
storage.writeFavedStickers();
|
||||
}
|
||||
_session->data().stickers().notifyUpdated();
|
||||
|
||||
if (_stickerSetDisenableRequests.empty()) {
|
||||
if (setDisenableRequests.empty()) {
|
||||
stickersSaveOrder();
|
||||
} else {
|
||||
requestSendDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::stickerSetDisenabled(mtpRequestId requestId) {
|
||||
_stickerSetDisenableRequests.remove(requestId);
|
||||
if (_stickerSetDisenableRequests.empty()) {
|
||||
stickersSaveOrder();
|
||||
}
|
||||
};
|
||||
|
||||
void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
|
||||
if (channel->amIn()) {
|
||||
session().changes().peerUpdated(
|
||||
@@ -2825,12 +2933,24 @@ void ApiWrap::refreshFileReference(
|
||||
}, [&](Data::FileOriginPeerPhoto data) {
|
||||
fail();
|
||||
}, [&](Data::FileOriginStickerSet data) {
|
||||
const auto isRecentAttached =
|
||||
(data.setId == Data::Stickers::CloudRecentAttachedSetId);
|
||||
if (data.setId == Data::Stickers::CloudRecentSetId
|
||||
|| data.setId == Data::Stickers::RecentSetId) {
|
||||
|| data.setId == Data::Stickers::RecentSetId
|
||||
|| isRecentAttached) {
|
||||
auto done = [=] { crl::on_main(_session, [=] {
|
||||
if (isRecentAttached) {
|
||||
local().writeRecentMasks();
|
||||
} else {
|
||||
local().writeRecentStickers();
|
||||
}
|
||||
}); };
|
||||
request(MTPmessages_GetRecentStickers(
|
||||
MTP_flags(0),
|
||||
MTP_flags(isRecentAttached
|
||||
? MTPmessages_GetRecentStickers::Flag::f_attached
|
||||
: MTPmessages_GetRecentStickers::Flags(0)),
|
||||
MTP_int(0)),
|
||||
[=] { crl::on_main(_session, [=] { local().writeRecentStickers(); }); });
|
||||
std::move(done));
|
||||
} else if (data.setId == Data::Stickers::FavedSetId) {
|
||||
request(MTPmessages_GetFavedStickers(MTP_int(0)),
|
||||
[=] { crl::on_main(_session, [=] { local().writeFavedStickers(); }); });
|
||||
@@ -2886,30 +3006,8 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &resu
|
||||
_session->data().sendWebPageGamePollNotifications();
|
||||
}
|
||||
|
||||
void ApiWrap::stickersSaveOrder() {
|
||||
if (_stickersOrder.size() < 2) {
|
||||
return;
|
||||
}
|
||||
QVector<MTPlong> mtpOrder;
|
||||
mtpOrder.reserve(_stickersOrder.size());
|
||||
for (const auto setId : std::as_const(_stickersOrder)) {
|
||||
mtpOrder.push_back(MTP_long(setId));
|
||||
}
|
||||
|
||||
_stickersReorderRequestId = request(MTPmessages_ReorderStickerSets(
|
||||
MTP_flags(0),
|
||||
MTP_vector<MTPlong>(mtpOrder)
|
||||
)).done([=](const MTPBool &result) {
|
||||
_stickersReorderRequestId = 0;
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_stickersReorderRequestId = 0;
|
||||
_session->data().stickers().setLastUpdate(0);
|
||||
updateStickers();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::updateStickers() {
|
||||
auto now = crl::now();
|
||||
const auto now = crl::now();
|
||||
requestStickers(now);
|
||||
requestRecentStickers(now);
|
||||
requestFavedStickers(now);
|
||||
@@ -2917,15 +3015,26 @@ void ApiWrap::updateStickers() {
|
||||
requestSavedGifs(now);
|
||||
}
|
||||
|
||||
void ApiWrap::requestRecentStickersForce() {
|
||||
requestRecentStickersWithHash(0);
|
||||
void ApiWrap::updateMasks() {
|
||||
const auto now = crl::now();
|
||||
requestStickers(now, true);
|
||||
requestRecentStickers(now, true);
|
||||
}
|
||||
|
||||
void ApiWrap::setGroupStickerSet(not_null<ChannelData*> megagroup, const MTPInputStickerSet &set) {
|
||||
void ApiWrap::requestRecentStickersForce(bool attached) {
|
||||
requestRecentStickersWithHash(0, attached);
|
||||
}
|
||||
|
||||
void ApiWrap::setGroupStickerSet(
|
||||
not_null<ChannelData*> megagroup,
|
||||
const StickerSetIdentifier &set) {
|
||||
Expects(megagroup->mgInfo != nullptr);
|
||||
|
||||
megagroup->mgInfo->stickerSet = set;
|
||||
request(MTPchannels_SetStickers(megagroup->inputChannel, set)).send();
|
||||
request(MTPchannels_SetStickers(
|
||||
megagroup->inputChannel,
|
||||
Data::InputStickerSet(set)
|
||||
)).send();
|
||||
_session->data().stickers().notifyUpdated();
|
||||
}
|
||||
|
||||
@@ -2977,17 +3086,29 @@ std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ApiWrap::requestStickers(TimeId now) {
|
||||
if (!_session->data().stickers().updateNeeded(now)
|
||||
|| _stickersUpdateRequest) {
|
||||
void ApiWrap::requestStickers(TimeId now, bool masks) {
|
||||
const auto requestId = [=]() -> mtpRequestId & {
|
||||
return masks
|
||||
? _masksUpdateRequest
|
||||
: _stickersUpdateRequest;
|
||||
};
|
||||
const auto needed = masks
|
||||
? _session->data().stickers().masksUpdateNeeded(now)
|
||||
: _session->data().stickers().updateNeeded(now);
|
||||
if (!needed || requestId()) {
|
||||
return;
|
||||
}
|
||||
auto onDone = [this](const MTPmessages_AllStickers &result) {
|
||||
_session->data().stickers().setLastUpdate(crl::now());
|
||||
_stickersUpdateRequest = 0;
|
||||
const auto onDone = [=](const MTPmessages_AllStickers &result) {
|
||||
if (masks) {
|
||||
_session->data().stickers().setLastMasksUpdate(crl::now());
|
||||
} else {
|
||||
_session->data().stickers().setLastUpdate(crl::now());
|
||||
}
|
||||
requestId() = 0;
|
||||
|
||||
switch (result.type()) {
|
||||
case mtpc_messages_allStickersNotModified: return;
|
||||
case mtpc_messages_getMaskStickers:
|
||||
case mtpc_messages_allStickers: {
|
||||
auto &d = result.c_messages_allStickers();
|
||||
_session->data().stickers().setsReceived(
|
||||
@@ -2997,39 +3118,67 @@ void ApiWrap::requestStickers(TimeId now) {
|
||||
default: Unexpected("Type in ApiWrap::stickersDone()");
|
||||
}
|
||||
};
|
||||
_stickersUpdateRequest = request(MTPmessages_GetAllStickers(
|
||||
MTP_int(Api::CountStickersHash(_session, true))
|
||||
)).done(onDone).fail([=](const MTP::Error &error) {
|
||||
LOG(("App Fail: Failed to get stickers!"));
|
||||
const auto onFail = [=](const MTP::Error &error) {
|
||||
LOG(("App Fail: Failed to get %1!"
|
||||
).arg(masks ? "masks" : "stickers"));
|
||||
onDone(MTP_messages_allStickersNotModified());
|
||||
}).send();
|
||||
};
|
||||
auto hash = MTP_int(Api::CountStickersHash(_session, true));
|
||||
requestId() = masks
|
||||
? request(MTPmessages_GetMaskStickers(
|
||||
std::move(hash))
|
||||
).done(onDone).fail(onFail).send()
|
||||
: request(MTPmessages_GetAllStickers(
|
||||
std::move(hash))
|
||||
).done(onDone).fail(onFail).send();
|
||||
}
|
||||
|
||||
void ApiWrap::requestRecentStickers(TimeId now) {
|
||||
if (!_session->data().stickers().recentUpdateNeeded(now)) {
|
||||
void ApiWrap::requestRecentStickers(TimeId now, bool attached) {
|
||||
const auto needed = attached
|
||||
? _session->data().stickers().recentAttachedUpdateNeeded(now)
|
||||
: _session->data().stickers().recentUpdateNeeded(now);
|
||||
if (!needed) {
|
||||
return;
|
||||
}
|
||||
requestRecentStickersWithHash(
|
||||
Api::CountRecentStickersHash(_session));
|
||||
Api::CountRecentStickersHash(_session, attached), attached);
|
||||
}
|
||||
|
||||
void ApiWrap::requestRecentStickersWithHash(int32 hash) {
|
||||
if (_recentStickersUpdateRequest) {
|
||||
void ApiWrap::requestRecentStickersWithHash(int32 hash, bool attached) {
|
||||
const auto requestId = [=]() -> mtpRequestId & {
|
||||
return attached
|
||||
? _recentAttachedStickersUpdateRequest
|
||||
: _recentStickersUpdateRequest;
|
||||
};
|
||||
if (requestId()) {
|
||||
return;
|
||||
}
|
||||
_recentStickersUpdateRequest = request(MTPmessages_GetRecentStickers(
|
||||
MTP_flags(0),
|
||||
const auto finish = [=] {
|
||||
auto &stickers = _session->data().stickers();
|
||||
if (attached) {
|
||||
stickers.setLastRecentAttachedUpdate(crl::now());
|
||||
} else {
|
||||
stickers.setLastRecentUpdate(crl::now());
|
||||
}
|
||||
requestId() = 0;
|
||||
};
|
||||
const auto flags = attached
|
||||
? MTPmessages_getRecentStickers::Flag::f_attached
|
||||
: MTPmessages_getRecentStickers::Flags(0);
|
||||
requestId() = request(MTPmessages_GetRecentStickers(
|
||||
MTP_flags(flags),
|
||||
MTP_int(hash)
|
||||
)).done([=](const MTPmessages_RecentStickers &result) {
|
||||
_session->data().stickers().setLastRecentUpdate(crl::now());
|
||||
_recentStickersUpdateRequest = 0;
|
||||
finish();
|
||||
|
||||
switch (result.type()) {
|
||||
case mtpc_messages_recentStickersNotModified: return;
|
||||
case mtpc_messages_recentStickers: {
|
||||
auto &d = result.c_messages_recentStickers();
|
||||
_session->data().stickers().specialSetReceived(
|
||||
Data::Stickers::CloudRecentSetId,
|
||||
attached
|
||||
? Data::Stickers::CloudRecentAttachedSetId
|
||||
: Data::Stickers::CloudRecentSetId,
|
||||
tr::lng_recent_stickers(tr::now),
|
||||
d.vstickers().v,
|
||||
d.vhash().v,
|
||||
@@ -3039,8 +3188,7 @@ void ApiWrap::requestRecentStickersWithHash(int32 hash) {
|
||||
default: Unexpected("Type in ApiWrap::recentStickersDone()");
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_session->data().stickers().setLastRecentUpdate(crl::now());
|
||||
_recentStickersUpdateRequest = 0;
|
||||
finish();
|
||||
|
||||
LOG(("App Fail: Failed to get recent stickers!"));
|
||||
}).send();
|
||||
@@ -3152,7 +3300,7 @@ void ApiWrap::readFeaturedSets() {
|
||||
for (const auto setId : _featuredSetsRead) {
|
||||
const auto it = sets.find(setId);
|
||||
if (it != sets.cend()) {
|
||||
it->second->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
|
||||
it->second->flags &= ~Data::StickersSetFlag::Unread;
|
||||
wrappedIds.append(MTP_long(setId));
|
||||
if (count) {
|
||||
--count;
|
||||
@@ -3726,7 +3874,6 @@ void ApiWrap::forwardMessages(
|
||||
}
|
||||
}
|
||||
const auto newFrom = item->history()->peer;
|
||||
const auto newGroupId = item->groupId();
|
||||
if (forwardFrom != newFrom) {
|
||||
sendAccumulated();
|
||||
forwardFrom = newFrom;
|
||||
@@ -3947,9 +4094,12 @@ void ApiWrap::sendFile(
|
||||
void ApiWrap::sendUploadedPhoto(
|
||||
FullMsgId localId,
|
||||
const MTPInputFile &file,
|
||||
Api::SendOptions options) {
|
||||
Api::SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers) {
|
||||
if (const auto item = _session->data().message(localId)) {
|
||||
const auto media = Api::PrepareUploadedPhoto(file);
|
||||
const auto media = Api::PrepareUploadedPhoto(
|
||||
file,
|
||||
std::move(attachedStickers));
|
||||
if (const auto groupId = item->groupId()) {
|
||||
uploadAlbumMedia(item, groupId, media);
|
||||
} else {
|
||||
@@ -3962,12 +4112,17 @@ void ApiWrap::sendUploadedDocument(
|
||||
FullMsgId localId,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
Api::SendOptions options) {
|
||||
Api::SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers) {
|
||||
if (const auto item = _session->data().message(localId)) {
|
||||
if (!item->media() || !item->media()->document()) {
|
||||
return;
|
||||
}
|
||||
const auto media = Api::PrepareUploadedDocument(item, file, thumb);
|
||||
const auto media = Api::PrepareUploadedDocument(
|
||||
item,
|
||||
file,
|
||||
thumb,
|
||||
std::move(attachedStickers));
|
||||
const auto groupId = item->groupId();
|
||||
if (groupId) {
|
||||
uploadAlbumMedia(item, groupId, media);
|
||||
@@ -4368,6 +4523,8 @@ void ApiWrap::sendMediaWithRandomId(
|
||||
caption.entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
|
||||
const auto updateRecentStickers = Api::HasAttachedStickers(media);
|
||||
|
||||
const auto flags = MTPmessages_SendMedia::Flags(0)
|
||||
| (replyTo
|
||||
? MTPmessages_SendMedia::Flag::f_reply_to_msg_id
|
||||
@@ -4400,6 +4557,10 @@ void ApiWrap::sendMediaWithRandomId(
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
finish();
|
||||
|
||||
if (updateRecentStickers) {
|
||||
requestRecentStickersForce(true);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
finish();
|
||||
|
||||
@@ -20,6 +20,7 @@ struct MessageGroupId;
|
||||
struct SendingAlbum;
|
||||
enum class SendMediaType;
|
||||
struct FileLoadTo;
|
||||
struct ChatRestrictionsInfo;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
@@ -107,7 +108,7 @@ QString RequestKey(Types &&...values) {
|
||||
|
||||
} // namespace Api
|
||||
|
||||
class ApiWrap : public MTP::Sender, private base::Subscriber {
|
||||
class ApiWrap final : public MTP::Sender {
|
||||
public:
|
||||
using SendAction = Api::SendAction;
|
||||
using MessageToSend = Api::MessageToSend;
|
||||
@@ -264,7 +265,7 @@ public:
|
||||
void kickParticipant(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights ¤tRights);
|
||||
ChatRestrictionsInfo currentRights);
|
||||
void unblockParticipant(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> participant);
|
||||
@@ -280,12 +281,14 @@ public:
|
||||
void requestStickerSets();
|
||||
void saveStickerSets(
|
||||
const Data::StickersSetsOrder &localOrder,
|
||||
const Data::StickersSetsOrder &localRemoved);
|
||||
const Data::StickersSetsOrder &localRemoved,
|
||||
bool setsMasks);
|
||||
void updateStickers();
|
||||
void requestRecentStickersForce();
|
||||
void updateMasks();
|
||||
void requestRecentStickersForce(bool attached = false);
|
||||
void setGroupStickerSet(
|
||||
not_null<ChannelData*> megagroup,
|
||||
const MTPInputStickerSet &set);
|
||||
const StickerSetIdentifier &set);
|
||||
std::vector<not_null<DocumentData*>> *stickersByEmoji(
|
||||
not_null<EmojiPtr> emoji);
|
||||
|
||||
@@ -339,12 +342,6 @@ public:
|
||||
not_null<UserData*> user,
|
||||
PhotoId afterId);
|
||||
|
||||
void stickerSetInstalled(uint64 setId) {
|
||||
_stickerSetInstalled.fire_copy(setId);
|
||||
}
|
||||
auto stickerSetInstalled() const {
|
||||
return _stickerSetInstalled.events();
|
||||
}
|
||||
void readFeaturedSetDelayed(uint64 setId);
|
||||
|
||||
void parseChannelParticipants(
|
||||
@@ -410,12 +407,14 @@ public:
|
||||
void sendUploadedPhoto(
|
||||
FullMsgId localId,
|
||||
const MTPInputFile &file,
|
||||
Api::SendOptions options);
|
||||
Api::SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers);
|
||||
void sendUploadedDocument(
|
||||
FullMsgId localId,
|
||||
const MTPInputFile &file,
|
||||
const std::optional<MTPInputFile> &thumb,
|
||||
Api::SendOptions options);
|
||||
Api::SendOptions options,
|
||||
std::vector<MTPInputDocument> attachedStickers);
|
||||
|
||||
void cancelLocalItem(not_null<HistoryItem*> item);
|
||||
|
||||
@@ -542,12 +541,9 @@ private:
|
||||
mtpRequestId req);
|
||||
void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result);
|
||||
|
||||
void stickerSetDisenabled(mtpRequestId requestId);
|
||||
void stickersSaveOrder();
|
||||
|
||||
void requestStickers(TimeId now);
|
||||
void requestRecentStickers(TimeId now);
|
||||
void requestRecentStickersWithHash(int32 hash);
|
||||
void requestStickers(TimeId now, bool masks = false);
|
||||
void requestRecentStickers(TimeId now, bool attached = false);
|
||||
void requestRecentStickersWithHash(int32 hash, bool attached = false);
|
||||
void requestFavedStickers(TimeId now);
|
||||
void requestFeaturedStickers(TimeId now);
|
||||
void requestSavedGifs(TimeId now);
|
||||
@@ -685,12 +681,16 @@ private:
|
||||
base::Timer _draftsSaveTimer;
|
||||
|
||||
base::flat_set<mtpRequestId> _stickerSetDisenableRequests;
|
||||
Data::StickersSetsOrder _stickersOrder;
|
||||
base::flat_set<mtpRequestId> _maskSetDisenableRequests;
|
||||
mtpRequestId _masksReorderRequestId = 0;
|
||||
mtpRequestId _stickersReorderRequestId = 0;
|
||||
mtpRequestId _stickersClearRecentRequestId = 0;
|
||||
mtpRequestId _stickersClearRecentAttachedRequestId = 0;
|
||||
|
||||
mtpRequestId _stickersUpdateRequest = 0;
|
||||
mtpRequestId _masksUpdateRequest = 0;
|
||||
mtpRequestId _recentStickersUpdateRequest = 0;
|
||||
mtpRequestId _recentAttachedStickersUpdateRequest = 0;
|
||||
mtpRequestId _favedStickersUpdateRequest = 0;
|
||||
mtpRequestId _featuredStickersUpdateRequest = 0;
|
||||
mtpRequestId _savedGifsUpdateRequest = 0;
|
||||
@@ -731,8 +731,6 @@ private:
|
||||
|
||||
base::Observable<PeerData*> _fullPeerUpdated;
|
||||
|
||||
rpl::event_stream<uint64> _stickerSetInstalled;
|
||||
|
||||
mtpRequestId _topPromotionRequestId = 0;
|
||||
std::pair<QString, uint32> _topPromotionKey;
|
||||
TimeId _topPromotionNextRequestTime = TimeId(0);
|
||||
|
||||
@@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history.h"
|
||||
#include "history/history_location_manager.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/view/history_view_service_message.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
@@ -28,7 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/update_checker.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "core/application.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
@@ -99,16 +98,6 @@ namespace App {
|
||||
|
||||
void initMedia() {
|
||||
Ui::StartCachedCorners();
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
static auto subscription = Window::Theme::Background()->add_subscription([](const Update &update) {
|
||||
if (update.paletteChanged()) {
|
||||
if (const auto m = App::main()) { // multi good
|
||||
m->updateScrollColors();
|
||||
}
|
||||
HistoryView::serviceColorsUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void deinitMedia() {
|
||||
@@ -282,8 +271,4 @@ namespace App {
|
||||
return result;
|
||||
}
|
||||
|
||||
QPixmap pixmapFromImageInPlace(QImage &&image) {
|
||||
return QPixmap::fromImage(std::move(image), Qt::ColorOnly);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,5 @@ namespace App {
|
||||
constexpr auto kImageSizeLimit = 64 * 1024 * 1024; // Open images up to 64mb jpg/png/gif
|
||||
QImage readImage(QByteArray data, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr);
|
||||
QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, QByteArray *content = 0);
|
||||
QPixmap pixmapFromImageInPlace(QImage &&image);
|
||||
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/openssl_help.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/confirm_phone_box.h" // ExtractPhonePrefix.
|
||||
#include "boxes/photo_crop_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/add_participants_box.h"
|
||||
#include "boxes/peers/edit_participant_box.h"
|
||||
@@ -159,7 +158,7 @@ void ShowAddParticipantsError(
|
||||
auto box = Box<EditAdminBox>(
|
||||
channel,
|
||||
user,
|
||||
MTP_chatAdminRights(MTP_flags(0)),
|
||||
ChatAdminRightsInfo(),
|
||||
QString());
|
||||
box->setSaveCallback(saveCallback);
|
||||
*weak = Ui::show(std::move(box));
|
||||
@@ -466,6 +465,7 @@ void GroupInfoBox::prepare() {
|
||||
|
||||
_photo.create(
|
||||
this,
|
||||
&_navigation->parentController()->window(),
|
||||
((_type == Type::Channel)
|
||||
? tr::lng_create_channel_crop
|
||||
: tr::lng_create_group_crop)(tr::now),
|
||||
|
||||
@@ -145,9 +145,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class SetupChannelBox final
|
||||
: public Ui::BoxContent
|
||||
, private base::Subscriber {
|
||||
class SetupChannelBox final : public Ui::BoxContent {
|
||||
public:
|
||||
SetupChannelBox(
|
||||
QWidget*,
|
||||
@@ -244,9 +242,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class RevokePublicLinkBox final
|
||||
: public Ui::BoxContent
|
||||
, private base::Subscriber {
|
||||
class RevokePublicLinkBox final : public Ui::BoxContent {
|
||||
public:
|
||||
RevokePublicLinkBox(
|
||||
QWidget*,
|
||||
|
||||
@@ -21,7 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "app.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -56,9 +56,7 @@ QImage TakeMiddleSample(QImage original, QSize size) {
|
||||
|
||||
} // namespace
|
||||
|
||||
class BackgroundBox::Inner final
|
||||
: public Ui::RpWidget
|
||||
, private base::Subscriber {
|
||||
class BackgroundBox::Inner final : public Ui::RpWidget {
|
||||
public:
|
||||
Inner(
|
||||
QWidget *parent,
|
||||
@@ -204,16 +202,22 @@ BackgroundBox::Inner::Inner(
|
||||
) | rpl::start_with_next([=] {
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
_check->invalidateCache();
|
||||
}, lifetime());
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
subscribe(Window::Theme::Background(), [=](const Update &update) {
|
||||
if (update.paletteChanged()) {
|
||||
_check->invalidateCache();
|
||||
} else if (update.type == Update::Type::New) {
|
||||
Window::Theme::Background()->updates(
|
||||
) | rpl::start_with_next([=](const Update &update) {
|
||||
if (update.type == Update::Type::New) {
|
||||
sortPapers();
|
||||
requestPapers();
|
||||
this->update();
|
||||
}
|
||||
});
|
||||
}, lifetime());
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
@@ -337,7 +341,7 @@ void BackgroundBox::Inner::validatePaperThumbnail(
|
||||
Data::PatternColor(color),
|
||||
paper.data.patternIntensity());
|
||||
}
|
||||
paper.thumbnail = App::pixmapFromImageInPlace(TakeMiddleSample(
|
||||
paper.thumbnail = Ui::PixmapFromImage(TakeMiddleSample(
|
||||
original,
|
||||
st::backgroundSize));
|
||||
paper.thumbnail.setDevicePixelRatio(cRetinaFactor());
|
||||
|
||||
@@ -29,7 +29,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/background_preview_box.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -100,12 +99,10 @@ private:
|
||||
};
|
||||
|
||||
ServiceCheck::Generator::Generator() {
|
||||
*_lifetime.make_state<base::Subscription>() = Window::Theme::Background(
|
||||
)->add_subscription([=](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
invalidate();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
auto ServiceCheck::Generator::framesForStyle(
|
||||
@@ -399,7 +396,7 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const Data::WallPaper &paper)
|
||||
: SimpleElementDelegate(controller)
|
||||
: SimpleElementDelegate(controller, [=] { update(); })
|
||||
, _controller(controller)
|
||||
, _text1(GenerateTextItem(
|
||||
delegate(),
|
||||
@@ -688,8 +685,8 @@ void BackgroundPreviewBox::setScaledFromImage(
|
||||
if (!_full.isNull()) {
|
||||
startFadeInFrom(std::move(_scaled));
|
||||
}
|
||||
_scaled = App::pixmapFromImageInPlace(std::move(image));
|
||||
_blurred = App::pixmapFromImageInPlace(std::move(blurred));
|
||||
_scaled = Ui::PixmapFromImage(std::move(image));
|
||||
_blurred = Ui::PixmapFromImage(std::move(blurred));
|
||||
if (_blur && (!_paper.document() || !_full.isNull())) {
|
||||
_blur->setDisabled(false);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "base/binary_guard.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "history/admin_log/history_admin_log_item.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "data/data_wall_paper.h"
|
||||
|
||||
namespace Data {
|
||||
class DocumentMedia;
|
||||
@@ -29,8 +29,7 @@ class Checkbox;
|
||||
|
||||
class BackgroundPreviewBox
|
||||
: public Ui::BoxContent
|
||||
, private HistoryView::SimpleElementDelegate
|
||||
, private base::Subscriber {
|
||||
, private HistoryView::SimpleElementDelegate {
|
||||
public:
|
||||
BackgroundPreviewBox(
|
||||
QWidget*,
|
||||
|
||||
@@ -76,10 +76,6 @@ defaultFeedUserpicButton: FeedUserpicButton {
|
||||
innerPart: defaultUserpicButton;
|
||||
}
|
||||
|
||||
cropPointSize: 10px;
|
||||
cropSkip: 13px;
|
||||
cropMinSize: 20px;
|
||||
|
||||
confirmInviteTitle: FlatLabel(defaultFlatLabel) {
|
||||
align: align(center);
|
||||
minWidth: 320px;
|
||||
@@ -386,6 +382,7 @@ confirmCaptionArea: InputField(defaultInputField) {
|
||||
textMargins: margins(1px, 26px, 31px, 4px);
|
||||
heightMax: 158px;
|
||||
}
|
||||
confirmEditCaptionAreaHeightMax: 78px;
|
||||
confirmBg: windowBgOver;
|
||||
confirmMaxHeight: 245px;
|
||||
confirmMaxHeightSkip: 25px;
|
||||
@@ -427,33 +424,42 @@ backgroundScroll: ScrollArea(boxScroll) {
|
||||
deltab: 10px;
|
||||
}
|
||||
|
||||
editMediaButtonSize: 28px;
|
||||
editMediaButtonSkip: 8px;
|
||||
sendMediaPreviewSize: 308px;
|
||||
sendMediaPreviewHeightMax: 1280;
|
||||
sendMediaRowSkip: 10px;
|
||||
|
||||
editMediaButtonSize: 32px;
|
||||
editMediaButtonSkip: 5px;
|
||||
editMediaButtonFileSkipRight: 1px;
|
||||
editMediaButtonFileSkipTop: 7px;
|
||||
|
||||
editMediaButtonIconFile: icon {{ "settings_edit", menuIconFg }};
|
||||
editMediaButtonIconPhoto: icon {{ "settings_edit", roundedFg }};
|
||||
editMediaButton: IconButton {
|
||||
editMediaButtonIconFile: icon {{ "send_media/send_media_replace", menuIconFg }};
|
||||
editMediaButton: IconButton(defaultIconButton) {
|
||||
width: editMediaButtonSize;
|
||||
height: editMediaButtonSize;
|
||||
|
||||
icon: editMediaButtonIconPhoto;
|
||||
icon: editMediaButtonIconFile;
|
||||
|
||||
rippleAreaSize: editMediaButtonSize;
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
|
||||
editMediaHintLabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
minWidth: sendMediaPreviewSize;
|
||||
}
|
||||
|
||||
// SendFilesBox
|
||||
|
||||
sendBoxAlbumGroupEditInternalSkip: 8px;
|
||||
sendBoxAlbumGroupSkipRight: 6px;
|
||||
sendBoxAlbumGroupSkipTop: 6px;
|
||||
sendBoxAlbumGroupRadius: 13px;
|
||||
sendBoxAlbumGroupHeight: 26px;
|
||||
sendBoxAlbumGroupSkipRight: 5px;
|
||||
sendBoxAlbumGroupSkipTop: 5px;
|
||||
sendBoxAlbumGroupRadius: 4px;
|
||||
sendBoxAlbumGroupSize: size(62px, 25px);
|
||||
sendBoxAlbumSmallGroupSize: size(30px, 25px);
|
||||
|
||||
sendBoxFileGroupSkipTop: 2px;
|
||||
sendBoxFileGroupSkipRight: 8px;
|
||||
sendBoxFileGroupSkipRight: 5px;
|
||||
sendBoxFileGroupEditInternalSkip: -1px;
|
||||
|
||||
sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) {
|
||||
@@ -462,16 +468,11 @@ sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) {
|
||||
}
|
||||
}
|
||||
sendBoxAlbumGroupEditButtonIconFile: editMediaButtonIconFile;
|
||||
sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "history_file_cancel", menuIconFg, point(6px, 6px) }};
|
||||
sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "send_media/send_media_delete", menuIconFg }};
|
||||
|
||||
sendBoxAlbumGroupButtonMediaEdit: icon {{ "settings_edit", roundedFg, point(3px, -2px) }};
|
||||
sendBoxAlbumGroupButtonMediaDelete: icon {{ "history_file_cancel", roundedFg, point(2px, 5px) }};
|
||||
sendBoxAlbumGroupButtonMedia: IconButton {
|
||||
width: sendBoxAlbumGroupHeight;
|
||||
height: sendBoxAlbumGroupHeight;
|
||||
|
||||
icon: sendBoxAlbumGroupButtonMediaEdit;
|
||||
}
|
||||
sendBoxAlbumButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg }};
|
||||
sendBoxAlbumGroupButtonMediaEdit: icon {{ "send_media/send_media_replace", roundedFg, point(4px, 1px) }};
|
||||
sendBoxAlbumGroupButtonMediaDelete: icon {{ "send_media/send_media_delete", roundedFg }};
|
||||
|
||||
// End of SendFilesBox
|
||||
|
||||
@@ -523,6 +524,7 @@ usernameTextStyle: TextStyle(boxTextStyle, passcodeTextStyle) {
|
||||
}
|
||||
usernameDefaultFg: windowSubTextFg;
|
||||
|
||||
editMediaLabelMargins: margins(0px, 11px, 0px, 0px);
|
||||
editMediaCheckboxMargins: margins(0px, 15px, 23px, 15px);
|
||||
|
||||
downloadPathSkip: 10px;
|
||||
@@ -649,10 +651,6 @@ groupStickersField: InputField(defaultMultiSelectSearchField) {
|
||||
}
|
||||
groupStickersSubTitleHeight: 36px;
|
||||
|
||||
sendMediaPreviewSize: 308px;
|
||||
sendMediaPreviewHeightMax: 1280;
|
||||
sendMediaRowSkip: 10px;
|
||||
|
||||
proxyUsePadding: margins(22px, 6px, 22px, 5px);
|
||||
proxyTryIPv6Padding: margins(22px, 8px, 22px, 5px);
|
||||
proxyRowPadding: margins(22px, 8px, 8px, 8px);
|
||||
|
||||
@@ -901,7 +901,7 @@ void DeleteMessagesBox::deleteAndClear() {
|
||||
_moderateInChannel->session().api().kickParticipant(
|
||||
_moderateInChannel,
|
||||
_moderateFrom,
|
||||
ChannelData::EmptyRestrictedRights(_moderateFrom));
|
||||
ChatRestrictionsInfo());
|
||||
}
|
||||
if (_reportSpam->checked()) {
|
||||
_moderateInChannel->session().api().request(
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class MaxInviteBox : public Ui::BoxContent, private base::Subscriber {
|
||||
class MaxInviteBox final : public Ui::BoxContent {
|
||||
public:
|
||||
MaxInviteBox(QWidget*, not_null<ChannelData*> channel);
|
||||
|
||||
|
||||
@@ -436,7 +436,6 @@ void Options::Option::updateFieldGeometry() {
|
||||
const auto skip = st::defaultRadio.diameter
|
||||
+ st::defaultCheckbox.textPosition.x();
|
||||
const auto left = anim::interpolate(0, skip, shown);
|
||||
const auto width = _content->width() - left;
|
||||
_field->resizeToWidth(_content->width() - left);
|
||||
_field->moveToLeft(left, 0);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
|
||||
class Image;
|
||||
|
||||
namespace ChatHelpers {
|
||||
class TabbedPanel;
|
||||
} // namespace ChatHelpers
|
||||
@@ -23,34 +19,19 @@ class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Data {
|
||||
class Media;
|
||||
class PhotoMedia;
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Ui {
|
||||
class AbstractSinglePreview;
|
||||
class InputField;
|
||||
class EmojiButton;
|
||||
class IconButton;
|
||||
class Checkbox;
|
||||
class VerticalLayout;
|
||||
class FadeShadow;
|
||||
enum class AlbumType;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Media {
|
||||
namespace Streaming {
|
||||
class Instance;
|
||||
class Document;
|
||||
struct Update;
|
||||
enum class Error;
|
||||
struct Information;
|
||||
} // namespace Streaming
|
||||
} // namespace Media
|
||||
|
||||
class EditCaptionBox final : public Ui::BoxContent, private base::Subscriber {
|
||||
class EditCaptionBox final : public Ui::BoxContent {
|
||||
public:
|
||||
EditCaptionBox(
|
||||
QWidget*,
|
||||
@@ -67,15 +48,15 @@ protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
void rebuildPreview();
|
||||
void setupEditEventHandler();
|
||||
void setupPhotoEditorEventHandler();
|
||||
void setupShadows();
|
||||
void setupField();
|
||||
void setupControls();
|
||||
|
||||
void updateBoxSize();
|
||||
void prepareStreamedPreview();
|
||||
void checkStreamedIsStarted();
|
||||
void setupStreamedPreview(
|
||||
std::shared_ptr<::Media::Streaming::Document> shared);
|
||||
void handleStreamingUpdate(::Media::Streaming::Update &&update);
|
||||
void handleStreamingError(::Media::Streaming::Error &&error);
|
||||
void streamingReady(::Media::Streaming::Information &&info);
|
||||
void startStreamedPlayer();
|
||||
void captionResized();
|
||||
|
||||
void setupEmojiPanel();
|
||||
void updateEmojiPanelGeometry();
|
||||
@@ -84,69 +65,43 @@ private:
|
||||
void setupDragArea();
|
||||
|
||||
void save();
|
||||
void captionResized();
|
||||
|
||||
void setName(QString nameString, qint64 size);
|
||||
bool fileFromClipboard(not_null<const QMimeData*> data);
|
||||
void updateEditPreview();
|
||||
void updateEditMediaButton();
|
||||
|
||||
int errorTopSkip() const;
|
||||
|
||||
void createEditMediaButton();
|
||||
bool setPreparedList(Ui::PreparedList &&list);
|
||||
|
||||
bool isThumbedLayout() const;
|
||||
|
||||
inline QString getNewMediaPath() {
|
||||
return _preparedList.files.empty()
|
||||
? QString()
|
||||
: _preparedList.files.front().path;
|
||||
}
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<HistoryItem*> _historyItem;
|
||||
const bool _isAllowedEditMedia = false;
|
||||
const Ui::AlbumType _albumType;
|
||||
|
||||
FullMsgId _msgId;
|
||||
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
||||
bool _thumbnailImageLoaded = false;
|
||||
Fn<void()> _refreshThumbnail;
|
||||
bool _animated = false;
|
||||
bool _photo = false;
|
||||
bool _doc = false;
|
||||
const base::unique_qptr<Ui::VerticalLayout> _controls;
|
||||
const base::unique_qptr<Ui::ScrollArea> _scroll;
|
||||
const base::unique_qptr<Ui::InputField> _field;
|
||||
const base::unique_qptr<Ui::EmojiButton> _emojiToggle;
|
||||
const base::unique_qptr<Ui::FadeShadow> _topShadow,_bottomShadow;
|
||||
|
||||
QPixmap _thumb;
|
||||
std::unique_ptr<::Media::Streaming::Instance> _streamed;
|
||||
|
||||
object_ptr<Ui::InputField> _field = { nullptr };
|
||||
object_ptr<Ui::EmojiButton> _emojiToggle = { nullptr };
|
||||
base::unique_qptr<Ui::AbstractSinglePreview> _content;
|
||||
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
||||
base::unique_qptr<QObject> _emojiFilter;
|
||||
|
||||
int _thumbx = 0;
|
||||
int _thumbw = 0;
|
||||
int _thumbh = 0;
|
||||
Ui::Text::String _name;
|
||||
QString _status;
|
||||
bool _isAudio = false;
|
||||
bool _isImage = false;
|
||||
|
||||
int _gifw = 0;
|
||||
int _gifh = 0;
|
||||
int _gifx = 0;
|
||||
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||
|
||||
Ui::PreparedList _preparedList;
|
||||
|
||||
mtpRequestId _saveRequestId = 0;
|
||||
|
||||
object_ptr<Ui::IconButton> _editMedia = nullptr;
|
||||
Ui::SlideWrap<Ui::RpWidget> *_wayWrap = nullptr;
|
||||
QString _newMediaPath;
|
||||
Ui::AlbumType _albumType = Ui::AlbumType();
|
||||
bool _isAllowedEditMedia = false;
|
||||
bool _asFile = false;
|
||||
rpl::event_stream<> _editMediaClicks;
|
||||
|
||||
QString _error;
|
||||
|
||||
rpl::variable<bool> _isPhoto = false;
|
||||
rpl::variable<int> _footerHeight = 0;
|
||||
|
||||
rpl::event_stream<> _editMediaClicks;
|
||||
rpl::event_stream<> _photoEditorOpens;
|
||||
rpl::event_stream<int> _contentHeight;
|
||||
|
||||
};
|
||||
|
||||
@@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_media_view.h"
|
||||
|
||||
@@ -423,7 +422,7 @@ void EditColorBox::Slider::generatePixmap() {
|
||||
if (!isHorizontal()) {
|
||||
image = std::move(image).transformed(QTransform(0, -1, 1, 0, 0, 0));
|
||||
}
|
||||
_pixmap = App::pixmapFromImageInPlace(std::move(image));
|
||||
_pixmap = Ui::PixmapFromImage(std::move(image));
|
||||
} else if (_type == Type::Opacity) {
|
||||
auto color = anim::shifted(QColor(255, 255, 255, 255));
|
||||
auto transparent = anim::shifted(QColor(255, 255, 255, 0));
|
||||
@@ -459,7 +458,7 @@ void EditColorBox::Slider::generatePixmap() {
|
||||
if (!isHorizontal()) {
|
||||
image = std::move(image).transformed(QTransform(0, -1, 1, 0, 0, 0));
|
||||
}
|
||||
_pixmap = App::pixmapFromImageInPlace(std::move(image));
|
||||
_pixmap = Ui::PixmapFromImage(std::move(image));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,7 +529,7 @@ void EditColorBox::Slider::setLightnessLimits(int min, int max) {
|
||||
}
|
||||
|
||||
void EditColorBox::Slider::updatePixmapFromMask() {
|
||||
_pixmap = App::pixmapFromImageInPlace(style::colorizeImage(_mask, _color));
|
||||
_pixmap = Ui::PixmapFromImage(style::colorizeImage(_mask, _color));
|
||||
}
|
||||
|
||||
void EditColorBox::Slider::updateCurrentPoint(QPoint localPosition) {
|
||||
|
||||
@@ -216,7 +216,6 @@ std::pair<Languages, Languages> PrepareLists() {
|
||||
Lang::GetInstance().nativeName()
|
||||
};
|
||||
};
|
||||
const auto i = ranges::find(official, current, projId);
|
||||
recent.insert(begin(recent), generate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,7 +516,7 @@ void LocalStorageBox::updateMediaLabel() {
|
||||
}
|
||||
|
||||
void LocalStorageBox::setupLimits(not_null<Ui::VerticalLayout*> container) {
|
||||
const auto shadow = container->add(
|
||||
container->add(
|
||||
object_ptr<Ui::PlainShadow>(container),
|
||||
st::localStorageRowPadding);
|
||||
|
||||
|
||||
@@ -1062,7 +1062,9 @@ void RecoverBox::submit() {
|
||||
|
||||
const auto send = crl::guard(this, [=] {
|
||||
_submitRequest = _api.request(MTPauth_RecoverPassword(
|
||||
MTP_string(code)
|
||||
MTP_flags(0),
|
||||
MTP_string(code),
|
||||
MTPaccount_PasswordInputSettings()
|
||||
)).done([=](const MTPauth_Authorization &result) {
|
||||
codeSubmitDone(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
|
||||
@@ -25,7 +25,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
@@ -738,11 +737,11 @@ PeerListContent::PeerListContent(
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
invalidatePixmapsCache();
|
||||
}
|
||||
});
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
invalidatePixmapsCache();
|
||||
}, lifetime());
|
||||
|
||||
_repaintByStatus.setCallback([this] { update(); });
|
||||
}
|
||||
|
||||
|
||||
@@ -527,9 +527,7 @@ struct PeerListState {
|
||||
QString searchQuery;
|
||||
};
|
||||
|
||||
class PeerListContent
|
||||
: public Ui::RpWidget
|
||||
, private base::Subscriber {
|
||||
class PeerListContent : public Ui::RpWidget {
|
||||
public:
|
||||
PeerListContent(
|
||||
QWidget *parent,
|
||||
|
||||
@@ -516,7 +516,7 @@ bool AddBotToGroupBoxController::needToCreateRow(
|
||||
not_null<PeerData*> peer) const {
|
||||
if (sharingBotGame()) {
|
||||
if (!peer->canWrite()
|
||||
|| peer->amRestricted(ChatRestriction::f_send_games)) {
|
||||
|| peer->amRestricted(ChatRestriction::SendGames)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -626,7 +626,7 @@ void AddSpecialBoxController::showAdmin(
|
||||
// Finally show the admin.
|
||||
const auto currentRights = adminRights
|
||||
? *adminRights
|
||||
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
|
||||
: ChatAdminRightsInfo();
|
||||
auto box = Box<EditAdminBox>(
|
||||
_peer,
|
||||
user,
|
||||
@@ -634,7 +634,7 @@ void AddSpecialBoxController::showAdmin(
|
||||
_additional.adminRank(user));
|
||||
if (_additional.canAddOrEditAdmin(user)) {
|
||||
const auto done = crl::guard(this, [=](
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank) {
|
||||
editAdminDone(user, newRights, rank);
|
||||
});
|
||||
@@ -650,7 +650,7 @@ void AddSpecialBoxController::showAdmin(
|
||||
|
||||
void AddSpecialBoxController::editAdminDone(
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &rights,
|
||||
ChatAdminRightsInfo rights,
|
||||
const QString &rank) {
|
||||
if (_editParticipantBox) {
|
||||
_editParticipantBox->closeBox();
|
||||
@@ -662,9 +662,11 @@ void AddSpecialBoxController::editAdminDone(
|
||||
_additional.applyParticipant(MTP_channelParticipantCreator(
|
||||
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
|
||||
peerToBareMTPInt(user->id),
|
||||
rights,
|
||||
MTP_chatAdminRights(
|
||||
MTP_flags(MTPDchatAdminRights::Flags::from_raw(
|
||||
uint32(rights.flags)))),
|
||||
MTP_string(rank)));
|
||||
} else if (rights.c_chatAdminRights().vflags().v == 0) {
|
||||
} else if (!rights.flags) {
|
||||
_additional.applyParticipant(MTP_channelParticipant(
|
||||
peerToBareMTPInt(user->id),
|
||||
MTP_int(date)));
|
||||
@@ -680,7 +682,9 @@ void AddSpecialBoxController::editAdminDone(
|
||||
? alreadyPromotedBy->id
|
||||
: user->session().userPeerId()),
|
||||
MTP_int(date),
|
||||
rights,
|
||||
MTP_chatAdminRights(
|
||||
MTP_flags(MTPDchatAdminRights::Flags::from_raw(
|
||||
uint32(rights.flags)))),
|
||||
MTP_string(rank)));
|
||||
}
|
||||
if (const auto callback = _adminDoneCallback) {
|
||||
@@ -730,7 +734,7 @@ void AddSpecialBoxController::showRestricted(
|
||||
// Finally edit the restricted.
|
||||
const auto currentRights = restrictedRights
|
||||
? *restrictedRights
|
||||
: ChannelData::EmptyRestrictedRights(user);
|
||||
: ChatRestrictionsInfo();
|
||||
auto box = Box<EditRestrictedBox>(
|
||||
_peer,
|
||||
user,
|
||||
@@ -738,7 +742,7 @@ void AddSpecialBoxController::showRestricted(
|
||||
currentRights);
|
||||
if (_additional.canRestrictParticipant(user)) {
|
||||
const auto done = crl::guard(this, [=](
|
||||
const MTPChatBannedRights &newRights) {
|
||||
ChatRestrictionsInfo newRights) {
|
||||
editRestrictedDone(user, newRights);
|
||||
});
|
||||
const auto fail = crl::guard(this, [=] {
|
||||
@@ -754,13 +758,13 @@ void AddSpecialBoxController::showRestricted(
|
||||
|
||||
void AddSpecialBoxController::editRestrictedDone(
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights &rights) {
|
||||
ChatRestrictionsInfo rights) {
|
||||
if (_editParticipantBox) {
|
||||
_editParticipantBox->closeBox();
|
||||
}
|
||||
|
||||
const auto date = base::unixtime::now(); // Incorrect, but ignored.
|
||||
if (Data::ChatBannedRightsFlags(rights) == 0) {
|
||||
if (!rights.flags) {
|
||||
if (const auto user = participant->asUser()) {
|
||||
_additional.applyParticipant(MTP_channelParticipant(
|
||||
peerToBareMTPInt(user->id),
|
||||
@@ -769,8 +773,7 @@ void AddSpecialBoxController::editRestrictedDone(
|
||||
_additional.setExternal(participant);
|
||||
}
|
||||
} else {
|
||||
const auto kicked = Data::ChatBannedRightsFlags(rights)
|
||||
& ChatRestriction::f_view_messages;
|
||||
const auto kicked = rights.flags & ChatRestriction::ViewMessages;
|
||||
const auto alreadyRestrictedBy = _additional.restrictedBy(
|
||||
participant);
|
||||
_additional.applyParticipant(MTP_channelParticipantBanned(
|
||||
@@ -782,7 +785,10 @@ void AddSpecialBoxController::editRestrictedDone(
|
||||
? alreadyRestrictedBy->id
|
||||
: participant->session().userPeerId()),
|
||||
MTP_int(date),
|
||||
rights));
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(MTPDchatBannedRights::Flags::from_raw(
|
||||
uint32(rights.flags))),
|
||||
MTP_int(rights.until))));
|
||||
}
|
||||
if (const auto callback = _bannedDoneCallback) {
|
||||
callback(participant, rights);
|
||||
@@ -839,10 +845,10 @@ void AddSpecialBoxController::kickUser(
|
||||
const auto restrictedRights = _additional.restrictedRights(participant);
|
||||
const auto currentRights = restrictedRights
|
||||
? *restrictedRights
|
||||
: ChannelData::EmptyRestrictedRights(participant);
|
||||
: ChatRestrictionsInfo();
|
||||
|
||||
const auto done = crl::guard(this, [=](
|
||||
const MTPChatBannedRights &newRights) {
|
||||
ChatRestrictionsInfo newRights) {
|
||||
editRestrictedDone(participant, newRights);
|
||||
});
|
||||
const auto fail = crl::guard(this, [=] {
|
||||
|
||||
@@ -10,6 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
|
||||
struct ChatAdminRightsInfo;
|
||||
struct ChatRestrictionsInfo;
|
||||
|
||||
namespace Window {
|
||||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
@@ -70,18 +73,17 @@ private:
|
||||
// with search + contacts search + global search.
|
||||
class AddSpecialBoxController
|
||||
: public PeerListController
|
||||
, private base::Subscriber
|
||||
, public base::has_weak_ptr {
|
||||
public:
|
||||
using Role = ParticipantsBoxController::Role;
|
||||
|
||||
using AdminDoneCallback = Fn<void(
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &adminRights,
|
||||
ChatAdminRightsInfo adminRights,
|
||||
const QString &rank)>;
|
||||
using BannedDoneCallback = Fn<void(
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights &bannedRights)>;
|
||||
ChatRestrictionsInfo bannedRights)>;
|
||||
AddSpecialBoxController(
|
||||
not_null<PeerData*> peer,
|
||||
Role role,
|
||||
@@ -109,12 +111,12 @@ private:
|
||||
void showAdmin(not_null<UserData*> user, bool sure = false);
|
||||
void editAdminDone(
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &rights,
|
||||
ChatAdminRightsInfo rights,
|
||||
const QString &rank);
|
||||
void showRestricted(not_null<UserData*> user, bool sure = false);
|
||||
void editRestrictedDone(
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights &rights);
|
||||
ChatRestrictionsInfo rights);
|
||||
void kickUser(not_null<PeerData*> participant, bool sure = false);
|
||||
bool appendRow(not_null<PeerData*> participant);
|
||||
bool prependRow(not_null<UserData*> user);
|
||||
@@ -143,9 +145,7 @@ protected:
|
||||
};
|
||||
|
||||
// Finds chat/channel members, then contacts, then global search results.
|
||||
class AddSpecialBoxSearchController
|
||||
: public PeerListSearchController
|
||||
, private base::Subscriber {
|
||||
class AddSpecialBoxSearchController : public PeerListSearchController {
|
||||
public:
|
||||
using Role = ParticipantsBoxController::Role;
|
||||
|
||||
|
||||
@@ -60,10 +60,9 @@ void SendRequest(
|
||||
user->username);
|
||||
user->session().api().applyUpdates(result);
|
||||
if (const auto settings = user->settings()) {
|
||||
using Flag = MTPDpeerSettings::Flag;
|
||||
const auto flags = Flag::f_add_contact
|
||||
| Flag::f_block_contact
|
||||
| Flag::f_report_spam;
|
||||
const auto flags = PeerSetting::AddContact
|
||||
| PeerSetting::BlockContact
|
||||
| PeerSetting::ReportSpam;
|
||||
user->setSettings(*settings & ~flags);
|
||||
}
|
||||
if (box) {
|
||||
@@ -241,9 +240,8 @@ void Controller::setupWarning() {
|
||||
|
||||
void Controller::setupSharePhoneNumber() {
|
||||
const auto settings = _user->settings();
|
||||
using Setting = MTPDpeerSettings::Flag;
|
||||
if (!settings
|
||||
|| !((*settings) & Setting::f_need_contacts_exception)) {
|
||||
|| !((*settings) & PeerSetting::NeedContactsException)) {
|
||||
return;
|
||||
}
|
||||
_sharePhone = _box->addRow(
|
||||
|
||||
@@ -197,43 +197,45 @@ EditAdminBox::EditAdminBox(
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &rights,
|
||||
ChatAdminRightsInfo rights,
|
||||
const QString &rank)
|
||||
: EditParticipantBox(
|
||||
nullptr,
|
||||
peer,
|
||||
user,
|
||||
(rights.c_chatAdminRights().vflags().v != 0))
|
||||
(rights.flags != 0))
|
||||
, _oldRights(rights)
|
||||
, _oldRank(rank) {
|
||||
}
|
||||
|
||||
MTPChatAdminRights EditAdminBox::defaultRights() const {
|
||||
const auto flags = peer()->isChat()
|
||||
ChatAdminRightsInfo EditAdminBox::defaultRights() const {
|
||||
using Flag = ChatAdminRight;
|
||||
|
||||
return peer()->isChat()
|
||||
? peer()->asChat()->defaultAdminRights(user())
|
||||
: peer()->isMegagroup()
|
||||
? (Flag::f_change_info
|
||||
| Flag::f_delete_messages
|
||||
| Flag::f_ban_users
|
||||
| Flag::f_invite_users
|
||||
| Flag::f_pin_messages
|
||||
| Flag::f_manage_call)
|
||||
: (Flag::f_change_info
|
||||
| Flag::f_post_messages
|
||||
| Flag::f_edit_messages
|
||||
| Flag::f_delete_messages
|
||||
| Flag::f_invite_users
|
||||
| Flag::f_manage_call);
|
||||
return MTP_chatAdminRights(MTP_flags(flags));
|
||||
? ChatAdminRightsInfo{ (Flag::ChangeInfo
|
||||
| Flag::DeleteMessages
|
||||
| Flag::BanUsers
|
||||
| Flag::InviteUsers
|
||||
| Flag::PinMessages
|
||||
| Flag::ManageCall) }
|
||||
: ChatAdminRightsInfo{ (Flag::ChangeInfo
|
||||
| Flag::PostMessages
|
||||
| Flag::EditMessages
|
||||
| Flag::DeleteMessages
|
||||
| Flag::InviteUsers
|
||||
| Flag::ManageCall) };
|
||||
}
|
||||
|
||||
void EditAdminBox::prepare() {
|
||||
using namespace rpl::mappers;
|
||||
using Flag = ChatAdminRight;
|
||||
using Flags = ChatAdminRights;
|
||||
|
||||
EditParticipantBox::prepare();
|
||||
|
||||
auto hadRights = _oldRights.c_chatAdminRights().vflags().v;
|
||||
setTitle(hadRights
|
||||
setTitle(_oldRights.flags
|
||||
? tr::lng_rights_edit_admin()
|
||||
: tr::lng_channel_add_admin());
|
||||
|
||||
@@ -243,16 +245,18 @@ void EditAdminBox::prepare() {
|
||||
|
||||
const auto chat = peer()->asChat();
|
||||
const auto channel = peer()->asChannel();
|
||||
const auto prepareRights = hadRights ? _oldRights : defaultRights();
|
||||
const auto prepareRights = _oldRights.flags
|
||||
? _oldRights
|
||||
: defaultRights();
|
||||
const auto disabledByDefaults = (channel && !channel->isMegagroup())
|
||||
? MTPDchatAdminRights::Flags(0)
|
||||
? ChatAdminRights()
|
||||
: DisabledByDefaultRestrictions(peer());
|
||||
const auto filterByMyRights = canSave()
|
||||
&& !hadRights
|
||||
&& !_oldRights.flags
|
||||
&& channel
|
||||
&& !channel->amCreator();
|
||||
const auto prepareFlags = disabledByDefaults
|
||||
| (prepareRights.c_chatAdminRights().vflags().v
|
||||
| (prepareRights.flags
|
||||
& (filterByMyRights ? channel->adminRights() : ~Flag(0)));
|
||||
|
||||
const auto disabledMessages = [&] {
|
||||
@@ -267,7 +271,7 @@ void EditAdminBox::prepare() {
|
||||
tr::lng_rights_permission_for_all(tr::now));
|
||||
if (amCreator() && user()->isSelf()) {
|
||||
result.emplace(
|
||||
~Flag::f_anonymous,
|
||||
~Flag::Anonymous,
|
||||
tr::lng_rights_permission_cant_edit(tr::now));
|
||||
} else if (const auto channel = peer()->asChannel()) {
|
||||
if (!channel->amCreator()) {
|
||||
@@ -304,7 +308,7 @@ void EditAdminBox::prepare() {
|
||||
rpl::duplicate(
|
||||
selectedFlags
|
||||
) | rpl::map(
|
||||
(_1 & Flag::f_add_admins) != 0
|
||||
(_1 & Flag::AddAdmins) != 0
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
refreshAboutAddAdminsText(checked);
|
||||
@@ -330,13 +334,13 @@ void EditAdminBox::prepare() {
|
||||
if (!_saveCallback) {
|
||||
return;
|
||||
}
|
||||
const auto newFlags = (value() | ChatAdminRight::f_other)
|
||||
const auto newFlags = (value() | ChatAdminRight::Other)
|
||||
& ((!channel || channel->amCreator())
|
||||
? ~Flags(0)
|
||||
: channel->adminRights());
|
||||
_saveCallback(
|
||||
_oldRights,
|
||||
MTP_chatAdminRights(MTP_flags(newFlags)),
|
||||
ChatAdminRightsInfo(newFlags),
|
||||
rank ? rank->getLastText().trimmed() : QString());
|
||||
});
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
@@ -593,12 +597,15 @@ EditRestrictedBox::EditRestrictedBox(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
bool hasAdminRights,
|
||||
const MTPChatBannedRights &rights)
|
||||
ChatRestrictionsInfo rights)
|
||||
: EditParticipantBox(nullptr, peer, user, hasAdminRights)
|
||||
, _oldRights(rights) {
|
||||
}
|
||||
|
||||
void EditRestrictedBox::prepare() {
|
||||
using Flag = ChatRestriction;
|
||||
using Flags = ChatRestrictions;
|
||||
|
||||
EditParticipantBox::prepare();
|
||||
|
||||
setTitle(tr::lng_rights_user_restrictions());
|
||||
@@ -612,14 +619,14 @@ void EditRestrictedBox::prepare() {
|
||||
const auto defaultRestrictions = chat
|
||||
? chat->defaultRestrictions()
|
||||
: channel->defaultRestrictions();
|
||||
const auto prepareRights = Data::ChatBannedRightsFlags(_oldRights)
|
||||
const auto prepareRights = _oldRights.flags
|
||||
? _oldRights
|
||||
: defaultRights();
|
||||
const auto prepareFlags = FixDependentRestrictions(
|
||||
Data::ChatBannedRightsFlags(prepareRights)
|
||||
prepareRights.flags
|
||||
| defaultRestrictions
|
||||
| ((channel && channel->isPublic())
|
||||
? (Flag::f_change_info | Flag::f_pin_messages)
|
||||
? (Flag::ChangeInfo | Flag::PinMessages)
|
||||
: Flags(0)));
|
||||
const auto disabledMessages = [&] {
|
||||
auto result = std::map<Flags, QString>();
|
||||
@@ -631,7 +638,7 @@ void EditRestrictedBox::prepare() {
|
||||
const auto disabled = FixDependentRestrictions(
|
||||
defaultRestrictions
|
||||
| ((channel && channel->isPublic())
|
||||
? (Flag::f_change_info | Flag::f_pin_messages)
|
||||
? (Flag::ChangeInfo | Flag::PinMessages)
|
||||
: Flags(0)));
|
||||
result.emplace(
|
||||
disabled,
|
||||
@@ -647,7 +654,7 @@ void EditRestrictedBox::prepare() {
|
||||
disabledMessages);
|
||||
addControl(std::move(checkboxes), QMargins());
|
||||
|
||||
_until = Data::ChatBannedRightsUntilDate(prepareRights);
|
||||
_until = prepareRights.until;
|
||||
addControl(object_ptr<Ui::BoxContentDivider>(this), st::rightsUntilMargin);
|
||||
addControl(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
@@ -670,9 +677,7 @@ void EditRestrictedBox::prepare() {
|
||||
}
|
||||
_saveCallback(
|
||||
_oldRights,
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(value()),
|
||||
MTP_int(getRealUntilValue())));
|
||||
ChatRestrictionsInfo{ value(), getRealUntilValue() });
|
||||
};
|
||||
addButton(tr::lng_settings_save(), save);
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
@@ -681,8 +686,8 @@ void EditRestrictedBox::prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
MTPChatBannedRights EditRestrictedBox::defaultRights() const {
|
||||
return MTP_chatBannedRights(MTP_flags(0), MTP_int(0));
|
||||
ChatRestrictionsInfo EditRestrictedBox::defaultRights() const {
|
||||
return ChatRestrictionsInfo();
|
||||
}
|
||||
|
||||
void EditRestrictedBox::showRestrictUntil() {
|
||||
@@ -767,7 +772,7 @@ void EditRestrictedBox::createUntilVariants() {
|
||||
}
|
||||
};
|
||||
auto addCurrentVariant = [&](TimeId from, TimeId to) {
|
||||
auto oldUntil = Data::ChatBannedRightsUntilDate(_oldRights);
|
||||
auto oldUntil = _oldRights.until;
|
||||
if (oldUntil < _until) {
|
||||
addCustomVariant(oldUntil, from, to);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "base/unique_qptr.h"
|
||||
#include "data/data_peer.h"
|
||||
|
||||
namespace MTP {
|
||||
class Error;
|
||||
@@ -73,13 +74,13 @@ public:
|
||||
QWidget*,
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &rights,
|
||||
ChatAdminRightsInfo rights,
|
||||
const QString &rank);
|
||||
|
||||
void setSaveCallback(
|
||||
Fn<void(
|
||||
MTPChatAdminRights,
|
||||
MTPChatAdminRights,
|
||||
ChatAdminRightsInfo,
|
||||
ChatAdminRightsInfo,
|
||||
const QString &rank)> callback) {
|
||||
_saveCallback = std::move(callback);
|
||||
}
|
||||
@@ -88,10 +89,7 @@ protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
using Flag = MTPDchatAdminRights::Flag;
|
||||
using Flags = MTPDchatAdminRights::Flags;
|
||||
|
||||
[[nodiscard]] MTPChatAdminRights defaultRights() const;
|
||||
[[nodiscard]] ChatAdminRightsInfo defaultRights() const;
|
||||
|
||||
not_null<Ui::InputField*> addRankInput();
|
||||
void transferOwnership();
|
||||
@@ -109,11 +107,11 @@ private:
|
||||
bool canTransferOwnership() const;
|
||||
not_null<Ui::SlideWrap<Ui::RpWidget>*> setupTransferButton(bool isGroup);
|
||||
|
||||
const MTPChatAdminRights _oldRights;
|
||||
const ChatAdminRightsInfo _oldRights;
|
||||
const QString _oldRank;
|
||||
Fn<void(
|
||||
MTPChatAdminRights,
|
||||
MTPChatAdminRights,
|
||||
ChatAdminRightsInfo,
|
||||
ChatAdminRightsInfo,
|
||||
const QString &rank)> _saveCallback;
|
||||
|
||||
QPointer<Ui::FlatLabel> _aboutAddAdmins;
|
||||
@@ -132,10 +130,10 @@ public:
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
bool hasAdminRights,
|
||||
const MTPChatBannedRights &rights);
|
||||
ChatRestrictionsInfo rights);
|
||||
|
||||
void setSaveCallback(
|
||||
Fn<void(MTPChatBannedRights, MTPChatBannedRights)> callback) {
|
||||
Fn<void(ChatRestrictionsInfo, ChatRestrictionsInfo)> callback) {
|
||||
_saveCallback = std::move(callback);
|
||||
}
|
||||
|
||||
@@ -143,10 +141,7 @@ protected:
|
||||
void prepare() override;
|
||||
|
||||
private:
|
||||
using Flag = MTPDchatBannedRights::Flag;
|
||||
using Flags = MTPDchatBannedRights::Flags;
|
||||
|
||||
[[nodiscard]] MTPChatBannedRights defaultRights() const;
|
||||
[[nodiscard]] ChatRestrictionsInfo defaultRights() const;
|
||||
|
||||
bool canSave() const {
|
||||
return !!_saveCallback;
|
||||
@@ -158,9 +153,9 @@ private:
|
||||
void createUntilVariants();
|
||||
TimeId getRealUntilValue() const;
|
||||
|
||||
const MTPChatBannedRights _oldRights;
|
||||
const ChatRestrictionsInfo _oldRights;
|
||||
TimeId _until = 0;
|
||||
Fn<void(MTPChatBannedRights, MTPChatBannedRights)> _saveCallback;
|
||||
Fn<void(ChatRestrictionsInfo, ChatRestrictionsInfo)> _saveCallback;
|
||||
|
||||
std::shared_ptr<Ui::RadiobuttonGroup> _untilGroup;
|
||||
std::vector<base::unique_qptr<Ui::Radiobutton>> _untilVariants;
|
||||
|
||||
@@ -43,7 +43,7 @@ constexpr auto kSortByOnlineDelay = crl::time(1000);
|
||||
void RemoveAdmin(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &oldRights,
|
||||
ChatAdminRightsInfo oldRights,
|
||||
Fn<void()> onDone,
|
||||
Fn<void()> onFail) {
|
||||
const auto newRights = MTP_chatAdminRights(MTP_flags(0));
|
||||
@@ -54,7 +54,7 @@ void RemoveAdmin(
|
||||
MTP_string(QString())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
channel->session().api().applyUpdates(result);
|
||||
channel->applyEditAdmin(user, oldRights, newRights, QString());
|
||||
channel->applyEditAdmin(user, oldRights, ChatAdminRightsInfo(), QString());
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
@@ -120,15 +120,16 @@ void SaveChatAdmin(
|
||||
void SaveChannelAdmin(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &oldRights,
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo oldRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank,
|
||||
Fn<void()> onDone,
|
||||
Fn<void()> onFail) {
|
||||
channel->session().api().request(MTPchannels_EditAdmin(
|
||||
channel->inputChannel,
|
||||
user->inputUser,
|
||||
newRights,
|
||||
MTP_chatAdminRights(MTP_flags(
|
||||
MTPDchatAdminRights::Flags::from_raw(uint32(newRights.flags)))),
|
||||
MTP_string(rank)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
channel->session().api().applyUpdates(result);
|
||||
@@ -147,14 +148,17 @@ void SaveChannelAdmin(
|
||||
void SaveChannelRestriction(
|
||||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights &oldRights,
|
||||
const MTPChatBannedRights &newRights,
|
||||
ChatRestrictionsInfo oldRights,
|
||||
ChatRestrictionsInfo newRights,
|
||||
Fn<void()> onDone,
|
||||
Fn<void()> onFail) {
|
||||
channel->session().api().request(MTPchannels_EditBanned(
|
||||
channel->inputChannel,
|
||||
participant->input,
|
||||
newRights
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(MTPDchatBannedRights::Flags::from_raw(
|
||||
uint32(newRights.flags))),
|
||||
MTP_int(newRights.until))
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
channel->session().api().applyUpdates(result);
|
||||
channel->applyEditBanned(participant, oldRights, newRights);
|
||||
@@ -192,18 +196,18 @@ void SaveChatParticipantKick(
|
||||
} // namespace
|
||||
|
||||
Fn<void(
|
||||
const MTPChatAdminRights &oldRights,
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo oldRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank)> SaveAdminCallback(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
Fn<void(
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank)> onDone,
|
||||
Fn<void()> onFail) {
|
||||
return [=](
|
||||
const MTPChatAdminRights &oldRights,
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo oldRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank) {
|
||||
const auto done = [=] { if (onDone) onDone(newRights, rank); };
|
||||
const auto saveForChannel = [=](not_null<ChannelData*> channel) {
|
||||
@@ -220,13 +224,10 @@ Fn<void(
|
||||
const auto saveChatAdmin = [&](bool isAdmin) {
|
||||
SaveChatAdmin(chat, user, isAdmin, done, onFail);
|
||||
};
|
||||
const auto flags = newRights.match([](
|
||||
const MTPDchatAdminRights &data) {
|
||||
return data.vflags().v;
|
||||
});
|
||||
if (flags == chat->defaultAdminRights(user) && rank.isEmpty()) {
|
||||
if (newRights.flags == chat->defaultAdminRights(user).flags
|
||||
&& rank.isEmpty()) {
|
||||
saveChatAdmin(true);
|
||||
} else if (!flags) {
|
||||
} else if (!newRights.flags) {
|
||||
saveChatAdmin(false);
|
||||
} else {
|
||||
peer->session().api().migrateChat(chat, saveForChannel);
|
||||
@@ -240,15 +241,15 @@ Fn<void(
|
||||
}
|
||||
|
||||
Fn<void(
|
||||
const MTPChatBannedRights &oldRights,
|
||||
const MTPChatBannedRights &newRights)> SaveRestrictedCallback(
|
||||
ChatRestrictionsInfo oldRights,
|
||||
ChatRestrictionsInfo newRights)> SaveRestrictedCallback(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PeerData*> participant,
|
||||
Fn<void(const MTPChatBannedRights &newRights)> onDone,
|
||||
Fn<void(ChatRestrictionsInfo newRights)> onDone,
|
||||
Fn<void()> onFail) {
|
||||
return [=](
|
||||
const MTPChatBannedRights &oldRights,
|
||||
const MTPChatBannedRights &newRights) {
|
||||
ChatRestrictionsInfo oldRights,
|
||||
ChatRestrictionsInfo newRights) {
|
||||
const auto done = [=] { if (onDone) onDone(newRights); };
|
||||
const auto saveForChannel = [=](not_null<ChannelData*> channel) {
|
||||
SaveChannelRestriction(
|
||||
@@ -260,15 +261,14 @@ Fn<void(
|
||||
onFail);
|
||||
};
|
||||
if (const auto chat = peer->asChatNotMigrated()) {
|
||||
const auto flags = Data::ChatBannedRightsFlags(newRights);
|
||||
if (participant->isUser()
|
||||
&& (flags & MTPDchatBannedRights::Flag::f_view_messages)) {
|
||||
&& (newRights.flags & ChatRestriction::ViewMessages)) {
|
||||
SaveChatParticipantKick(
|
||||
chat,
|
||||
participant->asUser(),
|
||||
done,
|
||||
onFail);
|
||||
} else if (!flags) {
|
||||
} else if (!newRights.flags) {
|
||||
done();
|
||||
} else {
|
||||
peer->session().api().migrateChat(chat, saveForChannel);
|
||||
@@ -373,11 +373,10 @@ bool ParticipantsAdditionalData::canRemoveParticipant(
|
||||
|
||||
auto ParticipantsAdditionalData::adminRights(
|
||||
not_null<UserData*> user) const
|
||||
-> std::optional<MTPChatAdminRights> {
|
||||
-> std::optional<ChatAdminRightsInfo> {
|
||||
if (const auto chat = _peer->asChat()) {
|
||||
return _admins.contains(user)
|
||||
? std::make_optional(MTPChatAdminRights(MTP_chatAdminRights(
|
||||
MTP_flags(chat->defaultAdminRights(user)))))
|
||||
? std::make_optional(chat->defaultAdminRights(user))
|
||||
: std::nullopt;
|
||||
}
|
||||
const auto i = _adminRights.find(user);
|
||||
@@ -394,7 +393,7 @@ QString ParticipantsAdditionalData::adminRank(
|
||||
|
||||
auto ParticipantsAdditionalData::restrictedRights(
|
||||
not_null<PeerData*> participant) const
|
||||
-> std::optional<MTPChatBannedRights> {
|
||||
-> std::optional<ChatRestrictionsInfo> {
|
||||
if (_peer->isChat()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -589,7 +588,7 @@ UserData *ParticipantsAdditionalData::applyCreator(
|
||||
const MTPDchannelParticipantCreator &data) {
|
||||
if (const auto user = applyRegular(data.vuser_id())) {
|
||||
_creator = user;
|
||||
_adminRights[user] = data.vadmin_rights();
|
||||
_adminRights[user] = ChatAdminRightsInfo(data.vadmin_rights());
|
||||
if (user->isSelf()) {
|
||||
_adminCanEdit.emplace(user);
|
||||
} else {
|
||||
@@ -620,7 +619,7 @@ UserData *ParticipantsAdditionalData::applyAdmin(
|
||||
_restrictedRights.erase(user);
|
||||
_kicked.erase(user);
|
||||
_restrictedBy.erase(user);
|
||||
_adminRights[user] = data.vadmin_rights();
|
||||
_adminRights[user] = ChatAdminRightsInfo(data.vadmin_rights());
|
||||
if (data.is_can_edit()) {
|
||||
_adminCanEdit.emplace(user);
|
||||
} else {
|
||||
@@ -684,7 +683,8 @@ PeerData *ParticipantsAdditionalData::applyBanned(
|
||||
} else {
|
||||
_kicked.erase(participant);
|
||||
}
|
||||
_restrictedRights[participant] = data.vbanned_rights();
|
||||
_restrictedRights[participant] = ChatRestrictionsInfo(
|
||||
data.vbanned_rights());
|
||||
if (const auto by = _peer->owner().userLoaded(data.vkicked_by())) {
|
||||
const auto i = _restrictedBy.find(participant);
|
||||
if (i == _restrictedBy.end()) {
|
||||
@@ -703,9 +703,7 @@ void ParticipantsAdditionalData::migrate(
|
||||
fillFromChannel(channel);
|
||||
|
||||
for (const auto user : _admins) {
|
||||
_adminRights.emplace(
|
||||
user,
|
||||
MTP_chatAdminRights(MTP_flags(chat->defaultAdminRights(user))));
|
||||
_adminRights.emplace(user, chat->defaultAdminRights(user));
|
||||
if (channel->amCreator()) {
|
||||
_adminCanEdit.emplace(user);
|
||||
}
|
||||
@@ -940,13 +938,13 @@ void ParticipantsBoxController::addNewItem() {
|
||||
}
|
||||
const auto adminDone = crl::guard(this, [=](
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &rights,
|
||||
ChatAdminRightsInfo rights,
|
||||
const QString &rank) {
|
||||
editAdminDone(user, rights, rank);
|
||||
});
|
||||
const auto restrictedDone = crl::guard(this, [=](
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights &rights) {
|
||||
ChatRestrictionsInfo rights) {
|
||||
editRestrictedDone(participant, rights);
|
||||
});
|
||||
const auto initBox = [](not_null<PeerListBox*> box) {
|
||||
@@ -1457,7 +1455,6 @@ void ParticipantsBoxController::rowActionClicked(
|
||||
base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
const auto chat = _peer->asChat();
|
||||
const auto channel = _peer->asChannel();
|
||||
const auto participant = row->peer();
|
||||
const auto user = participant->asUser();
|
||||
@@ -1523,19 +1520,15 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
|
||||
|
||||
void ParticipantsBoxController::showAdmin(not_null<UserData*> user) {
|
||||
const auto adminRights = _additional.adminRights(user);
|
||||
const auto currentRights = adminRights
|
||||
? *adminRights
|
||||
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
|
||||
const auto currentRights = adminRights.value_or(ChatAdminRightsInfo());
|
||||
auto box = Box<EditAdminBox>(
|
||||
_peer,
|
||||
user,
|
||||
currentRights,
|
||||
_additional.adminRank(user));
|
||||
const auto chat = _peer->asChat();
|
||||
const auto channel = _peer->asChannel();
|
||||
if (_additional.canAddOrEditAdmin(user)) {
|
||||
const auto done = crl::guard(this, [=](
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank) {
|
||||
editAdminDone(user, newRights, rank);
|
||||
});
|
||||
@@ -1551,7 +1544,7 @@ void ParticipantsBoxController::showAdmin(not_null<UserData*> user) {
|
||||
|
||||
void ParticipantsBoxController::editAdminDone(
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &rights,
|
||||
ChatAdminRightsInfo rights,
|
||||
const QString &rank) {
|
||||
_addBox = nullptr;
|
||||
if (_editParticipantBox) {
|
||||
@@ -1564,9 +1557,11 @@ void ParticipantsBoxController::editAdminDone(
|
||||
_additional.applyParticipant(MTP_channelParticipantCreator(
|
||||
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
|
||||
peerToBareMTPInt(user->id),
|
||||
rights,
|
||||
MTP_chatAdminRights(
|
||||
MTP_flags(MTPDchatAdminRights::Flags::from_raw(
|
||||
uint32(rights.flags)))),
|
||||
MTP_string(rank)));
|
||||
} else if (rights.c_chatAdminRights().vflags().v == 0) {
|
||||
} else if (!rights.flags) {
|
||||
_additional.applyParticipant(MTP_channelParticipant(
|
||||
peerToBareMTPInt(user->id),
|
||||
MTP_int(date)));
|
||||
@@ -1585,7 +1580,9 @@ void ParticipantsBoxController::editAdminDone(
|
||||
? alreadyPromotedBy->id
|
||||
: user->session().userPeerId()),
|
||||
MTP_int(date),
|
||||
rights,
|
||||
MTP_chatAdminRights(
|
||||
MTP_flags(MTPDchatAdminRights::Flags::from_raw(
|
||||
uint32(rights.flags)))),
|
||||
MTP_string(rank)));
|
||||
if (_role == Role::Admins) {
|
||||
prependRow(user);
|
||||
@@ -1601,18 +1598,16 @@ void ParticipantsBoxController::showRestricted(not_null<UserData*> user) {
|
||||
const auto restrictedRights = _additional.restrictedRights(user);
|
||||
const auto currentRights = restrictedRights
|
||||
? *restrictedRights
|
||||
: ChannelData::EmptyRestrictedRights(user);
|
||||
: ChatRestrictionsInfo();
|
||||
const auto hasAdminRights = _additional.adminRights(user).has_value();
|
||||
auto box = Box<EditRestrictedBox>(
|
||||
_peer,
|
||||
user,
|
||||
hasAdminRights,
|
||||
currentRights);
|
||||
const auto chat = _peer->asChat();
|
||||
const auto channel = _peer->asChannel();
|
||||
if (_additional.canRestrictParticipant(user)) {
|
||||
const auto done = crl::guard(this, [=](
|
||||
const MTPChatBannedRights &newRights) {
|
||||
ChatRestrictionsInfo newRights) {
|
||||
editRestrictedDone(user, newRights);
|
||||
});
|
||||
const auto fail = crl::guard(this, [=] {
|
||||
@@ -1628,7 +1623,7 @@ void ParticipantsBoxController::showRestricted(not_null<UserData*> user) {
|
||||
|
||||
void ParticipantsBoxController::editRestrictedDone(
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights &rights) {
|
||||
ChatRestrictionsInfo rights) {
|
||||
_addBox = nullptr;
|
||||
if (_editParticipantBox) {
|
||||
_editParticipantBox->closeBox();
|
||||
@@ -1636,7 +1631,7 @@ void ParticipantsBoxController::editRestrictedDone(
|
||||
|
||||
const auto user = participant->asUser();
|
||||
const auto date = base::unixtime::now(); // Incorrect, but ignored.
|
||||
if (Data::ChatBannedRightsFlags(rights) == 0) {
|
||||
if (!rights.flags) {
|
||||
if (user) {
|
||||
_additional.applyParticipant(MTP_channelParticipant(
|
||||
peerToBareMTPInt(user->id),
|
||||
@@ -1648,8 +1643,7 @@ void ParticipantsBoxController::editRestrictedDone(
|
||||
removeRow(participant);
|
||||
}
|
||||
} else {
|
||||
const auto kicked = Data::ChatBannedRightsFlags(rights)
|
||||
& ChatRestriction::f_view_messages;
|
||||
const auto kicked = rights.flags & ChatRestriction::ViewMessages;
|
||||
const auto alreadyRestrictedBy = _additional.restrictedBy(
|
||||
participant);
|
||||
_additional.applyParticipant(MTP_channelParticipantBanned(
|
||||
@@ -1661,7 +1655,10 @@ void ParticipantsBoxController::editRestrictedDone(
|
||||
? alreadyRestrictedBy->id
|
||||
: participant->session().userPeerId()),
|
||||
MTP_int(date),
|
||||
rights));
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(MTPDchatBannedRights::Flags::from_raw(
|
||||
uint32(rights.flags))),
|
||||
MTP_int(rights.until))));
|
||||
if (kicked) {
|
||||
if (_role == Role::Kicked) {
|
||||
prependRow(participant);
|
||||
@@ -1716,7 +1713,7 @@ void ParticipantsBoxController::kickParticipantSure(
|
||||
const auto restrictedRights = _additional.restrictedRights(participant);
|
||||
const auto currentRights = restrictedRights
|
||||
? *restrictedRights
|
||||
: ChannelData::EmptyRestrictedRights(participant);
|
||||
: ChatRestrictionsInfo();
|
||||
|
||||
if (const auto row = delegate()->peerListFindRow(participant->id.value)) {
|
||||
delegate()->peerListRemoveRow(row);
|
||||
@@ -1749,7 +1746,7 @@ void ParticipantsBoxController::removeAdminSure(not_null<UserData*> user) {
|
||||
SaveChatAdmin(chat, user, false, crl::guard(this, [=] {
|
||||
editAdminDone(
|
||||
user,
|
||||
MTP_chatAdminRights(MTP_flags(0)),
|
||||
ChatAdminRightsInfo(),
|
||||
QString());
|
||||
}), nullptr);
|
||||
} else if (const auto channel = _peer->asChannel()) {
|
||||
@@ -1760,7 +1757,7 @@ void ParticipantsBoxController::removeAdminSure(not_null<UserData*> user) {
|
||||
RemoveAdmin(channel, user, *adminRights, crl::guard(this, [=] {
|
||||
editAdminDone(
|
||||
user,
|
||||
MTP_chatAdminRights(MTP_flags(0)),
|
||||
ChatAdminRightsInfo(),
|
||||
QString());
|
||||
}), nullptr);
|
||||
}
|
||||
@@ -1961,7 +1958,7 @@ void ParticipantsBoxController::subscribeToCreatorChange(
|
||||
const auto isCreator = channel->amCreator();
|
||||
channel->flagsValue(
|
||||
) | rpl::filter([](const ChannelData::Flags::Change &change) {
|
||||
return (change.diff & MTPDchannel::Flag::f_creator);
|
||||
return (change.diff & ChannelDataFlag::Creator);
|
||||
}) | rpl::filter([=] {
|
||||
return (isCreator != channel->amCreator());
|
||||
}) | rpl::start_with_next([=] {
|
||||
|
||||
@@ -14,27 +14,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/weak_ptr.h"
|
||||
#include "info/profile/info_profile_members_controllers.h"
|
||||
|
||||
struct ChatAdminRightsInfo;
|
||||
struct ChatRestrictionsInfo;
|
||||
|
||||
namespace Window {
|
||||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
|
||||
Fn<void(
|
||||
const MTPChatAdminRights &oldRights,
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo oldRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank)> SaveAdminCallback(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user,
|
||||
Fn<void(
|
||||
const MTPChatAdminRights &newRights,
|
||||
ChatAdminRightsInfo newRights,
|
||||
const QString &rank)> onDone,
|
||||
Fn<void()> onFail);
|
||||
|
||||
Fn<void(
|
||||
const MTPChatBannedRights &oldRights,
|
||||
const MTPChatBannedRights &newRights)> SaveRestrictedCallback(
|
||||
ChatRestrictionsInfo oldRights,
|
||||
ChatRestrictionsInfo newRights)> SaveRestrictedCallback(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PeerData*> participant,
|
||||
Fn<void(const MTPChatBannedRights &newRights)> onDone,
|
||||
Fn<void(ChatRestrictionsInfo newRights)> onDone,
|
||||
Fn<void()> onFail);
|
||||
|
||||
void SubscribeToMigration(
|
||||
@@ -92,10 +95,10 @@ public:
|
||||
not_null<PeerData*> participant) const;
|
||||
[[nodiscard]] bool canRemoveParticipant(
|
||||
not_null<PeerData*> participant) const;
|
||||
[[nodiscard]] std::optional<MTPChatAdminRights> adminRights(
|
||||
[[nodiscard]] std::optional<ChatAdminRightsInfo> adminRights(
|
||||
not_null<UserData*> user) const;
|
||||
QString adminRank(not_null<UserData*> user) const;
|
||||
[[nodiscard]] std::optional<MTPChatBannedRights> restrictedRights(
|
||||
[[nodiscard]] std::optional<ChatRestrictionsInfo> restrictedRights(
|
||||
not_null<PeerData*> participant) const;
|
||||
[[nodiscard]] bool isCreator(not_null<UserData*> user) const;
|
||||
[[nodiscard]] bool isExternal(not_null<PeerData*> participant) const;
|
||||
@@ -122,11 +125,11 @@ private:
|
||||
base::flat_set<not_null<UserData*>> _admins;
|
||||
|
||||
// Data for channels.
|
||||
base::flat_map<not_null<UserData*>, MTPChatAdminRights> _adminRights;
|
||||
base::flat_map<not_null<UserData*>, ChatAdminRightsInfo> _adminRights;
|
||||
base::flat_map<not_null<UserData*>, QString> _adminRanks;
|
||||
base::flat_set<not_null<UserData*>> _adminCanEdit;
|
||||
base::flat_map<not_null<UserData*>, not_null<UserData*>> _adminPromotedBy;
|
||||
std::map<not_null<PeerData*>, MTPChatBannedRights> _restrictedRights;
|
||||
std::map<not_null<PeerData*>, ChatRestrictionsInfo> _restrictedRights;
|
||||
std::set<not_null<PeerData*>> _kicked;
|
||||
std::map<not_null<PeerData*>, not_null<UserData*>> _restrictedBy;
|
||||
std::set<not_null<PeerData*>> _external;
|
||||
@@ -221,12 +224,12 @@ private:
|
||||
void showAdmin(not_null<UserData*> user);
|
||||
void editAdminDone(
|
||||
not_null<UserData*> user,
|
||||
const MTPChatAdminRights &rights,
|
||||
ChatAdminRightsInfo rights,
|
||||
const QString &rank);
|
||||
void showRestricted(not_null<UserData*> user);
|
||||
void editRestrictedDone(
|
||||
not_null<PeerData*> participant,
|
||||
const MTPChatBannedRights &rights);
|
||||
ChatRestrictionsInfo rights);
|
||||
void removeKicked(
|
||||
not_null<PeerListRow*> row,
|
||||
not_null<PeerData*> participant);
|
||||
|
||||
@@ -64,8 +64,6 @@ void FillContent(
|
||||
return;
|
||||
}
|
||||
|
||||
const auto channel = peer->asChannel();
|
||||
|
||||
historyVisibility->setValue(savedValue);
|
||||
|
||||
const auto result = parent->add(
|
||||
|
||||
@@ -140,7 +140,7 @@ void AddButtonDelete(
|
||||
|
||||
void SaveDefaultRestrictions(
|
||||
not_null<PeerData*> peer,
|
||||
MTPChatBannedRights rights,
|
||||
ChatRestrictions rights,
|
||||
Fn<void()> done) {
|
||||
const auto api = &peer->session().api();
|
||||
const auto key = Api::RequestKey("default_restrictions", peer->id);
|
||||
@@ -148,7 +148,10 @@ void SaveDefaultRestrictions(
|
||||
const auto requestId = api->request(
|
||||
MTPmessages_EditChatDefaultBannedRights(
|
||||
peer->input,
|
||||
rights)
|
||||
MTP_chatBannedRights(
|
||||
MTP_flags(
|
||||
MTPDchatBannedRights::Flags::from_raw(uint32(rights))),
|
||||
MTP_int(0)))
|
||||
).done([=](const MTPUpdates &result) {
|
||||
api->clearModifyRequest(key);
|
||||
api->applyUpdates(result);
|
||||
@@ -215,52 +218,7 @@ void ShowEditPermissions(
|
||||
const auto close = crl::guard(box, [=] { box->closeBox(); });
|
||||
SaveDefaultRestrictions(
|
||||
peer,
|
||||
MTP_chatBannedRights(MTP_flags(result.rights), MTP_int(0)),
|
||||
close);
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
SaveSlowmodeSeconds(channel, result.slowmodeSeconds, close);
|
||||
}
|
||||
};
|
||||
box->saveEvents(
|
||||
) | rpl::start_with_next([=](EditPeerPermissionsBox::Result result) {
|
||||
if (*saving) {
|
||||
return;
|
||||
}
|
||||
*saving = true;
|
||||
|
||||
const auto saveFor = peer->migrateToOrMe();
|
||||
const auto chat = saveFor->asChat();
|
||||
if (!result.slowmodeSeconds || !chat) {
|
||||
save(saveFor, result);
|
||||
return;
|
||||
}
|
||||
const auto api = &peer->session().api();
|
||||
api->migrateChat(chat, [=](not_null<ChannelData*> channel) {
|
||||
save(channel, result);
|
||||
}, [=](const MTP::Error &error) {
|
||||
*saving = false;
|
||||
});
|
||||
}, box->lifetime());
|
||||
}
|
||||
|
||||
void ShowEditInviteLinks(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer) {
|
||||
auto content = Box<EditPeerPermissionsBox>(navigation, peer);
|
||||
const auto box = QPointer<EditPeerPermissionsBox>(content.data());
|
||||
navigation->parentController()->show(
|
||||
std::move(content),
|
||||
Ui::LayerOption::KeepOther);
|
||||
const auto saving = box->lifetime().make_state<int>(0);
|
||||
const auto save = [=](
|
||||
not_null<PeerData*> peer,
|
||||
EditPeerPermissionsBox::Result result) {
|
||||
Expects(result.slowmodeSeconds == 0 || peer->isChannel());
|
||||
|
||||
const auto close = crl::guard(box, [=] { box->closeBox(); });
|
||||
SaveDefaultRestrictions(
|
||||
peer,
|
||||
MTP_chatBannedRights(MTP_flags(result.rights), MTP_int(0)),
|
||||
result.rights,
|
||||
close);
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
SaveSlowmodeSeconds(channel, result.slowmodeSeconds, close);
|
||||
@@ -495,6 +453,7 @@ object_ptr<Ui::RpWidget> Controller::createPhotoEdit() {
|
||||
_wrap,
|
||||
object_ptr<Ui::UserpicButton>(
|
||||
_wrap,
|
||||
&_navigation->parentController()->window(),
|
||||
_peer,
|
||||
Ui::UserpicButton::Role::ChangePhoto,
|
||||
st::defaultUserpicButton),
|
||||
@@ -1354,7 +1313,6 @@ void Controller::saveLinkedChat() {
|
||||
channel->setLinkedChat(*_savingData.linkedChat);
|
||||
continueSave();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto &type = error.type();
|
||||
cancelSave();
|
||||
}).send();
|
||||
}
|
||||
@@ -1407,7 +1365,6 @@ void Controller::saveTitle() {
|
||||
}
|
||||
|
||||
void Controller::saveDescription() {
|
||||
const auto channel = _peer->asChannel();
|
||||
if (!_savingData.description
|
||||
|| *_savingData.description == _peer->about()) {
|
||||
return continueSave();
|
||||
@@ -1467,9 +1424,9 @@ void Controller::togglePreHistoryHidden(
|
||||
// Update in the result doesn't contain the
|
||||
// channelFull:flags field which holds this value.
|
||||
// So after saving we need to update it manually.
|
||||
const auto flags = channel->fullFlags();
|
||||
const auto flag = MTPDchannelFull::Flag::f_hidden_prehistory;
|
||||
channel->setFullFlags(hidden ? (flags | flag) : (flags & ~flag));
|
||||
const auto flags = channel->flags();
|
||||
const auto flag = ChannelDataFlag::PreHistoryHidden;
|
||||
channel->setFlags(hidden ? (flags | flag) : (flags & ~flag));
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
@@ -832,7 +832,6 @@ void CopyInviteLink(const QString &link) {
|
||||
}
|
||||
|
||||
void ShareInviteLinkBox(not_null<PeerData*> peer, const QString &link) {
|
||||
const auto session = &peer->session();
|
||||
const auto sending = std::make_shared<bool>();
|
||||
const auto box = std::make_shared<QPointer<ShareBox>>();
|
||||
|
||||
@@ -886,8 +885,6 @@ void ShareInviteLinkBox(not_null<PeerData*> peer, const QString &link) {
|
||||
}
|
||||
const auto owner = &peer->owner();
|
||||
auto &api = peer->session().api();
|
||||
auto &histories = owner->histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
for (const auto peer : result) {
|
||||
const auto history = owner->history(peer);
|
||||
auto message = ApiWrap::MessageToSend(history);
|
||||
@@ -901,9 +898,6 @@ void ShareInviteLinkBox(not_null<PeerData*> peer, const QString &link) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
auto filterCallback = [](PeerData *peer) {
|
||||
return peer->canWrite();
|
||||
};
|
||||
*box = Ui::show(
|
||||
Box<ShareBox>(ShareBox::Descriptor{
|
||||
.session = &peer->session(),
|
||||
|
||||
@@ -33,7 +33,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kPreloadPages = 2;
|
||||
constexpr auto kFullArcLength = 360 * 16;
|
||||
|
||||
enum class Color {
|
||||
|
||||
@@ -133,26 +133,26 @@ std::vector<std::pair<ChatAdminRights, QString>> AdminRightLabels(
|
||||
|
||||
if (isGroup) {
|
||||
return {
|
||||
{ Flag::f_change_info, tr::lng_rights_group_info(tr::now) },
|
||||
{ Flag::f_delete_messages, tr::lng_rights_group_delete(tr::now) },
|
||||
{ Flag::f_ban_users, tr::lng_rights_group_ban(tr::now) },
|
||||
{ Flag::f_invite_users, anyoneCanAddMembers
|
||||
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
|
||||
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
|
||||
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
|
||||
{ Flag::InviteUsers, anyoneCanAddMembers
|
||||
? tr::lng_rights_group_invite_link(tr::now)
|
||||
: tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::f_pin_messages, tr::lng_rights_group_pin(tr::now) },
|
||||
{ Flag::f_manage_call, tr::lng_rights_group_manage_calls(tr::now) },
|
||||
{ Flag::f_anonymous, tr::lng_rights_group_anonymous(tr::now) },
|
||||
{ Flag::f_add_admins, tr::lng_rights_add_admins(tr::now) },
|
||||
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
|
||||
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
|
||||
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
{ Flag::f_change_info, tr::lng_rights_channel_info(tr::now) },
|
||||
{ Flag::f_post_messages, tr::lng_rights_channel_post(tr::now) },
|
||||
{ Flag::f_edit_messages, tr::lng_rights_channel_edit(tr::now) },
|
||||
{ Flag::f_delete_messages, tr::lng_rights_channel_delete(tr::now) },
|
||||
{ Flag::f_invite_users, tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::f_manage_call, tr::lng_rights_group_manage_calls(tr::now) },
|
||||
{ Flag::f_add_admins, tr::lng_rights_add_admins(tr::now) }
|
||||
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
|
||||
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
|
||||
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
|
||||
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
|
||||
{ Flag::InviteUsers, tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
|
||||
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -163,31 +163,31 @@ auto Dependencies(ChatRestrictions)
|
||||
|
||||
return {
|
||||
// stickers <-> gifs
|
||||
{ Flag::f_send_gifs, Flag::f_send_stickers },
|
||||
{ Flag::f_send_stickers, Flag::f_send_gifs },
|
||||
{ Flag::SendGifs, Flag::SendStickers },
|
||||
{ Flag::SendStickers, Flag::SendGifs },
|
||||
|
||||
// stickers <-> games
|
||||
{ Flag::f_send_games, Flag::f_send_stickers },
|
||||
{ Flag::f_send_stickers, Flag::f_send_games },
|
||||
{ Flag::SendGames, Flag::SendStickers },
|
||||
{ Flag::SendStickers, Flag::SendGames },
|
||||
|
||||
// stickers <-> inline
|
||||
{ Flag::f_send_inline, Flag::f_send_stickers },
|
||||
{ Flag::f_send_stickers, Flag::f_send_inline },
|
||||
{ Flag::SendInline, Flag::SendStickers },
|
||||
{ Flag::SendStickers, Flag::SendInline },
|
||||
|
||||
// stickers -> send_media
|
||||
{ Flag::f_send_stickers, Flag::f_send_messages },
|
||||
// stickers -> send_messages
|
||||
{ Flag::SendStickers, Flag::SendMessages },
|
||||
|
||||
// embed_links -> send_media
|
||||
{ Flag::f_embed_links, Flag::f_send_messages },
|
||||
// embed_links -> send_messages
|
||||
{ Flag::EmbedLinks, Flag::SendMessages },
|
||||
|
||||
// send_media -> send_messages
|
||||
{ Flag::f_send_media, Flag::f_send_messages },
|
||||
{ Flag::SendMedia, Flag::SendMessages },
|
||||
|
||||
// send_polls -> send_messages
|
||||
{ Flag::f_send_polls, Flag::f_send_messages },
|
||||
{ Flag::SendPolls, Flag::SendMessages },
|
||||
|
||||
// send_messages -> view_messages
|
||||
{ Flag::f_send_messages, Flag::f_view_messages },
|
||||
{ Flag::SendMessages, Flag::ViewMessages },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -196,18 +196,18 @@ ChatRestrictions NegateRestrictions(ChatRestrictions value) {
|
||||
|
||||
return (~value) & (Flag(0)
|
||||
// view_messages is always allowed, so it is never in restrictions.
|
||||
//| Flag::f_view_messages
|
||||
| Flag::f_change_info
|
||||
| Flag::f_embed_links
|
||||
| Flag::f_invite_users
|
||||
| Flag::f_pin_messages
|
||||
| Flag::f_send_games
|
||||
| Flag::f_send_gifs
|
||||
| Flag::f_send_inline
|
||||
| Flag::f_send_media
|
||||
| Flag::f_send_messages
|
||||
| Flag::f_send_polls
|
||||
| Flag::f_send_stickers);
|
||||
//| Flag::ViewMessages
|
||||
| Flag::ChangeInfo
|
||||
| Flag::EmbedLinks
|
||||
| Flag::InviteUsers
|
||||
| Flag::PinMessages
|
||||
| Flag::SendGames
|
||||
| Flag::SendGifs
|
||||
| Flag::SendInline
|
||||
| Flag::SendMedia
|
||||
| Flag::SendMessages
|
||||
| Flag::SendPolls
|
||||
| Flag::SendStickers);
|
||||
}
|
||||
|
||||
auto Dependencies(ChatAdminRights)
|
||||
@@ -236,15 +236,15 @@ ChatRestrictions DisabledByAdminRights(not_null<PeerData*> peer) {
|
||||
Unexpected("User in DisabledByAdminRights.");
|
||||
}();
|
||||
return Flag(0)
|
||||
| ((adminRights & Admin::f_pin_messages)
|
||||
| ((adminRights & Admin::PinMessages)
|
||||
? Flag(0)
|
||||
: Flag::f_pin_messages)
|
||||
| ((adminRights & Admin::f_invite_users)
|
||||
: Flag::PinMessages)
|
||||
| ((adminRights & Admin::InviteUsers)
|
||||
? Flag(0)
|
||||
: Flag::f_invite_users)
|
||||
| ((adminRights & Admin::f_change_info)
|
||||
: Flag::InviteUsers)
|
||||
| ((adminRights & Admin::ChangeInfo)
|
||||
? Flag(0)
|
||||
: Flag::f_change_info);
|
||||
: Flag::ChangeInfo);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -262,21 +262,21 @@ ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer) {
|
||||
Unexpected("User in DisabledByDefaultRestrictions.");
|
||||
}());
|
||||
return Flag(0)
|
||||
| ((restrictions & Restriction::f_pin_messages)
|
||||
| ((restrictions & Restriction::PinMessages)
|
||||
? Flag(0)
|
||||
: Flag::f_pin_messages)
|
||||
: Flag::PinMessages)
|
||||
//
|
||||
// We allow to edit 'invite_users' admin right no matter what
|
||||
// is chosen in default permissions for 'invite_users', because
|
||||
// if everyone can 'invite_users' it handles invite link for admins.
|
||||
//
|
||||
//| ((restrictions & Restriction::f_invite_users)
|
||||
//| ((restrictions & Restriction::InviteUsers)
|
||||
// ? Flag(0)
|
||||
// : Flag::f_invite_users)
|
||||
// : Flag::InviteUsers)
|
||||
//
|
||||
| ((restrictions & Restriction::f_change_info)
|
||||
| ((restrictions & Restriction::ChangeInfo)
|
||||
? Flag(0)
|
||||
: Flag::f_change_info);
|
||||
: Flag::ChangeInfo);
|
||||
}
|
||||
|
||||
ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
|
||||
@@ -284,15 +284,15 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
|
||||
|
||||
// Fix iOS bug of saving send_inline like embed_links.
|
||||
// We copy send_stickers to send_inline.
|
||||
if (restrictions & ChatRestriction::f_send_stickers) {
|
||||
restrictions |= ChatRestriction::f_send_inline;
|
||||
if (restrictions & ChatRestriction::SendStickers) {
|
||||
restrictions |= ChatRestriction::SendInline;
|
||||
} else {
|
||||
restrictions &= ~ChatRestriction::f_send_inline;
|
||||
restrictions &= ~ChatRestriction::SendInline;
|
||||
}
|
||||
|
||||
// Apply the strictest.
|
||||
const auto fixOne = [&] {
|
||||
for (const auto [first, second] : dependencies) {
|
||||
for (const auto &[first, second] : dependencies) {
|
||||
if ((restrictions & second) && !(restrictions & first)) {
|
||||
restrictions |= first;
|
||||
return true;
|
||||
@@ -308,7 +308,7 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
|
||||
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup) {
|
||||
auto result = ChatAdminRights();
|
||||
for (const auto &[flag, label] : AdminRightLabels(isGroup, true)) {
|
||||
if (!(flag & ChatAdminRight::f_anonymous)) {
|
||||
if (!(flag & ChatAdminRight::Anonymous)) {
|
||||
result |= flag;
|
||||
}
|
||||
}
|
||||
@@ -407,7 +407,7 @@ void EditPeerPermissionsBox::prepare() {
|
||||
} else if (const auto channel = _peer->asChannel()) {
|
||||
return channel->defaultRestrictions()
|
||||
| (channel->isPublic()
|
||||
? (Flag::f_change_info | Flag::f_pin_messages)
|
||||
? (Flag::ChangeInfo | Flag::PinMessages)
|
||||
: Flags(0))
|
||||
| disabledByAdminRights;
|
||||
}
|
||||
@@ -421,7 +421,7 @@ void EditPeerPermissionsBox::prepare() {
|
||||
if (const auto channel = _peer->asChannel()) {
|
||||
if (channel->isPublic()) {
|
||||
result.emplace(
|
||||
Flag::f_change_info | Flag::f_pin_messages,
|
||||
Flag::ChangeInfo | Flag::PinMessages,
|
||||
tr::lng_rights_permission_unavailable(tr::now));
|
||||
}
|
||||
}
|
||||
@@ -533,7 +533,7 @@ Fn<int()> EditPeerPermissionsBox::addSlowmodeSlider(
|
||||
return has ? aboutInterval : about;
|
||||
});
|
||||
|
||||
const auto about = container->add(
|
||||
container->add(
|
||||
object_ptr<Ui::DividerLabel>(
|
||||
container,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
@@ -753,11 +753,11 @@ EditFlagsControl<Flags> CreateEditFlags(
|
||||
};
|
||||
}
|
||||
|
||||
EditFlagsControl<MTPDchatBannedRights::Flags> CreateEditRestrictions(
|
||||
EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
|
||||
QWidget *parent,
|
||||
rpl::producer<QString> header,
|
||||
MTPDchatBannedRights::Flags restrictions,
|
||||
std::map<MTPDchatBannedRights::Flags, QString> disabledMessages) {
|
||||
ChatRestrictions restrictions,
|
||||
std::map<ChatRestrictions, QString> disabledMessages) {
|
||||
auto result = CreateEditFlags(
|
||||
parent,
|
||||
header,
|
||||
@@ -774,11 +774,11 @@ EditFlagsControl<MTPDchatBannedRights::Flags> CreateEditRestrictions(
|
||||
return result;
|
||||
}
|
||||
|
||||
EditFlagsControl<MTPDchatAdminRights::Flags> CreateEditAdminRights(
|
||||
EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
|
||||
QWidget *parent,
|
||||
rpl::producer<QString> header,
|
||||
MTPDchatAdminRights::Flags rights,
|
||||
std::map<MTPDchatAdminRights::Flags, QString> disabledMessages,
|
||||
ChatAdminRights rights,
|
||||
std::map<ChatAdminRights, QString> disabledMessages,
|
||||
bool isGroup,
|
||||
bool anyoneCanAddMembers) {
|
||||
return CreateEditFlags(
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
struct Result {
|
||||
MTPDchatBannedRights::Flags rights;
|
||||
ChatRestrictions rights;
|
||||
int slowmodeSeconds = 0;
|
||||
};
|
||||
|
||||
@@ -59,17 +59,17 @@ struct EditFlagsControl {
|
||||
rpl::producer<Flags> changes;
|
||||
};
|
||||
|
||||
EditFlagsControl<MTPDchatBannedRights::Flags> CreateEditRestrictions(
|
||||
EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
|
||||
QWidget *parent,
|
||||
rpl::producer<QString> header,
|
||||
MTPDchatBannedRights::Flags restrictions,
|
||||
std::map<MTPDchatBannedRights::Flags, QString> disabledMessages);
|
||||
ChatRestrictions restrictions,
|
||||
std::map<ChatRestrictions, QString> disabledMessages);
|
||||
|
||||
EditFlagsControl<MTPDchatAdminRights::Flags> CreateEditAdminRights(
|
||||
EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
|
||||
QWidget *parent,
|
||||
rpl::producer<QString> header,
|
||||
MTPDchatAdminRights::Flags rights,
|
||||
std::map<MTPDchatAdminRights::Flags, QString> disabledMessages,
|
||||
ChatAdminRights rights,
|
||||
std::map<ChatAdminRights, QString> disabledMessages,
|
||||
bool isGroup,
|
||||
bool anyoneCanAddMembers);
|
||||
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/photo_crop_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
PhotoCropBox::PhotoCropBox(
|
||||
QWidget*,
|
||||
const QImage &img,
|
||||
const QString &title)
|
||||
: _title(title)
|
||||
, _img(img) {
|
||||
}
|
||||
|
||||
void PhotoCropBox::prepare() {
|
||||
addButton(tr::lng_settings_save(), [this] { sendPhoto(); });
|
||||
addButton(tr::lng_cancel(), [this] { closeBox(); });
|
||||
|
||||
int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||
_thumb = App::pixmapFromImageInPlace(_img.scaled(s * cIntRetinaFactor(), s * cIntRetinaFactor(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
||||
_mask = QImage(_thumb.size(), QImage::Format_ARGB32_Premultiplied);
|
||||
_mask.setDevicePixelRatio(cRetinaFactor());
|
||||
_fade = QImage(_thumb.size(), QImage::Format_ARGB32_Premultiplied);
|
||||
_fade.setDevicePixelRatio(cRetinaFactor());
|
||||
_thumbw = _thumb.width() / cIntRetinaFactor();
|
||||
_thumbh = _thumb.height() / cIntRetinaFactor();
|
||||
if (_thumbw > _thumbh) {
|
||||
_cropw = _thumbh - 20;
|
||||
} else {
|
||||
_cropw = _thumbw - 20;
|
||||
}
|
||||
_cropx = (_thumbw - _cropw) / 2;
|
||||
_cropy = (_thumbh - _cropw) / 2;
|
||||
|
||||
_thumbx = (st::boxWideWidth - _thumbw) / 2;
|
||||
_thumby = st::boxPhotoPadding.top();
|
||||
setMouseTracking(true);
|
||||
|
||||
setDimensions(st::boxWideWidth, st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxTextFont->height + st::cropSkip);
|
||||
}
|
||||
|
||||
void PhotoCropBox::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
_downState = mouseState(e->pos());
|
||||
_fromposx = e->pos().x();
|
||||
_fromposy = e->pos().y();
|
||||
_fromcropx = _cropx;
|
||||
_fromcropy = _cropy;
|
||||
_fromcropw = _cropw;
|
||||
}
|
||||
return BoxContent::mousePressEvent(e);
|
||||
}
|
||||
|
||||
int PhotoCropBox::mouseState(QPoint p) {
|
||||
p -= QPoint(_thumbx, _thumby);
|
||||
int32 delta = st::cropPointSize, mdelta(-delta / 2);
|
||||
if (QRect(_cropx + mdelta, _cropy + mdelta, delta, delta).contains(p)) {
|
||||
return 1;
|
||||
} else if (QRect(_cropx + _cropw + mdelta, _cropy + mdelta, delta, delta).contains(p)) {
|
||||
return 2;
|
||||
} else if (QRect(_cropx + _cropw + mdelta, _cropy + _cropw + mdelta, delta, delta).contains(p)) {
|
||||
return 3;
|
||||
} else if (QRect(_cropx + mdelta, _cropy + _cropw + mdelta, delta, delta).contains(p)) {
|
||||
return 4;
|
||||
} else if (QRect(_cropx, _cropy, _cropw, _cropw).contains(p)) {
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
rpl::producer<QImage> PhotoCropBox::ready() const {
|
||||
return _readyImages.events();
|
||||
}
|
||||
|
||||
void PhotoCropBox::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (_downState) {
|
||||
_downState = 0;
|
||||
mouseMoveEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) {
|
||||
if (_downState && !(e->buttons() & Qt::LeftButton)) {
|
||||
mouseReleaseEvent(e);
|
||||
}
|
||||
if (_downState) {
|
||||
if (_downState == 1) {
|
||||
int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy;
|
||||
if (_fromcropx + d < 0) {
|
||||
d = -_fromcropx;
|
||||
}
|
||||
if (_fromcropy + d < 0) {
|
||||
d = -_fromcropy;
|
||||
}
|
||||
if (_fromcropw - d < st::cropMinSize) {
|
||||
d = _fromcropw - st::cropMinSize;
|
||||
}
|
||||
if (_cropx != _fromcropx + d || _cropy != _fromcropy + d || _cropw != _fromcropw - d) {
|
||||
_cropx = _fromcropx + d;
|
||||
_cropy = _fromcropy + d;
|
||||
_cropw = _fromcropw - d;
|
||||
update();
|
||||
}
|
||||
} else if (_downState == 2) {
|
||||
int32 dx = _fromposx - e->pos().x(), dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy;
|
||||
if (_fromcropx + _fromcropw - d > _thumbw) {
|
||||
d = _fromcropx + _fromcropw - _thumbw;
|
||||
}
|
||||
if (_fromcropy + d < 0) {
|
||||
d = -_fromcropy;
|
||||
}
|
||||
if (_fromcropw - d < st::cropMinSize) {
|
||||
d = _fromcropw - st::cropMinSize;
|
||||
}
|
||||
if (_cropy != _fromcropy + d || _cropw != _fromcropw - d) {
|
||||
_cropy = _fromcropy + d;
|
||||
_cropw = _fromcropw - d;
|
||||
update();
|
||||
}
|
||||
} else if (_downState == 3) {
|
||||
int32 dx = _fromposx - e->pos().x(), dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy;
|
||||
if (_fromcropx + _fromcropw - d > _thumbw) {
|
||||
d = _fromcropx + _fromcropw - _thumbw;
|
||||
}
|
||||
if (_fromcropy + _fromcropw - d > _thumbh) {
|
||||
d = _fromcropy + _fromcropw - _thumbh;
|
||||
}
|
||||
if (_fromcropw - d < st::cropMinSize) {
|
||||
d = _fromcropw - st::cropMinSize;
|
||||
}
|
||||
if (_cropw != _fromcropw - d) {
|
||||
_cropw = _fromcropw - d;
|
||||
update();
|
||||
}
|
||||
} else if (_downState == 4) {
|
||||
int32 dx = e->pos().x() - _fromposx, dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy;
|
||||
if (_fromcropx + d < 0) {
|
||||
d = -_fromcropx;
|
||||
}
|
||||
if (_fromcropy + _fromcropw - d > _thumbh) {
|
||||
d = _fromcropy + _fromcropw - _thumbh;
|
||||
}
|
||||
if (_fromcropw - d < st::cropMinSize) {
|
||||
d = _fromcropw - st::cropMinSize;
|
||||
}
|
||||
if (_cropx != _fromcropx + d || _cropw != _fromcropw - d) {
|
||||
_cropx = _fromcropx + d;
|
||||
_cropw = _fromcropw - d;
|
||||
update();
|
||||
}
|
||||
} else if (_downState == 5) {
|
||||
int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy;
|
||||
if (_fromcropx + dx < 0) {
|
||||
dx = -_fromcropx;
|
||||
} else if (_fromcropx + _fromcropw + dx > _thumbw) {
|
||||
dx = _thumbw - _fromcropx - _fromcropw;
|
||||
}
|
||||
if (_fromcropy + dy < 0) {
|
||||
dy = -_fromcropy;
|
||||
} else if (_fromcropy + _fromcropw + dy > _thumbh) {
|
||||
dy = _thumbh - _fromcropy - _fromcropw;
|
||||
}
|
||||
if (_cropx != _fromcropx + dx || _cropy != _fromcropy + dy) {
|
||||
_cropx = _fromcropx + dx;
|
||||
_cropy = _fromcropy + dy;
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
int32 cursorState = _downState ? _downState : mouseState(e->pos());
|
||||
QCursor cur(style::cur_default);
|
||||
if (cursorState == 1 || cursorState == 3) {
|
||||
cur = style::cur_sizefdiag;
|
||||
} else if (cursorState == 2 || cursorState == 4) {
|
||||
cur = style::cur_sizebdiag;
|
||||
} else if (cursorState == 5) {
|
||||
cur = style::cur_sizeall;
|
||||
}
|
||||
setCursor(cur);
|
||||
}
|
||||
|
||||
void PhotoCropBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
sendPhoto();
|
||||
} else {
|
||||
BoxContent::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void PhotoCropBox::paintEvent(QPaintEvent *e) {
|
||||
BoxContent::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
|
||||
p.setFont(st::boxTextFont);
|
||||
p.setPen(st::boxPhotoTextFg);
|
||||
p.drawText(QRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom(), width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), st::boxTextFont->height), _title, style::al_top);
|
||||
|
||||
p.translate(_thumbx, _thumby);
|
||||
p.drawPixmap(0, 0, _thumb);
|
||||
_mask.fill(Qt::white);
|
||||
{
|
||||
Painter p(&_mask);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(Qt::black);
|
||||
p.drawEllipse(_cropx, _cropy, _cropw, _cropw);
|
||||
}
|
||||
style::colorizeImage(_mask, st::photoCropFadeBg->c, &_fade);
|
||||
p.drawImage(0, 0, _fade);
|
||||
|
||||
int delta = st::cropPointSize;
|
||||
int mdelta = -delta / 2;
|
||||
p.fillRect(QRect(_cropx + mdelta, _cropy + mdelta, delta, delta), st::photoCropPointFg);
|
||||
p.fillRect(QRect(_cropx + _cropw + mdelta, _cropy + mdelta, delta, delta), st::photoCropPointFg);
|
||||
p.fillRect(QRect(_cropx + _cropw + mdelta, _cropy + _cropw + mdelta, delta, delta), st::photoCropPointFg);
|
||||
p.fillRect(QRect(_cropx + mdelta, _cropy + _cropw + mdelta, delta, delta), st::photoCropPointFg);
|
||||
}
|
||||
|
||||
void PhotoCropBox::sendPhoto() {
|
||||
auto from = _img;
|
||||
if (_img.width() < _thumb.width()) {
|
||||
from = _thumb.toImage();
|
||||
}
|
||||
float64 x = float64(_cropx) / _thumbw, y = float64(_cropy) / _thumbh, w = float64(_cropw) / _thumbw;
|
||||
int32 ix = int32(x * from.width()), iy = int32(y * from.height()), iw = int32(w * from.width());
|
||||
if (ix < 0) {
|
||||
ix = 0;
|
||||
}
|
||||
if (ix + iw > from.width()) {
|
||||
iw = from.width() - ix;
|
||||
}
|
||||
if (iy < 0) {
|
||||
iy = 0;
|
||||
}
|
||||
if (iy + iw > from.height()) {
|
||||
iw = from.height() - iy;
|
||||
}
|
||||
int32 offset = ix * from.depth() / 8 + iy * from.bytesPerLine();
|
||||
QImage cropped(from.constBits() + offset, iw, iw, from.bytesPerLine(), from.format()), tosend;
|
||||
if (from.format() == QImage::Format_Indexed8) {
|
||||
cropped.setColorCount(from.colorCount());
|
||||
cropped.setColorTable(from.colorTable());
|
||||
}
|
||||
if (cropped.width() > 1280) {
|
||||
tosend = cropped.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
} else if (cropped.width() < 320) {
|
||||
tosend = cropped.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
} else {
|
||||
tosend = cropped.copy();
|
||||
}
|
||||
|
||||
auto weak = Ui::MakeWeak(this);
|
||||
_readyImages.fire(std::move(tosend));
|
||||
if (weak) {
|
||||
closeBox();
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
class PhotoCropBox : public Ui::BoxContent {
|
||||
public:
|
||||
PhotoCropBox(QWidget*, const QImage &img, const QString &title);
|
||||
|
||||
int32 mouseState(QPoint p);
|
||||
|
||||
rpl::producer<QImage> ready() const;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
void sendPhoto();
|
||||
|
||||
QString _title;
|
||||
int32 _downState = 0;
|
||||
int32 _thumbx, _thumby, _thumbw, _thumbh;
|
||||
int32 _cropx, _cropy, _cropw;
|
||||
int32 _fromposx, _fromposy, _fromcropx, _fromcropy, _fromcropw;
|
||||
QImage _img;
|
||||
QPixmap _thumb;
|
||||
QImage _mask, _fade;
|
||||
rpl::event_stream<QImage> _readyImages;
|
||||
|
||||
};
|
||||
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "mainwidget.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "chat_helpers/send_context_menu.h"
|
||||
@@ -20,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "confirm_box.h"
|
||||
#include "editor/photo_editor_layer_widget.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "core/file_utilities.h"
|
||||
@@ -66,10 +68,6 @@ inline bool CanAddUrls(const QList<QUrl> &urls) {
|
||||
return !urls.isEmpty() && ranges::all_of(urls, &QUrl::isLocalFile);
|
||||
}
|
||||
|
||||
inline bool IsSingleItem(const Ui::PreparedList &list) {
|
||||
return list.files.size() == 1;
|
||||
}
|
||||
|
||||
void FileDialogCallback(
|
||||
FileDialog::OpenResult &&result,
|
||||
Fn<bool(const Ui::PreparedList&)> checkResult,
|
||||
@@ -187,6 +185,22 @@ rpl::producer<int> SendFilesBox::Block::itemReplaceRequest() const {
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<int> SendFilesBox::Block::itemModifyRequest() const {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
const auto preview = _preview.get();
|
||||
const auto from = _from;
|
||||
if (_isAlbum) {
|
||||
const auto album = static_cast<Ui::AlbumPreview*>(preview);
|
||||
return album->thumbModified() | rpl::map(_1 + from);
|
||||
} else if (_isSingleMedia) {
|
||||
const auto media = static_cast<Ui::SingleMediaPreview*>(preview);
|
||||
return media->modifyRequests() | rpl::map_to(from);
|
||||
} else {
|
||||
return rpl::never<int>();
|
||||
}
|
||||
}
|
||||
|
||||
void SendFilesBox::Block::setSendWay(Ui::SendFilesWay way) {
|
||||
if (!_isAlbum) {
|
||||
return;
|
||||
@@ -525,7 +539,6 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||
return controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::Layer);
|
||||
};
|
||||
const auto index = int(_blocks.size());
|
||||
_blocks.emplace_back(
|
||||
_inner.data(),
|
||||
&_list.files,
|
||||
@@ -601,6 +614,16 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||
FileDialog::AllOrImagesFilter(),
|
||||
crl::guard(this, callback));
|
||||
}, widget->lifetime());
|
||||
|
||||
block.itemModifyRequest(
|
||||
) | rpl::start_with_next([=, controller = _controller](int index) {
|
||||
Editor::OpenWithPreparedFile(
|
||||
this,
|
||||
controller,
|
||||
&_list.files[index],
|
||||
st::sendMediaPreviewSize,
|
||||
[=] { refreshAllAfterChanges(from); });
|
||||
}, widget->lifetime());
|
||||
}
|
||||
|
||||
void SendFilesBox::refreshControls() {
|
||||
@@ -640,6 +663,11 @@ void SendFilesBox::setupSendWayControls() {
|
||||
sendWay.setSendImagesAsPhotos(_sendImagesAsPhotos->checked());
|
||||
_sendWay = sendWay;
|
||||
}, lifetime());
|
||||
|
||||
_hintLabel.create(
|
||||
this,
|
||||
tr::lng_edit_photo_editor_hint(tr::now),
|
||||
st::editMediaHintLabel);
|
||||
}
|
||||
|
||||
void SendFilesBox::updateSendWayControlsVisibility() {
|
||||
@@ -647,6 +675,11 @@ void SendFilesBox::updateSendWayControlsVisibility() {
|
||||
_groupFiles->setVisible(_list.hasGroupOption(onlyOne));
|
||||
_sendImagesAsPhotos->setVisible(
|
||||
_list.hasSendImagesAsPhotosOption(onlyOne));
|
||||
|
||||
_hintLabel->setVisible(
|
||||
_controller->session().settings().photoEditorHintShown()
|
||||
? _list.hasSendImagesAsPhotosOption(false)
|
||||
: false);
|
||||
}
|
||||
|
||||
void SendFilesBox::setupCaption() {
|
||||
@@ -850,14 +883,15 @@ void SendFilesBox::updateBoxSize() {
|
||||
if (_caption) {
|
||||
footerHeight += st::boxPhotoCaptionSkip + _caption->height();
|
||||
}
|
||||
const auto pointers = {
|
||||
_groupFiles.data(),
|
||||
_sendImagesAsPhotos.data(),
|
||||
};
|
||||
for (auto pointer : pointers) {
|
||||
const auto pairs = std::array<std::pair<RpWidget*, int>, 3>{ {
|
||||
{ _groupFiles.data(), st::boxPhotoCompressedSkip },
|
||||
{ _sendImagesAsPhotos.data(), st::boxPhotoCompressedSkip },
|
||||
{ _hintLabel.data(), st::editMediaLabelMargins.top() },
|
||||
} };
|
||||
for (const auto &pair : pairs) {
|
||||
const auto pointer = pair.first;
|
||||
if (pointer && !pointer->isHidden()) {
|
||||
footerHeight += st::boxPhotoCompressedSkip
|
||||
+ pointer->heightNoMargins();
|
||||
footerHeight += pair.second + pointer->heightNoMargins();
|
||||
}
|
||||
}
|
||||
_footerHeight = footerHeight;
|
||||
@@ -916,16 +950,18 @@ void SendFilesBox::updateControlsGeometry() {
|
||||
_emojiToggle->update();
|
||||
}
|
||||
}
|
||||
const auto pointers = {
|
||||
_groupFiles.data(),
|
||||
_sendImagesAsPhotos.data(),
|
||||
};
|
||||
for (const auto pointer : ranges::views::reverse(pointers)) {
|
||||
const auto pairs = std::array<std::pair<RpWidget*, int>, 3>{ {
|
||||
{ _hintLabel.data(), st::editMediaLabelMargins.top() },
|
||||
{ _groupFiles.data(), st::boxPhotoCompressedSkip },
|
||||
{ _sendImagesAsPhotos.data(), st::boxPhotoCompressedSkip },
|
||||
} };
|
||||
for (const auto &pair : ranges::views::reverse(pairs)) {
|
||||
const auto pointer = pair.first;
|
||||
if (pointer && !pointer->isHidden()) {
|
||||
pointer->moveToLeft(
|
||||
st::boxPhotoPadding.left(),
|
||||
bottom - pointer->heightNoMargins());
|
||||
bottom -= st::boxPhotoCompressedSkip + pointer->heightNoMargins();
|
||||
bottom -= pair.second + pointer->heightNoMargins();
|
||||
}
|
||||
}
|
||||
_scroll->resize(width(), bottom - _titleHeight.current());
|
||||
@@ -976,6 +1012,12 @@ void SendFilesBox::send(
|
||||
for (auto &block : _blocks) {
|
||||
block.applyAlbumOrder();
|
||||
}
|
||||
|
||||
if (Storage::ApplyModifications(_list)) {
|
||||
_controller->session().settings().incrementPhotoEditorHintShown();
|
||||
_controller->session().saveSettings();
|
||||
}
|
||||
|
||||
_confirmed = true;
|
||||
if (_confirmedCallback) {
|
||||
auto caption = (_caption && !_caption->isHidden())
|
||||
|
||||
@@ -35,6 +35,7 @@ struct GroupMediaLayout;
|
||||
class EmojiButton;
|
||||
class AlbumPreview;
|
||||
class VerticalLayout;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
@@ -102,6 +103,7 @@ private:
|
||||
|
||||
[[nodiscard]] rpl::producer<int> itemDeleteRequest() const;
|
||||
[[nodiscard]] rpl::producer<int> itemReplaceRequest() const;
|
||||
[[nodiscard]] rpl::producer<int> itemModifyRequest() const;
|
||||
|
||||
void setSendWay(Ui::SendFilesWay way);
|
||||
void applyAlbumOrder();
|
||||
@@ -183,6 +185,7 @@ private:
|
||||
|
||||
object_ptr<Ui::Checkbox> _groupFiles = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _sendImagesAsPhotos = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _hintLabel = { nullptr };
|
||||
rpl::variable<Ui::SendFilesWay> _sendWay = Ui::SendFilesWay();
|
||||
|
||||
rpl::variable<int> _footerHeight = 0;
|
||||
|
||||
@@ -27,7 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history.h"
|
||||
#include "history/history_message.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
@@ -42,7 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
class ShareBox::Inner final : public Ui::RpWidget, private base::Subscriber {
|
||||
class ShareBox::Inner final : public Ui::RpWidget {
|
||||
public:
|
||||
Inner(QWidget *parent, const Descriptor &descriptor);
|
||||
|
||||
@@ -598,11 +597,10 @@ ShareBox::Inner::Inner(QWidget *parent, const Descriptor &descriptor)
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
invalidateCache();
|
||||
}
|
||||
});
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
invalidateCache();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void ShareBox::Inner::invalidateCache() {
|
||||
@@ -1113,7 +1111,6 @@ QString AppendShareGameScoreUrl(
|
||||
? session->data().channelLoaded(fullId.channel)
|
||||
: static_cast<ChannelData*>(nullptr);
|
||||
auto channelAccessHash = uint64(channel ? channel->access : 0);
|
||||
auto channelAccessHashInts = reinterpret_cast<int32*>(&channelAccessHash);
|
||||
shareHashDataInts[0] = session->userId().bare;
|
||||
shareHashDataInts[1] = fullId.channel.bare;
|
||||
shareHashDataInts[2] = fullId.msg;
|
||||
|
||||
@@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/image/image_location_factory.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/effects/path_shift_gradient.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
@@ -50,15 +51,16 @@ constexpr auto kStickersPanelPerRow = 5;
|
||||
using Data::StickersSet;
|
||||
using Data::StickersPack;
|
||||
using Data::StickersByEmojiMap;
|
||||
using SetFlag = Data::StickersSetFlag;
|
||||
|
||||
} // namespace
|
||||
|
||||
class StickerSetBox::Inner : public Ui::RpWidget, private base::Subscriber {
|
||||
class StickerSetBox::Inner final : public Ui::RpWidget {
|
||||
public:
|
||||
Inner(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const MTPInputStickerSet &set);
|
||||
const StickerSetIdentifier &set);
|
||||
|
||||
bool loaded() const;
|
||||
bool notInstalled() const;
|
||||
@@ -68,10 +70,17 @@ public:
|
||||
|
||||
void install();
|
||||
[[nodiscard]] rpl::producer<uint64> setInstalled() const;
|
||||
[[nodiscard]] rpl::producer<uint64> setArchived() const;
|
||||
[[nodiscard]] rpl::producer<> updateControls() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<Error> errors() const;
|
||||
|
||||
void archiveStickers();
|
||||
|
||||
bool isMasksSet() const {
|
||||
return (_setFlags & SetFlag::Masks);
|
||||
}
|
||||
|
||||
~Inner();
|
||||
|
||||
protected:
|
||||
@@ -104,10 +113,6 @@ private:
|
||||
void gotSet(const MTPmessages_StickerSet &set);
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
|
||||
bool isMasksSet() const {
|
||||
return (_setFlags & MTPDstickerSet::Flag::f_masks);
|
||||
}
|
||||
|
||||
not_null<Lottie::MultiPlayer*> getLottiePlayer();
|
||||
|
||||
void showPreview();
|
||||
@@ -124,11 +129,13 @@ private:
|
||||
QString _setTitle, _setShortName;
|
||||
int _setCount = 0;
|
||||
int32 _setHash = 0;
|
||||
MTPDstickerSet::Flags _setFlags = 0;
|
||||
Data::StickersSetFlags _setFlags;
|
||||
TimeId _setInstallDate = TimeId(0);
|
||||
ImageWithLocation _setThumbnail;
|
||||
|
||||
MTPInputStickerSet _input;
|
||||
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
||||
|
||||
StickerSetIdentifier _input;
|
||||
|
||||
mtpRequestId _installRequest = 0;
|
||||
|
||||
@@ -138,6 +145,7 @@ private:
|
||||
int _previewShown = -1;
|
||||
|
||||
rpl::event_stream<uint64> _setInstalled;
|
||||
rpl::event_stream<uint64> _setArchived;
|
||||
rpl::event_stream<> _updateControls;
|
||||
rpl::event_stream<Error> _errors;
|
||||
|
||||
@@ -146,7 +154,7 @@ private:
|
||||
StickerSetBox::StickerSetBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const MTPInputStickerSet &set)
|
||||
const StickerSetIdentifier &set)
|
||||
: _controller(controller)
|
||||
, _set(set) {
|
||||
}
|
||||
@@ -155,7 +163,7 @@ QPointer<Ui::BoxContent> StickerSetBox::Show(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<DocumentData*> document) {
|
||||
if (const auto sticker = document->sticker()) {
|
||||
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
|
||||
if (sticker->set) {
|
||||
return controller->show(
|
||||
Box<StickerSetBox>(controller, sticker->set),
|
||||
Ui::LayerOption::KeepOther).data();
|
||||
@@ -186,7 +194,12 @@ void StickerSetBox::prepare() {
|
||||
|
||||
_inner->setInstalled(
|
||||
) | rpl::start_with_next([=](uint64 setId) {
|
||||
_controller->session().api().stickerSetInstalled(setId);
|
||||
if (_inner->isMasksSet()) {
|
||||
Ui::Toast::Show(tr::lng_masks_installed(tr::now));
|
||||
} else {
|
||||
auto &stickers = _controller->session().data().stickers();
|
||||
stickers.notifyStickerSetInstalled(setId);
|
||||
}
|
||||
closeBox();
|
||||
}, lifetime());
|
||||
|
||||
@@ -194,6 +207,36 @@ void StickerSetBox::prepare() {
|
||||
) | rpl::start_with_next([=](Error error) {
|
||||
handleError(error);
|
||||
}, lifetime());
|
||||
|
||||
_inner->setArchived(
|
||||
) | rpl::start_with_next([=](uint64 setId) {
|
||||
const auto isMasks = _inner->isMasksSet();
|
||||
|
||||
Ui::Toast::Show(isMasks
|
||||
? tr::lng_masks_has_been_archived(tr::now)
|
||||
: tr::lng_stickers_has_been_archived(tr::now));
|
||||
|
||||
auto &order = isMasks
|
||||
? _controller->session().data().stickers().maskSetsOrderRef()
|
||||
: _controller->session().data().stickers().setsOrderRef();
|
||||
const auto index = order.indexOf(setId);
|
||||
if (index != -1) {
|
||||
order.removeAt(index);
|
||||
|
||||
auto &local = _controller->session().local();
|
||||
if (isMasks) {
|
||||
local.writeInstalledMasks();
|
||||
local.writeArchivedMasks();
|
||||
} else {
|
||||
local.writeInstalledStickers();
|
||||
local.writeArchivedStickers();
|
||||
}
|
||||
}
|
||||
|
||||
_controller->session().data().stickers().notifyUpdated();
|
||||
|
||||
closeBox();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void StickerSetBox::addStickers() {
|
||||
@@ -220,38 +263,6 @@ void StickerSetBox::handleError(Error error) {
|
||||
}
|
||||
}
|
||||
|
||||
void StickerSetBox::archiveStickers() {
|
||||
const auto weak = base::make_weak(_controller.get());
|
||||
const auto setId = _set.c_inputStickerSetID().vid().v;
|
||||
_controller->session().api().request(MTPmessages_InstallStickerSet(
|
||||
_set,
|
||||
MTP_boolTrue()
|
||||
)).done([=](const MTPmessages_StickerSetInstallResult &result) {
|
||||
const auto controller = weak.get();
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
if (result.type() == mtpc_messages_stickerSetInstallResultSuccess) {
|
||||
Ui::Toast::Show(tr::lng_stickers_has_been_archived(tr::now));
|
||||
|
||||
const auto &session = controller->session();
|
||||
auto &order = session.data().stickers().setsOrderRef();
|
||||
const auto index = order.indexOf(setId);
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
order.removeAt(index);
|
||||
|
||||
session.local().writeInstalledStickers();
|
||||
session.local().writeArchivedStickers();
|
||||
|
||||
session.data().stickers().notifyUpdated();
|
||||
}
|
||||
}).fail([](const MTP::Error &error) {
|
||||
Ui::Toast::Show(Lang::Hard::ServerError());
|
||||
}).send();
|
||||
}
|
||||
|
||||
void StickerSetBox::updateTitleAndButtons() {
|
||||
setTitle(_inner->title());
|
||||
updateButtons();
|
||||
@@ -260,8 +271,12 @@ void StickerSetBox::updateTitleAndButtons() {
|
||||
void StickerSetBox::updateButtons() {
|
||||
clearButtons();
|
||||
if (_inner->loaded()) {
|
||||
const auto isMasks = _inner->isMasksSet();
|
||||
if (_inner->notInstalled()) {
|
||||
addButton(tr::lng_stickers_add_pack(), [=] { addStickers(); });
|
||||
auto addText = isMasks
|
||||
? tr::lng_stickers_add_masks()
|
||||
: tr::lng_stickers_add_pack();
|
||||
addButton(std::move(addText), [=] { addStickers(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
if (!_inner->shortName().isEmpty()) {
|
||||
@@ -276,7 +291,9 @@ void StickerSetBox::updateButtons() {
|
||||
top->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(top);
|
||||
(*menu)->addAction(
|
||||
tr::lng_stickers_share_pack(tr::now),
|
||||
(isMasks
|
||||
? tr::lng_stickers_share_masks
|
||||
: tr::lng_stickers_share_pack)(tr::now),
|
||||
share);
|
||||
(*menu)->popup(QCursor::pos());
|
||||
return true;
|
||||
@@ -289,21 +306,25 @@ void StickerSetBox::updateButtons() {
|
||||
copyStickersLink();
|
||||
Ui::Toast::Show(tr::lng_stickers_copied(tr::now));
|
||||
};
|
||||
addButton(tr::lng_stickers_share_pack(), std::move(share));
|
||||
auto shareText = isMasks
|
||||
? tr::lng_stickers_share_masks()
|
||||
: tr::lng_stickers_share_pack();
|
||||
addButton(std::move(shareText), std::move(share));
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
if (!_inner->shortName().isEmpty()) {
|
||||
const auto top = addTopButton(st::infoTopBarMenu);
|
||||
const auto archive = [=] {
|
||||
archiveStickers();
|
||||
closeBox();
|
||||
_inner->archiveStickers();
|
||||
};
|
||||
const auto menu =
|
||||
std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
|
||||
top->setClickedCallback([=] {
|
||||
*menu = base::make_unique_q<Ui::PopupMenu>(top);
|
||||
(*menu)->addAction(
|
||||
tr::lng_stickers_archive_pack(tr::now),
|
||||
isMasks
|
||||
? tr::lng_masks_archive_pack(tr::now)
|
||||
: tr::lng_stickers_archive_pack(tr::now),
|
||||
archive);
|
||||
(*menu)->popup(QCursor::pos());
|
||||
return true;
|
||||
@@ -324,24 +345,21 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) {
|
||||
StickerSetBox::Inner::Inner(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const MTPInputStickerSet &set)
|
||||
const StickerSetIdentifier &set)
|
||||
: RpWidget(parent)
|
||||
, _controller(controller)
|
||||
, _api(&_controller->session().mtp())
|
||||
, _setId(set.id)
|
||||
, _setAccess(set.accessHash)
|
||||
, _setShortName(set.shortName)
|
||||
, _pathGradient(std::make_unique<Ui::PathShiftGradient>(
|
||||
st::windowBgRipple,
|
||||
st::windowBgOver,
|
||||
[=] { update(); }))
|
||||
, _input(set)
|
||||
, _previewTimer([=] { showPreview(); }) {
|
||||
set.match([&](const MTPDinputStickerSetID &data) {
|
||||
_setId = data.vid().v;
|
||||
_setAccess = data.vaccess_hash().v;
|
||||
}, [&](const MTPDinputStickerSetShortName &data) {
|
||||
_setShortName = qs(data.vshort_name());
|
||||
}, [](const MTPDinputStickerSetEmpty &) {
|
||||
}, [](const MTPDinputStickerSetAnimatedEmoji &) {
|
||||
}, [](const MTPDinputStickerSetDice &) {
|
||||
});
|
||||
|
||||
_api.request(MTPmessages_GetStickerSet(
|
||||
_input
|
||||
Data::InputStickerSet(_input)
|
||||
)).done([=](const MTPmessages_StickerSet &result) {
|
||||
gotSet(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
@@ -404,7 +422,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
|
||||
_setAccess = set.vaccess_hash().v;
|
||||
_setCount = set.vcount().v;
|
||||
_setHash = set.vhash().v;
|
||||
_setFlags = set.vflags().v;
|
||||
_setFlags = Data::ParseStickersSetFlags(set);
|
||||
_setInstallDate = set.vinstalled_date().value_or(0);
|
||||
_setThumbnail = [&] {
|
||||
if (const auto thumbs = set.vthumbs()) {
|
||||
@@ -424,12 +442,11 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
|
||||
const auto it = sets.find(_setId);
|
||||
if (it != sets.cend()) {
|
||||
const auto set = it->second.get();
|
||||
using ClientFlag = MTPDstickerSet_ClientFlag;
|
||||
const auto clientFlags = set->flags
|
||||
& (ClientFlag::f_featured
|
||||
| ClientFlag::f_not_loaded
|
||||
| ClientFlag::f_unread
|
||||
| ClientFlag::f_special);
|
||||
& (SetFlag::Featured
|
||||
| SetFlag::NotLoaded
|
||||
| SetFlag::Unread
|
||||
| SetFlag::Special);
|
||||
_setFlags |= clientFlags;
|
||||
set->flags = _setFlags;
|
||||
set->installDate = _setInstallDate;
|
||||
@@ -457,6 +474,10 @@ rpl::producer<uint64> StickerSetBox::Inner::setInstalled() const {
|
||||
return _setInstalled.events();
|
||||
}
|
||||
|
||||
rpl::producer<uint64> StickerSetBox::Inner::setArchived() const {
|
||||
return _setArchived.events();
|
||||
}
|
||||
|
||||
rpl::producer<> StickerSetBox::Inner::updateControls() const {
|
||||
return _updateControls.events();
|
||||
}
|
||||
@@ -467,18 +488,24 @@ rpl::producer<StickerSetBox::Error> StickerSetBox::Inner::errors() const {
|
||||
|
||||
void StickerSetBox::Inner::installDone(
|
||||
const MTPmessages_StickerSetInstallResult &result) {
|
||||
auto &sets = _controller->session().data().stickers().setsRef();
|
||||
auto &stickers = _controller->session().data().stickers();
|
||||
auto &sets = stickers.setsRef();
|
||||
const auto isMasks = isMasksSet();
|
||||
|
||||
bool wasArchived = (_setFlags & MTPDstickerSet::Flag::f_archived);
|
||||
const bool wasArchived = (_setFlags & SetFlag::Archived);
|
||||
if (wasArchived) {
|
||||
auto index = _controller->session().data().stickers().archivedSetsOrderRef().indexOf(_setId);
|
||||
const auto index = (isMasks
|
||||
? stickers.archivedMaskSetsOrderRef()
|
||||
: stickers.archivedSetsOrderRef()).indexOf(_setId);
|
||||
if (index >= 0) {
|
||||
_controller->session().data().stickers().archivedSetsOrderRef().removeAt(index);
|
||||
(isMasks
|
||||
? stickers.archivedMaskSetsOrderRef()
|
||||
: stickers.archivedSetsOrderRef()).removeAt(index);
|
||||
}
|
||||
}
|
||||
_setInstallDate = base::unixtime::now();
|
||||
_setFlags &= ~MTPDstickerSet::Flag::f_archived;
|
||||
_setFlags |= MTPDstickerSet::Flag::f_installed_date;
|
||||
_setFlags &= ~SetFlag::Archived;
|
||||
_setFlags |= SetFlag::Installed;
|
||||
auto it = sets.find(_setId);
|
||||
if (it == sets.cend()) {
|
||||
it = sets.emplace(
|
||||
@@ -502,8 +529,10 @@ void StickerSetBox::Inner::installDone(
|
||||
set->stickers = _pack;
|
||||
set->emoji = _emoji;
|
||||
|
||||
auto &order = _controller->session().data().stickers().setsOrderRef();
|
||||
int insertAtIndex = 0, currentIndex = order.indexOf(_setId);
|
||||
auto &order = isMasks
|
||||
? stickers.maskSetsOrderRef()
|
||||
: stickers.setsOrderRef();
|
||||
const auto insertAtIndex = 0, currentIndex = order.indexOf(_setId);
|
||||
if (currentIndex != insertAtIndex) {
|
||||
if (currentIndex > 0) {
|
||||
order.removeAt(currentIndex);
|
||||
@@ -515,8 +544,10 @@ void StickerSetBox::Inner::installDone(
|
||||
if (customIt != sets.cend()) {
|
||||
const auto custom = customIt->second.get();
|
||||
for (const auto sticker : std::as_const(_pack)) {
|
||||
int removeIndex = custom->stickers.indexOf(sticker);
|
||||
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
|
||||
const int removeIndex = custom->stickers.indexOf(sticker);
|
||||
if (removeIndex >= 0) {
|
||||
custom->stickers.removeAt(removeIndex);
|
||||
}
|
||||
}
|
||||
if (custom->stickers.isEmpty()) {
|
||||
sets.erase(customIt);
|
||||
@@ -524,14 +555,23 @@ void StickerSetBox::Inner::installDone(
|
||||
}
|
||||
|
||||
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
|
||||
_controller->session().data().stickers().applyArchivedResult(
|
||||
stickers.applyArchivedResult(
|
||||
result.c_messages_stickerSetInstallResultArchive());
|
||||
} else {
|
||||
auto &storage = _controller->session().local();
|
||||
if (wasArchived) {
|
||||
_controller->session().local().writeArchivedStickers();
|
||||
if (isMasks) {
|
||||
storage.writeArchivedMasks();
|
||||
} else {
|
||||
storage.writeArchivedStickers();
|
||||
}
|
||||
}
|
||||
_controller->session().local().writeInstalledStickers();
|
||||
_controller->session().data().stickers().notifyUpdated();
|
||||
if (isMasks) {
|
||||
storage.writeInstalledMasks();
|
||||
} else {
|
||||
storage.writeInstalledStickers();
|
||||
}
|
||||
stickers.notifyUpdated();
|
||||
}
|
||||
_setInstalled.fire_copy(_setId);
|
||||
}
|
||||
@@ -648,10 +688,10 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32 rows = (_elements.size() / kStickersPanelPerRow)
|
||||
+ ((_elements.size() % kStickersPanelPerRow) ? 1 : 0);
|
||||
int32 from = qFloor(e->rect().top() / st::stickersSize.height()), to = qFloor(e->rect().bottom() / st::stickersSize.height()) + 1;
|
||||
|
||||
_pathGradient->startFrame(0, width(), width() / 2);
|
||||
|
||||
for (int32 i = from; i < to; ++i) {
|
||||
for (int32 j = 0; j < kStickersPanelPerRow; ++j) {
|
||||
int32 index = i * kStickersPanelPerRow + j;
|
||||
@@ -747,7 +787,8 @@ void StickerSetBox::Inner::paintSticker(
|
||||
const auto &media = element.documentMedia;
|
||||
media->checkStickerSmall();
|
||||
|
||||
if (document->sticker()->animated
|
||||
const auto isAnimated = document->sticker()->animated;
|
||||
if (isAnimated
|
||||
&& !element.animated
|
||||
&& media->loaded()) {
|
||||
const_cast<Inner*>(this)->setupLottie(index);
|
||||
@@ -755,7 +796,7 @@ void StickerSetBox::Inner::paintSticker(
|
||||
|
||||
auto w = 1;
|
||||
auto h = 1;
|
||||
if (element.animated && !document->dimensions.isEmpty()) {
|
||||
if (isAnimated && !document->dimensions.isEmpty()) {
|
||||
const auto request = Lottie::FrameRequest{ boundingBoxSize() * cIntRetinaFactor() };
|
||||
const auto size = request.size(document->dimensions, true) / cIntRetinaFactor();
|
||||
w = std::max(size.width(), 1);
|
||||
@@ -767,6 +808,7 @@ void StickerSetBox::Inner::paintSticker(
|
||||
h = std::max(qRound(coef * document->dimensions.height()), 1);
|
||||
}
|
||||
QPoint ppos = position + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2);
|
||||
|
||||
if (element.animated && element.animated->ready()) {
|
||||
const auto frame = element.animated->frame();
|
||||
p.drawImage(
|
||||
@@ -779,6 +821,12 @@ void StickerSetBox::Inner::paintSticker(
|
||||
ppos,
|
||||
width(),
|
||||
image->pix(w, h));
|
||||
} else {
|
||||
ChatHelpers::PaintStickerThumbnailPath(
|
||||
p,
|
||||
media.get(),
|
||||
QRect(ppos, QSize(w, h)),
|
||||
_pathGradient.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,8 +841,8 @@ bool StickerSetBox::Inner::notInstalled() const {
|
||||
const auto &sets = _controller->session().data().stickers().sets();
|
||||
const auto it = sets.find(_setId);
|
||||
if ((it == sets.cend())
|
||||
|| !(it->second->flags & MTPDstickerSet::Flag::f_installed_date)
|
||||
|| (it->second->flags & MTPDstickerSet::Flag::f_archived)) {
|
||||
|| !(it->second->flags & SetFlag::Installed)
|
||||
|| (it->second->flags & SetFlag::Archived)) {
|
||||
return !_pack.empty();
|
||||
}
|
||||
return false;
|
||||
@@ -820,16 +868,11 @@ QString StickerSetBox::Inner::shortName() const {
|
||||
}
|
||||
|
||||
void StickerSetBox::Inner::install() {
|
||||
if (isMasksSet()) {
|
||||
_controller->show(
|
||||
Box<InformBox>(tr::lng_stickers_masks_pack(tr::now)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
return;
|
||||
} else if (_installRequest) {
|
||||
if (_installRequest) {
|
||||
return;
|
||||
}
|
||||
_installRequest = _api.request(MTPmessages_InstallStickerSet(
|
||||
_input,
|
||||
Data::InputStickerSet(_input),
|
||||
MTP_bool(false)
|
||||
)).done([=](const MTPmessages_StickerSetInstallResult &result) {
|
||||
installDone(result);
|
||||
@@ -838,4 +881,17 @@ void StickerSetBox::Inner::install() {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void StickerSetBox::Inner::archiveStickers() {
|
||||
_api.request(MTPmessages_InstallStickerSet(
|
||||
Data::InputStickerSet(_input),
|
||||
MTP_boolTrue()
|
||||
)).done([=](const MTPmessages_StickerSetInstallResult &result) {
|
||||
if (result.type() == mtpc_messages_stickerSetInstallResultSuccess) {
|
||||
_setArchived.fire_copy(_setId);
|
||||
}
|
||||
}).fail([](const MTP::Error &error) {
|
||||
Ui::Toast::Show(Lang::Hard::ServerError());
|
||||
}).send();
|
||||
}
|
||||
|
||||
StickerSetBox::Inner::~Inner() = default;
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
StickerSetBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const MTPInputStickerSet &set);
|
||||
const StickerSetIdentifier &set);
|
||||
|
||||
static QPointer<Ui::BoxContent> Show(
|
||||
not_null<Window::SessionController*> controller,
|
||||
@@ -46,11 +46,10 @@ private:
|
||||
void updateButtons();
|
||||
void addStickers();
|
||||
void copyStickersLink();
|
||||
void archiveStickers();
|
||||
void handleError(Error error);
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
MTPInputStickerSet _set;
|
||||
const StickerSetIdentifier _set;
|
||||
|
||||
class Inner;
|
||||
QPointer<Inner> _inner;
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace {
|
||||
using Data::StickersSet;
|
||||
using Data::StickersSetsOrder;
|
||||
using Data::StickersSetThumbnailView;
|
||||
using SetFlag = Data::StickersSetFlag;
|
||||
|
||||
constexpr auto kArchivedLimitFirstRequest = 10;
|
||||
constexpr auto kArchivedLimitPerPage = 30;
|
||||
@@ -90,7 +91,7 @@ public:
|
||||
|
||||
void saveGroupSet();
|
||||
|
||||
void rebuild();
|
||||
void rebuild(bool masks);
|
||||
void updateSize(int newWidth = 0);
|
||||
void updateRows(); // refresh only pack cover stickers
|
||||
bool appendSet(not_null<StickersSet*> set);
|
||||
@@ -152,6 +153,7 @@ private:
|
||||
~Row();
|
||||
|
||||
bool isRecentSet() const;
|
||||
bool isMasksSet() const;
|
||||
|
||||
const not_null<StickersSet*> set;
|
||||
DocumentData *sticker = nullptr;
|
||||
@@ -232,14 +234,15 @@ private:
|
||||
void rebuildMegagroupSet();
|
||||
void fixupMegagroupSetAddress();
|
||||
void handleMegagroupSetAddressChange();
|
||||
void setMegagroupSelectedSet(const MTPInputStickerSet &set);
|
||||
void setMegagroupSelectedSet(const StickerSetIdentifier &set);
|
||||
|
||||
int countMaxNameWidth() const;
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
MTP::Sender _api;
|
||||
|
||||
Section _section;
|
||||
const Section _section;
|
||||
const bool _isInstalled;
|
||||
|
||||
int32 _rowHeight;
|
||||
|
||||
@@ -282,7 +285,7 @@ private:
|
||||
|
||||
int _scrollbar = 0;
|
||||
ChannelData *_megagroupSet = nullptr;
|
||||
MTPInputStickerSet _megagroupSetInput = MTP_inputStickerSetEmpty();
|
||||
StickerSetIdentifier _megagroupSetInput;
|
||||
std::unique_ptr<Row> _megagroupSelectedSet;
|
||||
object_ptr<AddressField> _megagroupSetField = { nullptr };
|
||||
object_ptr<Ui::PlainShadow> _megagroupSelectedShadow = { nullptr };
|
||||
@@ -351,7 +354,7 @@ void StickersBox::Tab::returnWidget(object_ptr<Inner> widget) {
|
||||
Assert(_widget == _weak);
|
||||
}
|
||||
|
||||
StickersBox::Inner *StickersBox::Tab::widget() {
|
||||
StickersBox::Inner *StickersBox::Tab::widget() const {
|
||||
return _weak;
|
||||
}
|
||||
|
||||
@@ -366,7 +369,8 @@ void StickersBox::Tab::saveScrollTop() {
|
||||
StickersBox::StickersBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Section section)
|
||||
Section section,
|
||||
bool masks)
|
||||
: _controller(controller)
|
||||
, _api(&controller->session().mtp())
|
||||
, _tabs(this, st::stickersTabs)
|
||||
@@ -374,9 +378,11 @@ StickersBox::StickersBox(
|
||||
this,
|
||||
controller->session().data().stickers().featuredSetsUnreadCountValue())
|
||||
, _section(section)
|
||||
, _installed(0, this, controller, Section::Installed)
|
||||
, _featured(1, this, controller, Section::Featured)
|
||||
, _archived(2, this, controller, Section::Archived) {
|
||||
, _isMasks(masks)
|
||||
, _installed(_isMasks ? Tab() : Tab(0, this, controller, Section::Installed))
|
||||
, _masks(_isMasks ? Tab(0, this, controller, Section::Masks) : Tab())
|
||||
, _featured(_isMasks ? Tab() : Tab(1, this, controller, Section::Featured))
|
||||
, _archived((_isMasks ? 1 : 2), this, controller, Section::Archived) {
|
||||
_tabs->setRippleTopRoundRadius(st::boxRadius);
|
||||
}
|
||||
|
||||
@@ -387,6 +393,7 @@ StickersBox::StickersBox(
|
||||
: _controller(controller)
|
||||
, _api(&controller->session().mtp())
|
||||
, _section(Section::Installed)
|
||||
, _isMasks(false)
|
||||
, _installed(0, this, controller, megagroup)
|
||||
, _megagroupSet(megagroup) {
|
||||
_installed.widget()->scrollsToY(
|
||||
@@ -402,6 +409,7 @@ StickersBox::StickersBox(
|
||||
: _controller(controller)
|
||||
, _api(&controller->session().mtp())
|
||||
, _section(Section::Attached)
|
||||
, _isMasks(false)
|
||||
, _attached(0, this, controller, Section::Attached)
|
||||
, _attachedSets(attachedSets) {
|
||||
}
|
||||
@@ -422,8 +430,11 @@ void StickersBox::showAttachedStickers() {
|
||||
if (const auto set = session().data().stickers().feedSet(*setData)) {
|
||||
if (_attached.widget()->appendSet(set)) {
|
||||
addedSet = true;
|
||||
if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
|
||||
session().api().scheduleStickerSetRequest(set->id, set->access);
|
||||
if (set->stickers.isEmpty()
|
||||
|| (set->flags & SetFlag::NotLoaded)) {
|
||||
session().api().scheduleStickerSetRequest(
|
||||
set->id,
|
||||
set->access);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -447,7 +458,7 @@ void StickersBox::getArchivedDone(
|
||||
}
|
||||
|
||||
auto &stickers = result.c_messages_archivedStickers();
|
||||
auto &archived = session().data().stickers().archivedSetsOrderRef();
|
||||
auto &archived = archivedSetsOrderRef();
|
||||
if (offsetId) {
|
||||
auto index = archived.indexOf(offsetId);
|
||||
if (index >= 0) {
|
||||
@@ -488,8 +499,11 @@ void StickersBox::getArchivedDone(
|
||||
}
|
||||
if (_archived.widget()->appendSet(set)) {
|
||||
addedSet = true;
|
||||
if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
|
||||
session().api().scheduleStickerSetRequest(set->id, set->access);
|
||||
if (set->stickers.isEmpty()
|
||||
|| (set->flags & SetFlag::NotLoaded)) {
|
||||
session().api().scheduleStickerSetRequest(
|
||||
set->id,
|
||||
set->access);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,7 +528,11 @@ void StickersBox::getArchivedDone(
|
||||
void StickersBox::prepare() {
|
||||
if (_section == Section::Installed) {
|
||||
if (_tabs) {
|
||||
session().local().readArchivedStickers();
|
||||
if (_isMasks) {
|
||||
session().local().readArchivedMasks();
|
||||
} else {
|
||||
session().local().readArchivedStickers();
|
||||
}
|
||||
} else {
|
||||
setTitle(tr::lng_stickers_group_set());
|
||||
}
|
||||
@@ -524,7 +542,7 @@ void StickersBox::prepare() {
|
||||
setTitle(tr::lng_stickers_attached_sets());
|
||||
}
|
||||
if (_tabs) {
|
||||
if (session().data().stickers().archivedSetsOrder().isEmpty()) {
|
||||
if (archivedSetsOrder().isEmpty()) {
|
||||
preloadArchivedSets();
|
||||
}
|
||||
setNoContentMargin(true);
|
||||
@@ -534,21 +552,33 @@ void StickersBox::prepare() {
|
||||
lifetime());
|
||||
refreshTabs();
|
||||
}
|
||||
if (_installed.widget() && _section != Section::Installed) _installed.widget()->hide();
|
||||
if (_featured.widget() && _section != Section::Featured) _featured.widget()->hide();
|
||||
if (_archived.widget() && _section != Section::Archived) _archived.widget()->hide();
|
||||
if (_attached.widget() && _section != Section::Attached) _attached.widget()->hide();
|
||||
if (_installed.widget() && _section != Section::Installed) {
|
||||
_installed.widget()->hide();
|
||||
}
|
||||
if (_masks.widget() && _section != Section::Masks) {
|
||||
_masks.widget()->hide();
|
||||
}
|
||||
if (_featured.widget() && _section != Section::Featured) {
|
||||
_featured.widget()->hide();
|
||||
}
|
||||
if (_archived.widget() && _section != Section::Archived) {
|
||||
_archived.widget()->hide();
|
||||
}
|
||||
if (_attached.widget() && _section != Section::Attached) {
|
||||
_attached.widget()->hide();
|
||||
}
|
||||
|
||||
const auto installCallback = [=](uint64 setId) { installSet(setId); };
|
||||
if (_featured.widget()) {
|
||||
_featured.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); });
|
||||
_featured.widget()->setInstallSetCallback(installCallback);
|
||||
}
|
||||
if (_archived.widget()) {
|
||||
_archived.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); });
|
||||
_archived.widget()->setLoadMoreCallback([this] { loadMoreArchived(); });
|
||||
_archived.widget()->setInstallSetCallback(installCallback);
|
||||
_archived.widget()->setLoadMoreCallback([=] { loadMoreArchived(); });
|
||||
}
|
||||
if (_attached.widget()) {
|
||||
_attached.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); });
|
||||
_attached.widget()->setLoadMoreCallback([this] { showAttachedStickers(); });
|
||||
_attached.widget()->setInstallSetCallback(installCallback);
|
||||
_attached.widget()->setLoadMoreCallback([=] { showAttachedStickers(); });
|
||||
}
|
||||
|
||||
if (_megagroupSet) {
|
||||
@@ -565,6 +595,8 @@ void StickersBox::prepare() {
|
||||
|
||||
if (_section == Section::Installed) {
|
||||
_tab = &_installed;
|
||||
} else if (_section == Section::Masks) {
|
||||
_tab = &_masks;
|
||||
} else if (_section == Section::Archived) {
|
||||
_tab = &_archived;
|
||||
} else if (_section == Section::Attached) {
|
||||
@@ -580,18 +612,21 @@ void StickersBox::prepare() {
|
||||
[this] { handleStickersUpdated(); },
|
||||
lifetime());
|
||||
session().api().updateStickers();
|
||||
session().api().updateMasks();
|
||||
|
||||
if (_installed.widget()) {
|
||||
_installed.widget()->draggingScrollDelta(
|
||||
) | rpl::start_with_next([=](int delta) {
|
||||
scrollByDraggingDelta(delta);
|
||||
}, _installed.widget()->lifetime());
|
||||
if (!_megagroupSet) {
|
||||
boxClosing() | rpl::start_with_next([=] {
|
||||
saveChanges();
|
||||
}, lifetime());
|
||||
for (const auto &widget : { _installed.widget(), _masks.widget() }) {
|
||||
if (widget) {
|
||||
widget->draggingScrollDelta(
|
||||
) | rpl::start_with_next([=](int delta) {
|
||||
scrollByDraggingDelta(delta);
|
||||
}, widget->lifetime());
|
||||
}
|
||||
}
|
||||
if (!_megagroupSet) {
|
||||
boxClosing() | rpl::start_with_next([=] {
|
||||
saveChanges();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
if (_tabs) {
|
||||
_tabs->raise();
|
||||
@@ -601,28 +636,41 @@ void StickersBox::prepare() {
|
||||
}
|
||||
|
||||
void StickersBox::refreshTabs() {
|
||||
if (!_tabs) return;
|
||||
if (!_tabs) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &stickers = session().data().stickers();
|
||||
|
||||
_tabIndices.clear();
|
||||
auto sections = QStringList();
|
||||
sections.push_back(tr::lng_stickers_installed_tab(tr::now).toUpper());
|
||||
_tabIndices.push_back(Section::Installed);
|
||||
if (!session().data().stickers().featuredSetsOrder().isEmpty()) {
|
||||
auto sections = std::vector<QString>();
|
||||
if (_installed.widget()) {
|
||||
sections.push_back(tr::lng_stickers_installed_tab(tr::now).toUpper());
|
||||
_tabIndices.push_back(Section::Installed);
|
||||
}
|
||||
if (_masks.widget()) {
|
||||
sections.push_back(tr::lng_stickers_masks_tab(tr::now).toUpper());
|
||||
_tabIndices.push_back(Section::Masks);
|
||||
}
|
||||
if (!stickers.featuredSetsOrder().isEmpty() && _featured.widget()) {
|
||||
sections.push_back(tr::lng_stickers_featured_tab(tr::now).toUpper());
|
||||
_tabIndices.push_back(Section::Featured);
|
||||
}
|
||||
if (!session().data().stickers().archivedSetsOrder().isEmpty()) {
|
||||
if (!archivedSetsOrder().isEmpty() && _archived.widget()) {
|
||||
sections.push_back(tr::lng_stickers_archived_tab(tr::now).toUpper());
|
||||
_tabIndices.push_back(Section::Archived);
|
||||
}
|
||||
_tabs->setSections(sections);
|
||||
if ((_tab == &_archived && !_tabIndices.contains(Section::Archived))
|
||||
|| (_tab == &_featured && !_tabIndices.contains(Section::Featured))) {
|
||||
|| (_tab == &_featured && !_tabIndices.contains(Section::Featured))
|
||||
|| (_tab == &_masks && !_tabIndices.contains(Section::Masks))) {
|
||||
switchTab();
|
||||
} else if (_tab == &_archived) {
|
||||
_tabs->setActiveSectionFast(_tabIndices.indexOf(Section::Archived));
|
||||
} else if (_tab == &_featured) {
|
||||
_tabs->setActiveSectionFast(_tabIndices.indexOf(Section::Featured));
|
||||
} else if (_tab == &_masks) {
|
||||
_tabs->setActiveSectionFast(_tabIndices.indexOf(Section::Masks));
|
||||
}
|
||||
updateTabsGeometry();
|
||||
}
|
||||
@@ -635,20 +683,23 @@ void StickersBox::loadMoreArchived() {
|
||||
}
|
||||
|
||||
uint64 lastId = 0;
|
||||
const auto &order = session().data().stickers().archivedSetsOrder();
|
||||
const auto &order = archivedSetsOrder();
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
for (auto setIt = order.cend(), e = order.cbegin(); setIt != e;) {
|
||||
--setIt;
|
||||
auto it = sets.find(*setIt);
|
||||
if (it != sets.cend()) {
|
||||
if (it->second->flags & MTPDstickerSet::Flag::f_archived) {
|
||||
if (it->second->flags & SetFlag::Archived) {
|
||||
lastId = it->second->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto flags = _isMasks
|
||||
? MTPmessages_GetArchivedStickers::Flag::f_masks
|
||||
: MTPmessages_GetArchivedStickers::Flags(0);
|
||||
_archivedRequestId = _api.request(MTPmessages_GetArchivedStickers(
|
||||
MTP_flags(0),
|
||||
MTP_flags(flags),
|
||||
MTP_long(lastId),
|
||||
MTP_int(kArchivedLimitPerPage)
|
||||
)).done([=](const MTPmessages_ArchivedStickers &result) {
|
||||
@@ -674,13 +725,15 @@ void StickersBox::paintEvent(QPaintEvent *e) {
|
||||
void StickersBox::updateTabsGeometry() {
|
||||
if (!_tabs) return;
|
||||
|
||||
_tabs->resizeToWidth(_tabIndices.size() * width() / 3);
|
||||
const auto maxTabs = _isMasks ? 2 : 3;
|
||||
|
||||
_tabs->resizeToWidth(_tabIndices.size() * width() / maxTabs);
|
||||
_unreadBadge->setVisible(_tabIndices.contains(Section::Featured));
|
||||
|
||||
setInnerTopSkip(getTopSkip());
|
||||
|
||||
auto featuredLeft = width() / 3;
|
||||
auto featuredRight = 2 * width() / 3;
|
||||
auto featuredLeft = width() / maxTabs;
|
||||
auto featuredRight = 2 * width() / maxTabs;
|
||||
auto featuredTextWidth = st::stickersTabs.labelStyle.font->width(tr::lng_stickers_featured_tab(tr::now).toUpper());
|
||||
auto featuredTextRight = featuredLeft + (featuredRight - featuredLeft - featuredTextWidth) / 2 + featuredTextWidth;
|
||||
auto unreadBadgeLeft = featuredTextRight - st::stickersFeaturedBadgeSkip;
|
||||
@@ -712,6 +765,9 @@ void StickersBox::switchTab() {
|
||||
} else if (newSection == Section::Archived) {
|
||||
newTab = &_archived;
|
||||
requestArchivedSets();
|
||||
} else if (newSection == Section::Masks) {
|
||||
newTab = &_masks;
|
||||
session().api().updateMasks();
|
||||
}
|
||||
if (_tab == newTab) {
|
||||
onScrollToY(0);
|
||||
@@ -744,7 +800,7 @@ void StickersBox::switchTab() {
|
||||
_slideAnimation = std::make_unique<Ui::SlideAnimation>();
|
||||
_slideAnimation->setSnapshots(std::move(wasCache), std::move(nowCache));
|
||||
auto slideLeft = wasIndex > nowIndex;
|
||||
_slideAnimation->start(slideLeft, [this] { update(); }, st::slideDuration);
|
||||
_slideAnimation->start(slideLeft, [=] { update(); }, st::slideDuration);
|
||||
setInnerVisible(false);
|
||||
|
||||
setFocus();
|
||||
@@ -758,6 +814,16 @@ QPixmap StickersBox::grabContentCache() {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::array<StickersBox::Inner*, 5> StickersBox::widgets() const {
|
||||
return {
|
||||
_installed.widget(),
|
||||
_featured.widget(),
|
||||
_archived.widget(),
|
||||
_attached.widget(),
|
||||
_masks.widget()
|
||||
};
|
||||
}
|
||||
|
||||
void StickersBox::installSet(uint64 setId) {
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
const auto it = sets.find(setId);
|
||||
@@ -769,13 +835,14 @@ void StickersBox::installSet(uint64 setId) {
|
||||
const auto set = it->second.get();
|
||||
if (_localRemoved.contains(setId)) {
|
||||
_localRemoved.removeOne(setId);
|
||||
if (_installed.widget()) _installed.widget()->setRemovedSets(_localRemoved);
|
||||
if (_featured.widget()) _featured.widget()->setRemovedSets(_localRemoved);
|
||||
if (_archived.widget()) _archived.widget()->setRemovedSets(_localRemoved);
|
||||
if (_attached.widget()) _attached.widget()->setRemovedSets(_localRemoved);
|
||||
for (const auto &widget : widgets()) {
|
||||
if (widget) {
|
||||
widget->setRemovedSets(_localRemoved);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(set->flags & MTPDstickerSet::Flag::f_installed_date)
|
||||
|| (set->flags & MTPDstickerSet::Flag::f_archived)) {
|
||||
if (!(set->flags & SetFlag::Installed)
|
||||
|| (set->flags & SetFlag::Archived)) {
|
||||
_api.request(MTPmessages_InstallStickerSet(
|
||||
set->mtpInput(),
|
||||
MTP_boolFalse()
|
||||
@@ -811,8 +878,11 @@ void StickersBox::preloadArchivedSets() {
|
||||
return;
|
||||
}
|
||||
if (!_archivedRequestId) {
|
||||
const auto flags = _isMasks
|
||||
? MTPmessages_GetArchivedStickers::Flag::f_masks
|
||||
: MTPmessages_GetArchivedStickers::Flags(0);
|
||||
_archivedRequestId = _api.request(MTPmessages_GetArchivedStickers(
|
||||
MTP_flags(0),
|
||||
MTP_flags(flags),
|
||||
MTP_long(0),
|
||||
MTP_int(kArchivedLimitFirstRequest)
|
||||
)).done([=](const MTPmessages_ArchivedStickers &result) {
|
||||
@@ -828,12 +898,13 @@ void StickersBox::requestArchivedSets() {
|
||||
}
|
||||
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
const auto &order = session().data().stickers().archivedSetsOrder();
|
||||
const auto &order = archivedSetsOrder();
|
||||
for (const auto setId : order) {
|
||||
auto it = sets.find(setId);
|
||||
if (it != sets.cend()) {
|
||||
const auto set = it->second.get();
|
||||
if (set->stickers.isEmpty() && (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
|
||||
if (set->stickers.isEmpty()
|
||||
&& (set->flags & SetFlag::NotLoaded)) {
|
||||
session().api().scheduleStickerSetRequest(setId, set->access);
|
||||
}
|
||||
}
|
||||
@@ -850,19 +921,22 @@ void StickersBox::resizeEvent(QResizeEvent *e) {
|
||||
if (_titleShadow) {
|
||||
_titleShadow->setGeometry(0, 0, width(), st::lineWidth);
|
||||
}
|
||||
if (_installed.widget()) _installed.widget()->resize(width(), _installed.widget()->height());
|
||||
if (_featured.widget()) _featured.widget()->resize(width(), _featured.widget()->height());
|
||||
if (_archived.widget()) _archived.widget()->resize(width(), _archived.widget()->height());
|
||||
if (_attached.widget()) _attached.widget()->resize(width(), _attached.widget()->height());
|
||||
for (const auto &widget : widgets()) {
|
||||
if (widget) {
|
||||
widget->resize(width(), widget->height());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::handleStickersUpdated() {
|
||||
if (_section == Section::Installed || _section == Section::Featured) {
|
||||
if (_section == Section::Installed
|
||||
|| _section == Section::Featured
|
||||
|| _section == Section::Masks) {
|
||||
rebuildList();
|
||||
} else {
|
||||
_tab->widget()->updateRows();
|
||||
}
|
||||
if (session().data().stickers().archivedSetsOrder().isEmpty()) {
|
||||
if (archivedSetsOrder().isEmpty()) {
|
||||
preloadArchivedSets();
|
||||
} else {
|
||||
refreshTabs();
|
||||
@@ -870,28 +944,55 @@ void StickersBox::handleStickersUpdated() {
|
||||
}
|
||||
|
||||
void StickersBox::rebuildList(Tab *tab) {
|
||||
if (_section == Section::Attached) return;
|
||||
if (!tab) tab = _tab;
|
||||
if (_section == Section::Attached) {
|
||||
return;
|
||||
}
|
||||
if (!tab) {
|
||||
tab = _tab;
|
||||
}
|
||||
|
||||
if (tab == &_installed) {
|
||||
if ((tab == &_installed) || (tab == &_masks)) {
|
||||
_localOrder = tab->widget()->getFullOrder();
|
||||
_localRemoved = tab->widget()->getRemovedSets();
|
||||
}
|
||||
tab->widget()->rebuild();
|
||||
if (tab == &_installed) {
|
||||
tab->widget()->rebuild(_isMasks);
|
||||
if ((tab == &_installed) || (tab == &_masks)) {
|
||||
tab->widget()->setFullOrder(_localOrder);
|
||||
}
|
||||
tab->widget()->setRemovedSets(_localRemoved);
|
||||
}
|
||||
|
||||
void StickersBox::saveChanges() {
|
||||
const auto installed = _installed.widget();
|
||||
const auto masks = _masks.widget();
|
||||
|
||||
// Make sure that our changes in other tabs are applied in the Installed tab.
|
||||
rebuildList(&_installed);
|
||||
if (installed) {
|
||||
rebuildList(&_installed);
|
||||
}
|
||||
if (masks) {
|
||||
rebuildList(&_masks);
|
||||
}
|
||||
|
||||
if (_someArchivedLoaded) {
|
||||
session().local().writeArchivedStickers();
|
||||
if (_isMasks) {
|
||||
session().local().writeArchivedMasks();
|
||||
} else {
|
||||
session().local().writeArchivedStickers();
|
||||
}
|
||||
}
|
||||
if (installed) {
|
||||
session().api().saveStickerSets(
|
||||
installed->getOrder(),
|
||||
installed->getRemovedSets(),
|
||||
false);
|
||||
}
|
||||
if (masks) {
|
||||
session().api().saveStickerSets(
|
||||
masks->getOrder(),
|
||||
masks->getRemovedSets(),
|
||||
true);
|
||||
}
|
||||
session().api().saveStickerSets(_installed.widget()->getOrder(), _installed.widget()->getRemovedSets());
|
||||
}
|
||||
|
||||
void StickersBox::setInnerFocus() {
|
||||
@@ -900,6 +1001,18 @@ void StickersBox::setInnerFocus() {
|
||||
}
|
||||
}
|
||||
|
||||
const Data::StickersSetsOrder &StickersBox::archivedSetsOrder() const {
|
||||
return !_isMasks
|
||||
? session().data().stickers().archivedSetsOrder()
|
||||
: session().data().stickers().archivedMaskSetsOrder();
|
||||
}
|
||||
|
||||
Data::StickersSetsOrder &StickersBox::archivedSetsOrderRef() {
|
||||
return !_isMasks
|
||||
? session().data().stickers().archivedSetsOrderRef()
|
||||
: session().data().stickers().archivedMaskSetsOrderRef();
|
||||
}
|
||||
|
||||
StickersBox::~StickersBox() = default;
|
||||
|
||||
StickersBox::Inner::Row::Row(
|
||||
@@ -932,7 +1045,12 @@ StickersBox::Inner::Row::Row(
|
||||
StickersBox::Inner::Row::~Row() = default;
|
||||
|
||||
bool StickersBox::Inner::Row::isRecentSet() const {
|
||||
return (set->id == Data::Stickers::CloudRecentSetId);
|
||||
return (set->id == Data::Stickers::CloudRecentSetId)
|
||||
|| (set->id == Data::Stickers::CloudRecentAttachedSetId);
|
||||
}
|
||||
|
||||
bool StickersBox::Inner::Row::isMasksSet() const {
|
||||
return (set->flags & SetFlag::Masks);
|
||||
}
|
||||
|
||||
StickersBox::Inner::Inner(
|
||||
@@ -943,6 +1061,7 @@ StickersBox::Inner::Inner(
|
||||
, _controller(controller)
|
||||
, _api(&_controller->session().mtp())
|
||||
, _section(section)
|
||||
, _isInstalled(_section == Section::Installed || _section == Section::Masks)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _shiftingAnimation([=](crl::time now) {
|
||||
return shiftingAnimationCallback(now);
|
||||
@@ -963,6 +1082,7 @@ StickersBox::Inner::Inner(
|
||||
, _controller(controller)
|
||||
, _api(&_controller->session().mtp())
|
||||
, _section(StickersBox::Section::Installed)
|
||||
, _isInstalled(_section == Section::Installed || _section == Section::Masks)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _shiftingAnimation([=](crl::time now) {
|
||||
return shiftingAnimationCallback(now);
|
||||
@@ -1087,8 +1207,10 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const {
|
||||
auto buttonh = st::stickersRemove.height;
|
||||
auto buttonshift = st::stickersRemoveSkip;
|
||||
if (!removeButton) {
|
||||
auto &st = (_section == Section::Installed) ? st::stickersUndoRemove : st::stickersTrendingAdd;
|
||||
auto textWidth = (_section == Section::Installed) ? _undoWidth : _addWidth;
|
||||
const auto &st = _isInstalled
|
||||
? st::stickersUndoRemove
|
||||
: st::stickersTrendingAdd;
|
||||
const auto textWidth = _isInstalled ? _undoWidth : _addWidth;
|
||||
buttonw = textWidth - st.width;
|
||||
buttonh = st.height;
|
||||
buttonshift = 0;
|
||||
@@ -1117,7 +1239,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
|
||||
}
|
||||
}
|
||||
|
||||
if (_section == Section::Installed) {
|
||||
if (_isInstalled) {
|
||||
if (index >= 0 && index == _above) {
|
||||
auto current = _aboveShadowFadeOpacity.current();
|
||||
if (_started >= 0) {
|
||||
@@ -1144,13 +1266,13 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
|
||||
paintFakeButton(p, row, index);
|
||||
}
|
||||
|
||||
if (row->removed && _section == Section::Installed) {
|
||||
if (row->removed && _isInstalled) {
|
||||
p.setOpacity(st::stickersRowDisabledOpacity);
|
||||
}
|
||||
|
||||
auto stickerx = st::contactsPadding.left();
|
||||
|
||||
if (!_megagroupSet && _section == Section::Installed) {
|
||||
if (!_megagroupSet && _isInstalled) {
|
||||
stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip;
|
||||
if (!row->isRecentSet()) {
|
||||
st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width());
|
||||
@@ -1181,7 +1303,11 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
|
||||
}
|
||||
}
|
||||
|
||||
auto statusText = (row->count > 0) ? tr::lng_stickers_count(tr::now, lt_count, row->count) : tr::lng_contacts_loading(tr::now);
|
||||
const auto statusText = (row->count == 0)
|
||||
? tr::lng_contacts_loading(tr::now)
|
||||
: row->isMasksSet()
|
||||
? tr::lng_masks_count(tr::now, lt_count, row->count)
|
||||
: tr::lng_stickers_count(tr::now, lt_count, row->count);
|
||||
|
||||
p.setFont(st::contactsStatusFont);
|
||||
p.setPen(st::contactsStatusFg);
|
||||
@@ -1281,7 +1407,7 @@ void StickersBox::Inner::updateRowThumbnail(not_null<Row*> row) {
|
||||
Unexpected("StickersBox::Inner::updateRowThumbnail: row not found");
|
||||
}();
|
||||
const auto left = st::contactsPadding.left()
|
||||
+ ((!_megagroupSet && _section == Section::Installed)
|
||||
+ ((!_megagroupSet && _isInstalled)
|
||||
? st::stickersReorderIcon.width() + st::stickersReorderSkip
|
||||
: 0);
|
||||
update(
|
||||
@@ -1292,9 +1418,9 @@ void StickersBox::Inner::updateRowThumbnail(not_null<Row*> row) {
|
||||
}
|
||||
|
||||
void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int index) {
|
||||
auto removeButton = (_section == Section::Installed && !row->removed);
|
||||
auto removeButton = (_isInstalled && !row->removed);
|
||||
auto rect = relativeButtonRect(removeButton);
|
||||
if (_section != Section::Installed && row->installed && !row->archived && !row->removed) {
|
||||
if (!_isInstalled && row->installed && !row->archived && !row->removed) {
|
||||
// Checkbox after installed from Trending or Archived.
|
||||
int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (rect.width() + st::stickersFeaturedInstalled.width()) / 2);
|
||||
int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2;
|
||||
@@ -1317,10 +1443,12 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int ind
|
||||
} else {
|
||||
// Round button ADD when not installed from Trending or Archived.
|
||||
// Or round button UNDO after disabled from Installed.
|
||||
auto &st = (_section == Section::Installed) ? st::stickersUndoRemove : st::stickersTrendingAdd;
|
||||
auto textWidth = (_section == Section::Installed) ? _undoWidth : _addWidth;
|
||||
auto &text = (_section == Section::Installed) ? _undoText : _addText;
|
||||
auto &textBg = selected ? st.textBgOver : st.textBg;
|
||||
const auto &st = _isInstalled
|
||||
? st::stickersUndoRemove
|
||||
: st::stickersTrendingAdd;
|
||||
const auto textWidth = _isInstalled ? _undoWidth : _addWidth;
|
||||
const auto &text = _isInstalled ? _undoText : _addText;
|
||||
const auto &textBg = selected ? st.textBgOver : st.textBg;
|
||||
Ui::FillRoundRect(p, myrtlrect(rect), textBg, ImageRoundRadius::Small);
|
||||
if (row->ripple) {
|
||||
row->ripple->paint(p, rect.x(), rect.y(), width());
|
||||
@@ -1345,7 +1473,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
setActionDown(_actionSel);
|
||||
update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
|
||||
} else if (auto selectedIndex = std::get_if<int>(&_selected)) {
|
||||
if (_section == Section::Installed && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) {
|
||||
if (_isInstalled && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) {
|
||||
_above = _dragging = _started = *selectedIndex;
|
||||
_dragStart = mapFromGlobal(_mouse);
|
||||
}
|
||||
@@ -1367,9 +1495,9 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
|
||||
if (_actionDown >= 0 && _actionDown < _rows.size()) {
|
||||
update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
|
||||
const auto row = _rows[_actionDown].get();
|
||||
auto removeButton = (_section == Section::Installed && !row->removed);
|
||||
auto removeButton = (_isInstalled && !row->removed);
|
||||
if (!row->ripple) {
|
||||
if (_section == Section::Installed) {
|
||||
if (_isInstalled) {
|
||||
if (row->removed) {
|
||||
auto rippleSize = QSize(_undoWidth - st::stickersUndoRemove.width, st::stickersUndoRemove.height);
|
||||
auto rippleMask = Ui::RippleAnimation::roundRectMask(rippleSize, st::roundRadiusSmall);
|
||||
@@ -1512,14 +1640,14 @@ void StickersBox::Inner::updateSelected() {
|
||||
selected = selectedIndex;
|
||||
local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight);
|
||||
const auto row = _rows[selectedIndex].get();
|
||||
if (!_megagroupSet && (_section == Section::Installed || !row->installed || row->archived || row->removed)) {
|
||||
auto removeButton = (_section == Section::Installed && !row->removed);
|
||||
if (!_megagroupSet && (_isInstalled || !row->installed || row->archived || row->removed)) {
|
||||
auto removeButton = (_isInstalled && !row->removed);
|
||||
auto rect = myrtlrect(relativeButtonRect(removeButton));
|
||||
actionSel = rect.contains(local) ? selectedIndex : -1;
|
||||
} else {
|
||||
actionSel = -1;
|
||||
}
|
||||
if (!_megagroupSet && _section == Section::Installed && !row->isRecentSet()) {
|
||||
if (!_megagroupSet && _isInstalled && !row->isRecentSet()) {
|
||||
auto dragAreaWidth = st::contactsPadding.left() + st::stickersReorderIcon.width() + st::stickersReorderSkip;
|
||||
auto dragArea = myrtlrect(0, 0, dragAreaWidth, _rowHeight);
|
||||
inDragArea = dragArea.contains(local);
|
||||
@@ -1543,7 +1671,7 @@ void StickersBox::Inner::updateSelected() {
|
||||
void StickersBox::Inner::updateCursor() {
|
||||
setCursor(_inDragArea
|
||||
? style::cur_sizeall
|
||||
: (!_megagroupSet && _section == Section::Installed)
|
||||
: (!_megagroupSet && _isInstalled)
|
||||
? ((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel))
|
||||
? style::cur_pointer
|
||||
: style::cur_default)
|
||||
@@ -1568,13 +1696,12 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_mouse = e->globalPos();
|
||||
updateSelected();
|
||||
if (_actionDown == _actionSel && _actionSel >= 0) {
|
||||
if (_section == Section::Installed) {
|
||||
if (_isInstalled) {
|
||||
setRowRemoved(_actionDown, !_rows[_actionDown]->removed);
|
||||
} else if (_installSetCallback) {
|
||||
_installSetCallback(_rows[_actionDown]->set->id);
|
||||
}
|
||||
} else if (_dragging >= 0) {
|
||||
QPoint local(mapFromGlobal(_mouse));
|
||||
_rows[_dragging]->yadd.start(0.);
|
||||
_aboveShadowFadeStart = _shiftingStartTimes[_dragging] = crl::now();
|
||||
_aboveShadowFadeOpacity = anim::value(aboveShadowOpacity(), 0);
|
||||
@@ -1593,14 +1720,14 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
const auto showSetByRow = [&](const Row &row) {
|
||||
setSelected(SelectedRow());
|
||||
_controller->show(
|
||||
Box<StickerSetBox>(_controller, row.set->mtpInput()),
|
||||
Box<StickerSetBox>(_controller, row.set->identifier()),
|
||||
Ui::LayerOption::KeepOther);
|
||||
};
|
||||
if (selectedIndex >= 0 && !_inDragArea) {
|
||||
const auto row = _rows[selectedIndex].get();
|
||||
if (!row->isRecentSet()) {
|
||||
if (_megagroupSet) {
|
||||
setMegagroupSelectedSet(row->set->mtpInput());
|
||||
setMegagroupSelectedSet(row->set->identifier());
|
||||
} else {
|
||||
showSetByRow(*row);
|
||||
}
|
||||
@@ -1615,15 +1742,12 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
void StickersBox::Inner::saveGroupSet() {
|
||||
Expects(_megagroupSet != nullptr);
|
||||
|
||||
auto oldId = (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID)
|
||||
? _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID().vid().v
|
||||
: 0;
|
||||
auto newId = (_megagroupSetInput.type() == mtpc_inputStickerSetID)
|
||||
? _megagroupSetInput.c_inputStickerSetID().vid().v
|
||||
: 0;
|
||||
auto oldId = _megagroupSet->mgInfo->stickerSet.id;
|
||||
auto newId = _megagroupSetInput.id;
|
||||
if (newId != oldId) {
|
||||
session().api().setGroupStickerSet(_megagroupSet, _megagroupSetInput);
|
||||
session().api().stickerSetInstalled(Data::Stickers::MegagroupSetId);
|
||||
session().data().stickers().notifyStickerSetInstalled(
|
||||
Data::Stickers::MegagroupSetId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1756,7 +1880,7 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
const auto it = sets.find(_megagroupSelectedSet->set->id);
|
||||
if (it != sets.cend() && !it->second->shortName.isEmpty()) {
|
||||
setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
|
||||
setMegagroupSelectedSet({});
|
||||
}
|
||||
}
|
||||
} else if (!_megagroupSetRequestId) {
|
||||
@@ -1765,12 +1889,10 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
|
||||
)).done([=](const MTPmessages_StickerSet &result) {
|
||||
_megagroupSetRequestId = 0;
|
||||
auto set = session().data().stickers().feedSetFull(result);
|
||||
setMegagroupSelectedSet(MTP_inputStickerSetID(
|
||||
MTP_long(set->id),
|
||||
MTP_long(set->access)));
|
||||
setMegagroupSelectedSet(set->identifier());
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_megagroupSetRequestId = 0;
|
||||
setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
|
||||
setMegagroupSelectedSet({});
|
||||
}).send();
|
||||
} else {
|
||||
_megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout);
|
||||
@@ -1779,7 +1901,8 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
|
||||
|
||||
void StickersBox::Inner::rebuildMegagroupSet() {
|
||||
Expects(_megagroupSet != nullptr);
|
||||
if (_megagroupSetInput.type() != mtpc_inputStickerSetID) {
|
||||
|
||||
if (!_megagroupSetInput.id) {
|
||||
if (_megagroupSelectedSet) {
|
||||
_megagroupSetField->setText(QString());
|
||||
_megagroupSetField->finishAnimating();
|
||||
@@ -1789,15 +1912,14 @@ void StickersBox::Inner::rebuildMegagroupSet() {
|
||||
_megagroupSelectedShadow.destroy();
|
||||
return;
|
||||
}
|
||||
auto &inputId = _megagroupSetInput.c_inputStickerSetID();
|
||||
auto setId = inputId.vid().v;
|
||||
auto setId = _megagroupSetInput.id;
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
auto it = sets.find(setId);
|
||||
if (it == sets.cend()
|
||||
|| (it->second->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
|
||||
|| (it->second->flags & SetFlag::NotLoaded)) {
|
||||
session().api().scheduleStickerSetRequest(
|
||||
inputId.vid().v,
|
||||
inputId.vaccess_hash().v);
|
||||
_megagroupSetInput.id,
|
||||
_megagroupSetInput.accessHash);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1833,14 +1955,14 @@ void StickersBox::Inner::rebuildMegagroupSet() {
|
||||
_megagroupSelectedRemove.create(this, st::groupStickersRemove);
|
||||
_megagroupSelectedRemove->show(anim::type::instant);
|
||||
_megagroupSelectedRemove->setClickedCallback([this] {
|
||||
setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
|
||||
setMegagroupSelectedSet({});
|
||||
});
|
||||
_megagroupSelectedShadow.create(this);
|
||||
updateControlsGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::rebuild() {
|
||||
void StickersBox::Inner::rebuild(bool masks) {
|
||||
_itemsTop = st::membersMarginTop;
|
||||
|
||||
if (_megagroupSet) {
|
||||
@@ -1859,10 +1981,14 @@ void StickersBox::Inner::rebuild() {
|
||||
return session().data().stickers().featuredSetsOrder();
|
||||
}
|
||||
return result;
|
||||
} else if (_section == Section::Masks) {
|
||||
return session().data().stickers().maskSetsOrder();
|
||||
} else if (_section == Section::Featured) {
|
||||
return session().data().stickers().featuredSetsOrder();
|
||||
}
|
||||
return session().data().stickers().archivedSetsOrder();
|
||||
return masks
|
||||
? session().data().stickers().archivedMaskSetsOrder()
|
||||
: session().data().stickers().archivedSetsOrder();
|
||||
})();
|
||||
_rows.reserve(order.size() + 1);
|
||||
_shiftingStartTimes.reserve(order.size() + 1);
|
||||
@@ -1874,8 +2000,10 @@ void StickersBox::Inner::rebuild() {
|
||||
? tr::lng_stickers_group_from_featured(tr::now)
|
||||
: tr::lng_stickers_group_from_your(tr::now));
|
||||
updateControlsGeometry();
|
||||
} else if (_section == Section::Installed) {
|
||||
auto cloudIt = sets.find(Data::Stickers::CloudRecentSetId);
|
||||
} else if (_isInstalled) {
|
||||
const auto cloudIt = sets.find((_section == Section::Masks)
|
||||
? Data::Stickers::CloudRecentAttachedSetId
|
||||
: Data::Stickers::CloudRecentSetId); // Section::Installed.
|
||||
if (cloudIt != sets.cend() && !cloudIt->second->stickers.isEmpty()) {
|
||||
rebuildAppendSet(cloudIt->second.get(), maxNameWidth);
|
||||
}
|
||||
@@ -1890,7 +2018,7 @@ void StickersBox::Inner::rebuild() {
|
||||
rebuildAppendSet(set, maxNameWidth);
|
||||
|
||||
if (set->stickers.isEmpty()
|
||||
|| (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
|
||||
|| (set->flags & SetFlag::NotLoaded)) {
|
||||
session().api().scheduleStickerSetRequest(set->id, set->access);
|
||||
}
|
||||
}
|
||||
@@ -1898,9 +2026,9 @@ void StickersBox::Inner::rebuild() {
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setMegagroupSelectedSet(const MTPInputStickerSet &set) {
|
||||
void StickersBox::Inner::setMegagroupSelectedSet(const StickerSetIdentifier &set) {
|
||||
_megagroupSetInput = set;
|
||||
rebuild();
|
||||
rebuild(false);
|
||||
_scrollsToY.fire(0);
|
||||
updateSelected();
|
||||
}
|
||||
@@ -1944,7 +2072,7 @@ void StickersBox::Inner::updateRows() {
|
||||
auto wasInstalled = row->installed;
|
||||
auto wasArchived = row->archived;
|
||||
fillSetFlags(set, &row->installed, &row->official, &row->unread, &row->archived);
|
||||
if (_section == Section::Installed) {
|
||||
if (_isInstalled) {
|
||||
row->archived = false;
|
||||
}
|
||||
if (row->installed != wasInstalled || row->archived != wasArchived) {
|
||||
@@ -1969,11 +2097,11 @@ bool StickersBox::Inner::appendSet(not_null<StickersSet*> set) {
|
||||
|
||||
int StickersBox::Inner::countMaxNameWidth() const {
|
||||
int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
|
||||
if (!_megagroupSet && _section == Section::Installed) {
|
||||
if (!_megagroupSet && _isInstalled) {
|
||||
namex += st::stickersReorderIcon.width() + st::stickersReorderSkip;
|
||||
}
|
||||
int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x();
|
||||
if (_section == Section::Installed) {
|
||||
if (_isInstalled) {
|
||||
if (!_megagroupSet) {
|
||||
namew -= _undoWidth - st::stickersUndoRemove.width;
|
||||
}
|
||||
@@ -1993,7 +2121,7 @@ void StickersBox::Inner::rebuildAppendSet(
|
||||
if (set->id != Data::Stickers::CloudRecentSetId) {
|
||||
fillSetFlags(set, &installed, &official, &unread, &archived);
|
||||
}
|
||||
if (_section == Section::Installed && archived) {
|
||||
if (_isInstalled && archived) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2105,11 +2233,11 @@ void StickersBox::Inner::fillSetFlags(
|
||||
bool *outOfficial,
|
||||
bool *outUnread,
|
||||
bool *outArchived) {
|
||||
*outInstalled = (set->flags & MTPDstickerSet::Flag::f_installed_date);
|
||||
*outOfficial = (set->flags & MTPDstickerSet::Flag::f_official);
|
||||
*outArchived = (set->flags & MTPDstickerSet::Flag::f_archived);
|
||||
*outInstalled = (set->flags & SetFlag::Installed);
|
||||
*outOfficial = (set->flags & SetFlag::Official);
|
||||
*outArchived = (set->flags & SetFlag::Archived);
|
||||
if (_section == Section::Featured) {
|
||||
*outUnread = (set->flags & MTPDstickerSet_ClientFlag::f_unread);
|
||||
*outUnread = (set->flags & SetFlag::Unread);
|
||||
} else {
|
||||
*outUnread = false;
|
||||
}
|
||||
|
||||
@@ -49,19 +49,21 @@ namespace Stickers {
|
||||
class Set;
|
||||
} // namespace Stickers
|
||||
|
||||
class StickersBox final : public Ui::BoxContent, private base::Subscriber {
|
||||
class StickersBox final : public Ui::BoxContent {
|
||||
public:
|
||||
enum class Section {
|
||||
Installed,
|
||||
Featured,
|
||||
Archived,
|
||||
Attached,
|
||||
Masks,
|
||||
};
|
||||
|
||||
StickersBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Section section);
|
||||
Section section,
|
||||
bool masks = false);
|
||||
StickersBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
@@ -94,7 +96,7 @@ private:
|
||||
object_ptr<Inner> takeWidget();
|
||||
void returnWidget(object_ptr<Inner> widget);
|
||||
|
||||
[[nodiscard]] Inner *widget();
|
||||
[[nodiscard]] Inner *widget() const;
|
||||
[[nodiscard]] int index() const;
|
||||
|
||||
void saveScrollTop();
|
||||
@@ -103,7 +105,7 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
int _index = 0;
|
||||
const int _index = 0;
|
||||
object_ptr<Inner> _widget = { nullptr };
|
||||
QPointer<Inner> _weak;
|
||||
int _scrollTop = 0;
|
||||
@@ -132,6 +134,11 @@ private:
|
||||
uint64 offsetId);
|
||||
void showAttachedStickers();
|
||||
|
||||
const Data::StickersSetsOrder &archivedSetsOrder() const;
|
||||
Data::StickersSetsOrder &archivedSetsOrderRef();
|
||||
|
||||
std::array<Inner*, 5> widgets() const;
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
MTP::Sender _api;
|
||||
|
||||
@@ -142,8 +149,10 @@ private:
|
||||
object_ptr<CounterWidget> _unreadBadge = { nullptr };
|
||||
|
||||
Section _section;
|
||||
const bool _isMasks;
|
||||
|
||||
Tab _installed;
|
||||
Tab _masks;
|
||||
Tab _featured;
|
||||
Tab _archived;
|
||||
Tab _attached;
|
||||
|
||||
@@ -1184,6 +1184,16 @@ desktopCaptureSubmit: RoundButton(desktopCaptureCancel) {
|
||||
color: shadowFg;
|
||||
}
|
||||
}
|
||||
desktopCaptureWithAudio: Checkbox(defaultCheckbox) {
|
||||
textFg: groupCallMembersFg;
|
||||
textFgActive: groupCallMembersFg;
|
||||
rippleBg: groupCallMembersBgRipple;
|
||||
rippleBgActive: groupCallMembersBgRipple;
|
||||
style: semiboldTextStyle;
|
||||
}
|
||||
desktopCaptureWithAudioCheck: Check(defaultCheck) {
|
||||
untoggledFg: groupCallActiveFg;
|
||||
}
|
||||
|
||||
groupCallNarrowSkip: 9px;
|
||||
groupCallNarrowMembersWidth: 204px;
|
||||
|
||||
@@ -16,7 +16,7 @@ class SessionController;
|
||||
|
||||
namespace Calls {
|
||||
|
||||
class BoxController : public PeerListController, private base::Subscriber {
|
||||
class BoxController : public PeerListController {
|
||||
public:
|
||||
explicit BoxController(not_null<Window::SessionController*> window);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class GroupCall;
|
||||
class Panel;
|
||||
struct DhConfig;
|
||||
|
||||
class Instance : private base::Subscriber, public base::has_weak_ptr {
|
||||
class Instance final : public base::has_weak_ptr {
|
||||
public:
|
||||
Instance();
|
||||
~Instance();
|
||||
|
||||
@@ -48,7 +48,6 @@ enum class BarState {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxUsersInBar = 3;
|
||||
constexpr auto kUpdateDebugTimeoutMs = crl::time(500);
|
||||
constexpr auto kSwitchStateDuration = 120;
|
||||
|
||||
|
||||
@@ -210,8 +210,8 @@ void Panel::Incoming::RendererGL::paint(
|
||||
if (upload) {
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RGBA,
|
||||
GL_RGBA,
|
||||
Ui::GL::kFormatRGBA,
|
||||
Ui::GL::kFormatRGBA,
|
||||
data.original.size(),
|
||||
_rgbaSize,
|
||||
data.original.bytesPerLine() / 4,
|
||||
@@ -223,6 +223,7 @@ void Panel::Incoming::RendererGL::paint(
|
||||
Assert(data.format == Webrtc::FrameFormat::YUV420);
|
||||
Assert(!data.yuv420->size.isEmpty());
|
||||
const auto yuv = data.yuv420;
|
||||
const auto format = Ui::GL::CurrentSingleComponentFormat();
|
||||
|
||||
f.glActiveTexture(GL_TEXTURE0);
|
||||
_textures.bind(f, 1);
|
||||
@@ -230,8 +231,8 @@ void Panel::Incoming::RendererGL::paint(
|
||||
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RED,
|
||||
GL_RED,
|
||||
format,
|
||||
format,
|
||||
yuv->size,
|
||||
_lumaSize,
|
||||
yuv->y.stride,
|
||||
@@ -243,8 +244,8 @@ void Panel::Incoming::RendererGL::paint(
|
||||
if (upload) {
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RED,
|
||||
GL_RED,
|
||||
format,
|
||||
format,
|
||||
yuv->chromaSize,
|
||||
_chromaSize,
|
||||
yuv->u.stride,
|
||||
@@ -255,8 +256,8 @@ void Panel::Incoming::RendererGL::paint(
|
||||
if (upload) {
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RED,
|
||||
GL_RED,
|
||||
format,
|
||||
format,
|
||||
yuv->chromaSize,
|
||||
_chromaSize,
|
||||
yuv->v.stride,
|
||||
|
||||
@@ -31,7 +31,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Calls::Group {
|
||||
namespace {
|
||||
|
||||
constexpr auto kDefaultScheduleDuration = 60 * TimeId(60);
|
||||
constexpr auto kLabelRefreshInterval = 10 * crl::time(1000);
|
||||
|
||||
using Context = ChooseJoinAsProcess::Context;
|
||||
|
||||
@@ -74,12 +74,6 @@ constexpr auto kMaxMediumQualities = 16; // 4 Fulls or 16 Mediums.
|
||||
return msgId / double(1ULL << 32);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string ReadJsonString(
|
||||
const QJsonObject &object,
|
||||
const char *key) {
|
||||
return object.value(key).toString().toStdString();
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64 FindLocalRaisedHandRating(
|
||||
const std::vector<Data::GroupCallParticipant> &list) {
|
||||
const auto i = ranges::max_element(
|
||||
@@ -230,8 +224,7 @@ GroupCall::VideoTrack::VideoTrack(
|
||||
if (i == mgInfo->lastAdmins.end()) {
|
||||
return false;
|
||||
}
|
||||
const auto &rights = i->second.rights;
|
||||
return rights.c_chatAdminRights().is_manage_call();
|
||||
return (i->second.rights.flags & ChatAdminRight::ManageCall);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -240,10 +233,11 @@ GroupCall::VideoTrack::VideoTrack(
|
||||
struct VideoParams {
|
||||
std::string endpointId;
|
||||
std::vector<tgcalls::MediaSsrcGroup> ssrcGroups;
|
||||
uint32 additionalSsrc = 0;
|
||||
bool paused = false;
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return endpointId.empty() || ssrcGroups.empty();
|
||||
return !additionalSsrc && (endpointId.empty() || ssrcGroups.empty());
|
||||
}
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return !empty();
|
||||
@@ -262,7 +256,8 @@ struct ParticipantVideoParams {
|
||||
return !was;
|
||||
}
|
||||
return now->match([&](const MTPDgroupCallParticipantVideo &data) {
|
||||
if (data.is_paused() != was.paused) {
|
||||
if (data.is_paused() != was.paused
|
||||
|| data.vaudio_source().value_or_empty() != was.additionalSsrc) {
|
||||
return false;
|
||||
}
|
||||
if (gsl::make_span(data.vendpoint().v)
|
||||
@@ -311,6 +306,7 @@ struct ParticipantVideoParams {
|
||||
params->match([&](const MTPDgroupCallParticipantVideo &data) {
|
||||
result.paused = data.is_paused();
|
||||
result.endpointId = data.vendpoint().v.toStdString();
|
||||
result.additionalSsrc = data.vaudio_source().value_or_empty();
|
||||
const auto &list = data.vsource_groups().v;
|
||||
result.ssrcGroups.reserve(list.size());
|
||||
for (const auto &group : list) {
|
||||
@@ -350,6 +346,11 @@ bool IsScreenPaused(const std::shared_ptr<ParticipantVideoParams> ¶ms) {
|
||||
return params && params->screen.paused;
|
||||
}
|
||||
|
||||
uint32 GetAdditionalAudioSsrc(
|
||||
const std::shared_ptr<ParticipantVideoParams> ¶ms) {
|
||||
return params ? params->screen.additionalSsrc : 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<ParticipantVideoParams> ParseVideoParams(
|
||||
const tl::conditional<MTPGroupCallParticipantVideo> &camera,
|
||||
const tl::conditional<MTPGroupCallParticipantVideo> &screen,
|
||||
@@ -612,6 +613,10 @@ QString GroupCall::screenSharingDeviceId() const {
|
||||
return isSharingScreen() ? _screenDeviceId : QString();
|
||||
}
|
||||
|
||||
bool GroupCall::screenSharingWithAudio() const {
|
||||
return isSharingScreen() && _screenWithAudio;
|
||||
}
|
||||
|
||||
bool GroupCall::mutedByAdmin() const {
|
||||
const auto mute = muted();
|
||||
return mute == MuteState::ForceMuted || mute == MuteState::RaisedHand;
|
||||
@@ -634,7 +639,9 @@ void GroupCall::toggleVideo(bool active) {
|
||||
: Webrtc::VideoState::Inactive;
|
||||
}
|
||||
|
||||
void GroupCall::toggleScreenSharing(std::optional<QString> uniqueId) {
|
||||
void GroupCall::toggleScreenSharing(
|
||||
std::optional<QString> uniqueId,
|
||||
bool withAudio) {
|
||||
if (!_instance || !_id) {
|
||||
return;
|
||||
} else if (!uniqueId) {
|
||||
@@ -644,10 +651,14 @@ void GroupCall::toggleScreenSharing(std::optional<QString> uniqueId) {
|
||||
const auto changed = (_screenDeviceId != *uniqueId);
|
||||
const auto wasSharing = isSharingScreen();
|
||||
_screenDeviceId = *uniqueId;
|
||||
_screenWithAudio = withAudio;
|
||||
_screenState = Webrtc::VideoState::Active;
|
||||
if (changed && wasSharing && isSharingScreen()) {
|
||||
_screenCapture->switchToDevice(uniqueId->toStdString());
|
||||
}
|
||||
if (_screenInstance) {
|
||||
_screenInstance->setIsMuted(!withAudio);
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupCall::hasVideoWithFrames() const {
|
||||
@@ -676,20 +687,6 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
|
||||
setScheduledDate(date);
|
||||
}, _lifetime);
|
||||
|
||||
// If we joined before you could start video and then you can,
|
||||
// you have to rejoin so that the server knows your video params.
|
||||
//real->canStartVideoValue( // ignore can_start_video after call start.
|
||||
//) | rpl::combine_previous(
|
||||
//) | rpl::start_with_next([=](bool could, bool can) {
|
||||
// if (could || !can) {
|
||||
// return;
|
||||
// } if (_joinState.action == JoinAction::None) {
|
||||
// rejoin();
|
||||
// } else {
|
||||
// _joinState.nextActionPending = true;
|
||||
// }
|
||||
//}, _lifetime);
|
||||
|
||||
// Postpone creating video tracks, so that we know if Panel
|
||||
// supports OpenGL and we don't need ARGB32 frames at all.
|
||||
Ui::PostponeCall(this, [=] {
|
||||
@@ -985,22 +982,12 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
||||
return (_instance != nullptr);
|
||||
}) | rpl::start_with_next([=](const Update &update) {
|
||||
if (!update.now) {
|
||||
_instance->removeSsrcs({ update.was->ssrc });
|
||||
_instance->removeSsrcs({
|
||||
update.was->ssrc,
|
||||
GetAdditionalAudioSsrc(update.was->videoParams),
|
||||
});
|
||||
} else {
|
||||
const auto &now = *update.now;
|
||||
const auto &was = update.was;
|
||||
const auto volumeChanged = was
|
||||
? (was->volume != now.volume
|
||||
|| was->mutedByMe != now.mutedByMe)
|
||||
: (now.volume != Group::kDefaultVolume || now.mutedByMe);
|
||||
if (volumeChanged) {
|
||||
_instance->setVolume(
|
||||
now.ssrc,
|
||||
(now.mutedByMe
|
||||
? 0.
|
||||
: (now.volume
|
||||
/ float64(Group::kDefaultVolume))));
|
||||
}
|
||||
updateInstanceVolume(update.was, *update.now);
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
@@ -1509,7 +1496,6 @@ void GroupCall::applyParticipantLocally(
|
||||
? participant->canSelfUnmute
|
||||
: (!mute || IsGroupCallAdmin(_peer, participantPeer));
|
||||
const auto isMutedByYou = mute && !canManageCall;
|
||||
const auto mutedCount = 0/*participant->mutedCount*/;
|
||||
using Flag = MTPDgroupCallParticipant::Flag;
|
||||
const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0))
|
||||
| Flag::f_volume // Without flag the volume is reset to 100%.
|
||||
@@ -1970,14 +1956,37 @@ void GroupCall::setupMediaDevices() {
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
int GroupCall::activeVideoSendersCount() const {
|
||||
auto result = 0;
|
||||
for (const auto &[endpoint, track] : _activeVideoTracks) {
|
||||
if (endpoint.type == VideoEndpointType::Camera) {
|
||||
++result;
|
||||
} else {
|
||||
auto sharesCameraToo = false;
|
||||
for (const auto &[other, _] : _activeVideoTracks) {
|
||||
if (other.type == VideoEndpointType::Camera
|
||||
&& other.peer == endpoint.peer) {
|
||||
sharesCameraToo = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sharesCameraToo) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GroupCall::emitShareCameraError() {
|
||||
const auto emitError = [=](Error error) {
|
||||
emitShareCameraError(error);
|
||||
return true;
|
||||
};
|
||||
/*if (const auto real = lookupReal(); real && !real->canStartVideo()) {
|
||||
if (const auto real = lookupReal()
|
||||
; real && activeVideoSendersCount() >= real->unmutedVideoLimit()) {
|
||||
return emitError(Error::DisabledNoCamera);
|
||||
} else */if (!videoIsWorking()) {
|
||||
} else if (!videoIsWorking()) {
|
||||
return emitError(Error::DisabledNoCamera);
|
||||
} else if (mutedByAdmin()) {
|
||||
return emitError(Error::MutedNoCamera);
|
||||
@@ -2001,9 +2010,10 @@ bool GroupCall::emitShareScreenError() {
|
||||
emitShareScreenError(error);
|
||||
return true;
|
||||
};
|
||||
/*if (const auto real = lookupReal(); real && !real->canStartVideo()) {
|
||||
if (const auto real = lookupReal()
|
||||
; real && activeVideoSendersCount() >= real->unmutedVideoLimit()) {
|
||||
return emitError(Error::DisabledNoScreen);
|
||||
} else */if (!videoIsWorking()) {
|
||||
} else if (!videoIsWorking()) {
|
||||
return emitError(Error::DisabledNoScreen);
|
||||
} else if (mutedByAdmin()) {
|
||||
return emitError(Error::MutedNoScreen);
|
||||
@@ -2025,7 +2035,6 @@ void GroupCall::setupOutgoingVideo() {
|
||||
// Recursive entrance may happen if error happens when activating.
|
||||
return (previous != state);
|
||||
}) | rpl::start_with_next([=](VideoState previous, VideoState state) {
|
||||
const auto wasPaused = (previous == VideoState::Paused);
|
||||
const auto wasActive = (previous != VideoState::Inactive);
|
||||
const auto nowPaused = (state == VideoState::Paused);
|
||||
const auto nowActive = (state != VideoState::Inactive);
|
||||
@@ -2080,7 +2089,6 @@ void GroupCall::setupOutgoingVideo() {
|
||||
// Recursive entrance may happen if error happens when activating.
|
||||
return (previous != state);
|
||||
}) | rpl::start_with_next([=](VideoState previous, VideoState state) {
|
||||
const auto wasPaused = (previous == VideoState::Paused);
|
||||
const auto wasActive = (previous != VideoState::Inactive);
|
||||
const auto nowPaused = (state == VideoState::Paused);
|
||||
const auto nowActive = (state != VideoState::Inactive);
|
||||
@@ -2296,6 +2304,7 @@ bool GroupCall::tryCreateScreencast() {
|
||||
setScreenInstanceConnected(networkState);
|
||||
});
|
||||
},
|
||||
.createAudioDeviceModule = Webrtc::LoopbackAudioDeviceModuleCreator(),
|
||||
.videoCapture = _screenCapture,
|
||||
.videoContentType = tgcalls::VideoContentType::Screencast,
|
||||
};
|
||||
@@ -2303,6 +2312,9 @@ bool GroupCall::tryCreateScreencast() {
|
||||
LOG(("Call Info: Creating group screen instance"));
|
||||
_screenInstance = std::make_unique<tgcalls::GroupInstanceCustomImpl>(
|
||||
std::move(descriptor));
|
||||
|
||||
_screenInstance->setIsMuted(!_screenWithAudio);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2379,8 +2391,6 @@ void GroupCall::broadcastPartCancel(not_null<LoadPartTask*> task) {
|
||||
|
||||
void GroupCall::mediaChannelDescriptionsStart(
|
||||
std::shared_ptr<MediaChannelDescriptionsTask> task) {
|
||||
const auto raw = task.get();
|
||||
|
||||
const auto real = lookupReal();
|
||||
if (!real || (_instanceMode == InstanceMode::None)) {
|
||||
for (const auto ssrc : task->ssrcs()) {
|
||||
@@ -2405,7 +2415,6 @@ bool GroupCall::mediaChannelDescriptionsFill(
|
||||
auto result = false;
|
||||
const auto real = lookupReal();
|
||||
Assert(real != nullptr);
|
||||
const auto &existing = real->participants();
|
||||
for (const auto ssrc : task->ssrcs()) {
|
||||
const auto add = [&](
|
||||
std::optional<Channel> channel,
|
||||
@@ -2647,15 +2656,33 @@ void GroupCall::updateInstanceVolumes() {
|
||||
|
||||
const auto &participants = real->participants();
|
||||
for (const auto &participant : participants) {
|
||||
const auto setVolume = participant.mutedByMe
|
||||
|| (participant.volume != Group::kDefaultVolume);
|
||||
if (setVolume && participant.ssrc) {
|
||||
_instance->setVolume(
|
||||
participant.ssrc,
|
||||
(participant.mutedByMe
|
||||
? 0.
|
||||
: (participant.volume / float64(Group::kDefaultVolume))));
|
||||
}
|
||||
updateInstanceVolume(std::nullopt, participant);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupCall::updateInstanceVolume(
|
||||
const std::optional<Data::GroupCallParticipant> &was,
|
||||
const Data::GroupCallParticipant &now) {
|
||||
const auto nonDefault = now.mutedByMe
|
||||
|| (now.volume != Group::kDefaultVolume);
|
||||
const auto volumeChanged = was
|
||||
? (was->volume != now.volume || was->mutedByMe != now.mutedByMe)
|
||||
: nonDefault;
|
||||
const auto additionalSsrc = GetAdditionalAudioSsrc(now.videoParams);
|
||||
const auto set = now.ssrc
|
||||
&& (volumeChanged || (was && was->ssrc != now.ssrc));
|
||||
const auto additionalSet = additionalSsrc
|
||||
&& (volumeChanged
|
||||
|| (was && (GetAdditionalAudioSsrc(was->videoParams)
|
||||
!= additionalSsrc)));
|
||||
const auto localVolume = now.mutedByMe
|
||||
? 0.
|
||||
: (now.volume / float64(Group::kDefaultVolume));
|
||||
if (set) {
|
||||
_instance->setVolume(now.ssrc, localVolume);
|
||||
}
|
||||
if (additionalSet) {
|
||||
_instance->setVolume(additionalSsrc, localVolume);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2776,7 +2803,7 @@ void GroupCall::checkJoined() {
|
||||
MTP_vector<MTPint>(std::move(sources))
|
||||
)).done([=](const MTPVector<MTPint> &result) {
|
||||
if (!ranges::contains(result.v, MTP_int(_joinState.ssrc))) {
|
||||
LOG(("Call Info: Rejoin after no _mySsrc in checkGroupCall."));
|
||||
LOG(("Call Info: Rejoin after no my ssrc in checkGroupCall."));
|
||||
_joinState.nextActionPending = true;
|
||||
checkNextJoinAction();
|
||||
} else {
|
||||
@@ -2840,8 +2867,6 @@ void GroupCall::setScreenInstanceConnected(
|
||||
: inTransit
|
||||
? InstanceState::TransitionToRtc
|
||||
: InstanceState::Connected;
|
||||
const auto connected = (screenInstanceState
|
||||
!= InstanceState::Disconnected);
|
||||
if (_screenInstanceState.current() == screenInstanceState) {
|
||||
return;
|
||||
}
|
||||
@@ -3085,11 +3110,6 @@ std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
||||
return 0;
|
||||
}
|
||||
const auto owner = &_peer->owner();
|
||||
const auto &invited = owner->invitedToCallUsers(_id);
|
||||
auto &&toInvite = users | ranges::views::filter([&](
|
||||
not_null<UserData*> user) {
|
||||
return !invited.contains(user) && !real->participantByPeer(user);
|
||||
});
|
||||
|
||||
auto count = 0;
|
||||
auto slice = QVector<MTPInputUser>();
|
||||
|
||||
@@ -169,6 +169,8 @@ struct ParticipantVideoParams;
|
||||
const std::shared_ptr<ParticipantVideoParams> ¶ms);
|
||||
[[nodiscard]] bool IsScreenPaused(
|
||||
const std::shared_ptr<ParticipantVideoParams> ¶ms);
|
||||
[[nodiscard]] uint32 GetAdditionalAudioSsrc(
|
||||
const std::shared_ptr<ParticipantVideoParams> ¶ms);
|
||||
|
||||
class GroupCall final : public base::has_weak_ptr {
|
||||
public:
|
||||
@@ -378,8 +380,11 @@ public:
|
||||
[[nodiscard]] bool isCameraPaused() const;
|
||||
[[nodiscard]] const std::string &cameraSharingEndpoint() const;
|
||||
[[nodiscard]] QString screenSharingDeviceId() const;
|
||||
[[nodiscard]] bool screenSharingWithAudio() const;
|
||||
void toggleVideo(bool active);
|
||||
void toggleScreenSharing(std::optional<QString> uniqueId);
|
||||
void toggleScreenSharing(
|
||||
std::optional<QString> uniqueId,
|
||||
bool withAudio = false);
|
||||
[[nodiscard]] bool hasVideoWithFrames() const;
|
||||
[[nodiscard]] rpl::producer<bool> hasVideoWithFramesValue() const;
|
||||
|
||||
@@ -482,6 +487,9 @@ private:
|
||||
void sendSelfUpdate(SendUpdateType type);
|
||||
void updateInstanceMuteState();
|
||||
void updateInstanceVolumes();
|
||||
void updateInstanceVolume(
|
||||
const std::optional<Data::GroupCallParticipant> &was,
|
||||
const Data::GroupCallParticipant &now);
|
||||
void applyMeInCallLocally();
|
||||
void rejoin();
|
||||
void leave();
|
||||
@@ -543,6 +551,8 @@ private:
|
||||
void markTrackPaused(const VideoEndpoint &endpoint, bool paused);
|
||||
void markTrackShown(const VideoEndpoint &endpoint, bool shown);
|
||||
|
||||
[[nodiscard]] int activeVideoSendersCount() const;
|
||||
|
||||
[[nodiscard]] MTPInputGroupCall inputCall() const;
|
||||
|
||||
const not_null<Delegate*> _delegate;
|
||||
@@ -609,6 +619,7 @@ private:
|
||||
rpl::variable<Webrtc::VideoState> _screenState;
|
||||
rpl::variable<bool> _isSharingScreen = false;
|
||||
QString _screenDeviceId;
|
||||
bool _screenWithAudio = false;
|
||||
|
||||
base::flags<SendUpdateType> _pendingSelfUpdates;
|
||||
bool _requireARGB32 = true;
|
||||
|
||||
@@ -106,7 +106,7 @@ std::unique_ptr<PeerListRow> InviteController::createRow(
|
||||
if (!user
|
||||
|| user->isSelf()
|
||||
|| user->isBot()
|
||||
|| (user->flags() & MTPDuser::Flag::f_deleted)) {
|
||||
|| user->isInaccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_unique<PeerListRow>(user);
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace Calls::Group {
|
||||
namespace {
|
||||
|
||||
constexpr auto kKeepRaisedHandStatusDuration = 3 * crl::time(1000);
|
||||
constexpr auto kShadowMaxAlpha = 74;
|
||||
constexpr auto kUserpicSizeForBlur = 40;
|
||||
constexpr auto kUserpicBlurRadius = 8;
|
||||
|
||||
@@ -225,6 +224,7 @@ private:
|
||||
const Data::GroupCallParticipant &now);
|
||||
void updateRow(
|
||||
not_null<Row*> row,
|
||||
const std::optional<Data::GroupCallParticipant> &was,
|
||||
const Data::GroupCallParticipant *participant);
|
||||
void removeRow(not_null<Row*> row);
|
||||
void updateRowLevel(not_null<Row*> row, float level);
|
||||
@@ -496,9 +496,8 @@ void Members::Controller::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||
: update.now->peer;
|
||||
if (!update.now) {
|
||||
if (const auto row = findRow(participantPeer)) {
|
||||
const auto owner = &participantPeer->owner();
|
||||
if (isMe(participantPeer)) {
|
||||
updateRow(row, nullptr);
|
||||
updateRow(row, update.was, nullptr);
|
||||
} else {
|
||||
removeRow(row);
|
||||
delegate()->peerListRefreshRows();
|
||||
@@ -598,7 +597,7 @@ void Members::Controller::updateRow(
|
||||
if (row->state() == Row::State::Invited) {
|
||||
reorderIfInvitedBefore = row->absoluteIndex();
|
||||
}
|
||||
updateRow(row, &now);
|
||||
updateRow(row, was, &now);
|
||||
if ((now.speaking && (!was || !was->speaking))
|
||||
|| (now.raisedHandRating != (was ? was->raisedHandRating : 0))
|
||||
|| (!now.canSelfUnmute && was && was->canSelfUnmute)) {
|
||||
@@ -776,18 +775,25 @@ void Members::Controller::checkRowPosition(not_null<Row*> row) {
|
||||
|
||||
void Members::Controller::updateRow(
|
||||
not_null<Row*> row,
|
||||
const std::optional<Data::GroupCallParticipant> &was,
|
||||
const Data::GroupCallParticipant *participant) {
|
||||
const auto wasSounding = row->sounding();
|
||||
const auto wasSsrc = row->ssrc();
|
||||
const auto wasInChat = (row->state() != Row::State::Invited);
|
||||
const auto wasSsrc = was ? was->ssrc : 0;
|
||||
const auto wasAdditionalSsrc = was
|
||||
? GetAdditionalAudioSsrc(was->videoParams)
|
||||
: 0;
|
||||
row->setSkipLevelUpdate(_skipRowLevelUpdate);
|
||||
row->updateState(participant);
|
||||
const auto nowSounding = row->sounding();
|
||||
const auto nowSsrc = row->ssrc();
|
||||
const auto nowSsrc = participant ? participant->ssrc : 0;
|
||||
const auto nowAdditionalSsrc = participant
|
||||
? GetAdditionalAudioSsrc(participant->videoParams)
|
||||
: 0;
|
||||
|
||||
const auto wasNoSounding = _soundingRowBySsrc.empty();
|
||||
|
||||
if (wasSsrc == nowSsrc) {
|
||||
if (nowSounding != wasSounding) {
|
||||
if (nowSsrc && nowSounding != wasSounding) {
|
||||
if (nowSounding) {
|
||||
_soundingRowBySsrc.emplace(nowSsrc, row);
|
||||
} else {
|
||||
@@ -796,11 +802,25 @@ void Members::Controller::updateRow(
|
||||
}
|
||||
} else {
|
||||
_soundingRowBySsrc.remove(wasSsrc);
|
||||
if (nowSounding) {
|
||||
Assert(nowSsrc != 0);
|
||||
if (nowSounding && nowSsrc) {
|
||||
_soundingRowBySsrc.emplace(nowSsrc, row);
|
||||
}
|
||||
}
|
||||
if (wasAdditionalSsrc == nowAdditionalSsrc) {
|
||||
if (nowAdditionalSsrc && nowSounding != wasSounding) {
|
||||
if (nowSounding) {
|
||||
_soundingRowBySsrc.emplace(nowAdditionalSsrc, row);
|
||||
} else {
|
||||
_soundingRowBySsrc.remove(nowAdditionalSsrc);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_soundingRowBySsrc.remove(wasAdditionalSsrc);
|
||||
if (nowSounding && nowAdditionalSsrc) {
|
||||
_soundingRowBySsrc.emplace(nowAdditionalSsrc, row);
|
||||
}
|
||||
}
|
||||
|
||||
const auto nowNoSounding = _soundingRowBySsrc.empty();
|
||||
if (wasNoSounding && !nowNoSounding) {
|
||||
_soundingAnimation.start();
|
||||
@@ -812,7 +832,14 @@ void Members::Controller::updateRow(
|
||||
}
|
||||
|
||||
void Members::Controller::removeRow(not_null<Row*> row) {
|
||||
_soundingRowBySsrc.remove(row->ssrc());
|
||||
// There may be 0, 1 or 2 entries for a row.
|
||||
for (auto i = begin(_soundingRowBySsrc); i != end(_soundingRowBySsrc);) {
|
||||
if (i->second == row) {
|
||||
i = _soundingRowBySsrc.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
delegate()->peerListRemoveRow(row);
|
||||
}
|
||||
|
||||
@@ -1346,11 +1373,17 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (real->ssrc() != 0
|
||||
&& (!isMe(participantPeer) || _peer->canManageGroupCall())) {
|
||||
addMuteActionsToContextMenu(result, participantPeer, admin, real);
|
||||
if (participant
|
||||
&& (!isMe(participantPeer) || _peer->canManageGroupCall())
|
||||
&& (participant->ssrc != 0
|
||||
|| GetAdditionalAudioSsrc(participant->videoParams) != 0)) {
|
||||
addMuteActionsToContextMenu(
|
||||
result,
|
||||
participantPeer,
|
||||
admin,
|
||||
static_cast<Row*>(row.get()));
|
||||
}
|
||||
}
|
||||
|
||||
if (isMe(participantPeer)) {
|
||||
@@ -1548,14 +1581,14 @@ void Members::Controller::addMuteActionsToContextMenu(
|
||||
|
||||
std::unique_ptr<Row> Members::Controller::createRowForMe() {
|
||||
auto result = std::make_unique<Row>(this, _call->joinAs());
|
||||
updateRow(result.get(), nullptr);
|
||||
updateRow(result.get(), std::nullopt, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Row> Members::Controller::createRow(
|
||||
const Data::GroupCallParticipant &participant) {
|
||||
auto result = std::make_unique<Row>(this, participant.peer);
|
||||
updateRow(result.get(), &participant);
|
||||
updateRow(result.get(), std::nullopt, &participant);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1565,7 +1598,7 @@ std::unique_ptr<Row> Members::Controller::createInvitedRow(
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_unique<Row>(this, participantPeer);
|
||||
updateRow(result.get(), nullptr);
|
||||
updateRow(result.get(), std::nullopt, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1656,7 +1689,7 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
|
||||
) | rpl::map([=] {
|
||||
return Data::PeerFlagValue(
|
||||
channel,
|
||||
MTPDchannel::Flag::f_username);
|
||||
ChannelDataFlag::Username);
|
||||
}) | rpl::flatten_latest());
|
||||
} else {
|
||||
_canAddMembers = Data::CanWriteValue(peer.get());
|
||||
|
||||
@@ -144,7 +144,6 @@ void MembersRow::setSkipLevelUpdate(bool value) {
|
||||
|
||||
void MembersRow::updateState(
|
||||
const Data::GroupCallParticipant *participant) {
|
||||
setSsrc(participant ? participant->ssrc : 0);
|
||||
setVolume(participant
|
||||
? participant->volume
|
||||
: Group::kDefaultVolume);
|
||||
@@ -155,10 +154,16 @@ void MembersRow::updateState(
|
||||
_mutedByMe = false;
|
||||
_raisedHandRating = 0;
|
||||
} else if (!participant->muted
|
||||
|| (participant->sounding && participant->ssrc != 0)) {
|
||||
|| (participant->sounding && participant->ssrc != 0)
|
||||
|| (participant->additionalSounding
|
||||
&& GetAdditionalAudioSsrc(participant->videoParams) != 0)) {
|
||||
setState(State::Active);
|
||||
setSounding(participant->sounding && participant->ssrc != 0);
|
||||
setSpeaking(participant->speaking && participant->ssrc != 0);
|
||||
setSounding((participant->sounding && participant->ssrc != 0)
|
||||
|| (participant->additionalSounding
|
||||
&& GetAdditionalAudioSsrc(participant->videoParams) != 0));
|
||||
setSpeaking((participant->speaking && participant->ssrc != 0)
|
||||
|| (participant->additionalSpeaking
|
||||
&& GetAdditionalAudioSsrc(participant->videoParams) != 0));
|
||||
_mutedByMe = participant->mutedByMe;
|
||||
_raisedHandRating = 0;
|
||||
} else if (participant->canSelfUnmute) {
|
||||
@@ -283,10 +288,6 @@ void MembersRow::setState(State state) {
|
||||
}
|
||||
}
|
||||
|
||||
void MembersRow::setSsrc(uint32 ssrc) {
|
||||
_ssrc = ssrc;
|
||||
}
|
||||
|
||||
void MembersRow::setVolume(int volume) {
|
||||
_volume = volume;
|
||||
if (_statusIcon) {
|
||||
|
||||
@@ -85,9 +85,6 @@ public:
|
||||
[[nodiscard]] State state() const {
|
||||
return _state;
|
||||
}
|
||||
[[nodiscard]] uint32 ssrc() const {
|
||||
return _ssrc;
|
||||
}
|
||||
[[nodiscard]] bool sounding() const {
|
||||
return _sounding;
|
||||
}
|
||||
@@ -179,7 +176,6 @@ private:
|
||||
void setSounding(bool sounding);
|
||||
void setSpeaking(bool speaking);
|
||||
void setState(State state);
|
||||
void setSsrc(uint32 ssrc);
|
||||
void setVolume(int volume);
|
||||
|
||||
void ensureUserpicCache(
|
||||
@@ -212,7 +208,6 @@ private:
|
||||
QString _aboutText;
|
||||
crl::time _speakingLastTime = 0;
|
||||
uint64 _raisedHandRating = 0;
|
||||
uint32 _ssrc = 0;
|
||||
int _volume = Group::kDefaultVolume;
|
||||
bool _sounding : 1;
|
||||
bool _speaking : 1;
|
||||
|
||||
@@ -48,11 +48,13 @@ void EditGroupCallTitleBox(
|
||||
box->setFocusCallback([=] {
|
||||
input->setFocusFast();
|
||||
});
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
const auto submit = [=] {
|
||||
const auto result = input->getLastText().trimmed();
|
||||
box->closeBox();
|
||||
done(result);
|
||||
});
|
||||
};
|
||||
QObject::connect(input, &Ui::InputField::submitted, submit);
|
||||
box->addButton(tr::lng_settings_save(), submit);
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
@@ -76,11 +78,13 @@ void StartGroupCallRecordingBox(
|
||||
box->setFocusCallback([=] {
|
||||
input->setFocusFast();
|
||||
});
|
||||
box->addButton(tr::lng_group_call_recording_start_button(), [=] {
|
||||
const auto submit = [=] {
|
||||
const auto result = input->getLastText().trimmed();
|
||||
box->closeBox();
|
||||
done(result);
|
||||
});
|
||||
};
|
||||
QObject::connect(input, &Ui::InputField::submitted, submit);
|
||||
box->addButton(tr::lng_group_call_recording_start_button(), submit);
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
@@ -105,34 +109,6 @@ void StopGroupCallRecordingBox(
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
[[nodiscard]] auto ToDurationFrom(TimeId startDate) {
|
||||
return [=] {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto elapsed = std::max(now - startDate, 0);
|
||||
const auto hours = elapsed / 3600;
|
||||
const auto minutes = (elapsed % 3600) / 60;
|
||||
const auto seconds = (elapsed % 60);
|
||||
return hours
|
||||
? QString("%1:%2:%3"
|
||||
).arg(hours
|
||||
).arg(minutes, 2, 10, QChar('0')
|
||||
).arg(seconds, 2, 10, QChar('0'))
|
||||
: QString("%1:%2"
|
||||
).arg(minutes
|
||||
).arg(seconds, 2, 10, QChar('0'));
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<QString> ToRecordDuration(TimeId startDate) {
|
||||
return !startDate
|
||||
? (rpl::single(QString()) | rpl::type_erased())
|
||||
: rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(base::timer_each(
|
||||
crl::time(1000)
|
||||
)) | rpl::map(ToDurationFrom(startDate));
|
||||
}
|
||||
|
||||
class JoinAsAction final : public Ui::Menu::ItemBase {
|
||||
public:
|
||||
JoinAsAction(
|
||||
@@ -447,7 +423,6 @@ void RecordingAction::prepare(rpl::producer<QString> text) {
|
||||
std::move(text) | rpl::start_with_next([=](QString text) {
|
||||
const auto &padding = _st.itemPadding;
|
||||
_text.setMarkedText(_st.itemStyle, { text }, MenuTextOptions);
|
||||
const auto textWidth = _text.maxWidth();
|
||||
_textWidth = w - padding.left() - padding.right();
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
@@ -260,12 +260,26 @@ QString Panel::chooseSourceActiveDeviceId() {
|
||||
return _call->screenSharingDeviceId();
|
||||
}
|
||||
|
||||
bool Panel::chooseSourceActiveWithAudio() {
|
||||
return _call->screenSharingWithAudio();
|
||||
}
|
||||
|
||||
bool Panel::chooseSourceWithAudioSupported() {
|
||||
#ifdef Q_OS_WIN
|
||||
return true;
|
||||
#else // Q_OS_WIN
|
||||
return false;
|
||||
#endif // Q_OS_WIN
|
||||
}
|
||||
|
||||
rpl::lifetime &Panel::chooseSourceInstanceLifetime() {
|
||||
return lifetime();
|
||||
}
|
||||
|
||||
void Panel::chooseSourceAccepted(const QString &deviceId) {
|
||||
_call->toggleScreenSharing(deviceId);
|
||||
void Panel::chooseSourceAccepted(
|
||||
const QString &deviceId,
|
||||
bool withAudio) {
|
||||
_call->toggleScreenSharing(deviceId, withAudio);
|
||||
}
|
||||
|
||||
void Panel::chooseSourceStop() {
|
||||
@@ -498,7 +512,6 @@ void Panel::refreshLeftButton() {
|
||||
}
|
||||
|
||||
void Panel::refreshVideoButtons(std::optional<bool> overrideWideMode) {
|
||||
const auto real = _call->lookupReal();
|
||||
const auto create = overrideWideMode.value_or(mode() == PanelMode::Wide)
|
||||
|| (!_call->scheduleDate() && _call->videoIsWorking());
|
||||
const auto created = _video && _screenShare;
|
||||
@@ -1104,9 +1117,7 @@ void Panel::refreshTopButton() {
|
||||
updateButtonsGeometry(); // _wideMenu <-> _settings
|
||||
return;
|
||||
}
|
||||
const auto real = _call->lookupReal();
|
||||
const auto hasJoinAs = _call->showChooseJoinAs();
|
||||
const auto wide = (_mode.current() == PanelMode::Wide);
|
||||
const auto showNarrowMenu = _call->canManage()
|
||||
|| _call->videoIsWorking();
|
||||
const auto showNarrowUserpic = !showNarrowMenu && hasJoinAs;
|
||||
@@ -1188,7 +1199,7 @@ void Panel::chooseShareScreenSource() {
|
||||
if (_call->isSharingScreen()) {
|
||||
_call->toggleScreenSharing(std::nullopt);
|
||||
} else {
|
||||
chooseSourceAccepted(*source);
|
||||
chooseSourceAccepted(*source, false);
|
||||
}
|
||||
} else {
|
||||
Ui::DesktopCapture::ChooseSource(this);
|
||||
@@ -1368,12 +1379,12 @@ void Panel::kickParticipantSure(not_null<PeerData*> participantPeer) {
|
||||
const auto currentRestrictedRights = [&] {
|
||||
const auto user = participantPeer->asUser();
|
||||
if (!channel->mgInfo || !user) {
|
||||
return ChannelData::EmptyRestrictedRights(participantPeer);
|
||||
return ChatRestrictionsInfo();
|
||||
}
|
||||
const auto i = channel->mgInfo->lastRestricted.find(user);
|
||||
return (i != channel->mgInfo->lastRestricted.cend())
|
||||
? i->second.rights
|
||||
: ChannelData::EmptyRestrictedRights(participantPeer);
|
||||
: ChatRestrictionsInfo();
|
||||
}();
|
||||
channel->session().api().kickParticipant(
|
||||
channel,
|
||||
@@ -2146,9 +2157,6 @@ void Panel::refreshTitle() {
|
||||
_subtitle->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
}
|
||||
if (_subtitle) {
|
||||
const auto middle = _title
|
||||
? (_title->x() + _title->width() / 2)
|
||||
: (widget()->width() / 2);
|
||||
const auto top = _title
|
||||
? st::groupCallSubtitleTop
|
||||
: st::groupCallTitleTop;
|
||||
@@ -2163,8 +2171,6 @@ void Panel::refreshTitleGeometry() {
|
||||
return;
|
||||
}
|
||||
const auto fullRect = computeTitleRect();
|
||||
const auto recordingWidth = 2 * st::groupCallRecordingMarkSkip
|
||||
+ st::groupCallRecordingMark;
|
||||
const auto titleRect = _recordingMark
|
||||
? QRect(
|
||||
fullRect.x(),
|
||||
|
||||
@@ -169,8 +169,12 @@ private:
|
||||
|
||||
QWidget *chooseSourceParent() override;
|
||||
QString chooseSourceActiveDeviceId() override;
|
||||
bool chooseSourceActiveWithAudio() override;
|
||||
bool chooseSourceWithAudioSupported() override;
|
||||
rpl::lifetime &chooseSourceInstanceLifetime() override;
|
||||
void chooseSourceAccepted(const QString &deviceId) override;
|
||||
void chooseSourceAccepted(
|
||||
const QString &deviceId,
|
||||
bool withAudio) override;
|
||||
void chooseSourceStop() override;
|
||||
|
||||
const not_null<GroupCall*> _call;
|
||||
|
||||
@@ -53,7 +53,10 @@ namespace Calls::Group {
|
||||
namespace {
|
||||
|
||||
constexpr auto kDelaysCount = 201;
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
constexpr auto kCheckAccessibilityInterval = crl::time(500);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
void SaveCallJoinMuted(
|
||||
not_null<PeerData*> peer,
|
||||
@@ -96,7 +99,6 @@ object_ptr<ShareBox> ShareInviteLinkBox(
|
||||
const QString &linkSpeaker,
|
||||
const QString &linkListener,
|
||||
Fn<void(QString)> showToast) {
|
||||
const auto session = &peer->session();
|
||||
const auto sending = std::make_shared<bool>();
|
||||
const auto box = std::make_shared<QPointer<ShareBox>>();
|
||||
|
||||
@@ -167,8 +169,6 @@ object_ptr<ShareBox> ShareInviteLinkBox(
|
||||
}
|
||||
const auto owner = &peer->owner();
|
||||
auto &api = peer->session().api();
|
||||
auto &histories = owner->histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
for (const auto peer : result) {
|
||||
const auto history = owner->history(peer);
|
||||
auto message = ApiWrap::MessageToSend(history);
|
||||
|
||||
@@ -352,7 +352,6 @@ Viewport::Layout Viewport::applyLarge(Layout layout) const {
|
||||
const auto largeTop = largeRect.y();
|
||||
const auto largeRight = largeLeft + largeRect.width();
|
||||
const auto largeBottom = largeTop + largeRect.height();
|
||||
const auto largeCenter = largeRect.center();
|
||||
for (auto &geometry : list) {
|
||||
if (geometry.tile == _large) {
|
||||
geometry.*field = { QPoint(), layout.outer };
|
||||
|
||||
@@ -282,8 +282,6 @@ vec4 background() {
|
||||
const auto scaled = InterpolateScaledSize(unscaled, size, expandRatio);
|
||||
const auto left = (size.width() - scaled.width()) / 2;
|
||||
const auto top = (size.height() - scaled.height()) / 2;
|
||||
const auto right = left + scaled.width();
|
||||
const auto bottom = top + scaled.height();
|
||||
auto dleft = float(left) / scaled.width();
|
||||
auto dright = float(size.width() - left) / scaled.width();
|
||||
auto dtop = float(top) / scaled.height();
|
||||
@@ -511,7 +509,6 @@ void Viewport::RendererGL::paintTile(
|
||||
const auto fullNameShift = st.namePosition.y() + st::normalFont->height;
|
||||
const auto nameShift = anim::interpolate(fullNameShift, 0, shown);
|
||||
const auto row = tile->row();
|
||||
const auto style = row->computeIconState(MembersRowStyle::Video);
|
||||
|
||||
validateOutlineAnimation(tile, tileData);
|
||||
validatePausedAnimation(tile, tileData);
|
||||
@@ -976,8 +973,8 @@ void Viewport::RendererGL::bindFrame(
|
||||
const auto data = image.constBits();
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RGBA,
|
||||
GL_RGBA,
|
||||
Ui::GL::kFormatRGBA,
|
||||
Ui::GL::kFormatRGBA,
|
||||
image.size(),
|
||||
tileData.rgbaSize,
|
||||
stride,
|
||||
@@ -988,6 +985,7 @@ void Viewport::RendererGL::bindFrame(
|
||||
program.argb32->setUniformValue("s_texture", GLint(0));
|
||||
} else {
|
||||
const auto yuv = data.yuv420;
|
||||
const auto format = Ui::GL::CurrentSingleComponentFormat();
|
||||
program.yuv420->bind();
|
||||
f.glActiveTexture(GL_TEXTURE0);
|
||||
tileData.textures.bind(f, 0);
|
||||
@@ -995,8 +993,8 @@ void Viewport::RendererGL::bindFrame(
|
||||
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RED,
|
||||
GL_RED,
|
||||
format,
|
||||
format,
|
||||
yuv->size,
|
||||
tileData.textureSize,
|
||||
yuv->y.stride,
|
||||
@@ -1009,8 +1007,8 @@ void Viewport::RendererGL::bindFrame(
|
||||
if (upload) {
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RED,
|
||||
GL_RED,
|
||||
format,
|
||||
format,
|
||||
yuv->chromaSize,
|
||||
tileData.textureChromaSize,
|
||||
yuv->u.stride,
|
||||
@@ -1021,8 +1019,8 @@ void Viewport::RendererGL::bindFrame(
|
||||
if (upload) {
|
||||
uploadTexture(
|
||||
f,
|
||||
GL_RED,
|
||||
GL_RED,
|
||||
format,
|
||||
format,
|
||||
yuv->chromaSize,
|
||||
tileData.textureChromaSize,
|
||||
yuv->v.stride,
|
||||
@@ -1335,7 +1333,6 @@ void Viewport::RendererGL::validateDatas() {
|
||||
}
|
||||
for (const auto &request : requests) {
|
||||
const auto i = request.index;
|
||||
const auto index = _tileDataIndices[i];
|
||||
const auto &data = _tileData[_tileDataIndices[i]];
|
||||
if (data.nameRect.isEmpty()) {
|
||||
continue;
|
||||
@@ -1368,16 +1365,17 @@ void Viewport::RendererGL::validateNoiseTexture(
|
||||
if (_noiseTexture.created()) {
|
||||
return;
|
||||
}
|
||||
const auto format = Ui::GL::CurrentSingleComponentFormat();
|
||||
_noiseTexture.ensureCreated(f, GL_NEAREST, GL_REPEAT);
|
||||
_noiseTexture.bind(f, 0);
|
||||
f.glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RED,
|
||||
format,
|
||||
kNoiseTextureSize,
|
||||
kNoiseTextureSize,
|
||||
0,
|
||||
GL_RED,
|
||||
format,
|
||||
GL_UNSIGNED_BYTE,
|
||||
nullptr);
|
||||
|
||||
|
||||
@@ -75,10 +75,6 @@ MenuVolumeItem::MenuVolumeItem(
|
||||
_speakerRect = QRect(_itemRect.topLeft(), _stCross.icon.size());
|
||||
_arcPosition = _speakerRect.center()
|
||||
+ QPoint(0, st::groupCallMenuSpeakerArcsSkip);
|
||||
const auto sliderLeft = _arcPosition.x()
|
||||
+ st::groupCallMenuVolumeSkip
|
||||
+ _arcs->maxWidth()
|
||||
+ st::groupCallMenuVolumeSkip;
|
||||
_slider->setGeometry(
|
||||
st::groupCallMenuVolumeMargin.left(),
|
||||
_speakerRect.y(),
|
||||
|
||||