Compare commits

...

110 Commits

Author SHA1 Message Date
John Preston
07c8aae225 Version 2.1.1: Pin to top only new bots. 2020-05-01 21:20:10 +04:00
John Preston
3c1c17ef80 Version 2.1.1: Remove font substitutions on Win. 2020-05-01 19:59:54 +04:00
Ilya Fedin
b79ecb5909 Show friendly warning if snapd didn't update snap right for some reason 2020-05-01 17:30:11 +04:00
John Preston
b98f0933af Version 2.1.1.
- Improve quiz explanation tooltip layout.
- Fix possible crash in theme editor.
- Other minor bug fixes and improvements.
2020-05-01 17:16:57 +04:00
John Preston
05dcd6fc9c Fix possible crash in rlottie.
Fixes #7767.
2020-05-01 17:16:57 +04:00
John Preston
19bcc145ad Fix crash in theme editor. 2020-05-01 16:27:55 +04:00
John Preston
4ae760dd7e Fix send files emoji panel geometry.
Fixes #7704.
2020-05-01 16:05:24 +04:00
RadRussianRus
cad4d19272 Use "subscribers" instead of "members" in channels 2020-05-01 15:48:07 +04:00
Aokromes
ae64747489 Remove whitespaces, fix spaces 2020-05-01 14:47:33 +04:00
John Preston
db5d599052 Don't resolve the actual QImage on paste check. 2020-05-01 14:43:02 +04:00
John Preston
cc463b07b1 Don't send dice / dart to channels.
Fixes #7703.
2020-05-01 14:35:20 +04:00
John Preston
d8e55081b0 Disallow revoking dice media in first 24 hours.
Fixes #7745.
2020-05-01 13:21:57 +04:00
John Preston
9c66bd553a Increment emoji cache version. 2020-05-01 12:59:23 +04:00
23rd
a6bb180e22 Fixed rendering of colored Apple emoji with gender.
Fixed #6024.
2020-05-01 12:46:31 +04:00
John Preston
38ca3ba341 Update submodules. 2020-05-01 12:32:03 +04:00
23rd
8ef00dc4ff Fixed resetting menu scroll after refresh of filter list. 2020-05-01 12:31:13 +04:00
23rd
1630ad0804 Fixed crash when user pins chat in remotely removed filter. 2020-05-01 12:31:13 +04:00
23rd
c3c482aa50 Improved peer context menu item to archive chat. 2020-05-01 12:31:13 +04:00
23rd
f4a63e1e9d Removed info display for last messages in Saved Messages. 2020-05-01 12:31:13 +04:00
Ilya Fedin
161e51757c Change color of wayland decoration according to theme 2020-05-01 12:26:10 +04:00
Ilya Fedin
46d4b03d49 Fix freeze in notifications settings when notification daemon is unavailable 2020-05-01 12:15:01 +04:00
RadRussianRus
48743a7973 Exclude files that aren't necessary for actions 2020-05-01 12:12:49 +04:00
seniorivn
6709147560 Update shortcuts.cpp 2020-05-01 12:11:14 +04:00
seniorivn
0b2d4326e7 add folder commands for custom config 2020-05-01 12:11:14 +04:00
RadRussianRus
ca49e74b6f Show bot privacy status 2020-05-01 12:10:32 +04:00
Ilya Fedin
95b4f56b86 Don't use QDesktopServices::openUrl on snap 2020-05-01 12:06:01 +04:00
Nicholas Guriev
9828262a03 Update GSL to v3.0.1 and lib_base
* Use identical types for std::min.
2020-05-01 12:03:18 +04:00
John Preston
f76e094e98 Use info toast to show proxy / psa about text. 2020-04-30 15:20:50 +04:00
John Preston
067e52f5d1 Add an icon to the psa / quiz tooltip. 2020-04-30 14:51:26 +04:00
John Preston
4efd649c27 Hide tooltip button in psa / quizes. 2020-04-30 14:11:05 +04:00
John Preston
ff25f1d5c9 Slide psa / quiz toast from the top. 2020-04-30 13:16:42 +04:00
John Preston
dd78052f92 Use new toast style structure. 2020-04-30 11:35:01 +04:00
John Preston
8a4c7e3994 Show PSA tooltip icon and tooltip. 2020-04-30 11:35:01 +04:00
John Preston
44e71dfa03 Allow hiding PSA from the chats list. 2020-04-30 11:35:01 +04:00
John Preston
b6e184d0c8 Support bots as top promoted dialog entries. 2020-04-30 11:35:01 +04:00
John Preston
042ed8f54a Support psa_message in chats list. 2020-04-30 11:35:01 +04:00
John Preston
aabc8173c3 Use similar margins in all controls. 2020-04-30 11:35:01 +04:00
John Preston
c14e20b33f Support PSA forwarded info. 2020-04-30 11:35:01 +04:00
John Preston
266c1531ce Display PSA label instead of the proxy sponsor. 2020-04-30 11:35:01 +04:00
John Preston
8d632bd2be Update API scheme to layer 103. 2020-04-30 11:35:01 +04:00
John Preston
c70a1f03de Fix applying poll updates. 2020-04-30 11:35:01 +04:00
Ilya Fedin
17de6c1ff3 Fix scaling in crash reporter 2020-04-29 15:51:24 +04:00
Stepan Skryabin
4e210e40a2 Update supported Ubuntu version 2020-04-28 19:01:05 +04:00
Ilya Fedin
e13593b095 Restore setFamily in crash report window
Since setFamily in QApplication::setFont was removed
2020-04-28 19:00:44 +04:00
Ilya Fedin
e149f10d40 Revert gtk3 dialog in snap 2020-04-26 12:28:34 +04:00
Ilya Fedin
7f890122e6 Add methods to detect appimage, static binary and forced gtk dialog 2020-04-26 12:28:34 +04:00
Ilya Fedin
422831fa79 Update snap cache 2020-04-26 12:25:01 +04:00
Ilya Fedin
7494468f1f Add cinnamon gsettings schema to snap
Fixes #7697
2020-04-26 12:25:01 +04:00
Ilya Fedin
7bc86cc9af Fix directory opening with portal and use them by default with KDE 2020-04-24 14:33:26 +04:00
John Preston
c1f3fe1961 Version 2.1.
- Access a catalog of over 20,000 stickers made by professional
artists from the updated Sticker Panel by clicking the '+' icon.
- Use sticker search to find the stickers you're looking for - or
scroll from the latest packs all the way to the classics.
- Add explanations that appear after users respond to a quiz question.
- See how much time you have left to answer a question from @QuizBot
with the new countdown animation.
- Send a single 🎯 emoji to see if you hit the bullseye.
2020-04-24 09:08:08 +04:00
John Preston
cfd733c54c Add confirmation box for suspicious urls. 2020-04-23 19:00:19 +04:00
John Preston
3fa5e004fe Allow editing messages in channels indefinitely. 2020-04-23 16:21:30 +04:00
John Preston
862e4e45ad Closed alpha version 2.0.1.3. 2020-04-21 18:55:56 +04:00
John Preston
53df4d1b10 Fix magic for initConnection. 2020-04-21 18:55:35 +04:00
John Preston
5cfd402b70 Make darker toasts for quiz solutions. 2020-04-21 18:55:35 +04:00
John Preston
57e9651a8a Fix visual glitch in poll results viewing.
We need a visible widget to mark more button height.
An invisible 'more' button doesn't receive geometry change events.
2020-04-21 18:55:35 +04:00
John Preston
53d206c12c Custom tab-order for create poll box. 2020-04-21 18:55:35 +04:00
John Preston
46f3cf3395 Load more official sets while scrolling. 2020-04-21 18:55:35 +04:00
John Preston
dfc0491524 Improve trending stickers layout and position. 2020-04-21 18:55:35 +04:00
John Preston
54f757e770 Allow sending dice from dice media tooltip. 2020-04-21 18:55:35 +04:00
John Preston
abfd3ad1b9 Use built-in zero-value dice animations. 2020-04-21 18:55:35 +04:00
John Preston
bed208d621 Send dice media based on appconfig. 2020-04-21 18:55:35 +04:00
John Preston
33c453a13c Scroll history to bottom on sending a message. 2020-04-21 18:55:35 +04:00
John Preston
e118972d5c Support generic dice media display. 2020-04-21 18:55:35 +04:00
John Preston
fb8a9a930c Closed alpha version 2.0.1.2. 2020-04-21 18:55:35 +04:00
John Preston
7a9cfcc40d Improve poll closing by timer and results reloading. 2020-04-21 18:55:35 +04:00
John Preston
e1dc15321a Work around 32-bitness of GetLastInputInfo.
Fixes #7637.
2020-04-21 18:55:35 +04:00
John Preston
2b5e575b67 Closed alpha version 2.0.1.1: Fix macOS fonts. 2020-04-21 18:55:34 +04:00
John Preston
42e216603c Closed alpha version 2.0.1.1. 2020-04-21 18:55:34 +04:00
23rd
d46e145c61 Updated Qt to 5.12.8. 2020-04-21 18:55:34 +04:00
John Preston
5dcb232b77 Force reload results on auto-closed quiz. 2020-04-21 18:55:34 +04:00
John Preston
b34d5b8306 Check solution length in CreatePollBox. 2020-04-21 18:55:34 +04:00
John Preston
76d81ff197 Improve polls solution icon color. 2020-04-21 18:55:34 +04:00
John Preston
71637d2a0e Show progress left to close by timer in polls. 2020-04-21 18:55:34 +04:00
John Preston
423daecbde Add view solution button to polls. 2020-04-21 18:55:34 +04:00
John Preston
3cb76fb80b Support poll closing by date. 2020-04-21 18:55:34 +04:00
John Preston
6882093ed1 Send init connection params. 2020-04-21 18:55:34 +04:00
John Preston
699761b42f Support poll solution display in a toast. 2020-04-21 18:55:34 +04:00
John Preston
f50c50a152 Fix path choosing for Windows Store version. 2020-04-21 18:55:34 +04:00
John Preston
13d22947df Send poll solution with entities. 2020-04-21 18:55:34 +04:00
John Preston
6c08bab550 Add explanation block to CreatePollBox. 2020-04-21 18:55:34 +04:00
John Preston
3e2f4bed50 Update scheme to layer 102.
Support different dice-like media.
2020-04-21 18:55:34 +04:00
Ilya Fedin
41d39012d2 Synchronize AppMenu availability check with Qt 2020-04-21 14:06:03 +04:00
Ilya Fedin
a7764f84f0 Proper usage of pkg-config 2020-04-21 14:05:22 +04:00
VictorienXP
85fcec2fb5 Add .opus and .oga files as song formats 2020-04-21 14:04:51 +04:00
Ilya Fedin
82e835fbc2 Fix snap action 2020-04-20 10:52:10 +04:00
Ilya Fedin
80684d9073 Remove unnecessary files from snap 2020-04-20 10:52:10 +04:00
Ilya Fedin
b04f0e0d3d Use kde-neon extension for better desktop integration 2020-04-20 10:52:10 +04:00
23rd
65cc9bcd87 Updated parser of issue closer since template was changed.
The issue template was changed in de78f4255e.
2020-04-13 17:18:59 +03:00
Ilya Fedin
bc06a3aea3 Make actions ignore .md files not only in the root of repository 2020-04-13 17:39:00 +04:00
Ilya Fedin
de78f4255e Add installation method to bug report template 2020-04-13 17:39:00 +04:00
John Preston
d67dafaccb Fix check for 4K frame size in streaming. 2020-04-13 15:32:20 +04:00
John Preston
4f8ea4c807 Allow to play in-app large videos. 2020-04-13 15:32:14 +04:00
John Preston
15b19f8565 Allow sending large images again (up to 108MP). 2020-04-13 15:32:06 +04:00
John Preston
b16696db93 Don't scroll down when read from another device. 2020-04-13 15:31:54 +04:00
John Preston
63129072ba Mark voice/video message as read on mention click.
Fixes #5623.
2020-04-13 15:30:56 +04:00
John Preston
1fdd591aa0 Change manage folders button icon. 2020-04-13 15:30:40 +04:00
John Preston
f370ca97d0 Fix folders visibility above passcode lock. 2020-04-13 15:30:23 +04:00
John Preston
f5aba5a907 Fix build with new lib_ui commits. 2020-04-13 15:26:09 +04:00
Ilya Fedin
1d613995db Disable building of dav1d tools and tests in snap 2020-04-13 15:16:33 +04:00
Ilya Fedin
5bb1c77199 Use OpenAL without direct channels 2020-04-13 15:15:29 +04:00
Ilya Fedin
5b39c7013a Better algorithm for font choosing 2020-04-13 11:48:14 +04:00
Ilya Fedin
ed91c07f99 Restore the old behavior with fallback fontconfig configuration
With current code fallback works only through time and replaces the config even if it is changed by the user.

This commit fixes that.
2020-04-13 10:49:30 +04:00
Ilya Fedin
a66b2a4056 Synchronize snap ffmpeg arguments with generic linux one 2020-04-13 10:44:29 +04:00
Ilya Fedin
a1a7399023 Don't remove SNI object when SNI is lost 2020-04-13 10:43:37 +04:00
Ilya Fedin
e71b7dd384 Don't overwrite artifacts by multiple runs 2020-04-13 10:42:32 +04:00
Ilya Fedin
664b43acd7 Fixes for linux action:
* Disable building of unneeded openal tools and tests
* Disable ffmpeg linkage with unneeded libraries
* Disable unneeded dtd validation for libwayland
* Omit Qt flags that set to default values
* Fix prefix usage
* Build dependencies in release mode to reduce build size
2020-04-12 19:21:59 +04:00
Ilya Fedin
eac867ce85 Add possibility to enable autoupdate on non-special target 2020-04-10 15:06:09 +04:00
John Preston
2ad48f18f2 Use only safe file saving in localstorage. 2020-04-02 18:31:15 +04:00
John Preston
e823fe5891 Fix support / media shortcuts. 2020-04-02 16:20:53 +04:00
182 changed files with 3043 additions and 1090 deletions

View File

@@ -25,6 +25,8 @@ Tell us what happens instead
**Version of Telegram Desktop:**
**Installation source (Linux Only)** - the official website / GitHub releases / flatpak / snap / distribution package:
**Used theme**:
<details><summary><b>Logs</b>:</summary>

View File

@@ -21,14 +21,24 @@ jobs:
script: |
let errorStr = "Version not found.";
function maxIndexOf(str, i) {
let index = str.indexOf(i);
return (index == -1) ? Number.MAX_SAFE_INTEGER : index;
}
let item1 = "Version of Telegram Desktop";
let item2 = "Used theme";
let item2 = "Installation source";
let item3 = "Used theme";
let item4 = "<details>";
let body = context.payload.issue.body;
console.log("Body of issue:\n" + body);
let index1 = body.indexOf(item1);
let index2 = body.indexOf(item2);
index2 = (index2 == -1) ? Number.MAX_SAFE_INTEGER : index2;
let index2 = Math.min(
Math.min(
maxIndexOf(body, item2),
maxIndexOf(body, item3)),
maxIndexOf(body, item4));
console.log("Index 1: " + index1);
console.log("Index 2: " + index2);

View File

