Compare commits
224 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daf545a72a | ||
|
|
771869e945 | ||
|
|
ac1fe2cfee | ||
|
|
ed064ee13c | ||
|
|
9fcdec4166 | ||
|
|
bd4cf82405 | ||
|
|
3653a6f011 | ||
|
|
adc6930ac6 | ||
|
|
7305d542ba | ||
|
|
874c84ad4e | ||
|
|
4edb11f128 | ||
|
|
785014f7b7 | ||
|
|
4cb5bea69b | ||
|
|
07bc84d425 | ||
|
|
9019a2cb08 | ||
|
|
716cc6ef9e | ||
|
|
a509be99b0 | ||
|
|
618ce15b21 | ||
|
|
d2b5651c3b | ||
|
|
51ff484913 | ||
|
|
547a5a14df | ||
|
|
5179d9a03f | ||
|
|
26e84dbab2 | ||
|
|
013c8ebeb4 | ||
|
|
846e96579d | ||
|
|
eaa491518e | ||
|
|
4df7761e9d | ||
|
|
6cdc8f9dbc | ||
|
|
95e4abd784 | ||
|
|
6f9a540a61 | ||
|
|
137fca73bd | ||
|
|
2159307643 | ||
|
|
ded570a480 | ||
|
|
4fd68d97d5 | ||
|
|
edfe998811 | ||
|
|
116ae04f54 | ||
|
|
ce8e42bcc2 | ||
|
|
ea9386f0aa | ||
|
|
58451aed91 | ||
|
|
a6df03d990 | ||
|
|
16b1881268 | ||
|
|
0d25b154d9 | ||
|
|
89fac88677 | ||
|
|
9604a3bd80 | ||
|
|
5b3ffc778d | ||
|
|
c6c06c149d | ||
|
|
a37f7077b0 | ||
|
|
5514ab0ccf | ||
|
|
63a753d35c | ||
|
|
4e82b7973f | ||
|
|
09094affed | ||
|
|
c5634580f6 | ||
|
|
7828a92f08 | ||
|
|
e60e65f574 | ||
|
|
7a25d70240 | ||
|
|
01428572b0 | ||
|
|
a43a5ce6c5 | ||
|
|
d4ba01bad0 | ||
|
|
5d5cae7860 | ||
|
|
f3db7e636b | ||
|
|
1c2951598b | ||
|
|
39f8394f98 | ||
|
|
29c5f6b706 | ||
|
|
b2c9a92c3e | ||
|
|
f3647d7f8c | ||
|
|
f3e65181cd | ||
|
|
d5b429e910 | ||
|
|
1bde096417 | ||
|
|
3db0b11a6b | ||
|
|
8d00d93949 | ||
|
|
277fe540dc | ||
|
|
1683dccb50 | ||
|
|
47195e316f | ||
|
|
8c9014fcf6 | ||
|
|
2d7675ace0 | ||
|
|
61cc7efc2a | ||
|
|
0464a558f0 | ||
|
|
ff9321e971 | ||
|
|
d10b7e8402 | ||
|
|
71f3f67fe3 | ||
|
|
47983d59fb | ||
|
|
df29af5aea | ||
|
|
27b443b24d | ||
|
|
7b4a542890 | ||
|
|
db6c69fa5f | ||
|
|
7dfeea3f4e | ||
|
|
92a41c881d | ||
|
|
3d769a6dce | ||
|
|
330dfaa4d9 | ||
|
|
b35fff01b0 | ||
|
|
cc19928977 | ||
|
|
c5424d0a9a | ||
|
|
f3572e52ac | ||
|
|
949c486cac | ||
|
|
082b5ba782 | ||
|
|
0f86968afd | ||
|
|
90f52d80d7 | ||
|
|
4e97599e9d | ||
|
|
e0b3e69351 | ||
|
|
e0b4d1edce | ||
|
|
a54bc449e4 | ||
|
|
ea41aab713 | ||
|
|
fd00450f44 | ||
|
|
e22aed55b0 | ||
|
|
cb838e6e52 | ||
|
|
3c931b11d6 | ||
|
|
a14dbffb65 | ||
|
|
64dcae3174 | ||
|
|
6af527ac76 | ||
|
|
e1624e5d22 | ||
|
|
21857450f3 | ||
|
|
8ea4f26e31 | ||
|
|
76ac6c3be7 | ||
|
|
c4c5036ec0 | ||
|
|
ad87c2a15e | ||
|
|
7dbf331e18 | ||
|
|
ab53b4eab7 | ||
|
|
7d678e5fa7 | ||
|
|
6adb3e7200 | ||
|
|
7906be37b6 | ||
|
|
c12743925e | ||
|
|
b17b806d91 | ||
|
|
98ab91a56a | ||
|
|
0f8d9e885a | ||
|
|
bc891ca55e | ||
|
|
9653cfdd56 | ||
|
|
0b4a255acc | ||
|
|
94feb953aa | ||
|
|
7b65c9174f | ||
|
|
e74021fbc9 | ||
|
|
e6a474d720 | ||
|
|
976c696004 | ||
|
|
c057c88d30 | ||
|
|
674bab69f5 | ||
|
|
97d93b23dc | ||
|
|
d363a6ea84 | ||
|
|
da7e8a8dc3 | ||
|
|
4296f93e1a | ||
|
|
d0b16ce05b | ||
|
|
c3340fd016 | ||
|
|
36f1a18b3b | ||
|
|
ef969df86e | ||
|
|
229f7a2c15 | ||
|
|
fbd8abc1c6 | ||
|
|
73f3110403 | ||
|
|
dfa5386a27 | ||
|
|
e5227a7e05 | ||
|
|
a6b844408a | ||
|
|
dbd4aecc56 | ||
|
|
3332f012cf | ||
|
|
456f4d7b8a | ||
|
|
0b4ef3214e | ||
|
|
e946bf5338 | ||
|
|
e8a1fc0300 | ||
|
|
0bf0fb29d2 | ||
|
|
566f2dd670 | ||
|
|
e52e1672e8 | ||
|
|
bf255c0e00 | ||
|
|
55fb3405e5 | ||
|
|
adbe5e9605 | ||
|
|
29bfe43386 | ||
|
|
ca30c35c2b | ||
|
|
d4ad5d9f13 | ||
|
|
fd79973509 | ||
|
|
d2bd109169 | ||
|
|
1b5b9f46d2 | ||
|
|
ed345e0823 | ||
|
|
90adc2d97c | ||
|
|
787ed443f4 | ||
|
|
7ffb341597 | ||
|
|
483909854a | ||
|
|
289257dd0f | ||
|
|
547a39d835 | ||
|
|
eef3cdd31b | ||
|
|
4bfe40d02e | ||
|
|
107b72f442 | ||
|
|
8adbbe6885 | ||
|
|
191f832e52 | ||
|
|
9f0a756f71 | ||
|
|
0079a18e97 | ||
|
|
876a803e0e | ||
|
|
7009e967d0 | ||
|
|
076aa9452e | ||
|
|
d77c7a70ab | ||
|
|
8255de1ba8 | ||
|
|
aad1296829 | ||
|
|
738aff9c4f | ||
|
|
7740780eeb | ||
|
|
9edbb9762a | ||
|
|
98bb520f47 | ||
|
|
ae2182c1e5 | ||
|
|
4807244682 | ||
|
|
119f7e757d | ||
|
|
e34e640dbb | ||
|
|
e755851237 | ||
|
|
dff168c62e | ||
|
|
b39bf11d9e | ||
|
|
d8f53d5f60 | ||
|
|
f10da51517 | ||
|
|
3dc0e3818b | ||
|
|
1493b23574 | ||
|
|
70e298cfe4 | ||
|
|
9d4b8bb9b0 | ||
|
|
089432be5e | ||
|
|
4b503ad7ed | ||
|
|
aeb593dd77 | ||
|
|
0d4a83ea47 | ||
|
|
95b26911e0 | ||
|
|
4c2be58dd3 | ||
|
|
374e95de31 | ||
|
|
cfe3285e68 | ||
|
|
7b184e553b | ||
|
|
02e37ab2f2 | ||
|
|
48206bcf95 | ||
|
|
d0eb7ec522 | ||
|
|
77c2e12ebc | ||
|
|
a479fcd55c | ||
|
|
396635fa1d | ||
|
|
4755be4ace | ||
|
|
1148a2e144 | ||
|
|
827e755552 | ||
|
|
b80f5f9706 | ||
|
|
518f0e22cd | ||
|
|
610e0e7913 |
4
.github/workflows/linux.yml
vendored
@@ -41,7 +41,7 @@ on:
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
name: CentOS 7
|
||||
name: Rocky Linux 8
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/${{ github.repository }}/centos_env
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: scl enable rh-python38 -- scl enable llvm-toolset-7.0 -- scl enable devtoolset-10 -- bash --noprofile --norc -eo pipefail {0}
|
||||
shell: scl enable gcc-toolset-12 -- bash --noprofile --norc -eo pipefail {0}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
2
.github/workflows/snap.yml
vendored
@@ -61,7 +61,7 @@ jobs:
|
||||
sudo snap run lxd waitready
|
||||
|
||||
- name: Free up some disk space.
|
||||
uses: jlumbroso/free-disk-space@76866dbe54312617f00798d1762df7f43def6e5c
|
||||
uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
|
||||
|
||||
- name: Telegram Desktop snap build.
|
||||
run: sg lxd -c 'snap run snapcraft -v'
|
||||
|
||||
2
.github/workflows/win.yml
vendored
@@ -123,7 +123,7 @@ jobs:
|
||||
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
|
||||
|
||||
API="-D TDESKTOP_API_TEST=ON"
|
||||
if [ ${{ github.ref == 'refs/heads/nightly' }} ]; then
|
||||
if [ $GITHUB_REF == 'refs/heads/nightly' ]; then
|
||||
echo "Use the open credentials."
|
||||
API="-D TDESKTOP_API_ID=611335 -D TDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c"
|
||||
fi
|
||||
|
||||
3
.gitmodules
vendored
@@ -58,9 +58,6 @@
|
||||
[submodule "Telegram/ThirdParty/range-v3"]
|
||||
path = Telegram/ThirdParty/range-v3
|
||||
url = https://github.com/ericniebler/range-v3.git
|
||||
[submodule "Telegram/ThirdParty/fcitx-qt5"]
|
||||
path = Telegram/ThirdParty/fcitx-qt5
|
||||
url = https://github.com/fcitx/fcitx-qt5.git
|
||||
[submodule "Telegram/ThirdParty/nimf"]
|
||||
path = Telegram/ThirdParty/nimf
|
||||
url = https://github.com/hamonikr/nimf.git
|
||||
|
||||
@@ -61,7 +61,7 @@ if (NOT DESKTOP_APP_USE_PACKAGED)
|
||||
if (WIN32)
|
||||
set(qt_version 5.15.10)
|
||||
elseif (APPLE)
|
||||
set(qt_version 6.3.2)
|
||||
set(qt_version 6.2.5)
|
||||
endif()
|
||||
endif()
|
||||
include(cmake/external/qt/package.cmake)
|
||||
|
||||
@@ -17,13 +17,18 @@ The latest version is available for
|
||||
|
||||
* [Windows 7 and above (64 bit)](https://telegram.org/dl/desktop/win64) ([portable](https://telegram.org/dl/desktop/win64_portable))
|
||||
* [Windows 7 and above (32 bit)](https://telegram.org/dl/desktop/win) ([portable](https://telegram.org/dl/desktop/win_portable))
|
||||
* [macOS 10.12 and above](https://telegram.org/dl/desktop/mac)
|
||||
* [macOS 10.13 and above](https://telegram.org/dl/desktop/mac)
|
||||
* [Linux static build for 64 bit](https://telegram.org/dl/desktop/linux)
|
||||
* [Snap](https://snapcraft.io/telegram-desktop)
|
||||
* [Flatpak](https://flathub.org/apps/details/org.telegram.desktop)
|
||||
|
||||
## Old system versions
|
||||
|
||||
Version **4.9.9** was the last that supports older systems
|
||||
|
||||
* [macOS 10.12](https://updates.tdesktop.com/tmac/tsetup.4.9.9.dmg)
|
||||
* [Linux with glibc < 2.28 static build](https://updates.tdesktop.com/tlinux/tsetup.4.9.9.tar.xz)
|
||||
|
||||
Version **2.4.4** was the last that supports older systems
|
||||
|
||||
* [OS X 10.10 and 10.11](https://updates.tdesktop.com/tosx/tsetup-osx.2.4.4.dmg)
|
||||
|
||||
@@ -413,6 +413,7 @@ PRIVATE
|
||||
core/crash_report_window.h
|
||||
core/crash_reports.cpp
|
||||
core/crash_reports.h
|
||||
core/deadlock_detector.h
|
||||
core/file_utilities.cpp
|
||||
core/file_utilities.h
|
||||
core/launcher.cpp
|
||||
@@ -1261,6 +1262,8 @@ PRIVATE
|
||||
settings/settings_main.h
|
||||
settings/settings_notifications.cpp
|
||||
settings/settings_notifications.h
|
||||
settings/settings_notifications_type.cpp
|
||||
settings/settings_notifications_type.h
|
||||
settings/settings_power_saving.cpp
|
||||
settings/settings_power_saving.h
|
||||
settings/settings_premium.cpp
|
||||
@@ -1472,6 +1475,7 @@ PRIVATE
|
||||
qrc/emoji_5.qrc
|
||||
qrc/emoji_6.qrc
|
||||
qrc/emoji_7.qrc
|
||||
qrc/emoji_8.qrc
|
||||
qrc/emoji_preview.qrc
|
||||
qrc/telegram/animations.qrc
|
||||
qrc/telegram/export.qrc
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 821 KiB After Width: | Height: | Size: 832 KiB |
BIN
Telegram/Resources/emoji/emoji_8.webp
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
Telegram/Resources/icons/limits/boost.png
Normal file
|
After Width: | Height: | Size: 464 B |
BIN
Telegram/Resources/icons/limits/boost@2x.png
Normal file
|
After Width: | Height: | Size: 796 B |
BIN
Telegram/Resources/icons/limits/boost@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/mediaview/views.png
Normal file
|
After Width: | Height: | Size: 476 B |
BIN
Telegram/Resources/icons/mediaview/views@2x.png
Normal file
|
After Width: | Height: | Size: 884 B |
BIN
Telegram/Resources/icons/mediaview/views@3x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/mini_forward.png
Normal file
|
After Width: | Height: | Size: 319 B |
BIN
Telegram/Resources/icons/mini_forward@2x.png
Normal file
|
After Width: | Height: | Size: 539 B |
BIN
Telegram/Resources/icons/mini_forward@3x.png
Normal file
|
After Width: | Height: | Size: 777 B |
BIN
Telegram/Resources/icons/mini_reply_story.png
Normal file
|
After Width: | Height: | Size: 588 B |
BIN
Telegram/Resources/icons/mini_reply_story@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/mini_reply_story@3x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/stories/boost_mini.png
Normal file
|
After Width: | Height: | Size: 366 B |
BIN
Telegram/Resources/icons/stories/boost_mini@2x.png
Normal file
|
After Width: | Height: | Size: 589 B |
BIN
Telegram/Resources/icons/stories/boost_mini@3x.png
Normal file
|
After Width: | Height: | Size: 863 B |
@@ -451,6 +451,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_show_from" = "Show notifications from";
|
||||
"lng_settings_notify_all" = "All accounts";
|
||||
"lng_settings_notify_all_about" = "Turn this off if you want to receive notifications only from the account you are currently using.";
|
||||
"lng_settings_notify_global" = "Global settings";
|
||||
"lng_settings_notify_title" = "Notifications for chats";
|
||||
"lng_settings_desktop_notify" = "Desktop notifications";
|
||||
"lng_settings_native_title" = "Native notifications";
|
||||
@@ -458,8 +459,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_use_native_notifications" = "Use native notifications";
|
||||
"lng_settings_notifications_position" = "Location on the screen";
|
||||
"lng_settings_notifications_count" = "Notifications count";
|
||||
"lng_settings_sound_notify" = "Play sound";
|
||||
"lng_settings_sound_notify_off" = "Off";
|
||||
"lng_settings_sound_allowed" = "Allow sound";
|
||||
"lng_settings_alert_windows" = "Flash the taskbar icon";
|
||||
"lng_settings_alert_mac" = "Bounce the dock icon";
|
||||
"lng_settings_alert_linux" = "Draw attention to the window";
|
||||
@@ -480,6 +480,36 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_notification_hide_all" = "Hide all";
|
||||
"lng_notification_sample" = "This is a sample notification";
|
||||
"lng_notification_reminder" = "Reminder";
|
||||
"lng_notification_private_chats" = "Private chats";
|
||||
"lng_notification_groups" = "Groups";
|
||||
"lng_notification_channels" = "Channels";
|
||||
"lng_notification_click_to_change" = "Click here to change";
|
||||
"lng_notification_on" = "On, {exceptions}";
|
||||
"lng_notification_off" = "Off, {exceptions}";
|
||||
"lng_notification_exceptions#one" = "{count} exception";
|
||||
"lng_notification_exceptions#other" = "{count} exceptions";
|
||||
"lng_notification_exceptions_title" = "Exceptions";
|
||||
"lng_notification_title_private_chats" = "Notifications for private chats";
|
||||
"lng_notification_about_private_chats#one" = "Please note that **{count} chat** is listed as an exception and won't be affected by this change.";
|
||||
"lng_notification_about_private_chats#other" = "Please note that **{count} chats** are listed as exceptions and won't be affected by this change.";
|
||||
"lng_notification_title_groups" = "Notifications for groups";
|
||||
"lng_notification_about_groups#one" = "Please note that **{count} group** is listed as an exception and won't be affected by this change.";
|
||||
"lng_notification_about_groups#other" = "Please note that **{count} groups** are listed as exceptions and won't be affected by this change.";
|
||||
"lng_notification_title_channels" = "Notifications for channels";
|
||||
"lng_notification_about_channels#one" = "Please note that **{count} channel** is listed as an exception and won't be affected by this change.";
|
||||
"lng_notification_about_channels#other" = "Please note that **{count} channels** are listed as exceptions and won't be affected by this change.";
|
||||
"lng_notification_exceptions_view" = "View exceptions";
|
||||
"lng_notification_enable" = "Enable notifications";
|
||||
"lng_notification_sound" = "Sound";
|
||||
"lng_notification_tone" = "Notification tone";
|
||||
"lng_notification_exceptions_muted" = "Muted";
|
||||
"lng_notification_exceptions_unmuted" = "Unmuted";
|
||||
"lng_notification_exceptions_add" = "Add an exception";
|
||||
"lng_notification_exceptions_clear" = "Delete all exceptions";
|
||||
"lng_notification_exceptions_clear_sure" = "Are you sure you want to delete all exceptions?";
|
||||
"lng_notification_exceptions_clear_button" = "Delete";
|
||||
"lng_notification_exceptions_remove" = "Remove";
|
||||
"lng_notification_context_remove" = "Remove exception";
|
||||
|
||||
"lng_reaction_text" = "{reaction} to your «{text}»";
|
||||
"lng_reaction_notext" = "{reaction} to your message";
|
||||
@@ -518,6 +548,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_title_account_name" = "Show active account";
|
||||
"lng_settings_title_total_count" = "Total unread count";
|
||||
"lng_settings_native_frame" = "Use system window frame";
|
||||
"lng_settings_qt_frame" = "Use Qt window frame";
|
||||
"lng_settings_auto_start" = "Launch Telegram when system starts";
|
||||
"lng_settings_start_min" = "Launch minimized";
|
||||
"lng_settings_auto_start_disabled_uwp" = "Starting with the system was disabled in Windows Settings.\n\nPlease enable Telegram Desktop in the Startup Apps Settings.";
|
||||
@@ -1152,6 +1183,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_loading" = "Loading...";
|
||||
"lng_profile_saved_stories#one" = "{count} saved story";
|
||||
"lng_profile_saved_stories#other" = "{count} saved stories";
|
||||
"lng_profile_posts#one" = "{count} post";
|
||||
"lng_profile_posts#other" = "{count} posts";
|
||||
"lng_profile_photos#one" = "{count} photo";
|
||||
"lng_profile_photos#other" = "{count} photos";
|
||||
"lng_profile_gifs#one" = "{count} GIF";
|
||||
@@ -1581,6 +1614,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_action_suggested_video" = "{user} suggests you to use this profile video.";
|
||||
"lng_action_suggested_video_button" = "View Video";
|
||||
"lng_action_attach_menu_bot_allowed" = "You allowed this bot to message you when you added it in the attachment menu.";
|
||||
"lng_action_webapp_bot_allowed" = "You allowed this bot to message you in his web-app.";
|
||||
"lng_action_set_wallpaper_me" = "You set a new wallpaper for this chat";
|
||||
"lng_action_set_wallpaper" = "{user} set a new wallpaper for this chat";
|
||||
"lng_action_set_wallpaper_button" = "View Wallpaper";
|
||||
@@ -1769,6 +1803,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_share_location_unavailable" = "Sorry, location sharing is currently unavailable in Telegram Desktop.";
|
||||
"lng_bot_share_phone" = "Do you want to share your phone number with this bot?";
|
||||
"lng_bot_share_phone_confirm" = "Share";
|
||||
"lng_bot_allow_write_title" = "Allow messaging";
|
||||
"lng_bot_allow_write" = "Do you want to allow this bot writing you?";
|
||||
"lng_bot_allow_write_confirm" = "Allow";
|
||||
|
||||
"lng_attach_failed" = "Failed";
|
||||
"lng_attach_file" = "File";
|
||||
@@ -1965,6 +2002,38 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_premium_gift_terms" = "You can review the list of features and terms of use for Telegram Premium {link}.";
|
||||
"lng_premium_gift_terms_link" = "here";
|
||||
|
||||
"lng_boost_channel_button" = "Boost Channel";
|
||||
"lng_boost_level#one" = "Level {count}";
|
||||
"lng_boost_level#other" = "Level {count}";
|
||||
"lng_boost_channel_title_first" = "Enable stories for channel";
|
||||
"lng_boost_channel_needs_first#one" = "{channel} needs **{count}** more boost to enable posting stories. Help make it possible!";
|
||||
"lng_boost_channel_needs_first#other" = "{channel} needs **{count}** more boosts to enable posting stories. Help make it possible!";
|
||||
"lng_boost_channel_title_more" = "Help upgrade channel";
|
||||
"lng_boost_channel_needs_more#one" = "{channel} needs **{count}** more boost to be able to {post}.";
|
||||
"lng_boost_channel_needs_more#other" = "{channel} needs **{count}** more boosts to be able to {post}.";
|
||||
"lng_boost_channel_title_max" = "Maximum level reached";
|
||||
"lng_boost_channel_you_title" = "You boosted {channel}!";
|
||||
"lng_boost_channel_you_first#one" = "This channel needs **{count}** more boost\nto enable stories.";
|
||||
"lng_boost_channel_you_first#other" = "This channel needs **{count}** more boosts\nto enable stories.";
|
||||
"lng_boost_channel_you_more#one" = "This channel needs **{count}** more boost\nto be able to {post}.";
|
||||
"lng_boost_channel_you_more#other" = "This channel needs **{count}** more boosts\nto be able to {post}.";
|
||||
"lng_boost_channel_reached_first" = "This channel reached **Level 1** and can now post stories.";
|
||||
"lng_boost_channel_reached_more#one" = "This channel reached **Level {count}** and can now {post}.";
|
||||
"lng_boost_channel_reached_more#other" = "This channel reached **Level {count}** and can now {post}.";
|
||||
"lng_boost_channel_post_stories#one" = "post **{count} story** per day";
|
||||
"lng_boost_channel_post_stories#other" = "post **{count} stories** per day";
|
||||
"lng_boost_error_gifted_title" = "Can't boost with gifted Premium!";
|
||||
"lng_boost_error_gifted_text" = "Because your **Telegram Premium** subscription was gifted to you, you can't use it to boost channels.";
|
||||
"lng_boost_error_already_title" = "Already Boosted!";
|
||||
"lng_boost_error_already_text" = "You are already boosting this channel.";
|
||||
"lng_boost_error_premium_title" = "Premium needed!";
|
||||
"lng_boost_error_premium_text" = "Only **Telegram Premium** subscribers can boost channels. Do you want to subscribe to **Telegram Premium**?";
|
||||
"lng_boost_error_premium_yes" = "Yes";
|
||||
"lng_boost_error_flood_title" = "Can't boost too often!";
|
||||
"lng_boost_error_flood_text" = "You can change the channel you boost only once a day. Next time you can boost is in {left}.";
|
||||
"lng_boost_now_instead" = "You currently boost {channel}. Do you want to boost {other} instead?";
|
||||
"lng_boost_now_replace" = "Replace";
|
||||
|
||||
"lng_accounts_limit_title" = "Limit Reached";
|
||||
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected accounts.";
|
||||
"lng_accounts_limit1#other" = "You have reached the limit of **{count}** connected accounts.";
|
||||
@@ -2226,17 +2295,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_remove_from_menu" = "Remove From Menu";
|
||||
"lng_bot_remove_from_menu_sure" = "Remove {bot} from the attachment menu?";
|
||||
"lng_bot_remove_from_menu_done" = "Bot removed from the menu.";
|
||||
"lng_bot_remove_from_side_menu" = "Remove From Menu";
|
||||
"lng_bot_remove_from_side_menu_sure" = "Remove {bot} from the main menu?";
|
||||
"lng_bot_remove_from_side_menu_done" = "Bot removed from the main menu.";
|
||||
"lng_bot_settings" = "Settings";
|
||||
"lng_bot_open" = "Open Bot";
|
||||
"lng_bot_reload_page" = "Reload Page";
|
||||
"lng_bot_add_to_menu" = "{bot} asks your permission to be added as an option to your attachments menu so you can access it from any chat.";
|
||||
"lng_bot_add_to_menu_done" = "Bot added to the menu.";
|
||||
"lng_bot_will_be_added" = "{bot} shortcuts will be added to the attachment options and the main menu.";
|
||||
"lng_bot_side_menu_new" = "NEW";
|
||||
"lng_bot_menu_not_supported" = "This bot isn't supported in the attach menu.";
|
||||
"lng_bot_menu_already_added" = "This bot is already added in your attach menu.";
|
||||
"lng_bot_menu_button" = "Menu";
|
||||
"lng_bot_close_warning_title" = "Warning";
|
||||
"lng_bot_close_warning" = "Changes that you made may not be saved.";
|
||||
"lng_bot_close_warning_sure" = "Close anyway";
|
||||
"lng_bot_add_to_side_menu" = "{bot} asks your permission to be added as an option to your main menu so you can access it any time.";
|
||||
"lng_bot_add_to_side_menu_done" = "Bot added to the main menu.";
|
||||
|
||||
"lng_typing" = "typing";
|
||||
"lng_user_typing" = "{user} is typing";
|
||||
@@ -2340,6 +2416,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_open_gif" = "Open GIF";
|
||||
"lng_context_save_gif" = "Save GIF";
|
||||
"lng_context_delete_gif" = "Delete GIF";
|
||||
"lng_context_open_channel" = "Open Channel";
|
||||
"lng_context_attached_stickers" = "Attached Stickers";
|
||||
"lng_context_to_msg" = "Go To Message";
|
||||
"lng_context_reply_msg" = "Reply";
|
||||
@@ -2717,6 +2794,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_payments_terms_title" = "Terms of Service";
|
||||
"lng_payments_terms_text" = "Subscribe and accept terms of service of {bot}?";
|
||||
"lng_payments_terms_text_once" = "Are you accepting terms of service of {bot}?";
|
||||
"lng_payments_terms_agree" = "I agree to {link}";
|
||||
"lng_payments_terms_link" = "Terms of Service";
|
||||
"lng_payments_terms_accept" = "Accept";
|
||||
@@ -3049,9 +3127,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gigagroup_suggest_more" = "Learn more";
|
||||
|
||||
"lng_rights_channel_info" = "Change channel info";
|
||||
"lng_rights_channel_manage" = "Manage messages";
|
||||
"lng_rights_channel_post" = "Post messages";
|
||||
"lng_rights_channel_edit" = "Edit messages of others";
|
||||
"lng_rights_channel_delete" = "Delete messages of others";
|
||||
"lng_rights_channel_manage_stories" = "Manage stories";
|
||||
"lng_rights_channel_post_stories" = "Post stories";
|
||||
"lng_rights_channel_edit_stories" = "Edit stories of others";
|
||||
"lng_rights_channel_delete_stories" = "Delete stories of others";
|
||||
"lng_rights_channel_manage_calls" = "Manage live streams";
|
||||
"lng_rights_group_info" = "Change group info";
|
||||
"lng_rights_group_ban" = "Ban users";
|
||||
@@ -3310,6 +3393,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_admin_log_admin_post_messages" = "Post messages";
|
||||
"lng_admin_log_admin_edit_messages" = "Edit messages";
|
||||
"lng_admin_log_admin_delete_messages" = "Delete messages";
|
||||
"lng_admin_log_admin_post_stories" = "Post stories";
|
||||
"lng_admin_log_admin_edit_stories" = "Edit stories";
|
||||
"lng_admin_log_admin_delete_stories" = "Delete stories";
|
||||
"lng_admin_log_admin_remain_anonymous" = "Remain anonymous";
|
||||
"lng_admin_log_admin_ban_users" = "Ban users";
|
||||
"lng_admin_log_admin_invite_users" = "Add members";
|
||||
@@ -3525,6 +3611,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_export_option_choose_format" = "Choose export format";
|
||||
"lng_export_option_html" = "Human-readable HTML";
|
||||
"lng_export_option_json" = "Machine-readable JSON";
|
||||
"lng_export_option_html_and_json" = "Both";
|
||||
"lng_export_limits" = "From: {from}, to: {till}";
|
||||
"lng_export_beginning" = "the oldest message";
|
||||
"lng_export_end" = "present";
|
||||
@@ -3789,6 +3876,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_view_button_voice_chat_channel" = "Live stream";
|
||||
"lng_view_button_request_join" = "Request to Join";
|
||||
"lng_view_button_external_link" = "Open link";
|
||||
"lng_view_button_boost" = "Boost";
|
||||
|
||||
"lng_sponsored_hide_ads" = "Hide";
|
||||
"lng_sponsored_title" = "What are sponsored messages?";
|
||||
@@ -3799,6 +3887,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_telegram_features_url" = "https://t.me/TelegramTips";
|
||||
|
||||
"lng_mini_apps_disclaimer_title" = "Warning";
|
||||
"lng_mini_apps_disclaimer_text" = "You are about to use a mini app operated by an independent party **not affiliated with Telegram**. You must agree to the Terms of Use of mini apps to continue.";
|
||||
"lng_mini_apps_disclaimer_button" = "I agree to the {link}";
|
||||
"lng_mini_apps_disclaimer_link" = "Terms of Use";
|
||||
"lng_mini_apps_tos_url" = "https://telegram.org/tos/mini-apps";
|
||||
|
||||
"lng_ringtones_box_title" = "Notification Sound";
|
||||
"lng_ringtones_box_cloud_subtitle" = "Choose your tone";
|
||||
"lng_ringtones_box_upload_choose" = "Choose ringtone";
|
||||
@@ -3916,6 +4010,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stories_recent_button" = "Recent Stories";
|
||||
"lng_stories_archive_title" = "Stories Archive";
|
||||
"lng_stories_archive_about" = "Only you can see archived stories unless you choose to save them to your profile.";
|
||||
"lng_stories_channel_archive_about" = "Only admins of the channel can see archived stories unless they are saved to the channel page.";
|
||||
"lng_stories_reply_sent" = "Message Sent";
|
||||
"lng_stories_hidden_to_contacts" = "Stories from {user} will now be shown in **Archived Chats**.";
|
||||
"lng_stories_shown_in_chats" = "Stories from {user} will now be shown in the **Chats List**.";
|
||||
@@ -3935,6 +4030,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stories_archive_done" = "This story is hidden from your profile.";
|
||||
"lng_stories_archive_done_many#one" = "{count} story is hidden from your profile.";
|
||||
"lng_stories_archive_done_many#other" = "{count} stories are hidden from your profile.";
|
||||
"lng_stories_channel_save_sure" = "Do you want to save this story to the channel page?";
|
||||
"lng_stories_channel_save_sure_many#one" = "Do you want to save {count} story to the channel page?";
|
||||
"lng_stories_channel_save_sure_many#other" = "Do you want to save {count} stories to the channel page?";
|
||||
"lng_stories_channel_save_done" = "This story is saved to the channel page.";
|
||||
"lng_stories_channel_save_done_many#one" = "{count} story is saved to the channel page.";
|
||||
"lng_stories_channel_save_done_many#other" = "{count} stories are saved to the channel page.";
|
||||
"lng_stories_channel_save_done_about" = "Saved stories can be viewed by others on the channel page until they are removed.";
|
||||
"lng_stories_channel_archive_sure" = "Do you want to hide this story from the channel page?";
|
||||
"lng_stories_channel_archive_sure_many#one" = "Do you want to hide {count} story from the channel page?";
|
||||
"lng_stories_channel_archive_sure_many#other" = "Do you want to hide {count} stories from the channel page?";
|
||||
"lng_stories_channel_archive_done" = "This story is hidden from the channel page.";
|
||||
"lng_stories_channel_archive_done_many#one" = "{count} story is hidden from the channel page.";
|
||||
"lng_stories_channel_archive_done_many#other" = "{count} stories are hidden from the channel page.";
|
||||
"lng_stories_save_promo" = "Subscribe to {link} to download other people's unprotected stories to disk.";
|
||||
|
||||
"lng_stealth_mode_menu_item" = "Stealth Mode";
|
||||
|
||||
5
Telegram/Resources/qrc/emoji_8.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_8.webp">../emoji/emoji_8.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="4.9.3.0" />
|
||||
Version="4.10.2.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 4,9,3,0
|
||||
PRODUCTVERSION 4,9,3,0
|
||||
FILEVERSION 4,10,2,0
|
||||
PRODUCTVERSION 4,10,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "4.9.3.0"
|
||||
VALUE "FileVersion", "4.10.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.9.3.0"
|
||||
VALUE "ProductVersion", "4.10.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,9,3,0
|
||||
PRODUCTVERSION 4,9,3,0
|
||||
FILEVERSION 4,10,2,0
|
||||
PRODUCTVERSION 4,10,2,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", "4.9.3.0"
|
||||
VALUE "FileVersion", "4.10.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.9.3.0"
|
||||
VALUE "ProductVersion", "4.10.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -267,7 +267,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
QByteArray inner = f.readAll();
|
||||
stream << name << quint32(inner.size()) << inner;
|
||||
#ifdef Q_OS_UNIX
|
||||
#ifndef Q_OS_WIN
|
||||
stream << (QFileInfo(fullName).isExecutable() ? true : false);
|
||||
#endif
|
||||
}
|
||||
@@ -281,7 +281,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Compression start, size: " << resultSize << "\n";
|
||||
|
||||
QByteArray compressed, resultCheck;
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
|
||||
|
||||
compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size
|
||||
@@ -496,10 +496,8 @@ int main(int argc, char *argv[])
|
||||
QString outName((targetwin64 ? QString("tx64upd%1") : QString("tupdate%1")).arg(AlphaVersion ? AlphaVersion : version));
|
||||
#elif defined Q_OS_MAC
|
||||
QString outName((targetarmac ? QString("tarmacupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version));
|
||||
#elif defined Q_OS_UNIX
|
||||
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
|
||||
#else
|
||||
#error Unknown platform!
|
||||
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
|
||||
#endif
|
||||
if (AlphaVersion) {
|
||||
outName += "_" + AlphaSignature;
|
||||
|
||||
@@ -27,7 +27,7 @@ extern "C" {
|
||||
#include <openssl/evp.h>
|
||||
} // extern "C"
|
||||
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
|
||||
#include <LzmaLib.h>
|
||||
#else
|
||||
#include <lzma.h>
|
||||
|
||||
@@ -41,6 +41,7 @@ bool do_mkdir(const char *path) { // from http://stackoverflow.com/questions/675
|
||||
}
|
||||
|
||||
bool _debug = false;
|
||||
bool writeprotected = false;
|
||||
string updaterDir;
|
||||
string updaterName;
|
||||
string workDir;
|
||||
@@ -88,7 +89,7 @@ void writeLog(const char *format, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
bool copyFile(const char *from, const char *to, bool writeprotected) {
|
||||
bool copyFile(const char *from, const char *to) {
|
||||
FILE *ffrom = fopen(from, "rb"), *fto = fopen(to, "wb");
|
||||
if (!ffrom) {
|
||||
if (fto) fclose(fto);
|
||||
@@ -211,7 +212,7 @@ void delFolder() {
|
||||
rmdir(delFolder.c_str());
|
||||
}
|
||||
|
||||
bool update(bool writeprotected) {
|
||||
bool update() {
|
||||
writeLog("Update started..");
|
||||
|
||||
string updDir = workDir + "tupdates/temp", readyFilePath = workDir + "tupdates/temp/ready", tdataDir = workDir + "tupdates/temp/tdata";
|
||||
@@ -324,7 +325,7 @@ bool update(bool writeprotected) {
|
||||
writeLog("Copying file '%s' to '%s'..", fname.c_str(), tofname.c_str());
|
||||
int copyTries = 0, triesLimit = 30;
|
||||
do {
|
||||
if (!copyFile(fname.c_str(), tofname.c_str(), writeprotected)) {
|
||||
if (!copyFile(fname.c_str(), tofname.c_str())) {
|
||||
++copyTries;
|
||||
usleep(100000);
|
||||
} else {
|
||||
@@ -359,10 +360,10 @@ int main(int argc, char *argv[]) {
|
||||
bool needupdate = true;
|
||||
bool autostart = false;
|
||||
bool debug = false;
|
||||
bool writeprotected = false;
|
||||
bool tosettings = false;
|
||||
bool startintray = false;
|
||||
bool customWorkingDir = false;
|
||||
bool justUpdate = false;
|
||||
|
||||
char *key = 0;
|
||||
char *workdir = 0;
|
||||
@@ -381,6 +382,9 @@ int main(int argc, char *argv[]) {
|
||||
customWorkingDir = true;
|
||||
} else if (equal(argv[i], "-writeprotected")) {
|
||||
writeprotected = true;
|
||||
justUpdate = true;
|
||||
} else if (equal(argv[i], "-justupdate")) {
|
||||
justUpdate = true;
|
||||
} else if (equal(argv[i], "-key") && ++i < argc) {
|
||||
key = argv[i];
|
||||
} else if (equal(argv[i], "-workpath") && ++i < argc) {
|
||||
@@ -455,7 +459,7 @@ int main(int argc, char *argv[]) {
|
||||
} else {
|
||||
writeLog("Passed workpath is '%s'", workDir.c_str());
|
||||
}
|
||||
update(writeprotected);
|
||||
update();
|
||||
}
|
||||
} else {
|
||||
writeLog("Error: bad exe name!");
|
||||
@@ -464,36 +468,38 @@ int main(int argc, char *argv[]) {
|
||||
writeLog("Error: short exe name!");
|
||||
}
|
||||
|
||||
const auto fullBinaryPath = exePath + exeName;
|
||||
|
||||
auto values = vector<string>();
|
||||
const auto push = [&](string arg) {
|
||||
// Force null-terminated .data() call result.
|
||||
values.push_back(arg + char(0));
|
||||
};
|
||||
push(!argv0.empty() ? argv0 : fullBinaryPath);
|
||||
push("-noupdate");
|
||||
if (autostart) push("-autostart");
|
||||
if (debug) push("-debug");
|
||||
if (startintray) push("-startintray");
|
||||
if (tosettings) push("-tosettings");
|
||||
if (key) {
|
||||
push("-key");
|
||||
push(key);
|
||||
}
|
||||
if (customWorkingDir && workdir) {
|
||||
push("-workdir");
|
||||
push(workdir);
|
||||
}
|
||||
|
||||
auto args = vector<char*>();
|
||||
for (auto &arg : values) {
|
||||
args.push_back(arg.data());
|
||||
}
|
||||
args.push_back(nullptr);
|
||||
|
||||
// let the parent launch instead
|
||||
if (!writeprotected) {
|
||||
if (justUpdate) {
|
||||
writeLog("Closing log and quitting..");
|
||||
} else {
|
||||
const auto fullBinaryPath = exePath + exeName;
|
||||
|
||||
auto values = vector<string>();
|
||||
const auto push = [&](string arg) {
|
||||
// Force null-terminated .data() call result.
|
||||
values.push_back(arg + char(0));
|
||||
};
|
||||
push(!argv0.empty() ? argv0 : fullBinaryPath);
|
||||
push("-noupdate");
|
||||
if (autostart) push("-autostart");
|
||||
if (debug) push("-debug");
|
||||
if (startintray) push("-startintray");
|
||||
if (tosettings) push("-tosettings");
|
||||
if (key) {
|
||||
push("-key");
|
||||
push(key);
|
||||
}
|
||||
if (customWorkingDir && workdir) {
|
||||
push("-workdir");
|
||||
push(workdir);
|
||||
}
|
||||
|
||||
auto args = vector<char*>();
|
||||
for (auto &arg : values) {
|
||||
args.push_back(arg.data());
|
||||
}
|
||||
args.push_back(nullptr);
|
||||
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
@@ -503,9 +509,10 @@ int main(int argc, char *argv[]) {
|
||||
execv(fullBinaryPath.c_str(), args.data());
|
||||
return 1;
|
||||
}
|
||||
|
||||
writeLog("Executed Telegram, closing log and quitting..");
|
||||
}
|
||||
|
||||
writeLog("Executed Telegram, closing log and quitting..");
|
||||
closeLog();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -77,45 +77,59 @@ void BlockedPeers::block(not_null<PeerData*> peer) {
|
||||
_session->changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
|
||||
const auto requestId = _api.request(MTPcontacts_Block(
|
||||
MTP_flags(0),
|
||||
peer->input
|
||||
)).done([=] {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(true);
|
||||
if (_slice) {
|
||||
_slice->list.insert(
|
||||
_slice->list.begin(),
|
||||
{ peer->id, base::unixtime::now() });
|
||||
++_slice->total;
|
||||
_changes.fire_copy(*_slice);
|
||||
}
|
||||
}).fail([=] {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
return;
|
||||
} else if (blockAlreadySent(peer, true)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPcontacts_Block(
|
||||
MTP_flags(0),
|
||||
peer->input
|
||||
)).done([=] {
|
||||
const auto data = _blockRequests.take(peer);
|
||||
peer->setIsBlocked(true);
|
||||
if (_slice) {
|
||||
_slice->list.insert(
|
||||
_slice->list.begin(),
|
||||
{ peer->id, base::unixtime::now() });
|
||||
++_slice->total;
|
||||
_changes.fire_copy(*_slice);
|
||||
}
|
||||
if (data) {
|
||||
for (const auto &callback : data->callbacks) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
}).fail([=] {
|
||||
if (const auto data = _blockRequests.take(peer)) {
|
||||
for (const auto &callback : data->callbacks) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
}).send();
|
||||
|
||||
_blockRequests.emplace(peer, Request{
|
||||
.requestId = requestId,
|
||||
.blocking = true,
|
||||
});
|
||||
}
|
||||
|
||||
void BlockedPeers::unblock(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> onDone,
|
||||
Fn<void(bool success)> done,
|
||||
bool force) {
|
||||
if (!force && !peer->isBlocked()) {
|
||||
_session->changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
return;
|
||||
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
|
||||
} else if (blockAlreadySent(peer, false, done)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPcontacts_Unblock(
|
||||
MTP_flags(0),
|
||||
peer->input
|
||||
)).done([=] {
|
||||
_blockRequests.erase(peer);
|
||||
const auto data = _blockRequests.take(peer);
|
||||
peer->setIsBlocked(false);
|
||||
if (_slice) {
|
||||
auto &list = _slice->list;
|
||||
@@ -130,13 +144,46 @@ void BlockedPeers::unblock(
|
||||
}
|
||||
_changes.fire_copy(*_slice);
|
||||
}
|
||||
if (onDone) {
|
||||
onDone();
|
||||
if (data) {
|
||||
for (const auto &callback : data->callbacks) {
|
||||
callback(true);
|
||||
}
|
||||
}
|
||||
}).fail([=] {
|
||||
_blockRequests.erase(peer);
|
||||
if (const auto data = _blockRequests.take(peer)) {
|
||||
for (const auto &callback : data->callbacks) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
}).send();
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
const auto i = _blockRequests.emplace(peer, Request{
|
||||
.requestId = requestId,
|
||||
.blocking = false,
|
||||
}).first;
|
||||
if (done) {
|
||||
i->second.callbacks.push_back(std::move(done));
|
||||
}
|
||||
}
|
||||
|
||||
bool BlockedPeers::blockAlreadySent(
|
||||
not_null<PeerData*> peer,
|
||||
bool blocking,
|
||||
Fn<void(bool success)> done) {
|
||||
const auto i = _blockRequests.find(peer);
|
||||
if (i == end(_blockRequests)) {
|
||||
return false;
|
||||
} else if (i->second.blocking == blocking) {
|
||||
if (done) {
|
||||
i->second.callbacks.push_back(std::move(done));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const auto callbacks = base::take(i->second.callbacks);
|
||||
_blockRequests.erase(i);
|
||||
for (const auto &callback : callbacks) {
|
||||
callback(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlockedPeers::reload() {
|
||||
@@ -160,7 +207,7 @@ auto BlockedPeers::slice() -> rpl::producer<BlockedPeers::Slice> {
|
||||
: (_changes.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) {
|
||||
void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> done) {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
@@ -170,7 +217,7 @@ void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) {
|
||||
MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice)
|
||||
)).done([=](const MTPcontacts_Blocked &result) {
|
||||
_requestId = 0;
|
||||
onDone(TLToSlice(result, _session->data()));
|
||||
done(TLToSlice(result, _session->data()));
|
||||
}).fail([=] {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
|
||||
@@ -39,20 +39,31 @@ public:
|
||||
|
||||
void reload();
|
||||
rpl::producer<Slice> slice();
|
||||
void request(int offset, Fn<void(Slice)> onDone);
|
||||
void request(int offset, Fn<void(Slice)> done);
|
||||
|
||||
void block(not_null<PeerData*> peer);
|
||||
void unblock(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> onDone = nullptr,
|
||||
Fn<void(bool success)> done = nullptr,
|
||||
bool force = false);
|
||||
|
||||
private:
|
||||
struct Request {
|
||||
std::vector<Fn<void(bool success)>> callbacks;
|
||||
mtpRequestId requestId = 0;
|
||||
bool blocking = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool blockAlreadySent(
|
||||
not_null<PeerData*> peer,
|
||||
bool blocking,
|
||||
Fn<void(bool success)> done = nullptr);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
|
||||
base::flat_map<not_null<PeerData*>, Request> _blockRequests;
|
||||
mtpRequestId _requestId = 0;
|
||||
std::optional<Slice> _slice;
|
||||
rpl::event_stream<Slice> _changes;
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "info/profile/info_profile_badge.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
@@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace Api {
|
||||
@@ -195,6 +197,13 @@ ConfirmInviteBox::ConfirmInviteBox(
|
||||
: _session(session)
|
||||
, _submit(std::move(submit))
|
||||
, _title(this, st::confirmInviteTitle)
|
||||
, _badge(std::make_unique<Info::Profile::Badge>(
|
||||
this,
|
||||
st::infoPeerBadge,
|
||||
_session,
|
||||
rpl::single(Info::Profile::Badge::Content{ BadgeForInvite(invite) }),
|
||||
nullptr,
|
||||
[=] { return false; }))
|
||||
, _status(this, st::confirmInviteStatus)
|
||||
, _about(this, st::confirmInviteAbout)
|
||||
, _aboutRequests(this, st::confirmInviteStatus)
|
||||
@@ -275,9 +284,24 @@ ConfirmInviteBox::ChatInvite ConfirmInviteBox::Parse(
|
||||
.isMegagroup = data.is_megagroup(),
|
||||
.isBroadcast = data.is_broadcast(),
|
||||
.isRequestNeeded = data.is_request_needed(),
|
||||
.isFake = data.is_fake(),
|
||||
.isScam = data.is_scam(),
|
||||
.isVerified = data.is_verified(),
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] Info::Profile::BadgeType ConfirmInviteBox::BadgeForInvite(
|
||||
const ChatInvite &invite) {
|
||||
using Type = Info::Profile::BadgeType;
|
||||
return invite.isVerified
|
||||
? Type::Verified
|
||||
: invite.isScam
|
||||
? Type::Scam
|
||||
: invite.isFake
|
||||
? Type::Fake
|
||||
: Type::None;
|
||||
}
|
||||
|
||||
void ConfirmInviteBox::prepare() {
|
||||
addButton(
|
||||
(_requestApprove
|
||||
@@ -326,8 +350,26 @@ void ConfirmInviteBox::prepare() {
|
||||
|
||||
void ConfirmInviteBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
_title->move((width() - _title->width()) / 2, st::confirmInviteTitleTop);
|
||||
_status->move((width() - _status->width()) / 2, st::confirmInviteStatusTop);
|
||||
|
||||
const auto padding = st::boxRowPadding;
|
||||
auto nameWidth = width() - padding.left() - padding.right();
|
||||
auto badgeWidth = 0;
|
||||
if (const auto widget = _badge->widget()) {
|
||||
badgeWidth = st::infoVerifiedCheckPosition.x() + widget->width();
|
||||
nameWidth -= badgeWidth;
|
||||
}
|
||||
_title->resizeToWidth(std::min(nameWidth, _title->textMaxWidth()));
|
||||
_title->moveToLeft(
|
||||
(width() - _title->width() - badgeWidth) / 2,
|
||||
st::confirmInviteTitleTop);
|
||||
const auto badgeLeft = _title->x() + _title->width();
|
||||
const auto badgeTop = _title->y();
|
||||
const auto badgeBottom = _title->y() + _title->height();
|
||||
_badge->move(badgeLeft, badgeTop, badgeBottom);
|
||||
|
||||
_status->move(
|
||||
(width() - _status->width()) / 2,
|
||||
st::confirmInviteStatusTop);
|
||||
auto bottom = _status->y()
|
||||
+ _status->height()
|
||||
+ st::boxPadding.bottom()
|
||||
|
||||
@@ -12,6 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
class UserData;
|
||||
class ChannelData;
|
||||
|
||||
namespace Info::Profile {
|
||||
class Badge;
|
||||
enum class BadgeType;
|
||||
} // namespace Info::Profile
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
@@ -66,10 +71,15 @@ private:
|
||||
bool isMegagroup = false;
|
||||
bool isBroadcast = false;
|
||||
bool isRequestNeeded = false;
|
||||
bool isFake = false;
|
||||
bool isScam = false;
|
||||
bool isVerified = false;
|
||||
};
|
||||
[[nodiscard]] static ChatInvite Parse(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDchatInvite &data);
|
||||
[[nodiscard]] Info::Profile::BadgeType BadgeForInvite(
|
||||
const ChatInvite &invite);
|
||||
|
||||
ConfirmInviteBox(
|
||||
not_null<Main::Session*> session,
|
||||
@@ -81,12 +91,14 @@ private:
|
||||
|
||||
Fn<void()> _submit;
|
||||
object_ptr<Ui::FlatLabel> _title;
|
||||
std::unique_ptr<Info::Profile::Badge> _badge;
|
||||
object_ptr<Ui::FlatLabel> _status;
|
||||
object_ptr<Ui::FlatLabel> _about;
|
||||
object_ptr<Ui::FlatLabel> _aboutRequests;
|
||||
std::shared_ptr<Data::PhotoMedia> _photo;
|
||||
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
|
||||
std::vector<Participant> _participants;
|
||||
|
||||
bool _isChannel = false;
|
||||
bool _requestApprove = false;
|
||||
|
||||
|
||||
@@ -78,12 +78,8 @@ void SendReport(
|
||||
MTP_string(comment)
|
||||
)).done(std::move(done)).send();
|
||||
}, [&](StoryId id) {
|
||||
const auto user = peer->asUser();
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
peer->session().api().request(MTPstories_Report(
|
||||
user->inputUser,
|
||||
peer->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(id)),
|
||||
ReasonToTL(reason),
|
||||
MTP_string(comment)
|
||||
|
||||
@@ -17,11 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto TestApiId = 17349;
|
||||
constexpr auto SnapApiId = 611335;
|
||||
constexpr auto DesktopApiId = 2040;
|
||||
|
||||
Websites::Entry ParseEntry(
|
||||
[[nodiscard]] Websites::Entry ParseEntry(
|
||||
not_null<Data::Session*> owner,
|
||||
const MTPDwebAuthorization &data) {
|
||||
auto result = Websites::Entry{
|
||||
|
||||
@@ -776,10 +776,9 @@ QString ApiWrap::exportDirectMessageLink(
|
||||
|
||||
QString ApiWrap::exportDirectStoryLink(not_null<Data::Story*> story) {
|
||||
const auto storyId = story->fullId();
|
||||
const auto user = story->peer()->asUser();
|
||||
Assert(user != nullptr);
|
||||
const auto peer = story->peer();
|
||||
const auto fallback = [&] {
|
||||
const auto base = user->username();
|
||||
const auto base = peer->userName();
|
||||
const auto story = QString::number(storyId.story);
|
||||
const auto query = base + "/s/" + story;
|
||||
return session().createInternalLinkFull(query);
|
||||
@@ -789,7 +788,7 @@ QString ApiWrap::exportDirectStoryLink(not_null<Data::Story*> story) {
|
||||
? i->second
|
||||
: fallback();
|
||||
request(MTPstories_ExportStoryLink(
|
||||
story->peer()->asUser()->inputUser,
|
||||
peer->input,
|
||||
MTP_int(story->id())
|
||||
)).done([=](const MTPExportedStoryLink &result) {
|
||||
const auto link = qs(result.data().vlink());
|
||||
@@ -1887,17 +1886,8 @@ void ApiWrap::sendNotifySettingsUpdates() {
|
||||
}
|
||||
const auto &settings = session().data().notifySettings();
|
||||
for (const auto type : base::take(_updateNotifyDefaults)) {
|
||||
const auto input = [&] {
|
||||
switch (type) {
|
||||
case Data::DefaultNotify::User: return MTP_inputNotifyUsers();
|
||||
case Data::DefaultNotify::Group: return MTP_inputNotifyChats();
|
||||
case Data::DefaultNotify::Broadcast:
|
||||
return MTP_inputNotifyBroadcasts();
|
||||
}
|
||||
Unexpected("Default notify type in sendNotifySettingsUpdates");
|
||||
}();
|
||||
request(MTPaccount_UpdateNotifySettings(
|
||||
input,
|
||||
Data::DefaultNotifyToMTP(type),
|
||||
settings.defaultSettings(type).serialize()
|
||||
)).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
@@ -2445,7 +2435,13 @@ void ApiWrap::refreshFileReference(
|
||||
};
|
||||
v::match(origin.data, [&](Data::FileOriginMessage data) {
|
||||
if (const auto item = _session->data().message(data)) {
|
||||
if (item->isScheduled()) {
|
||||
const auto media = item->media();
|
||||
const auto storyId = media ? media->storyId() : FullStoryId();
|
||||
if (storyId) {
|
||||
request(MTPstories_GetStoriesByID(
|
||||
_session->data().peer(storyId.peer)->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(storyId.story))));
|
||||
} else if (item->isScheduled()) {
|
||||
const auto &scheduled = _session->data().scheduledMessages();
|
||||
const auto realId = scheduled.lookupId(item);
|
||||
request(MTPmessages_GetScheduledMessages(
|
||||
@@ -2542,14 +2538,9 @@ void ApiWrap::refreshFileReference(
|
||||
}, [&](Data::FileOriginPremiumPreviews data) {
|
||||
request(MTPhelp_GetPremiumPromo());
|
||||
}, [&](Data::FileOriginStory data) {
|
||||
const auto user = _session->data().peer(data.peerId)->asUser();
|
||||
if (user) {
|
||||
request(MTPstories_GetStoriesByID(
|
||||
user->inputUser,
|
||||
MTP_vector<MTPint>(1, MTP_int(data.storyId))));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
request(MTPstories_GetStoriesByID(
|
||||
_session->data().peer(data.peerId)->input,
|
||||
MTP_vector<MTPint>(1, MTP_int(data.storyId))));
|
||||
}, [&](v::null_t) {
|
||||
fail();
|
||||
});
|
||||
@@ -3329,25 +3320,37 @@ void ApiWrap::shareContact(
|
||||
const QString &phone,
|
||||
const QString &firstName,
|
||||
const QString &lastName,
|
||||
const SendAction &action) {
|
||||
const SendAction &action,
|
||||
Fn<void(bool)> done) {
|
||||
const auto userId = UserId(0);
|
||||
sendSharedContact(phone, firstName, lastName, userId, action);
|
||||
sendSharedContact(
|
||||
phone,
|
||||
firstName,
|
||||
lastName,
|
||||
userId,
|
||||
action,
|
||||
std::move(done));
|
||||
}
|
||||
|
||||
void ApiWrap::shareContact(
|
||||
not_null<UserData*> user,
|
||||
const SendAction &action) {
|
||||
const SendAction &action,
|
||||
Fn<void(bool)> done) {
|
||||
const auto userId = peerToUser(user->id);
|
||||
const auto phone = _session->data().findContactPhone(user);
|
||||
if (phone.isEmpty()) {
|
||||
if (done) {
|
||||
done(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
sendSharedContact(
|
||||
return sendSharedContact(
|
||||
phone,
|
||||
user->firstName,
|
||||
user->lastName,
|
||||
userId,
|
||||
action);
|
||||
action,
|
||||
std::move(done));
|
||||
}
|
||||
|
||||
void ApiWrap::sendSharedContact(
|
||||
@@ -3355,7 +3358,8 @@ void ApiWrap::sendSharedContact(
|
||||
const QString &firstName,
|
||||
const QString &lastName,
|
||||
UserId userId,
|
||||
const SendAction &action) {
|
||||
const SendAction &action,
|
||||
Fn<void(bool)> done) {
|
||||
sendAction(action);
|
||||
|
||||
const auto history = action.history;
|
||||
@@ -3406,7 +3410,7 @@ void ApiWrap::sendSharedContact(
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName),
|
||||
MTP_string()); // vcard
|
||||
sendMedia(item, media, action.options);
|
||||
sendMedia(item, media, action.options, std::move(done));
|
||||
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
_session->changes().historyUpdated(
|
||||
@@ -3937,18 +3941,20 @@ void ApiWrap::uploadAlbumMedia(
|
||||
void ApiWrap::sendMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputMedia &media,
|
||||
Api::SendOptions options) {
|
||||
Api::SendOptions options,
|
||||
Fn<void(bool)> done) {
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
_session->data().registerMessageRandomId(randomId, item->fullId());
|
||||
|
||||
sendMediaWithRandomId(item, media, options, randomId);
|
||||
sendMediaWithRandomId(item, media, options, randomId, std::move(done));
|
||||
}
|
||||
|
||||
void ApiWrap::sendMediaWithRandomId(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputMedia &media,
|
||||
Api::SendOptions options,
|
||||
uint64 randomId) {
|
||||
uint64 randomId,
|
||||
Fn<void(bool)> done) {
|
||||
const auto history = item->history();
|
||||
const auto replyTo = item->replyTo();
|
||||
|
||||
@@ -3990,10 +3996,12 @@ void ApiWrap::sendMediaWithRandomId(
|
||||
MTP_int(options.scheduled),
|
||||
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty())
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (done) done(true);
|
||||
if (updateRecentStickers) {
|
||||
requestRecentStickersForce(true);
|
||||
}
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (done) done(false);
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -294,8 +294,12 @@ public:
|
||||
const QString &phone,
|
||||
const QString &firstName,
|
||||
const QString &lastName,
|
||||
const SendAction &action);
|
||||
void shareContact(not_null<UserData*> user, const SendAction &action);
|
||||
const SendAction &action,
|
||||
Fn<void(bool)> done = nullptr);
|
||||
void shareContact(
|
||||
not_null<UserData*> user,
|
||||
const SendAction &action,
|
||||
Fn<void(bool)> done = nullptr);
|
||||
void applyAffectedMessages(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPmessages_AffectedMessages &result);
|
||||
@@ -489,7 +493,8 @@ private:
|
||||
const QString &firstName,
|
||||
const QString &lastName,
|
||||
UserId userId,
|
||||
const SendAction &action);
|
||||
const SendAction &action,
|
||||
Fn<void(bool)> done);
|
||||
|
||||
void deleteHistory(
|
||||
not_null<PeerData*> peer,
|
||||
@@ -516,12 +521,14 @@ private:
|
||||
void sendMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputMedia &media,
|
||||
Api::SendOptions options);
|
||||
Api::SendOptions options,
|
||||
Fn<void(bool)> done = nullptr);
|
||||
void sendMediaWithRandomId(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPInputMedia &media,
|
||||
Api::SendOptions options,
|
||||
uint64 randomId);
|
||||
uint64 randomId,
|
||||
Fn<void(bool)> done = nullptr);
|
||||
FileLoadTo fileLoadTaskOptions(const SendAction &action) const;
|
||||
|
||||
void getTopPromotionDelayed(TimeId now, TimeId next);
|
||||
|
||||
@@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/fields/special_fields.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/text/format_values.h"
|
||||
@@ -297,8 +298,11 @@ void AddContactBox::prepare() {
|
||||
: tr::lng_enter_contact_data());
|
||||
updateButtons();
|
||||
|
||||
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
|
||||
const auto submitted = [=] { submit(); };
|
||||
_first->submits(
|
||||
) | rpl::start_with_next(submitted, _first->lifetime());
|
||||
_last->submits(
|
||||
) | rpl::start_with_next(submitted, _last->lifetime());
|
||||
connect(_phone, &Ui::PhoneInput::submitted, [=] { submit(); });
|
||||
|
||||
setDimensions(
|
||||
@@ -567,23 +571,24 @@ void GroupInfoBox::prepare() {
|
||||
_description->setSubmitSettings(
|
||||
Core::App().settings().sendSubmitWay());
|
||||
|
||||
connect(_description, &Ui::InputField::resized, [=] {
|
||||
_description->heightChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
descriptionResized();
|
||||
});
|
||||
connect(_description, &Ui::InputField::submitted, [=] {
|
||||
submit();
|
||||
});
|
||||
connect(_description, &Ui::InputField::cancelled, [=] {
|
||||
}, _description->lifetime());
|
||||
_description->submits(
|
||||
) | rpl::start_with_next([=] { submit(); }, _description->lifetime());
|
||||
_description->cancelled(
|
||||
) | rpl::start_with_next([=] {
|
||||
closeBox();
|
||||
});
|
||||
}, _description->lifetime());
|
||||
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
getDelegate()->outerContainer(),
|
||||
_description,
|
||||
&_navigation->session());
|
||||
}
|
||||
|
||||
connect(_title, &Ui::InputField::submitted, [=] { submitName(); });
|
||||
_title->submits(
|
||||
) | rpl::start_with_next([=] { submitName(); }, _title->lifetime());
|
||||
|
||||
addButton(
|
||||
((_type != Type::Group || _canAddBot)
|
||||
@@ -1522,20 +1527,22 @@ void EditNameBox::prepare() {
|
||||
_first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
_last->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
|
||||
connect(_first, &Ui::InputField::submitted, [=] { submit(); });
|
||||
connect(_last, &Ui::InputField::submitted, [=] { submit(); });
|
||||
_first->submits(
|
||||
) | rpl::start_with_next([=] { submit(); }, _first->lifetime());
|
||||
_last->submits(
|
||||
) | rpl::start_with_next([=] { submit(); }, _last->lifetime());
|
||||
|
||||
_first->customTab(true);
|
||||
_last->customTab(true);
|
||||
|
||||
QObject::connect(
|
||||
_first,
|
||||
&Ui::InputField::tabbed,
|
||||
[=] { _last->setFocus(); });
|
||||
QObject::connect(
|
||||
_last,
|
||||
&Ui::InputField::tabbed,
|
||||
[=] { _first->setFocus(); });
|
||||
_first->tabbed(
|
||||
) | rpl::start_with_next([=] {
|
||||
_last->setFocus();
|
||||
}, _first->lifetime());
|
||||
_last->tabbed(
|
||||
) | rpl::start_with_next([=] {
|
||||
_first->setFocus();
|
||||
}, _last->lifetime());
|
||||
}
|
||||
|
||||
void EditNameBox::setInnerFocus() {
|
||||
|
||||
@@ -15,14 +15,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::Bold
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_payments.h" // paymentsSectionButton
|
||||
#include "styles/style_media_player.h" // mediaPlayerMenuCheck
|
||||
|
||||
namespace {
|
||||
@@ -32,14 +29,28 @@ Data::ChatFilter ChangedFilter(
|
||||
not_null<History*> history,
|
||||
bool add) {
|
||||
auto always = base::duplicate(filter.always());
|
||||
if (add) {
|
||||
always.insert(history);
|
||||
} else {
|
||||
always.remove(history);
|
||||
}
|
||||
auto never = base::duplicate(filter.never());
|
||||
if (add) {
|
||||
never.remove(history);
|
||||
} else {
|
||||
always.remove(history);
|
||||
}
|
||||
const auto result = Data::ChatFilter(
|
||||
filter.id(),
|
||||
filter.title(),
|
||||
filter.iconEmoji(),
|
||||
filter.flags(),
|
||||
std::move(always),
|
||||
filter.pinned(),
|
||||
std::move(never));
|
||||
const auto in = result.contains(history);
|
||||
if (in == add) {
|
||||
return result;
|
||||
}
|
||||
always = base::duplicate(result.always());
|
||||
never = base::duplicate(result.never());
|
||||
if (add) {
|
||||
always.insert(history);
|
||||
} else {
|
||||
never.insert(history);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mtproto/facade.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/fields/number_input.h"
|
||||
#include "ui/widgets/fields/password_input.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
|
||||
@@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
@@ -184,7 +184,8 @@ not_null<Ui::FlatLabel*> CreateWarningLabel(
|
||||
QString(),
|
||||
st::createPollWarning);
|
||||
result->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
QObject::connect(field, &Ui::InputField::changed, [=] {
|
||||
field->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
Ui::PostponeCall(crl::guard(field, [=] {
|
||||
const auto length = field->getLastText().size();
|
||||
const auto value = valueLimit - length;
|
||||
@@ -198,7 +199,7 @@ not_null<Ui::FlatLabel*> CreateWarningLabel(
|
||||
}
|
||||
result->setVisible(shown);
|
||||
}));
|
||||
});
|
||||
}, field->lifetime());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -243,13 +244,14 @@ Options::Option::Option(
|
||||
_content->resize(_content->width(), height);
|
||||
}, _field->lifetime());
|
||||
|
||||
QObject::connect(_field, &Ui::InputField::changed, [=] {
|
||||
_field->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
Ui::PostponeCall(crl::guard(_field, [=] {
|
||||
if (_hasCorrect) {
|
||||
_correct->toggle(isGood(), anim::type::normal);
|
||||
}
|
||||
}));
|
||||
});
|
||||
}, _field->lifetime());
|
||||
|
||||
createShadow();
|
||||
createRemove();
|
||||
@@ -303,10 +305,11 @@ void Options::Option::createRemove() {
|
||||
const auto toggle = lifetime.make_state<rpl::variable<bool>>(false);
|
||||
_removeAlways = lifetime.make_state<rpl::variable<bool>>(false);
|
||||
|
||||
QObject::connect(field, &Ui::InputField::changed, [=] {
|
||||
field->changes(
|
||||
) | rpl::start_with_next([field, toggle] {
|
||||
// Don't capture 'this'! Because Option is a value type.
|
||||
*toggle = !field->getLastText().isEmpty();
|
||||
});
|
||||
}, field->lifetime());
|
||||
rpl::combine(
|
||||
toggle->value(),
|
||||
_removeAlways->value(),
|
||||
@@ -649,28 +652,32 @@ void Options::addEmptyOption() {
|
||||
_position + _list.size() + _destroyed.size(),
|
||||
_chooseCorrectGroup));
|
||||
const auto field = _list.back()->field();
|
||||
QObject::connect(field, &Ui::InputField::submitted, [=] {
|
||||
field->submits(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto index = findField(field);
|
||||
if (_list[index]->isGood() && index + 1 < _list.size()) {
|
||||
_list[index + 1]->setFocus();
|
||||
}
|
||||
});
|
||||
QObject::connect(field, &Ui::InputField::changed, [=] {
|
||||
}, field->lifetime());
|
||||
field->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
Ui::PostponeCall(crl::guard(field, [=] {
|
||||
validateState();
|
||||
}));
|
||||
});
|
||||
QObject::connect(field, &Ui::InputField::focused, [=] {
|
||||
}, field->lifetime());
|
||||
field->focusedChanges(
|
||||
) | rpl::filter(rpl::mappers::_1) | rpl::start_with_next([=] {
|
||||
_scrollToWidget.fire_copy(field);
|
||||
});
|
||||
QObject::connect(field, &Ui::InputField::tabbed, [=] {
|
||||
}, field->lifetime());
|
||||
field->tabbed(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto index = findField(field);
|
||||
if (index + 1 < _list.size()) {
|
||||
_list[index + 1]->setFocus();
|
||||
} else {
|
||||
_tabbed.fire({});
|
||||
}
|
||||
});
|
||||
}, field->lifetime());
|
||||
base::install_event_filter(field, [=](not_null<QEvent*> event) {
|
||||
if (event->type() != QEvent::KeyPress
|
||||
|| !field->getLastText().isEmpty()) {
|
||||
@@ -927,9 +934,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||
st::boxDividerLabel),
|
||||
st::createPollLimitPadding));
|
||||
|
||||
connect(question, &Ui::InputField::tabbed, [=] {
|
||||
question->tabbed(
|
||||
) | rpl::start_with_next([=] {
|
||||
options->focusFirst();
|
||||
});
|
||||
}, question->lifetime());
|
||||
|
||||
AddSkip(container);
|
||||
AddSubsectionTitle(container, tr::lng_polls_create_settings());
|
||||
@@ -975,9 +983,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||
}
|
||||
}, question->lifetime());
|
||||
|
||||
connect(solution, &Ui::InputField::tabbed, [=] {
|
||||
solution->tabbed(
|
||||
) | rpl::start_with_next([=] {
|
||||
question->setFocus();
|
||||
});
|
||||
}, solution->lifetime());
|
||||
|
||||
quiz->setDisabled(_disabled & PollData::Flag::Quiz);
|
||||
if (multiple) {
|
||||
@@ -1009,12 +1018,12 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||
const auto text = question->getLastText().trimmed();
|
||||
return !text.isEmpty() && (text.size() <= kQuestionLimit);
|
||||
};
|
||||
|
||||
connect(question, &Ui::InputField::submitted, [=] {
|
||||
question->submits(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (isValidQuestion()) {
|
||||
options->focusFirst();
|
||||
}
|
||||
});
|
||||
}, question->lifetime());
|
||||
|
||||
_setInnerFocus = [=] {
|
||||
question->setFocusFast();
|
||||
|
||||
@@ -54,7 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/painter.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
@@ -488,9 +488,16 @@ void EditCaptionBox::setupField() {
|
||||
Core::App().settings().sendSubmitWay());
|
||||
_field->setMaxHeight(st::defaultComposeFiles.caption.heightMax);
|
||||
|
||||
connect(_field, &Ui::InputField::submitted, [=] { save(); });
|
||||
connect(_field, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
connect(_field, &Ui::InputField::resized, [=] { captionResized(); });
|
||||
_field->submits(
|
||||
) | rpl::start_with_next([=] { save(); }, _field->lifetime());
|
||||
_field->cancelled(
|
||||
) | rpl::start_with_next([=] {
|
||||
closeBox();
|
||||
}, _field->lifetime());
|
||||
_field->heightChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
captionResized();
|
||||
}, _field->lifetime());
|
||||
_field->setMimeDataHook([=](
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
@@ -522,10 +529,11 @@ void EditCaptionBox::setInitialText() {
|
||||
setCloseByOutsideClick(true);
|
||||
}
|
||||
});
|
||||
connect(_field, &Ui::InputField::changed, [=] {
|
||||
_field->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
_checkChangedTimer.callOnce(kChangesDebounceTimeout);
|
||||
setCloseByOutsideClick(false);
|
||||
});
|
||||
}, _field->lifetime());
|
||||
}
|
||||
|
||||
void EditCaptionBox::setupControls() {
|
||||
@@ -622,9 +630,10 @@ void EditCaptionBox::setupDragArea() {
|
||||
};
|
||||
// Avoid both drag areas appearing at one time.
|
||||
auto computeState = [=](const QMimeData *data) {
|
||||
using DragState = Storage::MimeDataState;
|
||||
const auto state = Storage::ComputeMimeDataState(data);
|
||||
return (state == Storage::MimeDataState::PhotoFiles)
|
||||
? Storage::MimeDataState::Image
|
||||
return (state == DragState::PhotoFiles || state == DragState::Image)
|
||||
? (_asFile ? DragState::Files : DragState::Image)
|
||||
: state;
|
||||
};
|
||||
const auto areas = DragArea::SetupDragAreaToContainer(
|
||||
|
||||
@@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/effects/panel_animation.h"
|
||||
#include "ui/filter_icons.h"
|
||||
@@ -619,11 +619,12 @@ void EditFilterBox(
|
||||
nameEditing->custom = true;
|
||||
}, box->lifetime());
|
||||
|
||||
QObject::connect(name, &Ui::InputField::changed, [=] {
|
||||
name->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (!nameEditing->settingDefault) {
|
||||
nameEditing->custom = true;
|
||||
}
|
||||
});
|
||||
}, name->lifetime());
|
||||
const auto updateDefaultTitle = [=](const Data::ChatFilter &filter) {
|
||||
if (nameEditing->custom) {
|
||||
return;
|
||||
|
||||
@@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/controls/invite_link_label.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
|
||||
@@ -21,10 +21,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/fields/password_input.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/sent_code_field.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/painter.h"
|
||||
#include "passport/passport_encryption.h"
|
||||
@@ -306,15 +305,26 @@ void PasscodeBox::prepare() {
|
||||
connect(_oldPasscode, &Ui::MaskedInputField::changed, [=] { oldChanged(); });
|
||||
connect(_newPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
|
||||
connect(_reenterPasscode, &Ui::MaskedInputField::changed, [=] { newChanged(); });
|
||||
connect(_passwordHint, &Ui::InputField::changed, [=] { newChanged(); });
|
||||
connect(_recoverEmail, &Ui::InputField::changed, [=] { emailChanged(); });
|
||||
_passwordHint->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
newChanged();
|
||||
}, _passwordHint->lifetime());
|
||||
_recoverEmail->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (!_emailError.isEmpty()) {
|
||||
_emailError = QString();
|
||||
update();
|
||||
}
|
||||
}, _recoverEmail->lifetime());
|
||||
|
||||
const auto fieldSubmit = [=] { submit(); };
|
||||
connect(_oldPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
|
||||
connect(_newPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
|
||||
connect(_reenterPasscode, &Ui::MaskedInputField::submitted, fieldSubmit);
|
||||
connect(_passwordHint, &Ui::InputField::submitted, fieldSubmit);
|
||||
connect(_recoverEmail, &Ui::InputField::submitted, fieldSubmit);
|
||||
_passwordHint->submits(
|
||||
) | rpl::start_with_next(fieldSubmit, _passwordHint->lifetime());
|
||||
_recoverEmail->submits(
|
||||
) | rpl::start_with_next(fieldSubmit, _recoverEmail->lifetime());
|
||||
|
||||
_recover->addClickHandler([=] { recoverByEmail(); });
|
||||
|
||||
@@ -1061,13 +1071,6 @@ void PasscodeBox::newChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::emailChanged() {
|
||||
if (!_emailError.isEmpty()) {
|
||||
_emailError = QString();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::recoverByEmail() {
|
||||
if (!_cloudFields.hasRecovery) {
|
||||
Assert(_session != nullptr);
|
||||
@@ -1189,8 +1192,12 @@ void RecoverBox::prepare() {
|
||||
+ _recoverCode->height()
|
||||
+ st::passcodeTextLine));
|
||||
|
||||
connect(_recoverCode, &Ui::InputField::changed, [=] { codeChanged(); });
|
||||
connect(_recoverCode, &Ui::InputField::submitted, [=] { submit(); });
|
||||
_recoverCode->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
codeChanged();
|
||||
}, _recoverCode->lifetime());
|
||||
_recoverCode->submits(
|
||||
) | rpl::start_with_next([=] { submit(); }, _recoverCode->lifetime());
|
||||
}
|
||||
|
||||
void RecoverBox::paintEvent(QPaintEvent *e) {
|
||||
|
||||
@@ -90,7 +90,6 @@ private:
|
||||
void closeReplacedBy();
|
||||
void oldChanged();
|
||||
void newChanged();
|
||||
void emailChanged();
|
||||
void save(bool force = false);
|
||||
void badOldPasscode();
|
||||
void recoverByEmail();
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peer_list_box.h"
|
||||
|
||||
#include "history/history.h" // chatListNameSortKey.
|
||||
#include "main/session/session_show.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
@@ -396,6 +397,27 @@ void PeerListController::setSearchNoResultsText(const QString &text) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListController::sortByName() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(
|
||||
id,
|
||||
history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> PeerListController::rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
@@ -741,8 +763,8 @@ int PeerListRow::paintNameIconGetWidth(
|
||||
? st::dialogsVerifiedIconOver
|
||||
: st::dialogsVerifiedIcon),
|
||||
.premium = &(selected
|
||||
? st::dialogsPremiumIconOver
|
||||
: st::dialogsPremiumIcon),
|
||||
? st::dialogsPremiumIcon.over
|
||||
: st::dialogsPremiumIcon.icon),
|
||||
.scam = &(selected ? st::dialogsScamFgOver : st::dialogsScamFg),
|
||||
.premiumFg = &(selected
|
||||
? st::dialogsVerifiedIconBgOver
|
||||
|
||||
@@ -560,6 +560,8 @@ protected:
|
||||
delegate()->peerListSetSearchNoResults(std::move(noResults));
|
||||
}
|
||||
|
||||
void sortByName();
|
||||
|
||||
private:
|
||||
PeerListDelegate *_delegate = nullptr;
|
||||
std::unique_ptr<PeerListSearchController> _searchController = nullptr;
|
||||
|
||||
@@ -594,25 +594,6 @@ void ContactsBoxController::sort() {
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByName() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(id, history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByOnline() {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
|
||||
@@ -192,7 +192,6 @@ protected:
|
||||
|
||||
private:
|
||||
void sort();
|
||||
void sortByName();
|
||||
void sortByOnline();
|
||||
void rebuildRows();
|
||||
void checkForEmptyRows();
|
||||
|
||||
@@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "info/profile/info_profile_cover.h"
|
||||
@@ -239,8 +239,8 @@ void Controller::initNameFields(
|
||||
_save();
|
||||
}
|
||||
};
|
||||
QObject::connect(first, &Ui::InputField::submitted, submit);
|
||||
QObject::connect(last, &Ui::InputField::submitted, submit);
|
||||
first->submits() | rpl::start_with_next(submit, first->lifetime());
|
||||
last->submits() | rpl::start_with_next(submit, last->lifetime());
|
||||
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
first->setMaxLength(Ui::EditPeer::kMaxUserFirstLastName);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peers/edit_forum_topic_box.h"
|
||||
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/effects/emoji_fly_animation.h"
|
||||
#include "ui/abstract_button.h"
|
||||
@@ -465,15 +465,13 @@ void EditForumTopicBox(
|
||||
ChooseNextColorId(current.colorId, state->otherColorIds),
|
||||
};
|
||||
});
|
||||
base::qt_signal_producer(
|
||||
title,
|
||||
&Ui::InputField::changed
|
||||
title->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
state->defaultIcon = DefaultIcon{
|
||||
title->getLastText().trimmed(),
|
||||
state->defaultIcon.current().colorId,
|
||||
};
|
||||
}, box->lifetime());
|
||||
}, title->lifetime());
|
||||
|
||||
if (!topic || !topic->isGeneral()) {
|
||||
Settings::AddDividerText(
|
||||
|
||||
@@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/toast/toast.h"
|
||||
@@ -384,8 +384,11 @@ void EditAdminBox::prepare() {
|
||||
if (!_saveCallback) {
|
||||
return;
|
||||
} else if (_addAsAdmin && !_addAsAdmin->checked()) {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
AddBotToGroup(user(), peer(), _addingBot->token);
|
||||
getDelegate()->hideLayer();
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
return;
|
||||
} else if (_addingBot && !_addingBot->existing) {
|
||||
const auto phrase = peer()->isBroadcast()
|
||||
@@ -461,13 +464,14 @@ not_null<Ui::InputField*> EditAdminBox::addRankInput(
|
||||
st::rightsAboutMargin);
|
||||
result->setMaxLength(kAdminRoleLimit);
|
||||
result->setInstantReplaces(Ui::InstantReplaces::TextOnly());
|
||||
connect(result, &Ui::InputField::changed, [=] {
|
||||
result->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto text = result->getLastText();
|
||||
const auto removed = TextUtilities::RemoveEmoji(text);
|
||||
if (removed != text) {
|
||||
result->setText(removed);
|
||||
}
|
||||
});
|
||||
}, result->lifetime());
|
||||
|
||||
container->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
|
||||
@@ -51,7 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
@@ -519,10 +519,10 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
|
||||
result->entity(),
|
||||
&_peer->session());
|
||||
|
||||
QObject::connect(
|
||||
result->entity(),
|
||||
&Ui::InputField::submitted,
|
||||
[=] { submitTitle(); });
|
||||
result->entity()->submits(
|
||||
) | rpl::start_with_next([=] {
|
||||
submitTitle();
|
||||
}, result->entity()->lifetime());
|
||||
|
||||
_controls.title = result->entity();
|
||||
return result;
|
||||
@@ -555,10 +555,10 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
|
||||
result->entity(),
|
||||
&_peer->session());
|
||||
|
||||
QObject::connect(
|
||||
result->entity(),
|
||||
&Ui::InputField::submitted,
|
||||
[=] { submitDescription(); });
|
||||
result->entity()->submits(
|
||||
) | rpl::start_with_next([=] {
|
||||
submitDescription();
|
||||
}, result->entity()->lifetime());
|
||||
|
||||
_controls.description = result->entity();
|
||||
return result;
|
||||
|
||||
@@ -51,13 +51,14 @@ constexpr auto kForceDisableTooltipDuration = 3 * crl::time(1000);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto NestedRestrictionLabelsList(
|
||||
Data::RestrictionsSetOptions options) {
|
||||
Data::RestrictionsSetOptions options)
|
||||
-> std::vector<NestedEditFlagsLabels<ChatRestrictions>> {
|
||||
using Flag = ChatRestriction;
|
||||
|
||||
auto first = std::vector<RestrictionLabel>{
|
||||
{ Flag::SendOther, tr::lng_rights_chat_send_text(tr::now) },
|
||||
};
|
||||
auto inner = std::vector<RestrictionLabel>{
|
||||
auto media = std::vector<RestrictionLabel>{
|
||||
{ Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) },
|
||||
{ Flag::SendVideos, tr::lng_rights_chat_videos(tr::now) },
|
||||
{ Flag::SendVideoMessages, tr::lng_rights_chat_video_messages(tr::now) },
|
||||
@@ -85,9 +86,64 @@ constexpr auto kForceDisableTooltipDuration = 3 * crl::time(1000);
|
||||
&RestrictionLabel::flags),
|
||||
end(second));
|
||||
}
|
||||
return std::vector<NestedEditFlagsLabels<ChatRestrictions>>{
|
||||
return {
|
||||
{ std::nullopt, std::move(first) },
|
||||
{ tr::lng_rights_chat_send_media(), std::move(inner) },
|
||||
{ tr::lng_rights_chat_send_media(), std::move(media) },
|
||||
{ std::nullopt, std::move(second) },
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] auto NestedAdminRightLabels(
|
||||
Data::AdminRightsSetOptions options)
|
||||
-> std::vector<NestedEditFlagsLabels<ChatAdminRights>> {
|
||||
using Flag = ChatAdminRight;
|
||||
|
||||
if (options.isGroup) {
|
||||
auto result = std::vector<AdminRightLabel>{
|
||||
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
|
||||
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
|
||||
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
|
||||
{ Flag::InviteByLinkOrAdd, options.anyoneCanAddMembers
|
||||
? tr::lng_rights_group_invite_link(tr::now)
|
||||
: tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
|
||||
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
|
||||
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
|
||||
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
|
||||
};
|
||||
if (!options.isForum) {
|
||||
result.erase(
|
||||
ranges::remove(
|
||||
result,
|
||||
Flag::ManageTopics | Flag(),
|
||||
&AdminRightLabel::flags),
|
||||
end(result));
|
||||
}
|
||||
return { { std::nullopt, std::move(result) } };
|
||||
}
|
||||
auto first = std::vector<AdminRightLabel>{
|
||||
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
|
||||
};
|
||||
auto messages = std::vector<AdminRightLabel>{
|
||||
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
|
||||
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
|
||||
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
|
||||
};
|
||||
auto stories = std::vector<AdminRightLabel>{
|
||||
{ Flag::PostStories, tr::lng_rights_channel_post_stories(tr::now) },
|
||||
{ Flag::EditStories, tr::lng_rights_channel_edit_stories(tr::now) },
|
||||
{ Flag::DeleteStories, tr::lng_rights_channel_delete_stories(tr::now) },
|
||||
};
|
||||
auto second = std::vector<AdminRightLabel>{
|
||||
{ Flag::InviteByLinkOrAdd, tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
|
||||
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
|
||||
};
|
||||
return {
|
||||
{ std::nullopt, std::move(first) },
|
||||
{ tr::lng_rights_channel_manage(), std::move(messages) },
|
||||
{ tr::lng_rights_channel_manage_stories(), std::move(stories) },
|
||||
{ std::nullopt, std::move(second) },
|
||||
};
|
||||
}
|
||||
@@ -319,16 +375,15 @@ not_null<Ui::RpWidget*> AddInnerToggle(
|
||||
button->geometryValue(
|
||||
) | rpl::start_with_next([=](const QRect &r) {
|
||||
const auto w = st::rightsButtonToggleWidth;
|
||||
constexpr auto kLineWidth = int(1);
|
||||
toggleButton->setGeometry(
|
||||
r.x() + r.width() - w,
|
||||
r.y(),
|
||||
w,
|
||||
r.height());
|
||||
separator->setGeometry(
|
||||
toggleButton->x() - kLineWidth,
|
||||
toggleButton->x() - st::lineWidth,
|
||||
r.y() + (r.height() - separatorHeight) / 2,
|
||||
kLineWidth,
|
||||
st::lineWidth,
|
||||
separatorHeight);
|
||||
}, toggleButton->lifetime());
|
||||
|
||||
@@ -1032,42 +1087,11 @@ std::vector<RestrictionLabel> RestrictionLabels(
|
||||
|
||||
std::vector<AdminRightLabel> AdminRightLabels(
|
||||
Data::AdminRightsSetOptions options) {
|
||||
using Flag = ChatAdminRight;
|
||||
|
||||
if (options.isGroup) {
|
||||
auto result = std::vector<AdminRightLabel>{
|
||||
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
|
||||
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
|
||||
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
|
||||
{ Flag::InviteByLinkOrAdd, options.anyoneCanAddMembers
|
||||
? tr::lng_rights_group_invite_link(tr::now)
|
||||
: tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
|
||||
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
|
||||
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
|
||||
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
|
||||
};
|
||||
if (!options.isForum) {
|
||||
result.erase(
|
||||
ranges::remove(
|
||||
result,
|
||||
Flag::ManageTopics | Flag(),
|
||||
&AdminRightLabel::flags),
|
||||
end(result));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return {
|
||||
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
|
||||
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
|
||||
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
|
||||
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
|
||||
{ Flag::InviteByLinkOrAdd, tr::lng_rights_group_invite(tr::now) },
|
||||
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
|
||||
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
|
||||
};
|
||||
auto result = std::vector<AdminRightLabel>();
|
||||
for (const auto &[_, r] : NestedAdminRightLabels(options)) {
|
||||
result.insert(result.end(), r.begin(), r.end());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
|
||||
@@ -1108,7 +1132,7 @@ EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
|
||||
rights,
|
||||
{
|
||||
.header = std::move(header),
|
||||
.labels = { { std::nullopt, AdminRightLabels(options) } },
|
||||
.labels = NestedAdminRightLabels(options),
|
||||
.disabledMessages = std::move(disabledMessages),
|
||||
});
|
||||
result.widget = std::move(widget);
|
||||
|
||||
@@ -32,7 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
|
||||
@@ -48,19 +48,6 @@ struct InfographicDescriptor {
|
||||
bool complexRatio = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] rpl::producer<> BoxShowFinishes(not_null<Ui::GenericBox*> box) {
|
||||
const auto singleShot = box->lifetime().make_state<rpl::lifetime>();
|
||||
const auto showFinishes = singleShot->make_state<rpl::event_stream<>>();
|
||||
|
||||
box->setShowFinishedCallback([=] {
|
||||
showFinishes->fire({});
|
||||
singleShot->destroy();
|
||||
box->setShowFinishedCallback(nullptr);
|
||||
});
|
||||
|
||||
return showFinishes->events();
|
||||
}
|
||||
|
||||
void AddSubsectionTitle(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
rpl::producer<QString> text) {
|
||||
@@ -423,8 +410,9 @@ void SimpleLimitBox(
|
||||
Settings::AddSkip(top, st::premiumInfographicPadding.top());
|
||||
Ui::Premium::AddBubbleRow(
|
||||
top,
|
||||
st::defaultPremiumBubble,
|
||||
BoxShowFinishes(box),
|
||||
descriptor.defaultLimit,
|
||||
0,
|
||||
descriptor.current,
|
||||
descriptor.premiumLimit,
|
||||
premiumPossible,
|
||||
@@ -783,16 +771,18 @@ void FilterLinksLimitBox(
|
||||
|
||||
void FiltersLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session) {
|
||||
not_null<Main::Session*> session,
|
||||
std::optional<int> filtersCountOverride) {
|
||||
const auto premium = session->premium();
|
||||
const auto premiumPossible = session->premiumPossible();
|
||||
|
||||
const auto limits = Data::PremiumLimits(session);
|
||||
const auto defaultLimit = float64(limits.dialogFiltersDefault());
|
||||
const auto premiumLimit = float64(limits.dialogFiltersPremium());
|
||||
const auto current = float64(ranges::count_if(
|
||||
const auto cloud = int(ranges::count_if(
|
||||
session->data().chatsFilters().list(),
|
||||
[](const Data::ChatFilter &f) { return f.id() != FilterId(); }));
|
||||
const auto current = float64(filtersCountOverride.value_or(cloud));
|
||||
|
||||
auto text = rpl::combine(
|
||||
tr::lng_filters_limit1(
|
||||
@@ -1092,6 +1082,7 @@ void AccountsLimitBox(
|
||||
Settings::AddSkip(top, st::premiumInfographicPadding.top());
|
||||
Ui::Premium::AddBubbleRow(
|
||||
top,
|
||||
st::defaultPremiumBubble,
|
||||
BoxShowFinishes(box),
|
||||
0,
|
||||
current,
|
||||
|
||||
@@ -42,7 +42,8 @@ void FilterLinksLimitBox(
|
||||
not_null<Main::Session*> session);
|
||||
void FiltersLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
||||
not_null<Main::Session*> session,
|
||||
std::optional<int> filtersCountOverride);
|
||||
void ShareableFiltersLimitBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
@@ -28,12 +28,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/call_delayed.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/scroll_content_shadow.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
@@ -42,9 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/attach/attach_album_preview.h"
|
||||
#include "ui/chat/attach/attach_single_file_preview.h"
|
||||
#include "ui/chat/attach/attach_single_media_preview.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/grouped_layout.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
#include "ui/painter.h"
|
||||
@@ -54,16 +50,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "api/api_common.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
#include <QtCore/QMimeData>
|
||||
@@ -74,10 +67,14 @@ constexpr auto kMaxMessageLength = 4096;
|
||||
|
||||
using Ui::SendFilesWay;
|
||||
|
||||
inline bool CanAddUrls(const QList<QUrl> &urls) {
|
||||
[[nodiscard]] inline bool CanAddUrls(const QList<QUrl> &urls) {
|
||||
return !urls.isEmpty() && ranges::all_of(urls, &QUrl::isLocalFile);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool CanAddFiles(not_null<const QMimeData*> data) {
|
||||
return data->hasImage() || CanAddUrls(Core::ReadMimeUrls(data));
|
||||
}
|
||||
|
||||
void FileDialogCallback(
|
||||
FileDialog::OpenResult &&result,
|
||||
Fn<bool(const Ui::PreparedList&)> checkResult,
|
||||
@@ -445,13 +442,15 @@ void SendFilesBox::setupDragArea() {
|
||||
auto computeState = [=](const QMimeData *data) {
|
||||
using DragState = Storage::MimeDataState;
|
||||
const auto state = Storage::ComputeMimeDataState(data);
|
||||
return (state == DragState::PhotoFiles)
|
||||
? DragState::Image
|
||||
return (state == DragState::PhotoFiles || state == DragState::Image)
|
||||
? (_sendWay.current().sendImagesAsPhotos()
|
||||
? DragState::Image
|
||||
: DragState::Files)
|
||||
: state;
|
||||
};
|
||||
const auto areas = DragArea::SetupDragAreaToContainer(
|
||||
this,
|
||||
[=](not_null<const QMimeData*> d) { return canAddFiles(d); },
|
||||
CanAddFiles,
|
||||
[=](bool f) { _caption->setAcceptDrops(f); },
|
||||
[=] { updateControlsGeometry(); },
|
||||
std::move(computeState));
|
||||
@@ -1031,22 +1030,26 @@ void SendFilesBox::setupCaption() {
|
||||
Core::App().settings().sendSubmitWay());
|
||||
_caption->setMaxLength(kMaxMessageLength);
|
||||
|
||||
connect(_caption, &Ui::InputField::resized, [=] {
|
||||
_caption->heightChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
captionResized();
|
||||
});
|
||||
connect(_caption, &Ui::InputField::submitted, [=](
|
||||
Qt::KeyboardModifiers modifiers) {
|
||||
}, _caption->lifetime());
|
||||
_caption->submits(
|
||||
) | rpl::start_with_next([=](Qt::KeyboardModifiers modifiers) {
|
||||
const auto ctrlShiftEnter = modifiers.testFlag(Qt::ShiftModifier)
|
||||
&& (modifiers.testFlag(Qt::ControlModifier)
|
||||
|| modifiers.testFlag(Qt::MetaModifier));
|
||||
send({}, ctrlShiftEnter);
|
||||
});
|
||||
connect(_caption, &Ui::InputField::cancelled, [=] { closeBox(); });
|
||||
}, _caption->lifetime());
|
||||
_caption->cancelled(
|
||||
) | rpl::start_with_next([=] {
|
||||
closeBox();
|
||||
}, _caption->lifetime());
|
||||
_caption->setMimeDataHook([=](
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::InputField::MimeAction action) {
|
||||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return canAddFiles(data);
|
||||
return CanAddFiles(data);
|
||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||
return addFiles(data);
|
||||
}
|
||||
@@ -1142,10 +1145,6 @@ void SendFilesBox::captionResized() {
|
||||
update();
|
||||
}
|
||||
|
||||
bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
|
||||
return data->hasImage() || CanAddUrls(Core::ReadMimeUrls(data));
|
||||
}
|
||||
|
||||
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
|
||||
const auto premium = _show->session().premium();
|
||||
auto list = [&] {
|
||||
|
||||
@@ -213,7 +213,6 @@ private:
|
||||
void updateControlsGeometry();
|
||||
void updateCaptionPlaceholder();
|
||||
|
||||
bool canAddFiles(not_null<const QMimeData*> data) const;
|
||||
bool addFiles(not_null<const QMimeData*> data);
|
||||
bool addFiles(Ui::PreparedList list);
|
||||
void addFile(Ui::PreparedFile &&file);
|
||||
|
||||
@@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
@@ -144,7 +144,7 @@ void RenameBox(not_null<Ui::GenericBox*> box) {
|
||||
Core::App().settings().setCustomDeviceModel(result);
|
||||
Core::App().saveSettingsDelayed();
|
||||
};
|
||||
QObject::connect(name, &Ui::InputField::submitted, submit);
|
||||
name->submits() | rpl::start_with_next(submit, name->lifetime());
|
||||
box->addButton(tr::lng_settings_save(), submit);
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
@@ -18,9 +18,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/text/text_options.h"
|
||||
@@ -227,9 +226,8 @@ void ShareBox::prepareCommentField() {
|
||||
|
||||
const auto field = _comment->entity();
|
||||
|
||||
connect(field, &Ui::InputField::submitted, [=] {
|
||||
submit({});
|
||||
});
|
||||
field->submits(
|
||||
) | rpl::start_with_next([=] { submit({}); }, field->lifetime());
|
||||
if (const auto show = uiShow(); show->valid()) {
|
||||
InitMessageFieldHandlers(
|
||||
_descriptor.session,
|
||||
@@ -250,6 +248,8 @@ void ShareBox::prepareCommentField() {
|
||||
void ShareBox::prepare() {
|
||||
prepareCommentField();
|
||||
|
||||
setCloseByOutsideClick(false);
|
||||
|
||||
_select->resizeToWidth(st::boxWideWidth);
|
||||
Ui::SendPendingMoveResizeEvents(_select);
|
||||
|
||||
@@ -602,7 +602,7 @@ void ShareBox::submitWhenOnline() {
|
||||
submit(Api::DefaultSendWhenOnlineOptions());
|
||||
}
|
||||
|
||||
void ShareBox::copyLink() {
|
||||
void ShareBox::copyLink() const {
|
||||
if (const auto onstack = _descriptor.copyCallback) {
|
||||
onstack();
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ private:
|
||||
void submitSilent();
|
||||
void submitScheduled();
|
||||
void submitWhenOnline();
|
||||
void copyLink();
|
||||
void copyLink() const;
|
||||
bool searchByUsername(bool useCache = false);
|
||||
|
||||
SendMenu::Type sendMenuType() const;
|
||||
|
||||
@@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/effects/slide_animation.h"
|
||||
#include "ui/widgets/discrete_sliders.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "ui/painter.h"
|
||||
@@ -53,6 +53,22 @@ constexpr auto kArchivedLimitFirstRequest = 10;
|
||||
constexpr auto kArchivedLimitPerPage = 30;
|
||||
constexpr auto kHandleMegagroupSetAddressChangeTimeout = crl::time(1000);
|
||||
|
||||
[[nodiscard]] QString FillSetTitle(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth,
|
||||
int *outTitleWidth) {
|
||||
auto result = set->title;
|
||||
auto titleWidth = st::contactsNameStyle.font->width(result);
|
||||
if (titleWidth > maxNameWidth) {
|
||||
result = st::contactsNameStyle.font->elided(result, maxNameWidth);
|
||||
titleWidth = st::contactsNameStyle.font->width(result);
|
||||
}
|
||||
if (outTitleWidth) {
|
||||
*outTitleWidth = titleWidth;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class StickersBox::CounterWidget : public Ui::RpWidget {
|
||||
@@ -98,22 +114,25 @@ public:
|
||||
void updateRows(); // refresh only pack cover stickers
|
||||
bool appendSet(not_null<StickersSet*> set);
|
||||
|
||||
StickersSetsOrder getOrder() const;
|
||||
StickersSetsOrder getFullOrder() const;
|
||||
StickersSetsOrder getRemovedSets() const;
|
||||
StickersSetsOrder order() const;
|
||||
StickersSetsOrder fullOrder() const;
|
||||
StickersSetsOrder removedSets() const;
|
||||
|
||||
void setFullOrder(const StickersSetsOrder &order);
|
||||
void setRemovedSets(const StickersSetsOrder &removed);
|
||||
|
||||
void setRowRemovedBySetId(uint64 setId, bool removed);
|
||||
|
||||
void setInstallSetCallback(Fn<void(uint64 setId)> callback) {
|
||||
_installSetCallback = std::move(callback);
|
||||
}
|
||||
void setRemoveSetCallback(Fn<void(uint64 setId)> callback) {
|
||||
_removeSetCallback = std::move(callback);
|
||||
}
|
||||
void setLoadMoreCallback(Fn<void()> callback) {
|
||||
_loadMoreCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setMinHeight(int newWidth, int minHeight);
|
||||
|
||||
int getVisibleTop() const {
|
||||
return _visibleTop;
|
||||
}
|
||||
@@ -151,13 +170,13 @@ private:
|
||||
int32 pixh);
|
||||
~Row();
|
||||
|
||||
bool isRecentSet() const;
|
||||
bool isMasksSet() const;
|
||||
bool isEmojiSet() const;
|
||||
bool isWebm() const;
|
||||
bool isInstalled() const;
|
||||
bool isUnread() const;
|
||||
bool isArchived() const;
|
||||
[[nodiscard]] bool isRecentSet() const;
|
||||
[[nodiscard]] bool isMasksSet() const;
|
||||
[[nodiscard]] bool isEmojiSet() const;
|
||||
[[nodiscard]] bool isWebm() const;
|
||||
[[nodiscard]] bool isInstalled() const;
|
||||
[[nodiscard]] bool isUnread() const;
|
||||
[[nodiscard]] bool isArchived() const;
|
||||
|
||||
const not_null<StickersSet*> set;
|
||||
DocumentData *sticker = nullptr;
|
||||
@@ -212,7 +231,11 @@ private:
|
||||
void setPressed(SelectedRow pressed);
|
||||
void setup();
|
||||
QRect relativeButtonRect(bool removeButton, bool installedSet) const;
|
||||
void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
|
||||
void ensureRipple(
|
||||
const style::RippleAnimation &st,
|
||||
QImage mask,
|
||||
bool removeButton,
|
||||
bool installedSet);
|
||||
|
||||
bool shiftingAnimationCallback(crl::time now);
|
||||
void paintRow(Painter &p, not_null<Row*> row, int index);
|
||||
@@ -237,10 +260,6 @@ private:
|
||||
void rebuildAppendSet(not_null<StickersSet*> set);
|
||||
void fillSetCover(not_null<StickersSet*> set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
|
||||
int fillSetCount(not_null<StickersSet*> set) const;
|
||||
[[nodiscard]] QString fillSetTitle(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth,
|
||||
int *outTitleWidth) const;
|
||||
[[nodiscard]] Data::StickersSetFlags fillSetFlags(
|
||||
not_null<StickersSet*> set) const;
|
||||
void rebuildMegagroupSet();
|
||||
@@ -270,6 +289,7 @@ private:
|
||||
Ui::Animations::Basic _shiftingAnimation;
|
||||
|
||||
Fn<void(uint64 setId)> _installSetCallback;
|
||||
Fn<void(uint64 setId)> _removeSetCallback;
|
||||
Fn<void()> _loadMoreCallback;
|
||||
|
||||
int _visibleTop = 0;
|
||||
@@ -598,17 +618,43 @@ void StickersBox::prepare() {
|
||||
_attached.widget()->hide();
|
||||
}
|
||||
|
||||
const auto installCallback = [=](uint64 setId) { installSet(setId); };
|
||||
if (_featured.widget()) {
|
||||
_featured.widget()->setInstallSetCallback(installCallback);
|
||||
}
|
||||
if (_archived.widget()) {
|
||||
_archived.widget()->setInstallSetCallback(installCallback);
|
||||
_archived.widget()->setLoadMoreCallback([=] { loadMoreArchived(); });
|
||||
}
|
||||
if (_attached.widget()) {
|
||||
_attached.widget()->setInstallSetCallback(installCallback);
|
||||
_attached.widget()->setLoadMoreCallback([=] { showAttachedStickers(); });
|
||||
{
|
||||
const auto installCallback = [=](uint64 setId) { installSet(setId); };
|
||||
const auto markAsInstalledCallback = [=](uint64 setId) {
|
||||
if (_installed.widget()) {
|
||||
_installed.widget()->setRowRemovedBySetId(setId, false);
|
||||
}
|
||||
if (_featured.widget()) {
|
||||
_featured.widget()->setRowRemovedBySetId(setId, false);
|
||||
}
|
||||
};
|
||||
const auto markAsRemovedCallback = [=](uint64 setId) {
|
||||
if (_installed.widget()) {
|
||||
_installed.widget()->setRowRemovedBySetId(setId, true);
|
||||
}
|
||||
if (_featured.widget()) {
|
||||
_featured.widget()->setRowRemovedBySetId(setId, true);
|
||||
}
|
||||
};
|
||||
if (const auto installed = _installed.widget()) {
|
||||
installed->setInstallSetCallback(markAsInstalledCallback);
|
||||
installed->setRemoveSetCallback(markAsRemovedCallback);
|
||||
}
|
||||
if (const auto featured = _featured.widget()) {
|
||||
featured->setInstallSetCallback([=](uint64 setId) {
|
||||
markAsInstalledCallback(setId);
|
||||
installCallback(setId);
|
||||
});
|
||||
featured->setRemoveSetCallback(markAsRemovedCallback);
|
||||
}
|
||||
if (const auto archived = _archived.widget()) {
|
||||
archived->setInstallSetCallback(installCallback);
|
||||
archived->setLoadMoreCallback([=] { loadMoreArchived(); });
|
||||
}
|
||||
if (const auto attached = _attached.widget()) {
|
||||
attached->setInstallSetCallback(installCallback);
|
||||
attached->setLoadMoreCallback([=] { showAttachedStickers(); });
|
||||
}
|
||||
}
|
||||
|
||||
if (_megagroupSet) {
|
||||
@@ -634,7 +680,7 @@ void StickersBox::prepare() {
|
||||
} else { // _section == Section::Featured
|
||||
_tab = &_featured;
|
||||
}
|
||||
setInnerWidget(_tab->takeWidget(), getTopSkip());
|
||||
setInnerWidget(_tab->takeWidget(), topSkip());
|
||||
setDimensions(st::boxWideWidth, st::boxMaxListHeight);
|
||||
|
||||
session().data().stickers().updated(_isEmoji
|
||||
@@ -757,7 +803,7 @@ void StickersBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
if (_slideAnimation) {
|
||||
_slideAnimation->paintFrame(p, 0, getTopSkip(), width());
|
||||
_slideAnimation->paintFrame(p, 0, topSkip(), width());
|
||||
if (!_slideAnimation->animating()) {
|
||||
_slideAnimation.reset();
|
||||
setInnerVisible(true);
|
||||
@@ -774,7 +820,7 @@ void StickersBox::updateTabsGeometry() {
|
||||
_tabs->resizeToWidth(_tabIndices.size() * width() / maxTabs);
|
||||
_unreadBadge->setVisible(_tabIndices.contains(Section::Featured));
|
||||
|
||||
setInnerTopSkip(getTopSkip());
|
||||
setInnerTopSkip(topSkip());
|
||||
|
||||
auto featuredLeft = width() / maxTabs;
|
||||
auto featuredRight = 2 * width() / maxTabs;
|
||||
@@ -790,7 +836,7 @@ void StickersBox::updateTabsGeometry() {
|
||||
_tabs->moveToLeft(0, 0);
|
||||
}
|
||||
|
||||
int StickersBox::getTopSkip() const {
|
||||
int StickersBox::topSkip() const {
|
||||
return _tabs ? (_tabs->height() - st::lineWidth) : 0;
|
||||
}
|
||||
|
||||
@@ -819,8 +865,8 @@ void StickersBox::switchTab() {
|
||||
}
|
||||
|
||||
if (_tab == &_installed) {
|
||||
_localOrder = _tab->widget()->getFullOrder();
|
||||
_localRemoved = _tab->widget()->getRemovedSets();
|
||||
_localOrder = _tab->widget()->fullOrder();
|
||||
_localRemoved = _tab->widget()->removedSets();
|
||||
}
|
||||
auto wasCache = grabContentCache();
|
||||
auto wasIndex = _tab->index();
|
||||
@@ -831,12 +877,12 @@ void StickersBox::switchTab() {
|
||||
_tab->returnWidget(std::move(widget));
|
||||
_tab = newTab;
|
||||
_section = newSection;
|
||||
setInnerWidget(_tab->takeWidget(), getTopSkip());
|
||||
setInnerWidget(_tab->takeWidget(), topSkip());
|
||||
_tabs->raise();
|
||||
_unreadBadge->raise();
|
||||
_tab->widget()->show();
|
||||
rebuildList();
|
||||
scrollToY(_tab->getScrollTop());
|
||||
scrollToY(_tab->scrollTop());
|
||||
setInnerVisible(true);
|
||||
auto nowCache = grabContentCache();
|
||||
auto nowIndex = _tab->index();
|
||||
@@ -901,7 +947,7 @@ void StickersBox::installSet(uint64 setId) {
|
||||
}
|
||||
|
||||
void StickersBox::installDone(
|
||||
const MTPmessages_StickerSetInstallResult &result) {
|
||||
const MTPmessages_StickerSetInstallResult &result) const {
|
||||
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
|
||||
session().data().stickers().applyArchivedResult(
|
||||
result.c_messages_stickerSetInstallResultArchive());
|
||||
@@ -998,12 +1044,12 @@ void StickersBox::rebuildList(Tab *tab) {
|
||||
tab = _tab;
|
||||
}
|
||||
|
||||
if ((tab == &_installed) || (tab == &_masks)) {
|
||||
_localOrder = tab->widget()->getFullOrder();
|
||||
_localRemoved = tab->widget()->getRemovedSets();
|
||||
if ((tab == &_installed) || (tab == &_masks) || (_tab == &_featured)) {
|
||||
_localOrder = tab->widget()->fullOrder();
|
||||
_localRemoved = tab->widget()->removedSets();
|
||||
}
|
||||
tab->widget()->rebuild(_isMasks);
|
||||
if ((tab == &_installed) || (tab == &_masks)) {
|
||||
if ((tab == &_installed) || (tab == &_masks) || (_tab == &_featured)) {
|
||||
tab->widget()->setFullOrder(_localOrder);
|
||||
}
|
||||
tab->widget()->setRemovedSets(_localRemoved);
|
||||
@@ -1030,14 +1076,14 @@ void StickersBox::saveChanges() {
|
||||
}
|
||||
if (installed) {
|
||||
session().api().saveStickerSets(
|
||||
installed->getOrder(),
|
||||
installed->getRemovedSets(),
|
||||
installed->order(),
|
||||
installed->removedSets(),
|
||||
Data::StickersType::Stickers);
|
||||
}
|
||||
if (masks) {
|
||||
session().api().saveStickerSets(
|
||||
masks->getOrder(),
|
||||
masks->getRemovedSets(),
|
||||
masks->order(),
|
||||
masks->removedSets(),
|
||||
Data::StickersType::Masks);
|
||||
}
|
||||
}
|
||||
@@ -1056,7 +1102,7 @@ const Data::StickersSetsOrder &StickersBox::archivedSetsOrder() const {
|
||||
: session().data().stickers().archivedMaskSetsOrder();
|
||||
}
|
||||
|
||||
Data::StickersSetsOrder &StickersBox::archivedSetsOrderRef() {
|
||||
Data::StickersSetsOrder &StickersBox::archivedSetsOrderRef() const {
|
||||
return !_isMasks
|
||||
? session().data().stickers().archivedSetsOrderRef()
|
||||
: session().data().stickers().archivedMaskSetsOrderRef();
|
||||
@@ -1594,6 +1640,12 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int ind
|
||||
const auto textWidth = _installedWidth;
|
||||
const auto &text = _installedText;
|
||||
_inactiveButtonBg.paint(p, myrtlrect(rect));
|
||||
if (row->ripple) {
|
||||
row->ripple->paint(p, rect.x(), rect.y(), width());
|
||||
if (row->ripple->empty()) {
|
||||
row->ripple.reset();
|
||||
}
|
||||
}
|
||||
p.setFont(st.font);
|
||||
p.setPen(st.textFg);
|
||||
p.drawTextLeft(rect.x() - (st.width / 2), rect.y() + st.textTop, width(), text, textWidth);
|
||||
@@ -1673,16 +1725,27 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
|
||||
if (row->removed) {
|
||||
auto rippleSize = QSize(_undoWidth - st::stickersUndoRemove.width, st::stickersUndoRemove.height);
|
||||
auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusLarge);
|
||||
ensureRipple(st::stickersUndoRemove.ripple, std::move(rippleMask), removeButton);
|
||||
ensureRipple(st::stickersUndoRemove.ripple, std::move(rippleMask), removeButton, false);
|
||||
} else {
|
||||
auto rippleSize = st::stickersRemove.rippleAreaSize;
|
||||
auto rippleMask = Ui::RippleAnimation::EllipseMask(QSize(rippleSize, rippleSize));
|
||||
ensureRipple(st::stickersRemove.ripple, std::move(rippleMask), removeButton);
|
||||
ensureRipple(st::stickersRemove.ripple, std::move(rippleMask), removeButton, false);
|
||||
}
|
||||
} else if (!row->isInstalled() || row->isArchived() || row->removed) {
|
||||
auto rippleSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height);
|
||||
auto rippleMask = Ui::RippleAnimation::RoundRectMask(rippleSize, st::roundRadiusLarge);
|
||||
ensureRipple(st::stickersTrendingAdd.ripple, std::move(rippleMask), removeButton);
|
||||
} else {
|
||||
const auto installedSet = row->isInstalled()
|
||||
&& !row->isArchived()
|
||||
&& !row->removed;
|
||||
const auto &st = installedSet
|
||||
? st::stickersTrendingInstalled
|
||||
: st::stickersTrendingAdd;
|
||||
auto rippleMask = Ui::RippleAnimation::RoundRectMask(
|
||||
QSize(_addWidth - st.width, st.height),
|
||||
st::roundRadiusLarge);
|
||||
ensureRipple(
|
||||
st.ripple,
|
||||
std::move(rippleMask),
|
||||
removeButton,
|
||||
installedSet);
|
||||
}
|
||||
}
|
||||
if (row->ripple) {
|
||||
@@ -1747,9 +1810,14 @@ void StickersBox::Inner::setPressed(SelectedRow pressed) {
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton) {
|
||||
_rows[_actionDown]->ripple = std::make_unique<Ui::RippleAnimation>(st, std::move(mask), [this, index = _actionDown, removeButton] {
|
||||
update(myrtlrect(relativeButtonRect(removeButton, false).translated(0, _itemsTop + index * _rowHeight)));
|
||||
void StickersBox::Inner::ensureRipple(
|
||||
const style::RippleAnimation &st,
|
||||
QImage mask,
|
||||
bool removeButton,
|
||||
bool installedSet) {
|
||||
const auto dy = _itemsTop + _actionDown * _rowHeight;
|
||||
_rows[_actionDown]->ripple = std::make_unique<Ui::RippleAnimation>(st, std::move(mask), [=] {
|
||||
update(myrtlrect(relativeButtonRect(removeButton, installedSet).translated(0, dy)));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1812,7 +1880,7 @@ void StickersBox::Inner::updateSelected() {
|
||||
selected = selectedIndex;
|
||||
local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight);
|
||||
const auto row = _rows[selectedIndex].get();
|
||||
if (!_megagroupSet && (_isInstalledTab || !row->isInstalled() || row->isArchived() || row->removed)) {
|
||||
if (!_megagroupSet && (_isInstalledTab || (_section == Section::Featured) || !row->isInstalled() || row->isArchived() || row->removed)) {
|
||||
auto removeButton = (_isInstalledTab && !row->removed);
|
||||
auto rect = myrtlrect(relativeButtonRect(removeButton, false));
|
||||
actionSel = rect.contains(local) ? selectedIndex : -1;
|
||||
@@ -1857,7 +1925,7 @@ float64 StickersBox::Inner::aboveShadowOpacity() const {
|
||||
|
||||
auto dx = 0;
|
||||
auto dy = qAbs(_above * _rowHeight + qRound(_rows[_above]->yadd.current()) - _started * _rowHeight);
|
||||
return qMin((dx + dy) * 2. / _rowHeight, 1.);
|
||||
return qMin((dx + dy) * 2. / _rowHeight, 1.);
|
||||
}
|
||||
|
||||
void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
@@ -1868,10 +1936,11 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_mouse = e->globalPos();
|
||||
updateSelected();
|
||||
if (_actionDown == _actionSel && _actionSel >= 0) {
|
||||
if (_isInstalledTab) {
|
||||
setRowRemoved(_actionDown, !_rows[_actionDown]->removed);
|
||||
} else if (_installSetCallback) {
|
||||
_installSetCallback(_rows[_actionDown]->set->id);
|
||||
const auto callback = _rows[_actionDown]->removed
|
||||
? _installSetCallback
|
||||
: _removeSetCallback;
|
||||
if (callback) {
|
||||
callback(_rows[_actionDown]->set->id);
|
||||
}
|
||||
} else if (_dragging >= 0) {
|
||||
_rows[_dragging]->yadd.start(0.);
|
||||
@@ -1921,6 +1990,13 @@ void StickersBox::Inner::saveGroupSet() {
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setRowRemovedBySetId(uint64 setId, bool removed) {
|
||||
const auto index = getRowIndex(setId);
|
||||
if (index >= 0) {
|
||||
setRowRemoved(index, removed);
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setRowRemoved(int index, bool removed) {
|
||||
auto &row = _rows[index];
|
||||
if (row->removed != removed) {
|
||||
@@ -2114,7 +2190,7 @@ void StickersBox::Inner::rebuildMegagroupSet() {
|
||||
auto removed = false;
|
||||
auto maxNameWidth = countMaxNameWidth(!_isInstalledTab);
|
||||
auto titleWidth = 0;
|
||||
auto title = fillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
auto title = FillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
if (!_megagroupSelectedSet
|
||||
|| _megagroupSelectedSet->set->id != set->id) {
|
||||
_megagroupSetField->setText(set->shortName);
|
||||
@@ -2217,11 +2293,6 @@ void StickersBox::Inner::setMegagroupSelectedSet(
|
||||
updateSelected();
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setMinHeight(int newWidth, int minHeight) {
|
||||
_minHeight = minHeight;
|
||||
updateSize(newWidth);
|
||||
}
|
||||
|
||||
void StickersBox::Inner::updateSize(int newWidth) {
|
||||
auto naturalHeight = _itemsTop + int(_rows.size()) * _rowHeight + st::membersMarginBottom;
|
||||
resize(newWidth ? newWidth : width(), qMax(_minHeight, naturalHeight));
|
||||
@@ -2269,7 +2340,7 @@ void StickersBox::Inner::updateRows() {
|
||||
&& row->isInstalled()
|
||||
&& !row->isArchived()
|
||||
&& !row->removed);
|
||||
row->title = fillSetTitle(
|
||||
row->title = FillSetTitle(
|
||||
set,
|
||||
installedSet ? maxNameWidthInstalled : maxNameWidth,
|
||||
&row->titleWidth);
|
||||
@@ -2331,7 +2402,7 @@ void StickersBox::Inner::rebuildAppendSet(not_null<StickersSet*> set) {
|
||||
&& !(flagsOverride & SetFlag::Archived)
|
||||
&& !removed);
|
||||
int titleWidth = 0;
|
||||
QString title = fillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
QString title = FillSetTitle(set, maxNameWidth, &titleWidth);
|
||||
int count = fillSetCount(set);
|
||||
|
||||
const auto existing = [&]{
|
||||
@@ -2458,22 +2529,6 @@ int StickersBox::Inner::fillSetCount(not_null<StickersSet*> set) const {
|
||||
return result + added;
|
||||
}
|
||||
|
||||
QString StickersBox::Inner::fillSetTitle(
|
||||
not_null<StickersSet*> set,
|
||||
int maxNameWidth,
|
||||
int *outTitleWidth) const {
|
||||
auto result = set->title;
|
||||
int titleWidth = st::contactsNameStyle.font->width(result);
|
||||
if (titleWidth > maxNameWidth) {
|
||||
result = st::contactsNameStyle.font->elided(result, maxNameWidth);
|
||||
titleWidth = st::contactsNameStyle.font->width(result);
|
||||
}
|
||||
if (outTitleWidth) {
|
||||
*outTitleWidth = titleWidth;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Data::StickersSetFlags StickersBox::Inner::fillSetFlags(
|
||||
not_null<StickersSet*> set) const {
|
||||
const auto result = set->flags;
|
||||
@@ -2494,19 +2549,19 @@ StickersSetsOrder StickersBox::Inner::collectSets(Check check) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
StickersSetsOrder StickersBox::Inner::getOrder() const {
|
||||
StickersSetsOrder StickersBox::Inner::order() const {
|
||||
return collectSets([](Row *row) {
|
||||
return !row->isArchived() && !row->removed && !row->isRecentSet();
|
||||
});
|
||||
}
|
||||
|
||||
StickersSetsOrder StickersBox::Inner::getFullOrder() const {
|
||||
StickersSetsOrder StickersBox::Inner::fullOrder() const {
|
||||
return collectSets([](Row *row) {
|
||||
return !row->isRecentSet();
|
||||
});
|
||||
}
|
||||
|
||||
StickersSetsOrder StickersBox::Inner::getRemovedSets() const {
|
||||
StickersSetsOrder StickersBox::Inner::removedSets() const {
|
||||
return collectSets([](Row *row) {
|
||||
return row->removed;
|
||||
});
|
||||
|
||||
@@ -104,7 +104,7 @@ private:
|
||||
[[nodiscard]] int index() const;
|
||||
|
||||
void saveScrollTop();
|
||||
int getScrollTop() const {
|
||||
int scrollTop() const {
|
||||
return _scrollTop;
|
||||
}
|
||||
|
||||
@@ -122,12 +122,12 @@ private:
|
||||
void updateTabsGeometry();
|
||||
void switchTab();
|
||||
void installSet(uint64 setId);
|
||||
int getTopSkip() const;
|
||||
int topSkip() const;
|
||||
void saveChanges();
|
||||
|
||||
QPixmap grabContentCache();
|
||||
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result) const;
|
||||
void installFail(const MTP::Error &error, uint64 setId);
|
||||
|
||||
void preloadArchivedSets();
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
void showAttachedStickers();
|
||||
|
||||
const Data::StickersSetsOrder &archivedSetsOrder() const;
|
||||
Data::StickersSetsOrder &archivedSetsOrderRef();
|
||||
Data::StickersSetsOrder &archivedSetsOrderRef() const;
|
||||
|
||||
std::array<Inner*, 5> widgets() const;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/menu/menu_action.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
|
||||
@@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/call_button.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "ui/widgets/rp_window.h"
|
||||
#include "ui/chat/group_call_bar.h"
|
||||
|
||||
@@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
|
||||
@@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_calls.h"
|
||||
#include "styles/style_layers.h"
|
||||
@@ -287,7 +287,7 @@ void EditGroupCallTitleBox(
|
||||
box->closeBox();
|
||||
done(result);
|
||||
};
|
||||
QObject::connect(input, &Ui::InputField::submitted, submit);
|
||||
input->submits() | rpl::start_with_next(submit, input->lifetime());
|
||||
box->addButton(tr::lng_settings_save(), submit);
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
@@ -346,7 +346,7 @@ void AddTitleGroupCallRecordingBox(
|
||||
box->closeBox();
|
||||
done(result);
|
||||
};
|
||||
QObject::connect(input, &Ui::InputField::submitted, submit);
|
||||
input->submits() | rpl::start_with_next(submit, input->lifetime());
|
||||
box->addButton(tr::lng_group_call_recording_start_button(), submit);
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
@@ -294,8 +294,11 @@ stickersTrendingAdd: RoundButton(defaultActiveButton) {
|
||||
stickersTrendingInstalled: RoundButton(stickersTrendingAdd) {
|
||||
textFg: activeButtonBg;
|
||||
textFgOver: activeButtonBgOver;
|
||||
textBg: activeButtonSecondaryFg;
|
||||
textBgOver: activeButtonSecondaryFgOver;
|
||||
textBg: lightButtonBgOver;
|
||||
textBgOver: lightButtonBgOver;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: activeButtonSecondaryFg;
|
||||
}
|
||||
}
|
||||
stickersRemove: IconButton(defaultIconButton) {
|
||||
width: 40px;
|
||||
|
||||
@@ -41,9 +41,9 @@ inline auto PreviewPath(int i) {
|
||||
|
||||
const auto kSets = {
|
||||
Set{ { 0, 0, 0, "Mac" }, PreviewPath(0) },
|
||||
Set{ { 1, 1392, 8'184'590, "Android" }, PreviewPath(1) },
|
||||
Set{ { 2, 1393, 5'413'219, "Twemoji" }, PreviewPath(2) },
|
||||
Set{ { 3, 1394, 6'967'218, "JoyPixels" }, PreviewPath(3) },
|
||||
Set{ { 1, 1804, 8'115'639, "Android" }, PreviewPath(1) },
|
||||
Set{ { 2, 1805, 5'481'197, "Twemoji" }, PreviewPath(2) },
|
||||
Set{ { 3, 1806, 7'047'594, "JoyPixels" }, PreviewPath(3) },
|
||||
};
|
||||
|
||||
using Loading = MTP::DedicatedLoader::Progress;
|
||||
|
||||
@@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/widgets/inner_dropdown.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
|
||||
@@ -31,7 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/effects/path_shift_gradient.h"
|
||||
|
||||
@@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/click_handler_types.h"
|
||||
#include "ui/controls/tabbed_search.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/image/image.h"
|
||||
|
||||
@@ -190,16 +190,18 @@ void EditLinkBox(
|
||||
}
|
||||
};
|
||||
|
||||
QObject::connect(text, &Ui::InputField::submitted, [=] {
|
||||
text->submits(
|
||||
) | rpl::start_with_next([=] {
|
||||
url->setFocusFast();
|
||||
});
|
||||
QObject::connect(url, &Ui::InputField::submitted, [=] {
|
||||
}, text->lifetime());
|
||||
url->submits(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (text->getLastText().isEmpty()) {
|
||||
text->setFocusFast();
|
||||
} else {
|
||||
submit();
|
||||
}
|
||||
});
|
||||
}, url->lifetime());
|
||||
|
||||
box->setTitle(url->getLastText().isEmpty()
|
||||
? tr::lng_formatting_link_create_title()
|
||||
@@ -223,8 +225,14 @@ void EditLinkBox(
|
||||
url->customTab(true);
|
||||
text->customTab(true);
|
||||
|
||||
QObject::connect(url, &Ui::InputField::tabbed, [=] { text->setFocus(); });
|
||||
QObject::connect(text, &Ui::InputField::tabbed, [=] { url->setFocus(); });
|
||||
url->tabbed(
|
||||
) | rpl::start_with_next([=] {
|
||||
text->setFocus();
|
||||
}, url->lifetime());
|
||||
text->tabbed(
|
||||
) | rpl::start_with_next([=] {
|
||||
url->setFocus();
|
||||
}, text->lifetime());
|
||||
}
|
||||
|
||||
TextWithEntities StripSupportHashtag(TextWithEntities text) {
|
||||
@@ -590,7 +598,8 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery(
|
||||
MessageLinksParser::MessageLinksParser(not_null<Ui::InputField*> field)
|
||||
: _field(field)
|
||||
, _timer([=] { parse(); }) {
|
||||
_connection = QObject::connect(_field, &Ui::InputField::changed, [=] {
|
||||
_lifetime = _field->changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto length = _field->getTextWithTags().text.size();
|
||||
const auto timeout = (std::abs(length - _lastLength) > 2)
|
||||
? 0
|
||||
|
||||
@@ -7,9 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/qt_connection.h"
|
||||
#include "chat_helpers/compose/compose_features.h"
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_SPELLCHECK
|
||||
@@ -132,7 +131,7 @@ private:
|
||||
int _lastLength = 0;
|
||||
bool _disabled = false;
|
||||
base::Timer _timer;
|
||||
base::qt_connection _connection;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lottie/lottie_single_player.h"
|
||||
#include "ui/dpr/dpr_icon.h"
|
||||
#include "ui/dpr/dpr_image.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect_part.h"
|
||||
|
||||
@@ -22,110 +22,6 @@ namespace {
|
||||
|
||||
std::map<int, const char*> BetaLogs() {
|
||||
return {
|
||||
{
|
||||
4005004,
|
||||
"- Allow wide range of interface scale options.\n"
|
||||
|
||||
"- Show opened chat name in the window title.\n"
|
||||
|
||||
"- Bug fixes and other minor improvements.\n"
|
||||
|
||||
"- Fix updating on macOS older than 10.14.\n"
|
||||
},
|
||||
{
|
||||
4005006,
|
||||
"- Try enabling non-fractional scale "
|
||||
"High DPI support on Windows and Linux.\n"
|
||||
|
||||
"- Experimental setting for fractional scale "
|
||||
"High DPI support on Windows and Linux.\n"
|
||||
|
||||
"- Fix navigation to bottom problems in groups you didn't join.\n"
|
||||
|
||||
"- Fix a crash in chat export settings changes.\n"
|
||||
|
||||
"- Fix a crash in sending some of JPEG images.\n"
|
||||
|
||||
"- Fix CJK fonts on Windows.\n"
|
||||
},
|
||||
{
|
||||
4005007,
|
||||
"- Fix glitches after moving window to another screen.\n",
|
||||
},
|
||||
{
|
||||
4005008,
|
||||
"- Allow opening another account in a new window "
|
||||
"(see Settings > Advanced > Experimental Settings).\n"
|
||||
|
||||
"- A lot of bugfixes for working with more than one window.\n"
|
||||
},
|
||||
{
|
||||
4006004,
|
||||
"- Allow media viewer to exit fullscreen and become a normal window."
|
||||
},
|
||||
{
|
||||
4006006,
|
||||
"- Confirmation window before starting a call.\n"
|
||||
|
||||
"- New \"Battery and Animations\" settings section.\n"
|
||||
|
||||
"- \"Save Power on Low Battery\" option for laptops.\n"
|
||||
|
||||
"- Improved windowed mode support for media viewer.\n"
|
||||
|
||||
"- Hardware accelerated video playback fix on macOS.\n"
|
||||
|
||||
"- New application icon on macOS following the system guidelines.\n"
|
||||
},
|
||||
{
|
||||
4006007,
|
||||
"- Fix crash when accepting incoming calls.\n"
|
||||
|
||||
"- Remove sound when cancelling an unconfirmed call.\n"
|
||||
},
|
||||
{
|
||||
4006008,
|
||||
"- Improve quality of voice messages with changed playback speed.\n"
|
||||
|
||||
"- Show when your message was read in small groups.\n"
|
||||
|
||||
"- Fix pasting images from Firefox on Windows.\n"
|
||||
|
||||
"- Improve memory usage for custom emoji.\n"
|
||||
},
|
||||
{
|
||||
4006010,
|
||||
"- Suggest sending an invite link if user forbids "
|
||||
"inviting him to groups.\n"
|
||||
|
||||
"- Show when a reaction was left on your message in small groups.\n"
|
||||
|
||||
"- Fix a crash in video chats on Windows.\n"
|
||||
|
||||
"- Fix a crash in audio speed change.\n"
|
||||
},
|
||||
{
|
||||
4006011,
|
||||
"- Allow larger interface scale values on high-dpi screens.\n"
|
||||
|
||||
"- Implement new voice and video speed change interface (up to 2.5x).\n"
|
||||
|
||||
"- Support global Fn+F shortcut to toggle fullscreen on macOS.\n"
|
||||
|
||||
"- Silent notification sound in Focus Mode on macOS.\n"
|
||||
|
||||
"- Fix media viewer on macOS with several screens.\n"
|
||||
|
||||
"- Fix a crash in connection type box.\n"
|
||||
|
||||
"- Fix possible crash on quit.\n"
|
||||
},
|
||||
{
|
||||
4006012,
|
||||
"- Fix several possible crashes.\n"
|
||||
|
||||
"- Deprecate macOS 10.12, Ubuntu 18.04 and CentOS 7 in July.\n"
|
||||
},
|
||||
{
|
||||
4008011,
|
||||
"- Fix initial video playback speed.\n"
|
||||
|
||||
@@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/send_files_box.h"
|
||||
#include "history/view/history_view_quick_action.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "window/section_widget.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
|
||||
@@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <new>
|
||||
#include <mutex>
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#include <new.h>
|
||||
@@ -25,7 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <client/windows/handler/exception_handler.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#elif defined Q_OS_UNIX // Q_OS_WIN
|
||||
#else // Q_OS_WIN
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -48,7 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
#endif // Q_OS_WIN
|
||||
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
namespace CrashReports {
|
||||
namespace {
|
||||
@@ -59,7 +59,7 @@ using AnnotationRefs = std::map<std::string, const QString*>;
|
||||
Annotations ProcessAnnotations;
|
||||
AnnotationRefs ProcessAnnotationRefs;
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
QString ReportPath;
|
||||
FILE *ReportFile = nullptr;
|
||||
@@ -197,13 +197,15 @@ const int HandledSignals[] = {
|
||||
SIGABRT,
|
||||
SIGFPE,
|
||||
SIGILL,
|
||||
#ifdef Q_OS_UNIX
|
||||
#ifndef Q_OS_WIN
|
||||
SIGBUS,
|
||||
SIGTRAP,
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // !Q_OS_WIN
|
||||
};
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#ifdef Q_OS_WIN
|
||||
void SignalHandler(int signum) {
|
||||
#else // Q_OS_WIN
|
||||
struct sigaction OldSigActions[32]/* = { 0 }*/;
|
||||
|
||||
void RestoreSignalHandlers() {
|
||||
@@ -229,9 +231,7 @@ void InvokeOldSignalHandler(int signum, siginfo_t *info, void *ucontext) {
|
||||
void SignalHandler(int signum, siginfo_t *info, void *ucontext) {
|
||||
RestoreSignalHandlers();
|
||||
|
||||
#else // Q_OS_UNIX
|
||||
void SignalHandler(int signum) {
|
||||
#endif // else for Q_OS_UNIX
|
||||
#endif // else for Q_OS_WIN
|
||||
|
||||
const char* name = 0;
|
||||
switch (signum) {
|
||||
@@ -253,9 +253,9 @@ void SignalHandler(int signum) {
|
||||
ReportingThreadId = nullptr;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#ifndef Q_OS_WIN
|
||||
InvokeOldSignalHandler(signum, info, ucontext);
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // !Q_OS_WIN
|
||||
}
|
||||
|
||||
bool SetSignalHandlers = true;
|
||||
@@ -267,9 +267,9 @@ google_breakpad::ExceptionHandler* BreakpadExceptionHandler = 0;
|
||||
bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success)
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success)
|
||||
#elif defined Q_OS_UNIX // Q_OS_MAC
|
||||
#else // Q_OS_MAC
|
||||
bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // else for Q_OS_WIN || Q_OS_MAC
|
||||
{
|
||||
if (CrashLogged) return success;
|
||||
CrashLogged = true;
|
||||
@@ -290,7 +290,7 @@ bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context,
|
||||
}
|
||||
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD
|
||||
|
||||
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -314,7 +314,7 @@ QString PlatformString() {
|
||||
}
|
||||
|
||||
void StartCatching() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
ProcessAnnotations["Binary"] = cExeName().toUtf8().constData();
|
||||
ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData();
|
||||
ProcessAnnotations["Version"] = (cAlphaVersion()
|
||||
@@ -370,7 +370,7 @@ void StartCatching() {
|
||||
false)) { // asynchronous_start
|
||||
}
|
||||
#endif // else for MAC_USE_BREAKPAD
|
||||
#elif defined Q_OS_UNIX
|
||||
#else
|
||||
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()),
|
||||
/*FilterCallback*/ 0,
|
||||
@@ -379,22 +379,22 @@ void StartCatching() {
|
||||
true,
|
||||
-1
|
||||
);
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // else for Q_OS_WIN || Q_OS_MAC
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void FinishCatching() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
|
||||
|
||||
delete base::take(BreakpadExceptionHandler);
|
||||
|
||||
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD
|
||||
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
StartResult Start() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
ReportPath = cWorkingDir() + u"tdata/working"_q;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -420,12 +420,12 @@ StartResult Start() {
|
||||
return lastdump;
|
||||
}
|
||||
|
||||
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
return Restart();
|
||||
}
|
||||
|
||||
Status Restart() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
if (ReportFile) {
|
||||
return Started;
|
||||
}
|
||||
@@ -470,13 +470,13 @@ Status Restart() {
|
||||
LOG(("FATAL: Could not open '%1' for writing!").arg(ReportPath));
|
||||
|
||||
return CantOpen;
|
||||
#else // !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#else // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
return Started;
|
||||
#endif // else for !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // else for !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
FinishCatching();
|
||||
|
||||
if (ReportFile) {
|
||||
@@ -489,7 +489,7 @@ void Finish() {
|
||||
unlink(ReportPath.toUtf8().constData());
|
||||
#endif // else for Q_OS_WIN
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void SetAnnotation(const std::string &key, const QString &value) {
|
||||
@@ -539,7 +539,7 @@ void SetAnnotationRef(const std::string &key, const QString *valuePtr) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
dump::~dump() {
|
||||
if (ReportFile) {
|
||||
@@ -604,6 +604,6 @@ const dump &operator<<(const dump &stream, double num) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
} // namespace CrashReports
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace CrashReports {
|
||||
|
||||
QString PlatformString();
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
struct dump {
|
||||
~dump();
|
||||
@@ -24,7 +24,7 @@ const dump &operator<<(const dump &stream, unsigned long num);
|
||||
const dump &operator<<(const dump &stream, unsigned long long num);
|
||||
const dump &operator<<(const dump &stream, double num);
|
||||
|
||||
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
enum Status {
|
||||
CantOpen,
|
||||
|
||||
83
Telegram/SourceFiles/core/deadlock_detector.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
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 Core::DeadlockDetector {
|
||||
|
||||
class PingPongEvent : public QEvent {
|
||||
public:
|
||||
static auto Type() {
|
||||
static const auto Result = QEvent::Type(QEvent::registerEventType());
|
||||
return Result;
|
||||
}
|
||||
|
||||
PingPongEvent(not_null<QObject*> sender)
|
||||
: QEvent(Type())
|
||||
, _sender(sender) {
|
||||
}
|
||||
|
||||
[[nodiscard]] not_null<QObject*> sender() const {
|
||||
return _sender;
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<QObject*> _sender;
|
||||
|
||||
};
|
||||
|
||||
class Pinger : public QObject {
|
||||
public:
|
||||
Pinger(not_null<QObject*> receiver)
|
||||
: _receiver(receiver)
|
||||
, _abortTimer([] { Unexpected("Deadlock found!"); }) {
|
||||
const auto callback = [=] {
|
||||
QCoreApplication::postEvent(_receiver, new PingPongEvent(this));
|
||||
_abortTimer.callOnce(30000);
|
||||
};
|
||||
_pingTimer.setCallback(callback);
|
||||
_pingTimer.callEach(60000);
|
||||
callback();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e) override {
|
||||
if (e->type() == PingPongEvent::Type()
|
||||
&& static_cast<PingPongEvent*>(e)->sender() == _receiver) {
|
||||
_abortTimer.cancel();
|
||||
}
|
||||
return QObject::event(e);
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<QObject*> _receiver;
|
||||
base::Timer _pingTimer;
|
||||
base::Timer _abortTimer;
|
||||
|
||||
};
|
||||
|
||||
class PingThread : public QThread {
|
||||
public:
|
||||
PingThread(not_null<QObject*> parent)
|
||||
: QThread(parent) {
|
||||
start();
|
||||
}
|
||||
|
||||
~PingThread() {
|
||||
quit();
|
||||
wait();
|
||||
}
|
||||
|
||||
protected:
|
||||
void run() override {
|
||||
Pinger pinger(parent());
|
||||
QThread::run();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace Core::DeadlockDetector
|
||||
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/options.h"
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QStandardPaths>
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
@@ -115,16 +116,26 @@ void ComputeDebugMode() {
|
||||
}
|
||||
|
||||
void ComputeExternalUpdater() {
|
||||
QFile file(u"/etc/tdesktop/externalupdater"_q);
|
||||
|
||||
if (file.exists() && file.open(QIODevice::ReadOnly)) {
|
||||
QTextStream fileStream(&file);
|
||||
while (!fileStream.atEnd()) {
|
||||
const auto path = fileStream.readLine();
|
||||
|
||||
if (path == (cExeDir() + cExeName())) {
|
||||
SetUpdaterDisabledAtStartup();
|
||||
return;
|
||||
auto locations = QStandardPaths::standardLocations(
|
||||
QStandardPaths::AppDataLocation);
|
||||
if (locations.isEmpty()) {
|
||||
locations << QString();
|
||||
}
|
||||
locations[0] = QDir::cleanPath(cWorkingDir());
|
||||
locations << QDir::cleanPath(cExeDir());
|
||||
for (const auto &location : locations) {
|
||||
const auto dir = location + u"/externalupdater.d"_q;
|
||||
for (const auto &info : QDir(dir).entryInfoList(QDir::Files)) {
|
||||
QFile file(info.absoluteFilePath());
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QTextStream fileStream(&file);
|
||||
while (!fileStream.atEnd()) {
|
||||
const auto path = fileStream.readLine();
|
||||
if (path == (cExeDir() + cExeName())) {
|
||||
SetUpdaterDisabledAtStartup();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +234,7 @@ bool CheckPortableVersionFolder() {
|
||||
if (cAlphaVersion()) {
|
||||
Assert(*AlphaPrivateKey != 0);
|
||||
|
||||
cForceWorkingDir(portable + '/');
|
||||
cForceWorkingDir(portable);
|
||||
QDir().mkpath(cWorkingDir() + u"tdata"_q);
|
||||
cSetAlphaPrivateKey(QByteArray(AlphaPrivateKey));
|
||||
if (!key.open(QIODevice::WriteOnly)) {
|
||||
@@ -239,7 +250,7 @@ bool CheckPortableVersionFolder() {
|
||||
if (!QDir(portable).exists()) {
|
||||
return true;
|
||||
}
|
||||
cForceWorkingDir(portable + '/');
|
||||
cForceWorkingDir(portable);
|
||||
if (!key.exists()) {
|
||||
return true;
|
||||
}
|
||||
@@ -291,7 +302,8 @@ Launcher::Launcher(int argc, char *argv[])
|
||||
: _argc(argc)
|
||||
, _argv(argv)
|
||||
, _arguments(readArguments(_argc, _argv))
|
||||
, _baseIntegration(_argc, _argv) {
|
||||
, _baseIntegration(_argc, _argv)
|
||||
, _initialWorkingDir(QDir::currentPath() + '/') {
|
||||
crl::toggle_fp_exceptions(true);
|
||||
|
||||
base::Integration::Set(&_baseIntegration);
|
||||
@@ -446,6 +458,10 @@ const QStringList &Launcher::arguments() const {
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
QString Launcher::initialWorkingDir() const {
|
||||
return _initialWorkingDir;
|
||||
}
|
||||
|
||||
bool Launcher::customWorkingDir() const {
|
||||
return !_customWorkingDir.isEmpty();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
virtual int exec();
|
||||
|
||||
const QStringList &arguments() const;
|
||||
QString initialWorkingDir() const;
|
||||
bool customWorkingDir() const;
|
||||
|
||||
uint64 installationTag() const;
|
||||
@@ -84,6 +85,7 @@ private:
|
||||
QStringList _arguments;
|
||||
BaseIntegration _baseIntegration;
|
||||
|
||||
QString _initialWorkingDir;
|
||||
QString _customWorkingDir;
|
||||
|
||||
};
|
||||
|
||||
@@ -378,6 +378,8 @@ bool ResolveUsernameOrPhone(
|
||||
startToken = params.value(u"startgroup"_q);
|
||||
} else if (params.contains(u"startchannel"_q)) {
|
||||
resolveType = ResolveType::AddToChannel;
|
||||
} else if (params.contains(u"boost"_q)) {
|
||||
resolveType = ResolveType::Boost;
|
||||
}
|
||||
auto post = ShowAtUnreadMsgId;
|
||||
auto adminRights = ChatAdminRights();
|
||||
@@ -392,7 +394,6 @@ bool ResolveUsernameOrPhone(
|
||||
const auto storyParam = params.value(u"story"_q);
|
||||
const auto storyId = storyParam.toInt();
|
||||
const auto appname = webChannelPreviewLink ? QString() : appnameParam;
|
||||
const auto appstart = params.value(u"startapp"_q);
|
||||
const auto commentParam = params.value(u"comment"_q);
|
||||
const auto commentId = commentParam.toInt();
|
||||
const auto topicParam = params.value(u"topic"_q);
|
||||
@@ -404,11 +405,11 @@ bool ResolveUsernameOrPhone(
|
||||
startToken = gameParam;
|
||||
resolveType = ResolveType::ShareGame;
|
||||
}
|
||||
if (startToken.isEmpty() && params.contains(u"startapp"_q)) {
|
||||
startToken = params.value(u"startapp"_q);
|
||||
}
|
||||
if (!appname.isEmpty()) {
|
||||
resolveType = ResolveType::BotApp;
|
||||
if (startToken.isEmpty() && params.contains(u"startapp"_q)) {
|
||||
startToken = params.value(u"startapp"_q);
|
||||
}
|
||||
}
|
||||
const auto myContext = context.value<ClickHandlerContext>();
|
||||
using Navigation = Window::SessionNavigation;
|
||||
@@ -436,7 +437,11 @@ bool ResolveUsernameOrPhone(
|
||||
.attachBotUsername = params.value(u"attach"_q),
|
||||
.attachBotToggleCommand = (params.contains(u"startattach"_q)
|
||||
? params.value(u"startattach"_q)
|
||||
: (appname.isEmpty() && params.contains(u"startapp"_q))
|
||||
? params.value(u"startapp"_q)
|
||||
: std::optional<QString>()),
|
||||
.attachBotMenuOpen = (appname.isEmpty()
|
||||
&& params.contains(u"startapp"_q)),
|
||||
.attachBotChooseTypes = InlineBots::ParseChooseTypes(
|
||||
params.value(u"choose"_q)),
|
||||
.voicechatHash = (params.contains(u"livestream"_q)
|
||||
@@ -839,6 +844,34 @@ bool ResolveLoginCode(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResolveBoost(
|
||||
Window::SessionController *controller,
|
||||
const Match &match,
|
||||
const QVariant &context) {
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
const auto params = url_parse_params(
|
||||
match->captured(1),
|
||||
qthelp::UrlParamNameTransform::ToLower);
|
||||
const auto domainParam = params.value(u"domain"_q);
|
||||
const auto channelParam = params.contains(u"c"_q)
|
||||
? params.value(u"c"_q)
|
||||
: params.value(u"channel"_q);
|
||||
|
||||
const auto myContext = context.value<ClickHandlerContext>();
|
||||
using Navigation = Window::SessionNavigation;
|
||||
controller->window().activate();
|
||||
controller->showPeerByLink(Navigation::PeerByLinkInfo{
|
||||
.usernameOrId = (!domainParam.isEmpty()
|
||||
? std::variant<QString, ChannelId>(domainParam)
|
||||
: ChannelId(BareId(channelParam.toULongLong()))),
|
||||
.resolveType = Window::ResolveType::Boost,
|
||||
.clickFromMessageId = myContext.itemId,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||
@@ -919,6 +952,10 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||
u"^login/?(\\?code=([0-9]+))(&|$)"_q,
|
||||
ResolveLoginCode
|
||||
},
|
||||
{
|
||||
u"^boost/?\\?(.+)(#|$)"_q,
|
||||
ResolveBoost,
|
||||
},
|
||||
{
|
||||
u"^([^\\?]+)(\\?|#|$)"_q,
|
||||
HandleUnknown
|
||||
@@ -1022,8 +1059,13 @@ QString TryConvertUrlToLocal(QString url) {
|
||||
"/\\d+/?(\\?|$)|"
|
||||
"/\\d+/\\d+/?(\\?|$)"
|
||||
")"_q, query, matchOptions)) {
|
||||
const auto channel = privateMatch->captured(1);
|
||||
const auto params = query.mid(privateMatch->captured(0).size()).toString();
|
||||
const auto base = u"tg://privatepost?channel="_q + privateMatch->captured(1);
|
||||
if (params.indexOf("boost", 0, Qt::CaseInsensitive) >= 0
|
||||
&& params.toLower().split('&').contains(u"boost"_q)) {
|
||||
return u"tg://boost?channel="_q + channel;
|
||||
}
|
||||
const auto base = u"tg://privatepost?channel="_q + channel;
|
||||
auto added = QString();
|
||||
if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, privateMatch->captured(2))) {
|
||||
added = u"&topic=%1&post=%2"_q.arg(threadPostMatch->captured(1)).arg(threadPostMatch->captured(2));
|
||||
@@ -1041,7 +1083,18 @@ QString TryConvertUrlToLocal(QString url) {
|
||||
"/s/\\d+/?(\\?|$)|"
|
||||
"/\\d+/\\d+/?(\\?|$)"
|
||||
")"_q, query, matchOptions)) {
|
||||
const auto domain = usernameMatch->captured(1);
|
||||
const auto params = query.mid(usernameMatch->captured(0).size()).toString();
|
||||
if (params.indexOf("boost", 0, Qt::CaseInsensitive) >= 0
|
||||
&& params.toLower().split('&').contains(u"boost"_q)) {
|
||||
return u"tg://boost?domain="_q + domain;
|
||||
} else if (domain == u"boost"_q) {
|
||||
if (const auto domainMatch = regex_match(u"^/([a-zA-Z0-9\\.\\_]+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {
|
||||
return u"tg://boost?domain="_q + domainMatch->captured(1);
|
||||
} else if (params.indexOf("c=", 0, Qt::CaseInsensitive) >= 0) {
|
||||
return u"tg://boost?"_q + params;
|
||||
}
|
||||
}
|
||||
const auto base = u"tg://resolve?domain="_q + url_encode(usernameMatch->captured(1));
|
||||
auto added = QString();
|
||||
if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {
|
||||
|
||||
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/launcher.h"
|
||||
#include "core/local_url_handlers.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "core/deadlock_detector.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/concurrent_timer.h"
|
||||
#include "base/invoke_queued.h"
|
||||
@@ -27,7 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/qthelp_regex.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/platform/ui_platform_utility.h"
|
||||
|
||||
#include <QtCore/QLockFile>
|
||||
#include <QtGui/QSessionManager>
|
||||
@@ -198,6 +198,13 @@ void Sandbox::launchApplication() {
|
||||
}
|
||||
setupScreenScale();
|
||||
|
||||
#ifndef _DEBUG
|
||||
if (Logs::DebugEnabled()) {
|
||||
using DeadlockDetector::PingThread;
|
||||
_deadlockDetector = std::make_unique<PingThread>(this);
|
||||
}
|
||||
#endif // !_DEBUG
|
||||
|
||||
_application = std::make_unique<Application>();
|
||||
|
||||
// Ideally this should go to constructor.
|
||||
@@ -267,6 +274,10 @@ bool Sandbox::event(QEvent *e) {
|
||||
return false;
|
||||
} else if (e->type() == QEvent::Close) {
|
||||
Quit();
|
||||
} else if (e->type() == DeadlockDetector::PingPongEvent::Type()) {
|
||||
postEvent(
|
||||
static_cast<DeadlockDetector::PingPongEvent*>(e)->sender(),
|
||||
new DeadlockDetector::PingPongEvent(this));
|
||||
}
|
||||
return QApplication::event(e);
|
||||
}
|
||||
@@ -581,18 +592,9 @@ void Sandbox::registerEnterFromEventLoop() {
|
||||
}
|
||||
|
||||
bool Sandbox::notifyOrInvoke(QObject *receiver, QEvent *e) {
|
||||
const auto type = e->type();
|
||||
if (type == base::InvokeQueuedEvent::Type()) {
|
||||
if (e->type() == base::InvokeQueuedEvent::Type()) {
|
||||
static_cast<base::InvokeQueuedEvent*>(e)->invoke();
|
||||
return true;
|
||||
} else if (receiver == this) {
|
||||
if (type == QEvent::ApplicationDeactivate) {
|
||||
if (Ui::Platform::SkipApplicationDeactivateEvent()) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == QEvent::ApplicationActivate) {
|
||||
Ui::Platform::GotApplicationActivateEvent();
|
||||
}
|
||||
}
|
||||
return QApplication::notify(receiver, e);
|
||||
}
|
||||
|
||||
@@ -131,6 +131,8 @@ private:
|
||||
|
||||
rpl::event_stream<> _widgetUpdateRequests;
|
||||
|
||||
std::unique_ptr<QThread> _deadlockDetector;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -370,7 +370,6 @@ QString UiIntegration::phrasePanelCloseAnyway() {
|
||||
return tr::lng_bot_close_warning_sure(tr::now);
|
||||
}
|
||||
|
||||
#if 0 // disabled for now
|
||||
QString UiIntegration::phraseBotSharePhone() {
|
||||
return tr::lng_bot_share_phone(tr::now);
|
||||
}
|
||||
@@ -382,7 +381,18 @@ QString UiIntegration::phraseBotSharePhoneTitle() {
|
||||
QString UiIntegration::phraseBotSharePhoneConfirm() {
|
||||
return tr::lng_bot_share_phone_confirm(tr::now);
|
||||
}
|
||||
#endif
|
||||
|
||||
QString UiIntegration::phraseBotAllowWrite() {
|
||||
return tr::lng_bot_allow_write(tr::now);
|
||||
}
|
||||
|
||||
QString UiIntegration::phraseBotAllowWriteTitle() {
|
||||
return tr::lng_bot_allow_write_title(tr::now);
|
||||
}
|
||||
|
||||
QString UiIntegration::phraseBotAllowWriteConfirm() {
|
||||
return tr::lng_bot_allow_write_confirm(tr::now);
|
||||
}
|
||||
|
||||
bool OpenGLLastCheckFailed() {
|
||||
return QFile::exists(OpenGLCheckFilePath());
|
||||
|
||||
@@ -84,11 +84,12 @@ public:
|
||||
QString phrasePanelCloseWarning() override;
|
||||
QString phrasePanelCloseUnsaved() override;
|
||||
QString phrasePanelCloseAnyway() override;
|
||||
#if 0 // disabled for now
|
||||
QString phraseBotSharePhone() override;
|
||||
QString phraseBotSharePhoneTitle() override;
|
||||
QString phraseBotSharePhoneConfirm() override;
|
||||
#endif
|
||||
QString phraseBotAllowWrite() override;
|
||||
QString phraseBotAllowWriteTitle() override;
|
||||
QString phraseBotAllowWriteConfirm() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -42,16 +42,16 @@ extern "C" {
|
||||
} // extern "C"
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
|
||||
#include <LzmaLib.h>
|
||||
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
#else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
|
||||
#include <lzma.h>
|
||||
#endif // else of Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
#endif // else of Q_OS_WIN && !TDESKTOP_USE_PACKAGED
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#ifndef Q_OS_WIN
|
||||
#include <unistd.h>
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // !Q_OS_WIN
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
@@ -275,11 +275,11 @@ bool UnpackUpdate(const QString &filepath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
|
||||
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
#else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
|
||||
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
#endif // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
|
||||
|
||||
QByteArray compressed = input.readAll();
|
||||
int32 compressedLen = compressed.size() - hSize;
|
||||
@@ -350,14 +350,14 @@ bool UnpackUpdate(const QString &filepath) {
|
||||
uncompressed.resize(uncompressedLen);
|
||||
|
||||
size_t resultLen = uncompressed.size();
|
||||
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
|
||||
#if defined Q_OS_WIN && !defined TDESKTOP_USE_PACKAGED // use Lzma SDK for win
|
||||
SizeT srcLen = compressedLen;
|
||||
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
|
||||
if (uncompressRes != SZ_OK) {
|
||||
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
|
||||
return false;
|
||||
}
|
||||
#else // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
#else // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
|
||||
lzma_stream stream = LZMA_STREAM_INIT;
|
||||
|
||||
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED);
|
||||
@@ -400,7 +400,7 @@ bool UnpackUpdate(const QString &filepath) {
|
||||
LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res));
|
||||
return false;
|
||||
}
|
||||
#endif // Q_OS_WIN && !DESKTOP_APP_USE_PACKAGED
|
||||
#endif // Q_OS_WIN && !TDESKTOP_USE_PACKAGED
|
||||
|
||||
tempDir.mkdir(tempDir.absolutePath());
|
||||
|
||||
@@ -448,9 +448,9 @@ bool UnpackUpdate(const QString &filepath) {
|
||||
bool executable = false;
|
||||
|
||||
stream >> relativeName >> fileSize >> fileInnerData;
|
||||
#ifdef Q_OS_UNIX
|
||||
#ifndef Q_OS_WIN
|
||||
stream >> executable;
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // !Q_OS_WIN
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status()));
|
||||
return false;
|
||||
@@ -1554,10 +1554,10 @@ bool checkReadyUpdate() {
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
QString curUpdater = (cExeDir() + cExeName() + u"/Contents/Frameworks/Updater"_q);
|
||||
QFileInfo updater(cWorkingDir() + u"tupdates/temp/Telegram.app/Contents/Frameworks/Updater"_q);
|
||||
#elif defined Q_OS_UNIX // Q_OS_MAC
|
||||
#else // Q_OS_MAC
|
||||
QString curUpdater = (cExeDir() + u"Updater"_q);
|
||||
QFileInfo updater(cWorkingDir() + u"tupdates/temp/Updater"_q);
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // else for Q_OS_WIN || Q_OS_MAC
|
||||
if (!updater.exists()) {
|
||||
QFileInfo current(curUpdater);
|
||||
if (!current.exists()) {
|
||||
@@ -1591,7 +1591,7 @@ bool checkReadyUpdate() {
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
#elif defined Q_OS_UNIX // Q_OS_MAC
|
||||
#else // Q_OS_MAC
|
||||
// if the files in the directory are owned by user, while the directory is not,
|
||||
// update will still fail since it's not possible to remove files
|
||||
if (QFile::exists(curUpdater)
|
||||
@@ -1619,7 +1619,7 @@ bool checkReadyUpdate() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // else for Q_OS_WIN || Q_OS_MAC
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
base::Platform::RemoveQuarantine(QFileInfo(curUpdater).absolutePath());
|
||||
|
||||
@@ -45,12 +45,9 @@ inline QString IconName() {
|
||||
|
||||
inline bool CanReadDirectory(const QString &path) {
|
||||
#ifndef Q_OS_MAC // directory_iterator since 10.15
|
||||
try {
|
||||
std::filesystem::directory_iterator(path.toStdString());
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
std::error_code error;
|
||||
std::filesystem::directory_iterator(path.toStdString(), error);
|
||||
return !error;
|
||||
#else
|
||||
Unexpected("Not implemented.");
|
||||
#endif
|
||||
|
||||