This commit is contained in:
John Preston 2016-04-07 20:19:18 +04:00
commit ecce77ec4c
282 changed files with 48983 additions and 24654 deletions

View file

@ -11,6 +11,7 @@ This document describes how you can contribute to Telegram Desktop. Please read
* [Pull upstream changes into your fork regularly](#pull-upstream-changes-into-your-fork-regularly)
* [How to get your pull request accepted](#how-to-get-your-pull-request-accepted)
* [Keep your pull requests limited to a single issue](#keep-your-pull-requests-limited-to-a-single-issue)
* [Squash your commits to a single commit](#squash-your-commits-to-a-single-commit)
* [Don't mix code changes with whitespace cleanup](#dont-mix-code-changes-with-whitespace-cleanup)
* [Keep your code simple!](#keep-your-code-simple)
* [Test your changes!](#test-your-changes)
@ -72,10 +73,8 @@ For more info, see [GitHub Help][help_change_commit_message].
## Build instructions
* [Visual Studio 2013][msvc]
* [XCode 6.4][xcode]
* [XCode 6.4 for OS X 10.6 and 10.7][xcode_old]
* [Qt Creator 3.2.0 Ubuntu][qtcreator]
See the [README.md](README.md#build-instructions) for details on the various build
environments.
## Pull upstream changes into your fork regularly
@ -90,9 +89,13 @@ Check the log to be sure that you actually want the changes, before merging:
git log upstream/master
Then merge the changes that you fetched:
Then rebase your changes on the latest commits in the `master` branch:
git merge upstream/master
git rebase upstream/master
After that, you have to force push your commits:
git push --force
For more info, see [GitHub Help][help_fork_repo].
@ -107,6 +110,21 @@ Pull requests should be as small/atomic as possible. Large, wide-sweeping change
* If you are making spelling corrections in the docs, don't modify other files.
* If you are adding new functions don't '*cleanup*' unrelated functions. That cleanup belongs in another pull request.
#### Squash your commits to a single commit
To keep the history of the project clean, you should make one commit per pull request.
If you already have multiple commits, you can add the commits together (squash them) with the following commands in Git Bash:
1. Open `Git Bash` (or `Git Shell`)
2. Enter following command to squash the recent {N} commits: `git reset --soft HEAD~{N} && git commit` (replace `{N}` with the number of commits you want to squash)
3. Press <kbd>i</kbd> to get into Insert-mode
4. Enter the commit message of the new commit (and add the [signature](#sign-your-work) at the and)
5. After adding the message, press <kbd>ESC</kbd> to get out of the Insert-mode
6. Write `:wq` and press <kbd>Enter</kbd> to save the new message or write `:q!` to discard your changes
7. Enter `git push --force` to push the new commit to the remote repository
For example, if you want to squash the last 5 commits, use `git reset --soft HEAD~5 && git commit`
### Don't mix code changes with whitespace cleanup
If you change two lines of code and correct 200 lines of whitespace issues in a file the diff on that pull request is functionally unreadable and will be **rejected**. Whitespace cleanups need to be in their own pull request.

26
.github/ISSUE_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,26 @@
<!--
Thanks for reporting issues of Telegram Desktop!
To make it easier for us to help you please enter detailed information below.
-->
### Steps to reproduce
1.
2.
3.
### Expected behaviour
Tell us what should happen
### Actual behaviour
Tell us what happens instead
### Configuration
**Operating system:**
**Version of Telegram Desktop:**
### Logs
Insert logs here (if necessary)
You can type "debugmode" in settings and then see ~/.TelegramDesktop/DebugLogs/log_...txt for log files.
Type "debugmode" in settings again to disable logs.

2
.gitignore vendored
View file

@ -7,9 +7,11 @@
/Telegram/SourceFiles/art/sprite_125x.png
/Telegram/SourceFiles/art/sprite_150x.png
/Telegram/*.user
*.vcxproj.user
*.suo
*.sdf
*.opensdf
*.opendb
/Telegram/*.aps
/Win32/
ipch/

47
.travis.yml Normal file
View file

@ -0,0 +1,47 @@
sudo: required
language: cpp
env:
- BUILD_VERSION=""
- BUILD_VERSION="disable_autoupdate"
- BUILD_VERSION="disable_register_custom_scheme"
- BUILD_VERSION="disable_crash_reports"
- BUILD_VERSION="disable_network_proxy"
arch:
packages:
- bzr
- wget
- qt5-base
- git
- patch
- libunity
- libappindicator-gtk2
- ffmpeg
- icu
- jasper
- libexif
- libmng
- libwebp
- libxkbcommon-x11
- libinput
- libproxy
- mtdev
- openal
- libva
- desktop-file-utils
- gtk-update-icon-cache
script:
- libtool --finish /usr/lib
- .travis/build.sh
before_install:
- "export TRAVIS_COMMIT_MSG=\"$(git log --format=%B --no-merges -n 1)\""
- .travis/check.sh
script:
- .travis/arch.sh

297
.travis/arch.sh Executable file
View file

@ -0,0 +1,297 @@
#!/bin/bash
# Copyright (C) 2016 Mikkel Oscar Lyderik Larsen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Source: https://raw.githubusercontent.com/mikkeloscar/arch-travis/master/arch-travis.sh
# Script for setting up and running a travis-ci build in an up to date
# Arch Linux chroot
ARCH_TRAVIS_MIRROR=${ARCH_TRAVIS_MIRROR:-"https://lug.mtu.edu/archlinux"}
ARCH_TRAVIS_ARCH_ISO=${ARCH_TRAVIS_ARCH_ISO:-"$(date +%Y.%m).01"}
mirror_entry='Server = '$ARCH_TRAVIS_MIRROR'/\$repo/os/\$arch'
archive="archlinux-bootstrap-$ARCH_TRAVIS_ARCH_ISO-x86_64.tar.gz"
default_root="root.x86_64"
ARCH_TRAVIS_CHROOT=${ARCH_TRAVIS_CHROOT:-"$default_root"}
user="travis"
user_home="/home/$user"
user_build_dir="/build"
user_uid=$UID
if [ -n "$CC" ]; then
# store travis CC
TRAVIS_CC=$CC
# reset to gcc for building arch packages
CC=gcc
fi
# default packages
default_packages=("base-devel" "git")
# pacman.conf repository line
repo_line=70
# setup working Arch Linux chroot
setup_chroot() {
arch_msg "Setting up Arch chroot"
if [ ! -f $archive ]; then
# get root fs
curl --fail -O "$ARCH_TRAVIS_MIRROR/iso/$ARCH_TRAVIS_ARCH_ISO/$archive" 2>&1
local ret=$?
# if it fails, try arch iso form the previous month
if [ $ret -gt 0 ]; then
ARCH_TRAVIS_ARCH_ISO="$(date +%Y.%m -d "-1 month").01"
archive="archlinux-bootstrap-$ARCH_TRAVIS_ARCH_ISO-x86_64.tar.gz"
as_normal "curl -O $ARCH_TRAVIS_MIRROR/iso/$ARCH_TRAVIS_ARCH_ISO/$archive"
fi
fi
# extract root fs
as_root "tar xf $archive"
# remove archive if ARCH_TRAVIS_CLEAN_CHROOT is set
if [ -n "$ARCH_TRAVIS_CLEAN_CHROOT" ]; then
as_root "rm $archive"
fi
if [ "$ARCH_TRAVIS_CHROOT" != "$default_root" ]; then
as_root "mv $default_root $ARCH_TRAVIS_CHROOT"
fi
# don't care for signed packages
as_root "sed -i 's|SigLevel = Required DatabaseOptional|SigLevel = Never|' $ARCH_TRAVIS_CHROOT/etc/pacman.conf"
# enable multilib
as_root "sed -i 's|#\[multilib\]|\[multilib\]\nInclude = /etc/pacman.d/mirrorlist|' $ARCH_TRAVIS_CHROOT/etc/pacman.conf"
# add mirror
as_root "echo $mirror_entry >> $ARCH_TRAVIS_CHROOT/etc/pacman.d/mirrorlist"
# add nameserver to resolv.conf
as_root "echo nameserver 8.8.8.8 >> $ARCH_TRAVIS_CHROOT/etc/resolv.conf"
sudo mount $ARCH_TRAVIS_CHROOT $ARCH_TRAVIS_CHROOT --bind
sudo mount --bind /proc $ARCH_TRAVIS_CHROOT/proc
sudo mount --bind /sys $ARCH_TRAVIS_CHROOT/sys
sudo mount --bind /dev $ARCH_TRAVIS_CHROOT/dev
sudo mount --bind /dev/pts $ARCH_TRAVIS_CHROOT/dev/pts
sudo mount --bind /dev/shm $ARCH_TRAVIS_CHROOT/dev/shm
sudo mount --bind /run $ARCH_TRAVIS_CHROOT/run
# update packages
chroot_as_root "pacman -Syy"
chroot_as_root "pacman -Syu ${default_packages[*]} --noconfirm"
# use LANG=en_US.UTF-8 as expected in travis environments
as_root "sed -i 's|#en_US.UTF-8|en_US.UTF-8|' $ARCH_TRAVIS_CHROOT/etc/locale.gen"
chroot_as_root "locale-gen"
# setup non-root user
chroot_as_root "useradd -u $user_uid -m -s /bin/bash $user"
# disable password for sudo users
as_root "echo \"$user ALL=(ALL) NOPASSWD: ALL\" >> $ARCH_TRAVIS_CHROOT/etc/sudoers.d/$user"
# Add build dir
chroot_as_root "mkdir $user_build_dir && chown $user $user_build_dir"
# bind $TRAVIS_BUILD_DIR to chroot build dir
sudo mount --bind $TRAVIS_BUILD_DIR $ARCH_TRAVIS_CHROOT$user_build_dir
# add custom repos
add_repositories
# setup pacaur for AUR packages
setup_pacaur
}
# add custom repositories to pacman.conf
add_repositories() {
if [ ${#CONFIG_REPOS[@]} -gt 0 ]; then
for r in "${CONFIG_REPOS[@]}"; do
local splitarr=(${r//=/ })
((repo_line+=1))
as_root "sed -i '${repo_line}i[${splitarr[0]}]' $ARCH_TRAVIS_CHROOT/etc/pacman.conf"
((repo_line+=1))
as_root "sed -i '${repo_line}iServer = ${splitarr[1]}\n' $ARCH_TRAVIS_CHROOT/etc/pacman.conf"
((repo_line+=1))
done
# update repos
chroot_as_root "pacman -Syy"
fi
}
# a wrapper which can be used to eventually add fakeroot support.
sudo_wrapper() {
sudo "$@"
}
# run command as normal user
as_normal() {
local str="$@"
run /bin/bash -c "$str"
}
# run command as root
as_root() {
local str="$@"
run sudo_wrapper /bin/bash -c "$str"
}
# run command in chroot as root
chroot_as_root() {
local str="$@"
run sudo_wrapper chroot $ARCH_TRAVIS_CHROOT /bin/bash -c "$str"
}
# run command in chroot as normal user
chroot_as_normal() {
local str="$@"
run sudo_wrapper chroot --userspec=$user:$user $ARCH_TRAVIS_CHROOT /bin/bash \
-c "export HOME=$user_home USER=$user TRAVIS_BUILD_DIR=$user_build_dir && cd $user_build_dir && $str"
}
# run command
run() {
"$@"
local ret=$?
if [ $ret -gt 0 ]; then
takedown_chroot
exit $ret
fi
}
# run build script
run_build_script() {
local cmd="$@"
echo "$ $cmd"
sudo_wrapper chroot --userspec=$user:$user $ARCH_TRAVIS_CHROOT /bin/bash -c "export HOME=$user_home USER=$user TRAVIS_BUILD_DIR=$user_build_dir && cd $user_build_dir && $cmd"
local ret=$?
if [ $ret -gt 0 ]; then
takedown_chroot
exit $ret
fi
}
# setup pacaur
setup_pacaur() {
local cowerarchive="cower.tar.gz"
local aururl="https://aur.archlinux.org/cgit/aur.git/snapshot/"
# install cower
as_normal "curl -O $aururl/$cowerarchive"
as_normal "tar xf $cowerarchive"
chroot_as_normal "cd cower && makepkg -is --skippgpcheck --noconfirm"
as_root "rm -r cower"
as_normal "rm $cowerarchive"
# install pacaur
chroot_as_normal "cower -dd pacaur"
chroot_as_normal "cd pacaur && makepkg -is --noconfirm"
chroot_as_normal "rm -rf pacaur"
}
# install package through pacaur
_pacaur() {
local pacaur="pacaur -S $@ --noconfirm --noedit"
chroot_as_normal "$pacaur"
}
# takedown chroot
# unmounts anything mounted in the chroot setup
takedown_chroot() {
sudo umount $ARCH_TRAVIS_CHROOT/{run,dev/shm,dev/pts,dev,sys,proc}
sudo umount $ARCH_TRAVIS_CHROOT$user_build_dir
sudo umount $ARCH_TRAVIS_CHROOT
if [ -n "$ARCH_TRAVIS_CLEAN_CHROOT" ]; then
as_root "rm -rf $ARCH_TRAVIS_CHROOT"
fi
}
# read value from .travis.yml
travis_yml() {
ruby -ryaml -e 'puts ARGV[1..-1].inject(YAML.load(File.read(ARGV[0]))) {|acc, key| acc[key] }' .travis.yml $@
}
read_config() {
old_ifs=$IFS
IFS=$'\n'
CONFIG_BUILD_SCRIPTS=($(travis_yml arch script))
CONFIG_PACKAGES=($(travis_yml arch packages))
CONFIG_REPOS=($(travis_yml arch repos))
IFS=$old_ifs
}
# run build scripts defined in .travis.yml
build_scripts() {
if [ ${#CONFIG_BUILD_SCRIPTS[@]} -gt 0 ]; then
for script in "${CONFIG_BUILD_SCRIPTS[@]}"; do
run_build_script $script
done
else
echo "No build scripts defined"
takedown_chroot
exit 1
fi
}
# install packages defined in .travis.yml
install_packages() {
for package in "${CONFIG_PACKAGES[@]}"; do
_pacaur $package
done
}
# install custom compiler if CC != gcc
install_c_compiler() {
if [ "$TRAVIS_CC" != "gcc" ]; then
_pacaur "$TRAVIS_CC"
fi
}
arch_msg() {
lightblue='\033[1;34m'
reset='\e[0m'
echo -e "${lightblue}$@${reset}"
}
# read .travis.yml
read_config
echo "travis_fold:start:arch_travis"
setup_chroot
install_packages
if [ -n "$CC" ]; then
install_c_compiler
# restore CC
CC=$TRAVIS_CC
fi
echo "travis_fold:end:arch_travis"
echo ""
arch_msg "Running travis build"
build_scripts
takedown_chroot
# vim:set ts=2 sw=2 et:

160
.travis/build.sh Executable file
View file

@ -0,0 +1,160 @@
#!/bin/bash
# Installs libs and compiles tdesktop
run() {
info_msg "Build version: ${BUILD_VERSION}"
downloadLibs
prepare
build
check
}
downloadLibs() {
travis_fold_start "download_libs"
# Move telegram project to subfolder
mkdir tdesktop
mv -f Telegram tdesktop
# Download libraries
info_msg "QT-Version: ${_qtver}, SRC-Dir: ${srcdir}"
echo -e "\nDownload and extract qt"
qt_file=qt-everywhere-opensource-src-$_qtver.tar.xz
echo -e "QT-File: ${qt_file}"
wget "http://download.qt.io/official_releases/qt/${_qtver%.*}/$_qtver/single/$qt_file"
tar xf $qt_file
rm $qt_file
echo -e "Clone Breakpad"
git clone https://chromium.googlesource.com/breakpad/breakpad breakpad
echo -e "\nClone Linux Syscall Support"
git clone https://chromium.googlesource.com/linux-syscall-support breakpad-lss
echo -e "\nLets view the folder content"
ls
travis_fold_end "download_libs"
}
prepare() {
travis_fold_start "prepare"
start_msg "Preparing the libraries..."
cd "$srcdir/tdesktop"
mkdir -p "$srcdir/Libraries"
local qt_patch_file="$srcdir/tdesktop/Telegram/_qtbase_${_qtver//./_}_patch.diff"
if [ "$qt_patch_file" -nt "$srcdir/Libraries/QtStatic" ]; then
rm -rf "$srcdir/Libraries/QtStatic"
mv "$srcdir/qt-everywhere-opensource-src-$_qtver" "$srcdir/Libraries/QtStatic"
cd "$srcdir/Libraries/QtStatic/qtbase"
patch -p1 -i "$qt_patch_file"
fi
if [ ! -h "$srcdir/Libraries/breakpad" ]; then
ln -s "$srcdir/breakpad" "$srcdir/Libraries/breakpad"
ln -s "$srcdir/breakpad-lss" "$srcdir/Libraries/breakpad/src/third_party/lss"
fi
sed -i 's/CUSTOM_API_ID//g' "$srcdir/tdesktop/Telegram/Telegram.pro"
sed -i 's,LIBS += /usr/local/lib/libxkbcommon.a,,g' "$srcdir/tdesktop/Telegram/Telegram.pro"
sed -i 's,LIBS += /usr/local/lib/libz.a,LIBS += -lz,g' "$srcdir/tdesktop/Telegram/Telegram.pro"
local options=""
if [[ $BUILD_VERSION == *"disable_autoupdate"* ]]; then
options+="\nDEFINES += TDESKTOP_DISABLE_AUTOUPDATE"
fi
if [[ $BUILD_VERSION == *"disable_register_custom_scheme"* ]]; then
options+="\nDEFINES += TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME"
fi
if [[ $BUILD_VERSION == *"disable_crash_reports"* ]]; then
options+="\nDEFINES += TDESKTOP_DISABLE_CRASH_REPORTS"
fi
if [[ $BUILD_VERSION == *"disable_network_proxy"* ]]; then
options+="\nDEFINES += TDESKTOP_DISABLE_NETWORK_PROXY"
fi
options+='\nINCLUDEPATH += "/usr/lib/glib-2.0/include"'
options+='\nINCLUDEPATH += "/usr/lib/gtk-2.0/include"'
options+='\nINCLUDEPATH += "/usr/include/opus"'
options+='\nLIBS += -lcrypto -lssl'
info_msg "Build options: ${options}"
echo -e "${options}" >> "$srcdir/tdesktop/Telegram/Telegram.pro"
success_msg "Prepare done! :)"
travis_fold_end "prepare"
}
build() {
start_msg "Building the projects..."
info_msg "Build patched Qt"
# Build patched Qt
cd "$srcdir/Libraries/QtStatic"
./configure -prefix "$srcdir/qt" -release -opensource -confirm-license -qt-zlib \
-qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre -qt-xcb \
-qt-xkbcommon-x11 -no-opengl -static -nomake examples -nomake tests
make --silent module-qtbase module-qtimageformats
make --silent module-qtbase-install_subtargets module-qtimageformats-install_subtargets
export PATH="$srcdir/qt/bin:$PATH"
info_msg "Build breakpad"
# Build breakpad
cd "$srcdir/Libraries/breakpad"
./configure
make --silent
info_msg "Build MetaStyle"
# Build MetaStyle
mkdir -p "$srcdir/tdesktop/Linux/DebugIntermediateStyle"
cd "$srcdir/tdesktop/Linux/DebugIntermediateStyle"
qmake CONFIG+=debug "../../Telegram/MetaStyle.pro"
make --silent
info_msg "Build MetaLang"
# Build MetaLang
mkdir -p "$srcdir/tdesktop/Linux/DebugIntermediateLang"
cd "$srcdir/tdesktop/Linux/DebugIntermediateLang"
qmake CONFIG+=debug "../../Telegram/MetaLang.pro"
make --silent
info_msg "Build Telegram Desktop"
# Build Telegram Desktop
mkdir -p "$srcdir/tdesktop/Linux/ReleaseIntermediate"
cd "$srcdir/tdesktop/Linux/ReleaseIntermediate"
qmake CONFIG+=release "../../Telegram/Telegram.pro"
local pattern="^PRE_TARGETDEPS +="
grep "$pattern" "$srcdir/tdesktop/Telegram/Telegram.pro" | sed "s/$pattern//g" | xargs make
qmake CONFIG+=release "../../Telegram/Telegram.pro"
make
}
check() {
local filePath="$srcdir/tdesktop/Linux/Release/Telegram"
if test -f "$filePath"; then
success_msg "Build successful done! :)"
local size;
size=$(stat -c %s "$filePath")
success_msg "File size of ${filePath}: ${size} Bytes"
else
error_msg "Build error, output file does not exist"
exit 1
fi
}
source ./.travis/common.sh
run

25
.travis/check.sh Executable file
View file

@ -0,0 +1,25 @@
#!/bin/bash
# Checks commit message, ...
run() {
checkCommitMessage
}
checkCommitMessage() {
info_msg "Commit message: ${TRAVIS_COMMIT_MSG}";
info_msg "Is pull request: ${TRAVIS_PULL_REQUEST}";
if [[ $TRAVIS_PULL_REQUEST != "false" ]];then
if [[ $TRAVIS_COMMIT_MSG != *"Signed-off-by: "* ]];then
error_msg "The commit message does not contain the signature!"
error_msg "More information: https://github.com/telegramdesktop/tdesktop/blob/master/.github/CONTRIBUTING.md#sign-your-work"
exit 1
else
success_msg "Commit message contains signature"
fi
fi
}
source ./.travis/common.sh
run

40
.travis/common.sh Executable file
View file

@ -0,0 +1,40 @@
# set colors
RCol='\e[0m' # Text Reset
# Regular Bold Underline High Intensity BoldHigh Intens Background High Intensity Backgrounds
Bla='\e[0;30m'; BBla='\e[1;30m'; UBla='\e[4;30m'; IBla='\e[0;90m'; BIBla='\e[1;90m'; On_Bla='\e[40m'; On_IBla='\e[0;100m';
Red='\e[0;31m'; BRed='\e[1;31m'; URed='\e[4;31m'; IRed='\e[0;91m'; BIRed='\e[1;91m'; On_Red='\e[41m'; On_IRed='\e[0;101m';
Gre='\e[0;32m'; BGre='\e[1;32m'; UGre='\e[4;32m'; IGre='\e[0;92m'; BIGre='\e[1;92m'; On_Gre='\e[42m'; On_IGre='\e[0;102m';
Yel='\e[0;33m'; BYel='\e[1;33m'; UYel='\e[4;33m'; IYel='\e[0;93m'; BIYel='\e[1;93m'; On_Yel='\e[43m'; On_IYel='\e[0;103m';
Blu='\e[0;34m'; BBlu='\e[1;34m'; UBlu='\e[4;34m'; IBlu='\e[0;94m'; BIBlu='\e[1;94m'; On_Blu='\e[44m'; On_IBlu='\e[0;104m';
Pur='\e[0;35m'; BPur='\e[1;35m'; UPur='\e[4;35m'; IPur='\e[0;95m'; BIPur='\e[1;95m'; On_Pur='\e[45m'; On_IPur='\e[0;105m';
Cya='\e[0;36m'; BCya='\e[1;36m'; UCya='\e[4;36m'; ICya='\e[0;96m'; BICya='\e[1;96m'; On_Cya='\e[46m'; On_ICya='\e[0;106m';
Whi='\e[0;37m'; BWhi='\e[1;37m'; UWhi='\e[4;37m'; IWhi='\e[0;97m'; BIWhi='\e[1;97m'; On_Whi='\e[47m'; On_IWhi='\e[0;107m';
# Set variables
_qtver=5.5.1
srcdir=${PWD}
start_msg() {
echo -e "\n${Gre}$*${RCol}"
}
info_msg() {
echo -e "\n${Cya}$*${RCol}"
}
error_msg() {
echo -e "\n${BRed}$*${RCol}"
}
success_msg() {
echo -e "\n${BGre}$*${RCol}"
}
travis_fold_start() {
echo "travis_fold:start:$*"
}
travis_fold_end() {
echo "travis_fold:end:$*"
}

View file

@ -2,14 +2,16 @@
This is the complete source code and the build instructions for the alpha version of the official desktop client for the [Telegram][telegram] messenger, based on the [Telegram API][telegram_api] and the [MTProto][telegram_proto] secure protocol.
[![Build Status](https://travis-ci.org/telegramdesktop/tdesktop.svg?branch=master)](https://travis-ci.org/telegramdesktop/tdesktop)
The source code is published under GPLv3 with OpenSSL exception, the license is available [here][license].
## Supported systems
* Windows XP - Windows 10 (**not** RT)
* Mac OS X 10.8 - Mac OS X 10.10
* Mac OS X 10.8 - Mac OS X 10.11
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
* Ubuntu 12.04 - Ubuntu 14.04
* Ubuntu 12.04 - Ubuntu 15.04
* Fedora 22
## Third-party libraries
@ -20,6 +22,8 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* libexif 0.6.20 ([LGPL](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html))
* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))
* liblzma ([public domain](http://tukaani.org/xz/))
* Google Breakpad ([License](https://chromium.googlesource.com/breakpad/breakpad/+/master/LICENSE))
* Google Crashpad ([Apache License 2.0](https://chromium.googlesource.com/crashpad/crashpad/+/master/LICENSE))
* OpenAL Soft ([LGPL](http://kcat.strangesoft.net/openal.html))
* Opus codec ([BSD license](http://www.opus-codec.org/license/))
* FFmpeg ([LGPL](https://www.ffmpeg.org/legal.html))
@ -31,6 +35,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* [XCode 7][xcode]
* [XCode 7 for OS X 10.6 and 10.7][xcode_old]
* [Qt Creator 3.5.1 Ubuntu][qtcreator]
* [Using qmake on GNU/Linux][qmake]
## Projects in Telegram solution
@ -46,21 +51,6 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
Compiles given files to single update file, compresses it with lzma and signs with a private key. It is not built in **Debug** and **Release** configurations of Telegram solution, because private key is inaccessible.
* ### Prepare
Prepares a release for deployment, puts all current files to deploy/{version} folder.
**Windows**:
* tsetup{version}.exe installer
* Telegram.exe
* Telegram.pdb (debug info for crash minidumps view)
* tupdate{updversion} binary lzma update archive
**Mac**:
* tsetup{version}.dmg
* Telegram.app
* tmacupd{updversion} binary lzma update archive
* ### MetaEmoji
Creates four sprites and text2emoji replace code
@ -92,7 +82,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* ### MetaLang
Creates from languagepack file `Resources/lang.txt` language constants code and language file parse code:
Creates from languagepack file `Resources/lang.strings` language constants code and language file parse code:
* GeneratedFiles/lang.h
* GeneratedFiles/lang.cpp
@ -102,7 +92,8 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
[telegram_api]: https://core.telegram.org
[telegram_proto]: https://core.telegram.org/mtproto
[license]: LICENSE
[msvc]: MSVC.md
[xcode]: XCODE.md
[xcode_old]: XCODEold.md
[qtcreator]: QTCREATOR.md
[msvc]: doc/building-msvc.md
[xcode]: doc/building-xcode.md
[xcode_old]: doc/building-xcode-old.md
[qtcreator]: doc/building-qtcreator.md
[qmake]: doc/building-qmake.md

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
ProjectSection(ProjectDependencies) = postProject
@ -18,10 +18,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Telegram\Updater
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F863EAD-33C9-4014-A573-93F085BA9CB1}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "codegen", "codegen", "{2F863EAD-33C9-4014-A573-93F085BA9CB1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Telegram\Packer.vcxproj", "{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "codegen_style", "Telegram\build\vc\codegen_style\codegen_style.vcxproj", "{E4DF8176-4DEF-4859-962F-B497E3E7A323}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -82,8 +84,21 @@ Global
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Deploy|x64.ActiveCfg = Release|Win32
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|Win32.ActiveCfg = Release|Win32
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|x64.ActiveCfg = Release|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|Win32.ActiveCfg = Debug|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|Win32.Build.0 = Debug|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|x64.ActiveCfg = Debug|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|Win32.ActiveCfg = Debug|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|Win32.Build.0 = Debug|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|x64.ActiveCfg = Release|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|x64.Build.0 = Release|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|Win32.ActiveCfg = Release|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|Win32.Build.0 = Release|Win32
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E4DF8176-4DEF-4859-962F-B497E3E7A323} = {2F863EAD-33C9-4014-A573-93F085BA9CB1}
EndGlobalSection
EndGlobal

View file

@ -1,4 +1,5 @@
@echo OFF
setlocal
FOR /F "tokens=1,2* delims= " %%i in (Version) do set "%%i=%%j"
@ -29,6 +30,8 @@ set "HomePath=..\..\Telegram"
set "ReleasePath=..\Win32\Deploy"
set "DeployPath=%ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStrFull%"
set "SignPath=..\..\TelegramPrivate\Sign.bat"
set "BinaryName=Telegram"
set "DropboxSymbolsPath=Z:\Dropbox\Telegram\symbols"
if %BetaVersion% neq 0 (
if exist %DeployPath%\ (
@ -71,9 +74,13 @@ echo .
echo Version %AppVersionStrFull% build successfull. Preparing..
echo .
echo Dumping debug symbols..
call ..\..\Libraries\breakpad\src\tools\windows\binaries\dump_syms.exe %ReleasePath%\%BinaryName%.pdb > %ReleasePath%\%BinaryName%.sym
echo Done!
set "PATH=%PATH%;C:\Program Files\7-Zip;C:\Program Files (x86)\Inno Setup 5"
call %SignPath% %ReleasePath%\Telegram.exe
call %SignPath% %ReleasePath%\%BinaryName%.exe
if %errorlevel% neq 0 goto error
call %SignPath% %ReleasePath%\Updater.exe
@ -90,7 +97,7 @@ if %BetaVersion% equ 0 (
)
cd %ReleasePath%
call Packer.exe -version %VersionForPacker% -path Telegram.exe -path Updater.exe %DevParam%
call Packer.exe -version %VersionForPacker% -path %BinaryName%.exe -path Updater.exe %DevParam%
cd %HomePath%
if %errorlevel% neq 0 goto error
@ -109,6 +116,21 @@ if %BetaVersion% neq 0 (
set "PortableFile=tbeta%BetaVersion%_%BetaSignature%.zip"
)
for /f ^"usebackq^ eol^=^
^ delims^=^" %%a in (%ReleasePath%\%BinaryName%.sym) do (
set "SymbolsHashLine=%%a"
goto symbolslinedone
)
:symbolslinedone
FOR /F "tokens=1,2,3,4* delims= " %%i in ("%SymbolsHashLine%") do set "SymbolsHash=%%l"
echo Copying %BinaryName%.sym to %DropboxSymbolsPath%\%BinaryName%.pdb\%SymbolsHash%
if not exist %DropboxSymbolsPath%\%BinaryName%.pdb mkdir %DropboxSymbolsPath%\%BinaryName%.pdb
if not exist %DropboxSymbolsPath%\%BinaryName%.pdb\%SymbolsHash% mkdir %DropboxSymbolsPath%\%BinaryName%.pdb\%SymbolsHash%
xcopy %ReleasePath%\%BinaryName%.sym %DropboxSymbolsPath%\%BinaryName%.pdb\%SymbolsHash%\
echo Done!
if not exist %ReleasePath%\deploy mkdir %ReleasePath%\deploy
if not exist %ReleasePath%\deploy\%AppVersionStrMajor% mkdir %ReleasePath%\deploy\%AppVersionStrMajor%
mkdir %DeployPath%
@ -144,7 +166,7 @@ if not exist %DeployPath%\%PortableFile% goto error
if %BetaVersion% equ 0 (
if not exist %DeployPath%\%SetupFile% goto error
)
if not exist %DeployPath%\Telegram.pdb goto error
if not exist %DeployPath%\%BinaryName%.pdb goto error
if not exist %DeployPath%\Updater.exe goto error
if not exist %DeployPath%\Updater.pdb goto error
if not exist %FinalReleasePath%\%AppVersionStrMajor% mkdir %FinalReleasePath%\%AppVersionStrMajor%
@ -157,7 +179,7 @@ if %BetaVersion% equ 0 (
) else (
xcopy %DeployPath%\%BetaKeyFile% %FinalDeployPath%\ /Y
)
xcopy %DeployPath%\Telegram.pdb %FinalDeployPath%\
xcopy %DeployPath%\%BinaryName%.pdb %FinalDeployPath%\
xcopy %DeployPath%\Updater.exe %FinalDeployPath%\
xcopy %DeployPath%\Updater.pdb %FinalDeployPath%\

View file

@ -1,5 +1,7 @@
set -e
FastParam="$1"
while IFS='' read -r line || [[ -n "$line" ]]; do
set $line
eval $1="$2"
@ -37,6 +39,7 @@ if [ "$BuildTarget" == "linux" ]; then
WorkPath="./../Linux"
FixScript="$HomePath/FixMake.sh"
ReleasePath="./../Linux/Release"
BinaryName="Telegram"
elif [ "$BuildTarget" == "linux32" ]; then
echo "Building version $AppVersionStrFull for Linux 32bit.."
UpdateFile="tlinux32upd$AppVersion"
@ -44,6 +47,7 @@ elif [ "$BuildTarget" == "linux32" ]; then
WorkPath="./../Linux"
FixScript="$HomePath/FixMake32.sh"
ReleasePath="./../Linux/Release"
BinaryName="Telegram"
elif [ "$BuildTarget" == "mac" ]; then
echo "Building version $AppVersionStrFull for OS X 10.8+.."
UpdateFile="tmacupd$AppVersion"
@ -104,22 +108,25 @@ fi
#fi
if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
DropboxSymbolsPath="/media/psf/Home/Dropbox/Telegram/symbols"
mkdir -p "$WorkPath/ReleaseIntermediateUpdater"
cd "$WorkPath/ReleaseIntermediateUpdater"
/usr/local/Qt-5.5.1/bin/qmake "$HomePath/Updater.pro"
/usr/local/Qt-5.5.1/bin/qmake "$HomePath/Updater.pro" -r -spec linux-g++
make
echo "Updater build complete!"
cd "$HomePath"
mkdir -p "$WorkPath/ReleaseIntermediate"
cd "$WorkPath/ReleaseIntermediate"
/usr/local/Qt-5.5.1/bin/qmake "$HomePath/Telegram.pro"
/usr/local/Qt-5.5.1/bin/qmake "$HomePath/Telegram.pro" -r -spec linux-g++
eval "$FixScript"
make
echo "Telegram build complete!"
echo "$BinaryName build complete!"
cd "$HomePath"
if [ ! -f "$ReleasePath/Telegram" ]; then
echo "Telegram not found!"
if [ ! -f "$ReleasePath/$BinaryName" ]; then
echo "$BinaryName not found!"
exit 1
fi
@ -128,8 +135,16 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
exit 1
fi
echo "Dumping debug symbols.."
"./../../Libraries/breakpad/src/tools/linux/dump_syms/dump_syms" "$ReleasePath/$BinaryName" > "$ReleasePath/$BinaryName.sym"
echo "Done!"
echo "Stripping the executable.."
strip -s "$ReleasePath/$BinaryName"
echo "Done!"
echo "Preparing version $AppVersionStrFull, executing Packer.."
cd "$ReleasePath" && "./Packer" -path Telegram -path Updater -version $VersionForPacker $DevParam && cd "$HomePath"
cd "$ReleasePath" && "./Packer" -path "$BinaryName" -path Updater -version $VersionForPacker $DevParam && cd "$HomePath"
echo "Packer done!"
if [ "$BetaVersion" != "0" ]; then
@ -146,6 +161,12 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
SetupFile="tbeta${BetaVersion}_${BetaSignature}.tar.xz"
fi
SymbolsHash=`head -n 1 "$ReleasePath/$BinaryName.sym" | awk -F " " 'END {print $4}'`
echo "Copying $BinaryName.sym to $DropboxSymbolsPath/$BinaryName/$SymbolsHash"
mkdir -p "$DropboxSymbolsPath/$BinaryName/$SymbolsHash"
cp "$ReleasePath/$BinaryName.sym" "$DropboxSymbolsPath/$BinaryName/$SymbolsHash/"
echo "Done!"
if [ ! -d "$ReleasePath/deploy" ]; then
mkdir "$ReleasePath/deploy"
fi
@ -154,21 +175,25 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
mkdir "$ReleasePath/deploy/$AppVersionStrMajor"
fi
echo "Copying Telegram, Updater and $UpdateFile to deploy/$AppVersionStrMajor/$AppVersionStrFull..";
echo "Copying $BinaryName, Updater and $UpdateFile to deploy/$AppVersionStrMajor/$AppVersionStrFull..";
mkdir "$DeployPath"
mkdir "$DeployPath/Telegram"
mv "$ReleasePath/Telegram" "$DeployPath/Telegram/"
mv "$ReleasePath/Updater" "$DeployPath/Telegram/"
mkdir "$DeployPath/$BinaryName"
mv "$ReleasePath/$BinaryName" "$DeployPath/$BinaryName/"
mv "$ReleasePath/Updater" "$DeployPath/$BinaryName/"
mv "$ReleasePath/$UpdateFile" "$DeployPath/"
if [ "$BetaVersion" != "0" ]; then
mv "$ReleasePath/$BetaKeyFile" "$DeployPath/"
fi
cd "$DeployPath" && tar -cJvf "$SetupFile" "Telegram/" && cd "./../../../$HomePath"
cd "$DeployPath" && tar -cJvf "$SetupFile" "$BinaryName/" && cd "./../../../$HomePath"
fi
if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarget" == "macstore" ]; then
touch "./SourceFiles/telegram.qrc"
DropboxSymbolsPath="./../../../Dropbox/Telegram/symbols"
if [ "$FastParam" != "fast" ]; then
touch "./SourceFiles/telegram.qrc"
fi
xcodebuild -project Telegram.xcodeproj -alltargets -configuration Release build
if [ ! -d "$ReleasePath/$BinaryName.app" ]; then
@ -181,6 +206,28 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
exit 1
fi
if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ]; then
echo "Removing Updater debug symbols.."
rm -rf "$ReleasePath/$BinaryName.app/Contents/Frameworks/Updater.dSYM"
echo "Done!"
fi
echo "Dumping debug symbols.."
"./../../Libraries/breakpad/src/tools/mac/dump_syms/build/Release/dump_syms" "$ReleasePath/$BinaryName.app.dSYM" > "$ReleasePath/$BinaryName.sym" 2>/dev/null
echo "Done!"
echo "Stripping the executable.."
strip "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName"
echo "Done!"
echo "Signing the application.."
if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ]; then
codesign --force --deep --sign "Developer ID Application: John Preston" "$ReleasePath/$BinaryName.app"
elif [ "$BuildTarget" == "macstore" ]; then
codesign --force --deep --sign "3rd Party Mac Developer Application: TELEGRAM MESSENGER LLP (6N38VWS5BX)" "$ReleasePath/$BinaryName.app" --entitlements "Telegram/Telegram Desktop.entitlements"
fi
echo "Done!"
AppUUID=`dwarfdump -u "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName" | awk -F " " '{print $2}'`
DsymUUID=`dwarfdump -u "$ReleasePath/$BinaryName.app.dSYM" | awk -F " " '{print $2}'`
if [ "$AppUUID" != "$DsymUUID" ]; then
@ -215,6 +262,12 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
fi
fi
SymbolsHash=`head -n 1 "$ReleasePath/$BinaryName.sym" | awk -F " " 'END {print $4}'`
echo "Copying $BinaryName.sym to $DropboxSymbolsPath/$BinaryName/$SymbolsHash"
mkdir -p "$DropboxSymbolsPath/$BinaryName/$SymbolsHash"
cp "$ReleasePath/$BinaryName.sym" "$DropboxSymbolsPath/$BinaryName/$SymbolsHash/"
echo "Done!"
if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ]; then
if [ "$BetaVersion" == "0" ]; then
cd "$ReleasePath"
@ -254,10 +307,10 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ]; then
echo "Copying $BinaryName.app and $UpdateFile to deploy/$AppVersionStrMajor/$AppVersionStr..";
mkdir "$DeployPath"
mkdir "$DeployPath/Telegram"
cp -r "$ReleasePath/$BinaryName.app" "$DeployPath/Telegram/"
mkdir "$DeployPath/$BinaryName"
cp -r "$ReleasePath/$BinaryName.app" "$DeployPath/$BinaryName/"
if [ "$BetaVersion" != "0" ]; then
cd "$DeployPath" && zip -r "$SetupFile" "Telegram" && mv "$SetupFile" "./../../../" && cd "./../../../$HomePath"
cd "$DeployPath" && zip -r "$SetupFile" "$BinaryName" && mv "$SetupFile" "./../../../" && cd "./../../../$HomePath"
mv "$ReleasePath/$BetaKeyFile" "$DeployPath/"
fi
mv "$ReleasePath/$BinaryName.app.dSYM" "$DeployPath/"
@ -294,6 +347,7 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
rm "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName"
rm -rf "$ReleasePath/$BinaryName.app/Contents/_CodeSignature"
mkdir -p "$DropboxDeployPath"
cp -v "$DeployPath/$BinaryName.app" "$DropboxDeployPath/"
cp -rv "$DeployPath/$BinaryName.app.dSYM" "$DropboxDeployPath/"
fi

View file

@ -57,7 +57,11 @@ elif [ "$BuildTarget" == "mac" ]; then
echo "Deploying version $AppVersionStrFull for Windows.."
else
DeployMac="1"
DeployMac32="1"
if [ "$BetaVersion" != "0" ]; then
DeployMac32="0"
else
DeployMac32="1"
fi
DeployWin="1"
echo "Deploying three versions of $AppVersionStrFull: for Windows, OS X 10.6 and 10.7 and OS X 10.8+.."
fi
@ -165,13 +169,7 @@ fi
fi
fi
if [ ! -d "$DropboxPath" ]; then
mkdir "$DropboxPath"
fi
if [ ! -d "$DropboxDeployPath" ]; then
mkdir "$DropboxDeployPath"
fi
mkdir -p "$DropboxDeployPath"
fi
#fi
@ -194,7 +192,6 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ] || [ "$Build
fi
if [ "$DeployMac" == "1" ]; then
cp -v "$DeployPath/$UpdateFile" "$DropboxDeployPath/"
cp -v "$DeployPath/$SetupFile" "$DropboxDeployPath/$DropboxSetupFile"
if [ -d "$DropboxDeployPath/Telegram.app.dSYM" ]; then
rm -rf "$DropboxDeployPath/Telegram.app.dSYM"
@ -202,7 +199,6 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ] || [ "$Build
cp -rv "$DeployPath/Telegram.app.dSYM" "$DropboxDeployPath/"
fi
if [ "$DeployMac32" == "1" ]; then
mv -v "$Mac32DeployPath/$Mac32UpdateFile" "$DropboxDeployPath/"
mv -v "$Mac32DeployPath/$Mac32SetupFile" "$DropboxDeployPath/$DropboxMac32SetupFile"
if [ -d "$DropboxDeployPath/Telegram32.app.dSYM" ]; then
rm -rf "$DropboxDeployPath/Telegram32.app.dSYM"
@ -213,7 +209,6 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ] || [ "$Build
mv -v "$WinDeployPath/Telegram.pdb" "$DropboxDeployPath/"
mv -v "$WinDeployPath/Updater.exe" "$DropboxDeployPath/"
mv -v "$WinDeployPath/Updater.pdb" "$DropboxDeployPath/"
mv -v "$WinDeployPath/$WinUpdateFile" "$DropboxDeployPath/"
if [ "$BetaVersion" == "0" ]; then
mv -v "$WinDeployPath/$WinSetupFile" "$DropboxDeployPath/"
fi

View file

@ -11,12 +11,7 @@ Replace () {
}
Replace '\-llzma' '\/usr\/lib\/x86_64\-linux\-gnu\/liblzma\.a'
Replace '\-lz' '\/usr\/lib\/x86_64\-linux\-gnu\/libz\.a'
Replace '\-lssl' '\/usr\/lib\/x86_64\-linux\-gnu\/libssl\.a'
Replace '\-lcrypto' '\/usr\/lib\/x86_64\-linux\-gnu\/libcrypto\.a'
Replace '\-lexif' '\/usr\/lib\/x86_64\-linux\-gnu\/libexif\.a'
Replace '\-lgobject\-2\.0' '\/usr\/lib\/x86_64\-linux\-gnu\/libgobject\-2\.0\.a \/usr\/lib\/x86_64\-linux\-gnu\/libffi\.a'
Replace '\-lXi' '\/usr\/lib\/x86_64\-linux\-gnu\/libXi\.a'
Replace '\-lXi' '\/usr\/lib\/x86_64\-linux\-gnu\/libXi\.a \/usr\/lib\/x86_64\-linux\-gnu\/libXext\.a'
Replace '\-lSM' '\/usr\/lib\/x86_64\-linux\-gnu\/libSM\.a'
Replace '\-lICE' '\/usr\/lib\/x86_64\-linux\-gnu\/libICE\.a'
Replace '\-lfontconfig' '\/usr\/lib\/x86_64\-linux\-gnu\/libfontconfig\.a \/usr\/lib\/x86_64\-linux\-gnu\/libexpat\.a'
@ -30,3 +25,4 @@ Replace '\-lswresample' '\/usr\/local\/lib\/libswresample\.a'
Replace '\-lswscale' '\/usr\/local\/lib\/libswscale\.a'
Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a'
Replace '\-lva' '\/usr\/local\/lib\/libva\.a'
Replace '\-lQt5Network' '\/usr\/local\/Qt-5.5.1\/lib\/libQt5Network.a \/usr\/local\/ssl\/lib\/libssl.a \/usr\/local\/ssl\/lib\/libcrypto.a'

View file

@ -11,12 +11,7 @@ Replace () {
}
Replace '\-llzma' '\/usr\/lib\/i386\-linux\-gnu\/liblzma\.a'
Replace '\-lz' '\/usr\/lib\/i386\-linux\-gnu\/libz\.a'
Replace '\-lssl' '\/usr\/lib\/i386\-linux\-gnu\/libssl\.a'
Replace '\-lcrypto' '\/usr\/lib\/i386\-linux\-gnu\/libcrypto\.a'
Replace '\-lexif' '\/usr\/lib\/i386\-linux\-gnu\/libexif\.a'
Replace '\-lgobject\-2\.0' '\/usr\/lib\/i386\-linux\-gnu\/libgobject\-2\.0\.a \/usr\/lib\/i386\-linux\-gnu\/libffi\.a'
Replace '\-lXi' '\/usr\/lib\/i386\-linux\-gnu\/libXi\.a'
Replace '\-lXi' '\/usr\/lib\/i386\-linux\-gnu\/libXi\.a \/usr\/lib\/i386\-linux\-gnu\/libXext\.a'
Replace '\-lSM' '\/usr\/lib\/i386\-linux\-gnu\/libSM\.a'
Replace '\-lICE' '\/usr\/lib\/i386\-linux\-gnu\/libICE\.a'
Replace '\-lfontconfig' '\/usr\/lib\/i386\-linux\-gnu\/libfontconfig\.a \/usr\/lib\/i386\-linux\-gnu\/libexpat\.a'
@ -30,3 +25,4 @@ Replace '\-lswresample' '\/usr\/local\/lib\/libswresample\.a'
Replace '\-lswscale' '\/usr\/local\/lib\/libswscale\.a'
Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a'
Replace '\-lva' '\/usr\/local\/lib\/libva\.a'
Replace '\-lQt5Network' '\/usr\/local\/Qt-5.5.1\/lib\/libQt5Network.a \/usr\/local\/ssl\/lib\/libssl.a \/usr\/local\/ssl\/lib\/libcrypto.a'

View file

@ -12,7 +12,7 @@ CONFIG(release, debug|release) {
DESTDIR = ./../ReleaseLang
}
CONFIG += plugin static
CONFIG += plugin static c++11
macx {
QMAKE_INFO_PLIST = ./SourceFiles/_other/Lang.plist

View file

@ -12,7 +12,7 @@ CONFIG(release, debug|release) {
DESTDIR = ./../ReleaseStyle
}
CONFIG += plugin static
CONFIG += plugin static c++11
macx {
QMAKE_INFO_PLIST = ./SourceFiles/_other/Style.plist

View file

@ -0,0 +1 @@
de,es,it,ko,nl,pt_BR

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
"lng_language_name" = "English";
"lng_switch_to_this" = "Switch to English";
@ -86,8 +86,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_cancel" = "Cancel";
"lng_continue" = "Continue";
"lng_close" = "Close";
"lng_connecting" = "Connecting..";
"lng_reconnecting" = "Reconnect {count:now|in # s|in # s}..";
"lng_connecting" = "Connecting...";
"lng_reconnecting" = "Reconnect {count:now|in # s|in # s}...";
"lng_reconnecting_try_now" = "Try now";
"lng_status_service_notifications" = "service notifications";
@ -108,7 +108,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_status_lastseen_date" = "last seen {date}";
"lng_status_lastseen_date_time" = "last seen {date} at {time}";
"lng_status_online" = "online";
"lng_status_connecting" = "connecting..";
"lng_status_connecting" = "connecting...";
"lng_chat_status_unaccessible" = "group is unaccessible";
"lng_chat_status_members" = "{count:no members|# member|# members}";
@ -123,8 +123,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_server_error" = "Internal server error.";
"lng_flood_error" = "Too many tries. Please try again later.";
"lng_gif_error" = "An error has occured while reading GIF animation :(";
"lng_edit_error" = "You cannot edit this message";
"lng_edit_deleted" = "This message was deleted";
"lng_edit_too_long" = "Your message text is too long";
"lng_edit_message" = "Edit message";
"lng_edit_message_text" = "New message text...";
"lng_deleted" = "Unknown";
"lng_deleted_message" = "Deleted message";
"lng_pinned_message" = "Pinned message";
"lng_pinned_unpin_sure" = "Would you like to unpin this message?";
"lng_pinned_pin_sure" = "Would you like to pin this message?";
"lng_pinned_pin" = "Pin";
"lng_pinned_unpin" = "Unpin";
"lng_pinned_notify" = "Notify all members";
"lng_intro" = "Welcome to the official [a href=\"https://telegram.org/\"]Telegram[/a] desktop app.\nIt's [b]fast[/b] and [b]secure[/b].";
"lng_start_msgs" = "START MESSAGING";
@ -151,7 +162,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_code_telegram" = "Please enter the code you've just\nreceived in your previous [b]Telegram[/b] app.";
"lng_code_no_telegram" = "Send code via SMS";
"lng_code_call" = "Telegram will dial your number in {minutes}:{seconds}";
"lng_code_calling" = "Requesting a call from Telegram..";
"lng_code_calling" = "Requesting a call from Telegram...";
"lng_code_called" = "Telegram dialed your number";
"lng_bad_phone" = "Invalid phone number. Please try again.";
@ -190,7 +201,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_dlg_new_channel_name" = "Channel name";
"lng_no_contacts" = "You have no contacts";
"lng_no_chats" = "Your chats will be here";
"lng_contacts_loading" = "Loading..";
"lng_contacts_loading" = "Loading...";
"lng_contacts_not_found" = "No contacts found";
"lng_dlg_search_chat" = "Search in this chat";
"lng_dlg_search_channel" = "Search in this channel";
@ -199,7 +210,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_settings_save" = "Save";
"lng_settings_upload" = "Set Profile Photo";
"lng_settings_crop_profile" = "Select a square area for your profile photo";
"lng_settings_uploading_photo" = "Uploading photo..";
"lng_settings_uploading_photo" = "Uploading photo...";
"lng_username_title" = "Username";
"lng_username_about" = "You can choose a username on Telegram.\nIf you do, other people will be able to find\nyou by this username and contact you\nwithout knowing your phone number.\n\nYou can use a-z, 0-9 and underscores.\nMinimum length is 5 characters.";
@ -236,9 +247,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_settings_auto_update" = "Update automatically";
"lng_settings_current_version" = "Version {version}";
"lng_settings_check_now" = "Check for updates";
"lng_settings_update_checking" = "Checking for updates..";
"lng_settings_update_checking" = "Checking for updates...";
"lng_settings_latest_installed" = "Latest version is installed";
"lng_settings_downloading" = "Downloading update {ready} / {total} MB..";
"lng_settings_downloading" = "Downloading update {ready} / {total} MB...";
"lng_settings_update_ready" = "New version is ready";
"lng_settings_update_now" = "Restart Now";
"lng_settings_update_fail" = "Update check failed :(";
@ -262,6 +273,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_settings_bg_from_gallery" = "Choose from gallery";
"lng_settings_bg_from_file" = "Choose from file";
"lng_settings_bg_tile" = "Tile background";
"lng_settings_adaptive_wide" = "Adaptive layout for wide screens";
"lng_backgrounds_header" = "Choose your new chat background";
@ -279,7 +291,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_download_path_failed" = "File download could not be started. It could happen because of a bad download location.\n\nYou can change download path in Settings.";
"lng_download_path_settings" = "Settings";
"lng_download_finish_failed" = "File download could not be finished.\n\nWould you like to try again?";
"lng_download_path_clearing" = "Clearing..";
"lng_download_path_clearing" = "Clearing...";
"lng_download_path_cleared" = "Cleared!";
"lng_download_path_clear_failed" = "Clear failed :(";
@ -288,7 +300,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_settings_images_cached" = "{count:_not_used_|# image|# images}, {size}";
"lng_settings_audios_cached" = "{count:_not_used_|# voice message|# voice messages}, {size}";
"lng_local_storage_clear" = "Clear all";
"lng_local_storage_clearing" = "Clearing..";
"lng_local_storage_clearing" = "Clearing...";
"lng_local_storage_cleared" = "Cleared!";
"lng_local_storage_clear_failed" = "Clear failed :(";
@ -319,7 +331,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_passcode_logout" = "Log out";
"lng_passcode_need_unblock" = "You need to unlock me first.";
"lng_cloud_password_waiting" = "Confirmation link sent to {email}..";
"lng_cloud_password_waiting" = "Confirmation link sent to {email}...";
"lng_cloud_password_change" = "Change cloud password";
"lng_cloud_password_create" = "Cloud password";
"lng_cloud_password_remove" = "Remove cloud password";
@ -346,9 +358,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_cloud_password_is_same" = "Password was not changed";
"lng_connection_type" = "Connection type:";
"lng_connection_auto_connecting" = "Default (connecting..)";
"lng_connection_auto_connecting" = "Default (connecting...)";
"lng_connection_auto" = "Default ({transport} used)";
"lng_connection_proxy_connecting" = "Connecting through proxy..";
"lng_connection_proxy_connecting" = "Connecting through proxy...";
"lng_connection_proxy" = "{transport} with proxy";
"lng_connection_header" = "Connection type";
"lng_connection_auto_rb" = "Auto (TCP if available or HTTP)";
@ -384,7 +396,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_sessions_other_desc" = "You can log in to Telegram from other mobile, tablet and desktop devices, using the same phone number. All your data will be instantly synchronized.";
"lng_sessions_terminate_all" = "Terminate all other sessions";
"lng_preview_loading" = "Getting Link Info..";
"lng_preview_loading" = "Getting Link Info...";
"lng_profile_chat_unaccessible" = "Group is unaccessible";
"lng_topbar_info" = "Info";
@ -423,10 +435,11 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_profile_add_participant" = "Add Members";
"lng_profile_delete_and_exit" = "Leave";
"lng_profile_kick" = "Remove";
"lng_profile_admin" = "admin";
"lng_profile_sure_kick" = "Remove {user} from the group?";
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
"lng_profile_sure_kick_admin" = "Remove {user} from administrators?";
"lng_profile_loading" = "Loading..";
"lng_profile_loading" = "Loading...";
"lng_profile_shared_media" = "Shared media";
"lng_profile_no_media" = "No media in this conversation.";
"lng_profile_photos" = "{count:_not_used_|# photo|# photos} »";
@ -442,6 +455,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_profile_shared_links" = "{count:_not_used_|# shared link|# shared links} »";
"lng_profile_shared_links_header" = "Shared links overview";
"lng_profile_copy_phone" = "Copy phone number";
"lng_profile_copy_fullname" = "Copy name";
"lng_channel_add_admins" = "New administrator";
"lng_channel_add_members" = "Add members";
@ -463,13 +477,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_create_group_next" = "Next";
"lng_create_group_create" = "Create";
"lng_create_group_title" = "New Group";
"lng_create_group_about" = "Groups are ideal for smaller communities,\nthey can have up to {count:_not_used|# member|# members}";
"lng_create_group_about" = "Groups are ideal for limited communities,\nthey can have up to {count:_not_used|# member|# members}";
"lng_create_channel_title" = "New Channel";
"lng_create_channel_about" = "Channels are a tool for broadcasting your messages to unlimited audiences";
"lng_create_public_channel_title" = "Public Channel";
"lng_create_public_channel_about" = "Anyone can find the channel in search and join";
"lng_create_private_channel_title" = "Private Channel";
"lng_create_private_channel_about" = "Only people with a special invite link may join";
"lng_create_public_group_title" = "Public Group";
"lng_create_public_group_about" = "Anyone can find the group in search and join, chat history is available to everybody";
"lng_create_private_group_title" = "Private Group";
"lng_create_private_group_about" = "People can only join if they were invited or have an invite link";
"lng_create_channel_comments" = "Enable Comments";
"lng_create_channel_comments_about" = "If you enable comments, members will be able to discuss your posts in the channel";
"lng_create_group_skip" = "Skip";
@ -498,7 +516,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_sure_delete_group" = "Are you sure, you want to delete this group? All members will be removed and all messages will be lost.";
"lng_message_empty" = "Empty Message";
"lng_media_unsupported" = "Media Unsupported";
"lng_message_unsupported" = "This message is not supported by your version of Telegram Desktop. Please update to the last version in Settings or install it from {link}";
"lng_action_add_user" = "{from} added {user}";
"lng_action_add_users_many" = "{from} added {users}";
@ -522,6 +540,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_action_created_chat" = "{from} created group «{title}»";
"lng_action_created_channel" = "Channel «{title}» created";
"lng_action_group_migrate" = "The group was upgraded to a supergroup";
"lng_action_pinned_message" = "{from} pinned «{text}»";
"lng_action_pinned_media" = "{from} pinned {media}";
"lng_action_pinned_media_photo" = "a photo";
"lng_action_pinned_media_video" = "a video file";
"lng_action_pinned_media_audio" = "an audio file";
"lng_action_pinned_media_voice" = "a voice message";
"lng_action_pinned_media_file" = "a file";
"lng_action_pinned_media_gif" = "a GIF animation";
"lng_action_pinned_media_contact" = "a contact information";
"lng_action_pinned_media_location" = "a location mark";
"lng_action_pinned_media_sticker" = "a sticker";
"lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached";
"lng_profile_migrate_about" = "If you'd like to go over this limit, you can upgrade your group to a supergroup. In supergroups:";
@ -531,6 +560,16 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_profile_migrate_feature4" = "— Notifications are muted by default";
"lng_profile_migrate_button" = "Upgrade to supergroup";
"lng_profile_migrate_sure" = "Are you sure you want to upgrade this group to supergroup? This action cannot be undone.";
"lng_profile_convert_button" = "Convert to supergroup";
"lng_profile_convert_title" = "Convert to supergroup";
"lng_profile_convert_about" = "In supergroups:";
"lng_profile_convert_feature1" = "— New members see the full message history";
"lng_profile_convert_feature2" = "— Messages are deleted for all members";
"lng_profile_convert_feature3" = "— Members can edit their own messages";
"lng_profile_convert_feature4" = "— Creator can set a public link for the group";
"lng_profile_convert_warning" = "{bold_start}Note:{bold_end} This action can not be undone";
"lng_profile_convert_confirm" = "Convert";
"lng_profile_add_more_after_upgrade" = "You will be able to add up to {count:_not_used_|# member|# members} after you upgrade your group to a supergroup.";
"lng_channel_comments_count" = "{count:_not_used_|# comment|# comments}";
"lng_channel_hide_comments" = "Hide comments";
@ -555,9 +594,18 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_channel_public_link_copied" = "Link copied to clipboard.";
"lng_forwarded_from" = "Forwarded from";
"lng_forwarded" = "Forwarded from {user}";
"lng_forwarded_channel" = "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})";
"lng_in_reply_to" = "In reply to";
"lng_bot_share_location_unavailable" = "Sorry, the location sharing is currently unavailable in Telegram Desktop.";
"lng_bot_inline_geo_unavailable" = "Sorry, this bot requires location sharing.\nIt is not unavailable in Telegram Desktop.";
"lng_bot_share_phone" = "Share Phone Number?";
"lng_bot_share_phone_confirm" = "Share";
"lng_attach_failed" = "Failed";
"lng_attach_file" = "File";
"lng_attach_photo" = "Photo";
@ -600,6 +648,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_saved_gifs" = "Saved GIFs";
"lng_inline_bot_results" = "Results from {inline_bot}";
"lng_inline_bot_no_results" = "No results";
"lng_inline_bot_via" = "via {inline_bot}";
"lng_box_remove" = "Remove";
@ -616,16 +665,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_stickers_remove" = "Delete";
"lng_stickers_return" = "Undo";
"lng_stickers_restore" = "Restore";
"lng_stickers_count" = "{count:Loading..|# sticker|# stickers}";
"lng_stickers_count" = "{count:Loading...|# sticker|# stickers}";
"lng_in_dlg_photo" = "Photo";
"lng_in_dlg_video" = "Video";
"lng_in_dlg_video" = "Video file";
"lng_in_dlg_audio_file" = "Audio file";
"lng_in_dlg_contact" = "Contact";
"lng_in_dlg_audio" = "Audio";
"lng_in_dlg_audio" = "Voice message";
"lng_in_dlg_file" = "File";
"lng_in_dlg_sticker" = "Sticker";
"lng_in_dlg_sticker_emoji" = "{emoji} (sticker)";
"lng_ban_user" = "Ban User";
"lng_delete_all_from" = "Delete all from this user";
"lng_report_spam" = "Report Spam";
"lng_report_spam_hide" = "Hide";
"lng_report_spam_thanks" = "Thank you for your report!";
@ -633,16 +685,23 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_report_spam_sure_group" = "Are you sure you want to report spam in this group?";
"lng_report_spam_sure_channel" = "Are you sure you want to report spam in this channel?";
"lng_report_spam_ok" = "Report";
"lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment. {more_info}";
"lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment. {more_info}";
"lng_cant_invite_not_contact_channel" = "Sorry, you can only add mutual contacts\nto channels at the moment. {more_info}";
"lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment.\n{more_info}";
"lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment.\n{more_info}";
"lng_cant_invite_not_contact_channel" = "Sorry, you can only add mutual contacts\nto channels at the moment.\n{more_info}";
"lng_cant_more_info" = "More info »";
"lng_cant_invite_banned" = "Sorry, only admin can add this user.";
"lng_cant_invite_privacy" = "Sorry, you cannot add this user to groups because of the privacy settings.";
"lng_cant_invite_privacy_channel" = "Sorry, you cannot add this user to channels because of the privacy settings.";
"lng_cant_do_this" = "Sorry, this action is unavailable.";
"lng_send_button" = "Send";
"lng_message_ph" = "Write a message..";
"lng_comment_ph" = "Write a comment..";
"lng_broadcast_ph" = "Broadcast a message..";
"lng_message_ph" = "Write a message...";
"lng_comment_ph" = "Write a comment...";
"lng_broadcast_ph" = "Broadcast a message...";
"lng_broadcast_silent_ph" = "Silent broadcast...";
"lng_record_cancel" = "Release outside this field to cancel";
"lng_will_be_notified" = "Members will be notified when you post";
"lng_wont_be_notified" = "Members will not be notified when you post";
"lng_empty_history" = "";
"lng_willbe_history" = "Please select a chat to start messaging";
"lng_message_with_from" = "[c]{from}:[/c] {message}";
@ -667,28 +726,29 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_user_typing" = "{user} is typing";
"lng_users_typing" = "{user} and {second_user} are typing";
"lng_many_typing" = "{count:_not_used_|# is|# are} typing";
"lng_send_action_record_video" = "recording video";
"lng_user_action_record_video" = "{user} is recording video";
"lng_send_action_upload_video" = "sending video";
"lng_user_action_upload_video" = "{user} is sending video";
"lng_send_action_record_audio" = "recording audio";
"lng_user_action_record_audio" = "{user} is recording audio";
"lng_send_action_upload_audio" = "sending audio";
"lng_user_action_upload_audio" = "{user} is sending audio";
"lng_send_action_upload_photo" = "sending photo";
"lng_user_action_upload_photo" = "{user} is sending photo";
"lng_send_action_upload_file" = "sending file";
"lng_user_action_upload_file" = "{user} is sending file";
"lng_send_action_geo_location" = "picking location";
"lng_user_action_geo_location" = "{user} is picking location";
"lng_send_action_choose_contact" = "choosing contact";
"lng_user_action_choose_contact" = "{user} is choosing contact";
"lng_send_action_record_video" = "recording a video";
"lng_user_action_record_video" = "{user} is recording a video";
"lng_send_action_upload_video" = "sending a video";
"lng_user_action_upload_video" = "{user} is sending a video";
"lng_send_action_record_audio" = "recording a voice message";
"lng_user_action_record_audio" = "{user} is recording a voice message";
"lng_send_action_upload_audio" = "sending a voice message";
"lng_user_action_upload_audio" = "{user} is sending a voice message";
"lng_send_action_upload_photo" = "sending a photo";
"lng_user_action_upload_photo" = "{user} is sending a photo";
"lng_send_action_upload_file" = "sending a file";
"lng_user_action_upload_file" = "{user} is sending a file";
"lng_send_action_geo_location" = "picking a location";
"lng_user_action_geo_location" = "{user} is picking a location";
"lng_send_action_choose_contact" = "choosing a contact";
"lng_user_action_choose_contact" = "{user} is choosing a contact";
"lng_unread_bar" = "{count:_not_used_|# unread message|# unread messages}";
"lng_maps_point" = "Location";
"lng_save_photo" = "Save image";
"lng_save_video" = "Save video";
"lng_save_audio" = "Save audio";
"lng_save_video" = "Save video file";
"lng_save_audio_file" = "Save audio file";
"lng_save_audio" = "Save voice message";
"lng_save_file" = "Save file";
"lng_save_downloaded" = "{ready} / {total} {mb}";
"lng_duration_and_size" = "{duration}, {size}";
@ -700,16 +760,12 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_context_view_group" = "View group info";
"lng_context_view_channel" = "View channel info";
"lng_context_open_link" = "Open Link";
"lng_context_copy_link" = "Copy Link";
"lng_context_open_email" = "Write to this address";
"lng_context_copy_post_link" = "Copy Post Link";
"lng_context_copy_email" = "Copy email address";
"lng_context_open_hashtag" = "Search by hashtag";
"lng_context_copy_hashtag" = "Copy hashtag";
"lng_context_open_mention" = "Open profile";
"lng_context_copy_mention" = "Copy username";
"lng_context_open_image" = "Open Image";
"lng_context_save_image" = "Save Image As..";
"lng_context_save_image" = "Save Image As...";
"lng_context_forward_image" = "Forward Image";
"lng_context_delete_image" = "Delete Image";
"lng_context_copy_image" = "Copy Image";
@ -717,14 +773,12 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_context_cancel_download" = "Cancel Download";
"lng_context_show_in_folder" = "Show in Folder";
"lng_context_show_in_finder" = "Show in Finder";
"lng_context_open_video" = "Open Video";
"lng_context_save_video" = "Save Video As..";
"lng_context_open_audio" = "Open Audio";
"lng_context_save_audio" = "Save Audio As..";
"lng_context_save_video" = "Save Video File As...";
"lng_context_save_audio_file" = "Save Audio File As...";
"lng_context_save_audio" = "Save Voice Message As...";
"lng_context_pack_info" = "Pack Info";
"lng_context_pack_add" = "Add Stickers";
"lng_context_open_file" = "Open File";
"lng_context_save_file" = "Save File As..";
"lng_context_save_file" = "Save File As...";
"lng_context_forward_file" = "Forward File";
"lng_context_delete_file" = "Delete File";
"lng_context_close_file" = "Close File";
@ -732,9 +786,12 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_context_save_gif" = "Save GIF";
"lng_context_to_msg" = "Go To Message";
"lng_context_reply_msg" = "Reply";
"lng_context_edit_msg" = "Edit";
"lng_context_forward_msg" = "Forward Message";
"lng_context_delete_msg" = "Delete Message";
"lng_context_select_msg" = "Select Message";
"lng_context_pin_msg" = "Pin Message";
"lng_context_unpin_msg" = "Unpin Message";
"lng_context_cancel_upload" = "Cancel Upload";
"lng_context_copy_selected" = "Copy Selected Text";
"lng_context_forward_selected" = "Forward Selected";
@ -748,7 +805,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_send_image_too_large" = "Could not send a file, because it is larger than 1.5 GB :(";
"lng_send_folder" = "Could not send «{name}» because it is a directory :(";
"lng_forward_choose" = "Choose recipient..";
"lng_forward_choose" = "Choose recipient...";
"lng_forward_cant" = "Sorry, no way to forward here :(";
"lng_forward_confirm" = "Forward to {recipient}?";
"lng_forward_share_contact" = "Share contact to {recipient}?";
@ -768,6 +825,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_edit_group_title" = "Edit group name";
"lng_edit_contact_title" = "Edit contact name";
"lng_edit_channel_title" = "Edit channel";
"lng_edit_sign_messages" = "Sign messages";
"lng_edit_group" = "Edit group";
"lng_edit_self_title" = "Edit your name";
"lng_confirm_contact_data" = "New Contact";
@ -793,7 +851,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_selected_delete" = "Delete";
"lng_selected_forward" = "Forward";
"lng_selected_count" = "{count:_not_used_|# message|# messages}";
"lng_selected_cancel_sure_this" = "Do you want to cancel this upload?";
"lng_selected_cancel_sure_this" = "Cancel uploading?";
"lng_selected_upload_stop" = "Stop";
"lng_selected_delete_sure_this" = "Do you want to delete this message?";
"lng_selected_delete_sure" = "Do you want to delete {count:_not_used_|# message|# messages}?";
"lng_box_delete" = "Delete";
@ -809,7 +868,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_search_global_results" = "Global search results";
"lng_media_save_progress" = "{ready} of {total} {mb}";
"lng_mediaview_save_as" = "Save As..";
"lng_mediaview_save_as" = "Save As...";
"lng_mediaview_copy" = "Copy";
"lng_mediaview_forward" = "Forward";
"lng_mediaview_delete" = "Delete";
@ -832,7 +891,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_new_version_wrap" = "Telegram Desktop was updated to version {version}\n\n{changes}\n\nFull version history is available here:\n{link}";
"lng_new_version_minor" = "— Bug fixes and other minor improvements";
"lng_new_version_text" = "GIF revolution: 10x faster sending and downloading, autoplay, save your favorite GIFs to a dedicated tab on the sticker panel.\n\nMore about GIFs:\n{gifs_link}\n\nInline bots: A new way to add bot content to any chat. Type a bot's username and your query in the text field to get instant results and send them to your chat partner. Try typing “@gif dog” in your next chat. Sample bots: @gif, @wiki, @bing, @vid, @bold.\n\nMore about inline bots:\n{bots_link}\n\nAlso in this release: New cute design for media, automatic download settings for photos, voice messages and GIFs.";
"lng_new_version_text" = "— Visual improvements";
"lng_menu_insert_unicode" = "Insert Unicode control character";

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
defaultFontFamily: 'Open Sans';
semibold: 'Open Sans Semibold';
@ -51,7 +51,10 @@ color7: #2996ad; // sea
color8: #ce671b; // orange
wndMinWidth: 380px;
wideModeWidth: 640px;
adaptiveNormalWidth: 640px;
adaptiveWideWidth: 1366px;
wndMinHeight: 480px;
wndDefWidth: 800px;
wndDefHeight: 600px;
@ -64,6 +67,13 @@ layerBg: black;
overBg: #edf2f5;
labelDefFlat: flatLabel {
font: font(fsize);
minWidth: 100px;
width: 0px;
align: align(left);
}
boxBg: white;
boxVerticalMargin: 10px;
boxWidth: 320px;
@ -72,6 +82,8 @@ boxPadding: margins(26px, 30px, 34px, 8px);
boxMaxListHeight: 600px;
boxFontSize: 14px;
boxTextFont: font(boxFontSize);
boxLittleSkip: 10px;
boxMediumSkip: 20px;
boxTitleFg: #444444;
boxTitleFont: font(boxFontSize bold);
@ -123,6 +135,10 @@ redBoxLinkButton: linkButton(defaultBoxLinkButton) {
overColor: #d15948;
downColor: #db6352;
}
boxLabel: flatLabel(labelDefFlat) {
font: font(boxFontSize);
align: align(topleft);
}
defaultInputArea: InputArea {
textFg: black;
@ -269,6 +285,21 @@ defaultPopupMenu: PopupMenu {
widthMin: 180px;
widthMax: 300px;
}
defaultTooltip: Tooltip {
textBg: #eef2f5;
textFg: #5d6c80;
textFont: normalFont;
textBorder: #c9d1db;
textPadding: margins(5px, 2px, 5px, 2px);
shift: point(-20px, 20px);
skip: 10px;
widthMax: 800px;
linesMax: 12;
}
almostTransparent: #ffffff0d;
boxScroll: flatScroll(solidScroll) {
width: 18px;
@ -593,13 +624,6 @@ scrollCountries: flatScroll(scrollDef) {
lnkText: #0f7dc7;
labelDefFlat: flatLabel {
font: font(fsize);
minWidth: 100px;
width: 0px;
align: align(left);
}
introBtnTop: 288px;
introSkip: 45px;
introFinishSkip: 15px;
@ -937,6 +961,7 @@ dlgActiveUnreadColor: #5b94bf;
dlgActiveUnreadBG: white;
dlgActiveColor: white;
dlgActiveDateColor: #d3e2ee;
dlgActiveUnreadMutedBG: dlgActiveDateColor;
topBarHeight: 54px;
topBarBG: white;
@ -950,6 +975,21 @@ topBarBackAlpha: 0.8;
topBarBackImg: sprite(65px, 112px, 9px, 16px);
topBarBackColor: #005faf;
topBarBackFont: font(16px);
topBarSearch: iconedButton(btnDefIconed) {
bgColor: transparent;
overBgColor: transparent;
icon: sprite(84px, 374px, 18px, 18px);
iconPos: point(13px, 18px);
downIcon: sprite(84px, 374px, 18px, 18px);
downIconPos: point(13px, 18px);
opacity: 0.22;
overOpacity: 0.36;
width: 44px;
height: topBarHeight;
}
topBarMinPadding: 5px;
topBarButton: flatButton(btnDefFlat) {
color: btnYesColor;
@ -1009,10 +1049,11 @@ msgServiceNameFont: semiboldFont;
msgServicePhotoWidth: 100px;
msgDateFont: font(13px);
msgMinWidth: 190px;
msgPhotoSize: 30px;
msgPhotoSize: 33px;
msgPhotoSkip: 40px;
msgPadding: margins(13px, 7px, 13px, 8px);
msgMargin: margins(13px, 4px, 53px, 4px);
msgMargin: margins(13px, 10px, 53px, 2px);
msgMarginTopAttached: 3px;
msgLnkPadding: 2px; // for media open / save links
msgBorder: #f0f0f0;
msgInBg: #fff;
@ -1044,11 +1085,27 @@ msgInReplyBarColor: #2fa9e2;
msgOutReplyBarSelColor: #4da79f;
msgInReplyBarSelColor: #2fa9e2;
msgBotKbDuration: 200;
msgBotKbFont: semiboldFont;
msgBotKbOverOpacity: 0.1;
msgBotKbIconPadding: 2px;
msgBotKbUrlIcon: sprite(188px, 338px, 10px, 10px);
msgBotKbCallbackIcon: msgBotKbUrlIcon;
msgBotKbRequestPhoneIcon: msgBotKbUrlIcon;
msgBotKbRequestLocationIcon: msgBotKbUrlIcon;
msgBotKbButton: botKeyboardButton {
margin: 5px;
padding: 10px;
height: 36px;
textTop: 8px;
downTextTop: 9px;
}
msgServiceBg: #89a0b47f;
msgServiceSelectBg: #bbc8d4a2;
msgServiceColor: #FFF;
msgServicePadding: margins(12px, 3px, 12px, 4px);
msgServiceMargin: margins(10px, 7px, 80px, 7px);
msgServiceMargin: margins(10px, 10px, 80px, 2px);
msgColor: #000;
msgDateColor: #000;
@ -1107,7 +1164,7 @@ collapseButton: flatButton(btnDefFlat) {
textTop: 3px;
overTextTop: 3px;
downTextTop: 3px;
height: 24px;
height: 25px;
}
collapseHideDuration: 200;
collapseShowDuration: 200;
@ -1144,6 +1201,24 @@ outTextStyle: textStyle(defaultTextStyle) {
selectBg: msgOutBgSelected;
selectOverlay: msgSelectOverlay;
}
inFwdTextStyle: textStyle(defaultTextStyle) {
linkFlags: semiboldFont;
linkFlagsOver: semiboldFont;
linkFg: msgInServiceFg;
linkFgDown: msgInServiceFg;
}
outFwdTextStyle: textStyle(inFwdTextStyle) {
linkFg: msgOutServiceFg;
linkFgDown: msgOutServiceFg;
}
inFwdTextStyleSelected: textStyle(inFwdTextStyle) {
linkFg: msgInServiceFgSelected;
linkFgDown: msgInServiceFgSelected;
}
outFwdTextStyleSelected: textStyle(inFwdTextStyle) {
linkFg: msgOutServiceFgSelected;
linkFgDown: msgOutServiceFgSelected;
}
medviewSaveAsTextStyle: textStyle(defaultTextStyle) {
linkFg: #91d9ff;
linkFgDown: #91d9ff;
@ -1265,11 +1340,21 @@ msgFileBlue: sprite(60px, 425px, 20px, 20px);
msgFileOverDuration: 200;
msgFileRadialLine: 3px;
msgFileExtPadding: 8px;
msgFileExtTop: 30px;
msgVideoSize: size(320px, 240px);
msgWaveformBar: 2px;
msgWaveformSkip: 1px;
msgWaveformMin: 2px;
msgWaveformMax: 20px;
msgWaveformInActive: #59b6eb;
msgWaveformInActiveSelected: #51a3d3;
msgWaveformInInactive: #d4dee6;
msgWaveformInInactiveSelected: #9cc1e1;
msgWaveformOutActive: #78c67f;
msgWaveformOutActiveSelected: #6badad;
msgWaveformOutInactive: #b3e2b4;
msgWaveformOutInactiveSelected: #91c3c3;
sendPadding: 9px;
btnSend: flatButton(btnDefFlat) {
color: btnYesColor;
@ -1349,7 +1434,7 @@ broadcastToggle: flatCheckbox {
bgColor: white;
disColor: black;
width: 36px;
width: 34px;
height: 46px;
duration: 200;
bgFunc: transition(easeOutCirc);
@ -1364,13 +1449,23 @@ broadcastToggle: flatCheckbox {
disImageRect: sprite(18px, 125px, 22px, 21px);
chkDisImageRect: sprite(18px, 125px, 22px, 21px);
imagePos: point(7px, 12px);
imagePos: point(6px, 12px);
}
silentToggle: flatCheckbox(broadcastToggle) {
width: 33px;
imageRect: sprite(354px, 242px, 21px, 21px);
chkImageRect: sprite(354px, 221px, 21px, 21px);
overImageRect: sprite(375px, 242px, 21px, 21px);
chkOverImageRect: sprite(375px, 221px, 21px, 21px);
disImageRect: sprite(354px, 242px, 21px, 21px);
chkDisImageRect: sprite(354px, 221px, 21px, 21px);
}
btnRecordAudio: sprite(379px, 390px, 16px, 24px);
btnRecordAudioActive: sprite(379px, 366px, 16px, 24px);
recordSignalColor: #f17077;
recordSignalMin: 5px;
recordSignalMax: 10px;
recordSignalMax: 12px;
recordCancel: #aaa;
recordCancelActive: #ec6466;
recordFont: font(13px);
@ -1383,6 +1478,7 @@ replyTop: 8px;
replyBottom: 6px;
replyIconPos: point(13px, 13px);
replyIcon: sprite(343px, 197px, 24px, 24px);
editIcon: sprite(371px, 286px, 24px, 24px);
replyCancel: iconedButton(btnDefIconed) {
icon: sprite(165px, 24px, 14px, 14px);
iconPos: point(17px, 17px);
@ -1447,6 +1543,7 @@ reportSpamBg: #fffffff0;
newMsgSound: ':/gui/art/newmsg.wav';
unreadBarHeight: 32px;
unreadBarMargin: 8px;
unreadBarFont: semiboldFont;
unreadBarBG: #fcfbfa;
unreadBarBorder: shadowColor;
@ -2017,17 +2114,17 @@ verifiedCheckInv: sprite(299px, 221px, 14px, 14px);
verifiedCheckPos: point(4px, 2px);
botKbDuration: 200;
botKbBg: #f7f7f7;
botKbOverBg: #e8ecef;
botKbDownBg: #dfe3e6;
botKbColor: #8a8a8f;
botKbFont: font(16px);
botKbBg: #edf1f5;
botKbOverBg: #d8e2ec;
botKbDownBg: #d8e2ec;
botKbColor: #4b565f;
botKbFont: font(15px semibold);
botKbButton: botKeyboardButton {
margin: 10px;
padding: 10px;
height: 36px;
textTop: 8px;
downTextTop: 9px;
height: 38px;
textTop: 9px;
downTextTop: 10px;
}
botKbTinyButton: botKeyboardButton {
margin: 4px;
@ -2045,6 +2142,7 @@ minPhotoSize: 100px;
maxMediaSize: 420px;
maxStickerSize: 256px;
maxGifSize: 320px;
maxSignatureSize: 144px;
mvBgColor: #222;
mvBgOpacity: 0.92;
@ -2180,6 +2278,9 @@ overviewFileStatusTop: 27px;
overviewFileDateTop: 49px;
overviewFileChecked: #2fa9e2;
overviewFileCheck: #00000066;
overviewFileExtPadding: 5px;
overviewFileExtTop: 24px;
overviewFileExtFont: font(18px semibold);
// Mac specific
@ -2376,7 +2477,7 @@ linksDateMargin: margins(0px, 15px, 0px, 2px);
linksPhotoCheck: sprite(184px, 196px, 16px, 16px);
linksPhotoChecked: sprite(168px, 196px, 16px, 16px);
inlineResultsLeft: 15px;
inlineResultsLeft: 11px;
inlineResultsSkip: 3px;
inlineMediaHeight: 96px;
inlineThumbSize: 64px;
@ -2385,5 +2486,12 @@ inlineDescriptionFg: #8a8a8a;
inlineRowMargin: 6px;
inlineRowBorder: linksBorder;
inlineRowBorderFg: linksBorderFg;
inlineRowFileNameTop: 2px;
inlineRowFileDescriptionTop: 23px;
inlineResultsMinWidth: 64px;
inlineDurationMargin: 3px;
editTextArea: InputArea(defaultInputArea) {
textMargins: margins(1px, 6px, 1px, 4px);
heightMax: 256px;
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
textStyle {
linkFlags: font;
@ -272,6 +272,20 @@ PopupMenu {
widthMax: number;
}
Tooltip {
textBg: color;
textFg: color;
textFont: font;
textBorder: color;
textPadding: margins;
shift: point;
skip: number;
widthMax: number;
linesMax: number;
}
botKeyboardButton {
margin: number;
padding: number;

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "genemoji.h"
@ -1942,7 +1942,7 @@ In addition, as a special exception, the copyright holders give permission\n\
to link the code of portions of this program with the OpenSSL library.\n\
\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n";
tcpp << "#include \"stdafx.h\"\n#include \"gui/emoji_config.h\"\n\n";

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include <QtCore/QMap>
#include <QtCore/QVector>

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "genlang.h"
@ -391,7 +391,7 @@ bool genLang(const QString &lang_in, const QString &lang_out) {
th.setCodec("ISO 8859-1");
th << "\
/*\n\
Created from \'/Resources/lang.txt\' by \'/MetaLang\' project\n\
Created from \'/Resources/lang.strings\' by \'/MetaLang\' project\n\
\n\
WARNING! All changes made in this file will be lost!\n\
\n\
@ -412,7 +412,7 @@ In addition, as a special exception, the copyright holders give permission\n\
to link the code of portions of this program with the OpenSSL library.\n\
\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n";
th << "#pragma once\n\n";
@ -475,7 +475,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
tcpp << "\
/*\n\
Created from \'/Resources/lang.txt\' by \'/MetaLang\' project\n\
Created from \'/Resources/lang.strings\' by \'/MetaLang\' project\n\
\n\
WARNING! All changes made in this file will be lost!\n\
\n\
@ -496,7 +496,7 @@ In addition, as a special exception, the copyright holders give permission\n\
to link the code of portions of this program with the OpenSSL library.\n\
\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n";
tcpp << "#include \"stdafx.h\"\n#include \"lang.h\"\n\n";
tcpp << "namespace {\n";
@ -606,13 +606,22 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
++depth;
current += ich;
if (tag == current) {
bool exact = (tag == current);
if (exact) {
tcpp << tab.repeated(depth + 1) << "if (ch + " << depth << " == e) {\n";
tcpp << tab.repeated(depth + 1) << "\treturn lt_" << tag << ";\n";
tcpp << tab.repeated(depth + 1) << "}\n";
}
tcpp << tab.repeated(depth + 1) << "if (ch + " << depth << " < e) switch (*(ch + " << depth << ")) {\n";
QByteArray nexttag = j.key();
if (exact && depth > 0 && nexttag.mid(0, depth) != current) {
current.chop(1);
--depth;
tcpp << tab.repeated(depth + 1) << "break;\n";
break;
} else {
tcpp << tab.repeated(depth + 1) << "if (ch + " << depth << " < e) switch (*(ch + " << depth << ")) {\n";
}
} while (true);
++j;
}
@ -637,7 +646,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
tcpp << "\tswitch (*(ch + " << depth << ")) {\n";
for (LangKeys::const_iterator i = keys.cbegin(), j = i + 1, e = keys.cend(); i != e; ++i) {
QByteArray key = i.key();
while (key.mid(0, depth) != current) {
while (depth > 0 && key.mid(0, depth) != current) {
tcpp << tab.repeated(depth - 3) << "}\n";
current.chop(1);
--depth;
@ -661,13 +670,22 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
++depth;
current += ich;
if (key == current) {
bool exact = (key == current);
if (exact) {
tcpp << tab.repeated(depth - 3) << "if (ch + " << depth << " == e) {\n";
tcpp << tab.repeated(depth - 3) << "\treturn " << key << (keysTags[key].isEmpty() ? "" : "__tagged") << ";\n";
tcpp << tab.repeated(depth - 3) << "}\n";
}
tcpp << tab.repeated(depth - 3) << "if (ch + " << depth << " < e) switch (*(ch + " << depth << ")) {\n";
QByteArray nextkey = j.key();
if (exact && depth > 0 && nextkey.mid(0, depth) != current) {
current.chop(1);
--depth;
tcpp << tab.repeated(depth - 3) << "break;\n";
break;
} else {
tcpp << tab.repeated(depth - 3) << "if (ch + " << depth << " < e) switch (*(ch + " << depth << ")) {\n";
}
} while (true);
++j;
}
@ -707,16 +725,25 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
tcpp << "\tif (index >= lngtags_max_counted_values) return lngkeys_cnt;\n\n";
if (!tags.isEmpty()) {
tcpp << "\tswitch (key) {\n";
for (int i = 0, l = keysOrder.size(); i < l; ++i) {
QVector<QByteArray> &tagsList(keysTags[keysOrder[i]]);
for (auto key : keysOrder) {
QVector<QByteArray> &tagsList(keysTags[key]);
if (tagsList.isEmpty()) continue;
QMap<QByteArray, QVector<QString> > &countedTags(keysCounted[keysOrder[i]]);
tcpp << "\tcase " << keysOrder[i] << "__tagged: {\n";
QMap<QByteArray, QVector<QString> > &countedTags(keysCounted[key]);
bool hasCounted = false;
for (auto tag : tagsList) {
if (!countedTags[tag].isEmpty()) {
hasCounted = true;
break;
}
}
if (!hasCounted) continue;
tcpp << "\tcase " << key << "__tagged: {\n";
tcpp << "\t\tswitch (tag) {\n";
for (int j = 0, s = tagsList.size(); j < s; ++j) {
if (!countedTags[tagsList[j]].isEmpty()) {
tcpp << "\t\tcase lt_" << tagsList[j] << ": return LangKey(" << keysOrder[i] << "__" << tagsList[j] << "0 + index);\n";
for (auto tag : tagsList) {
if (!countedTags[tag].isEmpty()) {
tcpp << "\t\tcase lt_" << tag << ": return LangKey(" << key << "__" << tag << "0 + index);\n";
}
}
tcpp << "\t\t}\n";
@ -724,7 +751,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
}
tcpp << "\t}\n\n";
}
tcpp << "\treturn lngkeys_cnt;";
tcpp << "\treturn lngkeys_cnt;\n";
tcpp << "}\n\n";
tcpp << "bool LangLoader::feedKeyValue(LangKey key, const QString &value) {\n";

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include <QtCore/QMap>
#include <QtCore/QVector>

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "genstyles.h"
@ -381,9 +381,9 @@ In addition, as a special exception, the copyright holders give permission\n\
to link the code of portions of this program with the OpenSSL library.\n\
\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n";
tout << "#pragma once\n\n#include \"style.h\"\n\nnamespace style {\n";
tout << "#pragma once\n\n#include \"gui/style.h\"\n\nnamespace style {\n";
for (int i = 0, l = byIndex.size(); i < l; ++i) {
ClassData &cls(byIndex[i]);
classes.insert(cls.name, cls);
@ -1542,9 +1542,9 @@ In addition, as a special exception, the copyright holders give permission\n\
to link the code of portions of this program with the OpenSSL library.\n\
\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n";
tout << "#pragma once\n\n#include \"style.h\"\n\nnamespace st {\n";
tout << "#pragma once\n\n#include \"gui/style.h\"\n\nnamespace st {\n";
tcpp << "\
/*\n\
Created from \'/Resources/style.txt\' by \'/MetaStyle\' project\n\
@ -1568,7 +1568,7 @@ In addition, as a special exception, the copyright holders give permission\n\
to link the code of portions of this program with the OpenSSL library.\n\
\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n";
tcpp << "#include \"stdafx.h\"\n#include \"style_auto.h\"\n\nnamespace {\n";
for (int i = 0, l = scalars.size(); i < l; ++i) {
@ -1945,7 +1945,7 @@ In addition, as a special exception, the copyright holders give permission\n\
to link the code of portions of this program with the OpenSSL library.\n\
\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n";
tnum << "#include \"stdafx.h\"\n#include \"numbers.h\"\n\n";
tnum << "QVector<int> phoneNumberParse(const QString &number) {\n";

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include <QtCore/QMap>
#include <QtCore/QVector>

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "memain.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include <QtCore/QTimer>

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "mlmain.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include <QtCore/QTimer>

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "msmain.h"
#include <QtCore/QDir>

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include <QtCore/QTimer>

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "packer.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "updater.h"
@ -255,7 +255,7 @@ bool update() {
} else {
break;
}
} while (copyTries < 30);
} while (copyTries < 100);
if (!copyResult) {
writeLog(L"Error: failed to copy, asking to retry..");
WCHAR errMsg[2048];
@ -328,14 +328,11 @@ void updateRegistry() {
}
}
#include <ShlObj.h>
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) {
openLog();
#ifdef _NEED_WIN_GENERATE_DUMP
_oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter);
#endif
// CAPIHook apiHook("kernel32.dll", "SetUnhandledExceptionFilter", (PROC)RedirectedSetUnhandledExceptionFilter);
writeLog(L"Updaters started..");
@ -459,13 +456,12 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
ShellExecute(0, 0, (updateTo + L"Telegram.exe").c_str(), (L"-noupdate" + targs).c_str(), 0, SW_SHOWNORMAL);
}
writeLog(L"Executed Telegram.exe, closing log and quiting..");
writeLog(L"Executed Telegram.exe, closing log and quitting..");
closeLog();
return 0;
}
#ifdef _NEED_WIN_GENERATE_DUMP
static const WCHAR *_programName = L"Telegram Desktop"; // folder in APPDATA, if current path is unavailable for writing
static const WCHAR *_exeName = L"Updater.exe";
@ -486,13 +482,18 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) {
static const int maxFileLen = MAX_PATH * 10;
WCHAR szPath[maxFileLen];
wsprintf(szPath, L"%stdumps\\", path);
wsprintf(szPath, L"%stdata\\", path);
if (!CreateDirectory(szPath, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
return 0;
}
}
wsprintf(szPath, L"%sdumps\\", path);
if (!CreateDirectory(szPath, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
return 0;
}
}
WCHAR szFileName[maxFileLen];
WCHAR szExeName[maxFileLen];
@ -564,4 +565,10 @@ LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers) {
return _oldWndExceptionFilter ? (*_oldWndExceptionFilter)(pExceptionPointers) : EXCEPTION_CONTINUE_SEARCH;
}
#endif
// see http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) {
// When the CRT calls SetUnhandledExceptionFilter with NULL parameter
// our handler will not get removed.
_oldWndExceptionFilter = lpTopLevelExceptionFilter;
return 0;
}

View file

@ -16,13 +16,19 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include <windows.h>
#include <string>
#pragma warning(push)
#pragma warning(disable:4091)
#include <DbgHelp.h>
#include <ShlObj.h>
#pragma warning(pop)
#include <Shellapi.h>
#include <Shlwapi.h>
@ -32,12 +38,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
using std::deque;
using std::wstring;
#define _NEED_WIN_GENERATE_DUMP
#ifdef _NEED_WIN_GENERATE_DUMP
extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter;
LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers);
#endif _NEED_WIN_GENERATE_DUMP
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
static int updaterVersion = 1000;
static const WCHAR *updaterVersionStr = L"0.1.0";

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include <cstdio>
#include <sys/stat.h>
@ -324,7 +324,7 @@ bool update() {
int main(int argc, char *argv[]) {
bool needupdate = true, autostart = false, debug = false, tosettings = false, startintray = false, testmode = false;
char *key = 0;
char *key = 0, *crashreport = 0;
for (int i = 1; i < argc; ++i) {
if (equal(argv[i], "-noupdate")) {
needupdate = false;
@ -342,7 +342,9 @@ int main(int argc, char *argv[]) {
key = argv[i];
} else if (equal(argv[i], "-workpath") && ++i < argc) {
workDir = argv[i];
}
} else if (equal(argv[i], "-crashreport") && ++i < argc) {
crashreport = argv[i];
}
}
openLog();
@ -408,24 +410,27 @@ int main(int argc, char *argv[]) {
char *args[MaxArgsCount] = {0}, p_noupdate[] = "-noupdate", p_autostart[] = "-autostart", p_debug[] = "-debug", p_tosettings[] = "-tosettings", p_key[] = "-key", p_startintray[] = "-startintray", p_testmode[] = "-testmode";
int argIndex = 0;
args[argIndex++] = path;
args[argIndex++] = p_noupdate;
if (autostart) args[argIndex++] = p_autostart;
if (debug) args[argIndex++] = p_debug;
if (startintray) args[argIndex++] = p_startintray;
if (testmode) args[argIndex++] = p_testmode;
if (tosettings) args[argIndex++] = p_tosettings;
if (key) {
args[argIndex++] = p_key;
args[argIndex++] = key;
}
if (crashreport) {
args[argIndex++] = crashreport;
} else {
args[argIndex++] = p_noupdate;
if (autostart) args[argIndex++] = p_autostart;
if (debug) args[argIndex++] = p_debug;
if (startintray) args[argIndex++] = p_startintray;
if (testmode) args[argIndex++] = p_testmode;
if (tosettings) args[argIndex++] = p_tosettings;
if (key) {
args[argIndex++] = p_key;
args[argIndex++] = key;
}
}
pid_t pid = fork();
switch (pid) {
case -1: writeLog("fork() failed!"); return 1;
case 0: execv(path, args); return 1;
}
writeLog("Executed Telegram, closing log and quiting..");
writeLog("Executed Telegram, closing log and quitting..");
closeLog();
return 0;

View file

@ -16,13 +16,14 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#import <Cocoa/Cocoa.h>
NSString *appName = @"Telegram.app";
NSString *appDir = nil;
NSString *workDir = nil;
NSString *crashReportArg = nil;
#ifdef _DEBUG
BOOL _debug = YES;
@ -101,6 +102,10 @@ int main(int argc, const char * argv[]) {
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
procId = [[formatter numberFromString:[NSString stringWithUTF8String:argv[i]]] intValue];
}
} else if ([@"-crashreport" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
if (++i < argc) {
crashReportArg = [NSString stringWithUTF8String:argv[i]];
}
} else if ([@"-noupdate" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
update = NO;
} else if ([@"-tosettings" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
@ -214,15 +219,17 @@ int main(int argc, const char * argv[]) {
}
NSString *appPath = [[NSArray arrayWithObjects:appDir, appRealName, nil] componentsJoinedByString:@""];
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:@"-noupdate", nil];
if (toSettings) [args addObject:@"-tosettings"];
if (_debug) [args addObject:@"-debug"];
if (startInTray) [args addObject:@"-startintray"];
if (testMode) [args addObject:@"-testmode"];
if (autoStart) [args addObject:@"-autostart"];
if (key) {
[args addObject:@"-key"];
[args addObject:key];
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: crashReportArg ? crashReportArg : @"-noupdate", nil];
if (!crashReportArg) {
if (toSettings) [args addObject:@"-tosettings"];
if (_debug) [args addObject:@"-debug"];
if (startInTray) [args addObject:@"-startintray"];
if (testMode) [args addObject:@"-testmode"];
if (autoStart) [args addObject:@"-autostart"];
if (key) {
[args addObject:@"-key"];
[args addObject:key];
}
}
writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]);
NSError *error = nil;

View file

@ -16,10 +16,10 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "style.h"
#include "gui/style.h"
#include "lang.h"
#include "application.h"
@ -29,89 +29,65 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "localstorage.h"
ApiWrap::ApiWrap(QObject *parent) : QObject(parent) {
ApiWrap::ApiWrap(QObject *parent) : QObject(parent)
, _messageDataResolveDelayed(new SingleDelayedCall(this, "resolveMessageDatas")) {
App::initBackground();
connect(&_replyToTimer, SIGNAL(timeout()), this, SLOT(resolveReplyTo()));
connect(&_webPagesTimer, SIGNAL(timeout()), this, SLOT(resolveWebPages()));
}
void ApiWrap::init() {
}
void ApiWrap::itemRemoved(HistoryItem *item) {
if (HistoryReply *reply = item->toHistoryReply()) {
ChannelData *channel = reply->history()->peer->asChannel();
ReplyToRequests *requests(replyToRequests(channel, true));
if (requests) {
ReplyToRequests::iterator i = requests->find(reply->replyToId());
if (i != requests->cend()) {
for (QList<HistoryReply*>::iterator j = i->replies.begin(); j != i->replies.end();) {
if ((*j) == reply) {
j = i->replies.erase(j);
} else {
++j;
}
}
if (i->replies.isEmpty()) {
requests->erase(i);
}
}
if (channel && requests->isEmpty()) {
_channelReplyToRequests.remove(channel);
}
}
}
void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback *callback) {
MessageDataRequest::CallbackPtr pcallback(callback);
MessageDataRequest &req(channel ? _channelMessageDataRequests[channel][msgId] : _messageDataRequests[msgId]);
req.callbacks.append(pcallback);
if (!req.req) _messageDataResolveDelayed->call();
}
void ApiWrap::requestReplyTo(HistoryReply *reply, ChannelData *channel, MsgId id) {
ReplyToRequest &req(channel ? _channelReplyToRequests[channel][id] : _replyToRequests[id]);
req.replies.append(reply);
if (!req.req) _replyToTimer.start(1);
}
ApiWrap::MessageIds ApiWrap::collectMessageIds(const ReplyToRequests &requests) {
ApiWrap::MessageIds ApiWrap::collectMessageIds(const MessageDataRequests &requests) {
MessageIds result;
result.reserve(requests.size());
for (ReplyToRequests::const_iterator i = requests.cbegin(), e = requests.cend(); i != e; ++i) {
for (MessageDataRequests::const_iterator i = requests.cbegin(), e = requests.cend(); i != e; ++i) {
if (i.value().req > 0) continue;
result.push_back(MTP_int(i.key()));
}
return result;
}
ApiWrap::ReplyToRequests *ApiWrap::replyToRequests(ChannelData *channel, bool onlyExisting) {
ApiWrap::MessageDataRequests *ApiWrap::messageDataRequests(ChannelData *channel, bool onlyExisting) {
if (channel) {
ChannelReplyToRequests::iterator i = _channelReplyToRequests.find(channel);
if (i == _channelReplyToRequests.cend()) {
ChannelMessageDataRequests::iterator i = _channelMessageDataRequests.find(channel);
if (i == _channelMessageDataRequests.cend()) {
if (onlyExisting) return 0;
i = _channelReplyToRequests.insert(channel, ReplyToRequests());
i = _channelMessageDataRequests.insert(channel, MessageDataRequests());
}
return &i.value();
}
return &_replyToRequests;
return &_messageDataRequests;
}
void ApiWrap::resolveReplyTo() {
if (_replyToRequests.isEmpty() && _channelReplyToRequests.isEmpty()) return;
void ApiWrap::resolveMessageDatas() {
if (_messageDataRequests.isEmpty() && _channelMessageDataRequests.isEmpty()) return;
MessageIds ids = collectMessageIds(_replyToRequests);
MessageIds ids = collectMessageIds(_messageDataRequests);
if (!ids.isEmpty()) {
mtpRequestId req = MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotReplyTo, (ChannelData*)0), RPCFailHandlerPtr(), 0, 5);
for (ReplyToRequests::iterator i = _replyToRequests.begin(); i != _replyToRequests.cend(); ++i) {
mtpRequestId req = MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotMessageDatas, (ChannelData*)nullptr), RPCFailHandlerPtr(), 0, 5);
for (MessageDataRequests::iterator i = _messageDataRequests.begin(); i != _messageDataRequests.cend(); ++i) {
if (i.value().req > 0) continue;
i.value().req = req;
}
}
for (ChannelReplyToRequests::iterator j = _channelReplyToRequests.begin(); j != _channelReplyToRequests.cend();) {
for (ChannelMessageDataRequests::iterator j = _channelMessageDataRequests.begin(); j != _channelMessageDataRequests.cend();) {
if (j->isEmpty()) {
j = _channelReplyToRequests.erase(j);
j = _channelMessageDataRequests.erase(j);
continue;
}
MessageIds ids = collectMessageIds(j.value());
if (!ids.isEmpty()) {
mtpRequestId req = MTP::send(MTPchannels_GetMessages(j.key()->inputChannel, MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotReplyTo, j.key()), RPCFailHandlerPtr(), 0, 5);
for (ReplyToRequests::iterator i = j->begin(); i != j->cend(); ++i) {
mtpRequestId req = MTP::send(MTPchannels_GetMessages(j.key()->inputChannel, MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotMessageDatas, j.key()), RPCFailHandlerPtr(), 0, 5);
for (MessageDataRequests::iterator i = j->begin(); i != j->cend(); ++i) {
if (i.value().req > 0) continue;
i.value().req = req;
}
@ -120,7 +96,7 @@ void ApiWrap::resolveReplyTo() {
}
}
void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) {
void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) {
switch (msgs.type()) {
case mtpc_messages_messages: {
const MTPDmessages_messages &d(msgs.c_messages_messages());
@ -141,10 +117,10 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs,
if (channel) {
channel->ptsReceived(d.vpts.v);
} else {
LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotReplyTo)"));
LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem)"));
}
if (d.has_collapsed()) { // should not be returned
LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (ApiWrap::gotReplyTo)"));
LOG(("API Error: channels.getMessages and messages.getMessages should not return collapsed groups! (ApiWrap::gotDependencyItem)"));
}
App::feedUsers(d.vusers);
@ -152,16 +128,12 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs,
App::feedMsgs(d.vmessages, NewMessageExisting);
} break;
}
ReplyToRequests *requests(replyToRequests(channel, true));
MessageDataRequests *requests(messageDataRequests(channel, true));
if (requests) {
for (ReplyToRequests::iterator i = requests->begin(); i != requests->cend();) {
for (MessageDataRequests::iterator i = requests->begin(); i != requests->cend();) {
if (i.value().req == req) {
for (QList<HistoryReply*>::const_iterator j = i.value().replies.cbegin(), e = i.value().replies.cend(); j != e; ++j) {
if (*j) {
(*j)->updateReplyTo(true);
} else {
App::main()->updateReplyTo();
}
for (MessageDataRequest::Callbacks::const_iterator j = i.value().callbacks.cbegin(), e = i.value().callbacks.cend(); j != e; ++j) {
(*j)->call(channel, i.key());
}
i = requests->erase(i);
} else {
@ -169,7 +141,7 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs,
}
}
if (channel && requests->isEmpty()) {
_channelReplyToRequests.remove(channel);
_channelMessageDataRequests.remove(channel);
}
}
}
@ -258,7 +230,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
}
if (f.has_migrated_from_chat_id()) {
if (!channel->mgInfo) {
channel->flags |= MTPDchannel::flag_megagroup;
channel->flags |= MTPDchannel::Flag::f_megagroup;
channel->flagsUpdated();
}
ChatData *cfrom = App::chat(peerFromChat(f.vmigrated_from_chat_id));
@ -273,7 +245,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
if (!h->isEmpty()) {
h->clear(true);
}
if (!hto->dialogs.isEmpty() && !h->dialogs.isEmpty()) {
if (hto->inChatList() && h->inChatList()) {
App::removeDialog(h);
}
}
@ -317,6 +289,13 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
h->asChannelHistory()->unreadCountAll = f.vunread_count.v;
}
}
if (channel->isMegagroup()) {
if (f.has_pinned_msg_id()) {
channel->mgInfo->pinnedMsgId = f.vpinned_msg_id.v;
} else {
channel->mgInfo->pinnedMsgId = 0;
}
}
channel->fullUpdated();
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), f.vnotify_settings);
@ -344,12 +323,21 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result, mtpRequestId req) {
const MTPDuserFull &d(result.c_userFull());
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser), false);
App::feedPhoto(d.vprofile_photo);
if (d.has_profile_photo()) {
App::feedPhoto(d.vprofile_photo);
}
App::feedUserLink(MTP_int(peerToUser(peer->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link, false);
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), d.vnotify_settings);
if (App::main()) {
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), d.vnotify_settings);
}
peer->asUser()->setBotInfo(d.vbot_info);
peer->asUser()->blocked = mtpIsTrue(d.vblocked) ? UserIsBlocked : UserIsNotBlocked;
if (d.has_bot_info()) {
peer->asUser()->setBotInfo(d.vbot_info);
} else {
peer->asUser()->setBotInfoVersion(-1);
}
peer->asUser()->blocked = d.is_blocked() ? UserIsBlocked : UserIsNotBlocked;
peer->asUser()->about = d.has_about() ? qs(d.vabout) : QString();
if (req) {
QMap<PeerData*, mtpRequestId>::iterator i = _fullPeerRequests.find(peer);
@ -419,13 +407,13 @@ void ApiWrap::requestLastParticipants(ChannelData *peer, bool fromStart) {
return;
}
}
mtpRequestId req = MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsRecent(), MTP_int(fromStart ? 0 : peer->mgInfo->lastParticipants.size()), MTP_int(cMaxGroupCount())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer));
mtpRequestId req = MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsRecent(), MTP_int(fromStart ? 0 : peer->mgInfo->lastParticipants.size()), MTP_int(Global::ChatSizeMax())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer));
_participantsRequests.insert(peer, fromStart ? req : -req);
}
void ApiWrap::requestBots(ChannelData *peer) {
if (!peer || !peer->isMegagroup() || _botsRequests.contains(peer)) return;
_botsRequests.insert(peer, MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer)));
_botsRequests.insert(peer, MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(Global::ChatSizeMax())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer)));
}
void ApiWrap::gotChat(PeerData *peer, const MTPmessages_Chats &result) {
@ -524,7 +512,7 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP
UserData *u = App::user(userId);
if (bots) {
if (u->botInfo) {
peer->mgInfo->bots.insert(u, true);
peer->mgInfo->bots.insert(u);
botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
if (!u->botInfo->inited) {
needBotsInfos = true;
@ -536,9 +524,9 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP
} else {
if (peer->mgInfo->lastParticipants.indexOf(u) < 0) {
peer->mgInfo->lastParticipants.push_back(u);
if (admin) peer->mgInfo->lastAdmins.insert(u, true);
if (admin) peer->mgInfo->lastAdmins.insert(u);
if (u->botInfo) {
peer->mgInfo->bots.insert(u, true);
peer->mgInfo->bots.insert(u);
if (peer->mgInfo->botStatus != 0 && peer->mgInfo->botStatus < 2) {
peer->mgInfo->botStatus = 2;
}
@ -645,15 +633,23 @@ void ApiWrap::kickParticipantDone(KickRequest kick, const MTPUpdates &result, mt
int32 i = kick.first->asChannel()->mgInfo->lastParticipants.indexOf(kick.second);
if (i >= 0) {
kick.first->asChannel()->mgInfo->lastParticipants.removeAt(i);
kick.first->asChannel()->mgInfo->lastAdmins.remove(kick.second);
}
kick.first->asChannel()->mgInfo->bots.remove(kick.second);
if (kick.first->asChannel()->count > 1) {
kick.first->asChannel()->count--;
--kick.first->asChannel()->count;
} else {
kick.first->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
kick.first->asChannel()->mgInfo->lastParticipantsCount = 0;
}
if (kick.first->asChannel()->mgInfo->lastAdmins.contains(kick.second)) {
kick.first->asChannel()->mgInfo->lastAdmins.remove(kick.second);
if (kick.first->asChannel()->adminsCount > 1) {
--kick.first->asChannel()->adminsCount;
}
}
kick.first->asChannel()->mgInfo->bots.remove(kick.second);
if (kick.first->asChannel()->mgInfo->bots.isEmpty() && kick.first->asChannel()->mgInfo->botStatus > 0) {
kick.first->asChannel()->mgInfo->botStatus = -1;
}
}
emit fullPeerUpdated(kick.first);
}
@ -672,9 +668,9 @@ void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) {
void ApiWrap::requestStickerSets() {
for (QMap<uint64, QPair<uint64, mtpRequestId> >::iterator i = _stickerSetRequests.begin(), j = i, e = _stickerSetRequests.end(); i != e; i = j) {
++j;
if (i.value().second) continue;
++j;
int32 wait = (j == e) ? 0 : 10;
i.value().second = MTP::send(MTPmessages_GetStickerSet(MTP_inputStickerSetID(MTP_long(i.key()), MTP_long(i.value().first))), rpcDone(&ApiWrap::gotStickerSet, i.key()), rpcFail(&ApiWrap::gotStickerSetFail, i.key()), 0, wait);
}
@ -689,8 +685,8 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
if (d.vset.type() != mtpc_stickerSet) return;
const MTPDstickerSet &s(d.vset.c_stickerSet());
StickerSets &sets(cRefStickerSets());
StickerSets::iterator it = sets.find(setId);
Stickers::Sets &sets(Global::RefStickerSets());
auto it = sets.find(setId);
if (it == sets.cend()) return;
it->access = s.vaccess_hash.v;
@ -700,7 +696,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
it->flags = s.vflags.v;
const QVector<MTPDocument> &d_docs(d.vdocuments.c_vector().v);
StickerSets::iterator custom = sets.find(CustomStickerSetId);
auto custom = sets.find(Stickers::CustomSetId);
StickerPack pack;
pack.reserve(d_docs.size());
@ -731,12 +727,32 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
++i;
}
}
if (pack.isEmpty()) {
int32 removeIndex = cStickerSetsOrder().indexOf(setId);
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex);
int removeIndex = Global::StickerSetsOrder().indexOf(setId);
if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex);
sets.erase(it);
} else {
it->stickers = pack;
it->emoji.clear();
const QVector<MTPStickerPack> &v(d.vpacks.c_vector().v);
for (int32 i = 0, l = v.size(); i < l; ++i) {
if (v.at(i).type() != mtpc_stickerPack) continue;
const MTPDstickerPack &pack(v.at(i).c_stickerPack());
if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) {
const QVector<MTPlong> &stickers(pack.vdocuments.c_vector().v);
StickerPack p;
p.reserve(stickers.size());
for (int32 j = 0, c = stickers.size(); j < c; ++j) {
DocumentData *doc = App::document(stickers.at(j).v);
if (!doc || !doc->sticker()) continue;
p.push_back(doc);
}
it->emoji.insert(e, p);
}
}
}
if (writeRecent) {
@ -887,10 +903,8 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
}
for (QMap<uint64, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), NewMessageExisting);
if (item) {
item->initDimensions();
Notify::historyItemResized(item);
if (HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), NewMessageExisting)) {
item->setPendingInitDimensions();
}
}
@ -902,8 +916,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
WebPageItems::const_iterator j = items.constFind(i.key());
if (j != items.cend()) {
for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) {
k.key()->initDimensions();
Notify::historyItemResized(k.key());
k.key()->setPendingInitDimensions();
}
}
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -28,9 +28,8 @@ public:
ApiWrap(QObject *parent);
void init();
void itemRemoved(HistoryItem *item);
void requestReplyTo(HistoryReply *reply, ChannelData *channel, MsgId id);
typedef SharedCallback<void, ChannelData*, MsgId> RequestMessageDataCallback;
void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback *callback);
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);
@ -59,28 +58,30 @@ signals:
public slots:
void resolveReplyTo();
void resolveMessageDatas();
void resolveWebPages();
void delayedRequestParticipantsCount();
private:
void gotReplyTo(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
struct ReplyToRequest {
ReplyToRequest() : req(0) {
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
struct MessageDataRequest {
MessageDataRequest() : req(0) {
}
typedef SharedCallback<void, ChannelData*, MsgId>::Ptr CallbackPtr;
typedef QList<CallbackPtr> Callbacks;
mtpRequestId req;
QList<HistoryReply*> replies;
Callbacks callbacks;
};
typedef QMap<MsgId, ReplyToRequest> ReplyToRequests;
ReplyToRequests _replyToRequests;
typedef QMap<ChannelData*, ReplyToRequests> ChannelReplyToRequests;
ChannelReplyToRequests _channelReplyToRequests;
SingleTimer _replyToTimer;
typedef QMap<MsgId, MessageDataRequest> MessageDataRequests;
MessageDataRequests _messageDataRequests;
typedef QMap<ChannelData*, MessageDataRequests> ChannelMessageDataRequests;
ChannelMessageDataRequests _channelMessageDataRequests;
SingleDelayedCall *_messageDataResolveDelayed;
typedef QVector<MTPint> MessageIds;
MessageIds collectMessageIds(const ReplyToRequests &requests);
ReplyToRequests *replyToRequests(ChannelData *channel, bool onlyExisting = false);
MessageIds collectMessageIds(const MessageDataRequests &requests);
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
void gotUserFull(PeerData *peer, const MTPUserFull &result, mtpRequestId req);

File diff suppressed because it is too large Load diff

View file

@ -16,13 +16,13 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "types.h"
#include "basic_types.h"
class Application;
class AppClass;
class Window;
class MainWidget;
class SettingsWidget;
@ -36,30 +36,18 @@ class FileUploader;
typedef QMap<HistoryItem*, NullType> HistoryItemsMap;
typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems;
typedef QHash<VideoData*, HistoryItemsMap> VideoItems;
typedef QHash<AudioData*, HistoryItemsMap> AudioItems;
typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems;
typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems;
typedef QHash<int32, HistoryItemsMap> SharedContactItems;
typedef QHash<ClipReader*, HistoryItem*> GifItems;
typedef QHash<PhotoId, PhotoData*> PhotosData;
typedef QHash<VideoId, VideoData*> VideosData;
typedef QHash<AudioId, AudioData*> AudiosData;
typedef QHash<DocumentId, DocumentData*> DocumentsData;
struct ReplyMarkup {
ReplyMarkup(int32 flags = 0) : flags(flags) {
}
typedef QList<QList<QString> > Commands;
Commands commands;
int32 flags;
};
class LayeredWidget;
namespace App {
Application *app();
AppClass *app();
Window *wnd();
MainWidget *main();
SettingsWidget *settings();
@ -68,7 +56,6 @@ namespace App {
ApiWrap *api();
void logOut();
bool loggedOut();
QString formatPhone(QString phone);
@ -85,6 +72,7 @@ namespace App {
void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true);
void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d, bool emitPeerUpdated = true);
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
void updateEditedMessage(const MTPDmessage &m);
void addSavedGif(DocumentData *doc);
void checkSavedGif(HistoryItem *item);
void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type);
@ -106,9 +94,6 @@ namespace App {
PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs);
PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0);
PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0);
VideoData *feedVideo(const MTPDvideo &video, VideoData *convert = 0);
AudioData *feedAudio(const MTPaudio &audio, AudioData *convert = 0);
AudioData *feedAudio(const MTPDaudio &audio, AudioData *convert = 0);
DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb);
DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0);
DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = 0);
@ -116,36 +101,57 @@ namespace App {
WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = 0);
WebPageData *feedWebPage(const MTPWebPage &webpage);
PeerData *peerLoaded(const PeerId &id);
UserData *userLoaded(const PeerId &id);
ChatData *chatLoaded(const PeerId &id);
ChannelData *channelLoaded(const PeerId &id);
UserData *userLoaded(int32 user);
ChatData *chatLoaded(int32 chat);
ChannelData *channelLoaded(int32 channel);
PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asUser(peer(id, restriction));
}
inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChat(peer(id, restriction));
}
inline ChannelData *channel(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChannel(peer(id, restriction));
}
inline UserData *user(UserId userId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asUser(peer(peerFromUser(userId), restriction));
}
inline ChatData *chat(ChatId chatId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChat(peer(peerFromChat(chatId), restriction));
}
inline ChannelData *channel(ChannelId channelId, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
return asChannel(peer(peerFromChannel(channelId), restriction));
}
inline PeerData *peerLoaded(const PeerId &id) {
return peer(id, PeerData::FullLoaded);
}
inline UserData *userLoaded(const PeerId &id) {
return user(id, PeerData::FullLoaded);
}
inline ChatData *chatLoaded(const PeerId &id) {
return chat(id, PeerData::FullLoaded);
}
inline ChannelData *channelLoaded(const PeerId &id) {
return channel(id, PeerData::FullLoaded);
}
inline UserData *userLoaded(UserId userId) {
return user(userId, PeerData::FullLoaded);
}
inline ChatData *chatLoaded(ChatId chatId) {
return chat(chatId, PeerData::FullLoaded);
}
inline ChannelData *channelLoaded(ChannelId channelId) {
return channel(channelId, PeerData::FullLoaded);
}
PeerData *peer(const PeerId &id);
UserData *user(const PeerId &id);
ChatData *chat(const PeerId &id);
ChannelData *channel(const PeerId &id);
UserData *user(int32 user_id);
ChatData *chat(int32 chat_id);
ChannelData *channel(int32 channel_id);
UserData *self();
PeerData *peerByName(const QString &username);
QString peerName(const PeerData *peer, bool forDialogs = false);
PhotoData *photo(const PhotoId &photo);
PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 date, const ImagePtr &thumb, const ImagePtr &medium, const ImagePtr &full);
VideoData *video(const VideoId &video);
VideoData *videoSet(const VideoId &video, VideoData *convert, const uint64 &access, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size);
AudioData *audio(const AudioId &audio);
AudioData *audioSet(const AudioId &audio, AudioData *convert, const uint64 &access, int32 date, const QString &mime, int32 duration, int32 dc, int32 size);
DocumentData *document(const DocumentId &document);
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation);
WebPageData *webPage(const WebPageId &webPage);
WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill);
ImageLinkData *imageLink(const QString &imageLink);
ImageLinkData *imageLinkSet(const QString &imageLink, ImageLinkType type, const QString &url);
LocationData *location(const LocationCoords &coords);
void forgetMedia();
MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo);
@ -155,16 +161,27 @@ namespace App {
History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead);
History *historyLoaded(const PeerId &peer);
HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
inline History *history(const PeerData *peer) {
t_assert(peer != nullptr);
return history(peer->id);
}
inline History *historyLoaded(const PeerData *peer) {
return peer ? historyLoaded(peer->id) : nullptr;
}
inline HistoryItem *histItemById(const ChannelData *channel, MsgId itemId) {
return histItemById(channel ? peerToChannel(channel->id) : 0, itemId);
}
inline HistoryItem *histItemById(const FullMsgId &msgId) {
return histItemById(msgId.channel, msgId.msg);
}
void historyRegItem(HistoryItem *item);
void historyItemDetached(HistoryItem *item);
void historyUnregItem(HistoryItem *item);
void historyUpdateDependent(HistoryItem *item);
void historyClearMsgs();
void historyClearItems();
void historyRegReply(HistoryReply *reply, HistoryItem *to);
void historyUnregReply(HistoryReply *reply, HistoryItem *to);
void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency);
void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency);
void historyRegRandom(uint64 randomId, const FullMsgId &itemId);
void historyUnregRandom(uint64 randomId);
@ -202,9 +219,15 @@ namespace App {
bool isValidPhone(QString phone);
enum LaunchState {
Launched = 0,
QuitRequested = 1,
QuitProcessed = 2,
};
void quit();
bool quiting();
void setQuiting();
bool quitting();
LaunchState launchState();
void setLaunchState(LaunchState state);
QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0);
QImage readImage(const QString &file, QByteArray *format = 0, bool opaque = true, bool *animated = 0, QByteArray *content = 0);
@ -214,16 +237,6 @@ namespace App {
const PhotoItems &photoItems();
const PhotosData &photosData();
void regVideoItem(VideoData *data, HistoryItem *item);
void unregVideoItem(VideoData *data, HistoryItem *item);
const VideoItems &videoItems();
const VideosData &videosData();
void regAudioItem(AudioData *data, HistoryItem *item);
void unregAudioItem(AudioData*data, HistoryItem *item);
const AudioItems &audioItems();
const AudiosData &audiosData();
void regDocumentItem(DocumentData *data, HistoryItem *item);
void unregDocumentItem(DocumentData *data, HistoryItem *item);
const DocumentItems &documentItems();
@ -246,16 +259,10 @@ namespace App {
void unregMuted(PeerData *peer);
void updateMuted();
void regInlineResultLoader(FileLoader *loader, InlineResult *result);
void unregInlineResultLoader(FileLoader *loader);
InlineResult *inlineResultFromLoader(FileLoader *loader);
void feedReplyMarkup(ChannelId channelId, MsgId msgId, const MTPReplyMarkup &markup);
void clearReplyMarkup(ChannelId channelId, MsgId msgId);
const ReplyMarkup &replyMarkup(ChannelId channelId, MsgId msgId);
void setProxySettings(QNetworkAccessManager &manager);
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxy getHttpProxySettings();
#endif
void setProxySettings(QTcpSocket &socket);
QImage **cornersMask();

File diff suppressed because it is too large Load diff

View file

@ -16,35 +16,57 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QNetworkReply>
#include "window.h"
#include "pspecific.h"
class MainWidget;
class FileUploader;
class Translator;
class UpdateDownloader;
class Application : public PsApplication, public RPCSender {
class UpdateChecker;
class Application : public QApplication {
Q_OBJECT
public:
Application(int &argc, char **argv);
~Application();
static Application *app();
static Window *wnd();
static QString language();
static int32 languageId();
static MainWidget *main();
// Single instance application
public slots:
void socketConnected();
void socketError(QLocalSocket::LocalSocketError e);
void socketDisconnected();
void socketWritten(qint64 bytes);
void socketReading();
void newInstanceConnected();
void readClients();
void removeClients();
void startApplication(); // will be done in exec()
void closeApplication(); // will be done in aboutToQuit()
private:
typedef QPair<QLocalSocket*, QByteArray> LocalClient;
typedef QList<LocalClient> LocalClients;
QString _localServerName, _localSocketReadData;
QLocalServer _localServer;
QLocalSocket _localSocket;
LocalClients _localClients;
bool _secondInstance;
void singleInstanceChecked();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
// Autoupdating
public:
void startUpdateCheck(bool forceWait);
void stopUpdate();
enum UpdatingState {
UpdatingNone,
@ -52,11 +74,87 @@ public:
UpdatingReady,
};
UpdatingState updatingState();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
int32 updatingSize();
int32 updatingReady();
signals:
void updateChecking();
void updateLatest();
void updateProgress(qint64 ready, qint64 total);
void updateReady();
void updateFailed();
public slots:
void updateCheck();
void updateGotCurrent();
void updateFailedCurrent(QNetworkReply::NetworkError e);
void onUpdateReady();
void onUpdateFailed();
private:
SingleTimer _updateCheckTimer;
QNetworkReply *_updateReply;
QNetworkAccessManager _updateManager;
QThread *_updateThread;
UpdateChecker *_updateChecker;
#endif
};
namespace Sandbox {
QRect availableGeometry();
QRect screenGeometry(const QPoint &p);
void setActiveWindow(QWidget *window);
bool isSavingSession();
void installEventFilter(QObject *filter);
void execExternal(const QString &cmd);
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void startUpdateCheck();
void stopUpdate();
#endif
Application::UpdatingState updatingState();
int32 updatingSize();
int32 updatingReady();
void updateChecking();
void updateLatest();
void updateProgress(qint64 ready, qint64 total);
void updateFailed();
void updateReady();
#endif
void connect(const char *signal, QObject *object, const char *method);
void launch();
}
class MainWidget;
class FileUploader;
class Translator;
class AppClass : public QObject, public RPCSender {
Q_OBJECT
public:
AppClass();
~AppClass();
static AppClass *app();
static Window *wnd();
static MainWidget *main();
FileUploader *uploader();
void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
@ -85,14 +183,6 @@ public:
signals:
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void updateChecking();
void updateLatest();
void updateDownloading(qint64 ready, qint64 total);
void updateReady();
void updateFailed();
#endif
void peerPhotoDone(PeerId peer);
void peerPhotoFail(PeerId peer);
@ -100,31 +190,9 @@ signals:
public slots:
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void startUpdateCheck(bool forceWait = false);
#endif
void socketConnected();
void socketError(QLocalSocket::LocalSocketError e);
void socketDisconnected();
void socketWritten(qint64 bytes);
void socketReading();
void newInstanceConnected();
void closeApplication();
void doMtpUnpause();
void readClients();
void removeClients();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void updateGotCurrent();
void updateFailedCurrent(QNetworkReply::NetworkError e);
void onUpdateReady();
void onUpdateFailed();
#endif
void photoUpdated(const FullMsgId &msgId, const MTPInputFile &file);
void photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void onSwitchDebugMode();
void onSwitchTestMode();
@ -132,6 +200,8 @@ public slots:
void killDownloadSessions();
void onAppStateChanged(Qt::ApplicationState state);
void call_handleHistoryUpdate();
private:
QMap<FullMsgId, PeerId> photoUpdates;
@ -139,35 +209,12 @@ private:
QMap<int32, uint64> killDownloadSessionTimes;
SingleTimer killDownloadSessionsTimer;
void startApp();
uint64 _lastActionTime;
typedef QPair<QLocalSocket*, QByteArray> ClientSocket;
typedef QVector<ClientSocket> ClientSockets;
QString serverName;
QLocalSocket socket;
QString socketRead;
QLocalServer server;
ClientSockets clients;
bool closing;
uint64 lastActionTime;
void execExternal(const QString &cmd);
Window *window;
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
mtpRequestId updateRequestId;
QNetworkAccessManager updateManager;
QNetworkReply *updateReply;
SingleTimer updateCheckTimer;
QThread *updateThread;
UpdateDownloader *updateDownloader;
#endif
Window *_window;
FileUploader *_uploader;
Translator *_translator;
SingleTimer _mtpUnpauseTimer;
Translator *_translator;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 243 KiB

File diff suppressed because it is too large Load diff

View file

@ -16,11 +16,11 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "types.h"
#include "basic_types.h"
void audioInit();
bool audioWorks();
@ -56,7 +56,7 @@ public:
void play(const AudioMsgId &audio, int64 position = 0);
void play(const SongMsgId &song, int64 position = 0);
void pauseresume(MediaOverviewType type, bool fast = false);
void seek(int64 position); // type == OverviewDocuments
void seek(int64 position); // type == OverviewFiles
void stop(MediaOverviewType type);
void stopAndClear();
@ -201,8 +201,8 @@ signals:
void captureOnStart();
void captureOnStop(bool needResult);
void onDone(QByteArray data, qint32 samples);
void onUpdate(qint16 level, qint32 samples);
void onDone(QByteArray data, VoiceWaveform waveform, qint32 samples);
void onUpdate(quint16 level, qint32 samples);
void onError();
private:
@ -338,8 +338,8 @@ public:
signals:
void error();
void update(qint16 level, qint32 samples);
void done(QByteArray data, qint32 samples);
void update(quint16 level, qint32 samples);
void done(QByteArray data, VoiceWaveform waveform, qint32 samples);
public slots:
@ -360,3 +360,4 @@ private:
};
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat);
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data);

View file

@ -16,13 +16,26 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "autoupdater.h"
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#ifdef Q_OS_WIN // use Lzma SDK for win
#include <LzmaLib.h>
#else // Q_OS_WIN
#include <lzma.h>
#endif // else of Q_OS_WIN
#include "application.h"
#include "pspecific.h"
#include "autoupdater.h"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
@ -34,7 +47,7 @@ typedef int VerInt;
typedef wchar_t VerChar;
#endif
UpdateDownloader::UpdateDownloader(QThread *thread, const QString &url) : reply(0), already(0), full(0) {
UpdateChecker::UpdateChecker(QThread *thread, const QString &url) : reply(0), already(0), full(0) {
updateUrl = url;
moveToThread(thread);
manager.moveToThread(thread);
@ -44,14 +57,14 @@ UpdateDownloader::UpdateDownloader(QThread *thread, const QString &url) : reply(
initOutput();
}
void UpdateDownloader::initOutput() {
void UpdateChecker::initOutput() {
QString fileName;
QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl);
if (m.hasMatch()) {
fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString());
}
if (fileName.isEmpty()) {
fileName = qsl("tupdate-%1").arg(MTP::nonce<uint32>() % 1000000);
fileName = qsl("tupdate-%1").arg(rand_value<uint32>() % 1000000);
}
QString dirStr = cWorkingDir() + qsl("tupdates/");
fileName = dirStr + fileName;
@ -99,11 +112,11 @@ void UpdateDownloader::initOutput() {
}
}
void UpdateDownloader::start() {
void UpdateChecker::start() {
sendRequest();
}
void UpdateDownloader::sendRequest() {
void UpdateChecker::sendRequest() {
QNetworkRequest req(updateUrl);
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";
req.setRawHeader("Range", rangeHeaderValue);
@ -115,7 +128,7 @@ void UpdateDownloader::sendRequest() {
connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot()));
}
void UpdateDownloader::partMetaGot() {
void UpdateChecker::partMetaGot() {
typedef QList<QNetworkReply::RawHeaderPair> Pairs;
Pairs pairs = reply->rawHeaderPairs();
for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) {
@ -126,23 +139,24 @@ void UpdateDownloader::partMetaGot() {
QMutexLocker lock(&mutex);
full = m.captured(1).toInt();
}
emit App::app()->updateDownloading(already, full);
Sandbox::updateProgress(already, full);
}
}
}
}
int32 UpdateDownloader::ready() {
int32 UpdateChecker::ready() {
QMutexLocker lock(&mutex);
return already;
}
int32 UpdateDownloader::size() {
int32 UpdateChecker::size() {
QMutexLocker lock(&mutex);
return full;
}
void UpdateDownloader::partFinished(qint64 got, qint64 total) {
void UpdateChecker::partFinished(qint64 got, qint64 total) {
if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
@ -179,11 +193,11 @@ void UpdateDownloader::partFinished(qint64 got, qint64 total) {
outputFile.close();
unpackUpdate();
} else {
emit App::app()->updateDownloading(already, full);
Sandbox::updateProgress(already, full);
}
}
void UpdateDownloader::partFailed(QNetworkReply::NetworkError e) {
void UpdateChecker::partFailed(QNetworkReply::NetworkError e) {
if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
@ -198,15 +212,15 @@ void UpdateDownloader::partFailed(QNetworkReply::NetworkError e) {
}
}
LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e));
emit App::app()->updateFailed();
Sandbox::updateFailed();
}
void UpdateDownloader::fatalFail() {
void UpdateChecker::fatalFail() {
clearAll();
emit App::app()->updateFailed();
Sandbox::updateFailed();
}
void UpdateDownloader::clearAll() {
void UpdateChecker::clearAll() {
psDeleteDir(cWorkingDir() + qsl("tupdates"));
}
@ -225,7 +239,7 @@ void UpdateDownloader::clearAll() {
// return QString::fromWCharArray(errMsg);
//}
void UpdateDownloader::unpackUpdate() {
void UpdateChecker::unpackUpdate() {
QByteArray packed;
if (!outputFile.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read updates file!"));
@ -465,10 +479,10 @@ void UpdateDownloader::unpackUpdate() {
}
outputFile.remove();
emit App::app()->updateReady();
Sandbox::updateReady();
}
UpdateDownloader::~UpdateDownloader() {
UpdateChecker::~UpdateChecker() {
delete reply;
reply = 0;
}
@ -477,7 +491,7 @@ bool checkReadyUpdate() {
QString readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"), readyPath = cWorkingDir() + qsl("tupdates/temp");
if (!QFile(readyFilePath).exists()) {
if (QDir(cWorkingDir() + qsl("tupdates/ready")).exists() || QDir(cWorkingDir() + qsl("tupdates/temp")).exists()) {
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
}
return false;
}
@ -488,30 +502,30 @@ bool checkReadyUpdate() {
QFile fVersion(versionPath);
if (!fVersion.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read version file '%1'").arg(versionPath));
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
VerInt versionNum;
if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) {
LOG(("Update Error: cant read version from file '%1'").arg(versionPath));
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
if (versionNum == 0x7FFFFFFF) { // beta version
quint64 betaVersion = 0;
if (fVersion.read((char*)&betaVersion, sizeof(quint64)) != sizeof(quint64)) {
LOG(("Update Error: cant read beta version from file '%1'").arg(versionPath));
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
if (!cBetaVersion() || betaVersion <= cBetaVersion()) {
LOG(("Update Error: cant install beta version %1 having beta version %2").arg(betaVersion).arg(cBetaVersion()));
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
} else if (versionNum <= AppVersion) {
LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion));
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
fVersion.close();
@ -530,11 +544,11 @@ bool checkReadyUpdate() {
if (!updater.exists()) {
QFileInfo current(curUpdater);
if (!current.exists()) {
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) {
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
}
@ -545,24 +559,24 @@ bool checkReadyUpdate() {
cSetWriteProtected(true);
return true;
} else {
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
}
if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) {
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
#elif defined Q_OS_MAC
QDir().mkpath(QFileInfo(curUpdater).absolutePath());
DEBUG_LOG(("Update Info: moving %1 to %2..").arg(updater.absoluteFilePath()).arg(curUpdater));
DEBUG_LOG(("Update Info: moving %1 to %2...").arg(updater.absoluteFilePath()).arg(curUpdater));
if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) {
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
#elif defined Q_OS_LINUX
if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) {
UpdateDownloader::clearAll();
UpdateChecker::clearAll();
return false;
}
#endif

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -26,11 +26,11 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QNetworkReply>
class UpdateDownloader : public QObject {
class UpdateChecker : public QObject {
Q_OBJECT
public:
UpdateDownloader(QThread *thread, const QString &url);
UpdateChecker(QThread *thread, const QString &url);
void unpackUpdate();
@ -39,7 +39,7 @@ public:
static void clearAll();
~UpdateDownloader();
~UpdateChecker();
public slots:
@ -66,6 +66,11 @@ private:
bool checkReadyUpdate();
#else
class UpdateChecker : public QObject {
Q_OBJECT
};
#endif
QString countBetaVersionSignature(uint64 version);

View file

@ -16,10 +16,20 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "basic_types.h"
#include <openssl/crypto.h>
#include <openssl/sha.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#include "application.h"
uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
@ -35,6 +45,10 @@ uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
// Base types compile-time check
#ifdef TDESKTOP_CUSTOM_NULLPTR
NullPointerClass nullptr;
#endif
namespace {
template <typename T, int N>
class _TypeSizeCheckerHelper {
@ -106,8 +120,8 @@ namespace {
}
}
int32 myunixtime() {
return (int32)time(NULL);
TimeId myunixtime() {
return (TimeId)time(NULL);
}
void unixtimeInit() {
@ -135,19 +149,19 @@ void unixtimeSet(int32 serverTime, bool force) {
_initMsgIdConstants();
}
int32 unixtime() {
int32 result = myunixtime();
TimeId unixtime() {
TimeId result = myunixtime();
QReadLocker locker(&unixtimeLock);
return result + unixtimeDelta;
}
int32 fromServerTime(const MTPint &serverTime) {
TimeId fromServerTime(const MTPint &serverTime) {
QReadLocker locker(&unixtimeLock);
return serverTime.v - unixtimeDelta;
}
MTPint toServerTime(const int32 &clientTime) {
MTPint toServerTime(const TimeId &clientTime) {
QReadLocker locker(&unixtimeLock);
return MTP_int(clientTime + unixtimeDelta);
}
@ -187,6 +201,32 @@ namespace {
delete l;
}
int _ffmpegLockManager(void **mutex, AVLockOp op) {
switch (op) {
case AV_LOCK_CREATE: {
t_assert(*mutex == 0);
*mutex = reinterpret_cast<void*>(new QMutex());
} break;
case AV_LOCK_OBTAIN: {
t_assert(*mutex != 0);
reinterpret_cast<QMutex*>(*mutex)->lock();
} break;
case AV_LOCK_RELEASE: {
t_assert(*mutex != 0);
reinterpret_cast<QMutex*>(*mutex)->unlock();
}; break;
case AV_LOCK_DESTROY: {
t_assert(*mutex != 0);
delete reinterpret_cast<QMutex*>(*mutex);
*mutex = 0;
} break;
}
return 0;
}
float64 _msFreq;
float64 _msgIdCoef;
int64 _msStart = 0, _msAddToMsStart = 0, _msAddToUnixtime = 0;
@ -238,36 +278,51 @@ namespace {
_MsStarter _msStarter;
}
InitOpenSSL::InitOpenSSL() {
if (!RAND_status()) { // should be always inited in all modern OS
char buf[16];
memcpy(buf, &_msStart, 8);
memcpy(buf + 8, &_msFreq, 8);
uchar sha256Buffer[32];
RAND_seed(hashSha256(buf, 16, sha256Buffer), 32);
if (!RAND_status()) {
LOG(("MTP Error: Could not init OpenSSL rand, RAND_status() is 0.."));
namespace ThirdParty {
void start() {
PlatformSpecific::ThirdParty::start();
if (!RAND_status()) { // should be always inited in all modern OS
char buf[16];
memcpy(buf, &_msStart, 8);
memcpy(buf + 8, &_msFreq, 8);
uchar sha256Buffer[32];
RAND_seed(hashSha256(buf, 16, sha256Buffer), 32);
if (!RAND_status()) {
LOG(("MTP Error: Could not init OpenSSL rand, RAND_status() is 0..."));
}
}
int32 numLocks = CRYPTO_num_locks();
if (numLocks) {
_sslLocks = new QMutex[numLocks];
CRYPTO_set_locking_callback(_sslLockingCallback);
} else {
LOG(("MTP Error: Could not init OpenSSL threads, CRYPTO_num_locks() returned zero!"));
}
CRYPTO_THREADID_set_callback(_sslThreadId);
CRYPTO_set_dynlock_create_callback(_sslCreateFunction);
CRYPTO_set_dynlock_lock_callback(_sslLockFunction);
CRYPTO_set_dynlock_destroy_callback(_sslDestroyFunction);
av_register_all();
avcodec_register_all();
av_lockmgr_register(_ffmpegLockManager);
_sslInited = true;
}
int32 numLocks = CRYPTO_num_locks();
if (numLocks) {
_sslLocks = new QMutex[numLocks];
CRYPTO_set_locking_callback(_sslLockingCallback);
} else {
LOG(("MTP Error: Could not init OpenSSL threads, CRYPTO_num_locks() returned zero!"));
void finish() {
av_lockmgr_register(0);
delete[] _sslLocks;
_sslLocks = 0;
PlatformSpecific::ThirdParty::finish();
}
CRYPTO_THREADID_set_callback(_sslThreadId);
CRYPTO_set_dynlock_create_callback(_sslCreateFunction);
CRYPTO_set_dynlock_lock_callback(_sslLockFunction);
CRYPTO_set_dynlock_destroy_callback(_sslDestroyFunction);
_sslInited = true;
}
InitOpenSSL::~InitOpenSSL() {
delete[] _sslLocks;
_sslLocks = 0;
}
bool checkms() {
@ -640,10 +695,7 @@ char *hashMd5Hex(const int32 *hashmd5, void *dest) {
}
void memset_rand(void *data, uint32 len) {
if (!_sslInited) {
LOG(("Critical Error: memset_rand() called before OpenSSL init!"));
exit(-1);
}
t_assert(_sslInited);
RAND_bytes((uchar*)data, len);
}
@ -777,8 +829,7 @@ QString translitRusEng(const QString &rus) {
result.reserve(rus.size() * 2);
int32 toSkip = 0;
for (QString::const_iterator i = rus.cbegin(), e = rus.cend(); i != e;) {
i += toSkip;
for (QString::const_iterator i = rus.cbegin(), e = rus.cend(); i != e; i += toSkip) {
result += translitLetterRusEng(*i, (i + 1 == e) ? ' ' : *(i + 1), toSkip);
}
return result;
@ -982,3 +1033,33 @@ MimeType mimeTypeForData(const QByteArray &data) {
}
return MimeType(QMimeDatabase().mimeTypeForData(data));
}
struct ComposerMetadatasMap {
QMap<uint64, ComposerMetadata*> data;
~ComposerMetadatasMap() {
for_const (const ComposerMetadata *p, data) {
delete p;
}
}
};
const ComposerMetadata *GetComposerMetadata(uint64 mask) {
static ComposerMetadatasMap ComposerMetadatas;
static QMutex ComposerMetadatasMutex;
QMutexLocker lock(&ComposerMetadatasMutex);
auto i = ComposerMetadatas.data.constFind(mask);
if (i == ComposerMetadatas.data.cend()) {
ComposerMetadata *meta = new ComposerMetadata(mask);
t_assert(meta != nullptr);
i = ComposerMetadatas.data.insert(mask, meta);
}
return i.value();
}
const ComposerMetadata *Composer::ZeroComposerMetadata = GetComposerMetadata(0);
ComponentWrapStruct ComponentWraps[64];
QAtomicInt ComponentIndexLast;

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -44,6 +44,8 @@ AboutBox::AboutBox() : AbstractBox(st::aboutWidth)
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
prepare();
setAcceptDrops(true);
}
void AboutBox::hideAll() {
@ -82,7 +84,7 @@ void AboutBox::onVersion() {
}
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(countBetaVersionSignature(cRealBetaVersion())));
App::app()->clipboard()->setText(url);
Application::clipboard()->setText(url);
Ui::showLayer(new InformBox("The link to the current private beta version of Telegram Desktop was copied to the clipboard."));
} else {
@ -105,10 +107,39 @@ void AboutBox::paintEvent(QPaintEvent *e) {
paintTitle(p, qsl("Telegram Desktop"));
}
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
QString _getCrashReportFile(const QMimeData *m) {
if (!m || m->urls().size() != 1) return QString();
QString file(m->urls().at(0).toLocalFile());
if (file.startsWith(qsl("/.file/id="))) file = psConvertFileUrl(file);
return file.endsWith(qstr(".telegramcrash"), Qt::CaseInsensitive) ? file : QString();
}
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
void AboutBox::dragEnterEvent(QDragEnterEvent *e) {
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
if (!_getCrashReportFile(e->mimeData()).isEmpty()) {
e->setDropAction(Qt::CopyAction);
e->accept();
}
#endif
}
void AboutBox::dropEvent(QDropEvent *e) {
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
if (!_getCrashReportFile(e->mimeData()).isEmpty()) {
e->acceptProposedAction();
showCrashReportWindow(_getCrashReportFile(e->mimeData()));
}
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
}
QString telegramFaqLink() {
QString result = qsl("https://telegram.org/faq");
if (cLang() > languageDefault && cLang() < languageCount) {
const char *code = LanguageCodes[cLang()];
const char *code = LanguageCodes[cLang()].c_str();
if (qstr("de") == code || qstr("es") == code || qstr("it") == code || qstr("ko") == code) {
result += qsl("/") + code;
} else if (qstr("pt_BR") == code) {

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -32,6 +32,9 @@ public:
void keyPressEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e);
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
public slots:
void onVersion();

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -178,6 +178,14 @@ void AbstractBox::resizeMaxHeight(int32 newWidth, int32 maxHeight) {
_maxHeight = maxHeight;
resize(newWidth, countHeight());
if (parentWidget()) {
QRect r = geometry();
int32 parenth = parentWidget()->height();
if (r.top() + r.height() + st::boxVerticalMargin > parenth) {
int32 newTop = qMax(parenth - int(st::boxVerticalMargin) - r.height(), (parenth - r.height()) / 2);
if (newTop != r.top()) {
move(r.left(), newTop);
}
}
parentWidget()->update(geometry().united(g).marginsAdded(QMargins(st::boxShadow.pxWidth(), st::boxShadow.pxHeight(), st::boxShadow.pxWidth(), st::boxShadow.pxHeight())));
}
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -188,11 +188,11 @@ void AddContactBox::onSave() {
}
_sentName = firstName;
if (_user) {
_contactId = MTP::nonce<uint64>();
_contactId = rand_value<uint64>();
QVector<MTPInputContact> v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_user->phone), MTP_string(firstName), MTP_string(lastName)));
_addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector<MTPInputContact>(v), MTP_bool(false)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveUserFail));
} else {
_contactId = MTP::nonce<uint64>();
_contactId = rand_value<uint64>();
QVector<MTPInputContact> v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(phone), MTP_string(firstName), MTP_string(lastName)));
_addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector<MTPInputContact>(v), MTP_bool(false)), rpcDone(&AddContactBox::onImportDone));
}
@ -224,18 +224,15 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
App::feedUsers(d.vusers);
const QVector<MTPImportedContact> &v(d.vimported.c_vector().v);
int32 uid = 0;
UserData *user = nullptr;
if (!v.isEmpty()) {
const MTPDimportedContact &c(v.front().c_importedContact());
if (c.vclient_id.v != _contactId) return;
uid = c.vuser_id.v;
if (uid && !App::userLoaded(uid)) {
uid = 0;
}
user = App::userLoaded(c.vuser_id.v);
}
if (uid) {
Notify::userIsContactChanged(App::userLoaded(peerFromUser(uid)), true);
if (user) {
Notify::userIsContactChanged(user, true);
Ui::hideLayer();
} else {
_save.hide();
@ -275,7 +272,7 @@ NewGroupBox::NewGroupBox() : AbstractBox(),
_group(this, qsl("group_type"), 0, lang(lng_create_group_title), true),
_channel(this, qsl("group_type"), 1, lang(lng_create_channel_title)),
_aboutGroupWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x()),
_aboutGroup(st::normalFont, lng_create_group_about(lt_count, cMaxGroupCount()), _defaultOptions, _aboutGroupWidth),
_aboutGroup(st::normalFont, lng_create_group_about(lt_count, Global::MegagroupSizeMax()), _defaultOptions, _aboutGroupWidth),
_aboutChannel(st::normalFont, lang(lng_create_channel_about), _defaultOptions, _aboutGroupWidth),
_next(this, lang(lng_create_group_next), st::defaultBoxButton),
_cancel(this, lang(lng_cancel), st::cancelBoxButton) {
@ -499,8 +496,8 @@ void GroupInfoBox::onNext() {
Ui::showLayer(new ContactsBox(title, _photoBig), KeepOtherLayers);
} else {
bool mega = false;
int32 flags = mega ? MTPchannels_CreateChannel::flag_megagroup : MTPchannels_CreateChannel::flag_broadcast;
_creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(flags), MTP_string(title), MTP_string(description)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail));
MTPchannels_CreateChannel::Flags flags = mega ? MTPchannels_CreateChannel::Flag::f_megagroup : MTPchannels_CreateChannel::Flag::f_broadcast;
_creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_flags(flags), MTP_string(title), MTP_string(description)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail));
}
}
@ -540,6 +537,9 @@ bool GroupInfoBox::creationFail(const RPCError &error) {
_title.setFocus();
_title.showError();
return true;
} else if (error.type() == qstr("USER_RESTRICTED")) {
Ui::showLayer(new InformBox(lang(lng_cant_do_this)));
return true;
}
return false;
}
@ -605,12 +605,12 @@ void GroupInfoBox::onPhotoReady(const QImage &img) {
SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : AbstractBox()
, _channel(channel)
, _existing(existing)
, _public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true)
, _private(this, qsl("channel_privacy"), 1, lang(lng_create_private_channel_title))
, _public(this, qsl("channel_privacy"), 0, lang(channel->isMegagroup() ? lng_create_public_group_title : lng_create_public_channel_title), true)
, _private(this, qsl("channel_privacy"), 1, lang(channel->isMegagroup() ? lng_create_private_group_title : lng_create_private_channel_title))
, _comments(this, lang(lng_create_channel_comments), false)
, _aboutPublicWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x())
, _aboutPublic(st::normalFont, lang(lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth)
, _aboutPrivate(st::normalFont, lang(lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth)
, _aboutPublic(st::normalFont, lang(channel->isMegagroup() ? lng_create_public_group_about : lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth)
, _aboutPrivate(st::normalFont, lang(channel->isMegagroup() ? lng_create_private_group_about : lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth)
, _aboutComments(st::normalFont, lang(lng_create_channel_comments_about), _defaultOptions, _aboutPublicWidth)
, _link(this, st::defaultInputField, QString(), channel->username, true)
, _linkOver(false)
@ -626,7 +626,7 @@ SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : Abstract
_checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail));
_aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth);
setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom());
updateMaxHeight();
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose()));
@ -669,6 +669,14 @@ void SetupChannelBox::showDone() {
_link.setFocus();
}
void SetupChannelBox::updateMaxHeight() {
if (!_channel->isMegagroup() || _public.checked()) {
setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom());
} else {
setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupSkip + st::newGroupPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom());
}
}
void SetupChannelBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (_link.hasFocus()) {
@ -699,22 +707,26 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) {
//QRect aboutComments(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _comments.y() + _comments.height(), _aboutPublicWidth, _aboutPublicHeight);
//_aboutComments.drawLeft(p, aboutComments.x(), aboutComments.y(), aboutComments.width(), width());
p.setPen(st::black);
p.setFont(st::newGroupLinkFont);
p.drawTextLeft(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultInputField.textMargins.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link.isHidden() ? lng_create_group_invite_link : lng_create_group_link));
if (!_channel->isMegagroup() || !_link.isHidden()) {
p.setPen(st::black);
p.setFont(st::newGroupLinkFont);
p.drawTextLeft(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultInputField.textMargins.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link.isHidden() ? lng_create_group_invite_link : lng_create_group_link));
}
if (_link.isHidden()) {
QTextOption option(style::al_left);
option.setWrapMode(QTextOption::WrapAnywhere);
p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont);
p.setPen(st::btnDefLink.color);
p.drawText(_invitationLink, _channel->invitationUrl, option);
if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) {
p.setOpacity(a_goodOpacity.current());
p.setPen(st::setGoodColor);
p.setFont(st::boxTextFont);
p.drawTextRight(st::boxPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink);
p.setOpacity(1);
if (!_channel->isMegagroup()) {
QTextOption option(style::al_left);
option.setWrapMode(QTextOption::WrapAnywhere);
p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont);
p.setPen(st::btnDefLink.color);
p.drawText(_invitationLink, _channel->invitationUrl, option);
if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) {
p.setOpacity(a_goodOpacity.current());
p.setPen(st::setGoodColor);
p.setFont(st::boxTextFont);
p.drawTextRight(st::boxPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink);
p.setOpacity(1);
}
}
} else {
if (!_errorText.isEmpty()) {
@ -750,7 +762,7 @@ void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) {
void SetupChannelBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e);
if (_linkOver) {
App::app()->clipboard()->setText(_channel->invitationUrl);
Application::clipboard()->setText(_channel->invitationUrl);
_goodTextLink = lang(lng_create_channel_link_copied);
a_goodOpacity = anim::fvalue(1, 0);
_a_goodFade.start();
@ -827,7 +839,7 @@ void SetupChannelBox::onChange() {
}
_checkTimer.stop();
} else {
int32 i, len = name.size();
int32 len = name.size();
for (int32 i = 0; i < len; ++i) {
QChar ch = name.at(i);
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') {
@ -879,6 +891,9 @@ void SetupChannelBox::onPrivacyChange() {
_link.hide();
setFocus();
}
if (_channel->isMegagroup()) {
updateMaxHeight();
}
update();
}
@ -929,7 +944,10 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) {
_checkRequestId = 0;
QString err(error.type());
if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") {
if (err == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
Ui::hideLayer();
return true;
} else if (err == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
if (_existing) {
Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
} else {
@ -938,11 +956,11 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) {
onPrivacyChange();
}
return true;
} else if (err == "USERNAME_INVALID") {
} else if (err == qstr("USERNAME_INVALID")) {
_errorText = lang(lng_create_channel_link_invalid);
update();
return true;
} else if (err == "USERNAME_OCCUPIED" && _checkUsername != _channel->username) {
} else if (err == qstr("USERNAME_OCCUPIED") && _checkUsername != _channel->username) {
_errorText = lang(lng_create_channel_link_occupied);
update();
return true;
@ -957,7 +975,10 @@ bool SetupChannelBox::onFirstCheckFail(const RPCError &error) {
_checkRequestId = 0;
QString err(error.type());
if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") {
if (err == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
Ui::hideLayer();
return true;
} else if (err == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
if (_existing) {
Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
} else {
@ -1094,7 +1115,8 @@ void EditNameTitleBox::onSave() {
}
_sentName = first;
if (_peer == App::self()) {
_requestId = MTP::send(MTPaccount_UpdateProfile(MTP_string(first), MTP_string(last)), rpcDone(&EditNameTitleBox::onSaveSelfDone), rpcFail(&EditNameTitleBox::onSaveSelfFail));
MTPaccount_UpdateProfile::Flags flags = MTPaccount_UpdateProfile::Flag::f_first_name | MTPaccount_UpdateProfile::Flag::f_last_name;
_requestId = MTP::send(MTPaccount_UpdateProfile(MTP_flags(flags), MTP_string(first), MTP_string(last), MTPstring()), rpcDone(&EditNameTitleBox::onSaveSelfDone), rpcFail(&EditNameTitleBox::onSaveSelfFail));
} else if (_peer->isChat()) {
_requestId = MTP::send(MTPmessages_EditChatTitle(_peer->asChat()->inputChat, MTP_string(first)), rpcDone(&EditNameTitleBox::onSaveChatDone), rpcFail(&EditNameTitleBox::onSaveChatFail));
}
@ -1150,14 +1172,17 @@ void EditNameTitleBox::onSaveChatDone(const MTPUpdates &updates) {
emit closed();
}
EditChannelBox::EditChannelBox(ChannelData *channel) :
_channel(channel),
_save(this, lang(lng_settings_save), st::defaultBoxButton),
_cancel(this, lang(lng_cancel), st::cancelBoxButton),
_title(this, st::defaultInputField, lang(lng_dlg_new_channel_name), _channel->name),
_description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about),
_publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::defaultBoxLinkButton),
_saveTitleRequestId(0), _saveDescriptionRequestId(0) {
EditChannelBox::EditChannelBox(ChannelData *channel) : AbstractBox()
, _channel(channel)
, _save(this, lang(lng_settings_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _title(this, st::defaultInputField, lang(lng_dlg_new_channel_name), _channel->name)
, _description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about)
, _sign(this, lang(lng_edit_sign_messages), channel->addsSignature())
, _publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::defaultBoxLinkButton)
, _saveTitleRequestId(0)
, _saveDescriptionRequestId(0)
, _saveSignRequestId(0) {
connect(App::main(), SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(peerUpdated(PeerData*)));
setMouseTracking(true);
@ -1183,6 +1208,7 @@ _saveTitleRequestId(0), _saveDescriptionRequestId(0) {
void EditChannelBox::hideAll() {
_title.hide();
_description.hide();
_sign.hide();
_save.hide();
_cancel.hide();
_publicLink.hide();
@ -1193,10 +1219,15 @@ void EditChannelBox::showAll() {
_description.show();
_save.show();
_cancel.show();
if (_channel->isMegagroup()) {
_publicLink.hide();
} else {
if (_channel->canEditUsername()) {
_publicLink.show();
} else {
_publicLink.hide();
}
if (_channel->isMegagroup()) {
_sign.hide();
} else {
_sign.show();
}
}
@ -1224,6 +1255,7 @@ void EditChannelBox::paintEvent(QPaintEvent *e) {
void EditChannelBox::peerUpdated(PeerData *peer) {
if (peer == _channel) {
_publicLink.setText(lang(_channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link));
_sign.setChecked(_channel->addsSignature());
}
}
@ -1235,7 +1267,12 @@ void EditChannelBox::onDescriptionResized() {
void EditChannelBox::updateMaxHeight() {
int32 h = st::boxTitleHeight + st::newGroupInfoPadding.top() + _title.height();
h += st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom();
h += st::newGroupPublicLinkPadding.top() + _publicLink.height() + st::newGroupPublicLinkPadding.bottom();
if (!_channel->isMegagroup()) {
h += st::newGroupPublicLinkPadding.top() + _sign.height() + st::newGroupPublicLinkPadding.bottom();
}
if (_channel->canEditUsername()) {
h += st::newGroupPublicLinkPadding.top() + _publicLink.height() + st::newGroupPublicLinkPadding.bottom();
}
h += st::boxPadding.bottom() + st::newGroupInfoPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom();
setMaxHeight(h);
}
@ -1246,14 +1283,20 @@ void EditChannelBox::resizeEvent(QResizeEvent *e) {
_description.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _title.y() + _title.height() + st::newGroupDescriptionPadding.top());
_publicLink.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description.y() + _description.height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
_sign.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description.y() + _description.height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
if (_channel->isMegagroup()) {
_publicLink.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description.y() + _description.height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
} else {
_publicLink.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _sign.y() + _sign.height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
}
_save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y());
}
void EditChannelBox::onSave() {
if (_saveTitleRequestId || _saveDescriptionRequestId) return;
if (_saveTitleRequestId || _saveDescriptionRequestId || _saveSignRequestId) return;
QString title = prepareText(_title.getLastText()), description = prepareText(_description.getLastText(), true);
if (title.isEmpty()) {
@ -1263,7 +1306,11 @@ void EditChannelBox::onSave() {
}
_sentTitle = title;
_sentDescription = description;
_saveTitleRequestId = MTP::send(MTPchannels_EditTitle(_channel->inputChannel, MTP_string(_sentTitle)), rpcDone(&EditChannelBox::onSaveTitleDone), rpcFail(&EditChannelBox::onSaveFail));
if (_sentTitle == _channel->name) {
saveDescription();
} else {
_saveTitleRequestId = MTP::send(MTPchannels_EditTitle(_channel->inputChannel, MTP_string(_sentTitle)), rpcDone(&EditChannelBox::onSaveTitleDone), rpcFail(&EditChannelBox::onSaveFail));
}
}
void EditChannelBox::onPublicLink() {
@ -1271,7 +1318,19 @@ void EditChannelBox::onPublicLink() {
}
void EditChannelBox::saveDescription() {
_saveDescriptionRequestId = MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail));
if (_sentDescription == _channel->about) {
saveSign();
} else {
_saveDescriptionRequestId = MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail));
}
}
void EditChannelBox::saveSign() {
if (_channel->isMegagroup() || _channel->addsSignature() == _sign.checked()) {
onClose();
} else {
_saveSignRequestId = MTP::send(MTPchannels_ToggleSignatures(_channel->inputChannel, MTP_bool(_sign.checked())), rpcDone(&EditChannelBox::onSaveSignDone), rpcFail(&EditChannelBox::onSaveFail));
}
}
bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) {
@ -1295,24 +1354,46 @@ bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) {
_saveDescriptionRequestId = 0;
if (err == qstr("CHAT_ABOUT_NOT_MODIFIED")) {
_channel->about = _sentDescription;
if (App::api()) emit App::api()->fullPeerUpdated(_channel);
onClose();
if (App::api()) {
emit App::api()->fullPeerUpdated(_channel);
}
saveSign();
return true;
} else {
_description.setFocus();
}
} else if (req == _saveSignRequestId) {
_saveSignRequestId = 0;
if (err == qstr("CHAT_NOT_MODIFIED")) {
onClose();
return true;
}
}
return true;
}
void EditChannelBox::onSaveTitleDone(const MTPUpdates &updates) {
_saveTitleRequestId = 0;
App::main()->sentUpdatesReceived(updates);
if (App::main()) {
App::main()->sentUpdatesReceived(updates);
}
saveDescription();
}
void EditChannelBox::onSaveDescriptionDone(const MTPBool &result) {
_saveDescriptionRequestId = 0;
_channel->about = _sentDescription;
if (App::api()) emit App::api()->fullPeerUpdated(_channel);
if (App::api()) {
emit App::api()->fullPeerUpdated(_channel);
}
saveSign();
}
void EditChannelBox::onSaveSignDone(const MTPUpdates &updates) {
_saveSignRequestId = 0;
if (App::main()) {
App::main()->sentUpdatesReceived(updates);
}
onClose();
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -211,6 +211,8 @@ private:
bool onCheckFail(const RPCError &error);
bool onFirstCheckFail(const RPCError &error);
void updateMaxHeight();
ChannelData *_channel;
bool _existing;
@ -315,18 +317,21 @@ private:
void onSaveTitleDone(const MTPUpdates &updates);
void onSaveDescriptionDone(const MTPBool &result);
void onSaveSignDone(const MTPUpdates &updates);
bool onSaveFail(const RPCError &e, mtpRequestId req);
void saveDescription();
void saveSign();
ChannelData *_channel;
BoxButton _save, _cancel;
InputField _title;
InputArea _description;
Checkbox _sign;
LinkButton _publicLink;
mtpRequestId _saveTitleRequestId, _saveDescriptionRequestId;
mtpRequestId _saveTitleRequestId, _saveDescriptionRequestId, _saveSignRequestId;
QString _sentTitle, _sentDescription;
};

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -34,19 +34,19 @@ TextParseOptions _confirmBoxTextOptions = {
Qt::LayoutDirectionAuto, // dir
};
ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style::BoxButton &doneStyle, const QString &cancelText, const style::BoxButton &cancelStyle) : AbstractBox(st::boxWidth),
_informative(false),
_text(100),
_confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle),
_cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, cancelStyle) {
ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style::BoxButton &doneStyle, const QString &cancelText, const style::BoxButton &cancelStyle) : AbstractBox(st::boxWidth)
, _informative(false)
, _text(100)
, _confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle)
, _cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, cancelStyle) {
init(text);
}
ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style::BoxButton &doneStyle, bool informative) : AbstractBox(st::boxWidth),
_informative(true),
_text(100),
_confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle),
_cancel(this, QString(), st::cancelBoxButton) {
ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style::BoxButton &doneStyle, bool informative) : AbstractBox(st::boxWidth)
, _informative(true)
, _text(100)
, _confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle)
, _cancel(this, QString(), st::cancelBoxButton) {
init(text);
}
@ -83,33 +83,30 @@ void ConfirmBox::mouseMoveEvent(QMouseEvent *e) {
void ConfirmBox::mousePressEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
if (textlnkOver()) {
textlnkDown(textlnkOver());
update();
}
ClickHandler::pressed();
return LayeredWidget::mousePressEvent(e);
}
void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
updateHover();
if (textlnkOver() && textlnkOver() == textlnkDown()) {
if (ClickHandlerPtr activated = ClickHandler::unpressed()) {
Ui::hideLayer();
textlnkOver()->onClick(e->button());
App::activateClickHandler(activated, e->button());
}
textlnkDown(TextLinkPtr());
}
void ConfirmBox::leaveEvent(QEvent *e) {
if (_myLink) {
if (textlnkOver() == _myLink) {
textlnkOver(TextLinkPtr());
update();
}
_myLink = TextLinkPtr();
setCursor(style::cur_default);
update();
}
ClickHandler::clearActive(this);
}
void ConfirmBox::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
setCursor(active ? style::cur_pointer : style::cur_default);
update();
}
void ConfirmBox::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
update();
}
void ConfirmBox::updateLink() {
@ -119,17 +116,12 @@ void ConfirmBox::updateLink() {
void ConfirmBox::updateHover() {
QPoint m(mapFromGlobal(_lastMousePos));
bool wasMy = (_myLink == textlnkOver());
textstyleSet(&st::boxTextStyle);
_myLink = _text.linkLeft(m.x() - st::boxPadding.left(), m.y() - st::boxPadding.top(), _textWidth, width(), (_text.maxWidth() < width()) ? style::al_center : style::al_left);
ClickHandlerPtr handler = _text.linkLeft(m.x() - st::boxPadding.left(), m.y() - st::boxPadding.top(), _textWidth, width(), style::al_left);
textstyleRestore();
if (_myLink != textlnkOver()) {
if (wasMy || _myLink || rect().contains(m)) {
textlnkOver(_myLink);
}
setCursor(_myLink ? style::cur_pointer : style::cur_default);
update();
}
ClickHandler::setActive(handler, this);
}
void ConfirmBox::closePressed() {
@ -174,22 +166,29 @@ void ConfirmBox::resizeEvent(QResizeEvent *e) {
_cancel.moveToRight(st::boxButtonPadding.right() + _confirm.width() + st::boxButtonPadding.left(), _confirm.y());
}
ConfirmLinkBox::ConfirmLinkBox(const QString &url) : ConfirmBox(lang(lng_open_this_link) + qsl("\n\n") + url, lang(lng_open_link)), _url(url) {
SharePhoneConfirmBox::SharePhoneConfirmBox(PeerData *recipient)
: ConfirmBox(lang(lng_bot_share_phone), lang(lng_bot_share_phone_confirm))
, _recipient(recipient) {
connect(this, SIGNAL(confirmed()), this, SLOT(onConfirm()));
}
void SharePhoneConfirmBox::onConfirm() {
emit confirmed(_recipient);
}
ConfirmLinkBox::ConfirmLinkBox(const QString &url) : ConfirmBox(lang(lng_open_this_link) + qsl("\n\n") + url, lang(lng_open_link))
, _url(url) {
connect(this, SIGNAL(confirmed()), this, SLOT(onOpenLink()));
}
void ConfirmLinkBox::onOpenLink() {
if (reMailStart().match(_url).hasMatch()) {
EmailLink(_url).onClick(Qt::LeftButton);
} else {
TextLink(_url).onClick(Qt::LeftButton);
}
Ui::hideLayer();
UrlClickHandler::doOpen(_url);
}
MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth)
, _close(this, lang(lng_box_ok), st::defaultBoxButton)
, _text(st::boxTextFont, lng_participant_invite_sorry(lt_count, cMaxGroupCount()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right())
, _text(st::boxTextFont, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right())
, _link(link)
, _linkOver(false)
, a_goodOpacity(0, 0)
@ -212,7 +211,7 @@ void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e);
if (_linkOver) {
App::app()->clipboard()->setText(_link);
Application::clipboard()->setText(_link);
_goodTextLink = lang(lng_create_channel_link_copied);
a_goodOpacity = anim::fvalue(1, 0);
_a_good.start();
@ -279,3 +278,228 @@ void MaxInviteBox::resizeEvent(QResizeEvent *e) {
_close.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close.height());
_invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height);
}
ConvertToSupergroupBox::ConvertToSupergroupBox(ChatData *chat) : AbstractBox(st::boxWideWidth)
, _chat(chat)
, _text(100)
, _note(100)
, _convert(this, lang(lng_profile_convert_confirm), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
QStringList text;
text.push_back(lang(lng_profile_convert_feature1));
text.push_back(lang(lng_profile_convert_feature2));
text.push_back(lang(lng_profile_convert_feature3));
text.push_back(lang(lng_profile_convert_feature4));
textstyleSet(&st::boxTextStyle);
_text.setText(st::boxTextFont, text.join('\n'), _confirmBoxTextOptions);
_note.setText(st::boxTextFont, lng_profile_convert_warning(lt_bold_start, textcmdStartSemibold(), lt_bold_end, textcmdStopSemibold()), _confirmBoxTextOptions);
_textWidth = st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right();
_textHeight = _text.countHeight(_textWidth);
setMaxHeight(st::boxTitleHeight + _textHeight + st::boxPadding.bottom() + _note.countHeight(_textWidth) + st::boxButtonPadding.top() + _convert.height() + st::boxButtonPadding.bottom());
textstyleRestore();
connect(&_convert, SIGNAL(clicked()), this, SLOT(onConvert()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
prepare();
}
void ConvertToSupergroupBox::onConvert() {
MTP::send(MTPmessages_MigrateChat(_chat->inputChat), rpcDone(&ConvertToSupergroupBox::convertDone), rpcFail(&ConvertToSupergroupBox::convertFail));
}
void ConvertToSupergroupBox::convertDone(const MTPUpdates &updates) {
Ui::hideLayer();
App::main()->sentUpdatesReceived(updates);
const QVector<MTPChat> *v = 0;
switch (updates.type()) {
case mtpc_updates: v = &updates.c_updates().vchats.c_vector().v; break;
case mtpc_updatesCombined: v = &updates.c_updatesCombined().vchats.c_vector().v; break;
default: LOG(("API Error: unexpected update cons %1 (ConvertToSupergroupBox::convertDone)").arg(updates.type())); break;
}
PeerData *peer = 0;
if (v && !v->isEmpty()) {
for (int32 i = 0, l = v->size(); i < l; ++i) {
if (v->at(i).type() == mtpc_channel) {
peer = App::channel(v->at(i).c_channel().vid.v);
Ui::showPeerHistory(peer, ShowAtUnreadMsgId);
QTimer::singleShot(ReloadChannelMembersTimeout, App::api(), SLOT(delayedRequestParticipantsCount()));
}
}
}
if (!peer) {
LOG(("API Error: channel not found in updates (ProfileInner::migrateDone)"));
}
}
bool ConvertToSupergroupBox::convertFail(const RPCError &error) {
if (mtpIsFlood(error)) return false;
Ui::hideLayer();
return true;
}
void ConvertToSupergroupBox::hideAll() {
_convert.hide();
_cancel.hide();
}
void ConvertToSupergroupBox::showAll() {
_convert.show();
_cancel.show();
}
void ConvertToSupergroupBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
onConvert();
} else {
AbstractBox::keyPressEvent(e);
}
}
void ConvertToSupergroupBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
paintTitle(p, lang(lng_profile_convert_title));
// draw box title / text
p.setPen(st::black);
textstyleSet(&st::boxTextStyle);
_text.drawLeft(p, st::boxPadding.left(), st::boxTitleHeight, _textWidth, width());
_note.drawLeft(p, st::boxPadding.left(), st::boxTitleHeight + _textHeight + st::boxPadding.bottom(), _textWidth, width());
textstyleRestore();
}
void ConvertToSupergroupBox::resizeEvent(QResizeEvent *e) {
_convert.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _convert.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _convert.width() + st::boxButtonPadding.left(), _convert.y());
}
PinMessageBox::PinMessageBox(ChannelData *channel, MsgId msgId) : AbstractBox(st::boxWidth)
, _channel(channel)
, _msgId(msgId)
, _text(this, lang(lng_pinned_pin_sure), st::boxLabel)
, _notify(this, lang(lng_pinned_notify), true)
, _pin(this, lang(lng_pinned_pin), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _requestId(0) {
_text.resizeToWidth(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right());
setMaxHeight(st::boxPadding.top() + _text.height() + st::boxMediumSkip + _notify.height() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _pin.height() + st::boxButtonPadding.bottom());
connect(&_pin, SIGNAL(clicked()), this, SLOT(onPin()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
}
void PinMessageBox::resizeEvent(QResizeEvent *e) {
_text.moveToLeft(st::boxPadding.left(), st::boxPadding.top());
_notify.moveToLeft(st::boxPadding.left(), _text.y() + _text.height() + st::boxMediumSkip);
_pin.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _pin.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _pin.width() + st::boxButtonPadding.left(), _pin.y());
}
void PinMessageBox::onPin() {
if (_requestId) return;
MTPchannels_UpdatePinnedMessage::Flags flags = 0;
if (_notify.checked()) {
flags |= MTPchannels_UpdatePinnedMessage::Flag::f_silent;
}
_requestId = MTP::send(MTPchannels_UpdatePinnedMessage(MTP_flags(flags), _channel->inputChannel, MTP_int(_msgId)), rpcDone(&PinMessageBox::pinDone), rpcFail(&PinMessageBox::pinFail));
}
void PinMessageBox::showAll() {
_text.show();
_notify.show();
_pin.show();
_cancel.show();
}
void PinMessageBox::hideAll() {
_text.hide();
_notify.hide();
_pin.hide();
_cancel.hide();
}
void PinMessageBox::pinDone(const MTPUpdates &updates) {
if (App::main()) {
App::main()->sentUpdatesReceived(updates);
}
Ui::hideLayer();
}
bool PinMessageBox::pinFail(const RPCError &error) {
if (mtpIsFlood(error)) return false;
Ui::hideLayer();
return true;
}
RichDeleteMessageBox::RichDeleteMessageBox(ChannelData *channel, UserData *from, MsgId msgId) : AbstractBox(st::boxWidth)
, _channel(channel)
, _from(from)
, _msgId(msgId)
, _text(this, lang(lng_selected_delete_sure_this), st::boxLabel)
, _banUser(this, lang(lng_ban_user), false)
, _reportSpam(this, lang(lng_report_spam), false)
, _deleteAll(this, lang(lng_delete_all_from), false)
, _delete(this, lang(lng_box_delete), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
t_assert(_channel != nullptr);
_text.resizeToWidth(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right());
setMaxHeight(st::boxPadding.top() + _text.height() + st::boxMediumSkip + _banUser.height() + st::boxLittleSkip + _reportSpam.height() + st::boxLittleSkip + _deleteAll.height() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _delete.height() + st::boxButtonPadding.bottom());
connect(&_delete, SIGNAL(clicked()), this, SLOT(onDelete()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
}
void RichDeleteMessageBox::resizeEvent(QResizeEvent *e) {
_text.moveToLeft(st::boxPadding.left(), st::boxPadding.top());
_banUser.moveToLeft(st::boxPadding.left(), _text.y() + _text.height() + st::boxMediumSkip);
_reportSpam.moveToLeft(st::boxPadding.left(), _banUser.y() + _banUser.height() + st::boxLittleSkip);
_deleteAll.moveToLeft(st::boxPadding.left(), _reportSpam.y() + _reportSpam.height() + st::boxLittleSkip);
_delete.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _delete.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _delete.width() + st::boxButtonPadding.left(), _delete.y());
}
void RichDeleteMessageBox::onDelete() {
if (_banUser.checked()) {
MTP::send(MTPchannels_KickFromChannel(_channel->inputChannel, _from->inputUser, MTP_boolTrue()), App::main()->rpcDone(&MainWidget::sentUpdatesReceived));
}
if (_reportSpam.checked()) {
MTP::send(MTPchannels_ReportSpam(_channel->inputChannel, _from->inputUser, MTP_vector<MTPint>(1, MTP_int(_msgId))));
}
if (_deleteAll.checked()) {
App::main()->deleteAllFromUser(_channel, _from);
}
if (HistoryItem *item = App::histItemById(_channel ? peerToChannel(_channel->id) : 0, _msgId)) {
bool wasLast = (item->history()->lastMsg == item);
item->destroy();
if (_msgId > 0) {
App::main()->deleteMessages(_channel, QVector<MTPint>(1, MTP_int(_msgId)));
} else if (wasLast) {
App::main()->checkPeerHistory(_channel);
}
}
Ui::hideLayer();
}
void RichDeleteMessageBox::showAll() {
_text.show();
_banUser.show();
_reportSpam.show();
_deleteAll.show();
_delete.show();
_cancel.show();
}
void RichDeleteMessageBox::hideAll() {
_text.hide();
_banUser.hide();
_reportSpam.hide();
_deleteAll.hide();
_delete.hide();
_cancel.hide();
}

View file

@ -16,14 +16,14 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "abstractbox.h"
class InformBox;
class ConfirmBox : public AbstractBox {
class ConfirmBox : public AbstractBox, public ClickHandlerHost {
Q_OBJECT
public:
@ -38,6 +38,10 @@ public:
void leaveEvent(QEvent *e);
void updateLink();
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active);
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed);
public slots:
void onCancel();
@ -69,7 +73,6 @@ private:
void updateHover();
QPoint _lastMousePos;
TextLinkPtr _myLink;
BoxButton _confirm, _cancel;
};
@ -80,6 +83,23 @@ public:
}
};
class SharePhoneConfirmBox : public ConfirmBox {
Q_OBJECT
public:
SharePhoneConfirmBox(PeerData *recipient);
signals:
void confirmed(PeerData *recipient);
private slots:
void onConfirm();
private:
PeerData *_recipient;
};
class ConfirmLinkBox : public ConfirmBox {
Q_OBJECT
@ -133,3 +153,100 @@ private:
anim::fvalue a_goodOpacity;
Animation _a_good;
};
class ConvertToSupergroupBox : public AbstractBox, public RPCSender {
Q_OBJECT
public:
ConvertToSupergroupBox(ChatData *chat);
void keyPressEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
public slots:
void onConvert();
protected:
void hideAll();
void showAll();
private:
void convertDone(const MTPUpdates &updates);
bool convertFail(const RPCError &error);
ChatData *_chat;
Text _text, _note;
int32 _textWidth, _textHeight;
BoxButton _convert, _cancel;
};
class PinMessageBox : public AbstractBox, public RPCSender {
Q_OBJECT
public:
PinMessageBox(ChannelData *channel, MsgId msgId);
void resizeEvent(QResizeEvent *e);
public slots:
void onPin();
protected:
void showAll();
void hideAll();
private:
void pinDone(const MTPUpdates &updates);
bool pinFail(const RPCError &error);
ChannelData *_channel;
MsgId _msgId;
FlatLabel _text;
Checkbox _notify;
BoxButton _pin, _cancel;
mtpRequestId _requestId;
};
class RichDeleteMessageBox : public AbstractBox, public RPCSender {
Q_OBJECT
public:
RichDeleteMessageBox(ChannelData *channel, UserData *from, MsgId msgId);
void resizeEvent(QResizeEvent *e);
public slots:
void onDelete();
protected:
void showAll();
void hideAll();
private:
ChannelData *_channel;
UserData *_from;
MsgId _msgId;
FlatLabel _text;
Checkbox _banUser, _reportSpam, _deleteAll;
BoxButton _delete, _cancel;
};

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -201,8 +201,10 @@ void ConnectionBox::onSave() {
} else {
cSetConnectionType(dbictAuto);
cSetConnectionProxy(ConnectionProxy());
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxyFactory::setUseSystemConfiguration(false);
QNetworkProxyFactory::setUseSystemConfiguration(true);
#endif
}
if (cPlatform() == dbipWindows && cTryIPv6() != _tryIPv6.checked()) {
cSetTryIPv6(_tryIPv6.checked());
@ -313,9 +315,11 @@ void AutoDownloadBox::onSave() {
bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups));
cSetAutoDownloadAudio(autoDownloadAudio);
if (enabledPrivate || enabledGroups) {
const AudiosData &data(App::audiosData());
for (AudiosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged();
const DocumentsData &data(App::documentsData());
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
if (i.value()->voice()) {
i.value()->automaticLoadSettingsChanged();
}
}
}
changed = true;
@ -328,7 +332,9 @@ void AutoDownloadBox::onSave() {
if (enabledPrivate || enabledGroups) {
const DocumentsData &data(App::documentsData());
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged();
if (i.value()->isAnimation()) {
i.value()->automaticLoadSettingsChanged();
}
}
Notify::automaticLoadSettingsChangedGif();
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -33,6 +33,10 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "confirmbox.h"
QString cantInviteError() {
return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info)));
}
ContactsInner::ContactsInner(CreatingGroupType creating) : TWidget()
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
@ -224,7 +228,7 @@ void ContactsInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &old
void ContactsInner::onAddBot() {
if (_bot->botInfo && !_bot->botInfo->startGroupToken.isEmpty()) {
MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToPeer->input, MTP_long(MTP::nonce<uint64>()), MTP_string(_bot->botInfo->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _bot));
MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToPeer->input, MTP_long(rand_value<uint64>()), MTP_string(_bot->botInfo->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _bot));
} else {
App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot));
}
@ -257,6 +261,18 @@ void ContactsInner::addAdminDone(const MTPUpdates &result, mtpRequestId req) {
if (req != _addAdminRequestId) return;
_addAdminRequestId = 0;
if (_addAdmin && _channel && _channel->isMegagroup()) {
if (_channel->mgInfo->lastParticipants.indexOf(_addAdmin) < 0) {
_channel->mgInfo->lastParticipants.push_front(_addAdmin);
}
_channel->mgInfo->lastAdmins.insert(_addAdmin);
if (_addAdmin->botInfo) {
_channel->mgInfo->bots.insert(_addAdmin);
if (_channel->mgInfo->botStatus != 0 && _channel->mgInfo->botStatus < 2) {
_channel->mgInfo->botStatus = 2;
}
}
}
if (_addAdminBox) _addAdminBox->onClose();
emit adminAdded();
}
@ -272,6 +288,8 @@ bool ContactsInner::addAdminFail(const RPCError &error, mtpRequestId req) {
Ui::showLayer(new MaxInviteBox(_channel->invitationUrl), KeepOtherLayers);
} else if (error.type() == "ADMINS_TOO_MUCH") {
Ui::showLayer(new InformBox(lang(lng_channel_admins_too_much)), KeepOtherLayers);
} else if (error.type() == qstr("USER_RESTRICTED")) {
Ui::showLayer(new InformBox(lang(lng_cant_do_this)), KeepOtherLayers);
} else {
emit adminAdded();
}
@ -350,7 +368,7 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) {
preloadFrom != _contacts->list.end && (_newItemHeight + preloadFrom->pos * _rowHeight) < yTo;
preloadFrom = preloadFrom->next
) {
preloadFrom->history->peer->photo->load();
preloadFrom->history->peer->loadUserpic();
}
}
} else if (!_filtered.isEmpty()) {
@ -361,7 +379,7 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) {
if (to > _filtered.size()) to = _filtered.size();
for (; from < to; ++from) {
_filtered[from]->history->peer->photo->load();
_filtered[from]->history->peer->loadUserpic();
}
}
}
@ -427,13 +445,13 @@ void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, b
sel = false;
}
} else {
if (data->inchat || data->check || selectedCount() >= ((_channel && _channel->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())) {
if (data->inchat || data->check || selectedCount() >= Global::MegagroupSizeMax()) {
sel = false;
}
}
p.fillRect(0, 0, width(), _rowHeight, inverse ? st::contactsBgActive : (sel ? st::contactsBgOver : st::white));
p.setPen(inverse ? st::white : st::black);
p.drawPixmapLeft(st::contactsPadding.left(), st::contactsPadding.top(), width(), peer->photo->pix(st::contactsPhotoSize));
peer->paintUserpicLeft(p, st::contactsPhotoSize, st::contactsPadding.left(), st::contactsPadding.top(), width());
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int32 iconw = (_chat || _creating != CreatingGroupNone) ? (st::contactsCheckPosition.x() * 2 + st::contactsCheckIcon.pxWidth()) : 0;
@ -767,10 +785,14 @@ void ContactsInner::changeCheckState(ContactData *data, PeerData *peer) {
data->check = false;
_checkedContacts.remove(peer);
--_selCount;
} else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())) {
} else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
data->check = true;
_checkedContacts.insert(peer, true);
++_selCount;
} else if (_channel && !_channel->isMegagroup()) {
Ui::showLayer(new MaxInviteBox(_channel->invitationUrl), KeepOtherLayers);
} else if (!_channel && selectedCount() >= Global::ChatSizeMax() && selectedCount() < Global::MegagroupSizeMax()) {
Ui::showLayer(new InformBox(lng_profile_add_more_after_upgrade(lt_count, Global::MegagroupSizeMax())), KeepOtherLayers);
}
if (cnt != _selCount) emit chosenChanged();
}
@ -1535,7 +1557,7 @@ void ContactsBox::paintEvent(QPaintEvent *e) {
paintTitle(p, lang(lng_channel_admins));
} else if (_inner.chat() || _inner.creating() != CreatingGroupNone) {
QString title(lang(addingAdmin ? lng_channel_add_admin : lng_profile_add_participant));
QString additional(addingAdmin ? QString() : QString("%1 / %2").arg(_inner.selectedCount()).arg(((_inner.channel() && _inner.channel()->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())));
QString additional((addingAdmin || (_inner.channel() && !_inner.channel()->isMegagroup())) ? QString() : QString("%1 / %2").arg(_inner.selectedCount()).arg(Global::MegagroupSizeMax()));
paintTitle(p, title, additional);
} else if (_inner.bot()) {
paintTitle(p, lang(lng_bot_choose_group));
@ -1652,12 +1674,15 @@ void ContactsBox::getAdminsDone(const MTPmessages_ChatFull &result) {
}
}
_saveRequestId = 0;
for (ChatData::Admins::const_iterator i = curadmins.cbegin(), e = curadmins.cend(); i != e; ++i) {
MTP::send(MTPmessages_EditChatAdmin(_inner.chat()->inputChat, i.key()->inputUser, MTP_boolFalse()), rpcDone(&ContactsBox::removeAdminDone, i.key()), rpcFail(&ContactsBox::editAdminFail), 0, (appoint.isEmpty() && i + 1 == e) ? 0 : 10);
for_const (UserData *user, curadmins) {
MTP::send(MTPmessages_EditChatAdmin(_inner.chat()->inputChat, user->inputUser, MTP_boolFalse()), rpcDone(&ContactsBox::removeAdminDone, user), rpcFail(&ContactsBox::editAdminFail), 0, 10);
}
for (int32 i = 0, l = appoint.size(); i < l; ++i) {
MTP::send(MTPmessages_EditChatAdmin(_inner.chat()->inputChat, appoint.at(i)->inputUser, MTP_boolTrue()), rpcDone(&ContactsBox::setAdminDone, appoint.at(i)), rpcFail(&ContactsBox::editAdminFail), 0, (i + 1 == l) ? 0 : 10);
for_const (UserData *user, appoint) {
MTP::send(MTPmessages_EditChatAdmin(_inner.chat()->inputChat, user->inputUser, MTP_boolTrue()), rpcDone(&ContactsBox::setAdminDone, user), rpcFail(&ContactsBox::editAdminFail), 0, 10);
}
MTP::sendAnything();
_saveRequestId = curadmins.size() + appoint.size();
if (!_saveRequestId) {
onClose();
@ -1669,7 +1694,7 @@ void ContactsBox::setAdminDone(UserData *user, const MTPBool &result) {
if (_inner.chat()->noParticipantInfo()) {
App::api()->requestFullPeer(_inner.chat());
} else {
_inner.chat()->admins.insert(user, true);
_inner.chat()->admins.insert(user);
}
}
--_saveRequestId;
@ -1704,7 +1729,13 @@ bool ContactsBox::editAdminFail(const RPCError &error) {
if (mtpIsFlood(error)) return true;
--_saveRequestId;
_inner.chat()->invalidateParticipants();
if (!_saveRequestId) onClose();
if (!_saveRequestId) {
if (error.type() == qstr("USER_RESTRICTED")) {
Ui::showLayer(new InformBox(lang(lng_cant_do_this)));
return true;
}
onClose();
}
return false;
}
@ -1749,7 +1780,10 @@ bool ContactsBox::creationFail(const RPCError &error) {
_filter.showError();
return true;
} else if (error.type() == "PEER_FLOOD") {
Ui::showLayer(new InformBox(lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info)))), KeepOtherLayers);
Ui::showLayer(new InformBox(cantInviteError()), KeepOtherLayers);
return true;
} else if (error.type() == qstr("USER_RESTRICTED")) {
Ui::showLayer(new InformBox(lang(lng_cant_do_this)));
return true;
}
return false;
@ -1757,7 +1791,7 @@ bool ContactsBox::creationFail(const RPCError &error) {
MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget()
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _newItemHeight((channel->amCreator() && (channel->count < (channel->isMegagroup() ? cMaxMegaGroupCount() : cMaxGroupCount()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilterAdmins)) ? st::contactsNewItemHeight : 0)
, _newItemHeight((channel->amCreator() && (channel->count < (channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilterAdmins)) ? st::contactsNewItemHeight : 0)
, _newItemSel(false)
, _channel(channel)
, _filter(filter)
@ -1787,7 +1821,7 @@ MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget
void MembersInner::load() {
if (!_loadingRequestId) {
_loadingRequestId = MTP::send(MTPchannels_GetParticipants(_channel->inputChannel, (_filter == MembersFilterRecent) ? MTP_channelParticipantsRecent() : MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&MembersInner::membersReceived), rpcFail(&MembersInner::membersFailed));
_loadingRequestId = MTP::send(MTPchannels_GetParticipants(_channel->inputChannel, (_filter == MembersFilterRecent) ? MTP_channelParticipantsRecent() : MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(Global::ChatSizeMax())), rpcDone(&MembersInner::membersReceived), rpcFail(&MembersInner::membersFailed));
}
}
@ -1826,7 +1860,7 @@ void MembersInner::paintEvent(QPaintEvent *e) {
paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown);
p.translate(0, _rowHeight);
}
if (to == _rows.size() && _filter == MembersFilterRecent && (_rows.size() < _channel->count || _rows.size() >= cMaxGroupCount())) {
if (to == _rows.size() && _filter == MembersFilterRecent && (_rows.size() < _channel->count || _rows.size() >= Global::ChatSizeMax())) {
p.setPen(st::stickersReorderFg);
_about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center);
}
@ -1895,7 +1929,7 @@ void MembersInner::paintDialog(Painter &p, PeerData *peer, MemberData *data, boo
UserData *user = peer->asUser();
p.fillRect(0, 0, width(), _rowHeight, (sel ? st::contactsBgOver : st::white)->b);
p.drawPixmapLeft(st::contactsPadding.left(), st::contactsPadding.top(), width(), peer->photo->pix(st::contactsPhotoSize));
peer->paintUserpicLeft(p, st::contactsPhotoSize, st::contactsPadding.left(), st::contactsPadding.top(), width());
p.setPen(st::black);
@ -1980,7 +2014,7 @@ void MembersInner::loadProfilePhotos(int32 yFrom) {
if (to > _rows.size()) to = _rows.size();
for (; from < to; ++from) {
_rows[from]->photo->load();
_rows[from]->loadUserpic();
}
}
}
@ -2005,7 +2039,7 @@ void MembersInner::refresh() {
} else {
_about.setText(st::boxTextFont, lng_channel_only_last_shown(lt_count, _rows.size()));
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
if (_filter != MembersFilterRecent || (_rows.size() >= _channel->count && _rows.size() < cMaxGroupCount())) {
if (_filter != MembersFilterRecent || (_rows.size() >= _channel->count && _rows.size() < Global::ChatSizeMax())) {
_aboutHeight = 0;
}
resize(width(), st::membersPadding.top() + _newItemHeight + _rows.size() * _rowHeight + st::membersPadding.bottom() + _aboutHeight);
@ -2182,6 +2216,16 @@ void MembersInner::membersReceived(const MTPchannels_ChannelParticipants &result
_datas.push_back(0);
}
}
// update admins if we got all of them
if (_filter == MembersFilterAdmins && _channel->isMegagroup() && _rows.size() < Global::ChatSizeMax()) {
_channel->mgInfo->lastAdmins.clear();
for (int32 i = 0, l = _rows.size(); i != l; ++i) {
if (_roles.at(i) == MemberRoleCreator || _roles.at(i) == MemberRoleEditor) {
_channel->mgInfo->lastAdmins.insert(_rows.at(i));
}
}
}
}
if (_rows.isEmpty()) {
_rows.push_back(App::self());
@ -2297,7 +2341,7 @@ void MembersBox::onScroll() {
}
void MembersBox::onAdd() {
if (_inner.filter() == MembersFilterRecent && _inner.channel()->count >= (_inner.channel()->isMegagroup() ? cMaxMegaGroupCount() : cMaxGroupCount())) {
if (_inner.filter() == MembersFilterRecent && _inner.channel()->count >= (_inner.channel()->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
Ui::showLayer(new MaxInviteBox(_inner.channel()->invitationUrl), KeepOtherLayers);
return;
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -28,6 +28,8 @@ enum MembersFilter {
};
typedef QMap<UserData*, bool> MembersAlreadyIn;
QString cantInviteError();
class ConfirmBox;
class ContactsInner : public TWidget, public RPCSender {
Q_OBJECT

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -46,12 +46,12 @@ _close(this, lang(lng_box_ok), st::defaultBoxButton) {
for (int32 i = 0; i < languageCount; ++i) {
LangLoaderResult result;
if (i) {
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[i] + qsl(".strings"), LangLoaderRequest(lng_language_name));
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[i].c_str() + qsl(".strings"), LangLoaderRequest(lng_language_name));
result = loader.found();
} else {
result.insert(lng_language_name, langOriginal(lng_language_name));
}
_langs.push_back(new Radiobutton(this, qsl("lang"), i, result.value(lng_language_name, LanguageCodes[i] + qsl(" language")), (cLang() == i), st::langsButton));
_langs.push_back(new Radiobutton(this, qsl("lang"), i, result.value(lng_language_name, LanguageCodes[i].c_str() + qsl(" language")), (cLang() == i), st::langsButton));
_langs.back()->move(st::boxPadding.left() + st::boxOptionListPadding.left(), y);
y += _langs.back()->height() + st::boxOptionListPadding.top();
connect(_langs.back(), SIGNAL(changed()), this, SLOT(onChange()));
@ -82,14 +82,14 @@ void LanguageBox::showAll() {
void LanguageBox::mousePressEvent(QMouseEvent *e) {
if ((e->modifiers() & Qt::CTRL) && (e->modifiers() & Qt::ALT) && (e->modifiers() & Qt::SHIFT)) {
for (int32 i = 1; i < languageCount; ++i) {
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[i] + qsl(".strings"), LangLoaderRequest(lngkeys_cnt));
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[i].c_str() + qsl(".strings"), LangLoaderRequest(lngkeys_cnt));
if (!loader.errors().isEmpty()) {
Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i] + qsl("\" error :(\n\nError: ") + loader.errors()));
Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i].c_str() + qsl("\" error :(\n\nError: ") + loader.errors()));
return;
} else if (!loader.warnings().isEmpty()) {
QString warn = loader.warnings();
if (warn.size() > 256) warn = warn.mid(0, 254) + qsl("..");
Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i] + qsl("\" warnings :(\n\nWarnings: ") + warn));
if (warn.size() > 256) warn = warn.mid(0, 253) + qsl("...");
Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i].c_str() + qsl("\" warnings :(\n\nWarnings: ") + warn));
return;
}
}
@ -112,7 +112,7 @@ void LanguageBox::onChange() {
if (_langs[i]->checked() && langId != cLang()) {
LangLoaderResult result;
if (langId > 0) {
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[langId] + qsl(".strings"), LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok));
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[langId].c_str() + qsl(".strings"), LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok));
result = loader.found();
} else if (langId == languageTest) {
LangLoaderPlain loader(cLangFile(), LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok));

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -400,12 +400,12 @@ void PasscodeBox::onSave(bool force) {
if (!_oldPasscode.isHidden()) {
hashSha256(oldPasswordData.constData(), oldPasswordData.size(), oldPasswordHash.data());
}
int32 flags = MTPDaccount_passwordInputSettings::flag_new_salt | MTPDaccount_passwordInputSettings::flag_new_password_hash | MTPDaccount_passwordInputSettings::flag_hint;
MTPDaccount_passwordInputSettings::Flags flags = MTPDaccount_passwordInputSettings::Flag::f_new_salt | MTPDaccount_passwordInputSettings::Flag::f_new_password_hash | MTPDaccount_passwordInputSettings::Flag::f_hint;
if (_oldPasscode.isHidden() || _newPasscode.isHidden()) {
flags |= MTPDaccount_passwordInputSettings::flag_email;
flags |= MTPDaccount_passwordInputSettings::Flag::f_email;
}
MTPaccount_PasswordInputSettings settings(MTP_account_passwordInputSettings(MTP_int(flags), MTP_string(_newSalt), MTP_string(newPasswordHash), MTP_string(hint), MTP_string(email)));
_setRequest = MTP::send(MTPaccount_UpdatePasswordSettings(MTP_string(oldPasswordHash), settings), rpcDone(&PasscodeBox::setPasswordDone), rpcFail(&PasscodeBox::setPasswordFail));
MTPaccount_PasswordInputSettings settings(MTP_account_passwordInputSettings(MTP_flags(flags), MTP_bytes(_newSalt), MTP_bytes(newPasswordHash), MTP_string(hint), MTP_string(email)));
_setRequest = MTP::send(MTPaccount_UpdatePasswordSettings(MTP_bytes(oldPasswordHash), settings), rpcDone(&PasscodeBox::setPasswordDone), rpcFail(&PasscodeBox::setPasswordFail));
}
} else {
cSetPasscodeBadTries(0);

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,10 +16,10 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "style.h"
#include "gui/style.h"
#include "lang.h"
#include "application.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,10 +16,10 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "style.h"
#include "gui/style.h"
#include "lang.h"
#include "localstorage.h"
@ -69,8 +69,8 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
if (_animated) {
int32 limitW = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
int32 limitH = st::confirmMaxHeight;
maxW = dimensions.width();
maxH = dimensions.height();
maxW = qMax(dimensions.width(), 1);
maxH = qMax(dimensions.height(), 1);
if (maxW * limitH > maxH * limitW) {
if (maxW < limitW) {
maxH = maxH * limitW / maxW;
@ -82,7 +82,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
maxH = limitH;
}
}
_thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), true, true, false, maxW, maxH);
_thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixBlurred, maxW, maxH);
} else {
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
if (i->width() >= maxW && i->height() >= maxH) {
@ -124,7 +124,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
} else {
_thumbw = st::msgFileThumbSize;
}
_thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, true, false, true, st::msgFileThumbSize, st::msgFileThumbSize);
_thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, ImagePixSmooth | ImagePixRounded, st::msgFileThumbSize, st::msgFileThumbSize);
}
_name.setText(st::semiboldFont, _file->filename, _textNameOptions);
@ -274,7 +274,7 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
p.drawSpriteCenter(inner, _isImage ? st::msgFileOutImage : st::msgFileOutFile);
} else {
p.drawPixmapLeft(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), userDefPhoto(1)->pixRounded(st::msgFileSize));
p.drawPixmapLeft(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), userDefPhoto(1)->pixCircled(st::msgFileSize));
}
p.setFont(st::semiboldFont);
p.setPen(st::black);
@ -359,3 +359,330 @@ void PhotoSendBox::onSend(bool ctrlShiftEnter) {
_confirmed = true;
onClose();
}
EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
, _msgId(msg->fullId())
, _animated(false)
, _photo(false)
, _doc(false)
, _field(0)
, _save(this, lang(lng_settings_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _thumbx(0)
, _thumby(0)
, _thumbw(0)
, _thumbh(0)
, _statusw(0)
, _isImage(false)
, _previewCancelled(false)
, _saveRequestId(0) {
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
QSize dimensions;
ImagePtr image;
QString caption;
DocumentData *doc = 0;
if (HistoryMedia *media = msg->getMedia()) {
HistoryMediaType t = media->type();
switch (t) {
case MediaTypeGif: {
_animated = true;
doc = static_cast<HistoryGif*>(media)->getDocument();
dimensions = doc->dimensions;
image = doc->thumb;
} break;
case MediaTypePhoto: {
_photo = true;
PhotoData *photo = static_cast<HistoryPhoto*>(media)->photo();
dimensions = QSize(photo->full->width(), photo->full->height());
image = photo->full;
} break;
case MediaTypeVideo: {
_animated = true;
doc = static_cast<HistoryVideo*>(media)->getDocument();
dimensions = doc->dimensions;
image = doc->thumb;
} break;
case MediaTypeFile:
case MediaTypeMusicFile:
case MediaTypeVoiceFile: {
_doc = true;
doc = static_cast<HistoryDocument*>(media)->getDocument();
image = doc->thumb;
} break;
}
caption = media->getCaption();
}
if ((!_animated && (dimensions.isEmpty() || doc)) || image->isNull()) {
_animated = false;
if (image->isNull()) {
_thumbw = 0;
} else {
int32 tw = image->width(), th = image->height();
if (tw > th) {
_thumbw = (tw * st::msgFileThumbSize) / th;
} else {
_thumbw = st::msgFileThumbSize;
}
_thumb = imagePix(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, ImagePixSmooth | ImagePixRounded, st::msgFileThumbSize, st::msgFileThumbSize);
}
if (doc) {
if (doc->voice()) {
_name.setText(st::semiboldFont, lang(lng_media_audio), _textNameOptions);
} else {
_name.setText(st::semiboldFont, documentName(doc), _textNameOptions);
}
_status = formatSizeText(doc->size);
_statusw = qMax(_name.maxWidth(), st::normalFont->width(_status));
_isImage = doc->isImage();
}
} else {
int32 maxW = 0, maxH = 0;
if (_animated) {
int32 limitW = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
int32 limitH = st::confirmMaxHeight;
maxW = qMax(dimensions.width(), 1);
maxH = qMax(dimensions.height(), 1);
if (maxW * limitH > maxH * limitW) {
if (maxW < limitW) {
maxH = maxH * limitW / maxW;
maxW = limitW;
}
} else {
if (maxH < limitH) {
maxW = maxW * limitH / maxH;
maxH = limitH;
}
}
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixBlurred, maxW, maxH);
} else {
maxW = dimensions.width();
maxH = dimensions.height();
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixRounded, maxW, maxH);
}
int32 tw = _thumb.width(), th = _thumb.height();
if (!tw || !th) {
tw = th = 1;
}
_thumbw = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
if (_thumb.width() < _thumbw) {
_thumbw = (_thumb.width() > 20) ? _thumb.width() : 20;
}
int32 maxthumbh = qMin(qRound(1.5 * _thumbw), int(st::confirmMaxHeight));
_thumbh = qRound(th * float64(_thumbw) / tw);
if (_thumbh > maxthumbh) {
_thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh);
_thumbh = maxthumbh;
if (_thumbw < 10) {
_thumbw = 10;
}
}
_thumbx = (width() - _thumbw) / 2;
_thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly);
_thumb.setDevicePixelRatio(cRetinaFactor());
}
if (_animated || _photo || _doc) {
_field = new InputArea(this, st::confirmCaptionArea, lang(lng_photo_caption), caption);
_field->setMaxLength(MaxPhotoCaption);
_field->setCtrlEnterSubmit(CtrlEnterSubmitBoth);
} else {
QString text = textApplyEntities(msg->originalText(), msg->originalEntities());
_field = new InputArea(this, st::editTextArea, lang(lng_photo_caption), text);
// _field->setMaxLength(MaxMessageSize); // entities can make text in input field larger but still valid
_field->setCtrlEnterSubmit(cCtrlEnter() ? CtrlEnterSubmitCtrlEnter : CtrlEnterSubmitEnter);
}
updateBoxSize();
connect(_field, SIGNAL(submitted(bool)), this, SLOT(onSave(bool)));
connect(_field, SIGNAL(cancelled()), this, SLOT(onClose()));
connect(_field, SIGNAL(resized()), this, SLOT(onCaptionResized()));
QTextCursor c(_field->textCursor());
c.movePosition(QTextCursor::End);
_field->setTextCursor(c);
prepare();
}
bool EditCaptionBox::captionFound() const {
return _animated || _photo || _doc;
}
void EditCaptionBox::onCaptionResized() {
updateBoxSize();
resizeEvent(0);
update();
}
void EditCaptionBox::updateBoxSize() {
int32 bottomh = st::boxPhotoCompressedPadding.bottom() + _field->height() + st::normalFont->height + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom();
if (_photo || _animated) {
setMaxHeight(st::boxPhotoPadding.top() + _thumbh + bottomh);
} else if (_thumbw) {
setMaxHeight(st::boxPhotoPadding.top() + 0 + st::msgFileThumbSize + 0 + bottomh);
} else if (_doc) {
setMaxHeight(st::boxPhotoPadding.top() + 0 + st::msgFileSize + 0 + bottomh);
} else {
setMaxHeight(st::boxPhotoPadding.top() + st::boxTitleFont->height + bottomh);
}
}
void EditCaptionBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
if (_photo || _animated) {
if (_thumbx > st::boxPhotoPadding.left()) {
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg->b);
}
if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) {
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg->b);
}
p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), _thumb);
if (_animated) {
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_thumbh - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen);
p.setBrush(st::msgDateImgBg);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.drawEllipse(inner);
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
p.drawSpriteCenter(inner, st::msgFileInPlay);
}
} else if (_doc) {
int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
int32 h = _thumbw ? (0 + st::msgFileThumbSize + 0) : (0 + st::msgFileSize + 0);
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0;
if (_thumbw) {
nameleft = 0 + st::msgFileThumbSize + st::msgFileThumbPadding.right();
nametop = st::msgFileThumbNameTop - st::msgFileThumbPadding.top();
nameright = 0;
statustop = st::msgFileThumbStatusTop - st::msgFileThumbPadding.top();
} else {
nameleft = 0 + st::msgFileSize + st::msgFilePadding.right();
nametop = st::msgFileNameTop - st::msgFilePadding.top();
nameright = 0;
statustop = st::msgFileStatusTop - st::msgFilePadding.top();
}
int32 namewidth = w - nameleft - 0;
if (namewidth > _statusw) {
//w -= (namewidth - _statusw);
//namewidth = _statusw;
}
int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top();
// App::roundRect(p, x, y, w, h, st::msgInBg, MessageInCorners, &st::msgInShadow);
if (_thumbw) {
QRect rthumb(rtlrect(x + 0, y + 0, st::msgFileThumbSize, st::msgFileThumbSize, width()));
p.drawPixmap(rthumb.topLeft(), _thumb);
} else {
QRect inner(rtlrect(x + 0, y + 0, st::msgFileSize, st::msgFileSize, width()));
p.setPen(Qt::NoPen);
p.setBrush(st::msgFileInBg);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.drawEllipse(inner);
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
p.drawSpriteCenter(inner, _isImage ? st::msgFileInImage : st::msgFileInFile);
}
p.setFont(st::semiboldFont);
p.setPen(st::black);
_name.drawLeftElided(p, x + nameleft, y + nametop, namewidth, width());
style::color status(st::mediaInFg);
p.setFont(st::normalFont);
p.setPen(status);
p.drawTextLeft(x + nameleft, y + statustop, width(), _status);
} else {
p.setFont(st::boxTitleFont);
p.setPen(st::black);
p.drawTextLeft(_field->x(), st::boxPhotoPadding.top(), width(), lang(lng_edit_message));
}
if (!_error.isEmpty()) {
p.setFont(st::normalFont);
p.setPen(st::setErrColor);
p.drawTextLeft(_field->x(), _field->y() + _field->height() + (st::boxButtonPadding.top() / 2), width(), _error);
}
}
void EditCaptionBox::resizeEvent(QResizeEvent *e) {
_save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y());
_field->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _field->height());
_field->moveToLeft(st::boxPhotoPadding.left(), _save.y() - st::boxButtonPadding.top() - st::normalFont->height - _field->height());
}
void EditCaptionBox::hideAll() {
_save.hide();
_cancel.hide();
_field->hide();
}
void EditCaptionBox::showAll() {
_save.show();
_cancel.show();
_field->show();
}
void EditCaptionBox::showDone() {
setInnerFocus();
}
void EditCaptionBox::onSave(bool ctrlShiftEnter) {
if (_saveRequestId) return;
HistoryItem *item = App::histItemById(_msgId);
if (!item) {
_error = lang(lng_edit_deleted);
update();
return;
}
MTPmessages_EditMessage::Flags flags = 0;
if (_previewCancelled) {
flags |= MTPmessages_EditMessage::Flag::f_no_webpage;
}
MTPVector<MTPMessageEntity> sentEntities;
if (!sentEntities.c_vector().v.isEmpty()) {
flags |= MTPmessages_EditMessage::Flag::f_entities;
}
_saveRequestId = MTP::send(MTPmessages_EditMessage(MTP_flags(flags), item->history()->peer->input, MTP_int(item->id), MTP_string(_field->getLastText()), MTPnullMarkup, sentEntities), rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail));
}
void EditCaptionBox::saveDone(const MTPUpdates &updates) {
_saveRequestId = 0;
onClose();
if (App::main()) {
App::main()->sentUpdatesReceived(updates);
}
}
bool EditCaptionBox::saveFail(const RPCError &error) {
if (mtpIsFlood(error)) return false;
_saveRequestId = 0;
QString err = error.type();
if (err == qstr("MESSAGE_ID_INVALID") || err == qstr("CHAT_ADMIN_REQUIRED") || err == qstr("MESSAGE_EDIT_TIME_EXPIRED")) {
_error = lang(lng_edit_error);
} else if (err == qstr("MESSAGE_NOT_MODIFIED")) {
onClose();
return true;
} else if (err == qstr("MESSAGE_EMPTY")) {
_field->setFocus();
_field->showError();
} else {
_error = lang(lng_edit_error);
}
update();
return true;
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -42,11 +42,6 @@ public:
}
}
signals:
void confirmed();
void cancelled();
public slots:
void onCompressedChange();
@ -87,3 +82,57 @@ private:
bool _confirmed;
};
class EditCaptionBox : public AbstractBox, public RPCSender {
Q_OBJECT
public:
EditCaptionBox(HistoryItem *msg);
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
bool captionFound() const;
void setInnerFocus() {
_field->setFocus();
}
public slots:
void onCaptionResized();
void onSave(bool ctrlShiftEnter = false);
protected:
void hideAll();
void showAll();
void showDone();
private:
void updateBoxSize();
void saveDone(const MTPUpdates &updates);
bool saveFail(const RPCError &error);
FullMsgId _msgId;
bool _animated, _photo, _doc;
QPixmap _thumb;
InputArea *_field;
BoxButton _save, _cancel;
int32 _thumbx, _thumby, _thumbw, _thumbh;
Text _name;
QString _status;
int32 _statusw;
bool _isImage;
bool _previewCancelled;
mtpRequestId _saveRequestId;
QString _error;
};

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -29,9 +29,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "localstorage.h"
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) :
_loaded(false), _setId(0), _setAccess(0), _setCount(0), _setHash(0), _setFlags(0), _bottom(0),
_input(set), _installRequest(0) {
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget()
, _loaded(false)
, _setId(0)
, _setAccess(0)
, _setCount(0)
, _setHash(0)
, _setFlags(0)
, _bottom(0)
, _input(set)
, _installRequest(0)
, _previewShown(-1) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
switch (set.type()) {
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
@ -39,10 +47,14 @@ _input(set), _installRequest(0) {
}
MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&StickerSetInner::gotSet), rpcFail(&StickerSetInner::failedSet));
App::main()->updateStickers();
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
}
void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_pack.clear();
_emoji.clear();
if (set.type() == mtpc_messages_stickerSet) {
const MTPDmessages_stickerSet &d(set.c_messages_stickerSet());
const QVector<MTPDocument> &v(d.vdocuments.c_vector().v);
@ -53,6 +65,23 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_pack.push_back(doc);
}
const QVector<MTPStickerPack> &packs(d.vpacks.c_vector().v);
for (int32 i = 0, l = packs.size(); i < l; ++i) {
if (packs.at(i).type() != mtpc_stickerPack) continue;
const MTPDstickerPack &pack(packs.at(i).c_stickerPack());
if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) {
const QVector<MTPlong> &stickers(pack.vdocuments.c_vector().v);
StickerPack p;
p.reserve(stickers.size());
for (int32 j = 0, c = stickers.size(); j < c; ++j) {
DocumentData *doc = App::document(stickers.at(j).v);
if (!doc || !doc->sticker()) continue;
p.push_back(doc);
}
_emoji.insert(e, p);
}
}
if (d.vset.type() == mtpc_stickerSet) {
const MTPDstickerSet &s(d.vset.c_stickerSet());
_setTitle = stickerSetTitle(s);
@ -88,12 +117,17 @@ bool StickerSetInner::failedSet(const RPCError &error) {
}
void StickerSetInner::installDone(const MTPBool &result) {
StickerSets &sets(cRefStickerSets());
Stickers::Sets &sets(Global::RefStickerSets());
_setFlags &= ~MTPDstickerSet::flag_disabled;
sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)).value().stickers = _pack;
_setFlags &= ~MTPDstickerSet::Flag::f_disabled;
auto it = sets.find(_setId);
if (it == sets.cend()) {
it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags));
}
it.value().stickers = _pack;
it.value().emoji = _emoji;
StickerSetsOrder &order(cRefStickerSetsOrder());
Stickers::Order &order(Global::RefStickerSetsOrder());
int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId);
if (currentIndex != insertAtIndex) {
if (currentIndex > 0) {
@ -102,7 +136,7 @@ void StickerSetInner::installDone(const MTPBool &result) {
order.insert(insertAtIndex, _setId);
}
StickerSets::iterator custom = sets.find(CustomStickerSetId);
auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) {
for (int32 i = 0, l = _pack.size(); i < l; ++i) {
int32 removeIndex = custom->stickers.indexOf(_pack.at(i));
@ -125,6 +159,47 @@ bool StickerSetInner::installFailed(const RPCError &error) {
return true;
}
void StickerSetInner::mousePressEvent(QMouseEvent *e) {
int32 index = stickerFromGlobalPos(e->globalPos());
if (index >= 0 && index < _pack.size()) {
_previewTimer.start(QApplication::startDragTime());
}
}
void StickerSetInner::mouseMoveEvent(QMouseEvent *e) {
if (_previewShown >= 0) {
int32 index = stickerFromGlobalPos(e->globalPos());
if (index >= 0 && index < _pack.size() && index != _previewShown) {
_previewShown = index;
Ui::showStickerPreview(_pack.at(_previewShown));
}
}
}
void StickerSetInner::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.stop();
}
void StickerSetInner::onPreview() {
int32 index = stickerFromGlobalPos(QCursor::pos());
if (index >= 0 && index < _pack.size()) {
_previewShown = index;
Ui::showStickerPreview(_pack.at(_previewShown));
}
}
int32 StickerSetInner::stickerFromGlobalPos(const QPoint &p) const {
QPoint l(mapFromGlobal(p));
if (rtl()) l.setX(width() - l.x());
int32 row = (l.y() >= st::stickersPadding.top()) ? qFloor((l.y() - st::stickersPadding.top()) / st::stickersSize.height()) : -1;
int32 col = (l.x() >= st::stickersPadding.left()) ? qFloor((l.x() - st::stickersPadding.left()) / st::stickersSize.width()) : -1;
if (row >= 0 && col >= 0 && col < StickerPanPerRow) {
int32 result = row * StickerPanPerRow + col;
return (result < _pack.size()) ? result : -1;
}
return -1;
}
void StickerSetInner::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
Painter p(this);
@ -149,12 +224,8 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
if (doc->status == FileReady) {
doc->automaticLoad(0);
}
if (doc->sticker()->img->isNull() && doc->loaded() && doc->loaded(true)) {
if (doc->data().isEmpty()) {
doc->sticker()->img = ImagePtr(doc->already());
} else {
doc->sticker()->img = ImagePtr(doc->data());
}
if (doc->sticker()->img->isNull() && doc->loaded(DocumentData::FilePathResolveChecked)) {
doc->sticker()->img = doc->data().isEmpty() ? ImagePtr(doc->filepath()) : ImagePtr(doc->data());
}
}
@ -185,8 +256,8 @@ bool StickerSetInner::loaded() const {
int32 StickerSetInner::notInstalled() const {
if (!_loaded) return 0;
StickerSets::const_iterator it = cStickerSets().constFind(_setId);
if (it == cStickerSets().cend() || (it->flags & MTPDstickerSet::flag_disabled)) return _pack.size();
auto it = Global::StickerSets().constFind(_setId);
if (it == Global::StickerSets().cend() || (it->flags & MTPDstickerSet::Flag::f_disabled)) return _pack.size();
return 0;
}
@ -611,14 +682,14 @@ void StickersInner::rebuild() {
int32 namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x() - qMax(qMax(_returnWidth, _removeWidth), _restoreWidth);
clear();
const StickerSetsOrder &order(cStickerSetsOrder());
const Stickers::Order &order(Global::StickerSetsOrder());
_animStartTimes.reserve(order.size());
const StickerSets &sets(cStickerSets());
for (int32 i = 0, l = order.size(); i < l; ++i) {
StickerSets::const_iterator it = sets.constFind(order.at(i));
const Stickers::Sets &sets(Global::StickerSets());
for (int i = 0, l = order.size(); i < l; ++i) {
auto it = sets.constFind(order.at(i));
if (it != sets.cend()) {
bool disabled = (it->flags & MTPDstickerSet::flag_disabled);
bool disabled = (it->flags & MTPDstickerSet::Flag::f_disabled);
DocumentData *sticker = it->stickers.isEmpty() ? 0 : it->stickers.at(0);
int32 pixw = 0, pixh = 0;
@ -643,10 +714,10 @@ void StickersInner::rebuild() {
if (titleWidth > namew) {
title = st::contactsNameFont->elided(title, namew);
}
bool official = (it->flags & MTPDstickerSet::flag_official);
bool official = (it->flags & MTPDstickerSet::Flag::f_official);
(disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, official, disabled, pixw, pixh));
_animStartTimes.push_back(0);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_flag_NOT_LOADED)) {
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
App::api()->scheduleStickerSetRequest(it->id, it->access);
}
}
@ -661,8 +732,8 @@ QVector<uint64> StickersInner::getOrder() const {
result.reserve(_rows.size());
for (int32 i = 0, l = _rows.size(); i < l; ++i) {
if (_rows.at(i)->disabled) {
StickerSets::const_iterator it = cStickerSets().constFind(_rows.at(i)->id);
if (it == cStickerSets().cend() || !(it->flags & MTPDstickerSet::flag_official)) {
auto it = Global::StickerSets().constFind(_rows.at(i)->id);
if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_official)) {
continue;
}
}
@ -704,6 +775,7 @@ StickersBox::StickersBox() : ItemListBox(st::boxScroll)
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated()));
App::main()->updateStickers();
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
@ -761,7 +833,7 @@ void StickersBox::reorderDone(const MTPBool &result) {
bool StickersBox::reorderFail(const RPCError &result) {
if (mtpIsFlood(result)) return false;
_reorderRequest = 0;
cSetLastStickersUpdate(0);
Global::SetLastStickersUpdate(0);
App::main()->updateStickers();
onClose();
return true;
@ -785,12 +857,12 @@ void StickersBox::closePressed() {
MTP::cancel(i.key());
}
_disenableRequests.clear();
cSetLastStickersUpdate(0);
Global::SetLastStickersUpdate(0);
App::main()->updateStickers();
} else if (_reorderRequest) {
MTP::cancel(_reorderRequest);
_reorderRequest = 0;
cSetLastStickersUpdate(0);
Global::SetLastStickersUpdate(0);
App::main()->updateStickers();
}
}
@ -842,11 +914,11 @@ void StickersBox::onSave() {
bool writeRecent = false;
RecentStickerPack &recent(cGetRecentStickers());
StickerSets &sets(cRefStickerSets());
Stickers::Sets &sets(Global::RefStickerSets());
QVector<uint64> reorder = _inner.getOrder(), disabled = _inner.getDisabledSets();
for (int32 i = 0, l = disabled.size(); i < l; ++i) {
StickerSets::iterator it = sets.find(disabled.at(i));
auto it = sets.find(disabled.at(i));
if (it != sets.cend()) {
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
@ -856,35 +928,35 @@ void StickersBox::onSave() {
++i;
}
}
if (!(it->flags & MTPDstickerSet::flag_disabled)) {
if (!(it->flags & MTPDstickerSet::Flag::f_disabled)) {
MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
if (it->flags & MTPDstickerSet::flag_official) {
if (it->flags & MTPDstickerSet::Flag::f_official) {
_disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolTrue()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType());
it->flags |= MTPDstickerSet::flag_disabled;
it->flags |= MTPDstickerSet::Flag::f_disabled;
} else {
_disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType());
int32 removeIndex = cStickerSetsOrder().indexOf(it->id);
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex);
int removeIndex = Global::StickerSetsOrder().indexOf(it->id);
if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex);
sets.erase(it);
}
}
}
}
StickerSetsOrder &order(cRefStickerSetsOrder());
Stickers::Order &order(Global::RefStickerSetsOrder());
order.clear();
for (int32 i = 0, l = reorder.size(); i < l; ++i) {
StickerSets::iterator it = sets.find(reorder.at(i));
for (int i = 0, l = reorder.size(); i < l; ++i) {
auto it = sets.find(reorder.at(i));
if (it != sets.cend()) {
if ((it->flags & MTPDstickerSet::flag_disabled) && !disabled.contains(it->id)) {
if ((it->flags & MTPDstickerSet::Flag::f_disabled) && !disabled.contains(it->id)) {
MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
_disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolFalse()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType());
it->flags &= ~MTPDstickerSet::flag_disabled;
it->flags &= ~MTPDstickerSet::Flag::f_disabled;
}
order.push_back(reorder.at(i));
}
}
for (StickerSets::iterator it = sets.begin(); it != sets.cend();) {
if (it->id == CustomStickerSetId || it->id == RecentStickerSetId || order.contains(it->id)) {
for (auto it = sets.begin(); it != sets.cend();) {
if (it->id == Stickers::CustomSetId || it->id == Stickers::RecentSetId || order.contains(it->id)) {
++it;
} else {
it = sets.erase(it);
@ -920,12 +992,12 @@ void StickersBox::showAll() {
int32 stickerPacksCount(bool includeDisabledOfficial) {
int32 result = 0;
const StickerSetsOrder &order(cStickerSetsOrder());
const StickerSets &sets(cStickerSets());
for (int32 i = 0, l = order.size(); i < l; ++i) {
StickerSets::const_iterator it = sets.constFind(order.at(i));
const Stickers::Order &order(Global::StickerSetsOrder());
const Stickers::Sets &sets(Global::StickerSets());
for (int i = 0, l = order.size(); i < l; ++i) {
auto it = sets.constFind(order.at(i));
if (it != sets.cend()) {
if (!(it->flags & MTPDstickerSet::flag_disabled) || ((it->flags & MTPDstickerSet::flag_official) && includeDisabledOfficial)) {
if (!(it->flags & MTPDstickerSet::Flag::f_disabled) || ((it->flags & MTPDstickerSet::Flag::f_official) && includeDisabledOfficial)) {
++result;
}
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -29,7 +29,9 @@ public:
StickerSetInner(const MTPInputStickerSet &set);
void init();
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void paintEvent(QPaintEvent *e);
@ -42,10 +44,12 @@ public:
void setScrollBottom(int32 bottom);
void install();
QString getTitle() const;
~StickerSetInner();
public slots:
void onPreview();
signals:
void updateButtons();
@ -53,6 +57,8 @@ signals:
private:
int32 stickerFromGlobalPos(const QPoint &p) const;
void gotSet(const MTPmessages_StickerSet &set);
bool failedSet(const RPCError &error);
@ -60,15 +66,20 @@ private:
bool installFailed(const RPCError &error);
StickerPack _pack;
StickersByEmojiMap _emoji;
bool _loaded;
uint64 _setId, _setAccess;
QString _title, _setTitle, _setShortName;
int32 _setCount, _setHash, _setFlags;
int32 _setCount, _setHash;
MTPDstickerSet::Flags _setFlags;
int32 _bottom;
MTPInputStickerSet _input;
mtpRequestId _installRequest;
QTimer _previewTimer;
int32 _previewShown;
};
class StickerSetBox : public ScrollableBox, public RPCSender {

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
@ -160,7 +160,7 @@ void UsernameBox::onChanged() {
}
_checkTimer.stop();
} else {
int32 i, len = name.size();
int32 len = name.size();
for (int32 i = 0; i < len; ++i) {
QChar ch = name.at(i);
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_' && (ch != '@' || i > 0)) {
@ -191,7 +191,7 @@ void UsernameBox::onChanged() {
}
void UsernameBox::onLinkClick() {
App::app()->clipboard()->setText(qsl("https://telegram.me/") + getName());
Application::clipboard()->setText(qsl("https://telegram.me/") + getName());
_copiedTextLink = lang(lng_username_copied);
update();
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -0,0 +1,3 @@
int main(int argc, char *argv[]) {
return 0;
}

View file

@ -16,14 +16,14 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
static const int32 AppVersion = 9017;
static const wchar_t *AppVersionStr = L"0.9.17";
static const int32 AppVersion = 9040;
static const wchar_t *AppVersionStr = L"0.9.40";
static const bool DevVersion = false;
//#define BETA_VERSION (9015008ULL) // just comment this line to build public version
//#define BETA_VERSION (9034004ULL) // just comment this line to build public version
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";
@ -51,11 +51,11 @@ enum {
MTPIPv4ConnectionWaitTimeout = 1000, // 1 seconds waiting for ipv4, until we accept ipv6
MTPMillerRabinIterCount = 30, // 30 Miller-Rabin iterations for dh_prime primality check
MTPUploadSessionsCount = 4, // max 4 upload sessions is created
MTPDownloadSessionsCount = 4, // max 4 download sessions is created
MTPUploadSessionsCount = 2, // max 2 upload sessions is created
MTPDownloadSessionsCount = 2, // max 2 download sessions is created
MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill
MTPEnumDCTimeout = 4000, // 4 seconds timeout for help_getConfig to work (them move to other dc)
MTPEnumDCTimeout = 8000, // 8 seconds timeout for help_getConfig to work (then move to other dc)
MTPDebugBufferSize = 1024 * 1024, // 1 mb start size
@ -101,6 +101,9 @@ enum {
MediaOverviewStartPerPage = 5,
MediaOverviewPreloadCount = 4,
// a new message from the same sender is attached to previous within 15 minutes
AttachMessageToPreviousSecondsDelta = 900,
AudioVoiceMsgSimultaneously = 4,
AudioSongSimultaneously = 4,
AudioCheckPositionTimeout = 100, // 100ms per check audio pos
@ -118,6 +121,8 @@ enum {
AudioVoiceMsgInMemory = 2 * 1024 * 1024, // 2 Mb audio is hold in memory and auto loaded
AudioPauseDeviceTimeout = 3000, // pause in 3 secs after playing is over
WaveformSamplesCount = 100,
StickerInMemory = 2 * 1024 * 1024, // 2 Mb stickers hold in memory, auto loaded and displayed inline
StickerMaxSize = 2048, // 2048x2048 is a max image size for sticker
@ -127,12 +132,13 @@ enum {
MaxZoomLevel = 7, // x8
ZoomToScreenLevel = 1024, // just constant
ShortcutsCountLimit = 256, // how many shortcuts can be in json file
PreloadHeightsCount = 3, // when 3 screens to scroll left make a preload request
EmojiPanPerRow = 7,
EmojiPanRowsPerPage = 6,
StickerPanPerRow = 5,
StickerPanRowsPerPage = 4,
SavedGifsMaxPerRow = 4,
StickersUpdateTimeout = 3600000, // update not more than once in an hour
SearchPeopleLimit = 5,
@ -140,9 +146,9 @@ enum {
MaxUsernameLength = 32,
UsernameCheckTimeout = 200,
MaxChannelDescription = 120,
MaxChannelDescription = 255,
MaxGroupChannelTitle = 255,
MaxPhotoCaption = 140,
MaxPhotoCaption = 200,
MaxMessageSize = 4096,
MaxHttpRedirects = 5, // when getting external data/images
@ -167,6 +173,8 @@ enum {
ChoosePeerByDragTimeout = 1000, // 1 second mouse not moved to choose dialog when dragging a file
ReloadChannelMembersTimeout = 1000, // 1 second wait before reload members in channel after adding
PinnedMessageTextLimit = 16,
};
inline bool isNotificationsUser(uint64 id) {
@ -191,7 +199,7 @@ inline const char *cGUIDStr() {
return gGuidStr;
}
inline const char **cPublicRSAKeys(uint32 &cnt) {
inline const char **cPublicRSAKeys(int &keysCount) {
static const char *(keys[]) = {"\
-----BEGIN RSA PUBLIC KEY-----\n\
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n\
@ -201,7 +209,7 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n\
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\
-----END RSA PUBLIC KEY-----"};
cnt = sizeof(keys) / sizeof(const char*);
keysCount = arraysize(keys);
return keys;
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once

View file

@ -16,10 +16,10 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "style.h"
#include "gui/style.h"
#include "lang.h"
#include "application.h"
@ -247,18 +247,15 @@ void DialogsInner::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool a
History *history = App::history(peer->id);
if (peer->migrateTo()) {
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, peer->migrateTo()->photo->pix(st::dlgPhotoSize));
} else {
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, peer->photo->pix(st::dlgPhotoSize));
}
PeerData *userpicPeer = (peer->migrateTo() ? peer->migrateTo() : peer);
userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth());
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
int32 namewidth = w - nameleft - st::dlgPaddingHor;
QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
// draw chat icon
if (peer->isChat()) {
if (peer->isChat() || peer->isMegagroup()) {
p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), App::sprite(), (act ? st::dlgActiveChatImg : st::dlgChatImg));
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
} else if (peer->isChannel()) {
@ -299,7 +296,7 @@ void DialogsInner::searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) c
p.fillRect(fullRect, st::dlgBG->b);
if (onlyBackground) return;
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, _searchInPeer->photo->pix(st::dlgPhotoSize));
_searchInPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth());
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
int32 namewidth = w - nameleft - st::dlgPaddingHor * 2 - st::btnCancelSearch.width;
@ -443,16 +440,12 @@ void DialogsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
}
void DialogsInner::createDialog(History *history) {
bool creating = history->dialogs.isEmpty();
bool creating = !history->inChatList();
if (creating) {
history->dialogs = dialogs.addToEnd(history);
contactsNoDialogs.del(history->peer, history->dialogs[0]);
DialogRow *mainRow = history->addToChatList(dialogs);
contactsNoDialogs.del(history->peer, mainRow);
}
History::DialogLinks links = history->dialogs;
int32 movedFrom = links[0]->pos * st::dlgHeight;
dialogs.adjustByPos(links);
int32 movedTo = links[0]->pos * st::dlgHeight;
RefPair(int32, movedFrom, int32, movedTo) = history->adjustByPosInChatsList(dialogs);
emit dialogMoved(movedFrom, movedTo);
@ -471,8 +464,7 @@ void DialogsInner::removeDialog(History *history) {
if (sel && sel->history == history) {
sel = 0;
}
dialogs.del(history->peer);
history->dialogs = History::DialogLinks();
history->removeFromChatList(dialogs);
history->clearNotifications();
if (App::wnd()) App::wnd()->notifyClear(history);
if (contacts.list.rowByPeer.constFind(history->peer->id) != contacts.list.rowByPeer.cend()) {
@ -550,8 +542,8 @@ void DialogsInner::updateSelectedRow(PeerData *peer) {
if (_state == DefaultState) {
if (peer) {
if (History *h = App::historyLoaded(peer->id)) {
if (h->dialogs.contains(0)) {
update(0, h->dialogs.value(0)->pos * st::dlgHeight, fullWidth(), st::dlgHeight);
if (h->inChatList()) {
update(0, h->posInChatList() * st::dlgHeight, fullWidth(), st::dlgHeight);
}
}
} else if (sel) {
@ -624,7 +616,7 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) {
if (_menuPeer->isUser()) {
_menu->addAction(lang(lng_profile_clear_history), this, SLOT(onContextClearHistory()))->setEnabled(true);
_menu->addAction(lang(lng_profile_delete_conversation), this, SLOT(onContextDeleteAndLeave()))->setEnabled(true);
if (_menuPeer->asUser()->access != UserNoAccess) {
if (_menuPeer->asUser()->access != UserNoAccess && _menuPeer != App::self()) {
_menu->addAction(lang((_menuPeer->asUser()->blocked == UserIsBlocked) ? (_menuPeer->asUser()->botInfo ? lng_profile_unblock_bot : lng_profile_unblock_user) : (_menuPeer->asUser()->botInfo ? lng_profile_block_bot : lng_profile_block_user)), this, SLOT(onContextToggleBlock()))->setEnabled(true);
connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData*)));
}
@ -651,7 +643,7 @@ void DialogsInner::onContextProfile() {
void DialogsInner::onContextToggleNotifications() {
if (!_menuPeer) return;
App::main()->updateNotifySetting(_menuPeer, menuPeerMuted());
App::main()->updateNotifySetting(_menuPeer, menuPeerMuted() ? NotifySettingSetNotify : NotifySettingSetMuted);
}
void DialogsInner::onContextSearch() {
@ -963,7 +955,9 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) {
case mtpc_dialog: {
const MTPDdialog &d(i->c_dialog());
history = App::historyFromDialog(peerFromMTP(d.vpeer), d.vunread_count.v, d.vread_inbox_max_id.v);
App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history);
if (App::main()) {
App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history);
}
} break;
case mtpc_dialogChannel: {
@ -986,7 +980,9 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) {
if (!history->isMegagroup() && d.vtop_message.v > d.vtop_important_message.v) {
history->setNotLoadedAtBottom();
}
App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history);
if (App::main()) {
App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history);
}
} break;
}
@ -1015,7 +1011,7 @@ void DialogsInner::addSavedPeersAfter(const QDateTime &date) {
SavedPeersByTime &saved(cRefSavedPeersByTime());
while (!saved.isEmpty() && (date.isNull() || date < saved.lastKey())) {
History *history = App::history(saved.last()->id);
history->setPosInDialogsDate(saved.lastKey());
history->setChatsListDate(saved.lastKey());
contactsNoDialogs.del(history->peer);
saved.remove(saved.lastKey(), saved.last());
}
@ -1040,13 +1036,16 @@ bool DialogsInner::searchReceived(const QVector<MTPMessage> &messages, DialogsSe
_lastSearchDate = lastDateFound;
}
}
if (type == DialogsSearchFromStart || type == DialogsSearchFromOffset) {
_lastSearchPeer = item->history()->peer;
if (item) {
if (type == DialogsSearchFromStart || type == DialogsSearchFromOffset) {
_lastSearchPeer = item->history()->peer;
}
}
MsgId msgId = item ? item->id : idFromMessage(*i);
if (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset) {
_lastSearchMigratedId = item->id;
_lastSearchMigratedId = msgId;
} else {
_lastSearchId = item->id;
_lastSearchId = msgId;
}
}
if (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset) {
@ -1067,8 +1066,11 @@ void DialogsInner::peopleReceived(const QString &query, const QVector<MTPPeer> &
_peopleResults.reserve(people.size());
for (QVector<MTPPeer>::const_iterator i = people.cbegin(), e = people.cend(); i != e; ++i) {
PeerId peerId = peerFromMTP(*i);
History *h = App::historyLoaded(peerId);
if (h && !h->dialogs.isEmpty()) continue; // skip dialogs
if (History *h = App::historyLoaded(peerId)) {
if (h->inChatList()) {
continue; // skip existing chats
}
}
_peopleResults.push_back(App::peer(peerId));
}
@ -1359,6 +1361,8 @@ void DialogsInner::selectSkipPage(int32 pixels, int32 direction) {
}
void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (!parentWidget()) return;
int32 yTo = yFrom + parentWidget()->height() * 5;
MTP::clearLoaderPriorities();
if (_state == DefaultState) {
@ -1366,7 +1370,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (yFrom < otherStart) {
dialogs.list.adjustCurrent(yFrom, st::dlgHeight);
for (DialogRow *row = dialogs.list.current; row != dialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) {
row->history->peer->photo->load();
row->history->peer->loadUserpic();
}
yFrom = 0;
} else {
@ -1376,7 +1380,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (yTo > 0) {
contactsNoDialogs.list.adjustCurrent(yFrom, st::dlgHeight);
for (DialogRow *row = contactsNoDialogs.list.current; row != contactsNoDialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) {
row->history->peer->photo->load();
row->history->peer->loadUserpic();
}
}
} else if (_state == FilteredState || _state == SearchedState) {
@ -1387,7 +1391,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (to > _filterResults.size()) to = _filterResults.size();
for (; from < to; ++from) {
_filterResults[from]->history->peer->photo->load();
_filterResults[from]->history->peer->loadUserpic();
}
}
@ -1398,7 +1402,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (to > _peopleResults.size()) to = _peopleResults.size();
for (; from < to; ++from) {
_peopleResults[from]->photo->load();
_peopleResults[from]->loadUserpic();
}
}
from = (yFrom > filteredOffset() + ((_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight) ? ((yFrom - filteredOffset() - (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - _filterResults.size() - _peopleResults.size();
@ -1408,7 +1412,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (to > _searchResults.size()) to = _searchResults.size();
for (; from < to; ++from) {
_searchResults[from]->_item->history()->peer->photo->load();
_searchResults[from]->_item->history()->peer->loadUserpic();
}
}
}
@ -1515,6 +1519,11 @@ void DialogsInner::destroyData() {
}
void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
if (!inPeer) {
outPeer = 0;
outMsg = 0;
return;
}
if (_state == DefaultState) {
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id);
if (i == dialogs.list.rowByPeer.constEnd()) {
@ -1599,6 +1608,11 @@ void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&ou
}
void DialogsInner::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
if (!inPeer) {
outPeer = 0;
outMsg = 0;
return;
}
if (_state == DefaultState) {
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id);
if (i == dialogs.list.rowByPeer.constEnd()) {
@ -1777,11 +1791,11 @@ void DialogsWidget::activate() {
}
void DialogsWidget::createDialog(History *history) {
bool creating = history->dialogs.isEmpty();
bool creating = !history->inChatList();
_inner.createDialog(history);
if (creating && history->peer->migrateFrom()) {
if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) {
if (!h->dialogs.isEmpty()) {
if (h->inChatList()) {
removeDialog(h);
}
}
@ -2038,8 +2052,11 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
MTP::cancel(_searchRequest);
}
if (_searchInPeer) {
int32 flags = (_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) ? MTPmessages_Search::flag_important_only : 0;
_searchRequest = MTP::send(MTPmessages_Search(MTP_int(flags), _searchInPeer->input, MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, DialogsSearchPeerFromStart), rpcFail(&DialogsWidget::searchFailed, DialogsSearchPeerFromStart));
MTPmessages_Search::Flags flags = 0;
if (_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) {
flags |= MTPmessages_Search::Flag::f_important_only;
}
_searchRequest = MTP::send(MTPmessages_Search(MTP_flags(flags), _searchInPeer->input, MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, DialogsSearchPeerFromStart), rpcFail(&DialogsWidget::searchFailed, DialogsSearchPeerFromStart));
} else {
_searchRequest = MTP::send(MTPmessages_SearchGlobal(MTP_string(_searchQuery), MTP_int(0), MTP_inputPeerEmpty(), MTP_int(0), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, DialogsSearchFromStart), rpcFail(&DialogsWidget::searchFailed, DialogsSearchFromStart));
}
@ -2077,6 +2094,7 @@ void DialogsWidget::onChooseByDrag() {
void DialogsWidget::searchMessages(const QString &query, PeerData *inPeer) {
if ((_filter.getLastText() != query) || (inPeer && inPeer != _searchInPeer && inPeer->migrateTo() != _searchInPeer)) {
if (inPeer) {
onCancelSearch();
_searchInPeer = inPeer->migrateTo() ? inPeer->migrateTo() : inPeer;
_searchInMigrated = _searchInPeer ? _searchInPeer->migrateFrom() : 0;
_inner.searchInPeer(_searchInPeer);
@ -2098,8 +2116,11 @@ void DialogsWidget::onSearchMore() {
PeerData *offsetPeer = _inner.lastSearchPeer();
MsgId offsetId = _inner.lastSearchId();
if (_searchInPeer) {
int32 flags = (_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) ? MTPmessages_Search::flag_important_only : 0;
_searchRequest = MTP::send(MTPmessages_Search(MTP_int(flags), _searchInPeer->input, MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(offsetId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, offsetId ? DialogsSearchPeerFromOffset : DialogsSearchPeerFromStart), rpcFail(&DialogsWidget::searchFailed, offsetId ? DialogsSearchPeerFromOffset : DialogsSearchPeerFromStart));
MTPmessages_Search::Flags flags = 0;
if (_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) {
flags |= MTPmessages_Search::Flag::f_important_only;
}
_searchRequest = MTP::send(MTPmessages_Search(MTP_flags(flags), _searchInPeer->input, MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(offsetId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, offsetId ? DialogsSearchPeerFromOffset : DialogsSearchPeerFromStart), rpcFail(&DialogsWidget::searchFailed, offsetId ? DialogsSearchPeerFromOffset : DialogsSearchPeerFromStart));
} else {
_searchRequest = MTP::send(MTPmessages_SearchGlobal(MTP_string(_searchQuery), MTP_int(offsetDate), offsetPeer ? offsetPeer->input : MTP_inputPeerEmpty(), MTP_int(offsetId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, offsetId ? DialogsSearchFromOffset : DialogsSearchFromStart), rpcFail(&DialogsWidget::searchFailed, offsetId ? DialogsSearchFromOffset : DialogsSearchFromStart));
}
@ -2108,8 +2129,11 @@ void DialogsWidget::onSearchMore() {
}
} else if (_searchInMigrated && !_searchFullMigrated) {
MsgId offsetMigratedId = _inner.lastSearchMigratedId();
int32 flags = (_searchInMigrated->isChannel() && !_searchInMigrated->isMegagroup()) ? MTPmessages_Search::flag_important_only : 0;
_searchRequest = MTP::send(MTPmessages_Search(MTP_int(flags), _searchInMigrated->input, MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(offsetMigratedId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, offsetMigratedId ? DialogsSearchMigratedFromOffset : DialogsSearchMigratedFromStart), rpcFail(&DialogsWidget::searchFailed, offsetMigratedId ? DialogsSearchMigratedFromOffset : DialogsSearchMigratedFromStart));
MTPmessages_Search::Flags flags = 0;
if (_searchInMigrated->isChannel() && !_searchInMigrated->isMegagroup()) {
flags |= MTPmessages_Search::Flag::f_important_only;
}
_searchRequest = MTP::send(MTPmessages_Search(MTP_flags(flags), _searchInMigrated->input, MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(offsetMigratedId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, offsetMigratedId ? DialogsSearchMigratedFromOffset : DialogsSearchMigratedFromStart), rpcFail(&DialogsWidget::searchFailed, offsetMigratedId ? DialogsSearchMigratedFromOffset : DialogsSearchMigratedFromStart));
}
}
}
@ -2268,7 +2292,7 @@ void DialogsWidget::dragEnterEvent(QDragEnterEvent *e) {
_dragForward = e->mimeData()->hasFormat(qsl("application/x-td-forward-selected"));
if (!_dragForward) _dragForward = e->mimeData()->hasFormat(qsl("application/x-td-forward-pressed-link"));
if (!_dragForward) _dragForward = e->mimeData()->hasFormat(qsl("application/x-td-forward-pressed"));
if (_dragForward && !cWideMode()) _dragForward = false;
if (_dragForward && Adaptive::OneColumn()) _dragForward = false;
if (_dragForward) {
e->setDropAction(Qt::CopyAction);
e->accept();
@ -2540,7 +2564,7 @@ bool DialogsWidget::onCancelSearch() {
_searchRequest = 0;
}
if (_searchInPeer && !clearing) {
if (!cWideMode()) {
if (Adaptive::OneColumn()) {
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
}
_searchInPeer = _searchInMigrated = 0;
@ -2560,7 +2584,7 @@ void DialogsWidget::onCancelSearchInPeer() {
_searchRequest = 0;
}
if (_searchInPeer) {
if (!cWideMode() && !App::main()->selectingPeer()) {
if (Adaptive::OneColumn() && !App::main()->selectingPeer()) {
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
}
_searchInPeer = _searchInMigrated = 0;
@ -2570,7 +2594,7 @@ void DialogsWidget::onCancelSearchInPeer() {
_filter.clear();
_filter.updatePlaceholder();
onFilterUpdate();
if (cWideMode() && !App::main()->selectingPeer()) {
if (!Adaptive::OneColumn() && !App::main()->selectingPeer()) {
emit cancelled();
}
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -67,7 +67,6 @@ public:
void selectSkipPage(int32 pixels, int32 direction);
void createDialog(History *history);
void moveDialogToTop(const History::DialogLinks &links);
void dlgUpdated(DialogRow *row);
void dlgUpdated(History *row, MsgId msgId);
void removeDialog(History *history);
@ -220,15 +219,15 @@ public:
void searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req);
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req);
void dragEnterEvent(QDragEnterEvent *e);
void dragMoveEvent(QDragMoveEvent *e);
void dragLeaveEvent(QDragLeaveEvent *e);
void dropEvent(QDropEvent *e);
void dragEnterEvent(QDragEnterEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e) override;
void updateDragInScroll(bool inScroll);
void resizeEvent(QResizeEvent *e);
void keyPressEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void searchInPeer(PeerData *peer);
@ -260,6 +259,11 @@ public:
void updateNotifySettings(PeerData *peer);
void rpcClear() override {
_inner.rpcClear();
RPCSender::rpcClear();
}
void notify_userIsContactChanged(UserData *user, bool fromThisApp);
signals:

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -157,8 +157,21 @@ private:
};
class EmojiPanel;
static const int EmojiColorsCount = 5;
namespace InlineBots {
namespace Layout {
class ItemBase;
} // namespace Layout
class Result;
} // namespace InlineBots
namespace internal {
constexpr int InlineItemsMaxPerRow = 5;
constexpr int EmojiColorsCount = 5;
using InlineResult = InlineBots::Result;
using InlineResults = QList<InlineBots::Result*>;
using InlineItem = InlineBots::Layout::ItemBase;
class EmojiColorPicker : public TWidget {
Q_OBJECT
@ -222,6 +235,7 @@ private:
};
class EmojiPanel;
class EmojiPanInner : public TWidget {
Q_OBJECT
@ -359,8 +373,8 @@ public:
uint64 currentSet(int yOffset) const;
void ui_repaintInlineItem(const LayoutInlineItem *layout);
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
void ui_repaintInlineItem(const InlineItem *layout);
bool ui_isInlineItemVisible(const InlineItem *layout);
bool ui_isInlineItemBeingChosen();
bool inlineResultsShown() const {
@ -368,11 +382,7 @@ public:
}
int32 countHeight(bool plain = false);
~StickerPanInner() {
clearInlineRows(true);
deleteUnusedGifLayouts();
deleteUnusedInlineLayouts();
}
~StickerPanInner();
public slots:
@ -385,7 +395,7 @@ signals:
void selected(DocumentData *sticker);
void selected(PhotoData *photo);
void selected(InlineResult *result, UserData *bot);
void selected(InlineBots::Result *result, UserData *bot);
void removing(quint64 setId);
@ -420,10 +430,10 @@ private:
int32 _top;
struct DisplayedSet {
DisplayedSet(uint64 id, int32 flags, const QString &title, int32 hoversSize, const StickerPack &pack = StickerPack()) : id(id), flags(flags), title(title), hovers(hoversSize, 0), pack(pack) {
DisplayedSet(uint64 id, MTPDstickerSet::Flags flags, const QString &title, int32 hoversSize, const StickerPack &pack = StickerPack()) : id(id), flags(flags), title(title), hovers(hoversSize, 0), pack(pack) {
}
uint64 id;
int32 flags;
MTPDstickerSet::Flags flags;
QString title;
QVector<float64> hovers;
StickerPack pack;
@ -439,7 +449,7 @@ private:
QTimer _updateInlineItems;
bool _inlineWithThumb;
typedef QVector<LayoutInlineItem*> InlineItems;
typedef QVector<InlineItem*> InlineItems;
struct InlineRow {
InlineRow() : height(0) {
}
@ -450,13 +460,13 @@ private:
InlineRows _inlineRows;
void clearInlineRows(bool resultsDeleted);
typedef QMap<DocumentData*, LayoutInlineGif*> GifLayouts;
using GifLayouts = QMap<DocumentData*, InlineItem*>;
GifLayouts _gifLayouts;
LayoutInlineGif *layoutPrepareSavedGif(DocumentData *doc, int32 position);
InlineItem *layoutPrepareSavedGif(DocumentData *doc, int32 position);
typedef QMap<InlineResult*, LayoutInlineItem*> InlineLayouts;
using InlineLayouts = QMap<InlineResult*, InlineItem*>;
InlineLayouts _inlineLayouts;
LayoutInlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
InlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
@ -469,7 +479,6 @@ private:
int32 validateExistingInlineRows(const InlineResults &results);
int32 _selected, _pressedSel;
QPoint _lastMousePos;
TextLinkPtr _linkOver, _linkDown;
LinkButton _settings;
@ -482,7 +491,7 @@ class EmojiPanel : public TWidget {
public:
EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY); // NoneStickerSetId if in emoji
EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY); // Stickers::NoneSetId if in emoji
void setText(const QString &text);
void setDeleteVisible(bool isVisible);
@ -532,6 +541,8 @@ protected:
};
} // namespace internal
class EmojiPan : public TWidget, public RPCSender {
Q_OBJECT
@ -580,8 +591,8 @@ public:
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
void ui_repaintInlineItem(const LayoutInlineItem *layout);
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemBeingChosen();
bool inlineResultsShown() const {
@ -622,7 +633,7 @@ signals:
void emojiSelected(EmojiPtr emoji);
void stickerSelected(DocumentData *sticker);
void photoSelected(PhotoData *photo);
void inlineResultSelected(InlineResult *result, UserData *bot);
void inlineResultSelected(InlineBots::Result *result, UserData *bot);
void updateStickers();
@ -642,7 +653,7 @@ private:
void updateIcons();
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab);
void updatePanelsPositions(const QVector<EmojiPanel*> &panels, int32 st);
void updatePanelsPositions(const QVector<internal::EmojiPanel*> &panels, int32 st);
void showAll();
void hideAll();
@ -661,7 +672,7 @@ private:
BoxShadow _shadow;
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
QList<StickerIcon> _icons;
QList<internal::StickerIcon> _icons;
QVector<float64> _iconHovers;
int32 _iconOver, _iconSel, _iconDown;
bool _iconsDragging;
@ -681,13 +692,13 @@ private:
Animation _a_slide;
ScrollArea e_scroll;
EmojiPanInner e_inner;
QVector<EmojiPanel*> e_panels;
EmojiSwitchButton e_switch;
internal::EmojiPanInner e_inner;
QVector<internal::EmojiPanel*> e_panels;
internal::EmojiSwitchButton e_switch;
ScrollArea s_scroll;
StickerPanInner s_inner;
QVector<EmojiPanel*> s_panels;
EmojiSwitchButton s_switch;
internal::StickerPanInner s_inner;
QVector<internal::EmojiPanel*> s_panels;
internal::EmojiSwitchButton s_switch;
uint64 _removingSetId;
@ -699,13 +710,9 @@ private:
clearResults();
}
QString nextOffset;
InlineResults results;
void clearResults() {
for (int32 i = 0, l = results.size(); i < l; ++i) {
delete results.at(i);
}
results.clear();
}
QString switchPmText, switchPmStartParam;
internal::InlineResults results;
void clearResults();
};
typedef QMap<QString, InlineCacheEntry*> InlineCache;
InlineCache _inlineCache;
@ -734,18 +741,20 @@ class MentionsInner : public TWidget {
public:
MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows);
MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerPack *srows);
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void clearSel();
bool moveSel(int direction);
void clearSel(bool hidden = false);
bool moveSel(int key);
bool select();
void setRecentInlineBotsInRows(int32 bots);
@ -755,27 +764,35 @@ public:
signals:
void chosen(QString mentionOrHashtag);
void selected(DocumentData *sticker);
void mustScrollTo(int scrollToTop, int scrollToBottom);
public slots:
void onParentGeometryChanged();
void onUpdateSelected(bool force = false);
void onPreview();
private:
void updateSelectedRow();
void setSel(int sel, bool scroll = false);
MentionsDropdown *_parent;
MentionRows *_mrows;
HashtagRows *_hrows;
BotCommandRows *_brows;
int32 _recentInlineBotsInRows;
int32 _sel;
StickerPack *_srows;
int32 _stickersPerRow, _recentInlineBotsInRows;
int32 _sel, _down;
bool _mouseSel;
QPoint _mousePos;
bool _overDelete;
bool _previewShown;
QTimer _previewTimer;
};
class MentionsDropdown : public TWidget {
@ -791,7 +808,8 @@ public:
bool clearFilteredBotCommands();
void showFiltered(PeerData *peer, QString query, bool start);
void updateFiltered(bool toDown = false);
void showStickers(EmojiPtr emoji);
void updateFiltered(bool resetScroll = false);
void setBoundings(QRect boundings);
void step_appearance(float64 ms, bool timer);
@ -807,6 +825,10 @@ public:
bool eventFilter(QObject *obj, QEvent *e);
QString getSelected() const;
bool stickersShown() const {
return !_srows.isEmpty();
}
bool overlaps(const QRect &globalRect) {
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false;
@ -818,6 +840,7 @@ public:
signals:
void chosen(QString mentionOrHashtag);
void stickerSelected(DocumentData *sticker);
public slots:
@ -828,14 +851,15 @@ public slots:
private:
void recount(bool toDown = false);
void recount(bool resetScroll = false);
QPixmap _cache;
MentionRows _mrows;
HashtagRows _hrows;
BotCommandRows _brows;
StickerPack _srows;
void rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, bool toDown);
void rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, const StickerPack &srows, bool resetScroll);
ScrollArea _scroll;
MentionsInner _inner;
@ -843,6 +867,7 @@ private:
ChatData *_chat;
UserData *_user;
ChannelData *_channel;
EmojiPtr _emoji;
QString _filter;
QRect _boundings;
bool _addInlineBots;

View file

@ -16,19 +16,26 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "window.h"
#include "mainwidget.h"
#include "application.h"
#include "boxes/confirmbox.h"
#include "layerwidget.h"
#include "lang.h"
Q_DECLARE_METATYPE(ClickHandlerPtr);
Q_DECLARE_METATYPE(Qt::MouseButton);
namespace App {
void sendBotCommand(const QString &cmd, MsgId replyTo) {
if (MainWidget *m = main()) m->sendBotCommand(cmd, replyTo);
void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) {
if (MainWidget *m = main()) m->sendBotCommand(peer, cmd, replyTo);
}
bool insertBotCommand(const QString &cmd, bool specialGif) {
@ -36,12 +43,55 @@ namespace App {
return false;
}
void searchByHashtag(const QString &tag, PeerData *inPeer) {
if (MainWidget *m = main()) m->searchMessages(tag + ' ', (inPeer && inPeer->isChannel()) ? inPeer : 0);
void activateBotCommand(const HistoryItem *msg, int row, int col) {
const HistoryMessageReplyMarkup::Button *button = nullptr;
if (auto *markup = msg->Get<HistoryMessageReplyMarkup>()) {
if (row < markup->rows.size()) {
const HistoryMessageReplyMarkup::ButtonRow &buttonRow(markup->rows.at(row));
if (col < buttonRow.size()) {
button = &buttonRow.at(col);
}
}
}
if (!button) return;
switch (button->type) {
case HistoryMessageReplyMarkup::Button::Default: {
// Copy string before passing it to the sending method
// because the original button can be destroyed inside.
MsgId replyTo = (msg->id > 0) ? msg->id : 0;
sendBotCommand(msg->history()->peer, QString(button->text), replyTo);
} break;
case HistoryMessageReplyMarkup::Button::Callback: {
if (MainWidget *m = main()) {
m->app_sendBotCallback(button, msg, row, col);
}
} break;
case HistoryMessageReplyMarkup::Button::Url: {
auto url = QString::fromUtf8(button->data);
HiddenUrlClickHandler(url).onClick(Qt::LeftButton);
} break;
case HistoryMessageReplyMarkup::Button::RequestLocation: {
Ui::showLayer(new InformBox(lang(lng_bot_share_location_unavailable)));
} break;
case HistoryMessageReplyMarkup::Button::RequestPhone: {
SharePhoneConfirmBox *box = new SharePhoneConfirmBox(msg->history()->peer);
box->connect(box, SIGNAL(confirmed(PeerData*)), App::main(), SLOT(onSharePhoneWithBot(PeerData*)));
Ui::showLayer(box);
} break;
}
}
void openPeerByName(const QString &username, bool toProfile, const QString &startToken) {
if (MainWidget *m = main()) m->openPeerByName(username, toProfile, startToken);
void searchByHashtag(const QString &tag, PeerData *inPeer) {
if (MainWidget *m = main()) m->searchMessages(tag + ' ', (inPeer && inPeer->isChannel() && !inPeer->isMegagroup()) ? inPeer : 0);
}
void openPeerByName(const QString &username, MsgId msgId, const QString &startToken) {
if (MainWidget *m = main()) m->openPeerByName(username, msgId, startToken);
}
void joinGroupByHash(const QString &hash) {
@ -62,11 +112,29 @@ namespace App {
}
void removeDialog(History *history) {
if (MainWidget *m = main()) m->removeDialog(history);
if (MainWidget *m = main()) {
m->removeDialog(history);
}
}
void showSettings() {
if (Window *win = wnd()) win->showSettings();
if (Window *w = wnd()) {
w->showSettings();
}
}
void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
if (Window *w = wnd()) {
qRegisterMetaType<ClickHandlerPtr>();
qRegisterMetaType<Qt::MouseButton>();
QMetaObject::invokeMethod(w, "app_activateClickHandler", Qt::QueuedConnection, Q_ARG(ClickHandlerPtr, handler), Q_ARG(Qt::MouseButton, button));
}
}
void logOutDelayed() {
if (Window *w = App::wnd()) {
QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection);
}
}
}
@ -74,11 +142,15 @@ namespace App {
namespace Ui {
void showStickerPreview(DocumentData *sticker) {
if (MainWidget *m = App::main()) m->ui_showStickerPreview(sticker);
if (Window *w = App::wnd()) {
w->ui_showStickerPreview(sticker);
}
}
void hideStickerPreview() {
if (MainWidget *m = App::main()) m->ui_hideStickerPreview();
if (Window *w = App::wnd()) {
w->ui_hideStickerPreview();
}
}
void showLayer(LayeredWidget *box, ShowLayerOptions options) {
@ -113,16 +185,22 @@ namespace Ui {
if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item);
}
void repaintInlineItem(const LayoutInlineItem *layout) {
void repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
if (!layout) return;
if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout);
}
bool isInlineItemVisible(const LayoutInlineItem *layout) {
bool isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout);
return false;
}
void autoplayMediaInlineAsync(const FullMsgId &msgId) {
if (MainWidget *m = App::main()) {
QMetaObject::invokeMethod(m, "ui_autoplayMediaInlineAsync", Qt::QueuedConnection, Q_ARG(qint32, msgId.channel), Q_ARG(qint32, msgId.msg));
}
}
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) {
if (MainWidget *m = App::main()) m->ui_showPeerHistory(peer, msgId, back);
}
@ -133,6 +211,29 @@ namespace Ui {
}
}
PeerData *getPeerForMouseAction() {
if (Window *w = App::wnd()) {
return w->ui_getPeerForMouseAction();
}
return nullptr;
}
bool hideWindowNoQuit() {
if (!App::quitting()) {
if (Window *w = App::wnd()) {
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
return w->minimizeToTray();
} else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
w->hide();
w->updateIsActive(Global::OfflineBlurTimeout());
w->updateGlobalMenu();
return true;
}
}
}
return false;
}
}
namespace Notify {
@ -153,6 +254,12 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting);
}
void replyMarkupUpdated(const HistoryItem *item) {
if (MainWidget *m = App::main()) {
m->notify_replyMarkupUpdated(item);
}
}
void migrateUpdated(PeerData *peer) {
if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer);
}
@ -161,10 +268,6 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_clipStopperHidden(type);
}
void historyItemResized(const HistoryItem *item, bool scrollToIt) {
if (MainWidget *m = App::main()) m->notify_historyItemResized(item, scrollToIt);
}
void historyItemLayoutChanged(const HistoryItem *item) {
if (MainWidget *m = App::main()) m->notify_historyItemLayoutChanged(item);
}
@ -173,4 +276,263 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_automaticLoadSettingsChangedGif();
}
void handlePendingHistoryUpdate() {
if (MainWidget *m = App::main()) {
m->notify_handlePendingHistoryUpdate();
}
for_const (HistoryItem *item, Global::PendingRepaintItems()) {
Ui::repaintHistoryItem(item);
}
Global::RefPendingRepaintItems().clear();
}
}
#define DefineReadOnlyVar(Namespace, Type, Name) const Type &Name() { \
t_assert_full(Namespace##Data != 0, #Namespace "Data != nullptr in " #Namespace "::" #Name, __FILE__, __LINE__); \
return Namespace##Data->Name; \
}
#define DefineRefVar(Namespace, Type, Name) DefineReadOnlyVar(Namespace, Type, Name) \
Type &Ref##Name() { \
t_assert_full(Namespace##Data != 0, #Namespace "Data != nullptr in " #Namespace "::Ref" #Name, __FILE__, __LINE__); \
return Namespace##Data->Name; \
}
#define DefineVar(Namespace, Type, Name) DefineRefVar(Namespace, Type, Name) \
void Set##Name(const Type &Name) { \
t_assert_full(Namespace##Data != 0, #Namespace "Data != nullptr in " #Namespace "::Set" #Name, __FILE__, __LINE__); \
Namespace##Data->Name = Name; \
}
namespace Sandbox {
namespace internal {
struct Data {
QString LangSystemISO;
int32 LangSystem = languageDefault;
QByteArray LastCrashDump;
ConnectionProxy PreLaunchProxy;
};
}
}
Sandbox::internal::Data *SandboxData = 0;
uint64 SandboxUserTag = 0;
namespace Sandbox {
bool CheckBetaVersionDir() {
QFile beta(cExeDir() + qsl("TelegramBeta_data/tdata/beta"));
if (cBetaVersion()) {
cForceWorkingDir(cExeDir() + qsl("TelegramBeta_data/"));
QDir().mkpath(cWorkingDir() + qstr("tdata"));
if (*BetaPrivateKey) {
cSetBetaPrivateKey(QByteArray(BetaPrivateKey));
}
if (beta.open(QIODevice::WriteOnly)) {
QDataStream dataStream(&beta);
dataStream.setVersion(QDataStream::Qt_5_3);
dataStream << quint64(cRealBetaVersion()) << cBetaPrivateKey();
} else {
LOG(("FATAL: Could not open '%1' for writing private key!").arg(beta.fileName()));
return false;
}
} else if (beta.exists()) {
cForceWorkingDir(cExeDir() + qsl("TelegramBeta_data/"));
if (beta.open(QIODevice::ReadOnly)) {
QDataStream dataStream(&beta);
dataStream.setVersion(QDataStream::Qt_5_3);
quint64 v;
QByteArray k;
dataStream >> v >> k;
if (dataStream.status() == QDataStream::Ok) {
cSetBetaVersion(qMax(v, AppVersion * 1000ULL));
cSetBetaPrivateKey(k);
cSetRealBetaVersion(v);
} else {
LOG(("FATAL: '%1' is corrupted, reinstall private beta!").arg(beta.fileName()));
return false;
}
} else {
LOG(("FATAL: could not open '%1' for reading private key!").arg(beta.fileName()));
return false;
}
}
return true;
}
void WorkingDirReady() {
if (QFile(cWorkingDir() + qsl("tdata/withtestmode")).exists()) {
cSetTestMode(true);
}
if (!cDebug() && QFile(cWorkingDir() + qsl("tdata/withdebug")).exists()) {
cSetDebug(true);
}
if (cBetaVersion()) {
cSetDevVersion(false);
} else if (!cDevVersion() && QFile(cWorkingDir() + qsl("tdata/devversion")).exists()) {
cSetDevVersion(true);
} else if (DevVersion) {
QFile f(cWorkingDir() + qsl("tdata/devversion"));
if (!f.exists() && f.open(QIODevice::WriteOnly)) {
f.write("1");
}
}
srand((int32)time(NULL));
SandboxUserTag = 0;
QFile usertag(cWorkingDir() + qsl("tdata/usertag"));
if (usertag.open(QIODevice::ReadOnly)) {
if (usertag.read(reinterpret_cast<char*>(&SandboxUserTag), sizeof(uint64)) != sizeof(uint64)) {
SandboxUserTag = 0;
}
usertag.close();
}
if (!SandboxUserTag) {
do {
memsetrnd_bad(SandboxUserTag);
} while (!SandboxUserTag);
if (usertag.open(QIODevice::WriteOnly)) {
usertag.write(reinterpret_cast<char*>(&SandboxUserTag), sizeof(uint64));
usertag.close();
}
}
}
void start() {
SandboxData = new internal::Data();
SandboxData->LangSystemISO = psCurrentLanguage();
if (SandboxData->LangSystemISO.isEmpty()) SandboxData->LangSystemISO = qstr("en");
QByteArray l = LangSystemISO().toLatin1();
for (int32 i = 0; i < languageCount; ++i) {
if (l.at(0) == LanguageCodes[i][0] && l.at(1) == LanguageCodes[i][1]) {
SandboxData->LangSystem = i;
break;
}
}
}
void finish() {
delete SandboxData;
SandboxData = 0;
}
uint64 UserTag() {
return SandboxUserTag;
}
DefineReadOnlyVar(Sandbox, QString, LangSystemISO);
DefineReadOnlyVar(Sandbox, int32, LangSystem);
DefineVar(Sandbox, QByteArray, LastCrashDump);
DefineVar(Sandbox, ConnectionProxy, PreLaunchProxy);
}
namespace Global {
namespace internal {
struct Data {
uint64 LaunchId = 0;
SingleDelayedCall HandleHistoryUpdate = { App::app(), "call_handleHistoryUpdate" };
Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout;
bool AdaptiveForWide = true;
int32 DebugLoggingFlags = 0;
// config
int32 ChatSizeMax = 200;
int32 MegagroupSizeMax = 1000;
int32 ForwardedCountMax = 100;
int32 OnlineUpdatePeriod = 120000;
int32 OfflineBlurTimeout = 5000;
int32 OfflineIdleTimeout = 30000;
int32 OnlineFocusTimeout = 1000;
int32 OnlineCloudTimeout = 300000;
int32 NotifyCloudDelay = 30000;
int32 NotifyDefaultDelay = 1500;
int32 ChatBigSize = 10;
int32 PushChatPeriod = 60000;
int32 PushChatLimit = 2;
int32 SavedGifsLimit = 200;
int32 EditTimeLimit = 172800;
HiddenPinnedMessagesMap HiddenPinnedMessages;
PendingItemsMap PendingRepaintItems;
Stickers::Sets StickerSets;
Stickers::Order StickerSetsOrder;
uint64 LastStickersUpdate = 0;
MTP::DcOptions DcOptions;
CircleMasksMap CircleMasks;
};
}
}
Global::internal::Data *GlobalData = 0;
namespace Global {
bool started() {
return GlobalData != 0;
}
void start() {
GlobalData = new internal::Data();
memset_rand(&GlobalData->LaunchId, sizeof(GlobalData->LaunchId));
}
void finish() {
delete GlobalData;
GlobalData = 0;
}
DefineReadOnlyVar(Global, uint64, LaunchId);
DefineRefVar(Global, SingleDelayedCall, HandleHistoryUpdate);
DefineVar(Global, Adaptive::Layout, AdaptiveLayout);
DefineVar(Global, bool, AdaptiveForWide);
DefineVar(Global, int32, DebugLoggingFlags);
// config
DefineVar(Global, int32, ChatSizeMax);
DefineVar(Global, int32, MegagroupSizeMax);
DefineVar(Global, int32, ForwardedCountMax);
DefineVar(Global, int32, OnlineUpdatePeriod);
DefineVar(Global, int32, OfflineBlurTimeout);
DefineVar(Global, int32, OfflineIdleTimeout);
DefineVar(Global, int32, OnlineFocusTimeout);
DefineVar(Global, int32, OnlineCloudTimeout);
DefineVar(Global, int32, NotifyCloudDelay);
DefineVar(Global, int32, NotifyDefaultDelay);
DefineVar(Global, int32, ChatBigSize);
DefineVar(Global, int32, PushChatPeriod);
DefineVar(Global, int32, PushChatLimit);
DefineVar(Global, int32, SavedGifsLimit);
DefineVar(Global, int32, EditTimeLimit);
DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages);
DefineRefVar(Global, PendingItemsMap, PendingRepaintItems);
DefineVar(Global, Stickers::Sets, StickerSets);
DefineVar(Global, Stickers::Order, StickerSetsOrder);
DefineVar(Global, uint64, LastStickersUpdate);
DefineVar(Global, MTP::DcOptions, DcOptions);
DefineRefVar(Global, CircleMasksMap, CircleMasks);
};

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -24,10 +24,11 @@ class LayeredWidget;
namespace App {
void sendBotCommand(const QString &cmd, MsgId replyTo = 0);
void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo = 0);
bool insertBotCommand(const QString &cmd, bool specialGif = false);
void activateBotCommand(const HistoryItem *msg, int row, int col);
void searchByHashtag(const QString &tag, PeerData *inPeer);
void openPeerByName(const QString &username, bool toProfile = false, const QString &startToken = QString());
void openPeerByName(const QString &username, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString());
void joinGroupByHash(const QString &hash);
void stickersBox(const QString &name);
void openLocalUrl(const QString &url);
@ -35,9 +36,21 @@ namespace App {
void removeDialog(History *history);
void showSettings();
void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
void logOutDelayed();
};
namespace Ui { // openssl doesn't allow me to use UI :(
namespace InlineBots {
namespace Layout {
class ItemBase;
} // namespace Layout
} // namespace InlineBots
namespace Ui {
void showStickerPreview(DocumentData *sticker);
void hideStickerPreview();
@ -49,8 +62,9 @@ namespace Ui { // openssl doesn't allow me to use UI :(
bool isInlineItemBeingChosen();
void repaintHistoryItem(const HistoryItem *item);
void repaintInlineItem(const LayoutInlineItem *layout);
bool isInlineItemVisible(const LayoutInlineItem *reader);
void repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
bool isInlineItemVisible(const InlineBots::Layout::ItemBase *reader);
void autoplayMediaInlineAsync(const FullMsgId &msgId);
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
inline void showPeerHistory(const PeerData *peer, MsgId msgId, bool back = false) {
@ -66,6 +80,12 @@ namespace Ui { // openssl doesn't allow me to use UI :(
inline void showChatsList() {
showPeerHistory(PeerId(0), 0);
}
inline void showChatsListAsync() {
showPeerHistoryAsync(PeerId(0), 0);
}
PeerData *getPeerForMouseAction();
bool hideWindowNoQuit();
};
@ -81,17 +101,138 @@ namespace Notify {
void botCommandsChanged(UserData *user);
void inlineBotRequesting(bool requesting);
void replyMarkupUpdated(const HistoryItem *item);
void migrateUpdated(PeerData *peer);
void clipStopperHidden(ClipStopperType type);
void historyItemResized(const HistoryItem *item, bool scrollToIt = false);
inline void historyItemsResized() {
historyItemResized(0);
}
void historyItemLayoutChanged(const HistoryItem *item);
void automaticLoadSettingsChangedGif();
// handle pending resize() / paint() on history items
void handlePendingHistoryUpdate();
};
#define DeclareReadOnlyVar(Type, Name) const Type &Name();
#define DeclareRefVar(Type, Name) DeclareReadOnlyVar(Type, Name) \
Type &Ref##Name();
#define DeclareVar(Type, Name) DeclareRefVar(Type, Name) \
void Set##Name(const Type &Name);
namespace Sandbox {
bool CheckBetaVersionDir();
void WorkingDirReady();
void start();
void finish();
uint64 UserTag();
DeclareReadOnlyVar(QString, LangSystemISO);
DeclareReadOnlyVar(int32, LangSystem);
DeclareVar(QByteArray, LastCrashDump);
DeclareVar(ConnectionProxy, PreLaunchProxy);
}
namespace Adaptive {
enum Layout {
OneColumnLayout,
NormalLayout,
WideLayout,
};
};
namespace DebugLogging {
enum Flags {
FileLoaderFlag = 0x00000001,
};
}
namespace Stickers {
static const uint64 DefaultSetId = 0; // for backward compatibility
static const uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL, RecentSetId = 0xFFFFFFFFFFFFFFFEULL;
static const uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel
struct Set {
Set(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, MTPDstickerSet::Flags flags) : id(id), access(access), title(title), shortName(shortName), count(count), hash(hash), flags(flags) {
}
uint64 id, access;
QString title, shortName;
int32 count, hash;
MTPDstickerSet::Flags flags;
StickerPack stickers;
StickersByEmojiMap emoji;
};
typedef QMap<uint64, Set> Sets;
typedef QList<uint64> Order;
}
namespace Global {
bool started();
void start();
void finish();
DeclareReadOnlyVar(uint64, LaunchId);
DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate);
DeclareVar(Adaptive::Layout, AdaptiveLayout);
DeclareVar(bool, AdaptiveForWide);
DeclareVar(int32, DebugLoggingFlags);
// config
DeclareVar(int32, ChatSizeMax);
DeclareVar(int32, MegagroupSizeMax);
DeclareVar(int32, ForwardedCountMax);
DeclareVar(int32, OnlineUpdatePeriod);
DeclareVar(int32, OfflineBlurTimeout);
DeclareVar(int32, OfflineIdleTimeout);
DeclareVar(int32, OnlineFocusTimeout); // not from config
DeclareVar(int32, OnlineCloudTimeout);
DeclareVar(int32, NotifyCloudDelay);
DeclareVar(int32, NotifyDefaultDelay);
DeclareVar(int32, ChatBigSize);
DeclareVar(int32, PushChatPeriod);
DeclareVar(int32, PushChatLimit);
DeclareVar(int32, SavedGifsLimit);
DeclareVar(int32, EditTimeLimit);
typedef QMap<PeerId, MsgId> HiddenPinnedMessagesMap;
DeclareVar(HiddenPinnedMessagesMap, HiddenPinnedMessages);
typedef OrderedSet<HistoryItem*> PendingItemsMap;
DeclareRefVar(PendingItemsMap, PendingRepaintItems);
DeclareVar(Stickers::Sets, StickerSets);
DeclareVar(Stickers::Order, StickerSetsOrder);
DeclareVar(uint64, LastStickersUpdate);
DeclareVar(MTP::DcOptions, DcOptions);
typedef QMap<uint64, QPixmap> CircleMasksMap;
DeclareRefVar(CircleMasksMap, CircleMasks);
};
namespace Adaptive {
inline bool OneColumn() {
return Global::AdaptiveLayout() == OneColumnLayout;
}
inline bool Normal() {
return Global::AdaptiveLayout() == NormalLayout;
}
inline bool Wide() {
return Global::AdaptiveForWide() && (Global::AdaptiveLayout() == WideLayout);
}
}
namespace DebugLogging {
inline bool FileLoader() {
return (Global::DebugLoggingFlags() | FileLoaderFlag) != 0;
}
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "fileuploader.h"
@ -32,7 +32,7 @@ FileUploader::FileUploader() : sentSize(0) {
void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &media) {
if (media.type == PreparePhoto) {
App::feedPhoto(media.photo, media.photoThumbs);
} else if (media.type == PrepareDocument) {
} else if (media.type == PrepareDocument || media.type == PrepareAudio) {
DocumentData *document;
if (media.photoThumbs.isEmpty()) {
document = App::feedDocument(media.document);
@ -40,13 +40,12 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
document = App::feedDocument(media.document, media.photoThumbs.begin().value());
}
document->status = FileUploading;
if (!media.data.isEmpty()) {
document->setData(media.data);
}
if (!media.file.isEmpty()) {
document->setLocation(FileLocation(StorageFilePartial, media.file));
}
} else if (media.type == PrepareAudio) {
AudioData *audio = App::feedAudio(media.audio);
audio->status = FileUploading;
audio->setData(media.data);
}
queue.insert(msgId, File(media));
sendNext();
@ -56,7 +55,7 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
if (file->type == PreparePhoto) {
PhotoData *photo = App::feedPhoto(file->photo, file->photoThumbs);
photo->uploadingData = new PhotoData::UploadingData(file->partssize);
} else if (file->type == PrepareDocument) {
} else if (file->type == PrepareDocument || file->type == PrepareAudio) {
DocumentData *document;
if (file->thumb.isNull()) {
document = App::feedDocument(file->document);
@ -64,13 +63,12 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
document = App::feedDocument(file->document, file->thumb);
}
document->status = FileUploading;
if (!file->content.isEmpty()) {
document->setData(file->content);
}
if (!file->filepath.isEmpty()) {
document->setLocation(FileLocation(StorageFilePartial, file->filepath));
}
} else if (file->type == PrepareAudio) {
AudioData *audio = App::feedAudio(file->audio);
audio->status = FileUploading;
audio->setData(file->content);
}
queue.insert(msgId, File(file));
sendNext();
@ -87,12 +85,6 @@ void FileUploader::currentFailed() {
doc->status = FileUploadFailed;
}
emit documentFailed(j.key());
} else if (j->type() == PrepareAudio) {
AudioData *audio = App::audio(j->id());
if (audio->status == FileUploading) {
audio->status = FileUploadFailed;
}
emit audioFailed(j.key());
}
queue.erase(j);
}
@ -111,7 +103,7 @@ void FileUploader::currentFailed() {
void FileUploader::killSessions() {
for (int i = 0; i < MTPUploadSessionsCount; ++i) {
MTP::stopSession(MTP::upl[i]);
MTP::stopSession(MTP::uplDcId(i));
}
}
@ -148,24 +140,19 @@ void FileUploader::sendNext() {
if (parts.isEmpty()) {
if (i->docSentParts >= i->docPartsCount) {
if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) {
bool silent = i->file && i->file->to.silent;
if (i->type() == PreparePhoto) {
emit photoReady(uploading, MTP_inputFile(MTP_long(i->id()), MTP_int(i->partsCount), MTP_string(i->filename()), MTP_string(i->file ? i->file->filemd5 : i->media.jpeg_md5)));
} else if (i->type() == PrepareDocument) {
emit photoReady(uploading, silent, MTP_inputFile(MTP_long(i->id()), MTP_int(i->partsCount), MTP_string(i->filename()), MTP_bytes(i->file ? i->file->filemd5 : i->media.jpeg_md5)));
} else if (i->type() == PrepareDocument || i->type() == PrepareAudio) {
QByteArray docMd5(32, Qt::Uninitialized);
hashMd5Hex(i->md5Hash.result(), docMd5.data());
MTPInputFile doc = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename())) : MTP_inputFile(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename()), MTP_string(docMd5));
MTPInputFile doc = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename())) : MTP_inputFile(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename()), MTP_bytes(docMd5));
if (i->partsCount) {
emit thumbDocumentReady(uploading, doc, MTP_inputFile(MTP_long(i->thumbId()), MTP_int(i->partsCount), MTP_string(i->file ? i->file->thumbname : (qsl("thumb.") + i->media.thumbExt)), MTP_string(i->file ? i->file->thumbmd5 : i->media.jpeg_md5)));
emit thumbDocumentReady(uploading, silent, doc, MTP_inputFile(MTP_long(i->thumbId()), MTP_int(i->partsCount), MTP_string(i->file ? i->file->thumbname : (qsl("thumb.") + i->media.thumbExt)), MTP_bytes(i->file ? i->file->thumbmd5 : i->media.jpeg_md5)));
} else {
emit documentReady(uploading, doc);
emit documentReady(uploading, silent, doc);
}
} else if (i->type() == PrepareAudio) {
QByteArray audioMd5(32, Qt::Uninitialized);
hashMd5Hex(i->md5Hash.result(), audioMd5.data());
MTPInputFile audio = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename())) : MTP_inputFile(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename()), MTP_string(audioMd5));
emit audioReady(uploading, audio);
}
queue.remove(uploading);
uploading = FullMsgId();
@ -200,9 +187,9 @@ void FileUploader::sendNext() {
}
mtpRequestId requestId;
if (i->docSize > UseBigFilesFrom) {
requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_bytes(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uplDcId(todc));
} else {
requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_bytes(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uplDcId(todc));
}
docRequestsSent.insert(requestId, i->docSentParts);
dcMap.insert(requestId, todc);
@ -213,7 +200,7 @@ void FileUploader::sendNext() {
} else {
UploadFileParts::iterator part = parts.begin();
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(partsOfId), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(partsOfId), MTP_int(part.key()), MTP_bytes(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uplDcId(todc));
requestsSent.insert(requestId, part.value());
dcMap.insert(requestId, todc);
sentSize += part.value().size();
@ -259,7 +246,7 @@ void FileUploader::clear() {
dcMap.clear();
sentSize = 0;
for (int32 i = 0; i < MTPUploadSessionsCount; ++i) {
MTP::stopSession(MTP::upl[i]);
MTP::stopSession(MTP::uplDcId(i));
sentSizes[i] = 0;
}
killSessionsTimer.stop();
@ -303,7 +290,7 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
photo->uploadingData->offset = k->fileSentSize;
}
emit photoProgress(k.key());
} else if (k->type() == PrepareDocument) {
} else if (k->type() == PrepareDocument || k->type() == PrepareAudio) {
DocumentData *doc = App::document(k->id());
if (doc->uploading()) {
doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
@ -312,15 +299,6 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
}
}
emit documentProgress(k.key());
} else if (k->type() == PrepareAudio) {
AudioData *audio = App::audio(k->id());
if (audio->uploading()) {
audio->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
if (audio->uploadOffset > audio->size) {
audio->uploadOffset = audio->size;
}
}
emit audioProgress(k.key());
}
}
}

View file

@ -16,7 +16,7 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
@ -48,18 +48,15 @@ public slots:
signals:
void photoReady(const FullMsgId &msgId, const MTPInputFile &file);
void documentReady(const FullMsgId &msgId, const MTPInputFile &file);
void thumbDocumentReady(const FullMsgId &msgId, const MTPInputFile &file, const MTPInputFile &thumb);
void audioReady(const FullMsgId &msgId, const MTPInputFile &file);
void photoReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void documentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void thumbDocumentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file, const MTPInputFile &thumb);
void photoProgress(const FullMsgId &msgId);
void documentProgress(const FullMsgId &msgId);
void audioProgress(const FullMsgId &msgId);
void photoFailed(const FullMsgId &msgId);
void documentFailed(const FullMsgId &msgId);
void audioFailed(const FullMsgId &msgId);
private:

View file

@ -16,12 +16,19 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "animation.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
}
#include "mainwidget.h"
#include "window.h"
@ -93,6 +100,7 @@ namespace anim {
if (!_clipThreads.isEmpty()) {
for (int32 i = 0, l = _clipThreads.size(); i < l; ++i) {
_clipThreads.at(i)->quit();
DEBUG_LOG(("Waiting for clipThread to finish: %1").arg(i));
_clipThreads.at(i)->wait();
delete _clipManagers.at(i);
delete _clipThreads.at(i);
@ -142,7 +150,7 @@ void AnimationManager::stop(Animation *obj) {
if (_iterating) {
_stopping.insert(obj, NullType());
if (!_starting.isEmpty()) {
_starting.insert(obj, NullType());
_starting.remove(obj);
}
} else {
AnimatingObjects::iterator i = _objects.find(obj);
@ -159,7 +167,9 @@ void AnimationManager::timeout() {
_iterating = true;
uint64 ms = getms();
for (AnimatingObjects::const_iterator i = _objects.begin(), e = _objects.end(); i != e; ++i) {
i.key()->step(ms, true);
if (!_stopping.contains(i.key())) {
i.key()->step(ms, true);
}
}
_iterating = false;
@ -189,18 +199,25 @@ QPixmap _prepareFrame(const ClipFrameRequest &request, const QImage &original, b
bool needOuter = (request.outerw != request.framew) || (request.outerh != request.frameh);
if (badSize || needOuter || hasAlpha || request.rounded) {
int32 factor(request.factor);
bool fill = false;
if (cache.width() != request.outerw || cache.height() != request.outerh) {
bool newcache = (cache.width() != request.outerw || cache.height() != request.outerh);
if (newcache) {
cache = QImage(request.outerw, request.outerh, QImage::Format_ARGB32_Premultiplied);
if (request.framew < request.outerw || request.frameh < request.outerh || hasAlpha) {
fill = true;
}
cache.setDevicePixelRatio(factor);
}
{
Painter p(&cache);
if (fill) {
p.fillRect(0, 0, cache.width() / factor, cache.height() / factor, st::black);
if (newcache) {
if (request.framew < request.outerw) {
p.fillRect(0, 0, (request.outerw - request.framew) / (2 * factor), cache.height() / factor, st::black);
p.fillRect((request.outerw - request.framew) / (2 * factor) + (request.framew / factor), 0, (cache.width() / factor) - ((request.outerw - request.framew) / (2 * factor) + (request.framew / factor)), cache.height() / factor, st::black);
}
if (request.frameh < request.outerh) {
p.fillRect(qMax(0, (request.outerw - request.framew) / (2 * factor)), 0, qMin(cache.width(), request.framew) / factor, (request.outerh - request.frameh) / (2 * factor), st::black);
p.fillRect(qMax(0, (request.outerw - request.framew) / (2 * factor)), (request.outerh - request.frameh) / (2 * factor) + (request.frameh / factor), qMin(cache.width(), request.framew) / factor, (cache.height() / factor) - ((request.outerh - request.frameh) / (2 * factor) + (request.frameh / factor)), st::black);
}
}
if (hasAlpha) {
p.fillRect(qMax(0, (request.outerw - request.framew) / (2 * factor)), qMax(0, (request.outerh - request.frameh) / (2 * factor)), qMin(cache.width(), request.framew) / factor, qMin(cache.height(), request.frameh) / factor, st::white);
}
QPoint position((request.outerw - request.framew) / (2 * factor), (request.outerh - request.frameh) / (2 * factor));
if (badSize) {
@ -235,7 +252,7 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
_clipManagers.push_back(new ClipReadManager(_clipThreads.back()));
_clipThreads.back()->start();
} else {
_threadIndex = int32(MTP::nonce<uint32>() % _clipThreads.size());
_threadIndex = int32(rand_value<uint32>() % _clipThreads.size());
int32 loadLevel = 0x7FFFFFFF;
for (int32 i = 0, l = _clipThreads.size(); i < l; ++i) {
int32 level = _clipManagers.at(i)->loadLevel();
@ -369,6 +386,7 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
frame->request.outerh = outerh * factor;
QImage cacheForResize;
frame->original.setDevicePixelRatio(factor);
frame->pix = QPixmap();
frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize);
@ -418,7 +436,6 @@ void ClipReader::stop() {
}
void ClipReader::error() {
_private = 0;
_state = ClipError;
}
@ -477,7 +494,7 @@ public:
, _frameDelay(0) {
}
bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) {
bool readNextFrame() {
if (_reader) _frameDelay = _reader->nextImageDelay();
if (_framesLeft < 1 && !jumpToStart()) {
return false;
@ -587,6 +604,11 @@ public:
}
bool readNextFrame() {
if (_frameRead) {
av_frame_unref(_frame);
_frameRead = false;
}
int res;
while (true) {
if (_avpkt.size > 0) { // previous packet not finished
@ -638,6 +660,20 @@ public:
}
if (got_frame) {
int64 duration = av_frame_get_pkt_duration(_frame);
int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
_currentFrameDelay = _nextFrameDelay;
if (_frameMs + _currentFrameDelay < frameMs) {
_currentFrameDelay = int32(frameMs - _frameMs);
}
if (duration == AV_NOPTS_VALUE) {
_nextFrameDelay = 0;
} else {
_nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
}
_frameMs = frameMs;
_hadFrame = _frameRead = true;
return true;
}
@ -700,20 +736,6 @@ public:
}
}
int64 duration = av_frame_get_pkt_duration(_frame);
int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
_currentFrameDelay = _nextFrameDelay;
if (_frameMs + _currentFrameDelay < frameMs) {
_currentFrameDelay = int32(frameMs - _frameMs);
}
if (duration == AV_NOPTS_VALUE) {
_nextFrameDelay = 0;
} else {
_nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
}
_frameMs = frameMs;
av_frame_unref(_frame);
return true;
}
@ -792,6 +814,10 @@ public:
}
~FFMpegReaderImplementation() {
if (_frameRead) {
av_frame_unref(_frame);
_frameRead = false;
}
if (_ioContext) av_free(_ioContext);
if (_codecContext) avcodec_close(_codecContext);
if (_swsContext) sws_freeContext(_swsContext);

View file

@ -16,11 +16,11 @@ In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "types.h"
#include "basic_types.h"
#include <QtCore/QTimer>
#include <QtGui/QColor>
@ -208,10 +208,10 @@ class AnimationCreator {
public:
AnimationCreator(AnimationImplementation *ptr) : _ptr(ptr) {}
AnimationCreator(const AnimationCreator &other) : _ptr(other.create()) {}
AnimationImplementation *create() const { return exchange(_ptr); }
AnimationImplementation *create() const { return getPointerAndReset(_ptr); }
~AnimationCreator() { deleteAndMark(_ptr); }
private:
AnimationCreator &operator=(const AnimationCreator &other);
AnimationCreator &operator=(const AnimationCreator &other) = delete;
mutable AnimationImplementation *_ptr;
};
class AnimationCallbacks {
@ -222,7 +222,7 @@ public:
~AnimationCallbacks() { deleteAndMark(_implementation); }
private:
AnimationCallbacks(const AnimationCallbacks &other);
AnimationCallbacks &operator=(const AnimationCallbacks &other);
AnimationCallbacks &operator=(const AnimationCallbacks &other) = delete;
AnimationImplementation *_implementation;
};

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