@@ -4,11 +4,41 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/linux.yml'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/linux.yml'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
jobs:
@@ -25,8 +55,8 @@ jobs:
env:
GIT: "https://github.com"
QT: "5_12_5"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.5"
QT: "5_12_8"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.8"
OPENSSL_VER: "1_1_1"
OPENSSL_PREFIX: "/usr/local/desktop-app/openssl-1.1.1"
CMAKE_VER: "3.17.0"
@@ -189,23 +219,28 @@ jobs:
git clone --branch release/3.4 $GIT/FFmpeg/FFmpeg ffmpeg
cd ffmpeg
./configure --prefix=$LibrariesPath/ffmpeg-cache \
--enable-protocol=file --enable-libopus \
./configure \
--disable-debug \
--disable-programs \
--disable-doc \
--disable-network \
--disable-autodetect \
--disable-everything \
--disable-neon \
--disable-iconv \
--enable-libopus \
--enable-vaapi \
--enable-vdpau \
--enable-protocol=file \
--enable-hwaccel=h264_vaapi \
--enable-hwaccel=h264_vdpau \
--enable-hwaccel=mpeg4_vaapi \
--enable-hwaccel=mpeg4_vdpau \
--enable-decoder=aac \
--enable-decoder=aac_at \
--enable-decoder=aac_fixed \
--enable-decoder=aac_latm \
--enable-decoder=aasc \
--enable-decoder=alac \
--enable-decoder=alac_at \
--enable-decoder=flac \
--enable-decoder=gif \
--enable-decoder=h264 \
@@ -227,14 +262,12 @@ jobs:
--enable-decoder=msmpeg4v3 \
--enable-decoder=opus \
--enable-decoder=pcm_alaw \
--enable-decoder=pcm_alaw_at \
--enable-decoder=pcm_f32be \
--enable-decoder=pcm_f32le \
--enable-decoder=pcm_f64be \
--enable-decoder=pcm_f64le \
--enable-decoder=pcm_lxf \
--enable-decoder=pcm_mulaw \
--enable-decoder=pcm_mulaw_at \
--enable-decoder=pcm_s16be \
--enable-decoder=pcm_s16be_planar \
--enable-decoder=pcm_s16le \
@@ -289,7 +322,7 @@ jobs:
--enable-muxer=opus
make -j$(nproc)
sudo make install
sudo make DESTDIR="$LibrariesPath/ffmpeg-cache" install
cd ..
rm -rf ffmpeg
- name: FFmpeg install.
@@ -298,7 +331,7 @@ jobs:
#List of files from cmake/external/ffmpeg/CMakeLists.txt.
copyLib() {
mkdir -p ffmpeg/$1
yes | cp -i ffmpeg-cache/lib/$1.a ffmpeg/$1/$1.a
yes | cp -i ffmpeg-cache/usr/local/lib/$1.a ffmpeg/$1/$1.a
}
copyLib libavformat
copyLib libavcodec
@@ -306,7 +339,7 @@ jobs:
copyLib libswscale
copyLib libavutil
sudo cp -R ffmpeg-cache/. /usr/local/
sudo cp -R ffmpeg-cache/. /
- name: PortAudio.
run: |
@@ -327,7 +360,13 @@ jobs:
git clone -b openal-soft-1.20.1 --depth=1 $GIT/kcat/openal-soft.git
cd openal-soft/build
cmake -D LIBTYPE:STRING=STATIC ..
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DLIBTYPE:STRING=STATIC \
-DALSOFT_EXAMPLES=OFF \
-DALSOFT_TESTS=OFF \
-DALSOFT_UTILS=OFF \
-DALSOFT_CONFIG=OFF
make -j$(nproc)
sudo make install
cd -
@@ -348,16 +387,15 @@ jobs:
git clone -b OpenSSL_${OPENSSL_VER}-stable --depth=1 \
$GIT/openssl/openssl $opensslDir
cd $opensslDir
./config --prefix=$LibrariesPath/openssl-cache
./config --prefix="$OPENSSL_PREFIX"
make -j$(nproc)
sudo make install_sw
sudo make DESTDIR="$LibrariesPath/openssl-cache" install_sw
cd ..
rm -rf $opensslDir
- name: OpenSSL install.
run: |
cd $LibrariesPath
sudo mkdir -p $OPENSSL_PREFIX
sudo cp -R openssl-cache/. $OPENSSL_PREFIX/
sudo cp -R openssl-cache/. /
- name: Libxkbcommon.
run: |
@@ -377,24 +415,24 @@ jobs:
git clone -b 1.16 https://gitlab.freedesktop.org/wayland/wayland
cd wayland
./autogen.sh --enable-static --disable-documentation
./autogen.sh --enable-static --disable-documentation --disable-dtd-validation
make -j$(nproc)
sudo make install
cd ..
rm -rf wayland
- name: Qt 5.12.5 cache.
- name: Qt 5.12.8 cache.
id: cache-qt
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/qt-cache
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_5.diff') }}
- name: Qt 5.12.5 build.
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}
- name: Qt 5.12.8 build.
if: steps.cache-qt.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
git clone -b v5.12.5 --depth=1 git://code.qt.io/qt/qt5.git qt_${QT}
git clone -b v5.12.8 --depth=1 git://code.qt.io/qt/qt5.git qt_${QT}
cd qt_${QT}
perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg
git submodule update qtbase qtwayland qtimageformats qtsvg
@@ -406,9 +444,8 @@ jobs:
git clone $GIT/desktop-app/nimf.git
cd ../../../..
./configure -prefix "$LibrariesPath/qt-cache" \
./configure -prefix "$QT_PREFIX" \
-release \
-force-debug-info \
-opensource \
-confirm-license \
-qt-zlib \
@@ -417,8 +454,6 @@ jobs:
-qt-harfbuzz \
-qt-pcre \
-qt-xcb \
-system-freetype \
-fontconfig \
-no-gtk \
-static \
-dbus-runtime \
@@ -428,14 +463,25 @@ jobs:
-nomake tests
make -j$(nproc)
sudo make install
sudo make INSTALL_ROOT="$LibrariesPath/qt-cache" install
cd ..
rm -rf qt_${QT}
- name: Qt 5.12.5 install.
- name: Qt 5.12.8 install.
run: |
cd $LibrariesPath
sudo mkdir -p $QT_PREFIX
sudo cp -R qt-cache/. $QT_PREFIX/
sudo cp -R qt-cache/. /
- name: Material Decoration.
run: |
cd $LibrariesPath
git clone --depth=1 $GIT/desktop-app/materialdecoration.git
cd materialdecoration
$QT_PREFIX/bin/qmake CONFIG+=static
make -j$(nproc)
sudo make install
cd ..
rm -rf materialdecoration
- name: Breakpad cache.
id: cache-breakpad
@@ -467,9 +513,9 @@ jobs:
cd ..
cd breakpad
./configure --prefix=$BreakpadCache
./configure
make -j$(nproc)
sudo make install
sudo make DESTDIR="$BreakpadCache" install
cd src
rm -r testing
git clone $GIT/google/googletest testing
@@ -486,7 +532,7 @@ jobs:
- name: Breakpad install.
run: |
cd $LibrariesPath
sudo cp -R breakpad-cache/. /usr/local/
sudo cp -R breakpad-cache/. /
mkdir -p breakpad/out/Default/
cp breakpad-cache/dump_syms breakpad/out/Default/dump_syms
@@ -499,6 +545,9 @@ jobs:
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
echo Define from matrix: $DEFINE
echo ::set-env name=ARTIFACT_NAME::Telegram_${{ matrix.defines }}
else
echo ::set-env name=ARTIFACT_NAME::Telegram
fi
./configure.sh \
@@ -534,5 +583,5 @@ jobs:
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
name: Telegram
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}/out/Debug/bin/artifact/

View File

@@ -4,11 +4,39 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/mac.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/configure.bat'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/mac.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/configure.bat'
jobs:
@@ -27,9 +55,9 @@ jobs:
PREFIX: "/usr/local/macos"
MACOSX_DEPLOYMENT_TARGET: "10.12"
XZ: "xz-5.2.4"
QT: "5_12_5"
QT: "5_12_8"
OPENSSL_VER: "1_1_1"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.5"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.8"
LIBICONV_VER: "libiconv-1.16"
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
@@ -376,20 +404,20 @@ jobs:
build/gyp_crashpad.py -Dmac_deployment_target=10.10
ninja -C out/Debug
- name: Qt 5.12.5 cache.
- name: Qt 5.12.8 cache.
id: cache-qt
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/qt-cache
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_5.diff') }}
- name: Use cached Qt 5.12.5.
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}
- name: Use cached Qt 5.12.8.
if: steps.cache-qt.outputs.cache-hit == 'true'
run: |
cd $LibrariesPath
mv qt-cache Qt-5.12.5
mv qt-cache Qt-5.12.8
sudo mkdir -p $QT_PREFIX
sudo mv -f Qt-5.12.5 "$(dirname "$QT_PREFIX")"/
- name: Qt 5.12.5 build.
sudo mv -f Qt-5.12.8 "$(dirname "$QT_PREFIX")"/
- name: Qt 5.12.8 build.
if: steps.cache-qt.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
@@ -397,7 +425,7 @@ jobs:
git clone git://code.qt.io/qt/qt5.git qt$QT
cd qt$QT
perl init-repository --module-subset=qtbase,qtimageformats
git checkout v5.12.5
git checkout v5.12.8
git submodule update qtbase
git submodule update qtimageformats
cd qtbase
@@ -433,6 +461,9 @@ jobs:
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
echo Define from matrix: $DEFINE
echo ::set-env name=ARTIFACT_NAME::Telegram_${{ matrix.defines }}
else
echo ::set-env name=ARTIFACT_NAME::Telegram
fi
./configure.sh -D TDESKTOP_API_TEST=ON -D DESKTOP_APP_USE_PACKAGED=OFF $DEFINE
@@ -453,5 +484,5 @@ jobs:
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
name: Telegram
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}/out/Debug/artifact/

View File

@@ -4,11 +4,41 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
jobs:
@@ -19,7 +49,7 @@ jobs:
env:
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
MANUAL_CACHING: "3"
MANUAL_CACHING: "5"
steps:
- name: Clone.
@@ -29,9 +59,6 @@ jobs:
- name: First set up.
run: |
# Workaround for Heroku
curl https://cli-assets.heroku.com/apt/release.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install gcc-8 g++-8 -y
sudo snap install --classic snapcraft
@@ -50,7 +77,7 @@ jobs:
md5 $keyName
}
snapcraft --version > CACHE_KEY.txt
snap run snapcraft --version > CACHE_KEY.txt
gcc-8 --version >> CACHE_KEY.txt
echo $MANUAL_CACHING >> CACHE_KEY.txt
md5 CACHE_KEY
@@ -67,7 +94,7 @@ jobs:
- name: CMake build.
if: steps.cache-cmake.outputs.cache-hit != 'true'
run: sudo snapcraft build --destructive-mode cmake
run: sudo snap run snapcraft build --destructive-mode cmake
- name: FFmpeg cache.
id: cache-ffmpeg
@@ -78,11 +105,11 @@ jobs:
- name: FFmpeg build.
if: steps.cache-ffmpeg.outputs.cache-hit != 'true'
run: sudo snapcraft build --destructive-mode ffmpeg
run: sudo snap run snapcraft build --destructive-mode ffmpeg
- name: Telegram Desktop snap build.
if: env.ONLY_CACHE == 'false'
run: sudo snapcraft --destructive-mode
run: sudo snap run snapcraft --destructive-mode
- name: Move artifact.
if: env.UPLOAD_ARTIFACT == 'true'
@@ -102,5 +129,5 @@ jobs:
- name: Remove unneeded directories for cache.
run: |
sudo rm -rf parts/{cmake,ffmpeg}/{build,src,ubuntu}
sudo rm -rf parts/{cmake,ffmpeg}/state/{stage,prime}
sudo rm -rf parts/*/{build,src,ubuntu}
sudo rm -rf parts/*/state/{stage,prime}

View File

@@ -4,11 +4,44 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/win.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/build_ffmpeg_win.sh'
- 'Telegram/Resources/uwp/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.sh'
- 'Telegram/Telegram.plist'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/win.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/build_ffmpeg_win.sh'
- 'Telegram/Resources/uwp/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/SourceFiles/platform/mac/**'
- '!Telegram/Patches/breakpad.diff'
- 'Telegram/Telegram/**'
- 'Telegram/configure.sh'
- 'Telegram/Telegram.plist'
jobs:
@@ -24,7 +57,7 @@ jobs:
SDK: "10.0.18362.0"
VC: "call vcvars32.bat && cd Libraries"
GIT: "https://github.com"
QT: "5_12_5"
QT: "5_12_8"
OPENSSL_VER: "1_1_1"
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
@@ -263,13 +296,13 @@ jobs:
rmdir /S /Q .git
- name: Qt 5.12.5 cache.
- name: Qt 5.12.8 cache.
id: cache-qt
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/Qt-5.12.5
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_5.diff') }}
- name: Configure Qt 5.12.5.
path: ${{ env.LibrariesPath }}/Qt-5.12.8
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}
- name: Configure Qt 5.12.8.
if: steps.cache-qt.outputs.cache-hit != 'true'
shell: cmd
run: |
@@ -278,7 +311,7 @@ jobs:
git clone git://code.qt.io/qt/qt5.git qt_%QT%
cd qt_%QT%
perl init-repository --module-subset=qtbase,qtimageformats
git checkout v5.12.5
git checkout v5.12.8
git submodule update qtbase
git submodule update qtimageformats
cd qtbase
@@ -289,7 +322,7 @@ jobs:
SET LIBS=libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib
configure ^
-prefix "%LibrariesPath%\Qt-5.12.5" ^
-prefix "%LibrariesPath%\Qt-5.12.8" ^
-debug ^
-force-debug-info ^
-opensource ^
@@ -304,7 +337,7 @@ jobs:
-nomake examples ^
-nomake tests ^
-platform win32-msvc
- name: Qt 5.12.5 build.
- name: Qt 5.12.8 build.
if: steps.cache-qt.outputs.cache-hit != 'true'
shell: cmd
run: |
@@ -324,6 +357,9 @@ jobs:
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
echo Define from matrix: $DEFINE
echo ::set-env name=ARTIFACT_NAME::Telegram_${{ matrix.defines }}
else
echo ::set-env name=ARTIFACT_NAME::Telegram
fi
echo "::set-env name=TDESKTOP_BUILD_DEFINE::$DEFINE"
@@ -355,5 +391,5 @@ jobs:
name: Upload artifact.
if: env.UPLOAD_ARTIFACT == 'true'
with:
name: Telegram
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}\out\Debug\artifact\

View File

@@ -16,14 +16,14 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* Windows XP - Windows 10 (**not** RT)
* Mac OS X 10.8 - Mac OS X 10.15
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
* Ubuntu 12.04 - Ubuntu 19.10
* Ubuntu 12.04 - Ubuntu 20.04
* Fedora 22 - Fedora 31
* [Snappy](https://snapcraft.io/telegram-desktop)
* [Flathub](https://flathub.org/apps/details/org.telegram.desktop)
## Third-party
* Qt 5.12.5 and 5.6.2, slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
* Qt 5.12.8 and 5.6.2, slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
* OpenSSL 1.1.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
* zlib 1.2.11 ([zlib License](http://www.zlib.net/zlib_license.html))
* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))

View File

@@ -1033,6 +1033,7 @@ PRIVATE
winrc/Telegram.rc
winrc/Telegram.manifest
langs/lang.strings
langs/cloud_lang.strings
numbers.txt
)
@@ -1187,7 +1188,7 @@ endif()
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
if ((NOT disable_autoupdate OR NOT LINUX) AND NOT build_macstore AND NOT build_winstore)
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR NOT LINUX) AND NOT build_macstore AND NOT build_winstore)
add_executable(Updater WIN32)
init_target(Updater)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -6,6 +6,11 @@ For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
"cloud_lng_badge_psa_covid" = "COVID-19";
"cloud_lng_about_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. To remove it from your chats list, right click it and select **Hide**.";
"cloud_lng_forwarded_psa_covid" = "COVID-19 Notification from {channel}";
"cloud_lng_tooltip_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. Learn more about this initiative at https://telegram.org/blog/coronavirus";
"cloud_lng_passport_in_ar" = "Arabic";
"cloud_lng_passport_in_az" = "Azerbaijani";
"cloud_lng_passport_in_bg" = "Bulgarian";

View File

@@ -118,6 +118,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_chat_status_online#one" = "{count} online";
"lng_chat_status_online#other" = "{count} online";
"lng_chat_status_members_online" = "{members_count}, {online_count}";
"lng_chat_status_subscribers#one" = "{count} subscriber";
"lng_chat_status_subscribers#other" = "{count} subscribers";
"lng_channel_status" = "channel";
"lng_group_status" = "group";
@@ -600,6 +602,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_proxy_sponsor" = "Proxy sponsor";
"lng_proxy_sponsor_about" = "This channel is shown by your proxy server.\nTo remove this channel from your chats list,\ndisable the proxy in Telegram Settings.";
"lng_proxy_sponsor_warning" = "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic.";
"lng_badge_psa_default" = "PSA";
"lng_about_psa_default" = "This message provides you with a public service announcement. To remove it from your chats list, right click it and select **Hide**.";
"lng_tooltip_psa_default" = "This message provides you with a public service announcement.";
"lng_settings_blocked_users" = "Blocked users";
"lng_settings_no_blocked_users" = "None";
@@ -764,6 +769,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_common_groups#one" = "{count} group in common";
"lng_profile_common_groups#other" = "{count} groups in common";
"lng_profile_participants_section" = "Members";
"lng_profile_subscribers_section" = "Subscribers";
"lng_profile_mobile_number" = "Mobile:";
"lng_profile_username" = "Username:";
"lng_profile_link" = "Link:";
@@ -885,6 +891,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_channel_info" = "Channel Info";
"lng_manage_peer_recent_actions" = "Recent Actions";
"lng_manage_peer_members" = "Members";
"lng_manage_peer_subscribers" = "Subscribers";
"lng_manage_peer_administrators" = "Administrators";
"lng_manage_peer_exceptions" = "Exceptions";
"lng_manage_peer_removed_users" = "Removed users";
@@ -1126,6 +1133,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_forwarded" = "Forwarded from {user}";
"lng_forwarded_date" = "Original: {date}";
"lng_forwarded_channel" = "Forwarded from {channel}";
"lng_forwarded_psa_default" = "Forwarded from {channel}";
"lng_forwarded_via" = "Forwarded from {user} via {inline_bot}";
"lng_forwarded_channel_via" = "Forwarded from {channel} via {inline_bot}";
"lng_forwarded_signed" = "{channel} ({user})";
@@ -1329,7 +1337,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_dialogs_skip_archive_in_search" = "Skip results from archive";
"lng_dialogs_show_archive_in_search" = "With results from archive";
"lng_about_dice" = "Send a 🎲 emoji to any chat to get a random number from Telegram.";
"lng_about_random" = "Send a {emoji} emoji to any chat to get a random number from Telegram.";
"lng_about_random_send" = "Send";
"lng_open_this_link" = "Open this link?";
"lng_open_link" = "Open";
@@ -1400,6 +1409,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_view_group" = "View group info";
"lng_context_view_channel" = "View channel info";
//"lng_context_view_feed_info" = "View feed info";
"lng_context_hide_psa" = "Hide this announcement";
"lng_context_pin_to_top" = "Pin to top";
"lng_context_unpin_from_top" = "Unpin from top";
"lng_context_mark_unread" = "Mark as unread";
@@ -2223,6 +2233,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_polls_choose_question" = "Please enter a question.";
"lng_polls_choose_answers" = "Please enter at least two options.";
"lng_polls_choose_correct" = "Please choose the correct answer.";
"lng_polls_solution_title" = "Explanation";
"lng_polls_solution_placeholder" = "Add a Comment (Optional)";
"lng_polls_solution_about" = "Users will see this comment after choosing a wrong answer, good for educational purposes.";
"lng_polls_poll_results_title" = "Poll results";
"lng_polls_quiz_results_title" = "Quiz results";

