Compare commits
304 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fea6393c6 | ||
|
|
53f063fe16 | ||
|
|
6ee72b9c32 | ||
|
|
5faefa7997 | ||
|
|
b0726cd31a | ||
|
|
64f5fa8dc3 | ||
|
|
ad300f5eae | ||
|
|
7331160e22 | ||
|
|
6af82e5ae5 | ||
|
|
9b2347171f | ||
|
|
c60629c17d | ||
|
|
353e18e8e3 | ||
|
|
f069df285d | ||
|
|
6c5f8dffa6 | ||
|
|
4a77e23b54 | ||
|
|
942e53b59b | ||
|
|
21a6a256b9 | ||
|
|
99567d3a53 | ||
|
|
eddad6b690 | ||
|
|
d02a8cbca1 | ||
|
|
3b079aa29a | ||
|
|
df5307dd32 | ||
|
|
65891508e0 | ||
|
|
b5f4e40c3e | ||
|
|
a427730acd | ||
|
|
d7639a1ab6 | ||
|
|
01a140ea29 | ||
|
|
6e0ff9b6a0 | ||
|
|
fb14eeeb1e | ||
|
|
0c701d9d95 | ||
|
|
f1ceb1c95a | ||
|
|
6bd41a07a1 | ||
|
|
2b78bb6e79 | ||
|
|
7e5d5ddafe | ||
|
|
150c25c81a | ||
|
|
95319bdaca | ||
|
|
d982835b50 | ||
|
|
6f040aa0b5 | ||
|
|
080ecece66 | ||
|
|
31ece2c26e | ||
|
|
9a20f4b935 | ||
|
|
ea61fd22f5 | ||
|
|
c77f8f9f41 | ||
|
|
ad758c51c2 | ||
|
|
8ac7fd14ec | ||
|
|
ed7c5e97cb | ||
|
|
fb928a15a6 | ||
|
|
f60155e7b8 | ||
|
|
7c28b1a6a6 | ||
|
|
a300f4662e | ||
|
|
3ff376774f | ||
|
|
e16c05385f | ||
|
|
6e8825cdd5 | ||
|
|
1c19895ce7 | ||
|
|
e62a4b065a | ||
|
|
ba363285a7 | ||
|
|
679c932697 | ||
|
|
581ec70bf3 | ||
|
|
4d2700ab1c | ||
|
|
b365136639 | ||
|
|
f23153e1ac | ||
|
|
26cb931dcf | ||
|
|
42d2190d17 | ||
|
|
63ad80200e | ||
|
|
68e9c63693 | ||
|
|
542ff88d3b | ||
|
|
bf7f73e472 | ||
|
|
c9f195be90 | ||
|
|
715da30a72 | ||
|
|
4e9f2aaadd | ||
|
|
71cbb037ce | ||
|
|
9e43972313 | ||
|
|
4a8bb75851 | ||
|
|
80dce3b65a | ||
|
|
056534fb41 | ||
|
|
e444b82683 | ||
|
|
d9e4f686fb | ||
|
|
2cd224af98 | ||
|
|
a50141ac8a | ||
|
|
f11b36cdb1 | ||
|
|
f30af1c4ed | ||
|
|
45def31826 | ||
|
|
a22afce820 | ||
|
|
af874bebfd | ||
|
|
7cdb651538 | ||
|
|
5e1752bcbc | ||
|
|
eb295cb19c | ||
|
|
ace42226b6 | ||
|
|
5e1b4b4e6a | ||
|
|
f009fa9e47 | ||
|
|
f08c00557d | ||
|
|
a0e0d95775 | ||
|
|
a4acab983d | ||
|
|
5237a7977d | ||
|
|
eb285bc1ac | ||
|
|
7d97cd25ab | ||
|
|
55f4a99824 | ||
|
|
34373836b9 | ||
|
|
1509891ec0 | ||
|
|
877ef7d78f | ||
|
|
8f26a24f78 | ||
|
|
6abd4bae58 | ||
|
|
f8844750f5 | ||
|
|
de984d44ac | ||
|
|
babcefeb23 | ||
|
|
71a55290ab | ||
|
|
8ef0b88633 | ||
|
|
f9c3415aa7 | ||
|
|
deb7d5914f | ||
|
|
469e4394bd | ||
|
|
1bcf9dda0a | ||
|
|
02fafde09d | ||
|
|
de5e1b3452 | ||
|
|
4381db691b | ||
|
|
bd879262c2 | ||
|
|
da88b4c475 | ||
|
|
276a18cddd | ||
|
|
6eb54e55a5 | ||
|
|
e7fa330215 | ||
|
|
27ed160a40 | ||
|
|
180b614c86 | ||
|
|
e2e6b64632 | ||
|
|
be46aacbe5 | ||
|
|
3bd46f3415 | ||
|
|
7e6e2960bd | ||
|
|
9df4377450 | ||
|
|
294ab035f0 | ||
|
|
f96554e271 | ||
|
|
2c1fdbe55b | ||
|
|
b5bce29514 | ||
|
|
97557b85d9 | ||
|
|
8a5cc70d9b | ||
|
|
d5075891b2 | ||
|
|
4df778f4e9 | ||
|
|
3cda66f1f3 | ||
|
|
e0991d9376 | ||
|
|
8c94742070 | ||
|
|
419b2b02bc | ||
|
|
b4998527dd | ||
|
|
8ac8598b20 | ||
|
|
f7ddf8b024 | ||
|
|
18f1563829 | ||
|
|
20ba35c0a7 | ||
|
|
de4764c1c7 | ||
|
|
31bb8a3ac5 | ||
|
|
e0156abe7c | ||
|
|
7d02e92843 | ||
|
|
80aef75ea5 | ||
|
|
c940062787 | ||
|
|
4b3b9ad140 | ||
|
|
1bb2efc346 | ||
|
|
0b699b45b1 | ||
|
|
3c0487db81 | ||
|
|
f62869e4df | ||
|
|
fce459f612 | ||
|
|
6a003114db | ||
|
|
39ed5cab0d | ||
|
|
4b67c8f4bb | ||
|
|
65604add65 | ||
|
|
3e69f65d1c | ||
|
|
0b26dbbc9e | ||
|
|
152d943f3d | ||
|
|
7fffd1d318 | ||
|
|
5d875341f4 | ||
|
|
61dbd4c4c2 | ||
|
|
5f42011c7b | ||
|
|
7e56174ba9 | ||
|
|
0a83b3f58c | ||
|
|
71fec23311 | ||
|
|
2ba3035a13 | ||
|
|
7a653a8e1b | ||
|
|
a93b32fb53 | ||
|
|
d82cc350c0 | ||
|
|
5997a7d48a | ||
|
|
7641fb6712 | ||
|
|
dfaf9b9d43 | ||
|
|
6147b0eec0 | ||
|
|
2eefef3649 | ||
|
|
1905a67e6c | ||
|
|
38ab18f6fb | ||
|
|
ddcc20c8a7 | ||
|
|
f3c6763058 | ||
|
|
91a11d2e74 | ||
|
|
fb880481a4 | ||
|
|
9e6703f02f | ||
|
|
da5435d1cb | ||
|
|
db0726364b | ||
|
|
944b2de852 | ||
|
|
53927502af | ||
|
|
828d8ea051 | ||
|
|
f2e345b39f | ||
|
|
6f625a899c | ||
|
|
28bc8c3bf3 | ||
|
|
ef30949943 | ||
|
|
4f888bc418 | ||
|
|
34caf6967e | ||
|
|
a728c783d9 | ||
|
|
934d232653 | ||
|
|
4fbc7771c9 | ||
|
|
571ab422bf | ||
|
|
9592f4de6e | ||
|
|
c126d99fd0 | ||
|
|
11c8a272ec | ||
|
|
f7170b8c50 | ||
|
|
9ce28f4cb7 | ||
|
|
522a457d98 | ||
|
|
9e9ffaa27b | ||
|
|
9ab4a8ab6e | ||
|
|
5c784081c2 | ||
|
|
9c84c0afe9 | ||
|
|
accc5e8b10 | ||
|
|
1e0c71a411 | ||
|
|
663687884b | ||
|
|
ade2bdcafd | ||
|
|
9e01e64f63 | ||
|
|
7cc0fd879d | ||
|
|
42bd835800 | ||
|
|
ef7b5cb8e7 | ||
|
|
2651d79b63 | ||
|
|
ddc12c3f71 | ||
|
|
9c3c2e9fa7 | ||
|
|
564f9ac38d | ||
|
|
1b49bd0843 | ||
|
|
831d79d912 | ||
|
|
d61f809cca | ||
|
|
130176fd7e | ||
|
|
1ea9be9877 | ||
|
|
e3b56aa05b | ||
|
|
4f4195c88a | ||
|
|
1d9a8af174 | ||
|
|
8b1e7e1fa9 | ||
|
|
eeb0b62bfa | ||
|
|
0a114bbe4a | ||
|
|
474458e4c3 | ||
|
|
c6b73631d8 | ||
|
|
bce318c48e | ||
|
|
9e4ac1c835 | ||
|
|
53933db077 | ||
|
|
4156d8e908 | ||
|
|
6491d83085 | ||
|
|
6259d30e2b | ||
|
|
3ee7a0dc16 | ||
|
|
43d8723e35 | ||
|
|
d59ab17ac5 | ||
|
|
d26cda097f | ||
|
|
6daa58b596 | ||
|
|
d0920d9eb9 | ||
|
|
fbd353501b | ||
|
|
9876aa64e0 | ||
|
|
b8ccf7b3d4 | ||
|
|
c15b5914b2 | ||
|
|
73aebb8890 | ||
|
|
f9270710be | ||
|
|
0b63abf5b4 | ||
|
|
51ae4af83e | ||
|
|
4832982988 | ||
|
|
b4d49715dc | ||
|
|
0de7b4eb39 | ||
|
|
3e88451ea8 | ||
|
|
5468fde492 | ||
|
|
f17e13cad0 | ||
|
|
f511449273 | ||
|
|
bbe65e212a | ||
|
|
5ebd0df15f | ||
|
|
66a34bcb89 | ||
|
|
acad1d4175 | ||
|
|
716fade52a | ||
|
|
3b9312d9ac | ||
|
|
f87d072c79 | ||
|
|
b61724019a | ||
|
|
3ffdb1ee56 | ||
|
|
5fbf280e4a | ||
|
|
f787e0fa1d | ||
|
|
0d33b92d24 | ||
|
|
8e5d0c66db | ||
|
|
6e8ac60399 | ||
|
|
f8bd80109c | ||
|
|
de89d349ad | ||
|
|
dbc9beaa19 | ||
|
|
1f171c4ed1 | ||
|
|
2e03888505 | ||
|
|
ab5eafbe68 | ||
|
|
73014a33fe | ||
|
|
7bdbe0ef77 | ||
|
|
d4dbad4649 | ||
|
|
24b23bbb5a | ||
|
|
abab44a02b | ||
|
|
b9c07e644f | ||
|
|
ce9c3b4ef8 | ||
|
|
13862bd561 | ||
|
|
856d38df49 | ||
|
|
27a5e13107 | ||
|
|
a71c24f803 | ||
|
|
758ec52b91 | ||
|
|
96418bb9f1 | ||
|
|
f750d94b2d | ||
|
|
6eb9695e1e | ||
|
|
33bbad8053 | ||
|
|
3ea34461b2 | ||
|
|
b6a202b721 | ||
|
|
4d8cb022c5 | ||
|
|
3046318de5 | ||
|
|
c351598f13 | ||
|
|
02084be583 |
2
.github/workflows/linux.yml
vendored
@@ -148,7 +148,7 @@ jobs:
|
||||
cd out/Debug
|
||||
mkdir artifact
|
||||
mv {Telegram,Updater} artifact/
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
with:
|
||||
|
||||
2
.github/workflows/mac.yml
vendored
@@ -131,7 +131,7 @@ jobs:
|
||||
mkdir artifact
|
||||
mv Telegram.app artifact/
|
||||
mv Updater artifact/
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
with:
|
||||
|
||||
9
.github/workflows/mac_packaged.yml
vendored
@@ -69,7 +69,7 @@ jobs:
|
||||
run: |
|
||||
brew update
|
||||
brew upgrade || true
|
||||
brew install ada-url autoconf automake boost cmake ffmpeg@6 jpeg-xl libavif libheif libtool openal-soft openh264 openssl opus ninja pkg-config python qt yasm xz
|
||||
brew install ada-url autoconf automake boost cmake ffmpeg@6 jpeg-xl libavif libheif libtool openal-soft openh264 openssl opus ninja pkg-config python qtbase qtimageformats qtsvg xz
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
|
||||
xcodebuild -version > CACHE_KEY.txt
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
fi
|
||||
echo "CACHE_KEY=`md5 -q CACHE_KEY.txt`" >> $GITHUB_ENV
|
||||
|
||||
echo "MACOSX_DEPLOYMENT_TARGET=$(grep 'set(QT_SUPPORTED_MIN_MACOS_VERSION' /opt/homebrew/Cellar/qt/6.9.2/lib/cmake/Qt6/Qt6ConfigExtras.cmake | sed -E 's/^.*"(.*)"\)$/\1/')" >> $GITHUB_ENV
|
||||
echo "MACOSX_DEPLOYMENT_TARGET=$(grep 'set(QT_SUPPORTED_MIN_MACOS_VERSION' /opt/homebrew/Cellar/qtbase/*/lib/cmake/Qt6/Qt6ConfigExtras.cmake | sed -E 's/^.*"(.*)"\)$/\1/')" >> $GITHUB_ENV
|
||||
echo "LibrariesPath=`pwd`" >> $GITHUB_ENV
|
||||
|
||||
curl -o tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
|
||||
@@ -115,7 +115,8 @@ jobs:
|
||||
cmake -Bbuild -GNinja . \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_C_FLAGS_DEBUG="" \
|
||||
-DCMAKE_CXX_FLAGS_DEBUG=""
|
||||
-DCMAKE_CXX_FLAGS_DEBUG="" \
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_absl=ON
|
||||
|
||||
cmake --build build --parallel
|
||||
|
||||
@@ -186,7 +187,7 @@ jobs:
|
||||
cd $REPO_NAME/build
|
||||
mkdir artifact
|
||||
mv Telegram.dmg artifact/
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
with:
|
||||
|
||||
2
.github/workflows/snap.yml
vendored
@@ -84,7 +84,7 @@ jobs:
|
||||
mkdir artifact
|
||||
mv $artifact_name artifact
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
with:
|
||||
|
||||
2
.github/workflows/win.yml
vendored
@@ -203,7 +203,7 @@ jobs:
|
||||
mkdir artifact
|
||||
move %OUT%\Telegram.exe artifact/
|
||||
move %OUT%\Updater.exe artifact/
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
name: Upload artifact.
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
||||
with:
|
||||
|
||||
@@ -1044,6 +1044,8 @@ PRIVATE
|
||||
info/polls/info_polls_results_widget.h
|
||||
info/profile/info_profile_actions.cpp
|
||||
info/profile/info_profile_actions.h
|
||||
info/profile/info_profile_badge_tooltip.cpp
|
||||
info/profile/info_profile_badge_tooltip.h
|
||||
info/profile/info_profile_badge.cpp
|
||||
info/profile/info_profile_badge.h
|
||||
info/profile/info_profile_cover.cpp
|
||||
@@ -1058,6 +1060,10 @@ PRIVATE
|
||||
info/profile/info_profile_members_controllers.h
|
||||
info/profile/info_profile_phone_menu.cpp
|
||||
info/profile/info_profile_phone_menu.h
|
||||
info/profile/info_profile_status_label.cpp
|
||||
info/profile/info_profile_status_label.h
|
||||
info/profile/info_profile_top_bar.cpp
|
||||
info/profile/info_profile_top_bar.h
|
||||
info/profile/info_profile_values.cpp
|
||||
info/profile/info_profile_values.h
|
||||
info/profile/info_profile_widget.cpp
|
||||
@@ -1066,6 +1072,7 @@ PRIVATE
|
||||
info/reactions_list/info_reactions_list_widget.h
|
||||
info/requests_list/info_requests_list_widget.cpp
|
||||
info/requests_list/info_requests_list_widget.h
|
||||
info/saved/info_saved_music_common.cpp
|
||||
info/saved/info_saved_music_common.h
|
||||
info/saved/info_saved_music_provider.cpp
|
||||
info/saved/info_saved_music_provider.h
|
||||
@@ -1667,8 +1674,12 @@ PRIVATE
|
||||
ui/item_text_options.cpp
|
||||
ui/item_text_options.h
|
||||
ui/resize_area.h
|
||||
ui/top_background_gradient.cpp
|
||||
ui/top_background_gradient.h
|
||||
ui/unread_badge.cpp
|
||||
ui/unread_badge.h
|
||||
ui/peer/video_userpic_player.cpp
|
||||
ui/peer/video_userpic_player.h
|
||||
window/main_window.cpp
|
||||
window/main_window.h
|
||||
window/notifications_manager.cpp
|
||||
|
||||
BIN
Telegram/Resources/animations/my_gifts_empty.tgs
Normal file
BIN
Telegram/Resources/animations/profile/profile_muting.tgs
Normal file
BIN
Telegram/Resources/animations/profile/profile_unmuting.tgs
Normal file
BIN
Telegram/Resources/animations/rtmp.tgs
Normal file
BIN
Telegram/Resources/animations/show_or_premium_lastseen.tgs
Normal file
BIN
Telegram/Resources/animations/show_or_premium_readtime.tgs
Normal file
BIN
Telegram/Resources/animations/toast/chats_filter_in.tgs
Normal file
3
Telegram/Resources/icons/profile/call.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M19.035,15.184L16.561,14.901C15.786,14.771 14.725,15.259 13.376,16.365C13.315,16.416 13.142,16.533 12.95,16.54C12.764,16.547 12.56,16.444 12.493,16.408C10.162,15.134 8.734,13.687 7.467,11.306C7.435,11.247 7.356,11.086 7.38,10.938C7.402,10.802 7.524,10.676 7.567,10.624C8.595,9.364 9.108,8.299 9.108,7.429L8.826,4.974C8.709,3.99 7.881,3.25 6.887,3.25L5.202,3.25C4.101,3.25 3.185,4.166 3.254,5.267C3.77,13.586 10.424,20.23 18.733,20.746C19.834,20.815 20.75,19.899 20.75,18.798L20.75,17.113C20.76,16.129 20.019,15.301 19.035,15.184Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 649 B |
3
Telegram/Resources/icons/profile/gift.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M11.157,13.843L11.157,21.158L7.506,21.158C6.265,21.158 5.26,20.152 5.26,18.911L5.26,13.843L11.157,13.843ZM18.741,13.829L18.74,18.911C18.74,20.152 17.735,21.158 16.494,21.158L12.842,21.158L12.842,13.843L18.6,13.843C18.648,13.843 18.695,13.838 18.741,13.829ZM14.727,3.208C15.308,3.208 15.832,3.33 16.301,3.575C16.77,3.819 17.144,4.158 17.423,4.591C17.702,5.025 17.841,5.519 17.841,6.075C17.841,6.454 17.768,6.802 17.622,7.119C17.492,7.402 17.319,7.652 17.104,7.871L17.037,7.935L19.302,7.935C19.923,7.935 20.426,8.438 20.426,9.058L20.426,11.313C20.426,11.933 19.923,12.436 19.302,12.436L18.74,12.436L18.741,12.45C18.695,12.441 18.648,12.436 18.6,12.436L12.842,12.436L12.842,7.951L11.16,7.951L11.16,6.729C11.16,6.118 10.977,5.631 10.611,5.268C10.245,4.905 9.804,4.723 9.287,4.723C8.8,4.723 8.403,4.853 8.097,5.114C7.79,5.375 7.637,5.736 7.637,6.197C7.637,6.668 7.827,7.078 8.207,7.427C8.521,7.715 8.94,7.885 9.464,7.935L11.157,7.935L11.157,12.436L4.698,12.436C4.077,12.436 3.574,11.933 3.574,11.313L3.574,9.058C3.574,8.438 4.077,7.935 4.698,7.935L6.849,7.935C6.603,7.702 6.408,7.43 6.265,7.119C6.119,6.802 6.046,6.454 6.046,6.075C6.046,5.519 6.185,5.025 6.464,4.591C6.743,4.158 7.118,3.819 7.59,3.575C8.061,3.33 8.585,3.208 9.16,3.208C9.8,3.208 10.369,3.371 10.868,3.698C11.367,4.025 11.727,4.487 11.948,5.085C12.169,4.487 12.527,4.025 13.023,3.698C13.519,3.371 14.087,3.208 14.727,3.208ZM14.608,4.723C14.087,4.723 13.643,4.905 13.276,5.268C12.91,5.631 12.843,6.118 12.843,6.729L12.842,7.935L14.423,7.935C14.909,7.888 15.305,7.739 15.61,7.487L15.679,7.427C16.059,7.078 16.249,6.668 16.249,6.197C16.249,5.736 16.096,5.375 15.79,5.114C15.484,4.853 15.09,4.723 14.608,4.723Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
3
Telegram/Resources/icons/profile/join.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M17.176,12.972C19.682,12.972 21.713,15.004 21.713,17.509C21.713,20.015 19.682,22.046 17.176,22.046C14.67,22.046 12.639,20.015 12.639,17.509C12.639,15.004 14.67,12.972 17.176,12.972ZM11.343,12.729C11.998,12.729 12.619,12.78 13.209,12.881C11.869,14.011 11.019,15.701 11.019,17.59C11.019,18.624 11.273,19.598 11.723,20.453L5.218,20.453C4.358,20.453 3.759,20.317 3.422,20.046C3.085,19.774 2.917,19.391 2.917,18.895C2.917,18.245 3.113,17.562 3.505,16.845C3.897,16.128 4.462,15.459 5.2,14.836C5.938,14.214 6.824,13.707 7.86,13.316C8.895,12.925 10.056,12.729 11.343,12.729ZM17.176,14.593C16.848,14.593 16.582,14.858 16.582,15.186L16.582,16.915L14.853,16.915C14.525,16.915 14.259,17.181 14.259,17.509C14.259,17.837 14.525,18.103 14.853,18.103L16.582,18.103L16.582,19.832C16.582,20.16 16.848,20.426 17.176,20.426C17.504,20.426 17.77,20.16 17.77,19.832L17.77,18.103L19.499,18.103C19.827,18.103 20.093,17.837 20.093,17.509C20.093,17.181 19.827,16.915 19.499,16.915L17.77,16.915L17.77,15.186C17.77,14.858 17.504,14.593 17.176,14.593ZM11.343,10.974C12.117,10.974 12.822,10.784 13.459,10.405C14.096,10.025 14.605,9.514 14.985,8.872C15.365,8.229 15.556,7.507 15.556,6.706C15.556,5.934 15.364,5.233 14.98,4.605C14.596,3.976 14.085,3.476 13.446,3.105C12.807,2.733 12.106,2.548 11.343,2.548C10.579,2.548 9.878,2.735 9.239,3.111C8.601,3.486 8.089,3.989 7.705,4.621C7.322,5.253 7.13,5.953 7.13,6.722C7.133,7.513 7.325,8.229 7.705,8.872C8.085,9.514 8.595,10.025 9.234,10.405C9.873,10.784 10.576,10.974 11.343,10.974Z" fill="#FFFFFF" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
3
Telegram/Resources/icons/profile/leave.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M12.329,3.574C13.94,3.574 15.245,4.88 15.245,6.491L15.245,7.463C15.245,8 14.81,8.435 14.273,8.435C13.736,8.435 13.301,8 13.301,7.463L13.301,6.491C13.301,5.954 12.866,5.519 12.329,5.519L6.171,5.519C5.634,5.519 5.199,5.954 5.199,6.491L5.199,17.509C5.199,18.046 5.634,18.481 6.171,18.481L12.329,18.481C12.866,18.481 13.301,18.046 13.301,17.509L13.301,16.537C13.301,16 13.736,15.565 14.273,15.565C14.81,15.565 15.245,16 15.245,16.537L15.245,17.509C15.245,19.12 13.94,20.426 12.329,20.426L6.171,20.426C4.56,20.426 3.255,19.12 3.255,17.509L3.255,6.491C3.255,4.88 4.56,3.574 6.171,3.574L12.329,3.574ZM19.045,7.945L21.927,11.13C22.374,11.624 22.374,12.376 21.927,12.87L19.045,16.055C18.685,16.453 18.07,16.484 17.672,16.124C17.274,15.763 17.243,15.149 17.603,14.751L19.212,12.972L10.06,12.972C9.523,12.972 9.088,12.537 9.088,12C9.088,11.463 9.523,11.028 10.06,11.028L19.212,11.028L17.603,9.249C17.257,8.867 17.272,8.285 17.626,7.921L17.672,7.876C18.07,7.516 18.685,7.547 19.045,7.945Z" fill="#FFFFFF" fill-rule="nonzero"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
3
Telegram/Resources/icons/profile/message.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M12.009,2.759C17.307,2.759 21.602,6.688 21.602,11.533C21.602,16.379 17.307,20.307 12.009,20.307C10.566,20.307 9.197,20.016 7.969,19.494C7.602,19.784 7.273,20.004 6.98,20.154C6.092,20.609 5.496,20.772 4.144,20.914C3.778,20.952 3.534,20.625 3.819,20.34C4.452,19.708 4.793,18.577 4.966,17.49C3.384,15.925 2.417,13.833 2.417,11.533C2.417,6.688 6.711,2.759 12.009,2.759Z" fill="#FFFFFF" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 505 B |
3
Telegram/Resources/icons/profile/mute.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M11.922,2.528C12.663,2.528 13.264,3.129 13.264,3.87L13.264,4.492C16.232,5.216 18.32,7.681 18.32,10.805L18.32,14.987C18.32,15.133 18.373,15.273 18.47,15.382L19.678,16.735C20.342,17.382 19.668,18.491 18.731,18.491L5.261,18.491C4.324,18.491 3.661,17.382 4.324,16.735L5.532,15.382C5.629,15.273 5.682,15.133 5.682,14.987L5.682,10.805C5.682,7.735 7.675,5.317 10.556,4.538L10.556,3.87C10.556,3.151 11.121,2.564 11.831,2.529L11.922,2.528ZM12.001,21.472C13.159,21.472 14.107,20.558 14.107,19.525L9.895,19.525C9.895,20.558 10.832,21.472 12.001,21.472Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 661 B |
BIN
Telegram/Resources/icons/profile/profile_manage.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
Telegram/Resources/icons/profile/profile_manage@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/profile/profile_manage@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/profile/profile_more.png
Normal file
|
After Width: | Height: | Size: 352 B |
BIN
Telegram/Resources/icons/profile/profile_more@2x.png
Normal file
|
After Width: | Height: | Size: 442 B |
BIN
Telegram/Resources/icons/profile/profile_more@3x.png
Normal file
|
After Width: | Height: | Size: 818 B |
3
Telegram/Resources/icons/profile/report.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M12,2.833C17.063,2.833 21.167,6.937 21.167,12C21.167,17.063 17.063,21.167 12,21.167C6.937,21.167 2.833,17.063 2.833,12C2.833,6.937 6.937,2.833 12,2.833ZM12,14.444C11.347,14.444 10.813,14.957 10.779,15.602L10.778,15.689C10.778,16.364 11.325,16.911 12,16.911C12.653,16.911 13.187,16.398 13.221,15.754L13.222,15.667C13.222,14.992 12.675,14.444 12,14.444ZM12,7.111C11.404,7.111 10.922,7.594 10.922,8.19L10.922,11.995C10.922,12.591 11.404,13.074 12,13.074C12.596,13.074 13.078,12.591 13.078,11.995L13.078,8.19C13.078,7.594 12.596,7.111 12,7.111Z" fill="#FFFFFF" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 680 B |
3
Telegram/Resources/icons/profile/unmute.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M14.107,19.525C14.107,20.558 13.159,21.472 12.001,21.472C10.832,21.472 9.895,20.558 9.895,19.525L14.107,19.525ZM3.505,3.471L20.618,19.654C20.962,19.979 20.977,20.52 20.652,20.864C20.327,21.207 19.786,21.222 19.443,20.898L2.329,4.714C1.986,4.389 1.971,3.848 2.295,3.505C2.62,3.161 3.162,3.146 3.505,3.471ZM5.718,10.105L14.585,18.491L5.261,18.491C4.324,18.491 3.661,17.382 4.324,16.735L5.532,15.382C5.629,15.273 5.682,15.133 5.682,14.987L5.682,10.805C5.682,10.568 5.694,10.334 5.718,10.105ZM11.922,2.528C12.663,2.528 13.264,3.129 13.264,3.87L13.264,4.492C16.232,5.216 18.32,7.681 18.32,10.805L18.32,14.987C18.32,15.133 18.373,15.273 18.47,15.382L18.781,15.73L8.174,5.699C8.862,5.176 9.666,4.779 10.556,4.538L10.556,3.87C10.556,3.151 11.121,2.564 11.831,2.529L11.922,2.528Z" fill="#FFFFFF" fill-rule="nonzero"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 910 B |
|
After Width: | Height: | Size: 866 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 764 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon / Filled / premium_themes</title>
|
||||
<g id="Icon-/-Filled-/-premium_themes" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M8.65381112,10.7516786 L14.600547,16.5507975 C14.7950866,16.740508 14.7950866,17.0480895 14.600547,17.2378 L13.8655201,17.9545811 C13.6709805,18.1442916 13.3555695,18.1442916 13.1610299,17.9545811 C12.1129217,17.0843554 11.3456336,16.4119807 10.8591655,15.937457 C10.7682049,15.8487297 10.5422415,15.7847321 10.4567355,15.904017 L10.201902,16.2497487 L10.0193453,16.4884401 L9.83300263,16.7270352 L9.02218186,17.7460428 L8.75587192,18.0918034 L8.59549123,18.3121046 C7.91167738,19.2768629 6.91083947,19.1001271 6.35158932,18.5547593 C5.80232578,18.0191302 5.85863289,17.1049913 6.79138874,16.4035319 L6.85891507,16.3573404 C6.99427087,16.2669684 7.14265185,16.157786 7.30037755,16.0361677 L7.68363141,15.7328223 L8.38962036,15.1596258 L8.6312678,14.9665056 C8.79873654,14.8340204 8.96615336,14.7048192 9.13062469,14.5839136 C9.24335825,14.5010414 9.22165977,14.3680769 9.1319646,14.280627 L8.89532907,14.0428177 C8.55768805,13.6947027 8.13153904,13.2224438 7.61688206,12.6260412 L7.21429408,12.1554622 C7.01975448,11.9657517 7.01975448,11.6581702 7.21429408,11.4684597 L7.9493209,10.7516786 C8.1438605,10.5619681 8.45927152,10.5619681 8.65381112,10.7516786 Z M14.0750341,4.02554926 C14.1700659,4.05313428 14.2562711,4.10500261 14.3244531,4.17672529 L17.4193876,7.36611999 C17.5229412,7.47283414 17.5525486,7.63117292 17.4945519,7.76809496 L16.3521671,10.465106 C16.3075918,10.570342 16.3567671,10.6917881 16.4620031,10.7363634 C16.5226789,10.7620641 16.5919675,10.7573313 16.648585,10.7236188 L18.8014275,9.44172252 C18.9580015,9.3484915 19.1591462,9.38314731 19.2754925,9.52340059 L19.824657,10.1854078 C20.080453,10.493765 20.0450803,10.9495406 19.7447707,11.2147384 L15.2419116,15.19113 L10.0408804,10.1008505 C10.8928945,9.23732408 11.6272327,8.25187058 12.2438948,7.14448999 C12.7106069,6.30638457 13.08566,5.39611751 13.3690539,4.41368881 C13.456971,4.1116676 13.7729463,3.93786178 14.0750341,4.02554926 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_menu_my_stories" = "My Stories";
|
||||
"lng_menu_my_groups" = "My Groups";
|
||||
"lng_menu_my_channels" = "My Channels";
|
||||
"lng_open_menu" = "Open navigation menu";
|
||||
|
||||
"lng_disable_notifications_from_tray" = "Disable notifications";
|
||||
"lng_enable_notifications_from_tray" = "Enable notifications";
|
||||
@@ -127,6 +128,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_cancel" = "Cancel";
|
||||
"lng_continue" = "Continue";
|
||||
"lng_close" = "Close";
|
||||
"lng_minimize_window" = "Minimize";
|
||||
"lng_maximize_window" = "Maximize";
|
||||
"lng_restore_window" = "Restore";
|
||||
"lng_go_back" = "Go back";
|
||||
"lng_connecting" = "Connecting...";
|
||||
"lng_reconnecting#one" = "Reconnect in {count} s...";
|
||||
"lng_reconnecting#other" = "Reconnect in {count} s...";
|
||||
@@ -388,6 +393,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_country_ph" = "Search";
|
||||
"lng_country_none" = "Country not found";
|
||||
"lng_country_select" = "Select Country";
|
||||
"lng_phone_number" = "Phone number";
|
||||
|
||||
"lng_code_ph" = "Code";
|
||||
"lng_code_desc" = "We've sent an activation code to your phone.\nPlease enter it below.";
|
||||
@@ -736,6 +742,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_settings_language" = "Language";
|
||||
"lng_settings_default_scale" = "Default interface scale";
|
||||
"lng_settings_scale" = "Interface scale";
|
||||
"lng_settings_connection_type" = "Connection type";
|
||||
"lng_settings_downloading_update" = "Downloading update {progress}...";
|
||||
"lng_settings_privacy_title" = "Privacy";
|
||||
@@ -970,6 +977,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_font_family" = "Font family";
|
||||
|
||||
"lng_settings_color_title" = "Color preview";
|
||||
"lng_settings_color_tab_profile" = "Profile";
|
||||
"lng_settings_color_tab_name" = "Name";
|
||||
"lng_settings_color_reply" = "Reply to your message";
|
||||
"lng_settings_color_reply_channel" = "Reply to your channel message";
|
||||
"lng_settings_color_text" = "Your name and replies to your messages will be shown in the selected color.";
|
||||
@@ -984,10 +993,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_color_emoji_off" = "Off";
|
||||
"lng_settings_color_emoji_about" = "Make replies to your messages stand out by adding custom patterns to them.";
|
||||
"lng_settings_color_emoji_about_channel" = "Select an icon to create a custom pattern for replies to your messages.";
|
||||
"lng_settings_color_subscribe" = "Subscribe to {link} to choose a custom color for your name.";
|
||||
"lng_settings_color_changed" = "Your name color has been updated!";
|
||||
"lng_settings_color_changed_channel" = "Your channel color has been updated!";
|
||||
"lng_settings_color_changed_profile" = "Your profile style has been updated!";
|
||||
"lng_settings_color_changed_profile_channel" = "Your channel profile style has been updated!";
|
||||
"lng_settings_color_apply" = "Apply Style";
|
||||
"lng_settings_color_profile_emoji" = "Add icons to Profile";
|
||||
"lng_settings_color_profile_emoji_channel" = "Profile Logo";
|
||||
"lng_settings_color_reset" = "Reset Profile Color";
|
||||
"lng_settings_color_profile_about" = "You can change the color of your name and customize replies to you. {link}";
|
||||
"lng_settings_color_profile_about_link" = "Change {emoji}";
|
||||
"lng_settings_color_choose_channel" = "Choose a color and a logo for your channel's profile";
|
||||
"lng_settings_color_choose_group" = "Choose a color and a logo for the group's profile";
|
||||
"lng_settings_color_group_boost_footer#one" = "The group has **{count}** boost. {link}";
|
||||
"lng_settings_color_group_boost_footer#other" = "The group has **{count}** boosts. {link}";
|
||||
"lng_settings_color_group_boost_footer_link" = "What are boosts?";
|
||||
|
||||
"lng_suggest_hide_new_title" = "Hide new chats?";
|
||||
"lng_suggest_hide_new_about" = "You are receiving lots of new chats from users who are not in your Contact List.\n\nDo you want to have such chats **automatically muted** and **archived**?";
|
||||
@@ -1612,6 +1632,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_delete_note" = "Delete Note";
|
||||
"lng_info_bio_label" = "Bio";
|
||||
"lng_info_link_label" = "Link";
|
||||
"lng_info_link_topic_label" = "This topic link will only work for group members";
|
||||
"lng_info_location_label" = "Location";
|
||||
"lng_info_about_label" = "Description";
|
||||
"lng_info_work_open" = "Open";
|
||||
@@ -1640,6 +1661,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_open_app_short" = "Open";
|
||||
"lng_profile_open_app_about" = "By launching this mini app, you agree to the {terms}.";
|
||||
"lng_profile_open_app_terms" = "Terms of Service for Mini Apps";
|
||||
"lng_profile_open_photo" = "Open Photo";
|
||||
"lng_profile_bot_permissions_title" = "Allow access to";
|
||||
"lng_profile_bot_emoji_status_access" = "Emoji Status";
|
||||
"lng_info_add_as_contact" = "Add to contacts";
|
||||
@@ -1662,6 +1684,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_changed_photo_title" = "Photo updated";
|
||||
"lng_profile_changed_photo_about" = "You can change it in {link}.";
|
||||
"lng_profile_changed_photo_link" = "Settings";
|
||||
|
||||
"lng_profile_action_short_message" = "Message";
|
||||
"lng_profile_action_short_mute" = "Mute";
|
||||
"lng_profile_action_short_unmute" = "Unmute";
|
||||
"lng_profile_action_short_call" = "Call";
|
||||
"lng_profile_action_short_discuss" = "Discuss";
|
||||
"lng_profile_action_short_gift" = "Gift";
|
||||
"lng_profile_action_short_join" = "Join";
|
||||
"lng_profile_action_short_report" = "Report";
|
||||
"lng_profile_action_short_leave" = "Leave";
|
||||
"lng_profile_action_short_more" = "More";
|
||||
"lng_profile_action_short_manage" = "Manage";
|
||||
|
||||
"lng_media_type_photos" = "Photos";
|
||||
"lng_media_type_gifs" = "GIFs";
|
||||
"lng_media_type_videos" = "Videos";
|
||||
@@ -2736,6 +2771,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_premium_summary_about_filter_tags" = "Display folder names for each chat in the chat list.";
|
||||
"lng_premium_summary_subtitle_todo_lists" = "Checklists";
|
||||
"lng_premium_summary_about_todo_lists" = "Plan, assign, and complete tasks - seamlessly and efficiently.";
|
||||
"lng_premium_summary_subtitle_peer_colors" = "Name and Profile Colors";
|
||||
"lng_premium_summary_about_peer_colors" = "Choose a color and logo for your profile and replies to your messages.";
|
||||
"lng_premium_summary_bottom_subtitle" = "About Telegram Premium";
|
||||
"lng_premium_summary_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
|
||||
"lng_premium_summary_button" = "Subscribe for {cost} per month";
|
||||
@@ -3345,6 +3382,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_feature_custom_emoji_pack" = "Custom Emoji Pack";
|
||||
"lng_feature_transcribe" = "Voice-to-Text Conversion";
|
||||
"lng_feature_autotranslate" = "Autotranslation of Messages";
|
||||
"lng_feature_profile_color_channel#one" = "**{count}** Color for Channel Cover";
|
||||
"lng_feature_profile_color_channel#other" = "**{count}** Colors for Channel Cover";
|
||||
"lng_feature_profile_color_group#one" = "**{count}** Color for Group Cover";
|
||||
"lng_feature_profile_color_group#other" = "**{count}** Colors for Group Cover";
|
||||
"lng_feature_profile_icon_channel" = "Custom Logo for Channel Cover";
|
||||
"lng_feature_profile_icon_group" = "Custom Logo for Group Cover";
|
||||
|
||||
"lng_edit_topics_enable" = "Enable Topics";
|
||||
"lng_edit_topics_about" = "The group chat will be divided into topics created by admins or users.";
|
||||
@@ -3615,6 +3658,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_stars_your_finished" = "none left";
|
||||
"lng_gift_stars_tabs_all" = "All Gifts";
|
||||
"lng_gift_stars_tabs_my" = "My Gifts";
|
||||
"lng_gift_stars_tabs_my_empty" = "You don't have any gifts you can use as a profile cover.";
|
||||
"lng_gift_stars_tabs_my_empty_next" = "Browse gifts available for purchase {emoji}";
|
||||
"lng_gift_stars_tabs_collectibles" = "Collectibles";
|
||||
"lng_gift_send_title" = "Send a Gift";
|
||||
"lng_gift_send_message" = "Enter Message";
|
||||
@@ -4536,6 +4581,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_message_tagged_with" = "Message tagged with {emoji}";
|
||||
"lng_tagged_view_saved" = "View";
|
||||
|
||||
"lng_add_channel_to_filter_selector" = "You can add a channel to your folder";
|
||||
"lng_add_group_to_filter_selector" = "You can add a group to your folder";
|
||||
|
||||
"lng_context_animated_emoji" = "This message contains emoji from **{name} pack**.";
|
||||
"lng_context_animated_emoji_many#one" = "This message contains emoji from **{count} pack**.";
|
||||
"lng_context_animated_emoji_many#other" = "This message contains emoji from **{count} packs**.";
|
||||
|
||||
@@ -45,6 +45,14 @@
|
||||
<file alias="photo_suggest_icon.tgs">../../animations/photo_suggest_icon.tgs</file>
|
||||
<file alias="toast/saved_messages.tgs">../../animations/toast/saved_messages.tgs</file>
|
||||
<file alias="toast/tagged.tgs">../../animations/toast/tagged.tgs</file>
|
||||
<file alias="my_gifts_empty.tgs">../../animations/my_gifts_empty.tgs</file>
|
||||
<file alias="toast/chats_filter_in.tgs">../../animations/toast/chats_filter_in.tgs</file>
|
||||
<file alias="rtmp.tgs">../../animations/rtmp.tgs</file>
|
||||
<file alias="show_or_premium_lastseen.tgs">../../animations/show_or_premium_lastseen.tgs</file>
|
||||
<file alias="show_or_premium_readtime.tgs">../../animations/show_or_premium_readtime.tgs</file>
|
||||
|
||||
<file alias="profile_muting.tgs">../../animations/profile/profile_muting.tgs</file>
|
||||
<file alias="profile_unmuting.tgs">../../animations/profile/profile_unmuting.tgs</file>
|
||||
|
||||
<file alias="dice_idle.tgs">../../animations/dice/dice_idle.tgs</file>
|
||||
<file alias="dart_idle.tgs">../../animations/dice/dart_idle.tgs</file>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="6.2.3.0" />
|
||||
Version="6.2.6.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 6,2,3,0
|
||||
PRODUCTVERSION 6,2,3,0
|
||||
FILEVERSION 6,2,6,0
|
||||
PRODUCTVERSION 6,2,6,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "6.2.3.0"
|
||||
VALUE "FileVersion", "6.2.6.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "6.2.3.0"
|
||||
VALUE "ProductVersion", "6.2.6.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 6,2,3,0
|
||||
PRODUCTVERSION 6,2,3,0
|
||||
FILEVERSION 6,2,6,0
|
||||
PRODUCTVERSION 6,2,6,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", "6.2.3.0"
|
||||
VALUE "FileVersion", "6.2.6.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2025"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "6.2.3.0"
|
||||
VALUE "ProductVersion", "6.2.6.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -9,7 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/color_int_conversion.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
@@ -20,8 +22,9 @@ constexpr auto kRequestEach = 3600 * crl::time(1000);
|
||||
|
||||
PeerColors::PeerColors(not_null<ApiWrap*> api)
|
||||
: _api(&api->instance())
|
||||
, _timer([=] { request(); }) {
|
||||
, _timer([=] { request(); requestProfile(); }) {
|
||||
request();
|
||||
requestProfile();
|
||||
_timer.callEach(kRequestEach);
|
||||
}
|
||||
|
||||
@@ -45,6 +48,24 @@ void PeerColors::request() {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void PeerColors::requestProfile() {
|
||||
if (_profileRequestId) {
|
||||
return;
|
||||
}
|
||||
_profileRequestId = _api.request(MTPhelp_GetPeerProfileColors(
|
||||
MTP_int(_profileHash)
|
||||
)).done([=](const MTPhelp_PeerColors &result) {
|
||||
_profileRequestId = 0;
|
||||
result.match([&](const MTPDhelp_peerColors &data) {
|
||||
_profileHash = data.vhash().v;
|
||||
applyProfile(data);
|
||||
}, [](const MTPDhelp_peerColorsNotModified &) {
|
||||
});
|
||||
}).fail([=] {
|
||||
_profileRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
std::vector<uint8> PeerColors::suggested() const {
|
||||
return _suggested.current();
|
||||
}
|
||||
@@ -76,21 +97,27 @@ const base::flat_map<uint8, int> &PeerColors::requiredLevelsChannel() const {
|
||||
return _requiredLevelsChannel;
|
||||
}
|
||||
|
||||
int PeerColors::requiredGroupLevelFor(PeerId channel, uint8 index) const {
|
||||
int PeerColors::requiredLevelFor(
|
||||
PeerId channel,
|
||||
uint8 index,
|
||||
bool isMegagroup,
|
||||
bool profile) const {
|
||||
if (Data::DecideColorIndex(channel) == index) {
|
||||
return 0;
|
||||
} else if (const auto i = _requiredLevelsGroup.find(index)
|
||||
; i != end(_requiredLevelsGroup)) {
|
||||
return i->second;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PeerColors::requiredChannelLevelFor(PeerId channel, uint8 index) const {
|
||||
if (Data::DecideColorIndex(channel) == index) {
|
||||
return 0;
|
||||
} else if (const auto i = _requiredLevelsChannel.find(index)
|
||||
; i != end(_requiredLevelsChannel)) {
|
||||
if (profile) {
|
||||
const auto it = _profileColors.find(index);
|
||||
if (it != end(_profileColors)) {
|
||||
return isMegagroup
|
||||
? it->second.requiredLevelsGroup
|
||||
: it->second.requiredLevelsChannel;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
const auto &levels = isMegagroup
|
||||
? _requiredLevelsGroup
|
||||
: _requiredLevelsChannel;
|
||||
if (const auto i = levels.find(index); i != end(levels)) {
|
||||
return i->second;
|
||||
}
|
||||
return 1;
|
||||
@@ -165,4 +192,87 @@ void PeerColors::apply(const MTPDhelp_peerColors &data) {
|
||||
_suggested = std::move(suggested);
|
||||
}
|
||||
|
||||
void PeerColors::applyProfile(const MTPDhelp_peerColors &data) {
|
||||
const auto parseColors = [](const MTPhelp_PeerColorSet &set) {
|
||||
const auto toUint = [](const MTPint &c) {
|
||||
return (uint32(1) << 24) | uint32(c.v);
|
||||
};
|
||||
return set.match([&](const MTPDhelp_peerColorSet &) {
|
||||
LOG(("API Error: peerColorSet in profile colors result!"));
|
||||
return Data::ColorProfileSet();
|
||||
}, [&](const MTPDhelp_peerColorProfileSet &data) {
|
||||
auto set = Data::ColorProfileSet();
|
||||
set.palette.reserve(data.vpalette_colors().v.size());
|
||||
set.bg.reserve(data.vbg_colors().v.size());
|
||||
set.story.reserve(data.vstory_colors().v.size());
|
||||
for (const auto &c : data.vpalette_colors().v) {
|
||||
set.palette.push_back(Ui::ColorFromSerialized(toUint(c)));
|
||||
}
|
||||
for (const auto &c : data.vbg_colors().v) {
|
||||
set.bg.push_back(Ui::ColorFromSerialized(toUint(c)));
|
||||
}
|
||||
for (const auto &c : data.vstory_colors().v) {
|
||||
set.story.push_back(Ui::ColorFromSerialized(toUint(c)));
|
||||
}
|
||||
return set;
|
||||
});
|
||||
};
|
||||
|
||||
auto suggested = std::vector<Data::ColorProfileData>();
|
||||
const auto &list = data.vcolors().v;
|
||||
suggested.reserve(list.size());
|
||||
for (const auto &color : list) {
|
||||
const auto &data = color.data();
|
||||
const auto colorIndexBare = data.vcolor_id().v;
|
||||
if (colorIndexBare < 0 || colorIndexBare >= Ui::kColorIndexCount) {
|
||||
LOG(("API Error: Bad color index: %1").arg(colorIndexBare));
|
||||
continue;
|
||||
}
|
||||
const auto colorIndex = uint8(colorIndexBare);
|
||||
auto result = ProfileColorOption();
|
||||
result.isHidden = data.is_hidden();
|
||||
if (const auto min = data.vgroup_min_level()) {
|
||||
result.requiredLevelsGroup = min->v;
|
||||
}
|
||||
if (const auto min = data.vchannel_min_level()) {
|
||||
result.requiredLevelsChannel = min->v;
|
||||
}
|
||||
if (const auto light = data.vcolors()) {
|
||||
result.data.light = parseColors(*light);
|
||||
}
|
||||
if (const auto dark = data.vdark_colors()) {
|
||||
result.data.dark = parseColors(*dark);
|
||||
}
|
||||
_profileColors[colorIndex] = std::move(result);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Data::ColorProfileSet> PeerColors::colorProfileFor(
|
||||
not_null<PeerData*> peer) const {
|
||||
if (const auto colorProfileIndex = peer->colorProfileIndex()) {
|
||||
return colorProfileFor(*colorProfileIndex);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<Data::ColorProfileSet> PeerColors::colorProfileFor(
|
||||
uint8 index) const {
|
||||
const auto i = _profileColors.find(index);
|
||||
if (i != end(_profileColors)) {
|
||||
return Window::Theme::IsNightMode()
|
||||
? i->second.data.dark
|
||||
: i->second.data.light;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<uint8> PeerColors::profileColorIndices() const {
|
||||
auto result = std::vector<uint8>();
|
||||
result.reserve(_profileColors.size());
|
||||
for (const auto &[index, option] : _profileColors) {
|
||||
result.push_back(index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "base/timer.h"
|
||||
#include "data/data_peer_colors.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
@@ -34,27 +35,45 @@ public:
|
||||
[[nodiscard]] auto requiredLevelsChannel() const
|
||||
-> const base::flat_map<uint8, int> &;
|
||||
|
||||
[[nodiscard]] int requiredGroupLevelFor(
|
||||
PeerId channel,
|
||||
uint8 index) const;
|
||||
[[nodiscard]] int requiredChannelLevelFor(
|
||||
[[nodiscard]] int requiredLevelFor(
|
||||
PeerId channel,
|
||||
uint8 index,
|
||||
bool isMegagroup,
|
||||
bool profile) const;
|
||||
|
||||
[[nodiscard]] std::optional<Data::ColorProfileSet> colorProfileFor(
|
||||
not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] std::optional<Data::ColorProfileSet> colorProfileFor(
|
||||
uint8 index) const;
|
||||
|
||||
[[nodiscard]] std::vector<uint8> profileColorIndices() const;
|
||||
|
||||
private:
|
||||
struct ProfileColorOption {
|
||||
Data::ColorProfileData data;
|
||||
int requiredLevelsChannel = 0;
|
||||
int requiredLevelsGroup = 0;
|
||||
bool isHidden = false;
|
||||
};
|
||||
|
||||
void request();
|
||||
void requestProfile();
|
||||
void apply(const MTPDhelp_peerColors &data);
|
||||
void applyProfile(const MTPDhelp_peerColors &data);
|
||||
|
||||
MTP::Sender _api;
|
||||
int32 _hash = 0;
|
||||
int32 _profileHash = 0;
|
||||
|
||||
mtpRequestId _requestId = 0;
|
||||
mtpRequestId _profileRequestId = 0;
|
||||
base::Timer _timer;
|
||||
rpl::variable<std::vector<uint8>> _suggested;
|
||||
base::flat_map<uint8, int> _requiredLevelsGroup;
|
||||
base::flat_map<uint8, int> _requiredLevelsChannel;
|
||||
rpl::event_stream<> _colorIndicesChanged;
|
||||
std::unique_ptr<Ui::ColorIndicesCompressed> _colorIndicesCurrent;
|
||||
base::flat_map<uint8, ProfileColorOption> _profileColors;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ Data::PremiumSubscriptionOption CreateSubscriptionOption(
|
||||
.costNoDiscount = Ui::FillAmountAndCurrency(
|
||||
monthlyAmount * months,
|
||||
currency),
|
||||
.costTotal = Ui::FillAmountAndCurrency(amount, currency),
|
||||
.costPerYear = Ui::FillAmountAndCurrency(
|
||||
amount / float64(months / 12.),
|
||||
currency),
|
||||
.botUrl = botUrl,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1216,6 +1216,10 @@ void ApiWrap::gotUserFull(
|
||||
void ApiWrap::requestPeerSettings(not_null<PeerData*> peer) {
|
||||
if (!_requestedPeerSettings.emplace(peer).second) {
|
||||
return;
|
||||
} else if (peer->isMonoforum()) {
|
||||
peer->setBarSettings(PeerBarSettings());
|
||||
_requestedPeerSettings.erase(peer);
|
||||
return;
|
||||
}
|
||||
request(MTPmessages_GetPeerSettings(
|
||||
peer->input
|
||||
@@ -1227,6 +1231,7 @@ void ApiWrap::requestPeerSettings(not_null<PeerData*> peer) {
|
||||
_requestedPeerSettings.erase(peer);
|
||||
});
|
||||
}).fail([=] {
|
||||
peer->setBarSettings(PeerBarSettings());
|
||||
_requestedPeerSettings.erase(peer);
|
||||
}).send();
|
||||
}
|
||||
@@ -1740,6 +1745,11 @@ void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_channelAmInRequests.remove(channel);
|
||||
applyUpdates(result);
|
||||
|
||||
session().data().addRecentJoinChat({
|
||||
.fromPeerId = channel->id,
|
||||
.joinedPeerId = channel->id,
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto &type = error.type();
|
||||
|
||||
|
||||
@@ -111,6 +111,10 @@ void ChatCreateDone(
|
||||
show,
|
||||
chat,
|
||||
CollectForbiddenUsers(&chat->session(), result));
|
||||
chat->owner().addRecentJoinChat({
|
||||
.fromPeerId = chat->id,
|
||||
.joinedPeerId = chat->id,
|
||||
});
|
||||
}
|
||||
};
|
||||
if (!success) {
|
||||
|
||||
@@ -537,7 +537,6 @@ changePhoneDescription: FlatLabel(defaultFlatLabel) {
|
||||
}
|
||||
changePhoneDescriptionPadding: margins(0px, 1px, 0px, 8px);
|
||||
changePhoneIconPadding: margins(0px, 39px, 0px, 5px);
|
||||
changePhoneIconSize: 120px;
|
||||
changePhoneLabel: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 275px;
|
||||
textFg: windowSubTextFg;
|
||||
@@ -546,6 +545,8 @@ changePhoneError: FlatLabel(changePhoneLabel) {
|
||||
textFg: boxTextFgError;
|
||||
}
|
||||
|
||||
normalBoxLottieSize: size(120px, 120px);
|
||||
|
||||
adminLogFilterUserpicLeft: 15px;
|
||||
adminLogFilterLittleSkip: 16px;
|
||||
adminLogFilterCheckbox: Checkbox(defaultBoxCheckbox) {
|
||||
|
||||
@@ -525,6 +525,14 @@ void EditCaptionBox::rebuildPreview() {
|
||||
_content->modifyRequests(
|
||||
) | rpl::start_to_stream(_photoEditorOpens, _content->lifetime());
|
||||
|
||||
_content->editCoverRequests() | rpl::start_with_next([=] {
|
||||
setupEditCoverHandler();
|
||||
}, _content->lifetime());
|
||||
|
||||
_content->clearCoverRequests() | rpl::start_with_next([=] {
|
||||
setupClearCoverHandler();
|
||||
}, _content->lifetime());
|
||||
|
||||
_content->heightValue(
|
||||
) | rpl::start_to_stream(_contentHeight, _content->lifetime());
|
||||
|
||||
@@ -740,6 +748,89 @@ void EditCaptionBox::setupPhotoEditorEventHandler() {
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void EditCaptionBox::setupEditCoverHandler() {
|
||||
if (_preparedList.files.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto &file = _preparedList.files.front();
|
||||
if (!file.isVideoFile()) {
|
||||
return;
|
||||
}
|
||||
const auto show = _controller->uiShow();
|
||||
const auto replace = [=](Ui::PreparedList list) {
|
||||
if (list.files.empty()) {
|
||||
return;
|
||||
}
|
||||
auto &entry = _preparedList.files.front();
|
||||
const auto video = entry.information
|
||||
? std::get_if<Ui::PreparedFileInformation::Video>(
|
||||
&entry.information->media)
|
||||
: nullptr;
|
||||
if (!video) {
|
||||
return;
|
||||
}
|
||||
auto old = std::shared_ptr<Ui::PreparedFile>(
|
||||
std::move(entry.videoCover));
|
||||
entry.videoCover = std::make_unique<Ui::PreparedFile>(
|
||||
std::move(list.files.front()));
|
||||
Editor::OpenWithPreparedFile(
|
||||
this,
|
||||
show,
|
||||
entry.videoCover.get(),
|
||||
st::sendMediaPreviewSize,
|
||||
crl::guard(this, [=](bool ok) {
|
||||
if (!ok) {
|
||||
_preparedList.files.front().videoCover = old
|
||||
? std::make_unique<Ui::PreparedFile>(
|
||||
std::move(*old))
|
||||
: nullptr;
|
||||
}
|
||||
rebuildPreview();
|
||||
}),
|
||||
video->thumbnail.size());
|
||||
};
|
||||
const auto checkResult = [=](const Ui::PreparedList &list) {
|
||||
if (list.files.empty()) {
|
||||
return true;
|
||||
}
|
||||
if (list.files.front().type != Ui::PreparedFile::Type::Photo) {
|
||||
show->showToast(tr::lng_choose_cover_bad(tr::now));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const auto callback = [=](FileDialog::OpenResult &&result) {
|
||||
const auto premium = show->session().premium();
|
||||
const auto showError = [=](tr::phrase<> t) {
|
||||
show->showToast(t(tr::now));
|
||||
};
|
||||
auto list = Storage::PreparedFileFromFilesDialog(
|
||||
std::move(result),
|
||||
checkResult,
|
||||
showError,
|
||||
st::sendMediaPreviewSize,
|
||||
premium);
|
||||
if (list) {
|
||||
replace(std::move(*list));
|
||||
}
|
||||
};
|
||||
|
||||
FileDialog::GetOpenPath(
|
||||
this,
|
||||
tr::lng_choose_cover(tr::now),
|
||||
FileDialog::ImagesFilter(),
|
||||
crl::guard(this, callback));
|
||||
}
|
||||
|
||||
void EditCaptionBox::setupClearCoverHandler() {
|
||||
if (_preparedList.files.empty()) {
|
||||
return;
|
||||
}
|
||||
auto &entry = _preparedList.files.front();
|
||||
entry.videoCover = nullptr;
|
||||
rebuildPreview();
|
||||
}
|
||||
|
||||
void EditCaptionBox::setupDragArea() {
|
||||
auto enterFilter = [=](not_null<const QMimeData*> data) {
|
||||
return !_isAllowedEditMedia
|
||||
|
||||
@@ -87,6 +87,8 @@ private:
|
||||
void rebuildPreview();
|
||||
void setupEditEventHandler();
|
||||
void setupPhotoEditorEventHandler();
|
||||
void setupEditCoverHandler();
|
||||
void setupClearCoverHandler();
|
||||
void setupField();
|
||||
void setupFieldAutocomplete();
|
||||
void setupControls();
|
||||
|
||||
@@ -16,11 +16,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_values.h" // Data::AmPremiumValue.
|
||||
#include "data/data_premium_limits.h"
|
||||
@@ -32,6 +37,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/chat/chats_filter_tag.h"
|
||||
#include "ui/controls/emoji_button_factory.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
#include "ui/effects/animation_value_f.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/panel_animation.h"
|
||||
@@ -54,6 +61,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info_userpic_builder.h"
|
||||
|
||||
namespace {
|
||||
@@ -357,6 +365,7 @@ void EditFilterBox(
|
||||
rpl::variable<TextWithEntities> title;
|
||||
rpl::variable<bool> staticTitle;
|
||||
rpl::variable<int> colorIndex;
|
||||
base::unique_qptr<ChatHelpers::TabbedPanel> emojiPanel;
|
||||
};
|
||||
const auto owner = &window->session().data();
|
||||
const auto state = box->lifetime().make_state<State>(State{
|
||||
@@ -423,7 +432,22 @@ void EditFilterBox(
|
||||
current.text,
|
||||
TextUtilities::ConvertEntitiesToTextTags(current.entities),
|
||||
}, Ui::InputField::HistoryAction::Clear);
|
||||
name->setMaxLength(kMaxFilterTitleLength);
|
||||
Ui::AddLengthLimitLabel(
|
||||
name,
|
||||
kMaxFilterTitleLength,
|
||||
Ui::LengthLimitLabelOptions{
|
||||
.customThreshold = 0,
|
||||
.customUpdatePosition = [=](QSize parent, QSize label) {
|
||||
return QPoint(
|
||||
parent.width()
|
||||
- st::windowFilterNameCharsLimitRightPosition.x()
|
||||
- label.width() / 2,
|
||||
st::windowFilterNameCharsLimitRightPosition.y());
|
||||
},
|
||||
.customCharactersCount = [=] {
|
||||
return Ui::ComputeFieldCharacterCount(name);
|
||||
},
|
||||
});
|
||||
|
||||
const auto nameEditing = box->lifetime().make_state<NameEditing>(
|
||||
NameEditing{ name });
|
||||
@@ -468,6 +492,47 @@ void EditFilterBox(
|
||||
nameEditing->custom = true;
|
||||
}, box->lifetime());
|
||||
|
||||
using Selector = ChatHelpers::TabbedSelector;
|
||||
state->emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
|
||||
box->getDelegate()->outerContainer(),
|
||||
window,
|
||||
object_ptr<Selector>(
|
||||
nullptr,
|
||||
window->uiShow(),
|
||||
Window::GifPauseReason::Layer,
|
||||
Selector::Mode::EmojiOnly));
|
||||
state->emojiPanel->setDesiredHeightValues(
|
||||
1.,
|
||||
st::emojiPanMinHeight / 2,
|
||||
st::emojiPanMinHeight);
|
||||
state->emojiPanel->hide();
|
||||
state->emojiPanel->selector()->setCurrentPeer(window->session().user());
|
||||
state->emojiPanel->selector()->emojiChosen(
|
||||
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
|
||||
Ui::InsertEmojiAtCursor(name->textCursor(), data.emoji);
|
||||
}, name->lifetime());
|
||||
state->emojiPanel->selector()->customEmojiChosen(
|
||||
) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
|
||||
const auto info = data.document->sticker();
|
||||
if (info
|
||||
&& info->setType == Data::StickersType::Emoji
|
||||
&& !window->session().premium()) {
|
||||
ShowPremiumPreviewBox(
|
||||
window,
|
||||
PremiumFeature::AnimatedEmoji);
|
||||
} else {
|
||||
Data::InsertCustomEmoji(name, data.document);
|
||||
}
|
||||
}, name->lifetime());
|
||||
|
||||
const auto emojiButton = Ui::AddEmojiToggleToField(
|
||||
name,
|
||||
box,
|
||||
window,
|
||||
state->emojiPanel.get(),
|
||||
st::windowFilterNameEmojiPosition);
|
||||
emojiButton->show();
|
||||
|
||||
name->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (!nameEditing->settingDefault) {
|
||||
@@ -741,7 +806,8 @@ void EditFilterBox(
|
||||
const auto staticTitle = !title.entities.isEmpty()
|
||||
&& state->staticTitle.current();
|
||||
const auto rules = data->current();
|
||||
if (title.empty()) {
|
||||
if (Ui::ComputeFieldCharacterCount(name) > kMaxFilterTitleLength
|
||||
|| title.empty()) {
|
||||
name->showError();
|
||||
box->scrollToY(0);
|
||||
return {};
|
||||
|
||||
@@ -466,8 +466,7 @@ void CreateModerateMessagesBox(
|
||||
inner->add(object_ptr<Ui::DividerLabel>(
|
||||
inner,
|
||||
std::move(label),
|
||||
st::defaultBoxDividerLabelPadding,
|
||||
RectPart::Top | RectPart::Bottom));
|
||||
st::defaultBoxDividerLabelPadding));
|
||||
|
||||
using Flag = ChatRestriction;
|
||||
using Flags = ChatRestrictions;
|
||||
|
||||
@@ -1070,6 +1070,10 @@ void AddParticipantsBoxController::Start(
|
||||
channel,
|
||||
params,
|
||||
ShowAtTheEndMsgId);
|
||||
channel->owner().addRecentJoinChat({
|
||||
.fromPeerId = channel->id,
|
||||
.joinedPeerId = channel->id,
|
||||
});
|
||||
}
|
||||
}, box->lifetime());
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/event_filter.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/star_gift_box.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_channel.h"
|
||||
@@ -36,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/dynamic_image.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/top_background_gradient.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_credits.h"
|
||||
#include "styles/style_premium.h"
|
||||
@@ -433,6 +433,7 @@ Ui::BoostCounters ParseBoostCounters(
|
||||
Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
|
||||
auto nameColorsByLevel = base::flat_map<int, int>();
|
||||
auto linkStylesByLevel = base::flat_map<int, int>();
|
||||
auto profileColorsByLevel = base::flat_map<int, int>();
|
||||
const auto group = channel->isMegagroup();
|
||||
const auto peerColors = &channel->session().api().peerColors();
|
||||
const auto &list = group
|
||||
@@ -445,6 +446,29 @@ Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
|
||||
}
|
||||
++linkStylesByLevel[level];
|
||||
}
|
||||
{
|
||||
const auto profileIndices = peerColors->profileColorIndices();
|
||||
auto lowestNonZeroLevel = std::numeric_limits<int>::max();
|
||||
auto levels = std::vector<int>();
|
||||
levels.reserve(profileIndices.size());
|
||||
|
||||
for (const auto index : profileIndices) {
|
||||
const auto level = peerColors->requiredLevelFor(
|
||||
channel->id,
|
||||
index,
|
||||
group,
|
||||
true);
|
||||
levels.push_back(level);
|
||||
if (level) {
|
||||
lowestNonZeroLevel = std::min(lowestNonZeroLevel, level);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto level : levels) {
|
||||
++profileColorsByLevel[std::max(level, lowestNonZeroLevel)];
|
||||
}
|
||||
}
|
||||
|
||||
const auto &themes = channel->owner().cloudThemes().chatThemes();
|
||||
if (themes.empty()) {
|
||||
channel->owner().cloudThemes().refreshChatThemes();
|
||||
@@ -453,7 +477,11 @@ Ui::BoostFeatures LookupBoostFeatures(not_null<ChannelData*> channel) {
|
||||
return Ui::BoostFeatures{
|
||||
.nameColorsByLevel = std::move(nameColorsByLevel),
|
||||
.linkStylesByLevel = std::move(linkStylesByLevel),
|
||||
.profileColorsByLevel = std::move(profileColorsByLevel),
|
||||
.linkLogoLevel = group ? 0 : levelLimits.channelBgIconLevelMin(),
|
||||
.profileIconLevel = group
|
||||
? levelLimits.groupProfileBgIconLevelMin()
|
||||
: levelLimits.channelProfileBgIconLevelMin(),
|
||||
.autotranslateLevel = group ? 0 : levelLimits.channelAutoTranslateLevelMin(),
|
||||
.transcribeLevel = group ? levelLimits.groupTranscribeLevelMin() : 0,
|
||||
.emojiPackLevel = group ? levelLimits.groupEmojiStickersLevelMin() : 0,
|
||||
@@ -895,9 +923,9 @@ public:
|
||||
auto p = QPainter(&_backgroundCache);
|
||||
p.setClipRect(inner);
|
||||
const auto skip = inner.width() / 3;
|
||||
Ui::PaintPoints(
|
||||
Ui::PaintBgPoints(
|
||||
p,
|
||||
Ui::PatternPointsSmall(),
|
||||
Ui::PatternBgPointsSmall(),
|
||||
_patternCache,
|
||||
_patternEmoji.get(),
|
||||
*_unique,
|
||||
|
||||
@@ -135,6 +135,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
||||
return tr::lng_premium_summary_subtitle_effects();
|
||||
case PremiumFeature::TodoLists:
|
||||
return tr::lng_premium_summary_subtitle_todo_lists();
|
||||
case PremiumFeature::PeerColors:
|
||||
return tr::lng_premium_summary_subtitle_peer_colors();
|
||||
|
||||
case PremiumFeature::BusinessLocation:
|
||||
return tr::lng_business_subtitle_location();
|
||||
@@ -202,6 +204,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
||||
return tr::lng_premium_summary_about_effects();
|
||||
case PremiumFeature::TodoLists:
|
||||
return tr::lng_premium_summary_about_todo_lists();
|
||||
case PremiumFeature::PeerColors:
|
||||
return tr::lng_premium_summary_about_peer_colors();
|
||||
|
||||
case PremiumFeature::BusinessLocation:
|
||||
return tr::lng_business_about_location();
|
||||
@@ -543,6 +547,7 @@ struct VideoPreviewDocument {
|
||||
case PremiumFeature::MessagePrivacy: return "message_privacy";
|
||||
case PremiumFeature::Effects: return "effects";
|
||||
case PremiumFeature::TodoLists: return "todo";
|
||||
case PremiumFeature::PeerColors: return "peer_colors";
|
||||
|
||||
case PremiumFeature::BusinessLocation: return "business_location";
|
||||
case PremiumFeature::BusinessHours: return "business_hours";
|
||||
|
||||
@@ -73,6 +73,7 @@ enum class PremiumFeature {
|
||||
Effects,
|
||||
FilterTags,
|
||||
TodoLists,
|
||||
PeerColors,
|
||||
|
||||
// Business features.
|
||||
BusinessLocation,
|
||||
|
||||
@@ -147,8 +147,7 @@ void ShowReportMessageBox(
|
||||
auto label = object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
tr::lng_report_details_message_about(),
|
||||
st::boxDividerLabel);
|
||||
label->setTextColorOverride(st->dividerFg->c);
|
||||
st->divider.label);
|
||||
using namespace Ui;
|
||||
const auto widget = container->add(
|
||||
object_ptr<PaddingWrap<>>(
|
||||
@@ -159,7 +158,7 @@ void ShowReportMessageBox(
|
||||
= CreateChild<BoxContentDivider>(
|
||||
widget,
|
||||
st::boxDividerHeight,
|
||||
st->dividerBg,
|
||||
st->divider.bar,
|
||||
RectPart::Top | RectPart::Bottom);
|
||||
background->lower();
|
||||
widget->sizeValue(
|
||||
|
||||
@@ -1734,7 +1734,8 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
||||
result,
|
||||
msgIds);
|
||||
const auto showRecentForwardsToSelf = result.size() == 1
|
||||
&& result.front()->peer()->isSelf();
|
||||
&& result.front()->peer()->isSelf()
|
||||
&& history->owner().session().premium();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
for (const auto thread : result) {
|
||||
if (!comment.text.isEmpty()) {
|
||||
|
||||
@@ -91,6 +91,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/top_background_gradient.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
@@ -571,61 +572,6 @@ auto GenerateGiftMedia(
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] QImage CreateGradient(
|
||||
QSize size,
|
||||
const Data::UniqueGift &gift) {
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(ratio);
|
||||
|
||||
auto p = QPainter(&result);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
auto gradient = QRadialGradient(
|
||||
QRect(QPoint(), size).center(),
|
||||
size.height() / 2);
|
||||
gradient.setStops({
|
||||
{ 0., gift.backdrop.centerColor },
|
||||
{ 1., gift.backdrop.edgeColor },
|
||||
});
|
||||
p.setBrush(gradient);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawRect(QRect(QPoint(), size));
|
||||
p.end();
|
||||
|
||||
const auto mask = Images::CornersMask(st::boxRadius);
|
||||
return Images::Round(std::move(result), mask, RectPart::FullTop);
|
||||
}
|
||||
|
||||
void PrepareImage(
|
||||
QImage &image,
|
||||
not_null<Text::CustomEmoji*> emoji,
|
||||
const PatternPoint &point,
|
||||
const Data::UniqueGift &gift) {
|
||||
if (!image.isNull() || !emoji->ready()) {
|
||||
return;
|
||||
}
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto size = Emoji::GetSizeNormal() / ratio;
|
||||
image = QImage(
|
||||
2 * QSize(size, size) * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
image.setDevicePixelRatio(ratio);
|
||||
image.fill(Qt::transparent);
|
||||
auto p = QPainter(&image);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setOpacity(point.opacity);
|
||||
if (point.scale < 1.) {
|
||||
p.translate(size, size);
|
||||
p.scale(point.scale, point.scale);
|
||||
p.translate(-size, -size);
|
||||
}
|
||||
const auto shift = (2 * size - (Emoji::GetSizeLarge() / ratio)) / 2;
|
||||
emoji->paint(p, {
|
||||
.textColor = gift.backdrop.patternColor,
|
||||
.position = QPoint(shift, shift),
|
||||
});
|
||||
}
|
||||
|
||||
PreviewWrap::PreviewWrap(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<PeerData*> recipient,
|
||||
@@ -2493,6 +2439,30 @@ void SendGiftBox(
|
||||
const auto premiumNeeded = star && star->info.requirePremium;
|
||||
if (premiumNeeded && !peer->session().premium()) {
|
||||
Settings::ShowPremiumGiftPremium(window, star->info);
|
||||
} else if (unique && star->resale) {
|
||||
window->show(Box(
|
||||
Settings::GlobalStarGiftBox,
|
||||
window->uiShow(),
|
||||
star->info,
|
||||
Settings::StarGiftResaleInfo{
|
||||
.recipientId = peer->id,
|
||||
.forceTon = star->forceTon,
|
||||
},
|
||||
Settings::CreditsEntryBoxStyleOverrides()));
|
||||
} else if (star && star->resale) {
|
||||
const auto id = star->info.id;
|
||||
if (state->resaleRequestingId == id) {
|
||||
return;
|
||||
}
|
||||
state->resaleRequestingId = id;
|
||||
state->resaleLifetime = ShowStarGiftResale(
|
||||
window,
|
||||
peer,
|
||||
id,
|
||||
star->info.resellTitle,
|
||||
[=] { state->resaleRequestingId = 0; });
|
||||
} else if (star && IsSoldOut(star->info)) {
|
||||
window->show(Box(SoldOutBox, window, *star));
|
||||
} else if (star
|
||||
&& star->info.lockedUntilDate
|
||||
&& star->info.lockedUntilDate > base::unixtime::now()) {
|
||||
@@ -2549,30 +2519,6 @@ void SendGiftBox(
|
||||
Api::InputSavedStarGiftId(savedId, unique),
|
||||
peer->input),
|
||||
formReady);
|
||||
} else if (unique && star->resale) {
|
||||
window->show(Box(
|
||||
Settings::GlobalStarGiftBox,
|
||||
window->uiShow(),
|
||||
star->info,
|
||||
Settings::StarGiftResaleInfo{
|
||||
.recipientId = peer->id,
|
||||
.forceTon = star->forceTon,
|
||||
},
|
||||
Settings::CreditsEntryBoxStyleOverrides()));
|
||||
} else if (star && star->resale) {
|
||||
const auto id = star->info.id;
|
||||
if (state->resaleRequestingId == id) {
|
||||
return;
|
||||
}
|
||||
state->resaleRequestingId = id;
|
||||
state->resaleLifetime = ShowStarGiftResale(
|
||||
window,
|
||||
peer,
|
||||
id,
|
||||
star->info.resellTitle,
|
||||
[=] { state->resaleRequestingId = 0; });
|
||||
} else if (star && IsSoldOut(star->info)) {
|
||||
window->show(Box(SoldOutBox, window, *star));
|
||||
} else if (star
|
||||
&& star->info.perUserTotal
|
||||
&& !star->info.perUserRemains) {
|
||||
@@ -3910,13 +3856,15 @@ void AddUniqueGiftCover(
|
||||
const auto pointsHeight = st::uniqueGiftSubtitleTop;
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
if (gift.gradient.size() != cover->size() * ratio) {
|
||||
gift.gradient = CreateGradient(cover->size(), *gift.gift);
|
||||
gift.gradient = Ui::CreateTopBgGradient(
|
||||
cover->size(),
|
||||
*gift.gift);
|
||||
}
|
||||
p.drawImage(0, 0, gift.gradient);
|
||||
|
||||
PaintPoints(
|
||||
Ui::PaintBgPoints(
|
||||
p,
|
||||
PatternPoints(),
|
||||
Ui::PatternBgPoints(),
|
||||
gift.emojis,
|
||||
gift.emoji.get(),
|
||||
*gift.gift,
|
||||
@@ -4021,13 +3969,15 @@ void AddWearGiftCover(
|
||||
const auto pointsHeight = st::uniqueGiftSubtitleTop;
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
if (state->gradient.size() != cover->size() * ratio) {
|
||||
state->gradient = CreateGradient(cover->size(), state->gift);
|
||||
state->gradient = Ui::CreateTopBgGradient(
|
||||
cover->size(),
|
||||
state->gift);
|
||||
}
|
||||
p.drawImage(0, 0, state->gradient);
|
||||
|
||||
PaintPoints(
|
||||
Ui::PaintBgPoints(
|
||||
p,
|
||||
PatternPoints(),
|
||||
Ui::PatternBgPoints(),
|
||||
state->emojis,
|
||||
state->emoji.get(),
|
||||
state->gift,
|
||||
@@ -5060,119 +5010,11 @@ void UpgradeBox(
|
||||
AddUniqueCloseButton(box, {});
|
||||
}
|
||||
|
||||
const std::vector<PatternPoint> &PatternPoints() {
|
||||
static const auto kSmall = 0.7;
|
||||
static const auto kFaded = 0.2;
|
||||
static const auto kLarge = 0.85;
|
||||
static const auto kOpaque = 0.3;
|
||||
static const auto result = std::vector<PatternPoint>{
|
||||
{ { 0.5, 0.066 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.177, 0.168 }, kSmall, kFaded },
|
||||
{ { 0.822, 0.168 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.37, 0.168 }, kLarge, kOpaque },
|
||||
{ { 0.63, 0.168 }, kLarge, kOpaque },
|
||||
|
||||
{ { 0.277, 0.308 }, kSmall, kOpaque },
|
||||
{ { 0.723, 0.308 }, kSmall, kOpaque },
|
||||
|
||||
{ { 0.13, 0.42 }, kSmall, kFaded },
|
||||
{ { 0.87, 0.42 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.27, 0.533 }, kLarge, kOpaque },
|
||||
{ { 0.73, 0.533 }, kLarge, kOpaque },
|
||||
|
||||
{ { 0.2, 0.73 }, kSmall, kFaded },
|
||||
{ { 0.8, 0.73 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.302, 0.825 }, kLarge, kOpaque },
|
||||
{ { 0.698, 0.825 }, kLarge, kOpaque },
|
||||
|
||||
{ { 0.5, 0.876 }, kLarge, kFaded },
|
||||
|
||||
{ { 0.144, 0.936 }, kSmall, kFaded },
|
||||
{ { 0.856, 0.936 }, kSmall, kFaded },
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<PatternPoint> &PatternPointsSmall() {
|
||||
static const auto kSmall = 0.45;
|
||||
static const auto kFaded = 0.2;
|
||||
static const auto kLarge = 0.55;
|
||||
static const auto kOpaque = 0.3;
|
||||
static const auto result = std::vector<PatternPoint>{
|
||||
{ { 0.5, 0.066 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.177, 0.168 }, kSmall, kFaded },
|
||||
{ { 0.822, 0.168 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.37, 0.168 }, kLarge, kOpaque },
|
||||
{ { 0.63, 0.168 }, kLarge, kOpaque },
|
||||
|
||||
{ { 0.277, 0.308 }, kSmall, kOpaque },
|
||||
{ { 0.723, 0.308 }, kSmall, kOpaque },
|
||||
|
||||
{ { 0.13, 0.42 }, kSmall, kFaded },
|
||||
{ { 0.87, 0.42 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.27, 0.533 }, kLarge, kOpaque },
|
||||
{ { 0.73, 0.533 }, kLarge, kOpaque },
|
||||
|
||||
{ { 0.2, 0.73 }, kSmall, kFaded },
|
||||
{ { 0.8, 0.73 }, kSmall, kFaded },
|
||||
|
||||
{ { 0.302, 0.825 }, kLarge, kOpaque },
|
||||
{ { 0.698, 0.825 }, kLarge, kOpaque },
|
||||
|
||||
{ { 0.5, 0.876 }, kLarge, kFaded },
|
||||
|
||||
{ { 0.144, 0.936 }, kSmall, kFaded },
|
||||
{ { 0.856, 0.936 }, kSmall, kFaded },
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
void PaintPoints(
|
||||
QPainter &p,
|
||||
const std::vector<PatternPoint> &points,
|
||||
base::flat_map<float64, QImage> &cache,
|
||||
not_null<Text::CustomEmoji*> emoji,
|
||||
const Data::UniqueGift &gift,
|
||||
const QRect &rect,
|
||||
float64 shown) {
|
||||
const auto origin = rect.topLeft();
|
||||
const auto width = rect.width();
|
||||
const auto height = rect.height();
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto paintPoint = [&](const PatternPoint &point) {
|
||||
const auto key = (1. + point.opacity) * 10. + point.scale;
|
||||
auto &image = cache[key];
|
||||
PrepareImage(image, emoji, point, gift);
|
||||
if (!image.isNull()) {
|
||||
const auto position = origin + QPoint(
|
||||
int(point.position.x() * width),
|
||||
int(point.position.y() * height));
|
||||
if (shown < 1.) {
|
||||
p.save();
|
||||
p.translate(position);
|
||||
p.scale(shown, shown);
|
||||
p.translate(-position);
|
||||
}
|
||||
const auto size = image.size() / ratio;
|
||||
p.drawImage(
|
||||
position - QPoint(size.width() / 2, size.height() / 2),
|
||||
image);
|
||||
if (shown < 1.) {
|
||||
p.restore();
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const auto &point : points) {
|
||||
paintPoint(point);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowStarGiftUpgradeBox(StarGiftUpgradeArgs &&args) {
|
||||
const auto weak = base::make_weak(args.controller);
|
||||
|
||||
@@ -87,23 +87,6 @@ void ShowUniqueGiftSellBox(
|
||||
|
||||
void GiftReleasedByHandler(not_null<PeerData*> peer);
|
||||
|
||||
struct PatternPoint {
|
||||
QPointF position;
|
||||
float64 scale = 1.;
|
||||
float64 opacity = 1.;
|
||||
};
|
||||
[[nodiscard]] const std::vector<PatternPoint> &PatternPoints();
|
||||
[[nodiscard]] const std::vector<PatternPoint> &PatternPointsSmall();
|
||||
|
||||
void PaintPoints(
|
||||
QPainter &p,
|
||||
const std::vector<PatternPoint> &points,
|
||||
base::flat_map<float64, QImage> &cache,
|
||||
not_null<Text::CustomEmoji*> emoji,
|
||||
const Data::UniqueGift &gift,
|
||||
const QRect &rect,
|
||||
float64 shown = 1.);
|
||||
|
||||
struct StarGiftUpgradeArgs {
|
||||
not_null<Window::SessionController*> controller;
|
||||
base::required<uint64> stargiftId;
|
||||
|
||||
@@ -624,11 +624,12 @@ groupCallMenuCover: ShortInfoCover(shortInfoCover) {
|
||||
namePosition: point(17px, 28px);
|
||||
statusPosition: point(17px, 8px);
|
||||
}
|
||||
groupCallTextPalette: TextPalette(defaultTextPalette) {
|
||||
linkFg: groupCallActiveFg;
|
||||
}
|
||||
groupCallMenuAbout: FlatLabel(defaultFlatLabel) {
|
||||
textFg: groupCallMemberNotJoinedStatus;
|
||||
palette: TextPalette(defaultTextPalette) {
|
||||
linkFg: groupCallActiveFg;
|
||||
}
|
||||
palette: groupCallTextPalette;
|
||||
minWidth: 200px;
|
||||
maxHeight: 92px;
|
||||
}
|
||||
@@ -1082,6 +1083,19 @@ groupCallBox: Box(defaultBox) {
|
||||
groupCallLayerBox: Box(groupCallBox) {
|
||||
buttonPadding: margins(8px, 8px, 8px, 8px);
|
||||
}
|
||||
groupCallDividerBar: DividerBar {
|
||||
bg: groupCallBg;
|
||||
top: icon {{ "box_divider_top", groupCallMemberNotJoinedStatus }};
|
||||
bottom: icon {{ "box_divider_bottom", groupCallMemberNotJoinedStatus }};
|
||||
}
|
||||
groupCallDividerLabel: DividerLabel {
|
||||
bar: groupCallDividerBar;
|
||||
label: FlatLabel(boxDividerLabel) {
|
||||
textFg: groupCallVideoSubTextFg;
|
||||
palette: groupCallTextPalette;
|
||||
}
|
||||
}
|
||||
|
||||
groupCallLevelMeter: LevelMeter(defaultLevelMeter) {
|
||||
height: 18px;
|
||||
lineWidth: 3px;
|
||||
|
||||
@@ -46,13 +46,9 @@ class Panel::Incoming::RendererGL final : public Ui::GL::Renderer {
|
||||
public:
|
||||
explicit RendererGL(not_null<Incoming*> owner);
|
||||
|
||||
void init(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions &f) override;
|
||||
void init(QOpenGLFunctions &f) override;
|
||||
|
||||
void deinit(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions *f) override;
|
||||
void deinit(QOpenGLFunctions *f) override;
|
||||
|
||||
void paint(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
@@ -100,7 +96,7 @@ public:
|
||||
explicit RendererSW(not_null<Incoming*> owner);
|
||||
|
||||
void paintFallback(
|
||||
Painter &&p,
|
||||
Painter &p,
|
||||
const QRegion &clip,
|
||||
Ui::GL::Backend backend) override;
|
||||
|
||||
@@ -123,9 +119,7 @@ Panel::Incoming::RendererGL::RendererGL(not_null<Incoming*> owner)
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void Panel::Incoming::RendererGL::init(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions &f) {
|
||||
void Panel::Incoming::RendererGL::init(QOpenGLFunctions &f) {
|
||||
constexpr auto kQuads = 2;
|
||||
constexpr auto kQuadVertices = kQuads * 4;
|
||||
constexpr auto kQuadValues = kQuadVertices * 4;
|
||||
@@ -168,9 +162,7 @@ void Panel::Incoming::RendererGL::init(
|
||||
}));
|
||||
}
|
||||
|
||||
void Panel::Incoming::RendererGL::deinit(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions *f) {
|
||||
void Panel::Incoming::RendererGL::deinit(QOpenGLFunctions *f) {
|
||||
_textures.destroy(f);
|
||||
_imageProgram = std::nullopt;
|
||||
_texturedVertexShader = nullptr;
|
||||
@@ -437,7 +429,7 @@ Panel::Incoming::RendererSW::RendererSW(not_null<Incoming*> owner)
|
||||
}
|
||||
|
||||
void Panel::Incoming::RendererSW::paintFallback(
|
||||
Painter &&p,
|
||||
Painter &p,
|
||||
const QRegion &clip,
|
||||
Ui::GL::Backend backend) {
|
||||
const auto markGuard = gsl::finally([&] {
|
||||
|
||||
@@ -2483,7 +2483,8 @@ void Panel::updateButtonsGeometry() {
|
||||
}
|
||||
|
||||
const auto wideMenuShown = _call->canManage()
|
||||
|| _call->showChooseJoinAs();
|
||||
|| _call->showChooseJoinAs()
|
||||
|| (!rtmp && messagesEnabled); // Screen share there.
|
||||
toggle(_settings, !hidden && !wideMenuShown);
|
||||
toggle(_wideMenu, !hidden && wideMenuShown);
|
||||
|
||||
|
||||
@@ -13,8 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "lottie/lottie_icon.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
@@ -48,6 +50,21 @@ void StartWithBox(
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
|
||||
{
|
||||
auto icon = Settings::CreateLottieIcon(
|
||||
box->verticalLayout(),
|
||||
{
|
||||
.name = u"rtmp"_q,
|
||||
.sizeOverride = st::normalBoxLottieSize,
|
||||
},
|
||||
{});
|
||||
box->verticalLayout()->add(std::move(icon.widget), {}, style::al_top);
|
||||
box->setShowFinishedCallback([animate = icon.animate] {
|
||||
animate(anim::repeat::loop);
|
||||
});
|
||||
Ui::AddSkip(box->verticalLayout());
|
||||
}
|
||||
|
||||
StartRtmpProcess::FillRtmpRows(
|
||||
box->verticalLayout(),
|
||||
true,
|
||||
|
||||
@@ -285,7 +285,7 @@ void SettingsBox(
|
||||
layout->add(object_ptr<Ui::BoxContentDivider>(
|
||||
layout,
|
||||
st::boxDividerHeight,
|
||||
st::groupCallDividerBg));
|
||||
st::groupCallDividerBar));
|
||||
};
|
||||
|
||||
if (addCheck || addMessages) {
|
||||
|
||||
@@ -312,9 +312,7 @@ Viewport::RendererGL::RendererGL(not_null<Viewport*> owner)
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void Viewport::RendererGL::init(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions &f) {
|
||||
void Viewport::RendererGL::init(QOpenGLFunctions &f) {
|
||||
_frameBuffer.emplace();
|
||||
_frameBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||
_frameBuffer->create();
|
||||
@@ -389,9 +387,7 @@ void Viewport::RendererGL::ensureARGB32Program() {
|
||||
}));
|
||||
}
|
||||
|
||||
void Viewport::RendererGL::deinit(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions *f) {
|
||||
void Viewport::RendererGL::deinit(QOpenGLFunctions *f) {
|
||||
_frameBuffer = std::nullopt;
|
||||
_frameVertexShader = nullptr;
|
||||
_imageProgram = std::nullopt;
|
||||
|
||||
@@ -28,13 +28,9 @@ class Viewport::RendererGL final : public Ui::GL::Renderer {
|
||||
public:
|
||||
explicit RendererGL(not_null<Viewport*> owner);
|
||||
|
||||
void init(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions &f) override;
|
||||
void init(QOpenGLFunctions &f) override;
|
||||
|
||||
void deinit(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions *f) override;
|
||||
void deinit(QOpenGLFunctions *f) override;
|
||||
|
||||
void paint(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
|
||||
@@ -37,7 +37,7 @@ Viewport::RendererSW::RendererSW(not_null<Viewport*> owner)
|
||||
}
|
||||
|
||||
void Viewport::RendererSW::paintFallback(
|
||||
Painter &&p,
|
||||
Painter &p,
|
||||
const QRegion &clip,
|
||||
Ui::GL::Backend backend) {
|
||||
auto bg = clip;
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
explicit RendererSW(not_null<Viewport*> owner);
|
||||
|
||||
void paintFallback(
|
||||
Painter &&p,
|
||||
Painter &p,
|
||||
const QRegion &clip,
|
||||
Ui::GL::Backend backend) override;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "calls/group/calls_volume_item.h"
|
||||
|
||||
#include "calls/group/calls_group_common.h"
|
||||
#include "ui/color_int_conversion.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
#include "ui/effects/cross_line.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
@@ -254,17 +255,11 @@ void MenuVolumeItem::setSliderVolume(int volume) {
|
||||
|
||||
void MenuVolumeItem::updateSliderColor(float64 value) {
|
||||
value = std::clamp(value, 0., 1.);
|
||||
const auto color = [](int rgb) {
|
||||
return QColor(
|
||||
int((rgb & 0xFF0000) >> 16),
|
||||
int((rgb & 0x00FF00) >> 8),
|
||||
int(rgb & 0x0000FF));
|
||||
};
|
||||
const auto colors = std::array<QColor, 4>{ {
|
||||
color(0xF66464),
|
||||
color(0xD0B738),
|
||||
color(0x24CD80),
|
||||
color(0x3BBCEC),
|
||||
Ui::ColorFromSerialized(0xF66464),
|
||||
Ui::ColorFromSerialized(0xD0B738),
|
||||
Ui::ColorFromSerialized(0x24CD80),
|
||||
Ui::ColorFromSerialized(0x3BBCEC),
|
||||
} };
|
||||
_slider->setActiveFgOverride((value < 0.25)
|
||||
? anim::color(colors[0], colors[1], value / 0.25)
|
||||
|
||||
@@ -213,7 +213,10 @@ Switcher::Switcher(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
rpl::producer<bool> &&toggled)
|
||||
: RpWidget(parent)
|
||||
, _background(this, st::groupCallRecordingInfoHeight, st::groupCallBg)
|
||||
, _background(
|
||||
this,
|
||||
st::groupCallRecordingInfoHeight,
|
||||
st::groupCallDividerBar)
|
||||
, _audio(this)
|
||||
, _video(this) {
|
||||
_audio->prepareAudio();
|
||||
|
||||
@@ -225,8 +225,7 @@ ReportBox {
|
||||
noIconButton: SettingsButton;
|
||||
label: FlatLabel;
|
||||
field: InputField;
|
||||
dividerBg: color;
|
||||
dividerFg: color;
|
||||
divider: DividerLabel;
|
||||
spam: icon;
|
||||
fake: icon;
|
||||
violence: icon;
|
||||
@@ -824,6 +823,29 @@ selfForwardsTaggerToast: Toast(defaultToast) {
|
||||
padding: margins(54px, 12px, 19px, 12px);
|
||||
iconPosition: point(15px, 6px);
|
||||
}
|
||||
joinChatAddToFilterToast: Toast(defaultToast) {
|
||||
minWidth: 160px;
|
||||
maxWidth: 380px;
|
||||
radius: 9px;
|
||||
padding: margins(54px, 12px, 44px, 12px);
|
||||
iconPosition: point(15px, 6px);
|
||||
}
|
||||
joinChatAddToFilterToastButton: IconButton(defaultIconButton) {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
icon: icon{
|
||||
{ "chat/reactions_round_small", windowBgRipple },
|
||||
{ "chat/reactions_expand_panel", windowSubTextFg },
|
||||
};
|
||||
iconOver: icon{
|
||||
{ "chat/reactions_round_small", windowBgRipple },
|
||||
{ "chat/reactions_expand_panel", windowSubTextFg },
|
||||
};
|
||||
rippleAreaPosition: point(10px, 10px);
|
||||
rippleAreaSize: 20px;
|
||||
ripple: universalRippleAnimation;
|
||||
}
|
||||
|
||||
choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }};
|
||||
choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }};
|
||||
@@ -1447,8 +1469,7 @@ defaultReportBox: ReportBox {
|
||||
}
|
||||
label: boxLabel;
|
||||
field: newGroupDescription;
|
||||
dividerBg: boxDividerBg;
|
||||
dividerFg: windowSubTextFg;
|
||||
divider: defaultDividerLabel;
|
||||
spam: menuIconDelete;
|
||||
fake: menuIconFake;
|
||||
violence: menuIconViolence;
|
||||
|
||||
@@ -1426,10 +1426,7 @@ void FrozenInfoBox(
|
||||
content,
|
||||
{
|
||||
.name = u"media_forbidden"_q,
|
||||
.sizeOverride = {
|
||||
st::changePhoneIconSize,
|
||||
st::changePhoneIconSize,
|
||||
},
|
||||
.sizeOverride = st::normalBoxLottieSize,
|
||||
},
|
||||
st::settingLocalPasscodeIconPadding);
|
||||
content->add(std::move(icon.widget));
|
||||
|
||||
@@ -68,6 +68,7 @@ enum class StickerLottieSize : uint8 {
|
||||
EmojiInteractionReserved7,
|
||||
ChatIntroHelloSticker,
|
||||
StickerEmojiSize,
|
||||
PinnedProfileUniqueGiftSize,
|
||||
};
|
||||
[[nodiscard]] uint8 LottieCacheKeyShift(
|
||||
uint8 replacementsTag,
|
||||
|
||||
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_download_manager.h"
|
||||
#include "base/battery_saving.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "base/invoke_queued.h"
|
||||
#include "base/concurrent_timer.h"
|
||||
#include "base/options.h"
|
||||
#include "base/qt_signal_producer.h"
|
||||
@@ -85,6 +86,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/qthelp_regex.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "ui/accessible/ui_accessible_factory.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/controls/location_picker.h"
|
||||
#include "styles/style_window.h"
|
||||
@@ -103,7 +105,6 @@ namespace {
|
||||
constexpr auto kQuitPreventTimeoutMs = crl::time(1500);
|
||||
constexpr auto kAutoLockTimeoutLateMs = crl::time(3000);
|
||||
constexpr auto kClearEmojiImageSourceTimeout = 10 * crl::time(1000);
|
||||
constexpr auto kFileOpenTimeoutMs = crl::time(1000);
|
||||
|
||||
LaunchState GlobalLaunchState/* = LaunchState::Running*/;
|
||||
|
||||
@@ -168,8 +169,7 @@ Application::Application()
|
||||
, _langCloudManager(std::make_unique<Lang::CloudManager>(langpack()))
|
||||
, _emojiKeywords(std::make_unique<ChatHelpers::EmojiKeywords>())
|
||||
, _tray(std::make_unique<Tray>())
|
||||
, _autoLockTimer([=] { checkAutoLock(); })
|
||||
, _fileOpenTimer([=] { checkFileOpen(); }) {
|
||||
, _autoLockTimer([=] { checkAutoLock(); }) {
|
||||
Ui::Integration::Set(&_private->uiIntegration);
|
||||
|
||||
_platformIntegration->init();
|
||||
@@ -287,6 +287,7 @@ void Application::run() {
|
||||
QCoreApplication::instance()->installTranslator(_translator.get());
|
||||
|
||||
style::StartManager(cScale());
|
||||
Ui::Accessible::Init();
|
||||
Ui::InitTextOptions();
|
||||
Ui::StartCachedCorners();
|
||||
Ui::Emoji::Init();
|
||||
@@ -692,24 +693,26 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
|
||||
|
||||
case QEvent::FileOpen: {
|
||||
if (object == QCoreApplication::instance()) {
|
||||
const auto event = static_cast<QFileOpenEvent*>(e);
|
||||
if (const auto file = event->file(); !file.isEmpty()) {
|
||||
_filesToOpen.append(file);
|
||||
_fileOpenTimer.callOnce(kFileOpenTimeoutMs);
|
||||
} else if (event->url().scheme() == u"tg"_q
|
||||
|| event->url().scheme() == u"tonsite"_q) {
|
||||
const auto url = QString::fromUtf8(
|
||||
event->url().toEncoded().trimmed());
|
||||
cSetStartUrl(url.mid(0, 8192));
|
||||
checkStartUrl();
|
||||
if (_lastActivePrimaryWindow
|
||||
&& StartUrlRequiresActivate(url)) {
|
||||
_lastActivePrimaryWindow->activate();
|
||||
}
|
||||
} else if (event->url().scheme() == u"interpret"_q) {
|
||||
_filesToOpen.append(event->url().toString());
|
||||
_fileOpenTimer.callOnce(kFileOpenTimeoutMs);
|
||||
if (_urlsToOpen.isEmpty()) {
|
||||
InvokeQueued(this, [=] {
|
||||
const auto activateRequired = ranges::any_of(
|
||||
ranges::views::all(
|
||||
_urlsToOpen
|
||||
) | ranges::views::transform([](const QUrl &url) {
|
||||
return url.toString();
|
||||
}),
|
||||
StartUrlRequiresActivate);
|
||||
cRefStartUrls() << base::take(_urlsToOpen);
|
||||
checkStartUrls();
|
||||
if (_lastActivePrimaryWindow && activateRequired) {
|
||||
_lastActivePrimaryWindow->activate();
|
||||
}
|
||||
});
|
||||
}
|
||||
const auto event = static_cast<QFileOpenEvent*>(e);
|
||||
_urlsToOpen << event->url().toString(QUrl::FullyEncoded).mid(
|
||||
0,
|
||||
8192);
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1081,37 +1084,27 @@ bool Application::canApplyLangPackWithoutRestart() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::checkFileOpen() {
|
||||
cSetSendPaths(_filesToOpen);
|
||||
_filesToOpen.clear();
|
||||
checkSendPaths();
|
||||
}
|
||||
|
||||
void Application::checkSendPaths() {
|
||||
if (!cSendPaths().isEmpty()
|
||||
void Application::checkStartUrls() {
|
||||
if (!Core::App().passcodeLocked()) {
|
||||
cRefStartUrls() = ranges::views::all(
|
||||
cRefStartUrls()
|
||||
) | ranges::views::filter([&](const QUrl &url) {
|
||||
if (url.scheme() == u"tonsite"_q) {
|
||||
iv().showTonSite(url.toString(), {});
|
||||
return false;
|
||||
} else if (_lastActivePrimaryWindow) {
|
||||
return !openLocalUrl(url.toString(), {});
|
||||
}
|
||||
return true;
|
||||
}) | ranges::to<QList<QUrl>>;
|
||||
}
|
||||
if (!cRefStartUrls().isEmpty()
|
||||
&& _lastActivePrimaryWindow
|
||||
&& !_lastActivePrimaryWindow->locked()) {
|
||||
_lastActivePrimaryWindow->widget()->sendPaths();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::checkStartUrl() {
|
||||
if (!cStartUrl().isEmpty()) {
|
||||
const auto url = cStartUrl();
|
||||
if (!Core::App().passcodeLocked()) {
|
||||
if (url.startsWith("tonsite://", Qt::CaseInsensitive)) {
|
||||
cSetStartUrl(QString());
|
||||
iv().showTonSite(url, {});
|
||||
} else if (_lastActivePrimaryWindow) {
|
||||
cSetStartUrl(QString());
|
||||
if (!openLocalUrl(url, {})) {
|
||||
cSetStartUrl(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::openLocalUrl(const QString &url, QVariant context) {
|
||||
return openCustomUrl("tg://", LocalUrlHandlers(), url, context);
|
||||
}
|
||||
|
||||
@@ -270,9 +270,7 @@ public:
|
||||
}
|
||||
|
||||
// Internal links.
|
||||
void checkStartUrl();
|
||||
void checkSendPaths();
|
||||
void checkFileOpen();
|
||||
void checkStartUrls();
|
||||
bool openLocalUrl(const QString &url, QVariant context);
|
||||
bool openInternalUrl(const QString &url, QVariant context);
|
||||
[[nodiscard]] QString changelogLink() const;
|
||||
@@ -451,8 +449,7 @@ private:
|
||||
crl::time _shouldLockAt = 0;
|
||||
base::Timer _autoLockTimer;
|
||||
|
||||
QStringList _filesToOpen;
|
||||
base::Timer _fileOpenTimer;
|
||||
QList<QUrl> _urlsToOpen;
|
||||
|
||||
std::optional<base::Timer> _saveSettingsTimer;
|
||||
|
||||
|
||||
@@ -536,15 +536,18 @@ void Launcher::processArguments() {
|
||||
{ "-tosettings" , KeyFormat::NoValues },
|
||||
{ "-startintray" , KeyFormat::NoValues },
|
||||
{ "-quit" , KeyFormat::NoValues },
|
||||
{ "-sendpath" , KeyFormat::AllLeftValues },
|
||||
{ "-workdir" , KeyFormat::OneValue },
|
||||
{ "--" , KeyFormat::OneValue },
|
||||
{ "--" , KeyFormat::AllLeftValues },
|
||||
{ "-scale" , KeyFormat::OneValue },
|
||||
};
|
||||
auto parseResult = QMap<QByteArray, QStringList>();
|
||||
auto parsingKey = QByteArray();
|
||||
auto parsingFormat = KeyFormat::NoValues;
|
||||
for (const auto &argument : std::as_const(_arguments)) {
|
||||
for (auto i = _arguments.cbegin(); i != _arguments.cend(); ++i) {
|
||||
if (i == _arguments.cbegin()) {
|
||||
continue;
|
||||
}
|
||||
const auto &argument = *i;
|
||||
switch (parsingFormat) {
|
||||
case KeyFormat::OneValue: {
|
||||
parseResult[parsingKey] = QStringList(argument.mid(0, 8192));
|
||||
@@ -559,7 +562,9 @@ void Launcher::processArguments() {
|
||||
if (it != parseMap.end()) {
|
||||
parsingFormat = it->second;
|
||||
parseResult[parsingKey] = QStringList();
|
||||
continue;
|
||||
}
|
||||
parseResult["--"].push_back(argument.mid(0, 8192));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -579,12 +584,15 @@ void Launcher::processArguments() {
|
||||
gStartToSettings = parseResult.contains("-tosettings");
|
||||
gStartInTray = parseResult.contains("-startintray");
|
||||
gQuit = parseResult.contains("-quit");
|
||||
gSendPaths = parseResult.value("-sendpath", {});
|
||||
_customWorkingDir = parseResult.value("-workdir", {}).join(QString());
|
||||
if (!_customWorkingDir.isEmpty()) {
|
||||
_customWorkingDir = QDir(_customWorkingDir).absolutePath() + '/';
|
||||
}
|
||||
gStartUrl = parseResult.value("--", {}).join(QString());
|
||||
|
||||
const auto startUrls = parseResult.value("--", {});
|
||||
gStartUrls = startUrls | ranges::views::transform([&](const QString &url) {
|
||||
return QUrl::fromUserInput(url, _initialWorkingDir);
|
||||
}) | ranges::views::filter(&QUrl::isValid) | ranges::to<QList<QUrl>>;
|
||||
|
||||
const auto scaleKey = parseResult.value("-scale", {});
|
||||
if (scaleKey.size() > 0) {
|
||||
|
||||
@@ -35,47 +35,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtGui/qpa/qplatformscreen.h>
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
|
||||
QChar _toHex(ushort v) {
|
||||
v = v & 0x000F;
|
||||
return QChar::fromLatin1((v >= 10) ? ('a' + (v - 10)) : ('0' + v));
|
||||
}
|
||||
ushort _fromHex(QChar c) {
|
||||
return ((c.unicode() >= uchar('a')) ? (c.unicode() - uchar('a') + 10) : (c.unicode() - uchar('0'))) & 0x000F;
|
||||
}
|
||||
|
||||
QString _escapeTo7bit(const QString &str) {
|
||||
QString result;
|
||||
result.reserve(str.size() * 2);
|
||||
for (int i = 0, l = str.size(); i != l; ++i) {
|
||||
QChar ch(str.at(i));
|
||||
ushort uch(ch.unicode());
|
||||
if (uch < 32 || uch > 127 || uch == ushort(uchar('%'))) {
|
||||
result.append('%').append(_toHex(uch >> 12)).append(_toHex(uch >> 8)).append(_toHex(uch >> 4)).append(_toHex(uch));
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString _escapeFrom7bit(const QString &str) {
|
||||
QString result;
|
||||
result.reserve(str.size());
|
||||
for (int i = 0, l = str.size(); i != l; ++i) {
|
||||
QChar ch(str.at(i));
|
||||
if (ch == QChar::fromLatin1('%') && i + 4 < l) {
|
||||
result.append(QChar(ushort((_fromHex(str.at(i + 1)) << 12) | (_fromHex(str.at(i + 2)) << 8) | (_fromHex(str.at(i + 3)) << 4) | _fromHex(str.at(i + 4)))));
|
||||
i += 4;
|
||||
} else {
|
||||
result.append(ch);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Sandbox::QuitOnStartRequested = false;
|
||||
|
||||
@@ -277,18 +236,15 @@ void Sandbox::socketConnected() {
|
||||
_secondInstance = true;
|
||||
|
||||
QString commands;
|
||||
const QStringList &lst(cSendPaths());
|
||||
for (QStringList::const_iterator i = lst.cbegin(), e = lst.cend(); i != e; ++i) {
|
||||
commands += u"SEND:"_q + _escapeTo7bit(*i) + ';';
|
||||
}
|
||||
if (qEnvironmentVariableIsSet("XDG_ACTIVATION_TOKEN")) {
|
||||
commands += u"XDG_ACTIVATION_TOKEN:"_q + _escapeTo7bit(qEnvironmentVariable("XDG_ACTIVATION_TOKEN")) + ';';
|
||||
commands += u"XDG_ACTIVATION_TOKEN:"_q + qgetenv("XDG_ACTIVATION_TOKEN").toBase64() + ';';
|
||||
}
|
||||
if (!cStartUrl().isEmpty()) {
|
||||
commands += u"OPEN:"_q + _escapeTo7bit(cStartUrl()) + ';';
|
||||
} else if (cQuit()) {
|
||||
for (const auto &url : cRefStartUrls()) {
|
||||
commands += u"OPEN:"_q + url.toString(QUrl::FullyEncoded) + ';';
|
||||
}
|
||||
if (cQuit()) {
|
||||
commands += u"CMD:quit;"_q;
|
||||
} else {
|
||||
} else if (cRefStartUrls().isEmpty()) {
|
||||
commands += u"CMD:show;"_q;
|
||||
}
|
||||
|
||||
@@ -434,11 +390,11 @@ void Sandbox::newInstanceConnected() {
|
||||
|
||||
void Sandbox::readClients() {
|
||||
// This method can be called before Application is constructed.
|
||||
QString startUrl;
|
||||
QStringList toSend;
|
||||
QList<QUrl> startUrls;
|
||||
for (LocalClients::iterator i = _localClients.begin(), e = _localClients.end(); i != e; ++i) {
|
||||
i->second.append(i->first->readAll());
|
||||
if (i->second.size()) {
|
||||
bool activationRequired = false;
|
||||
QString cmds(QString::fromLatin1(i->second));
|
||||
int32 from = 0, l = cmds.length();
|
||||
for (int32 to = cmds.indexOf(QChar(';'), from); to >= from; to = (from < l) ? cmds.indexOf(QChar(';'), from) : -1) {
|
||||
@@ -448,21 +404,13 @@ void Sandbox::readClients() {
|
||||
const auto windowId = execExternal(cmds.mid(from + 4, to - from - 4));
|
||||
const auto response = u"RES:%1_%2;"_q.arg(processId).arg(windowId).toLatin1();
|
||||
i->first->write(response.data(), response.size());
|
||||
} else if (cmd.startsWith(u"SEND:"_q)) {
|
||||
if (cSendPaths().isEmpty()) {
|
||||
toSend.append(_escapeFrom7bit(cmds.mid(from + 5, to - from - 5)));
|
||||
}
|
||||
} else if (cmd.startsWith(u"XDG_ACTIVATION_TOKEN:"_q)) {
|
||||
qputenv("XDG_ACTIVATION_TOKEN", _escapeFrom7bit(cmds.mid(from + 21, to - from - 21)).toUtf8());
|
||||
qputenv("XDG_ACTIVATION_TOKEN", QByteArray::fromBase64(cmds.mid(from + 21, to - from - 21).toLatin1()));
|
||||
} else if (cmd.startsWith(u"OPEN:"_q)) {
|
||||
startUrl = _escapeFrom7bit(cmds.mid(from + 5, to - from - 5)).mid(0, 8192);
|
||||
const auto activationRequired = StartUrlRequiresActivate(startUrl);
|
||||
const auto processId = QApplication::applicationPid();
|
||||
const auto windowId = activationRequired
|
||||
? execExternal("show")
|
||||
: 0;
|
||||
const auto response = u"RES:%1_%2;"_q.arg(processId).arg(windowId).toLatin1();
|
||||
i->first->write(response.data(), response.size());
|
||||
startUrls.append(cmds.mid(from + 5, to - from - 5).mid(0, 8192));
|
||||
if (!activationRequired) {
|
||||
activationRequired = StartUrlRequiresActivate(startUrls.back().toString());
|
||||
}
|
||||
} else {
|
||||
LOG(("Sandbox Error: unknown command %1 passed in local socket").arg(cmd.toString()));
|
||||
}
|
||||
@@ -471,21 +419,17 @@ void Sandbox::readClients() {
|
||||
if (from > 0) {
|
||||
i->second = i->second.mid(from);
|
||||
}
|
||||
const auto processId = QApplication::applicationPid();
|
||||
const auto windowId = activationRequired
|
||||
? execExternal("show")
|
||||
: 0;
|
||||
const auto response = u"RES:%1_%2;"_q.arg(processId).arg(windowId).toLatin1();
|
||||
i->first->write(response.data(), response.size());
|
||||
}
|
||||
}
|
||||
if (!toSend.isEmpty()) {
|
||||
QStringList paths(cSendPaths());
|
||||
paths.append(toSend);
|
||||
cSetSendPaths(paths);
|
||||
}
|
||||
cRefStartUrls() << base::take(startUrls);
|
||||
if (_application) {
|
||||
_application->checkSendPaths();
|
||||
}
|
||||
if (!startUrl.isEmpty()) {
|
||||
cSetStartUrl(startUrl);
|
||||
}
|
||||
if (_application) {
|
||||
_application->checkStartUrl();
|
||||
_application->checkStartUrls();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -440,6 +440,18 @@ QString UiIntegration::phraseQuoteHeaderCopy() {
|
||||
return tr::lng_code_block_header_copy(tr::now);
|
||||
}
|
||||
|
||||
QString UiIntegration::phraseMinimize() {
|
||||
return tr::lng_minimize_window(tr::now);
|
||||
}
|
||||
|
||||
QString UiIntegration::phraseMaximize() {
|
||||
return tr::lng_maximize_window(tr::now);
|
||||
}
|
||||
|
||||
QString UiIntegration::phraseRestore() {
|
||||
return tr::lng_restore_window(tr::now);
|
||||
}
|
||||
|
||||
bool OpenGLLastCheckFailed() {
|
||||
return QFile::exists(OpenGLCheckFilePath());
|
||||
}
|
||||
|
||||
@@ -92,6 +92,9 @@ public:
|
||||
QString phraseBotAllowWriteTitle() override;
|
||||
QString phraseBotAllowWriteConfirm() override;
|
||||
QString phraseQuoteHeaderCopy() override;
|
||||
QString phraseMinimize() override;
|
||||
QString phraseMaximize() override;
|
||||
QString phraseRestore() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 6002003;
|
||||
constexpr auto AppVersionStr = "6.2.3";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppVersion = 6002006;
|
||||
constexpr auto AppVersionStr = "6.2.6";
|
||||
constexpr auto AppBetaVersion = true;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -7,18 +7,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/components/recent_shared_media_gifts.h"
|
||||
|
||||
#include "api/api_credits.h" // InputSavedStarGiftId
|
||||
#include "api/api_premium.h"
|
||||
#include "apiwrap.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto kReloadThreshold = 60 * crl::time(1000);
|
||||
constexpr auto kMaxGifts = 3;
|
||||
constexpr auto kMaxPinnedGifts = 6;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -29,19 +37,42 @@ RecentSharedMediaGifts::RecentSharedMediaGifts(
|
||||
|
||||
RecentSharedMediaGifts::~RecentSharedMediaGifts() = default;
|
||||
|
||||
std::vector<Data::SavedStarGift> RecentSharedMediaGifts::filterGifts(
|
||||
const std::deque<Data::SavedStarGift> &gifts,
|
||||
bool onlyPinnedToTop) {
|
||||
auto result = std::vector<Data::SavedStarGift>();
|
||||
const auto maxCount = onlyPinnedToTop ? kMaxPinnedGifts : kMaxGifts;
|
||||
for (const auto &gift : gifts) {
|
||||
if (!onlyPinnedToTop || gift.pinned) {
|
||||
result.push_back(gift);
|
||||
if (result.size() >= maxCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RecentSharedMediaGifts::request(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void(std::vector<DocumentId>)> done) {
|
||||
Fn<void(std::vector<SavedStarGift>)> done,
|
||||
bool onlyPinnedToTop) {
|
||||
const auto it = _recent.find(peer->id);
|
||||
if (it != _recent.end()) {
|
||||
auto &entry = it->second;
|
||||
if (entry.lastRequestTime
|
||||
&& entry.lastRequestTime + kReloadThreshold > crl::now()) {
|
||||
done(std::vector<DocumentId>(entry.ids.begin(), entry.ids.end()));
|
||||
done(filterGifts(entry.gifts, onlyPinnedToTop));
|
||||
return;
|
||||
}
|
||||
if (entry.requestId) {
|
||||
peer->session().api().request(entry.requestId).cancel();
|
||||
entry.pendingCallbacks.push_back([=] {
|
||||
const auto it = _recent.find(peer->id);
|
||||
if (it != _recent.end()) {
|
||||
done(filterGifts(it->second.gifts, onlyPinnedToTop));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +82,7 @@ void RecentSharedMediaGifts::request(
|
||||
peer->input,
|
||||
MTP_int(0), // collection_id
|
||||
MTP_string(QString()),
|
||||
MTP_int(kMaxGifts)
|
||||
MTP_int(kMaxPinnedGifts)
|
||||
)).done([=](const MTPpayments_SavedStarGifts &result) {
|
||||
const auto &data = result.data();
|
||||
const auto owner = &peer->owner();
|
||||
@@ -60,22 +91,144 @@ void RecentSharedMediaGifts::request(
|
||||
auto &entry = _recent[peer->id];
|
||||
entry.lastRequestTime = crl::now();
|
||||
entry.requestId = 0;
|
||||
entry.ids = {};
|
||||
entry.gifts.clear();
|
||||
|
||||
auto conter = 0;
|
||||
for (const auto &gift : data.vgifts().v) {
|
||||
if (auto parsed = Api::FromTL(peer, gift)) {
|
||||
entry.ids.push_back(parsed->info.document->id);
|
||||
if (entry.ids.size() > kMaxGifts) {
|
||||
entry.ids.pop_front();
|
||||
}
|
||||
if (++conter >= kMaxGifts) {
|
||||
break;
|
||||
}
|
||||
entry.gifts.push_back(std::move(*parsed));
|
||||
}
|
||||
}
|
||||
done(std::vector<DocumentId>(entry.ids.begin(), entry.ids.end()));
|
||||
|
||||
done(filterGifts(entry.gifts, onlyPinnedToTop));
|
||||
for (const auto &callback : entry.pendingCallbacks) {
|
||||
callback();
|
||||
}
|
||||
entry.pendingCallbacks.clear();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void RecentSharedMediaGifts::clearLastRequestTime(
|
||||
not_null<PeerData*> peer) {
|
||||
const auto it = _recent.find(peer->id);
|
||||
if (it != _recent.end()) {
|
||||
it->second.lastRequestTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RecentSharedMediaGifts::togglePinned(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
const Data::SavedStarGiftId &manageId,
|
||||
bool pinned,
|
||||
std::shared_ptr<Data::UniqueGift> uniqueData,
|
||||
std::shared_ptr<Data::UniqueGift> replacingData) {
|
||||
const auto performToggle = [=](const std::vector<SavedStarGift> &gifts) {
|
||||
const auto limit = _session->appConfig().pinnedGiftsLimit();
|
||||
auto manageIds = std::vector<Data::SavedStarGiftId>();
|
||||
|
||||
if (pinned) {
|
||||
manageIds.push_back(manageId);
|
||||
for (const auto &gift : gifts) {
|
||||
if (gift.pinned && gift.manageId != manageId) {
|
||||
manageIds.push_back(gift.manageId);
|
||||
if (manageIds.size() >= limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &gift : gifts) {
|
||||
if (gift.pinned && gift.manageId != manageId) {
|
||||
manageIds.push_back(gift.manageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto inputs = QVector<MTPInputSavedStarGift>();
|
||||
inputs.reserve(manageIds.size());
|
||||
for (const auto &id : manageIds) {
|
||||
inputs.push_back(Api::InputSavedStarGiftId(id));
|
||||
}
|
||||
|
||||
_session->api().request(MTPpayments_ToggleStarGiftsPinnedToTop(
|
||||
peer->input,
|
||||
MTP_vector<MTPInputSavedStarGift>(std::move(inputs))
|
||||
)).done([=] {
|
||||
const auto updateLocal = [=] {
|
||||
using GiftAction = Data::GiftUpdate::Action;
|
||||
_session->data().notifyGiftUpdate({
|
||||
.id = manageId,
|
||||
.action = (pinned ? GiftAction::Pin : GiftAction::Unpin),
|
||||
});
|
||||
if (pinned) {
|
||||
show->showToast({
|
||||
.title = (uniqueData
|
||||
? tr::lng_gift_pinned_done_title(
|
||||
tr::now,
|
||||
lt_gift,
|
||||
Data::UniqueGiftName(*uniqueData))
|
||||
: QString()),
|
||||
.text = (replacingData
|
||||
? tr::lng_gift_pinned_done_replaced(
|
||||
tr::now,
|
||||
lt_gift,
|
||||
TextWithEntities{
|
||||
Data::UniqueGiftName(*replacingData),
|
||||
},
|
||||
Ui::Text::WithEntities)
|
||||
: tr::lng_gift_pinned_done(
|
||||
tr::now,
|
||||
Ui::Text::WithEntities)),
|
||||
.duration = Ui::Toast::kDefaultDuration * 2,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!pinned) {
|
||||
auto result = std::deque<SavedStarGift>();
|
||||
for (const auto &id : manageIds) {
|
||||
for (const auto &gift : gifts) {
|
||||
if (gift.manageId == id) {
|
||||
result.push_back(gift);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_recent[peer->id].gifts = std::move(result);
|
||||
updateLocal();
|
||||
} else {
|
||||
_session->api().request(MTPpayments_GetSavedStarGift(
|
||||
MTP_vector<MTPInputSavedStarGift>(
|
||||
1,
|
||||
Api::InputSavedStarGiftId(manageId))
|
||||
)).done([=](const MTPpayments_SavedStarGifts &result) {
|
||||
const auto &tlGift = result.data().vgifts().v.front();
|
||||
if (auto parsed = Api::FromTL(peer, tlGift)) {
|
||||
auto result = std::deque<SavedStarGift>();
|
||||
for (const auto &id : manageIds) {
|
||||
if (parsed->manageId == id) {
|
||||
parsed->pinned = true;
|
||||
result.push_back(*parsed);
|
||||
continue;
|
||||
}
|
||||
for (const auto &gift : gifts) {
|
||||
if (gift.manageId == id) {
|
||||
result.push_back(gift);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_recent[peer->id].gifts = std::move(result);
|
||||
updateLocal();
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
}).send();
|
||||
};
|
||||
|
||||
request(peer, performToggle, true);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -7,6 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_star_gift.h"
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
@@ -20,13 +26,29 @@ public:
|
||||
|
||||
void request(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void(std::vector<DocumentId>)> done);
|
||||
Fn<void(std::vector<Data::SavedStarGift>)> done,
|
||||
bool onlyPinnedToTop = false);
|
||||
|
||||
void clearLastRequestTime(not_null<PeerData*> peer);
|
||||
|
||||
void togglePinned(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
const Data::SavedStarGiftId &manageId,
|
||||
bool pinned,
|
||||
std::shared_ptr<Data::UniqueGift> uniqueData,
|
||||
std::shared_ptr<Data::UniqueGift> replacingData = nullptr);
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::vector<Data::SavedStarGift> filterGifts(
|
||||
const std::deque<SavedStarGift> &gifts,
|
||||
bool onlyPinnedToTop);
|
||||
|
||||
struct Entry {
|
||||
std::deque<DocumentId> ids;
|
||||
std::deque<SavedStarGift> gifts;
|
||||
crl::time lastRequestTime = 0;
|
||||
mtpRequestId requestId = 0;
|
||||
std::vector<Fn<void()>> pendingCallbacks;
|
||||
};
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
@@ -74,55 +74,56 @@ struct PeerUpdate {
|
||||
Usernames = (1ULL << 12),
|
||||
TranslationDisabled = (1ULL << 13),
|
||||
Color = (1ULL << 14),
|
||||
BackgroundEmoji = (1ULL << 15),
|
||||
StoriesState = (1ULL << 16),
|
||||
VerifyInfo = (1ULL << 17),
|
||||
StarsPerMessage = (1ULL << 18),
|
||||
ColorProfile = (1ULL << 15),
|
||||
BackgroundEmoji = (1ULL << 16),
|
||||
StoriesState = (1ULL << 17),
|
||||
VerifyInfo = (1ULL << 18),
|
||||
StarsPerMessage = (1ULL << 19),
|
||||
|
||||
// For users
|
||||
CanShareContact = (1ULL << 19),
|
||||
IsContact = (1ULL << 20),
|
||||
PhoneNumber = (1ULL << 21),
|
||||
OnlineStatus = (1ULL << 22),
|
||||
BotCommands = (1ULL << 23),
|
||||
BotCanBeInvited = (1ULL << 24),
|
||||
BotStartToken = (1ULL << 25),
|
||||
CommonChats = (1ULL << 26),
|
||||
PeerGifts = (1ULL << 27),
|
||||
HasCalls = (1ULL << 28),
|
||||
SupportInfo = (1ULL << 29),
|
||||
IsBot = (1ULL << 30),
|
||||
EmojiStatus = (1ULL << 31),
|
||||
BusinessDetails = (1ULL << 32),
|
||||
Birthday = (1ULL << 33),
|
||||
PersonalChannel = (1ULL << 34),
|
||||
StarRefProgram = (1ULL << 35),
|
||||
PaysPerMessage = (1ULL << 36),
|
||||
GiftSettings = (1ULL << 37),
|
||||
StarsRating = (1ULL << 38),
|
||||
ContactNote = (1ULL << 39),
|
||||
CanShareContact = (1ULL << 20),
|
||||
IsContact = (1ULL << 21),
|
||||
PhoneNumber = (1ULL << 22),
|
||||
OnlineStatus = (1ULL << 23),
|
||||
BotCommands = (1ULL << 24),
|
||||
BotCanBeInvited = (1ULL << 25),
|
||||
BotStartToken = (1ULL << 26),
|
||||
CommonChats = (1ULL << 27),
|
||||
PeerGifts = (1ULL << 28),
|
||||
HasCalls = (1ULL << 29),
|
||||
SupportInfo = (1ULL << 30),
|
||||
IsBot = (1ULL << 31),
|
||||
EmojiStatus = (1ULL << 32),
|
||||
BusinessDetails = (1ULL << 33),
|
||||
Birthday = (1ULL << 34),
|
||||
PersonalChannel = (1ULL << 35),
|
||||
StarRefProgram = (1ULL << 36),
|
||||
PaysPerMessage = (1ULL << 37),
|
||||
GiftSettings = (1ULL << 38),
|
||||
StarsRating = (1ULL << 39),
|
||||
ContactNote = (1ULL << 40),
|
||||
|
||||
// For chats and channels
|
||||
InviteLinks = (1ULL << 40),
|
||||
Members = (1ULL << 41),
|
||||
Admins = (1ULL << 42),
|
||||
BannedUsers = (1ULL << 43),
|
||||
Rights = (1ULL << 44),
|
||||
PendingRequests = (1ULL << 45),
|
||||
Reactions = (1ULL << 46),
|
||||
InviteLinks = (1ULL << 41),
|
||||
Members = (1ULL << 42),
|
||||
Admins = (1ULL << 43),
|
||||
BannedUsers = (1ULL << 44),
|
||||
Rights = (1ULL << 45),
|
||||
PendingRequests = (1ULL << 46),
|
||||
Reactions = (1ULL << 47),
|
||||
|
||||
// For channels
|
||||
ChannelAmIn = (1ULL << 47),
|
||||
StickersSet = (1ULL << 48),
|
||||
EmojiSet = (1ULL << 49),
|
||||
DiscussionLink = (1ULL << 50),
|
||||
MonoforumLink = (1ULL << 51),
|
||||
ChannelLocation = (1ULL << 52),
|
||||
Slowmode = (1ULL << 53),
|
||||
GroupCall = (1ULL << 54),
|
||||
ChannelAmIn = (1ULL << 48),
|
||||
StickersSet = (1ULL << 49),
|
||||
EmojiSet = (1ULL << 50),
|
||||
DiscussionLink = (1ULL << 51),
|
||||
MonoforumLink = (1ULL << 52),
|
||||
ChannelLocation = (1ULL << 53),
|
||||
Slowmode = (1ULL << 54),
|
||||
GroupCall = (1ULL << 55),
|
||||
|
||||
// For iteration
|
||||
LastUsedBit = (1ULL << 54),
|
||||
LastUsedBit = (1ULL << 55),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
||||
@@ -1117,9 +1117,10 @@ void DocumentData::save(
|
||||
if (!toFile.isEmpty()) {
|
||||
if (!media->bytes().isEmpty()) {
|
||||
QFile f(toFile);
|
||||
f.open(QIODevice::WriteOnly);
|
||||
f.write(media->bytes());
|
||||
f.close();
|
||||
if (f.open(QIODevice::WriteOnly)) {
|
||||
f.write(media->bytes());
|
||||
f.close();
|
||||
}
|
||||
|
||||
setLocation(Core::FileLocation(toFile));
|
||||
session().local().writeFileLocation(
|
||||
|
||||
@@ -952,6 +952,13 @@ void PeerData::setBarSettings(PeerBarSettings which) {
|
||||
history->refreshHiddenLinksItems();
|
||||
});
|
||||
}
|
||||
if (const auto from = migrateFrom()) {
|
||||
if (const auto history = owner().historyLoaded(from)) {
|
||||
crl::on_main(&history->session(), [=] {
|
||||
history->refreshHiddenLinksItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,6 +987,9 @@ bool PeerData::hideLinks() const {
|
||||
//if (!isUser()) {
|
||||
// return false;
|
||||
//}
|
||||
if (const auto to = migrateTo()) {
|
||||
return to->hideLinks();
|
||||
}
|
||||
const auto settings = barSettings();
|
||||
return !settings || (*settings & PeerBarSetting::ReportSpam);
|
||||
}
|
||||
@@ -1054,6 +1064,17 @@ bool PeerData::changeColor(
|
||||
return changed1 || changed2 || changed3;
|
||||
}
|
||||
|
||||
bool PeerData::changeColorProfile(
|
||||
const tl::conditional<MTPPeerColor> &cloudColor) {
|
||||
const auto changed1 = cloudColor
|
||||
? changeColorProfileIndex(Data::ColorIndexFromColor(cloudColor))
|
||||
: clearColorProfileIndex();
|
||||
const auto changed2 = changeProfileBackgroundEmojiId(
|
||||
Data::BackgroundEmojiIdFromColor(cloudColor));
|
||||
const auto changed3 = changeColorProfileCollectible(cloudColor);
|
||||
return changed1 || changed2 || changed3;
|
||||
}
|
||||
|
||||
void PeerData::fillNames() {
|
||||
_nameWords.clear();
|
||||
_nameFirstLetters.clear();
|
||||
@@ -1410,6 +1431,66 @@ bool PeerData::changeBackgroundEmojiId(DocumentId id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PeerData::changeColorProfileCollectible(Ui::ColorCollectible data) {
|
||||
if (!_colorProfileCollectible || (*_colorProfileCollectible != data)) {
|
||||
_colorProfileCollectible = std::make_shared<Ui::ColorCollectible>(
|
||||
std::move(data));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PeerData::changeColorProfileCollectible(
|
||||
const tl::conditional<MTPPeerColor> &cloudColor) {
|
||||
if (!cloudColor) {
|
||||
return clearColorProfileCollectible();
|
||||
}
|
||||
return cloudColor->match([&](const MTPDpeerColorCollectible &data) {
|
||||
return changeColorProfileCollectible(Data::ParseColorCollectible(data));
|
||||
}, [&](const MTPDpeerColor &) {
|
||||
return clearColorProfileCollectible();
|
||||
}, [&](const MTPDinputPeerColorCollectible &) {
|
||||
return clearColorProfileCollectible();
|
||||
});
|
||||
}
|
||||
|
||||
bool PeerData::clearColorProfileCollectible() {
|
||||
if (!_colorProfileCollectible) {
|
||||
return false;
|
||||
}
|
||||
_colorProfileCollectible = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PeerData::changeColorProfileIndex(uint8 index) {
|
||||
index %= Ui::kColorIndexCount;
|
||||
if (_colorProfileIndex == index) {
|
||||
return false;
|
||||
}
|
||||
_colorProfileIndex = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PeerData::clearColorProfileIndex() {
|
||||
if (!_colorProfileIndex.has_value()) {
|
||||
return false;
|
||||
}
|
||||
_colorProfileIndex = std::nullopt;
|
||||
return true;
|
||||
}
|
||||
|
||||
DocumentId PeerData::profileBackgroundEmojiId() const {
|
||||
return _profileBackgroundEmojiId;
|
||||
}
|
||||
|
||||
bool PeerData::changeProfileBackgroundEmojiId(DocumentId id) {
|
||||
if (_profileBackgroundEmojiId == id) {
|
||||
return false;
|
||||
}
|
||||
_profileBackgroundEmojiId = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PeerData::setEmojiStatus(const MTPEmojiStatus &status) {
|
||||
const auto parsed = owner().emojiStatuses().parse(status);
|
||||
setEmojiStatus(parsed.id, parsed.until);
|
||||
|
||||
@@ -229,6 +229,22 @@ public:
|
||||
[[nodiscard]] DocumentId backgroundEmojiId() const;
|
||||
bool changeBackgroundEmojiId(DocumentId id);
|
||||
|
||||
[[nodiscard]] std::optional<uint8> colorProfileIndex() const {
|
||||
return _colorProfileIndex;
|
||||
}
|
||||
[[nodiscard]] auto colorProfileCollectible() const
|
||||
-> const std::shared_ptr<Ui::ColorCollectible> & {
|
||||
return _colorProfileCollectible;
|
||||
}
|
||||
bool changeColorProfileCollectible(Ui::ColorCollectible data);
|
||||
bool changeColorProfileCollectible(
|
||||
const tl::conditional<MTPPeerColor> &cloudColor);
|
||||
bool clearColorProfileCollectible();
|
||||
bool changeColorProfileIndex(uint8 index);
|
||||
bool clearColorProfileIndex();
|
||||
[[nodiscard]] DocumentId profileBackgroundEmojiId() const;
|
||||
bool changeProfileBackgroundEmojiId(DocumentId id);
|
||||
|
||||
void setEmojiStatus(const MTPEmojiStatus &status);
|
||||
void setEmojiStatus(EmojiStatusId emojiStatusId, TimeId until = 0);
|
||||
[[nodiscard]] EmojiStatusId emojiStatusId() const;
|
||||
@@ -504,6 +520,7 @@ public:
|
||||
bool changeColorCollectible(
|
||||
const tl::conditional<MTPPeerColor> &cloudColor);
|
||||
bool changeColor(const tl::conditional<MTPPeerColor> &cloudColor);
|
||||
bool changeColorProfile(const tl::conditional<MTPPeerColor> &cloudColor);
|
||||
|
||||
enum class BlockStatus : char {
|
||||
Unknown,
|
||||
@@ -608,6 +625,7 @@ private:
|
||||
|
||||
EmojiStatusId _emojiStatusId;
|
||||
DocumentId _backgroundEmojiId = 0;
|
||||
DocumentId _profileBackgroundEmojiId = 0;
|
||||
crl::time _lastFullUpdate = 0;
|
||||
|
||||
QString _name;
|
||||
@@ -621,12 +639,14 @@ private:
|
||||
BarSettings _barSettings = PeerBarSettings(PeerBarSetting::Unknown);
|
||||
std::unique_ptr<PeerBarDetails> _barDetails;
|
||||
std::shared_ptr<Ui::ColorCollectible> _colorCollectible;
|
||||
std::shared_ptr<Ui::ColorCollectible> _colorProfileCollectible;
|
||||
|
||||
BlockStatus _blockStatus = BlockStatus::Unknown;
|
||||
LoadedStatus _loadedStatus = LoadedStatus::Not;
|
||||
TranslationFlag _translationFlag = TranslationFlag::Unknown;
|
||||
uint8 _colorIndex : 6 = 0;
|
||||
uint8 _colorIndexCloud : 1 = 0;
|
||||
std::optional<uint8> _colorProfileIndex;
|
||||
uint8 _userpicHasVideo : 1 = 0;
|
||||
|
||||
QString _about;
|
||||
|
||||
23
Telegram/SourceFiles/data/data_peer_colors.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
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
|
||||
|
||||
namespace Data {
|
||||
|
||||
struct ColorProfileSet {
|
||||
std::vector<QColor> palette;
|
||||
std::vector<QColor> bg;
|
||||
std::vector<QColor> story;
|
||||
};
|
||||
|
||||
struct ColorProfileData {
|
||||
ColorProfileSet light;
|
||||
ColorProfileSet dark;
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
@@ -15,7 +15,7 @@ struct PremiumSubscriptionOption {
|
||||
QString discount;
|
||||
QString costPerMonth;
|
||||
QString costNoDiscount;
|
||||
QString costTotal;
|
||||
QString costPerYear;
|
||||
QString currency;
|
||||
QString total;
|
||||
QString botUrl;
|
||||
|
||||
@@ -23,9 +23,7 @@ class SendActionManager final {
|
||||
public:
|
||||
struct AnimationUpdate {
|
||||
not_null<Thread*> thread;
|
||||
int left = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
QRect rect;
|
||||
bool textUpdated = false;
|
||||
};
|
||||
explicit SendActionManager();
|
||||
|
||||
@@ -792,6 +792,9 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||
_peerDecorationsUpdated.fire_copy(result);
|
||||
}
|
||||
}
|
||||
if (result->changeColorProfile(data.vprofile_color())) {
|
||||
flags |= UpdateFlag::ColorProfile;
|
||||
}
|
||||
});
|
||||
|
||||
if (minimal) {
|
||||
@@ -1106,6 +1109,9 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
_peerDecorationsUpdated.fire_copy(result);
|
||||
}
|
||||
}
|
||||
if (result->changeColorProfile(data.vprofile_color())) {
|
||||
flags |= UpdateFlag::ColorProfile;
|
||||
}
|
||||
}, [&](const MTPDchannelForbidden &data) {
|
||||
const auto channel = result->asChannel();
|
||||
|
||||
@@ -5293,6 +5299,14 @@ rpl::producer<RecentSelfForwards> Session::recentSelfForwards() const {
|
||||
return _recentSelfForwards.events();
|
||||
}
|
||||
|
||||
void Session::addRecentJoinChat(const RecentJoinChat &data) {
|
||||
_recentJoinChat.fire_copy(data);
|
||||
}
|
||||
|
||||
rpl::producer<RecentJoinChat> Session::recentJoinChat() const {
|
||||
return _recentJoinChat.events();
|
||||
}
|
||||
|
||||
void Session::clearLocalStorage() {
|
||||
_cache->close();
|
||||
_cache->clear();
|
||||
|
||||
@@ -126,6 +126,11 @@ struct RecentSelfForwards {
|
||||
MessageIdsList ids;
|
||||
};
|
||||
|
||||
struct RecentJoinChat {
|
||||
PeerId fromPeerId = 0;
|
||||
PeerId joinedPeerId = 0;
|
||||
};
|
||||
|
||||
class Session final {
|
||||
public:
|
||||
using ViewElement = HistoryView::Element;
|
||||
@@ -895,6 +900,9 @@ public:
|
||||
void addRecentSelfForwards(const RecentSelfForwards &data);
|
||||
[[nodiscard]] rpl::producer<RecentSelfForwards> recentSelfForwards() const;
|
||||
|
||||
void addRecentJoinChat(const RecentJoinChat &data);
|
||||
[[nodiscard]] rpl::producer<RecentJoinChat> recentJoinChat() const;
|
||||
|
||||
void clearLocalStorage();
|
||||
|
||||
private:
|
||||
@@ -1264,6 +1272,7 @@ private:
|
||||
NextToUpgradeGift> _nextForUpgradeGifts;
|
||||
|
||||
rpl::event_stream<RecentSelfForwards> _recentSelfForwards;
|
||||
rpl::event_stream<RecentJoinChat> _recentJoinChat;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
|
||||
@@ -458,7 +458,7 @@ void Entry::updateChatListEntryHeight() {
|
||||
session().changes().entryUpdated(this, Data::EntryUpdate::Flag::Height);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Entry::hasChatsFilterTags(FilterId exclude) const {
|
||||
bool Entry::hasChatsFilterTags(FilterId exclude) const {
|
||||
if (!owner().chatsFilters().tagsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -336,10 +336,9 @@ InnerWidget::InnerWidget(
|
||||
) | rpl::start_with_next([=](
|
||||
const Data::SendActionManager::AnimationUpdate &update) {
|
||||
const auto updateRect = Ui::RowPainter::SendActionAnimationRect(
|
||||
_st,
|
||||
update.left,
|
||||
update.width,
|
||||
update.height,
|
||||
update.thread,
|
||||
_filterId,
|
||||
update.rect,
|
||||
width(),
|
||||
update.textUpdated);
|
||||
updateDialogRow(
|
||||
@@ -374,9 +373,6 @@ InnerWidget::InnerWidget(
|
||||
) | rpl::start_with_next([=](bool refreshHeight) {
|
||||
if (refreshHeight) {
|
||||
_chatsFilterTags.clear();
|
||||
}
|
||||
if (refreshHeight && _filterId) {
|
||||
// Height of the main list will be refreshed in other way.
|
||||
_shownList->updateHeights(_narrowRatio);
|
||||
}
|
||||
refreshWithCollapsedRows();
|
||||
@@ -527,14 +523,25 @@ InnerWidget::InnerWidget(
|
||||
) | rpl::start_with_next([=](
|
||||
RowDescriptor previous,
|
||||
RowDescriptor next) {
|
||||
updateDialogRow(previous);
|
||||
if (const auto sublist = previous.key.sublist()) {
|
||||
updateDialogRow({ { sublist->owningHistory() }, {} });
|
||||
}
|
||||
updateDialogRow(next);
|
||||
if (const auto sublist = next.key.sublist()) {
|
||||
updateDialogRow({ { sublist->owningHistory() }, {} });
|
||||
}
|
||||
const auto update = [&](const RowDescriptor &descriptor) {
|
||||
if (const auto topic = descriptor.key.topic()) {
|
||||
if (_openedForum == topic->forum()) {
|
||||
updateDialogRow(descriptor);
|
||||
} else {
|
||||
updateDialogRow({ { topic->owningHistory() }, {} });
|
||||
}
|
||||
} else if (const auto sublist = descriptor.key.sublist()) {
|
||||
if (_savedSublists == sublist->parent()) {
|
||||
updateDialogRow(descriptor);
|
||||
} else {
|
||||
updateDialogRow({ { sublist->owningHistory() }, {} });
|
||||
}
|
||||
} else {
|
||||
updateDialogRow(descriptor);
|
||||
}
|
||||
};
|
||||
update(previous);
|
||||
update(next);
|
||||
}, lifetime());
|
||||
|
||||
_controller->activeChatsFilter(
|
||||
@@ -2106,6 +2113,7 @@ bool InnerWidget::addQuickActionRipple(
|
||||
}
|
||||
|
||||
auto name = ResolveQuickDialogLottieIconName(type);
|
||||
const auto rowHeight = row->height();
|
||||
context->icon = Lottie::MakeIcon({
|
||||
.name = std::move(name),
|
||||
.sizeOverride = Size(st::dialogsQuickActionSize),
|
||||
@@ -2114,16 +2122,12 @@ bool InnerWidget::addQuickActionRipple(
|
||||
context->icon->jumpTo(context->icon->framesCount() - 1, [=] {
|
||||
const auto size = QSize(
|
||||
st::dialogsQuickActionRippleSize,
|
||||
row->height());
|
||||
const auto isRemovingFromList
|
||||
= (action == Dialogs::Ui::QuickDialogAction::Archive);
|
||||
rowHeight);
|
||||
if (!context->ripple) {
|
||||
context->ripple = std::make_unique<Ui::RippleAnimation>(
|
||||
st::defaultRippleAnimation,
|
||||
Ui::RippleAnimation::RectMask(size),
|
||||
isRemovingFromList
|
||||
? Fn<void()>([=] { update(); })
|
||||
: updateCallback);
|
||||
updateCallback);
|
||||
}
|
||||
if (!context->rippleFg) {
|
||||
context->rippleFg = std::make_unique<Ui::RippleAnimation>(
|
||||
@@ -2140,13 +2144,11 @@ bool InnerWidget::addQuickActionRipple(
|
||||
Rect(size),
|
||||
context->icon.get(),
|
||||
ResolveQuickDialogLabel(
|
||||
row->history(),
|
||||
history,
|
||||
action,
|
||||
_filterId));
|
||||
}),
|
||||
isRemovingFromList
|
||||
? Fn<void()>([=] { update(); })
|
||||
: std::move(updateCallback));
|
||||
std::move(updateCallback));
|
||||
}
|
||||
context->ripple->add(QPoint(size.width() / 2, size.height() / 2));
|
||||
context->rippleFg->add(QPoint(size.width() / 2, size.height() / 2));
|
||||
@@ -3266,6 +3268,18 @@ void InnerWidget::showSponsoredMenu(int peerSearchIndex, QPoint globalPos) {
|
||||
const auto peer = entry->peer;
|
||||
const auto remove = crl::guard(this, [=] {
|
||||
_sponsoredRemoved.emplace(peer);
|
||||
if (_pressedRightButtonData) {
|
||||
for (const auto &result : _peerSearchResults) {
|
||||
if (result->peer == peer
|
||||
&& result->sponsored
|
||||
&& _pressedRightButtonData
|
||||
== &result->sponsored->button) {
|
||||
_pressedRightButtonData = nullptr;
|
||||
_pressedRightButton = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_peerSearchResults.erase(
|
||||
ranges::remove(
|
||||
_peerSearchResults,
|
||||
@@ -3594,12 +3608,17 @@ void InnerWidget::clearSearchResults(bool alsoPeerSearchResults) {
|
||||
}
|
||||
|
||||
void InnerWidget::clearPeerSearchResults() {
|
||||
_peerSearchResults.clear();
|
||||
if (_pressedRightButtonSponsored) {
|
||||
_pressedRightButtonData = nullptr;
|
||||
_pressedRightButtonSponsored = false;
|
||||
_pressedRightButton = false;
|
||||
if (_pressedRightButtonData) {
|
||||
for (const auto &result : _peerSearchResults) {
|
||||
if (result->sponsored
|
||||
&& _pressedRightButtonData == &result->sponsored->button) {
|
||||
_pressedRightButtonData = nullptr;
|
||||
_pressedRightButton = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_peerSearchResults.clear();
|
||||
}
|
||||
|
||||
void InnerWidget::clearPreviewResults() {
|
||||
@@ -4162,7 +4181,7 @@ void InnerWidget::refreshEmpty() {
|
||||
_emptyList,
|
||||
{
|
||||
.name = u"no_chats"_q,
|
||||
.sizeOverride = Size(st::changePhoneIconSize),
|
||||
.sizeOverride = st::normalBoxLottieSize,
|
||||
});
|
||||
_emptyList->add(std::move(icon.widget), style::al_top);
|
||||
Ui::AddSkip(_emptyList);
|
||||
|
||||
@@ -317,31 +317,32 @@ Row::~Row() {
|
||||
clearTopicJumpRipple();
|
||||
}
|
||||
|
||||
void Row::recountHeight(float64 narrowRatio, FilterId filterId) {
|
||||
if (const auto history = _id.history()) {
|
||||
const auto hasTags = _id.entry()->hasChatsFilterTags(filterId);
|
||||
const style::DialogRow &Row::ComputeSt(
|
||||
not_null<const Entry*> entry,
|
||||
FilterId filterId) {
|
||||
if (const auto history = entry->asHistory()) {
|
||||
const auto hasTags = entry->hasChatsFilterTags(filterId);
|
||||
const auto wideRow = history->isForum()
|
||||
|| history->amMonoforumAdmin();
|
||||
_height = wideRow
|
||||
? anim::interpolate(
|
||||
hasTags
|
||||
? st::taggedForumDialogRow.height
|
||||
: st::forumDialogRow.height,
|
||||
st::defaultDialogRow.height,
|
||||
narrowRatio)
|
||||
return wideRow
|
||||
? (hasTags ? st::taggedForumDialogRow : st::forumDialogRow)
|
||||
: hasTags
|
||||
? anim::interpolate(
|
||||
st::taggedDialogRow.height,
|
||||
st::defaultDialogRow.height,
|
||||
narrowRatio)
|
||||
: st::defaultDialogRow.height;
|
||||
} else if (_id.folder()) {
|
||||
_height = st::defaultDialogRow.height;
|
||||
} else if (_id.topic()) {
|
||||
_height = st::forumTopicRow.height;
|
||||
} else {
|
||||
_height = st::defaultDialogRow.height;
|
||||
? st::taggedDialogRow
|
||||
: st::defaultDialogRow;
|
||||
} else if (entry->asTopic()) {
|
||||
return st::forumTopicRow;
|
||||
}
|
||||
return st::defaultDialogRow;
|
||||
}
|
||||
|
||||
void Row::recountHeight(float64 narrowRatio, FilterId filterId) {
|
||||
const auto &st = ComputeSt(_id.entry(), filterId);
|
||||
_height = ((&st == &st::defaultDialogRow) || !_id.history())
|
||||
? st::defaultDialogRow.height
|
||||
: anim::interpolate(
|
||||
st.height,
|
||||
st::defaultDialogRow.height,
|
||||
narrowRatio);
|
||||
}
|
||||
|
||||
uint64 Row::sortKey(FilterId filterId) const {
|
||||
|
||||
@@ -87,6 +87,10 @@ public:
|
||||
Row(Key key, int index, int top);
|
||||
~Row();
|
||||
|
||||
[[nodiscard]] static const style::DialogRow &ComputeSt(
|
||||
not_null<const Entry*> entry,
|
||||
FilterId filterId);
|
||||
|
||||
[[nodiscard]] int top() const {
|
||||
return _top;
|
||||
}
|
||||
|
||||