View File

@@ -48,6 +48,7 @@
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
<file alias="art/sunrise.jpg">../../art/sunrise.jpg</file>
<file alias="art/dice_idle.tgs">../../art/dice_idle.tgs</file>
<file alias="art/dart_idle.tgs">../../art/dart_idle.tgs</file>
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>

View File

@@ -71,8 +71,8 @@ inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int =
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
inputMediaPoll#abe9ca25 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> = InputMedia;
inputMediaDice#aeffa807 = InputMedia;
inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
@@ -157,7 +157,7 @@ messageMediaGame#fdb19008 game:Game = MessageMedia;
messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageMediaDice#638fe46b value:int = MessageMedia;
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
@@ -533,7 +533,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
inputStickerSetDice#79e21a53 = InputStickerSet;
inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
@@ -651,7 +651,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
messageFwdHeader#353a686b flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader;
auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
@@ -692,8 +692,8 @@ contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers;
messages.featuredStickers#b6abc341 hash:int count:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers;
@@ -912,9 +912,6 @@ fileHash#6242c773 offset:int limit:int hash:bytes = FileHash;
inputClientProxy#75588b3f address:string port:int = InputClientProxy;
help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData;
help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector<Chat> users:Vector<User> = help.ProxyData;
help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate;
help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate;
@@ -1024,11 +1021,11 @@ help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:strin
pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
poll#d5529d06 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> = Poll;
poll#86e18161 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> close_period:flags.4?int close_date:flags.5?int = Poll;
pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters;
pollResults#c87024a2 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> = PollResults;
pollResults#badcc1a3 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> solution:flags.4?string solution_entities:flags.4?Vector<MessageEntity> = PollResults;
chatOnlines#f041e250 onlines:int = ChatOnlines;
@@ -1140,11 +1137,14 @@ messageInteractionCounters#ad4fc9bd msg_id:int views:int forwards:int = MessageI
stats.broadcastStats#bdf78394 period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph recent_message_interactions:Vector<MessageInteractionCounters> = stats.BroadcastStats;
help.promoDataEmpty#98f6ac75 expires:int = help.PromoData;
help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer chats:Vector<Chat> users:Vector<User> psa_type:flags.1?string psa_message:flags.2?string = help.PromoData;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X;
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
@@ -1382,6 +1382,7 @@ messages.getDialogFilters#f19ed96d = Vector<DialogFilter>;
messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@@ -1410,7 +1411,6 @@ help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
help.getProxyData#3d7758e1 = help.ProxyData;
help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
@@ -1420,6 +1420,8 @@ help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
help.getSupportName#d360e72c = help.SupportName;
help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo;
help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<MessageEntity> = help.UserInfo;
help.getPromoData#c0977421 = help.PromoData;
help.hidePromoData#1e251c95 peer:InputPeer = Bool;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
@@ -1459,6 +1461,7 @@ channels.getInactiveChannels#11e831ee = messages.InactiveChats;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
bots.setBotCommands#805d46f6 commands:Vector<BotCommand> = Bool;
payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm;
payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt;
@@ -1468,10 +1471,11 @@ payments.getSavedInfo#227d824b = payments.SavedInfo;
payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool;
payments.getBankCardData#2e79d779 number:string = payments.BankCardData;
stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector<InputStickerSetItem> = messages.StickerSet;
stickers.createStickerSet#f1036780 flags:# masks:flags.0?true animated:flags.1?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> = messages.StickerSet;
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;
stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet;
stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
stickers.setStickerSetThumb#9a364e30 stickerset:InputStickerSet thumb:InputDocument = messages.StickerSet;
phone.getCallConfig#55451fa9 = DataJSON;
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
@@ -1494,4 +1498,4 @@ folders.deleteFolder#1c295881 folder_id:int = Updates;
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
// LAYER 111
// LAYER 113

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="2.0.1.0" />
Version="2.1.1.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>

View File

@@ -33,8 +33,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,1,0
PRODUCTVERSION 2,0,1,0
FILEVERSION 2,1,1,0
PRODUCTVERSION 2,1,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -51,10 +51,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "2.0.1.0"
VALUE "FileVersion", "2.1.1.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.0.1.0"
VALUE "ProductVersion", "2.1.1.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -24,8 +24,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,1,0
PRODUCTVERSION 2,0,1,0
FILEVERSION 2,1,1,0
PRODUCTVERSION 2,1,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -42,10 +42,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "2.0.1.0"
VALUE "FileVersion", "2.1.1.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.0.1.0"
VALUE "ProductVersion", "2.1.1.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities.
#include "ui/text/text_entity.h" // TextWithEntities.
#include "main/main_session.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "mainwidget.h"
#include "apiwrap.h"
#include "app.h"
@@ -199,8 +201,23 @@ void SendExistingPhoto(
}
bool SendDice(Api::MessageToSend &message) {
static const auto kDiceString = QString::fromUtf8("\xF0\x9F\x8E\xB2");
if (message.textWithTags.text.midRef(0).trimmed() != kDiceString) {
const auto full = message.textWithTags.text.midRef(0).trimmed();
auto length = 0;
if (!Ui::Emoji::Find(full.data(), full.data() + full.size(), &length)
|| length != full.size()) {
return false;
}
auto &account = message.action.history->session().account();
auto &config = account.appConfig();
static const auto hardcoded = std::vector<QString>{
QString::fromUtf8("\xF0\x9F\x8E\xB2"),
QString::fromUtf8("\xF0\x9F\x8E\xAF")
};
const auto list = config.get<std::vector<QString>>(
"emojies_send_dice",
hardcoded);
const auto emoji = full.toString();
if (!ranges::contains(list, emoji)) {
return false;
}
const auto history = message.action.history;
@@ -266,7 +283,7 @@ bool SendDice(Api::MessageToSend &message) {
MTP_int(HistoryItem::NewMessageDate(
message.action.options.scheduled)),
MTP_string(),
MTP_messageMediaDice(MTP_int(0)),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(),
MTP_int(1),
@@ -284,7 +301,7 @@ bool SendDice(Api::MessageToSend &message) {
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
MTP_inputMediaDice(),
MTP_inputMediaDice(MTP_string(emoji)),
MTP_string(),
MTP_long(randomId),
MTPReplyMarkup(),

View File

@@ -23,6 +23,6 @@ void SendExistingPhoto(
Api::MessageToSend &&message,
not_null<PhotoData*> photo);
[[nodiscard]] bool SendDice(Api::MessageToSend &message);
bool SendDice(Api::MessageToSend &message);
} // namespace Api

View File

@@ -88,8 +88,8 @@ constexpr auto kMaxUsersPerInvite = 100;
// that was added to this chat.
constexpr auto kForwardMessagesOnAdd = 100;
constexpr auto kProxyPromotionInterval = TimeId(60 * 60);
constexpr auto kProxyPromotionMinDelay = TimeId(10);
constexpr auto kTopPromotionInterval = TimeId(60 * 60);
constexpr auto kTopPromotionMinDelay = TimeId(10);
constexpr auto kSmallDelayMs = 5;
constexpr auto kUnreadMentionsPreloadIfLess = 5;
constexpr auto kUnreadMentionsFirstRequestLimit = 10;
@@ -237,7 +237,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
, _dialogsLoadState(std::make_unique<DialogsLoadState>())
, _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
//, _feedReadTimer([=] { readFeeds(); }) // #feed
, _proxyPromotionTimer([=] { refreshProxyPromotion(); })
, _topPromotionTimer([=] { refreshTopPromotion(); })
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); })
, _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this)) {
@@ -288,13 +288,13 @@ void ApiWrap::requestChangelog(
).send();
}
void ApiWrap::refreshProxyPromotion() {
void ApiWrap::refreshTopPromotion() {
const auto now = base::unixtime::now();
const auto next = (_proxyPromotionNextRequestTime != 0)
? _proxyPromotionNextRequestTime
const auto next = (_topPromotionNextRequestTime != 0)
? _topPromotionNextRequestTime
: now;
if (_proxyPromotionRequestId) {
getProxyPromotionDelayed(now, next);
if (_topPromotionRequestId) {
getTopPromotionDelayed(now, next);
return;
}
const auto key = [&]() -> std::pair<QString, uint32> {
@@ -307,51 +307,51 @@ void ApiWrap::refreshProxyPromotion() {
}
return { proxy.host, proxy.port };
}();
if (_proxyPromotionKey == key && now < next) {
getProxyPromotionDelayed(now, next);
if (_topPromotionKey == key && now < next) {
getTopPromotionDelayed(now, next);
return;
}
_proxyPromotionKey = key;
if (key.first.isEmpty() || !key.second) {
proxyPromotionDone(MTP_help_proxyDataEmpty(
MTP_int(base::unixtime::now() + kProxyPromotionInterval)));
return;
}
_proxyPromotionRequestId = request(MTPhelp_GetProxyData(
)).done([=](const MTPhelp_ProxyData &result) {
_proxyPromotionRequestId = 0;
proxyPromotionDone(result);
_topPromotionKey = key;
_topPromotionRequestId = request(MTPhelp_GetPromoData(
)).done([=](const MTPhelp_PromoData &result) {
_topPromotionRequestId = 0;
topPromotionDone(result);
}).fail([=](const RPCError &error) {
_proxyPromotionRequestId = 0;
_topPromotionRequestId = 0;
const auto now = base::unixtime::now();
const auto next = _proxyPromotionNextRequestTime = now
+ kProxyPromotionInterval;
if (!_proxyPromotionTimer.isActive()) {
getProxyPromotionDelayed(now, next);
const auto next = _topPromotionNextRequestTime = now
+ kTopPromotionInterval;
if (!_topPromotionTimer.isActive()) {
getTopPromotionDelayed(now, next);
}
}).send();
}
void ApiWrap::getProxyPromotionDelayed(TimeId now, TimeId next) {
_proxyPromotionTimer.callOnce(std::min(
std::max(next - now, kProxyPromotionMinDelay),
kProxyPromotionInterval) * crl::time(1000));
void ApiWrap::getTopPromotionDelayed(TimeId now, TimeId next) {
_topPromotionTimer.callOnce(std::min(
std::max(next - now, kTopPromotionMinDelay),
kTopPromotionInterval) * crl::time(1000));
};
void ApiWrap::proxyPromotionDone(const MTPhelp_ProxyData &proxy) {
_proxyPromotionNextRequestTime = proxy.match([&](const auto &data) {
void ApiWrap::topPromotionDone(const MTPhelp_PromoData &proxy) {
_topPromotionNextRequestTime = proxy.match([&](const auto &data) {
return data.vexpires().v;
});
getProxyPromotionDelayed(base::unixtime::now(), _proxyPromotionNextRequestTime);
getTopPromotionDelayed(
base::unixtime::now(),
_topPromotionNextRequestTime);
proxy.match([&](const MTPDhelp_proxyDataEmpty &data) {
_session->data().setProxyPromoted(nullptr);
}, [&](const MTPDhelp_proxyDataPromo &data) {
proxy.match([&](const MTPDhelp_promoDataEmpty &data) {
_session->data().setTopPromoted(nullptr, QString(), QString());
}, [&](const MTPDhelp_promoData &data) {
_session->data().processChats(data.vchats());
_session->data().processUsers(data.vusers());
const auto peerId = peerFromMTP(data.vpeer());
const auto peer = _session->data().peer(peerId);
_session->data().setProxyPromoted(peer);
_session->data().setTopPromoted(
peer,
data.vpsa_type().value_or_empty(),
data.vpsa_message().value_or_empty());
if (const auto history = _session->data().historyLoaded(peer)) {
history->owner().histories().requestDialogEntry(history);
}
@@ -5754,16 +5754,6 @@ void ApiWrap::createPoll(
if (action.options.scheduled) {
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
const auto inputFlags = data.quiz()
? MTPDinputMediaPoll::Flag::f_correct_answers
: MTPDinputMediaPoll::Flag(0);
auto correct = QVector<MTPbytes>();
for (const auto &answer : data.answers) {
if (answer.correct) {
correct.push_back(MTP_bytes(answer.option));
}
}
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
@@ -5772,10 +5762,7 @@ void ApiWrap::createPoll(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
MTP_inputMediaPoll(
MTP_flags(inputFlags),
PollDataToMTP(&data),
MTP_vector<MTPbytes>(correct)),
PollDataToInputMedia(&data),
MTP_string(),
MTP_long(rand_value<uint64>()),
MTPReplyMarkup(),
@@ -5852,25 +5839,12 @@ void ApiWrap::closePoll(not_null<HistoryItem*> item) {
if (!poll) {
return;
}
const auto inputFlags = poll->quiz()
? MTPDinputMediaPoll::Flag::f_correct_answers
: MTPDinputMediaPoll::Flag(0);
auto correct = QVector<MTPbytes>();
for (const auto &answer : poll->answers) {
if (answer.correct) {
correct.push_back(MTP_bytes(answer.option));
}
}
const auto requestId = request(MTPmessages_EditMessage(
MTP_flags(MTPmessages_EditMessage::Flag::f_media),
item->history()->peer->input,
MTP_int(item->id),
MTPstring(),
MTP_inputMediaPoll(
MTP_flags(inputFlags),
PollDataToMTP(poll, true),
MTP_vector<MTPbytes>(correct)),
PollDataToInputMedia(poll, true),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(0) // schedule_date

View File

@@ -208,7 +208,7 @@ public:
void requestChangelog(
const QString &sinceVersion,
Fn<void(const MTPUpdates &result)> callback);
void refreshProxyPromotion();
void refreshTopPromotion();
void requestDeepLinkInfo(
const QString &path,
Fn<void(const MTPDhelp_deepLinkInfo &result)> callback);
@@ -646,8 +646,8 @@ private:
//void readFeeds(); // #feed
void getProxyPromotionDelayed(TimeId now, TimeId next);
void proxyPromotionDone(const MTPhelp_ProxyData &proxy);
void getTopPromotionDelayed(TimeId now, TimeId next);
void topPromotionDone(const MTPhelp_PromoData &proxy);
void sendNotifySettingsUpdates();
@@ -787,10 +787,10 @@ private:
//base::flat_map<not_null<Data::Feed*>, mtpRequestId> _feedReadRequests;
//base::Timer _feedReadTimer;
mtpRequestId _proxyPromotionRequestId = 0;
std::pair<QString, uint32> _proxyPromotionKey;
TimeId _proxyPromotionNextRequestTime = TimeId(0);
base::Timer _proxyPromotionTimer;
mtpRequestId _topPromotionRequestId = 0;
std::pair<QString, uint32> _topPromotionKey;
TimeId _topPromotionNextRequestTime = TimeId(0);
base::Timer _topPromotionTimer;
base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers;
base::Timer _updateNotifySettingsTimer;

View File

@@ -57,7 +57,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kImageAreaLimit = 6'016 * 3'384;
constexpr auto kImageAreaLimit = 12'032 * 9'024;
App::LaunchState _launchState = App::Launched;

View File

@@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/text/text_utilities.h"
#include "platform/platform_file_utilities.h"
#include "core/file_utilities.h"
#include "base/platform/base_platform_info.h"
#include "core/click_handler_types.h"
#include "core/update_checker.h"
@@ -23,7 +23,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
#include <QtGui/QDesktopServices>
namespace {
@@ -109,7 +108,7 @@ void AboutBox::showVersionHistory() {
Ui::show(Box<InformBox>("The link to the current private alpha version of Telegram Desktop was copied to the clipboard."));
} else {
QDesktopServices::openUrl(qsl("https://desktop.telegram.org/changelog"));
File::OpenUrl(qsl("https://desktop.telegram.org/changelog"));
}
}

View File

@@ -252,7 +252,7 @@ peerListBox: PeerList(defaultPeerList) {
}
localStorageRowHeight: 50px;
localStorageRowPadding: margins(23px, 5px, 20px, 5px);
localStorageRowPadding: margins(22px, 5px, 20px, 5px);
localStorageRowTitle: FlatLabel(defaultFlatLabel) {
textFg: windowBoldFg;
maxHeight: 20px;
@@ -275,11 +275,11 @@ localStorageClear: defaultBoxButton;
localStorageLimitLabel: LabelSimple(defaultLabelSimple) {
font: boxTextFont;
}
localStorageLimitLabelMargin: margins(23px, 10px, 20px, 5px);
localStorageLimitLabelMargin: margins(22px, 10px, 20px, 5px);
localStorageLimitSlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
}
localStorageLimitMargin: margins(23px, 5px, 20px, 10px);
localStorageLimitMargin: margins(22px, 5px, 20px, 10px);
shareRowsTop: 12px;
shareRowHeight: 108px;
@@ -340,7 +340,7 @@ sessionsHeight: 350px;
sessionHeight: 70px;
sessionCurrentPadding: margins(0px, 7px, 0px, 4px);
sessionCurrentHeight: 118px;
sessionPadding: margins(23px, 10px, 23px, 0px);
sessionPadding: margins(22px, 10px, 22px, 0px);
sessionNameFont: msgNameFont;
sessionNameFg: boxTextFg;
sessionWhenFont: msgDateFont;
@@ -428,7 +428,7 @@ aboutLabel: FlatLabel(defaultFlatLabel) {
}
autoDownloadTopDelta: 10px;
autoDownloadTitlePosition: point(23px, 18px);
autoDownloadTitlePosition: point(22px, 18px);
autoDownloadTitleFont: font(15px semibold);
autoDownloadLimitSlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
@@ -562,7 +562,7 @@ passcodeTextStyle: TextStyle(defaultTextStyle) {
lineHeight: 20px;
}
usernamePadding: margins(23px, 6px, 21px, 12px);
usernamePadding: margins(22px, 6px, 21px, 12px);
usernameSkip: 49px;
usernameTextStyle: TextStyle(boxTextStyle, passcodeTextStyle) {
}
@@ -642,9 +642,9 @@ rightsToggle: Toggle(defaultToggle) {
}
rightsDividerHeight: boxDividerHeight;
rightsDividerMargin: margins(0px, 0px, 0px, 20px);
rightsHeaderMargin: margins(23px, 0px, 23px, 8px);
rightsToggleMargin: margins(23px, 8px, 23px, 8px);
rightsAboutMargin: margins(23px, 8px, 23px, 8px);
rightsHeaderMargin: margins(22px, 0px, 22px, 8px);
rightsToggleMargin: margins(22px, 8px, 22px, 8px);
rightsAboutMargin: margins(22px, 8px, 22px, 8px);
rightsPhotoButton: UserpicButton(defaultUserpicButton) {
size: size(60px, 60px);
photoSize: 60px;
@@ -773,8 +773,8 @@ markdownLinkFieldPadding: margins(22px, 0px, 22px, 10px);
termsContent: FlatLabel(defaultFlatLabel) {
minWidth: 285px;
}
termsPadding: margins(23px, 4px, 16px, 16px);
termsAgePadding: margins(23px, 16px, 16px, 0px);
termsPadding: margins(22px, 4px, 16px, 16px);
termsAgePadding: margins(22px, 16px, 16px, 0px);
themesSmallSkip: 10px;
themesBackgroundSize: 120px;
@@ -800,7 +800,7 @@ themesMenuPosition: point(-2px, 25px);
createPollField: InputField(defaultInputField) {
font: boxTextFont;
textMargins: margins(0px, 0px, 0px, 0px);
textMargins: margins(0px, 4px, 0px, 4px);
textAlign: align(left);
heightMin: 36px;
heightMax: 86px;
@@ -822,6 +822,11 @@ createPollOptionField: InputField(createPollField) {
placeholderMargins: margins(2px, 0px, 2px, 0px);
heightMax: 68px;
}
createPollSolutionField: InputField(createPollField) {
textMargins: margins(0px, 4px, 0px, 4px);
border: 1px;
borderActive: 2px;
}
createPollLimitLabel: FlatLabel(defaultFlatLabel) {
minWidth: 274px;
align: align(topleft);
@@ -855,7 +860,7 @@ createPollWarning: FlatLabel(defaultFlatLabel) {
}
}
createPollWarningPosition: point(16px, 6px);
createPollCheckboxMargin: margins(23px, 10px, 23px, 10px);
createPollCheckboxMargin: margins(22px, 10px, 22px, 10px);
createPollFieldTitlePadding: margins(22px, 7px, 10px, 6px);
callSettingsButton: IconButton {

View File

@@ -38,6 +38,8 @@ constexpr auto kMaxOptionsCount = PollData::kMaxOptions;
constexpr auto kOptionLimit = 100;
constexpr auto kWarnQuestionLimit = 80;
constexpr auto kWarnOptionLimit = 30;
constexpr auto kSolutionLimit = 200;
constexpr auto kWarnSolutionLimit = 60;
constexpr auto kErrorLimit = 99;
class Options {
@@ -59,6 +61,7 @@ public:
[[nodiscard]] rpl::producer<int> usedCount() const;
[[nodiscard]] rpl::producer<not_null<QWidget*>> scrollToWidget() const;
[[nodiscard]] rpl::producer<> backspaceInFront() const;
[[nodiscard]] rpl::producer<> tabbed() const;
private:
class Option {
@@ -146,6 +149,7 @@ private:
bool _hasCorrect = false;
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
rpl::event_stream<> _backspaceInFront;
rpl::event_stream<> _tabbed;
};
@@ -217,6 +221,7 @@ Options::Option::Option(
InitField(outer, _field, session);
_field->setMaxLength(kOptionLimit + kErrorLimit);
_field->show();
_field->customTab(true);
_wrap->hide(anim::type::instant);
@@ -497,6 +502,10 @@ rpl::producer<> Options::backspaceInFront() const {
return _backspaceInFront.events();
}
rpl::producer<> Options::tabbed() const {
return _tabbed.events();
}
void Options::Option::show(anim::type animated) {
_wrap->show(animated);
}
@@ -647,6 +656,14 @@ void Options::addEmptyOption() {
QObject::connect(field, &Ui::InputField::focused, [=] {
_scrollToWidget.fire_copy(field);
});
QObject::connect(field, &Ui::InputField::tabbed, [=] {
const auto index = findField(field);
if (index + 1 < _list.size()) {
_list[index + 1]->setFocus();
} else {
_tabbed.fire({});
}
});
base::install_event_filter(field, [=](not_null<QEvent*> event) {
if (event->type() != QEvent::KeyPress
|| !field->getLastText().isEmpty()) {
@@ -768,6 +785,7 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
InitField(getDelegate()->outerContainer(), question, _session);
question->setMaxLength(kQuestionLimit + kErrorLimit);
question->setSubmitSettings(Ui::InputField::SubmitSettings::Both);
question->customTab(true);
const auto warning = CreateWarningLabel(
container,
@@ -794,6 +812,69 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
return question;
}
not_null<Ui::InputField*> CreatePollBox::setupSolution(
not_null<Ui::VerticalLayout*> container,
rpl::producer<bool> shown) {
using namespace Settings;
const auto outer = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container))
)->setDuration(0)->toggleOn(std::move(shown));
const auto inner = outer->entity();
AddSkip(inner);
AddSubsectionTitle(inner, tr::lng_polls_solution_title());
const auto solution = inner->add(
object_ptr<Ui::InputField>(
inner,
st::createPollSolutionField,
Ui::InputField::Mode::MultiLine,
tr::lng_polls_solution_placeholder()),
st::createPollFieldPadding);
InitField(getDelegate()->outerContainer(), solution, _session);
solution->setMaxLength(kSolutionLimit + kErrorLimit);
solution->setInstantReplaces(Ui::InstantReplaces::Default());
solution->setInstantReplacesEnabled(
_session->settings().replaceEmojiValue());
solution->setMarkdownReplacesEnabled(rpl::single(true));
solution->setEditLinkCallback(
DefaultEditLinkCallback(_session, solution));
solution->customTab(true);
const auto warning = CreateWarningLabel(
inner,
solution,
kSolutionLimit,
kWarnSolutionLimit);
rpl::combine(
solution->geometryValue(),
warning->sizeValue()
) | rpl::start_with_next([=](QRect geometry, QSize label) {
warning->moveToLeft(
(inner->width()
- label.width()
- st::createPollWarningPosition.x()),
(geometry.y()
- st::createPollFieldPadding.top()
- st::settingsSubsectionTitlePadding.bottom()
- st::settingsSubsectionTitle.style.font->height
+ st::settingsSubsectionTitle.style.font->ascent
- st::createPollWarning.style.font->ascent),
geometry.width());
}, warning->lifetime());
inner->add(
object_ptr<Ui::FlatLabel>(
inner,
tr::lng_polls_solution_about(),
st::boxDividerLabel),
st::createPollFieldTitlePadding);
return solution;
}
object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
using namespace Settings;
@@ -836,6 +917,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
st::boxDividerLabel),
st::createPollLimitPadding));
connect(question, &Ui::InputField::tabbed, [=] {
options->focusFirst();
});
AddSkip(container);
AddSubsectionTitle(container, tr::lng_polls_create_settings());
@@ -866,6 +951,24 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
(_chosen & PollData::Flag::Quiz),
st::defaultCheckbox),
st::createPollCheckboxMargin);
const auto solution = setupSolution(
container,
rpl::single(quiz->checked()) | rpl::then(quiz->checkedChanges()));
options->tabbed(
) | rpl::start_with_next([=] {
if (quiz->checked()) {
solution->setFocus();
} else {
question->setFocus();
}
}, question->lifetime());
connect(solution, &Ui::InputField::tabbed, [=] {
question->setFocus();
});
quiz->setDisabled(_disabled & PollData::Flag::Quiz);
if (multiple) {
multiple->setDisabled((_disabled & PollData::Flag::MultiChoice)
@@ -911,6 +1014,13 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
auto result = PollData(&_session->data(), id);
result.question = question->getLastText().trimmed();
result.answers = options->toPollAnswers();
const auto solutionWithTags = quiz->checked()
? solution->getTextWithAppliedMarkdown()
: TextWithTags();
result.solution = TextWithEntities{
solutionWithTags.text,
TextUtilities::ConvertTextTagsToEntities(solutionWithTags.tags)
};
const auto publicVotes = (anonymous && !anonymous->checked());
const auto multiChoice = (multiple && multiple->checked());
result.setFlags(Flag(0)
@@ -937,6 +1047,12 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
} else {
*error &= ~Error::Correct;
}
if (quiz->checked()
&& solution->getLastText().trimmed().size() > kSolutionLimit) {
*error |= Error::Solution;
} else {
*error &= ~Error::Solution;
}
};
const auto showError = [=](const QString &text) {
Ui::Toast::Show(text);
@@ -951,6 +1067,8 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
options->focusFirst();
} else if (*error & Error::Correct) {
showError(tr::lng_polls_choose_correct(tr::now));
} else if (*error & Error::Solution) {
solution->showError();
} else if (!*error) {
_submitRequests.fire({ collectResult(), sendOptions });
}

View File

@@ -36,7 +36,7 @@ public:
PollData::Flags disabled,
Api::SendType sendType);
rpl::producer<Result> submitRequests() const;
[[nodiscard]] rpl::producer<Result> submitRequests() const;
void submitFailed(const QString &error);
void setInnerFocus() override;
@@ -50,13 +50,17 @@ private:
Options = 0x02,
Correct = 0x04,
Other = 0x08,
Solution = 0x10,
};
friend constexpr inline bool is_flag_type(Error) { return true; }
using Errors = base::flags<Error>;
object_ptr<Ui::RpWidget> setupContent();
not_null<Ui::InputField*> setupQuestion(
[[nodiscard]] object_ptr<Ui::RpWidget> setupContent();
[[nodiscard]] not_null<Ui::InputField*> setupQuestion(
not_null<Ui::VerticalLayout*> container);
[[nodiscard]] not_null<Ui::InputField*> setupSolution(
not_null<Ui::VerticalLayout*> container,
rpl::producer<bool> shown);
const not_null<Main::Session*> _session;
const PollData::Flags _chosen = PollData::Flags();

View File

@@ -548,14 +548,9 @@ void EditCaptionBox::prepare() {
if (action == Ui::InputField::MimeAction::Check) {
if (!data->hasText() && !_isAllowedEditMedia) {
return false;
}
if (data->hasImage()) {
const auto image = qvariant_cast<QImage>(data->imageData());
if (!image.isNull()) {
return true;
}
}
if (const auto urls = data->urls(); !urls.empty()) {
} else if (data->hasImage()) {
return true;
} else if (const auto urls = data->urls(); !urls.empty()) {
if (ranges::find_if(
urls,
[](const QUrl &url) { return !url.isLocalFile(); }

View File

@@ -130,7 +130,7 @@ public:
LastSeen,
Custom,
};
void refreshStatus();
virtual void refreshStatus();
crl::time refreshStatusTime() const;
void setAbsoluteIndex(int index) {

View File

@@ -1056,7 +1056,9 @@ void ParticipantsBoxController::prepare() {
switch (_role) {
case Role::Admins: return tr::lng_channel_admins();
case Role::Profile:
case Role::Members: return tr::lng_profile_participants_section();
case Role::Members: return (_peer->isChannel() && !_peer->isMegagroup()
? tr::lng_profile_subscribers_section()
: tr::lng_profile_participants_section());
case Role::Restricted: return tr::lng_exceptions_list_title();
case Role::Kicked: return tr::lng_removed_list_title();
}
@@ -1786,6 +1788,12 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
|| _additional.canEditAdmin(user))) {
row->setActionLink(tr::lng_profile_kick(tr::now));
}
if (_role == Role::Members && user->isBot()) {
auto seesAllMessages = (user->botInfo->readsAllHistory || _additional.adminRights(user).has_value());
row->setCustomStatus(seesAllMessages
? tr::lng_status_bot_reads_all(tr::now)
: tr::lng_status_bot_not_reads_all(tr::now));
}
}
return row;
}

View File

@@ -967,7 +967,7 @@ void Controller::fillManageSection() {
if (canViewMembers) {
AddButtonWithCount(
_controls.buttonsLayout,
tr::lng_manage_peer_members(),
(_isGroup ? tr::lng_manage_peer_members() : tr::lng_manage_peer_subscribers()),
Info::Profile::MigratedOrMeValue(
_peer
) | rpl::map(

View File

@@ -1934,6 +1934,7 @@ void SendFilesBox::initSendWay() {
if (_albumPreview) {
_albumPreview->setSendWay(value);
}
updateEmojiPanelGeometry();
setInnerFocus();
});
}

View File

@@ -109,7 +109,7 @@ public:
bool actionSelected) override;
private:
void refreshStatus();
void refreshStatus() override;
static Type ComputeType(not_null<const HistoryItem*> item);
std::vector<not_null<HistoryItem*>> _items;

View File

@@ -89,11 +89,16 @@ stickersRowDisabledOpacity: 0.4;
stickersRowDuration: 200;
stickersSettings: icon {{ "emoji_settings", emojiIconFg }};
stickersTrending: icon {{ "emoji_trending", emojiIconFg }};
stickersTrending: icon {{ "stickers_add", emojiIconFg }};
stickersTrendingUnread: icon {
{ "stickers_add_unread", emojiIconFg },
{ "stickers_add_dot", dialogsUnreadBg }
};
stickersRecent: icon {{ "stickers_recent", emojiIconFg }};
stickersSearch: icon {{ "stickers_search", emojiIconFg, point(0px, 1px) }};
stickersSettingsUnreadSize: 17px;
stickersSettingsUnreadPosition: point(4px, 5px);
stickersSettingsUnreadSize: 6px;
stickersSettingsUnreadPosition: point(6px, 10px);
filtersRemove: IconButton(stickersRemove) {
ripple: defaultRippleAnimation;
@@ -213,8 +218,11 @@ stickerGroupCategoryAbout: defaultTextStyle;
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
stickerGroupCategoryAdd: stickersTrendingAdd;
stickersToastMaxWidth: 340px;
stickersToastPadding: margins(16px, 13px, 16px, 12px);
stickersToast: Toast(defaultToast) {
minWidth: 340px;
maxWidth: 340px;
padding: margins(16px, 13px, 16px, 12px);
}
stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }};
@@ -266,7 +274,7 @@ autocompleteRowAnswer: defaultTextStyle;
manageEmojiPreview: 22px;
manageEmojiPreviewWidth: 48px;
manageEmojiPreviewHeight: 48px;
manageEmojiPreviewPadding: margins(23px, 9px, 19px, 9px);
manageEmojiPreviewPadding: margins(22px, 9px, 19px, 9px);
manageEmojiMarginRight: 21px;
manageEmojiNameTop: 3px;
manageEmojiStatusTop: 25px;

View File

@@ -77,12 +77,11 @@ void ApplyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
Local::writeInstalledStickers();
Local::writeArchivedStickers();
auto toast = Ui::Toast::Config();
toast.text = tr::lng_stickers_packs_archived(tr::now);
toast.maxWidth = toast.minWidth = st::stickersToastMaxWidth;
toast.multiline = true;
toast.padding = st::stickersToastPadding;
Ui::Toast::Show(toast);
Ui::Toast::Show(Ui::Toast::Config{
.text = { tr::lng_stickers_packs_archived(tr::now) },
.st = &st::stickersToast,
.multiline = true,
});
// Ui::show(Box<StickersBox>(archived, &Auth()), Ui::LayerOption::KeepOther);
Auth().data().notifyStickersUpdated();

View File

@@ -24,8 +24,9 @@ constexpr auto kZeroDiceDocumentId = 0xa3b83c9f84fa9e83ULL;
} // namespace
DicePack::DicePack(not_null<Main::Session*> session)
: _session(session) {
DicePack::DicePack(not_null<Main::Session*> session, const QString &emoji)
: _session(session)
, _emoji(emoji) {
}
DicePack::~DicePack() = default;
@@ -34,10 +35,7 @@ DocumentData *DicePack::lookup(int value) {
if (!_requestId) {
load();
}
if (!value) {
ensureZeroGenerated();
return _zero;
}
tryGenerateLocalZero();
const auto i = _map.find(value);
return (i != end(_map)) ? i->second.get() : nullptr;
}
@@ -47,7 +45,7 @@ void DicePack::load() {
return;
}
_requestId = _session->api().request(MTPmessages_GetStickerSet(
MTP_inputStickerSetDice()
MTP_inputStickerSetDice(MTP_string(_emoji))
)).done([=](const MTPmessages_StickerSet &result) {
result.match([&](const MTPDmessages_stickerSet &data) {
applySet(data);
@@ -58,22 +56,50 @@ void DicePack::load() {
}
void DicePack::applySet(const MTPDmessages_stickerSet &data) {
auto index = 0;
_map.clear();
auto documents = base::flat_map<DocumentId, not_null<DocumentData*>>();
for (const auto &sticker : data.vdocuments().v) {
const auto document = _session->data().processDocument(
sticker);
if (document->sticker()) {
_map.emplace(++index, document);
documents.emplace(document->id, document);
}
}
for (const auto pack : data.vpacks().v) {
pack.match([&](const MTPDstickerPack &data) {
const auto emoji = qs(data.vemoticon());
if (emoji.isEmpty()) {
return;
}
const auto ch = int(emoji[0].unicode());
const auto index = (ch == '#') ? 0 : (ch + 1 - '1');
if (index < 0 || index > 6) {
return;
}
for (const auto id : data.vdocuments().v) {
if (const auto document = documents.take(id.v)) {
_map.emplace(index, *document);
}
}
});
}
}
void DicePack::ensureZeroGenerated() {
if (_zero) {
void DicePack::tryGenerateLocalZero() {
if (!_map.empty()) {
return;
}
const auto path = qsl(":/gui/art/dice_idle.tgs");
static const auto kDiceString = QString::fromUtf8("\xF0\x9F\x8E\xB2");
static const auto kDartString = QString::fromUtf8("\xF0\x9F\x8E\xAF");
const auto path = (_emoji == kDiceString)
? qsl(":/gui/art/dice_idle.tgs")
: (_emoji == kDartString)
? qsl(":/gui/art/dart_idle.tgs")
: QString();
if (path.isEmpty()) {
return;
}
auto task = FileLoadTask(
path,
QByteArray(),
@@ -84,13 +110,29 @@ void DicePack::ensureZeroGenerated() {
task.process();
const auto result = task.peekResult();
Assert(result != nullptr);
_zero = _session->data().processDocument(
const auto document = _session->data().processDocument(
result->document,
std::move(result->thumb));
_zero->setLocation(FileLocation(path));
document->setLocation(FileLocation(path));
Ensures(_zero->sticker());
Ensures(_zero->sticker()->animated);
_map.emplace(0, document);
Ensures(document->sticker());
Ensures(document->sticker()->animated);
}
DicePacks::DicePacks(not_null<Main::Session*> session) : _session(session) {
}
DocumentData *DicePacks::lookup(const QString &emoji, int value) {
const auto i = _packs.find(emoji);
if (i != end(_packs)) {
return i->second->lookup(value);
}
return _packs.emplace(
emoji,
std::make_unique<DicePack>(_session, emoji)
).first->second->lookup(value);
}
} // namespace Stickers

View File

@@ -1,4 +1,5 @@
/*
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
@@ -17,7 +18,7 @@ namespace Stickers {
class DicePack final {
public:
explicit DicePack(not_null<Main::Session*> session);
DicePack(not_null<Main::Session*> session, const QString &emoji);
~DicePack();
DocumentData *lookup(int value);
@@ -25,13 +26,26 @@ public:
private:
void load();
void applySet(const MTPDmessages_stickerSet &data);
void ensureZeroGenerated();
void tryGenerateLocalZero();
not_null<Main::Session*> _session;
const not_null<Main::Session*> _session;
QString _emoji;
base::flat_map<int, not_null<DocumentData*>> _map;
DocumentData *_zero = nullptr;
mtpRequestId _requestId = 0;
};
class DicePacks final {
public:
explicit DicePacks(not_null<Main::Session*> session);
DocumentData *lookup(const QString &emoji, int value);
private:
const not_null<Main::Session*> _session;
base::flat_map<QString, std::unique_ptr<DicePack>> _packs;
};
} // namespace Stickers

View File

@@ -44,6 +44,8 @@ namespace {
constexpr auto kInlineItemsMaxPerRow = 5;
constexpr auto kSearchRequestDelay = 400;
constexpr auto kRecentDisplayLimit = 20;
constexpr auto kPreloadOfficialPages = 4;
constexpr auto kOfficialLoadLimit = 40;
bool SetInMyList(MTPDstickerSet::Flags flags) {
return (flags & MTPDstickerSet::Flag::f_installed_date)
@@ -138,7 +140,6 @@ private:
void finishDragging();
void paintStickerSettingsIcon(Painter &p) const;
void paintSearchIcon(Painter &p) const;
void paintFeaturedStickerSetsBadge(Painter &p, int iconLeft) const;
void paintSetIcon(Painter &p, const StickerIcon &icon, int x) const;
void paintSelectionBar(Painter &p) const;
void paintLeftRightFading(Painter &p) const;
@@ -694,18 +695,6 @@ void StickersListWidget::Footer::paintSearchIcon(Painter &p) const {
st::stickersSearch.paint(p, searchLeft + (st::stickerIconWidth - st::stickersSearch.width()) / 2, _iconsTop + st::emojiCategory.iconPosition.y(), width());
}
void StickersListWidget::Footer::paintFeaturedStickerSetsBadge(Painter &p, int iconLeft) const {
if (const auto unread = _pan->session().data().featuredStickerSetsUnreadCount()) {
Dialogs::Layout::UnreadBadgeStyle unreadSt;
unreadSt.sizeId = Dialogs::Layout::UnreadBadgeInStickersPanel;
unreadSt.size = st::stickersSettingsUnreadSize;
int unreadRight = iconLeft + st::stickerIconWidth - st::stickersSettingsUnreadPosition.x();
if (rtl()) unreadRight = width() - unreadRight;
int unreadTop = _iconsTop + st::stickersSettingsUnreadPosition.y();
Dialogs::Layout::paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, unreadSt);
}
}
void StickersListWidget::Footer::validateIconLottieAnimation(
const StickerIcon &icon) {
if (icon.lottie
@@ -788,19 +777,22 @@ void StickersListWidget::Footer::paintSetIcon(
} else if (icon.megagroup) {
icon.megagroup->paintUserpicLeft(p, x + (st::stickerIconWidth - st::stickerGroupCategorySize) / 2, _iconsTop + (st::emojiFooterHeight - st::stickerGroupCategorySize) / 2, width(), st::stickerGroupCategorySize);
} else {
auto getSpecialSetIcon = [](uint64 setId) {
if (setId == Stickers::FeaturedSetId) {
return &st::stickersTrending;
const auto paintedIcon = [&] {
if (icon.setId == Stickers::FeaturedSetId) {
const auto session = &_pan->session();
return session->data().featuredStickerSetsUnreadCount()
? &st::stickersTrendingUnread
: &st::stickersTrending;
//} else if (setId == Stickers::FavedSetId) {
// return &st::stickersFaved;
}
return &st::emojiRecent;
};
auto paintedIcon = getSpecialSetIcon(icon.setId);
paintedIcon->paint(p, x + (st::stickerIconWidth - paintedIcon->width()) / 2, _iconsTop + st::emojiCategory.iconPosition.y(), width());
if (icon.setId == Stickers::FeaturedSetId) {
paintFeaturedStickerSetsBadge(p, x);
}
return &st::stickersRecent;
}();
paintedIcon->paint(
p,
x + (st::stickerIconWidth - paintedIcon->width()) / 2,
_iconsTop + (st::emojiFooterHeight - paintedIcon->height()) / 2,
width());
}
}
@@ -901,25 +893,86 @@ void StickersListWidget::checkVisibleFeatured(
readVisibleFeatured(visibleTop, visibleBottom);
const auto visibleHeight = visibleBottom - visibleTop;
if (visibleBottom > height() - visibleHeight * kPreloadOfficialPages) {
preloadMoreOfficial();
}
const auto rowHeight = featuredRowHeight();
const auto destroyAbove = floorclamp(visibleTop - visibleHeight, rowHeight, 0, _featuredSets.size());
const auto destroyBelow = ceilclamp(visibleBottom + visibleHeight, rowHeight, 0, _featuredSets.size());
const auto destroyAbove = floorclamp(visibleTop - visibleHeight, rowHeight, 0, _officialSets.size());
const auto destroyBelow = ceilclamp(visibleBottom + visibleHeight, rowHeight, 0, _officialSets.size());
for (auto i = 0; i != destroyAbove; ++i) {
destroyLottieIn(_featuredSets[i]);
destroyLottieIn(_officialSets[i]);
}
for (auto i = destroyBelow; i != _featuredSets.size(); ++i) {
destroyLottieIn(_featuredSets[i]);
for (auto i = destroyBelow; i != _officialSets.size(); ++i) {
destroyLottieIn(_officialSets[i]);
}
}
void StickersListWidget::preloadMoreOfficial() {
if (_officialRequestId) {
return;
}
_officialRequestId = _api.request(MTPmessages_GetOldFeaturedStickers(
MTP_int(_officialOffset),
MTP_int(kOfficialLoadLimit),
MTP_int(0)
)).done([=](const MTPmessages_FeaturedStickers &result) {
_officialRequestId = 0;
result.match([&](const MTPDmessages_featuredStickersNotModified &d) {
LOG(("Api Error: messages.featuredStickersNotModified."));
}, [&](const MTPDmessages_featuredStickers &data) {
const auto &list = data.vsets().v;
_officialOffset += list.size();
for (int i = 0, l = list.size(); i != l; ++i) {
auto &data = list[i];
const auto setData = data.match([&](const auto &data) {
return data.vset().match([](const MTPDstickerSet &data) {
return &data;
});
});
const auto covers = data.match([](const MTPDstickerSetCovered &) {
return Stickers::Pack();
}, [&](const MTPDstickerSetMultiCovered &data) {
auto result = Stickers::Pack();
for (const auto &cover : data.vcovers().v) {
const auto document = session().data().processDocument(cover);
if (document->sticker()) {
result.push_back(document);
}
}
return result;
});
if (const auto set = Stickers::FeedSet(*setData)) {
if (!covers.empty()) {
set->covers = covers;
}
if (set->stickers.empty() && set->covers.empty()) {
continue;
}
const auto externalLayout = true;
appendSet(
_officialSets,
set->id,
externalLayout,
AppendSkip::Installed);
}
}
});
resizeToWidth(width());
update();
}).fail([=](const RPCError &error) {
}).send();
}
void StickersListWidget::readVisibleFeatured(
int visibleTop,
int visibleBottom) {
const auto rowHeight = featuredRowHeight();
const auto rowFrom = floorclamp(visibleTop, rowHeight, 0, _featuredSets.size());
const auto rowTo = ceilclamp(visibleBottom, rowHeight, 0, _featuredSets.size());
const auto rowFrom = floorclamp(visibleTop, rowHeight, 0, _featuredSetsCount);
const auto rowTo = ceilclamp(visibleBottom, rowHeight, 0, _featuredSetsCount);
for (auto i = rowFrom; i < rowTo; ++i) {
auto &set = _featuredSets[i];
auto &set = _officialSets[i];
if (!(set.flags & MTPDstickerSet_ClientFlag::f_unread)) {
continue;
}
@@ -935,7 +988,7 @@ void StickersListWidget::readVisibleFeatured(
++loaded;
}
}
if (loaded == count) {
if (count > 0 && loaded == count) {
session().api().readFeaturedSetDelayed(set.id);
}
}
@@ -1227,7 +1280,7 @@ void StickersListWidget::addSearchRow(not_null<const Stickers::Set*> set) {
auto StickersListWidget::shownSets() const -> const std::vector<Set> & {
switch (_section) {
case Section::Featured: return _featuredSets;
case Section::Featured: return _officialSets;
case Section::Search: return _searchSets;
case Section::Stickers: return _mySets;
}
@@ -1236,7 +1289,7 @@ auto StickersListWidget::shownSets() const -> const std::vector<Set> & {
auto StickersListWidget::shownSets() -> std::vector<Set> & {
switch (_section) {
case Section::Featured: return _featuredSets;
case Section::Featured: return _officialSets;
case Section::Search: return _searchSets;
case Section::Stickers: return _mySets;
}
@@ -1349,10 +1402,11 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
}
auto &set = sets[info.section];
if (set.externalLayout) {
const auto size = (set.flags
const auto loadedCount = int(set.stickers.size());
const auto count = (set.flags
& MTPDstickerSet_ClientFlag::f_not_loaded)
? set.count
: int(set.stickers.size());
: loadedCount;
auto widthForTitle = stickersRight() - (st::emojiPanHeaderLeft - st::buttonRadius);
if (featuredHasAddButton(info.section)) {
@@ -1402,7 +1456,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
}
}
auto statusText = (size > 0) ? tr::lng_stickers_count(tr::now, lt_count, size) : tr::lng_contacts_loading(tr::now);
auto statusText = (count > 0) ? tr::lng_stickers_count(tr::now, lt_count, count) : tr::lng_contacts_loading(tr::now);
p.setFont(st::stickersTrendingSubheaderFont);
p.setPen(st::stickersTrendingSubheaderFg);
p.drawTextLeft(st::emojiPanHeaderLeft - st::buttonRadius, info.top + st::stickersTrendingSubheaderTop, width(), statusText);
@@ -1413,7 +1467,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
for (int j = fromColumn; j < toColumn; ++j) {
int index = j;
if (index >= size) break;
if (index >= loadedCount) break;
auto selected = selectedSticker ? (selectedSticker->section == info.section && selectedSticker->index == index) : false;
auto deleteSelected = false;
@@ -2116,12 +2170,33 @@ void StickersListWidget::refreshMySets() {
}
void StickersListWidget::refreshFeaturedSets() {
_featuredSets.clear();
_featuredSets.reserve(session().data().featuredStickerSetsOrder().size());
auto wasFeaturedSetsCount = base::take(_featuredSetsCount);
auto wereOfficial = base::take(_officialSets);
_officialSets.reserve(
session().data().featuredStickerSetsOrder().size()
+ wereOfficial.size()
- wasFeaturedSetsCount);
for (const auto setId : session().data().featuredStickerSetsOrder()) {
const auto externalLayout = true;
appendSet(_featuredSets, setId, externalLayout, AppendSkip::Installed);
appendSet(_officialSets, setId, externalLayout, AppendSkip::Installed);
}
_featuredSetsCount = _officialSets.size();
if (wereOfficial.size() > wasFeaturedSetsCount) {
auto &sets = session().data().stickerSets();
const auto from = begin(wereOfficial) + wasFeaturedSetsCount;
const auto till = end(wereOfficial);
for (auto i = from; i != till; ++i) {
auto &set = *i;
auto it = sets.constFind(set.id);
if (it == sets.cend()
|| ((it->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(it->flags & MTPDstickerSet::Flag::f_archived)
&& !_installedLocallySets.contains(set.id))) {
continue;
}
set.flags = it->flags;
_officialSets.push_back(std::move(set));
}
}
}
@@ -2247,28 +2322,27 @@ uint64 StickersListWidget::currentSet(int yOffset) const {
: sets[sectionInfoByOffset(yOffset).section].id;
}
void StickersListWidget::appendSet(
bool StickersListWidget::appendSet(
std::vector<Set> &to,
uint64 setId,
bool externalLayout,
AppendSkip skip) {
auto &sets = session().data().stickerSets();
auto it = sets.constFind(setId);
if (it == sets.cend() || it->stickers.isEmpty()) {
return;
if (it == sets.cend() || (!externalLayout && it->stickers.isEmpty())) {
return false;
}
if ((skip == AppendSkip::Archived)
&& (it->flags & MTPDstickerSet::Flag::f_archived)) {
return;
return false;
}
if ((skip == AppendSkip::Installed)
&& (it->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(it->flags & MTPDstickerSet::Flag::f_archived)) {
if (!_installedLocallySets.contains(setId)) {
return;
return false;
}
}
to.emplace_back(
it->id,
it->flags,
@@ -2277,7 +2351,10 @@ void StickersListWidget::appendSet(
it->thumbnail,
externalLayout,
it->count,
PrepareStickers(it->stickers));
PrepareStickers((it->stickers.empty() && externalLayout)
? it->covers
: it->stickers));
return true;
}
void StickersListWidget::refreshRecent() {
@@ -2487,8 +2564,7 @@ void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) {
void StickersListWidget::fillIcons(QList<StickerIcon> &icons) {
icons.clear();
icons.reserve(_mySets.size() + 1);
if (session().data().featuredStickerSetsUnreadCount()
&& !_featuredSets.empty()) {
if (!_officialSets.empty()) {
icons.push_back(StickerIcon(Stickers::FeaturedSetId));
}
@@ -2535,11 +2611,6 @@ void StickersListWidget::fillIcons(QList<StickerIcon> &icons) {
pixw,
pixh));
}
if (!session().data().featuredStickerSetsUnreadCount()
&& !_featuredSets.empty()) {
icons.push_back(StickerIcon(Stickers::FeaturedSetId));
}
}
bool StickersListWidget::preventAutoHide() {

View File

@@ -179,6 +179,11 @@ private:
bool externalLayout = false;
int count = 0;
};
struct FeaturedSet {
uint64 id = 0;
MTPDstickerSet::Flags flags = MTPDstickerSet::Flags();
std::vector<Sticker> stickers;
};
struct LottieSet {
struct Item {
not_null<Lottie::Animation*> animation;
@@ -192,6 +197,7 @@ private:
static std::vector<Sticker> PrepareStickers(const Stickers::Pack &pack);
void preloadMoreOfficial();
QSize boundingBoxSize() const;
template <typename Callback>
@@ -273,7 +279,7 @@ private:
Archived,
Installed,
};
void appendSet(
bool appendSet(
std::vector<Set> &to,
uint64 setId,
bool externalLayout,
@@ -303,13 +309,17 @@ private:
ChannelData *_megagroupSet = nullptr;
uint64 _megagroupSetIdRequested = 0;
std::vector<Set> _mySets;
std::vector<Set> _featuredSets;
std::vector<Set> _officialSets;
std::vector<Set> _searchSets;
int _featuredSetsCount = 0;
base::flat_set<uint64> _installedLocallySets;
std::vector<bool> _custom;
base::flat_set<not_null<DocumentData*>> _favedStickersMap;
std::weak_ptr<Lottie::FrameRenderer> _lottieRenderer;
mtpRequestId _officialRequestId = 0;
int _officialOffset = 0;
Section _section = Section::Stickers;
bool _displayingSet = false;

View File

@@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "observer_peer.h"
#include "storage/storage_databases.h"
#include "mainwidget.h"
#include "core/file_utilities.h"
#include "main/main_account.h"
#include "media/view/media_view_overlay_widget.h"
#include "mtproto/dc_options.h"
@@ -300,7 +301,7 @@ void Application::showDocument(not_null<DocumentData*> document, HistoryItem *it
if (cUseExternalVideoPlayer()
&& document->isVideoFile()
&& document->loaded()) {
QDesktopServices::openUrl(QUrl("file:///" + document->location(false).fname));
File::Launch(document->location(false).fname);
} else {
_mediaView->showDocument(document, item);
_mediaView->activateWindow();

View File

@@ -22,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "facades.h"
#include "app.h"
#include <QtGui/QDesktopServices>
#include <QtGui/QGuiApplication>
namespace {
@@ -51,9 +50,14 @@ void HiddenUrlClickHandler::Open(QString url, QVariant context) {
if (UrlRequiresConfirmation(url)
&& QGuiApplication::keyboardModifiers() != Qt::ControlModifier) {
Core::App().hideMediaView();
const auto displayUrl = parsedUrl.isValid()
const auto displayed = parsedUrl.isValid()
? parsedUrl.toDisplayString()
: url;
const auto displayUrl = !IsSuspicious(displayed)
? displayed
: parsedUrl.isValid()
? QString::fromUtf8(parsedUrl.toEncoded())
: ShowEncoded(displayed);
Ui::show(
Box<ConfirmBox>(
(tr::lng_open_this_link(tr::now)

View File

@@ -74,7 +74,7 @@ PreLaunchWindow::~PreLaunchWindow() {
PreLaunchLabel::PreLaunchLabel(QWidget *parent) : QLabel(parent) {
QFont labelFont(font());
labelFont.setFamily(style::internal::GetFontOverride(qsl("Open Sans Semibold")));
labelFont.setFamily(style::internal::GetFontOverride(style::internal::FontSemibold));
labelFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(labelFont);
@@ -92,7 +92,7 @@ void PreLaunchLabel::setText(const QString &text) {
PreLaunchInput::PreLaunchInput(QWidget *parent, bool password) : QLineEdit(parent) {
QFont logFont(font());
logFont.setFamily(style::internal::GetFontOverride(qsl("Open Sans")));
logFont.setFamily(style::internal::GetFontOverride());
logFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(logFont);
@@ -110,7 +110,7 @@ PreLaunchInput::PreLaunchInput(QWidget *parent, bool password) : QLineEdit(paren
PreLaunchLog::PreLaunchLog(QWidget *parent) : QTextEdit(parent) {
QFont logFont(font());
logFont.setFamily(style::internal::GetFontOverride(qsl("Open Sans")));
logFont.setFamily(style::internal::GetFontOverride());
logFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(logFont);
@@ -132,7 +132,7 @@ PreLaunchButton::PreLaunchButton(QWidget *parent, bool confirm) : QPushButton(pa
setObjectName(confirm ? "confirm" : "cancel");
QFont closeFont(font());
closeFont.setFamily(style::internal::GetFontOverride(qsl("Open Sans Semibold")));
closeFont.setFamily(style::internal::GetFontOverride(style::internal::FontSemibold));
closeFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(closeFont);
@@ -151,7 +151,7 @@ PreLaunchCheckbox::PreLaunchCheckbox(QWidget *parent) : QCheckBox(parent) {
setCheckState(Qt::Checked);
QFont closeFont(font());
closeFont.setFamily(style::internal::GetFontOverride(qsl("Open Sans Semibold")));
closeFont.setFamily(style::internal::GetFontOverride(style::internal::FontSemibold));
closeFont.setPixelSize(static_cast<PreLaunchWindow*>(parent)->basicSize());
setFont(closeFont);

View File

@@ -118,6 +118,13 @@ QString filedialogNextFilename(
namespace File {
void OpenUrl(const QString &url) {
crl::on_main([=] {
Ui::PreventDelayedActivation();
Platform::File::UnsafeOpenUrl(url);
});
}
void OpenEmailLink(const QString &email) {
crl::on_main([=] {
Ui::PreventDelayedActivation();
@@ -162,6 +169,10 @@ QString DefaultDownloadPath() {
namespace internal {
void UnsafeOpenUrlDefault(const QString &url) {
QDesktopServices::openUrl(url);
}
void UnsafeOpenEmailLinkDefault(const QString &email) {
auto url = QUrl(qstr("mailto:") + email);
QDesktopServices::openUrl(url);

View File

@@ -30,6 +30,7 @@ QString filedialogNextFilename(
namespace File {
// Those functions are async wrappers to Platform::File::Unsafe* calls.
void OpenUrl(const QString &url);
void OpenEmailLink(const QString &email);
void OpenWith(const QString &filepath, QPoint menuPosition);
void Launch(const QString &filepath);
@@ -43,6 +44,7 @@ inline QString UrlToLocalDefault(const QUrl &url) {
return url.toLocalFile();
}
void UnsafeOpenUrlDefault(const QString &url);
void UnsafeOpenEmailLinkDefault(const QString &email);
void UnsafeLaunchDefault(const QString &filepath);

View File

@@ -55,57 +55,81 @@ const auto SupportCommands = base::flat_set<Command>{
};
const auto CommandByName = base::flat_map<QString, Command>{
{ qsl("close_telegram") , Command::Close },
{ qsl("lock_telegram") , Command::Lock },
{ qsl("minimize_telegram"), Command::Minimize },
{ qsl("quit_telegram") , Command::Quit },
{ qsl("close_telegram") , Command::Close },
{ qsl("lock_telegram") , Command::Lock },
{ qsl("minimize_telegram") , Command::Minimize },
{ qsl("quit_telegram") , Command::Quit },
{ qsl("media_play") , Command::MediaPlay },
{ qsl("media_pause") , Command::MediaPause },
{ qsl("media_playpause") , Command::MediaPlayPause },
{ qsl("media_stop") , Command::MediaStop },
{ qsl("media_previous") , Command::MediaPrevious },
{ qsl("media_next") , Command::MediaNext },
{ qsl("media_play") , Command::MediaPlay },
{ qsl("media_pause") , Command::MediaPause },
{ qsl("media_playpause") , Command::MediaPlayPause },
{ qsl("media_stop") , Command::MediaStop },
{ qsl("media_previous") , Command::MediaPrevious },
{ qsl("media_next") , Command::MediaNext },
{ qsl("search") , Command::Search },
{ qsl("search") , Command::Search },
{ qsl("previous_chat") , Command::ChatPrevious },
{ qsl("next_chat") , Command::ChatNext },
{ qsl("first_chat") , Command::ChatFirst },
{ qsl("last_chat") , Command::ChatLast },
{ qsl("self_chat") , Command::ChatSelf },
{ qsl("previous_chat") , Command::ChatPrevious },
{ qsl("next_chat") , Command::ChatNext },
{ qsl("first_chat") , Command::ChatFirst },
{ qsl("last_chat") , Command::ChatLast },
{ qsl("self_chat") , Command::ChatSelf },
{ qsl("previous_folder") , Command::FolderPrevious },
{ qsl("next_folder") , Command::FolderNext },
{ qsl("all_chats") , Command::ShowAllChats },
{ qsl("folder1") , Command::ShowFolder1 },
{ qsl("folder2") , Command::ShowFolder2 },
{ qsl("folder3") , Command::ShowFolder3 },
{ qsl("folder4") , Command::ShowFolder4 },
{ qsl("folder5") , Command::ShowFolder5 },
{ qsl("folder6") , Command::ShowFolder6 },
{ qsl("last_folder") , Command::ShowFolderLast },
{ qsl("show_archive") , Command::ShowArchive },
{ qsl("show_archive") , Command::ShowArchive },
// Shortcuts that have no default values.
{ qsl("message") , Command::JustSendMessage },
{ qsl("message_silently") , Command::SendSilentMessage },
{ qsl("message_scheduled"), Command::ScheduleMessage },
{ qsl("message") , Command::JustSendMessage },
{ qsl("message_silently") , Command::SendSilentMessage },
{ qsl("message_scheduled") , Command::ScheduleMessage },
//
};
const auto CommandNames = base::flat_map<Command, QString>{
{ Command::Close , qsl("close_telegram") },
{ Command::Lock , qsl("lock_telegram") },
{ Command::Minimize , qsl("minimize_telegram") },
{ Command::Quit , qsl("quit_telegram") },
{ Command::Close , qsl("close_telegram") },
{ Command::Lock , qsl("lock_telegram") },
{ Command::Minimize , qsl("minimize_telegram") },
{ Command::Quit , qsl("quit_telegram") },
{ Command::MediaPlay , qsl("media_play") },
{ Command::MediaPause , qsl("media_pause") },
{ Command::MediaPlayPause, qsl("media_playpause") },
{ Command::MediaStop , qsl("media_stop") },
{ Command::MediaPrevious , qsl("media_previous") },
{ Command::MediaNext , qsl("media_next") },
{ Command::MediaPlay , qsl("media_play") },
{ Command::MediaPause , qsl("media_pause") },
{ Command::MediaPlayPause , qsl("media_playpause") },
{ Command::MediaStop , qsl("media_stop") },
{ Command::MediaPrevious , qsl("media_previous") },
{ Command::MediaNext , qsl("media_next") },
{ Command::Search , qsl("search") },
{ Command::Search , qsl("search") },
{ Command::ChatPrevious , qsl("previous_chat") },
{ Command::ChatNext , qsl("next_chat") },
{ Command::ChatFirst , qsl("first_chat") },
{ Command::ChatLast , qsl("last_chat") },
{ Command::ChatSelf , qsl("self_chat") },
{ Command::ChatPrevious , qsl("previous_chat") },
{ Command::ChatNext , qsl("next_chat") },
{ Command::ChatFirst , qsl("first_chat") },
{ Command::ChatLast , qsl("last_chat") },
{ Command::ChatSelf , qsl("self_chat") },
{ Command::FolderPrevious , qsl("previous_folder") },
{ Command::FolderNext , qsl("next_folder") },
{ Command::ShowAllChats , qsl("all_chats") },
{ Command::ShowFolder1 , qsl("folder1") },
{ Command::ShowFolder2 , qsl("folder2") },
{ Command::ShowFolder3 , qsl("folder3") },
{ Command::ShowFolder4 , qsl("folder4") },
{ Command::ShowFolder5 , qsl("folder5") },
{ Command::ShowFolder6 , qsl("folder6") },
{ Command::ShowFolderLast , qsl("last_folder") },
{ Command::ShowArchive , qsl("show_archive") },
{ Command::ShowArchive , qsl("show_archive") },
};
class Manager {
@@ -427,7 +451,6 @@ void Manager::set(const QString &keys, Command command, bool replace) {
} else if (replace) {
unregister(std::exchange(i->second, std::move(shortcut)));
} else {
shortcut = nullptr;
id = i->second->id();
}
if (!id) {
@@ -435,10 +458,10 @@ void Manager::set(const QString &keys, Command command, bool replace) {
return;
}
_commandByShortcutId.emplace(id, command);
if (shortcut && isMediaShortcut) {
if (!shortcut && isMediaShortcut) {
_mediaShortcuts.emplace(i->second.get());
}
if (shortcut && isSupportShortcut) {
if (!shortcut && isSupportShortcut) {
_supportShortcuts.emplace(i->second.get());
}
}

View File

@@ -66,6 +66,11 @@ std::shared_ptr<ClickHandler> UiIntegration::createLinkHandler(
const QString &data,
const TextParseOptions &options) {
switch (type) {
case EntityType::Url:
return (!data.isEmpty() && UrlClickHandler::IsSuspicious(data))
? std::make_shared<HiddenUrlClickHandler>(data)
: nullptr;
case EntityType::CustomUrl:
return !data.isEmpty()
? std::make_shared<HiddenUrlClickHandler>(data)
@@ -138,7 +143,9 @@ bool UiIntegration::handleUrlClick(
Core::App().openInternalUrl(local, context);
return true;
}
return false;
File::OpenUrl(url);
return true;
}

View File

@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
constexpr auto AppName = "Telegram Desktop"_cs;
constexpr auto AppFile = "Telegram"_cs;
constexpr auto AppVersion = 2000001;
constexpr auto AppVersionStr = "2.0.1";
constexpr auto AppVersion = 2001001;
constexpr auto AppVersionStr = "2.1.1";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View File

@@ -46,7 +46,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Data {
namespace {
Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
constexpr auto kFastRevokeRestriction = 24 * 60 * TimeId(60);
[[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
auto result = Call();
result.finishReason = [&] {
if (const auto reason = call.vreason()) {
@@ -68,7 +70,7 @@ Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
return result;
}
Invoice ComputeInvoiceData(
[[nodiscard]] Invoice ComputeInvoiceData(
not_null<HistoryItem*> item,
const MTPDmessageMediaInvoice &data) {
auto result = Invoice();
@@ -84,7 +86,7 @@ Invoice ComputeInvoiceData(
return result;
}
QString WithCaptionDialogsText(
[[nodiscard]] QString WithCaptionDialogsText(
const QString &attachType,
const QString &caption) {
if (caption.isEmpty()) {
@@ -102,7 +104,7 @@ QString WithCaptionDialogsText(
TextUtilities::Clean(caption));
}
QString WithCaptionNotificationText(
[[nodiscard]] QString WithCaptionNotificationText(
const QString &attachType,
const QString &caption) {
if (caption.isEmpty()) {
@@ -220,7 +222,7 @@ bool Media::allowsEditMedia() const {
return false;
}
bool Media::allowsRevoke() const {
bool Media::allowsRevoke(TimeId now) const {
return true;
}
@@ -1326,21 +1328,34 @@ std::unique_ptr<HistoryView::Media> MediaPoll::createView(
return std::make_unique<HistoryView::Poll>(message, _poll);
}
MediaDice::MediaDice(not_null<HistoryItem*> parent, int value)
MediaDice::MediaDice(not_null<HistoryItem*> parent, QString emoji, int value)
: Media(parent)
, _emoji(emoji)
, _value(value) {
}
std::unique_ptr<Media> MediaDice::clone(not_null<HistoryItem*> parent) {
return std::make_unique<MediaDice>(parent, _value);
return std::make_unique<MediaDice>(parent, _emoji, _value);
}
int MediaDice::diceValue() const {
QString MediaDice::emoji() const {
return _emoji;
}
int MediaDice::value() const {
return _value;
}
bool MediaDice::allowsRevoke(TimeId now) const {
const auto peer = parent()->history()->peer;
if (peer->isSelf() || !peer->isUser()) {
return true;
}
return (now >= parent()->date() + kFastRevokeRestriction);
}
QString MediaDice::notificationText() const {
return QString::fromUtf8("\xF0\x9F\x8E\xB2");
return _emoji;
}
QString MediaDice::pinnedTextSubstring() const {

View File

@@ -95,7 +95,7 @@ public:
virtual bool allowsEdit() const;
virtual bool allowsEditCaption() const;
virtual bool allowsEditMedia() const;
virtual bool allowsRevoke() const;
virtual bool allowsRevoke(TimeId now) const;
virtual bool forwardedBecomesUnread() const;
virtual QString errorTextForForward(not_null<PeerData*> peer) const;
@@ -407,12 +407,14 @@ private:
class MediaDice final : public Media {
public:
MediaDice(not_null<HistoryItem*> parent, int value);
MediaDice(not_null<HistoryItem*> parent, QString emoji, int value);
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
int diceValue() const;
[[nodiscard]] QString emoji() const;
[[nodiscard]] int value() const;
bool allowsRevoke(TimeId now) const override;
QString notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
@@ -423,6 +425,7 @@ public:
not_null<HistoryItem*> realParent) override;
private:
QString _emoji;
int _value = 0;
};

View File

@@ -406,7 +406,8 @@ bool PeerData::canPinMessages() const {
if (const auto user = asUser()) {
return user->fullFlags() & MTPDuserFull::Flag::f_can_pin_message;
} else if (const auto chat = asChat()) {
return chat->amIn() && !chat->amRestricted(ChatRestriction::f_pin_messages);
return chat->amIn()
&& !chat->amRestricted(ChatRestriction::f_pin_messages);
} else if (const auto channel = asChannel()) {
return channel->isMegagroup()
? !channel->amRestricted(ChatRestriction::f_pin_messages)
@@ -416,6 +417,19 @@ bool PeerData::canPinMessages() const {
Unexpected("Peer type in PeerData::canPinMessages.");
}
bool PeerData::canEditMessagesIndefinitely() const {
if (const auto user = asUser()) {
return user->isSelf();
} else if (const auto chat = asChat()) {
return false;
} else if (const auto channel = asChannel()) {
return channel->isMegagroup()
? channel->canPinMessages()
: channel->canEditMessages();
}
Unexpected("Peer type in PeerData::canEditMessagesIndefinitely.");
}
void PeerData::setPinnedMessageId(MsgId messageId) {
const auto min = [&] {
if (const auto channel = asChannel()) {

View File

@@ -297,6 +297,7 @@ public:
[[nodiscard]] ImagePtr currentUserpic() const;
[[nodiscard]] bool canPinMessages() const;
[[nodiscard]] bool canEditMessagesIndefinitely() const;
[[nodiscard]] MsgId pinnedMessageId() const {
return _pinnedMessageId;
}

View File

@@ -10,11 +10,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "base/call_delayed.h"
#include "main/main_session.h"
#include "api/api_text_entities.h"
#include "ui/text_options.h"
namespace {
constexpr auto kShortPollTimeout = 30 * crl::time(1000);
constexpr auto kReloadAfterAutoCloseDelay = crl::time(1000);
const PollAnswer *AnswerByOption(
const std::vector<PollAnswer> &list,
@@ -41,6 +45,20 @@ PollData::PollData(not_null<Data::Session*> owner, PollId id)
, _owner(owner) {
}
bool PollData::closeByTimer() {
if (closed()) {
return false;
}
_flags |= Flag::Closed;
++version;
base::call_delayed(kReloadAfterAutoCloseDelay, &_owner->session(), [=] {
_lastResultsUpdate = -1; // Force reload results.
++version;
_owner->notifyPollUpdateDelayed(this);
});
return true;
}
bool PollData::applyChanges(const MTPDpoll &poll) {
Expects(poll.vid().v == id);
@@ -49,6 +67,8 @@ bool PollData::applyChanges(const MTPDpoll &poll) {
| (poll.is_public_voters() ? Flag::PublicVotes : Flag(0))
| (poll.is_multiple_choice() ? Flag::MultiChoice : Flag(0))
| (poll.is_quiz() ? Flag::Quiz : Flag(0));
const auto newCloseDate = poll.vclose_date().value_or_empty();
const auto newClosePeriod = poll.vclose_period().value_or_empty();
auto newAnswers = ranges::view::all(
poll.vanswers().v
) | ranges::view::transform([](const MTPPollAnswer &data) {
@@ -63,6 +83,8 @@ bool PollData::applyChanges(const MTPDpoll &poll) {
) | ranges::to_vector;
const auto changed1 = (question != newQuestion)
|| (closeDate != newCloseDate)
|| (closePeriod != newClosePeriod)
|| (_flags != newFlags);
const auto changed2 = (answers != newAnswers);
if (!changed1 && !changed2) {
@@ -70,6 +92,8 @@ bool PollData::applyChanges(const MTPDpoll &poll) {
}
if (changed1) {
question = newQuestion;
closeDate = newCloseDate;
closePeriod = newClosePeriod;
_flags = newFlags;
}
if (changed2) {
@@ -88,7 +112,7 @@ bool PollData::applyChanges(const MTPDpoll &poll) {
bool PollData::applyResults(const MTPPollResults &results) {
return results.match([&](const MTPDpollResults &results) {
lastResultsUpdate = crl::now();
_lastResultsUpdate = crl::now();
const auto newTotalVoters =
results.vtotal_voters().value_or(totalVoters);
@@ -123,6 +147,17 @@ bool PollData::applyResults(const MTPPollResults &results) {
}) | ranges::to_vector;
}
}
if (results.vsolution()) {
auto newSolution = TextWithEntities{
results.vsolution().value_or_empty(),
Api::EntitiesFromMTP(
results.vsolution_entities().value_or_empty())
};
if (solution != newSolution) {
solution = std::move(newSolution);
changed = true;
}
}
if (!changed) {
return false;
}
@@ -132,13 +167,16 @@ bool PollData::applyResults(const MTPPollResults &results) {
});
}
void PollData::checkResultsReload(not_null<HistoryItem*> item, crl::time now) {
if (lastResultsUpdate && lastResultsUpdate + kShortPollTimeout > now) {
void PollData::checkResultsReload(
not_null<HistoryItem*> item,
crl::time now) {
if (_lastResultsUpdate > 0
&& _lastResultsUpdate + kShortPollTimeout > now) {
return;
} else if (closed()) {
} else if (closed() && _lastResultsUpdate >= 0) {
return;
}
lastResultsUpdate = now;
_lastResultsUpdate = now;
_owner->session().api().reloadPollResults(item);
}
@@ -169,11 +207,9 @@ bool PollData::applyResultToAnswers(
changed = true;
}
}
if (!isMinResults || closed()) {
if (answer->correct != voters.is_correct()) {
answer->correct = voters.is_correct();
changed = true;
}
if (voters.is_correct() && !answer->correct) {
answer->correct = voters.is_correct();
changed = true;
}
return changed;
});
@@ -226,10 +262,49 @@ MTPPoll PollDataToMTP(not_null<const PollData*> poll, bool close) {
const auto flags = ((poll->closed() || close) ? Flag::f_closed : Flag(0))
| (poll->multiChoice() ? Flag::f_multiple_choice : Flag(0))
| (poll->publicVotes() ? Flag::f_public_voters : Flag(0))
| (poll->quiz() ? Flag::f_quiz : Flag(0));
| (poll->quiz() ? Flag::f_quiz : Flag(0))
| (poll->closePeriod > 0 ? Flag::f_close_period : Flag(0))
| (poll->closeDate > 0 ? Flag::f_close_date : Flag(0));
return MTP_poll(
MTP_long(poll->id),
MTP_flags(flags),
MTP_string(poll->question),
MTP_vector<MTPPollAnswer>(answers));
MTP_vector<MTPPollAnswer>(answers),
MTP_int(poll->closePeriod),
MTP_int(poll->closeDate));
}
MTPInputMedia PollDataToInputMedia(
not_null<const PollData*> poll,
bool close) {
auto inputFlags = MTPDinputMediaPoll::Flag(0)
| (poll->quiz()
? MTPDinputMediaPoll::Flag::f_correct_answers
: MTPDinputMediaPoll::Flag(0));
auto correct = QVector<MTPbytes>();
for (const auto &answer : poll->answers) {
if (answer.correct) {
correct.push_back(MTP_bytes(answer.option));
}
}
auto solution = poll->solution;
const auto prepareFlags = Ui::ItemTextDefaultOptions().flags;
TextUtilities::PrepareForSending(solution, prepareFlags);
TextUtilities::Trim(solution);
const auto sentEntities = Api::EntitiesToMTP(
solution.entities,
Api::ConvertOption::SkipLocal);
if (!solution.text.isEmpty()) {
inputFlags |= MTPDinputMediaPoll::Flag::f_solution;
}
if (!sentEntities.v.isEmpty()) {
inputFlags |= MTPDinputMediaPoll::Flag::f_solution_entities;
}
return MTP_inputMediaPoll(
MTP_flags(inputFlags),
PollDataToMTP(poll, close),
MTP_vector<MTPbytes>(correct),
MTP_string(solution.text),
sentEntities);
}

View File

@@ -40,6 +40,7 @@ struct PollData {
friend inline constexpr bool is_flag_type(Flag) { return true; };
using Flags = base::flags<Flag>;
bool closeByTimer();
bool applyChanges(const MTPDpoll &poll);
bool applyResults(const MTPPollResults &results);
void checkResultsReload(not_null<HistoryItem*> item, crl::time now);
@@ -60,10 +61,11 @@ struct PollData {
QString question;
std::vector<PollAnswer> answers;
std::vector<not_null<UserData*>> recentVoters;
int totalVoters = 0;
std::vector<QByteArray> sendingVotes;
crl::time lastResultsUpdate = 0;
TextWithEntities solution;
TimeId closePeriod = 0;
TimeId closeDate = 0;
int totalVoters = 0;
int version = 0;
static constexpr auto kMaxOptions = 10;
@@ -73,9 +75,15 @@ private:
const MTPPollAnswerVoters &result,
bool isMinResults);
not_null<Data::Session*> _owner;
const not_null<Data::Session*> _owner;
Flags _flags = Flags();
crl::time _lastResultsUpdate = 0; // < 0 means force reload.
};
MTPPoll PollDataToMTP(not_null<const PollData*> poll, bool close = false);
[[nodiscard]] MTPPoll PollDataToMTP(
not_null<const PollData*> poll,
bool close = false);
[[nodiscard]] MTPInputMedia PollDataToInputMedia(
not_null<const PollData*> poll,
bool close = false);

View File

@@ -191,6 +191,7 @@ Session::Session(not_null<Main::Session*> session)
, _sendActionsAnimation([=](crl::time now) {
return sendActionsAnimationCallback(now);
})
, _pollsClosingTimer([=] { checkPollsClosings(); })
, _unmuteByFinishedTimer([=] { unmuteByFinished(); })
, _groups(this)
, _chatsFilters(std::make_unique<ChatFilters>(this))
@@ -2877,6 +2878,10 @@ not_null<PollData*> Session::processPoll(const MTPPoll &data) {
if (changed) {
notifyPollUpdateDelayed(result);
}
if (result->closeDate > 0 && !result->closed()) {
_pollsClosings.emplace(result->closeDate, result);
checkPollsClosings();
}
return result;
});
}
@@ -2890,6 +2895,29 @@ not_null<PollData*> Session::processPoll(const MTPDmessageMediaPoll &data) {
return result;
}
void Session::checkPollsClosings() {
const auto now = base::unixtime::now();
auto closest = 0;
for (auto i = _pollsClosings.begin(); i != _pollsClosings.end();) {
if (i->first <= now) {
if (i->second->closeByTimer()) {
notifyPollUpdateDelayed(i->second);
}
i = _pollsClosings.erase(i);
} else {
if (!closest) {
closest = i->first;
}
++i;
}
}
if (closest) {
_pollsClosingTimer.callOnce((closest - now) * crl::time(1000));
} else {
_pollsClosingTimer.cancel();
}
}
void Session::applyUpdate(const MTPDupdateMessagePoll &update) {
const auto updated = [&] {
const auto poll = update.vpoll();
@@ -3685,30 +3713,37 @@ MessageIdsList Session::takeMimeForwardIds() {
return std::move(_mimeForwardIds);
}
void Session::setProxyPromoted(PeerData *promoted) {
if (_proxyPromoted != promoted) {
if (const auto history = historyLoaded(_proxyPromoted)) {
history->cacheProxyPromoted(false);
void Session::setTopPromoted(
PeerData *promoted,
const QString &type,
const QString &message) {
const auto changed = (_topPromoted != promoted);
const auto history = promoted ? this->history(promoted).get() : nullptr;
if (changed
|| (history && history->topPromotionMessage() != message)) {
if (changed) {
if (const auto history = historyLoaded(_topPromoted)) {
history->cacheTopPromotion(false, QString(), QString());
}
}
const auto old = std::exchange(_proxyPromoted, promoted);
if (_proxyPromoted) {
const auto history = this->history(_proxyPromoted);
history->cacheProxyPromoted(true);
const auto old = std::exchange(_topPromoted, promoted);
if (history) {
history->cacheTopPromotion(true, type, message);
history->requestChatListMessage();
Notify::peerUpdatedDelayed(
_proxyPromoted,
Notify::PeerUpdate::Flag::ChannelPromotedChanged);
_topPromoted,
Notify::PeerUpdate::Flag::TopPromotedChanged);
}
if (old) {
if (changed && old) {
Notify::peerUpdatedDelayed(
old,
Notify::PeerUpdate::Flag::ChannelPromotedChanged);
Notify::PeerUpdate::Flag::TopPromotedChanged);
}
}
}
PeerData *Session::proxyPromoted() const {
return _proxyPromoted;
PeerData *Session::topPromoted() const {
return _topPromoted;
}
bool Session::updateWallpapers(const MTPaccount_WallPapers &data) {

View File

@@ -678,8 +678,11 @@ public:
void setMimeForwardIds(MessageIdsList &&list);
MessageIdsList takeMimeForwardIds();
void setProxyPromoted(PeerData *promoted);
PeerData *proxyPromoted() const;
void setTopPromoted(
PeerData *promoted,
const QString &type,
const QString &message);
PeerData *topPromoted() const;
bool updateWallpapers(const MTPaccount_WallPapers &data);
void removeWallpaper(const WallPaper &paper);
@@ -822,6 +825,8 @@ private:
void setWallpapers(const QVector<MTPWallPaper> &data, int32 hash);
void checkPollsClosings();
not_null<Main::Session*> _session;
Storage::DatabasePointer _cache;
@@ -943,6 +948,9 @@ private:
base::flat_set<not_null<GameData*>> _gamesUpdated;
base::flat_set<not_null<PollData*>> _pollsUpdated;
base::flat_multi_map<TimeId, not_null<PollData*>> _pollsClosings;
base::Timer _pollsClosingTimer;
base::flat_map<FolderId, std::unique_ptr<Folder>> _folders;
//rpl::variable<FeedId> _defaultFeedId = FeedId(); // #feed
@@ -952,7 +960,7 @@ private:
base::flat_set<not_null<ViewElement*>> _heavyViewParts;
PeerData *_proxyPromoted = nullptr;
PeerData *_topPromoted = nullptr;
NotifySettings _defaultUserNotifySettings;
NotifySettings _defaultChatNotifySettings;

View File

@@ -86,15 +86,20 @@ void Entry::cachePinnedIndex(FilterId filterId, int index) {
}
}
void Entry::cacheProxyPromoted(bool promoted) {
if (_isProxyPromoted != promoted) {
_isProxyPromoted = promoted;
updateChatListSortPosition();
updateChatListEntry();
if (!_isProxyPromoted) {
updateChatListExistence();
}
void Entry::cacheTopPromoted(bool promoted) {
if (_isTopPromoted == promoted) {
return;
}
_isTopPromoted = promoted;
updateChatListSortPosition();
updateChatListEntry();
if (!_isTopPromoted) {
updateChatListExistence();
}
}
bool Entry::isTopPromoted() const {
return _isTopPromoted;
}
bool Entry::needUpdateInChatList() const {

View File

@@ -120,10 +120,7 @@ public:
return lookupPinnedIndex(filterId) != 0;
}
void cachePinnedIndex(FilterId filterId, int index);
bool isProxyPromoted() const {
return _isProxyPromoted;
}
void cacheProxyPromoted(bool promoted);
[[nodiscard]] bool isTopPromoted() const;
[[nodiscard]] uint64 sortKeyInChatList(FilterId filterId) const {
return filterId
? computeSortPosition(filterId)
@@ -137,7 +134,7 @@ public:
virtual int fixedOnTopIndex() const = 0;
static constexpr auto kArchiveFixOnTopIndex = 1;
static constexpr auto kProxyPromotionFixOnTopIndex = 2;
static constexpr auto kTopPromotionFixOnTopIndex = 2;
virtual bool shouldBeInChatList() const = 0;
virtual int chatListUnreadCount() const = 0;
@@ -194,6 +191,8 @@ protected:
[[nodiscard]] int lookupPinnedIndex(FilterId filterId) const;
void cacheTopPromoted(bool promoted);
private:
virtual void changedChatListPinHook();
void pinnedIndexChanged(int was, int now);
@@ -211,8 +210,8 @@ private:
uint64 _sortKeyInChatList = 0;
uint64 _sortKeyByDate = 0;
base::flat_map<FilterId, int> _pinnedIndex;
bool _isProxyPromoted = false;
TimeId _timeId = 0;
bool _isTopPromoted = false;
};

View File

@@ -35,6 +35,7 @@ namespace {
// Show all dates that are in the last 20 hours in time format.
constexpr int kRecentlyInSeconds = 20 * 3600;
const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
bool ShowUserBotIcon(not_null<UserData*> user) {
return user->isBot() && !user->isSupport();
@@ -296,10 +297,19 @@ void paintRow(
namewidth,
st::msgNameFont->height);
const auto promoted = (history && history->useProxyPromotion())
const auto promoted = (history && history->useTopPromotion())
&& !(flags & (Flag::SearchResult/* | Flag::FeedSearchResult*/)); // #feed
if (promoted) {
const auto text = tr::lng_proxy_sponsor(tr::now);
const auto type = history->topPromotionType();
const auto custom = type.isEmpty()
? QString()
: Lang::Current().getNonDefaultValue(
kPsaBadgePrefix + type.toUtf8());
const auto text = type.isEmpty()
? tr::lng_proxy_sponsor(tr::now)
: custom.isEmpty()
? tr::lng_badge_psa_default(tr::now)
: custom;
PaintRowTopRight(p, text, rectForName, active, selected);
} else if (from/* && !(flags & Flag::FeedSearchResult)*/) { // #feed
if (const auto chatTypeIcon = ChatTypeIcon(from, active, selected)) {
@@ -315,7 +325,18 @@ void paintRow(
auto texttop = st::dialogsPadding.y()
+ st::msgNameFont->height
+ st::dialogsSkip;
if (draft
if (promoted && !history->topPromotionMessage().isEmpty()) {
auto availableWidth = namewidth;
p.setFont(st::dialogsTextFont);
if (history->cloudDraftTextCache.isEmpty()) {
history->cloudDraftTextCache.setText(
st::dialogsTextStyle,
history->topPromotionMessage(),
Ui::DialogTextOptions());
}
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg));
history->cloudDraftTextCache.drawElided(p, nameleft, texttop, availableWidth, 1);
} else if (draft
|| (supportMode
&& Auth().supportHelper().isOccupiedBySomeone(history))) {
if (!promoted) {

View File

@@ -582,6 +582,11 @@ void InnerWidget::elementShowPollResults(
FullMsgId context) {
}
void InnerWidget::elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) {
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) {
memento->setFilter(std::move(_filter));
memento->setAdmins(std::move(_admins));

View File

@@ -104,6 +104,9 @@ public:
void elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context) override;
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) override;
~InnerWidget();

View File

@@ -1706,9 +1706,6 @@ void History::applyInboxReadUpdate(
}
void History::inboxRead(MsgId upTo, std::optional<int> stillUnread) {
if (unreadCount() > 0 && loadedAtBottom()) {
App::main()->historyToDown(this);
}
if (stillUnread.has_value() && folderKnown()) {
setUnreadCount(*stillUnread);
} else if (const auto still = countStillUnreadLocal(upTo)) {
@@ -1968,6 +1965,9 @@ void History::setFolderPointer(Data::Folder *folder) {
if (folder) {
folder->registerOne(this);
}
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::FolderChanged);
}
void History::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
@@ -2583,17 +2583,19 @@ void History::updateChatListExistence() {
//}
}
bool History::useProxyPromotion() const {
if (!isProxyPromoted()) {
bool History::useTopPromotion() const {
if (!isTopPromoted()) {
return false;
} else if (const auto channel = peer->asChannel()) {
return !isPinnedDialog(FilterId()) && !channel->amIn();
} else if (const auto user = peer->asUser()) {
return !isPinnedDialog(FilterId()) && user->isBot() && isEmpty();
}
return false;
}
int History::fixedOnTopIndex() const {
return useProxyPromotion() ? kProxyPromotionFixOnTopIndex : 0;
return useTopPromotion() ? kTopPromotionFixOnTopIndex : 0;
}
bool History::trackUnreadMessages() const {
@@ -2610,7 +2612,7 @@ bool History::shouldBeInChatList() const {
return true;
} else if (const auto channel = peer->asChannel()) {
if (!channel->amIn()) {
return isProxyPromoted();
return isTopPromoted();
//} else if (const auto feed = channel->feed()) { // #feed
// return !feed->needUpdateInChatList();
}
@@ -2618,6 +2620,10 @@ bool History::shouldBeInChatList() const {
return chat->amIn()
|| !lastMessageKnown()
|| (lastMessage() != nullptr);
} else if (const auto user = peer->asUser()) {
if (user->isBot() && isTopPromoted()) {
return true;
}
}
return !lastMessageKnown()
|| (lastMessage() != nullptr);
@@ -2721,6 +2727,41 @@ void History::dialogEntryApplied() {
}
}
void History::cacheTopPromotion(
bool promoted,
const QString &type,
const QString &message) {
const auto changed = (isTopPromoted() != promoted);
cacheTopPromoted(promoted);
if (topPromotionType() != type || _topPromotedMessage != message) {
_topPromotedType = type;
_topPromotedMessage = message;
cloudDraftTextCache.clear();
} else if (changed) {
cloudDraftTextCache.clear();
}
}
QStringRef History::topPromotionType() const {
return topPromotionAboutShown()
? _topPromotedType.midRef(5)
: _topPromotedType.midRef(0);
}
bool History::topPromotionAboutShown() const {
return _topPromotedType.startsWith("seen^");
}
void History::markTopPromotionAboutShown() {
if (!topPromotionAboutShown()) {
_topPromotedType = "seen^" + _topPromotedType;
}
}
QString History::topPromotionMessage() const {
return _topPromotedMessage;
}
bool History::clearUnreadOnClientSide() const {
if (!session().supportMode()) {
return false;

View File

@@ -237,6 +237,15 @@ public:
MsgId maxOutboxRead);
void dialogEntryApplied();
void cacheTopPromotion(
bool promoted,
const QString &type,
const QString &message);
[[nodiscard]] QStringRef topPromotionType() const;
[[nodiscard]] QString topPromotionMessage() const;
[[nodiscard]] bool topPromotionAboutShown() const;
void markTopPromotionAboutShown();
MsgId minMsgId() const;
MsgId maxMsgId() const;
MsgId msgIdForRead() const;
@@ -330,7 +339,7 @@ public:
void setForwardDraft(MessageIdsList &&items);
History *migrateSibling() const;
bool useProxyPromotion() const;
[[nodiscard]] bool useTopPromotion() const;
int fixedOnTopIndex() const override;
void updateChatListExistence() override;
bool shouldBeInChatList() const override;
@@ -559,6 +568,9 @@ private:
TimeId _lastSentDraftTime = 0;
MessageIdsList _forwardDraft;
QString _topPromotedMessage;
QString _topPromotedType;
base::flat_map<not_null<UserData*>, crl::time> _typing;
base::flat_map<not_null<UserData*>, SendAction> _sendActions;
QString _sendActionString;

View File

@@ -379,6 +379,20 @@ botKbTinyButton: BotKeyboardButton {
botKbScroll: defaultSolidScroll;
historyDateFadeDuration: 200;
historyDiceToast: Toast(defaultToast) {
minWidth: msgMinWidth;
maxWidth: 640px;
}
historyErrorToast: Toast(defaultToast) {
minWidth: msgMinWidth;
}
historyInfoToast: Toast(defaultToast) {
minWidth: msgMinWidth;
maxWidth: 380px;
padding: margins(54px, 13px, 19px, 12px);
icon: icon {{ "toast_info", toastFg }};
iconPosition: point(13px, 13px);
}
historyPhotoLeft: 14px;
historyPhotoBubbleMinWidth: 200px;
@@ -394,6 +408,15 @@ historyBubbleTailOutRightSelected: icon {{ "bubble_tail-flip_horizontal", msgOut
historyPeerUserpicFont: semiboldFont;
historyPsaIconIn: icon {{ "message_psa_tooltip", msgFileThumbLinkInFg }};
historyPsaIconInSelected: icon {{ "message_psa_tooltip", msgFileThumbLinkInFgSelected }};
historyPsaIconOut: icon {{ "message_psa_tooltip", msgFileThumbLinkOutFg }};
historyPsaIconOutSelected: icon {{ "message_psa_tooltip", msgFileThumbLinkOutFgSelected }};
historyPsaIconSkip1: 23px;
historyPsaIconSkip2: 23px;
historyPsaIconPosition1: point(-5px, 0px);
historyPsaIconPosition2: point(-5px, 0px);
historyStatusFg: windowSubTextFg;
historyStatusFgActive: windowActiveTextFg;
historyStatusFgTyping: historyStatusFgActive;
@@ -506,15 +529,13 @@ historyGroupSkip: 4px;
historyGroupRadialSize: 44px;
historyGroupRadialLine: 3px;
historyAboutProxy: FlatLabel(defaultFlatLabel) {
align: align(top);
textFg: windowSubTextFg;
}
historyAboutProxyPadding: margins(20px, 10px, 20px, 10px);
historyMapPoint: icon {{ "map_point", mapPointDrop }};
historyMapPointInner: icon {{ "map_point_inner", mapPointDot }};
historyPsaForwardPalette: TextPalette(defaultTextPalette) {
linkFg: boxTextFgGood;
}
webPageLeft: 10px;
webPageBar: 2px;
webPageTitleFont: semiboldFont;
@@ -618,6 +639,15 @@ historyAudioInDownloadSelected: icon {{ "history_audio_download", historyFileInI
historyAudioOutDownload: icon {{ "history_audio_download", historyFileOutIconFg }};
historyAudioOutDownloadSelected: icon {{ "history_audio_download", historyFileOutIconFgSelected }};
historyQuizExplainIn: icon {{ "quiz_explain", msgFileThumbLinkInFg }};
historyQuizExplainInSelected: icon {{ "quiz_explain", msgFileThumbLinkInFgSelected }};
historyQuizExplainOut: icon {{ "quiz_explain", msgFileThumbLinkOutFg }};
historyQuizExplainOutSelected: icon {{ "quiz_explain", msgFileThumbLinkOutFgSelected }};
historyQuizTimerIn: icon {{ "quiz_timer", msgFileThumbLinkInFg }};
historyQuizTimerInSelected: icon {{ "quiz_timer", msgFileThumbLinkInFgSelected }};
historyQuizTimerOut: icon {{ "quiz_timer", msgFileThumbLinkOutFg }};
historyQuizTimerOutSelected: icon {{ "quiz_timer", msgFileThumbLinkOutFgSelected }};
historySlowmodeCounterMargins: margins(0px, 0px, 10px, 0px);
largeEmojiSize: 36px;

View File

@@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_inner_widget.h"
#include <rpl/merge.h>
#include "styles/style_history.h"
#include "core/file_utilities.h"
#include "core/crash_reports.h"
#include "history/history.h"
@@ -57,6 +56,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_histories.h"
#include "facades.h"
#include "app.h"
#include "styles/style_history.h"
#include "styles/style_window.h" // st::windowMinWidth
#include <QtGui/QClipboard>
#include <QtWidgets/QApplication>
@@ -132,16 +133,16 @@ void HistoryInner::BotAbout::clickHandlerPressedChanged(
HistoryInner::HistoryInner(
not_null<HistoryWidget*> historyWidget,
not_null<Ui::ScrollArea*> scroll,
not_null<Window::SessionController*> controller,
Ui::ScrollArea *scroll,
not_null<History*> history)
: RpWidget(nullptr)
, _widget(historyWidget)
, _scroll(scroll)
, _controller(controller)
, _peer(history->peer)
, _history(history)
, _migrated(history->migrateFrom())
, _widget(historyWidget)
, _scroll(scroll)
, _scrollDateCheck([this] { scrollDateCheck(); })
, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) {
Instance = this;
@@ -2476,9 +2477,14 @@ void HistoryInner::elementStartStickerLoop(
}
void HistoryInner::elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context) {
_controller->showPollResults(poll, context);
not_null<PollData*> poll,
FullMsgId context) {
}
void HistoryInner::elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) {
_widget->showInfoTooltip(text, std::move(hiddenCallback));
}
auto HistoryInner::getSelectionState() const
@@ -3348,6 +3354,13 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
Instance->elementShowPollResults(poll, context);
}
}
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) override {
if (Instance) {
Instance->elementShowTooltip(text, hiddenCallback);
}
}
};

View File

@@ -49,8 +49,8 @@ public:
HistoryInner(
not_null<HistoryWidget*> historyWidget,
not_null<Ui::ScrollArea*> scroll,
not_null<Window::SessionController*> controller,
Ui::ScrollArea *scroll,
not_null<History*> history);
Main::Session &session() const;
@@ -85,6 +85,9 @@ public:
void elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context);
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback);
void updateBotInfo(bool recount = true);
@@ -311,14 +314,20 @@ private:
static HistoryInner *Instance;
not_null<Window::SessionController*> _controller;
const not_null<HistoryWidget*> _widget;
const not_null<Ui::ScrollArea*> _scroll;
const not_null<Window::SessionController*> _controller;
const not_null<PeerData*> _peer;
const not_null<History*> _history;
History *_migrated = nullptr;
int _contentWidth = 0;
int _historyPaddingTop = 0;
// Save visible area coords for painting / pressing userpics.
int _visibleAreaTop = 0;
int _visibleAreaBottom = 0;
// With migrated history we perhaps do not need to display
// the first _history message date (just skip it by height).
int _historySkipHeight = 0;
@@ -326,8 +335,6 @@ private:
std::unique_ptr<BotAbout> _botAbout;
std::unique_ptr<HistoryView::EmptyPainter> _emptyPainter;
HistoryWidget *_widget = nullptr;
Ui::ScrollArea *_scroll = nullptr;
mutable History *_curHistory = nullptr;
mutable int _curBlock = 0;
mutable int _curItem = 0;
@@ -375,10 +382,6 @@ private:
base::unique_qptr<Ui::PopupMenu> _menu;
// save visible area coords for painting / pressing userpics
int _visibleAreaTop = 0;
int _visibleAreaBottom = 0;
bool _scrollDateShown = false;
Ui::Animations::Simple _scrollDateOpacity;
SingleQueuedInvokation _scrollDateCheck;

View File

@@ -585,13 +585,11 @@ bool HistoryItem::canDeleteForEveryone(TimeId now) const {
return false;
}
}
if (!peer->isUser()) {
if (!toHistoryMessage()) {
if (!peer->isUser() && !toHistoryMessage()) {
return false;
} else if (const auto media = this->media()) {
if (!media->allowsRevoke(now)) {
return false;
} else if (const auto media = this->media()) {
if (!media->allowsRevoke()) {
return false;
}
}
}
if (!out()) {

View File

@@ -32,6 +32,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QGuiApplication>
namespace {
const auto kPsaForwardedPrefix = "cloud_lng_forwarded_psa_";
} // namespace
void HistoryMessageVia::create(UserId userId) {
bot = Auth().data().user(userId);
maxWidth = st::msgServiceNameFont->width(
@@ -127,7 +133,7 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
} else {
phrase = name;
}
if (via) {
if (via && psaType.isEmpty()) {
if (fromChannel) {
phrase = tr::lng_forwarded_channel_via(
tr::now,
@@ -144,11 +150,19 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
textcmdLink(2, '@' + via->bot->username));
}
} else {
if (fromChannel) {
phrase = tr::lng_forwarded_channel(
tr::now,
lt_channel,
textcmdLink(1, phrase));
if (fromChannel || !psaType.isEmpty()) {
auto custom = psaType.isEmpty()
? QString()
: Lang::Current().getNonDefaultValue(
kPsaForwardedPrefix + psaType.toUtf8());
phrase = !custom.isEmpty()
? custom.replace("{channel}", textcmdLink(1, phrase))
: (psaType.isEmpty()
? tr::lng_forwarded_channel
: tr::lng_forwarded_psa_default)(
tr::now,
lt_channel,
textcmdLink(1, phrase));
} else {
phrase = tr::lng_forwarded(
tr::now,

View File

@@ -77,6 +77,7 @@ struct HistoryMessageForwarded : public RuntimeComponent<HistoryMessageForwarded
PeerData *originalSender = nullptr;
std::unique_ptr<HiddenSenderInfo> hiddenSenderInfo;
QString originalAuthor;
QString psaType;
MsgId originalId = 0;
mutable Ui::Text::String text = { 1 };

View File

@@ -8,13 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h"
#include "mainwidget.h"
#include "core/file_utilities.h"
#include "lang/lang_keys.h"
#include "ui/image/image.h"
#include "data/data_file_origin.h"
#include "platform/platform_specific.h"
#include <QtGui/QDesktopServices>
namespace {
constexpr auto kCoordPrecision = 8;
@@ -32,7 +31,7 @@ QString LocationClickHandler::copyToClipboardContextItemText() const {
void LocationClickHandler::onClick(ClickContext context) const {
if (!psLaunchMaps(_point)) {
QDesktopServices::openUrl(_text);
File::OpenUrl(_text);
}
}

View File

@@ -383,6 +383,7 @@ struct HistoryMessage::CreateConfig {
QString author;
PeerId senderOriginal = 0;
QString senderNameOriginal;
QString forwardPsaType;
MsgId originalId = 0;
PeerId savedFromPeer = 0;
MsgId savedFromMsgId = 0;
@@ -407,6 +408,7 @@ void HistoryMessage::FillForwardedInfo(
}
config.originalDate = data.vdate().v;
config.senderNameOriginal = qs(data.vfrom_name().value_or_empty());
config.forwardPsaType = qs(data.vpsa_type().value_or_empty());
config.originalId = data.vchannel_post().value_or_empty();
config.authorOriginal = qs(data.vpost_author().value_or_empty());
const auto savedFromPeer = data.vsaved_from_peer();
@@ -768,15 +770,8 @@ bool HistoryMessage::allowsSendNow() const {
}
bool HistoryMessage::isTooOldForEdit(TimeId now) const {
const auto peer = _history->peer;
if (peer->isSelf()) {
return false;
} else if (const auto megagroup = peer->asMegagroup()) {
if (megagroup->canPinMessages()) {
return false;
}
}
return (now - date() >= Global::EditTimeLimit());
return !_history->peer->canEditMessagesIndefinitely()
&& (now - date() >= Global::EditTimeLimit());
}
bool HistoryMessage::allowsEdit(TimeId now) const {
@@ -874,6 +869,7 @@ void HistoryMessage::setupForwardedComponent(const CreateConfig &config) {
}
forwarded->originalId = config.originalId;
forwarded->originalAuthor = config.authorOriginal;
forwarded->psaType = config.forwardPsaType;
forwarded->savedFromPeer = history()->owner().peerLoaded(
config.savedFromPeer);
forwarded->savedFromMsgId = config.savedFromMsgId;
@@ -1025,7 +1021,10 @@ std::unique_ptr<Data::Media> HistoryMessage::CreateMedia(
item,
item->history()->owner().processPoll(media));
}, [&](const MTPDmessageMediaDice &media) -> Result {
return std::make_unique<Data::MediaDice>(item, media.vvalue().v);
return std::make_unique<Data::MediaDice>(
item,
qs(media.vemoticon()),
media.vvalue().v);
}, [](const MTPDmessageMediaEmpty &) -> Result {
return nullptr;
}, [](const MTPDmessageMediaUnsupported &) -> Result {

Some files were not shown because too many files have changed in this diff Show More