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) * [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) * [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) * [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) * [Don't mix code changes with whitespace cleanup](#dont-mix-code-changes-with-whitespace-cleanup)
* [Keep your code simple!](#keep-your-code-simple) * [Keep your code simple!](#keep-your-code-simple)
* [Test your changes!](#test-your-changes) * [Test your changes!](#test-your-changes)
@ -72,10 +73,8 @@ For more info, see [GitHub Help][help_change_commit_message].
## Build instructions ## Build instructions
* [Visual Studio 2013][msvc] See the [README.md](README.md#build-instructions) for details on the various build
* [XCode 6.4][xcode] environments.
* [XCode 6.4 for OS X 10.6 and 10.7][xcode_old]
* [Qt Creator 3.2.0 Ubuntu][qtcreator]
## Pull upstream changes into your fork regularly ## 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 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]. 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 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. * 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 ### 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. 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_125x.png
/Telegram/SourceFiles/art/sprite_150x.png /Telegram/SourceFiles/art/sprite_150x.png
/Telegram/*.user /Telegram/*.user
*.vcxproj.user
*.suo *.suo
*.sdf *.sdf
*.opensdf *.opensdf
*.opendb
/Telegram/*.aps /Telegram/*.aps
/Win32/ /Win32/
ipch/ 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. 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]. The source code is published under GPLv3 with OpenSSL exception, the license is available [here][license].
## Supported systems ## Supported systems
* Windows XP - Windows 10 (**not** RT) * 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) * 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 * Fedora 22
## Third-party libraries ## 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)) * 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)) * LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))
* liblzma ([public domain](http://tukaani.org/xz/)) * 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)) * OpenAL Soft ([LGPL](http://kcat.strangesoft.net/openal.html))
* Opus codec ([BSD license](http://www.opus-codec.org/license/)) * Opus codec ([BSD license](http://www.opus-codec.org/license/))
* FFmpeg ([LGPL](https://www.ffmpeg.org/legal.html)) * 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][xcode]
* [XCode 7 for OS X 10.6 and 10.7][xcode_old] * [XCode 7 for OS X 10.6 and 10.7][xcode_old]
* [Qt Creator 3.5.1 Ubuntu][qtcreator] * [Qt Creator 3.5.1 Ubuntu][qtcreator]
* [Using qmake on GNU/Linux][qmake]
## Projects in Telegram solution ## 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. 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 * ### MetaEmoji
Creates four sprites and text2emoji replace code 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 * ### 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.h
* GeneratedFiles/lang.cpp * 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_api]: https://core.telegram.org
[telegram_proto]: https://core.telegram.org/mtproto [telegram_proto]: https://core.telegram.org/mtproto
[license]: LICENSE [license]: LICENSE
[msvc]: MSVC.md [msvc]: doc/building-msvc.md
[xcode]: XCODE.md [xcode]: doc/building-xcode.md
[xcode_old]: XCODEold.md [xcode_old]: doc/building-xcode-old.md
[qtcreator]: QTCREATOR.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 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013 # Visual Studio 14
VisualStudioVersion = 12.0.30501.0 VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
@ -18,10 +18,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Telegram\Updater
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}"
EndProject 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 EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Telegram\Packer.vcxproj", "{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Telegram\Packer.vcxproj", "{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "codegen_style", "Telegram\build\vc\codegen_style\codegen_style.vcxproj", "{E4DF8176-4DEF-4859-962F-B497E3E7A323}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@ -82,8 +84,21 @@ Global
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Deploy|x64.ActiveCfg = Release|Win32 {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|Win32.ActiveCfg = Release|Win32
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|x64.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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E4DF8176-4DEF-4859-962F-B497E3E7A323} = {2F863EAD-33C9-4014-A573-93F085BA9CB1}
EndGlobalSection
EndGlobal EndGlobal

View file

@ -1,4 +1,5 @@
@echo OFF @echo OFF
setlocal
FOR /F "tokens=1,2* delims= " %%i in (Version) do set "%%i=%%j" 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 "ReleasePath=..\Win32\Deploy"
set "DeployPath=%ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStrFull%" set "DeployPath=%ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStrFull%"
set "SignPath=..\..\TelegramPrivate\Sign.bat" set "SignPath=..\..\TelegramPrivate\Sign.bat"
set "BinaryName=Telegram"
set "DropboxSymbolsPath=Z:\Dropbox\Telegram\symbols"
if %BetaVersion% neq 0 ( if %BetaVersion% neq 0 (
if exist %DeployPath%\ ( if exist %DeployPath%\ (
@ -71,9 +74,13 @@ echo .
echo Version %AppVersionStrFull% build successfull. Preparing.. echo Version %AppVersionStrFull% build successfull. Preparing..
echo . 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" 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 if %errorlevel% neq 0 goto error
call %SignPath% %ReleasePath%\Updater.exe call %SignPath% %ReleasePath%\Updater.exe
@ -90,7 +97,7 @@ if %BetaVersion% equ 0 (
) )
cd %ReleasePath% 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% cd %HomePath%
if %errorlevel% neq 0 goto error if %errorlevel% neq 0 goto error
@ -109,6 +116,21 @@ if %BetaVersion% neq 0 (
set "PortableFile=tbeta%BetaVersion%_%BetaSignature%.zip" 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 mkdir %ReleasePath%\deploy
if not exist %ReleasePath%\deploy\%AppVersionStrMajor% mkdir %ReleasePath%\deploy\%AppVersionStrMajor% if not exist %ReleasePath%\deploy\%AppVersionStrMajor% mkdir %ReleasePath%\deploy\%AppVersionStrMajor%
mkdir %DeployPath% mkdir %DeployPath%
@ -144,7 +166,7 @@ if not exist %DeployPath%\%PortableFile% goto error
if %BetaVersion% equ 0 ( if %BetaVersion% equ 0 (
if not exist %DeployPath%\%SetupFile% goto error 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.exe goto error
if not exist %DeployPath%\Updater.pdb goto error if not exist %DeployPath%\Updater.pdb goto error
if not exist %FinalReleasePath%\%AppVersionStrMajor% mkdir %FinalReleasePath%\%AppVersionStrMajor% if not exist %FinalReleasePath%\%AppVersionStrMajor% mkdir %FinalReleasePath%\%AppVersionStrMajor%
@ -157,7 +179,7 @@ if %BetaVersion% equ 0 (
) else ( ) else (
xcopy %DeployPath%\%BetaKeyFile% %FinalDeployPath%\ /Y xcopy %DeployPath%\%BetaKeyFile% %FinalDeployPath%\ /Y
) )
xcopy %DeployPath%\Telegram.pdb %FinalDeployPath%\ xcopy %DeployPath%\%BinaryName%.pdb %FinalDeployPath%\
xcopy %DeployPath%\Updater.exe %FinalDeployPath%\ xcopy %DeployPath%\Updater.exe %FinalDeployPath%\
xcopy %DeployPath%\Updater.pdb %FinalDeployPath%\ xcopy %DeployPath%\Updater.pdb %FinalDeployPath%\

View file

@ -1,5 +1,7 @@
set -e set -e
FastParam="$1"
while IFS='' read -r line || [[ -n "$line" ]]; do while IFS='' read -r line || [[ -n "$line" ]]; do
set $line set $line
eval $1="$2" eval $1="$2"
@ -37,6 +39,7 @@ if [ "$BuildTarget" == "linux" ]; then
WorkPath="./../Linux" WorkPath="./../Linux"
FixScript="$HomePath/FixMake.sh" FixScript="$HomePath/FixMake.sh"
ReleasePath="./../Linux/Release" ReleasePath="./../Linux/Release"
BinaryName="Telegram"
elif [ "$BuildTarget" == "linux32" ]; then elif [ "$BuildTarget" == "linux32" ]; then
echo "Building version $AppVersionStrFull for Linux 32bit.." echo "Building version $AppVersionStrFull for Linux 32bit.."
UpdateFile="tlinux32upd$AppVersion" UpdateFile="tlinux32upd$AppVersion"
@ -44,6 +47,7 @@ elif [ "$BuildTarget" == "linux32" ]; then
WorkPath="./../Linux" WorkPath="./../Linux"
FixScript="$HomePath/FixMake32.sh" FixScript="$HomePath/FixMake32.sh"
ReleasePath="./../Linux/Release" ReleasePath="./../Linux/Release"
BinaryName="Telegram"
elif [ "$BuildTarget" == "mac" ]; then elif [ "$BuildTarget" == "mac" ]; then
echo "Building version $AppVersionStrFull for OS X 10.8+.." echo "Building version $AppVersionStrFull for OS X 10.8+.."
UpdateFile="tmacupd$AppVersion" UpdateFile="tmacupd$AppVersion"
@ -104,22 +108,25 @@ fi
#fi #fi
if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
DropboxSymbolsPath="/media/psf/Home/Dropbox/Telegram/symbols"
mkdir -p "$WorkPath/ReleaseIntermediateUpdater" mkdir -p "$WorkPath/ReleaseIntermediateUpdater"
cd "$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 make
echo "Updater build complete!" echo "Updater build complete!"
cd "$HomePath" cd "$HomePath"
mkdir -p "$WorkPath/ReleaseIntermediate" mkdir -p "$WorkPath/ReleaseIntermediate"
cd "$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" eval "$FixScript"
make make
echo "Telegram build complete!" echo "$BinaryName build complete!"
cd "$HomePath" cd "$HomePath"
if [ ! -f "$ReleasePath/Telegram" ]; then if [ ! -f "$ReleasePath/$BinaryName" ]; then
echo "Telegram not found!" echo "$BinaryName not found!"
exit 1 exit 1
fi fi
@ -128,8 +135,16 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
exit 1 exit 1
fi 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.." 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!" echo "Packer done!"
if [ "$BetaVersion" != "0" ]; then if [ "$BetaVersion" != "0" ]; then
@ -146,6 +161,12 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
SetupFile="tbeta${BetaVersion}_${BetaSignature}.tar.xz" SetupFile="tbeta${BetaVersion}_${BetaSignature}.tar.xz"
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 [ ! -d "$ReleasePath/deploy" ]; then if [ ! -d "$ReleasePath/deploy" ]; then
mkdir "$ReleasePath/deploy" mkdir "$ReleasePath/deploy"
fi fi
@ -154,21 +175,25 @@ if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then
mkdir "$ReleasePath/deploy/$AppVersionStrMajor" mkdir "$ReleasePath/deploy/$AppVersionStrMajor"
fi 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"
mkdir "$DeployPath/Telegram" mkdir "$DeployPath/$BinaryName"
mv "$ReleasePath/Telegram" "$DeployPath/Telegram/" mv "$ReleasePath/$BinaryName" "$DeployPath/$BinaryName/"
mv "$ReleasePath/Updater" "$DeployPath/Telegram/" mv "$ReleasePath/Updater" "$DeployPath/$BinaryName/"
mv "$ReleasePath/$UpdateFile" "$DeployPath/" mv "$ReleasePath/$UpdateFile" "$DeployPath/"
if [ "$BetaVersion" != "0" ]; then if [ "$BetaVersion" != "0" ]; then
mv "$ReleasePath/$BetaKeyFile" "$DeployPath/" mv "$ReleasePath/$BetaKeyFile" "$DeployPath/"
fi fi
cd "$DeployPath" && tar -cJvf "$SetupFile" "Telegram/" && cd "./../../../$HomePath" cd "$DeployPath" && tar -cJvf "$SetupFile" "$BinaryName/" && cd "./../../../$HomePath"
fi fi
if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarget" == "macstore" ]; then 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 xcodebuild -project Telegram.xcodeproj -alltargets -configuration Release build
if [ ! -d "$ReleasePath/$BinaryName.app" ]; then if [ ! -d "$ReleasePath/$BinaryName.app" ]; then
@ -181,6 +206,28 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
exit 1 exit 1
fi 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}'` AppUUID=`dwarfdump -u "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName" | awk -F " " '{print $2}'`
DsymUUID=`dwarfdump -u "$ReleasePath/$BinaryName.app.dSYM" | awk -F " " '{print $2}'` DsymUUID=`dwarfdump -u "$ReleasePath/$BinaryName.app.dSYM" | awk -F " " '{print $2}'`
if [ "$AppUUID" != "$DsymUUID" ]; then if [ "$AppUUID" != "$DsymUUID" ]; then
@ -215,6 +262,12 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
fi fi
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 [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ]; then
if [ "$BetaVersion" == "0" ]; then if [ "$BetaVersion" == "0" ]; then
cd "$ReleasePath" cd "$ReleasePath"
@ -254,10 +307,10 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ]; then if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ]; then
echo "Copying $BinaryName.app and $UpdateFile to deploy/$AppVersionStrMajor/$AppVersionStr.."; echo "Copying $BinaryName.app and $UpdateFile to deploy/$AppVersionStrMajor/$AppVersionStr..";
mkdir "$DeployPath" mkdir "$DeployPath"
mkdir "$DeployPath/Telegram" mkdir "$DeployPath/$BinaryName"
cp -r "$ReleasePath/$BinaryName.app" "$DeployPath/Telegram/" cp -r "$ReleasePath/$BinaryName.app" "$DeployPath/$BinaryName/"
if [ "$BetaVersion" != "0" ]; then 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/" mv "$ReleasePath/$BetaKeyFile" "$DeployPath/"
fi fi
mv "$ReleasePath/$BinaryName.app.dSYM" "$DeployPath/" mv "$ReleasePath/$BinaryName.app.dSYM" "$DeployPath/"
@ -294,6 +347,7 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
rm "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName" rm "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName"
rm -rf "$ReleasePath/$BinaryName.app/Contents/_CodeSignature" rm -rf "$ReleasePath/$BinaryName.app/Contents/_CodeSignature"
mkdir -p "$DropboxDeployPath"
cp -v "$DeployPath/$BinaryName.app" "$DropboxDeployPath/" cp -v "$DeployPath/$BinaryName.app" "$DropboxDeployPath/"
cp -rv "$DeployPath/$BinaryName.app.dSYM" "$DropboxDeployPath/" cp -rv "$DeployPath/$BinaryName.app.dSYM" "$DropboxDeployPath/"
fi fi

View file

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

View file

@ -11,12 +11,7 @@ Replace () {
} }
Replace '\-llzma' '\/usr\/lib\/x86_64\-linux\-gnu\/liblzma\.a' Replace '\-llzma' '\/usr\/lib\/x86_64\-linux\-gnu\/liblzma\.a'
Replace '\-lz' '\/usr\/lib\/x86_64\-linux\-gnu\/libz\.a' Replace '\-lXi' '\/usr\/lib\/x86_64\-linux\-gnu\/libXi\.a \/usr\/lib\/x86_64\-linux\-gnu\/libXext\.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 '\-lSM' '\/usr\/lib\/x86_64\-linux\-gnu\/libSM\.a' Replace '\-lSM' '\/usr\/lib\/x86_64\-linux\-gnu\/libSM\.a'
Replace '\-lICE' '\/usr\/lib\/x86_64\-linux\-gnu\/libICE\.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' 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 '\-lswscale' '\/usr\/local\/lib\/libswscale\.a'
Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a' Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a'
Replace '\-lva' '\/usr\/local\/lib\/libva\.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 '\-llzma' '\/usr\/lib\/i386\-linux\-gnu\/liblzma\.a'
Replace '\-lz' '\/usr\/lib\/i386\-linux\-gnu\/libz\.a' Replace '\-lXi' '\/usr\/lib\/i386\-linux\-gnu\/libXi\.a \/usr\/lib\/i386\-linux\-gnu\/libXext\.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 '\-lSM' '\/usr\/lib\/i386\-linux\-gnu\/libSM\.a' Replace '\-lSM' '\/usr\/lib\/i386\-linux\-gnu\/libSM\.a'
Replace '\-lICE' '\/usr\/lib\/i386\-linux\-gnu\/libICE\.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' 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 '\-lswscale' '\/usr\/local\/lib\/libswscale\.a'
Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a' Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a'
Replace '\-lva' '\/usr\/local\/lib\/libva\.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 DESTDIR = ./../ReleaseLang
} }
CONFIG += plugin static CONFIG += plugin static c++11
macx { macx {
QMAKE_INFO_PLIST = ./SourceFiles/_other/Lang.plist QMAKE_INFO_PLIST = ./SourceFiles/_other/Lang.plist

View file

@ -12,7 +12,7 @@ CONFIG(release, debug|release) {
DESTDIR = ./../ReleaseStyle DESTDIR = ./../ReleaseStyle
} }
CONFIG += plugin static CONFIG += plugin static c++11
macx { macx {
QMAKE_INFO_PLIST = ./SourceFiles/_other/Style.plist 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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_language_name" = "English";
"lng_switch_to_this" = "Switch to 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_cancel" = "Cancel";
"lng_continue" = "Continue"; "lng_continue" = "Continue";
"lng_close" = "Close"; "lng_close" = "Close";
"lng_connecting" = "Connecting.."; "lng_connecting" = "Connecting...";
"lng_reconnecting" = "Reconnect {count:now|in # s|in # s}.."; "lng_reconnecting" = "Reconnect {count:now|in # s|in # s}...";
"lng_reconnecting_try_now" = "Try now"; "lng_reconnecting_try_now" = "Try now";
"lng_status_service_notifications" = "service notifications"; "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" = "last seen {date}";
"lng_status_lastseen_date_time" = "last seen {date} at {time}"; "lng_status_lastseen_date_time" = "last seen {date} at {time}";
"lng_status_online" = "online"; "lng_status_online" = "online";
"lng_status_connecting" = "connecting.."; "lng_status_connecting" = "connecting...";
"lng_chat_status_unaccessible" = "group is unaccessible"; "lng_chat_status_unaccessible" = "group is unaccessible";
"lng_chat_status_members" = "{count:no members|# member|# members}"; "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_server_error" = "Internal server error.";
"lng_flood_error" = "Too many tries. Please try again later."; "lng_flood_error" = "Too many tries. Please try again later.";
"lng_gif_error" = "An error has occured while reading GIF animation :("; "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" = "Unknown";
"lng_deleted_message" = "Deleted message"; "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_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"; "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_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_no_telegram" = "Send code via SMS";
"lng_code_call" = "Telegram will dial your number in {minutes}:{seconds}"; "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_code_called" = "Telegram dialed your number";
"lng_bad_phone" = "Invalid phone number. Please try again."; "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_dlg_new_channel_name" = "Channel name";
"lng_no_contacts" = "You have no contacts"; "lng_no_contacts" = "You have no contacts";
"lng_no_chats" = "Your chats will be here"; "lng_no_chats" = "Your chats will be here";
"lng_contacts_loading" = "Loading.."; "lng_contacts_loading" = "Loading...";
"lng_contacts_not_found" = "No contacts found"; "lng_contacts_not_found" = "No contacts found";
"lng_dlg_search_chat" = "Search in this chat"; "lng_dlg_search_chat" = "Search in this chat";
"lng_dlg_search_channel" = "Search in this channel"; "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_save" = "Save";
"lng_settings_upload" = "Set Profile Photo"; "lng_settings_upload" = "Set Profile Photo";
"lng_settings_crop_profile" = "Select a square area for your 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_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."; "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_auto_update" = "Update automatically";
"lng_settings_current_version" = "Version {version}"; "lng_settings_current_version" = "Version {version}";
"lng_settings_check_now" = "Check for updates"; "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_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_ready" = "New version is ready";
"lng_settings_update_now" = "Restart Now"; "lng_settings_update_now" = "Restart Now";
"lng_settings_update_fail" = "Update check failed :("; "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_gallery" = "Choose from gallery";
"lng_settings_bg_from_file" = "Choose from file"; "lng_settings_bg_from_file" = "Choose from file";
"lng_settings_bg_tile" = "Tile background"; "lng_settings_bg_tile" = "Tile background";
"lng_settings_adaptive_wide" = "Adaptive layout for wide screens";
"lng_backgrounds_header" = "Choose your new chat background"; "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_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_path_settings" = "Settings";
"lng_download_finish_failed" = "File download could not be finished.\n\nWould you like to try again?"; "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_cleared" = "Cleared!";
"lng_download_path_clear_failed" = "Clear failed :("; "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_images_cached" = "{count:_not_used_|# image|# images}, {size}";
"lng_settings_audios_cached" = "{count:_not_used_|# voice message|# voice messages}, {size}"; "lng_settings_audios_cached" = "{count:_not_used_|# voice message|# voice messages}, {size}";
"lng_local_storage_clear" = "Clear all"; "lng_local_storage_clear" = "Clear all";
"lng_local_storage_clearing" = "Clearing.."; "lng_local_storage_clearing" = "Clearing...";
"lng_local_storage_cleared" = "Cleared!"; "lng_local_storage_cleared" = "Cleared!";
"lng_local_storage_clear_failed" = "Clear failed :("; "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_logout" = "Log out";
"lng_passcode_need_unblock" = "You need to unlock me first."; "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_change" = "Change cloud password";
"lng_cloud_password_create" = "Cloud password"; "lng_cloud_password_create" = "Cloud password";
"lng_cloud_password_remove" = "Remove 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_cloud_password_is_same" = "Password was not changed";
"lng_connection_type" = "Connection type:"; "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_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_proxy" = "{transport} with proxy";
"lng_connection_header" = "Connection type"; "lng_connection_header" = "Connection type";
"lng_connection_auto_rb" = "Auto (TCP if available or HTTP)"; "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_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_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_profile_chat_unaccessible" = "Group is unaccessible";
"lng_topbar_info" = "Info"; "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_add_participant" = "Add Members";
"lng_profile_delete_and_exit" = "Leave"; "lng_profile_delete_and_exit" = "Leave";
"lng_profile_kick" = "Remove"; "lng_profile_kick" = "Remove";
"lng_profile_admin" = "admin";
"lng_profile_sure_kick" = "Remove {user} from the group?"; "lng_profile_sure_kick" = "Remove {user} from the group?";
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?"; "lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
"lng_profile_sure_kick_admin" = "Remove {user} from administrators?"; "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_shared_media" = "Shared media";
"lng_profile_no_media" = "No media in this conversation."; "lng_profile_no_media" = "No media in this conversation.";
"lng_profile_photos" = "{count:_not_used_|# photo|# photos} »"; "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" = "{count:_not_used_|# shared link|# shared links} »";
"lng_profile_shared_links_header" = "Shared links overview"; "lng_profile_shared_links_header" = "Shared links overview";
"lng_profile_copy_phone" = "Copy phone number"; "lng_profile_copy_phone" = "Copy phone number";
"lng_profile_copy_fullname" = "Copy name";
"lng_channel_add_admins" = "New administrator"; "lng_channel_add_admins" = "New administrator";
"lng_channel_add_members" = "Add members"; "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_next" = "Next";
"lng_create_group_create" = "Create"; "lng_create_group_create" = "Create";
"lng_create_group_title" = "New Group"; "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_title" = "New Channel";
"lng_create_channel_about" = "Channels are a tool for broadcasting your messages to unlimited audiences"; "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_title" = "Public Channel";
"lng_create_public_channel_about" = "Anyone can find the channel in search and join"; "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_title" = "Private Channel";
"lng_create_private_channel_about" = "Only people with a special invite link may join"; "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" = "Enable Comments";
"lng_create_channel_comments_about" = "If you enable comments, members will be able to discuss your posts in the channel"; "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"; "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_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_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_user" = "{from} added {user}";
"lng_action_add_users_many" = "{from} added {users}"; "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_chat" = "{from} created group «{title}»";
"lng_action_created_channel" = "Channel «{title}» created"; "lng_action_created_channel" = "Channel «{title}» created";
"lng_action_group_migrate" = "The group was upgraded to a supergroup"; "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_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:"; "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_feature4" = "— Notifications are muted by default";
"lng_profile_migrate_button" = "Upgrade to supergroup"; "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_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_comments_count" = "{count:_not_used_|# comment|# comments}";
"lng_channel_hide_comments" = "Hide 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_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_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_failed" = "Failed";
"lng_attach_file" = "File"; "lng_attach_file" = "File";
"lng_attach_photo" = "Photo"; "lng_attach_photo" = "Photo";
@ -600,6 +648,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_saved_gifs" = "Saved GIFs"; "lng_saved_gifs" = "Saved GIFs";
"lng_inline_bot_results" = "Results from {inline_bot}"; "lng_inline_bot_results" = "Results from {inline_bot}";
"lng_inline_bot_no_results" = "No results"; "lng_inline_bot_no_results" = "No results";
"lng_inline_bot_via" = "via {inline_bot}";
"lng_box_remove" = "Remove"; "lng_box_remove" = "Remove";
@ -616,16 +665,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_stickers_remove" = "Delete"; "lng_stickers_remove" = "Delete";
"lng_stickers_return" = "Undo"; "lng_stickers_return" = "Undo";
"lng_stickers_restore" = "Restore"; "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_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_contact" = "Contact";
"lng_in_dlg_audio" = "Audio"; "lng_in_dlg_audio" = "Voice message";
"lng_in_dlg_file" = "File"; "lng_in_dlg_file" = "File";
"lng_in_dlg_sticker" = "Sticker"; "lng_in_dlg_sticker" = "Sticker";
"lng_in_dlg_sticker_emoji" = "{emoji} (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" = "Report Spam";
"lng_report_spam_hide" = "Hide"; "lng_report_spam_hide" = "Hide";
"lng_report_spam_thanks" = "Thank you for your report!"; "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_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_sure_channel" = "Are you sure you want to report spam in this channel?";
"lng_report_spam_ok" = "Report"; "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_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. {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. {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_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_send_button" = "Send";
"lng_message_ph" = "Write a message.."; "lng_message_ph" = "Write a message...";
"lng_comment_ph" = "Write a comment.."; "lng_comment_ph" = "Write a comment...";
"lng_broadcast_ph" = "Broadcast a message.."; "lng_broadcast_ph" = "Broadcast a message...";
"lng_broadcast_silent_ph" = "Silent broadcast...";
"lng_record_cancel" = "Release outside this field to cancel"; "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_empty_history" = "";
"lng_willbe_history" = "Please select a chat to start messaging"; "lng_willbe_history" = "Please select a chat to start messaging";
"lng_message_with_from" = "[c]{from}:[/c] {message}"; "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_user_typing" = "{user} is typing";
"lng_users_typing" = "{user} and {second_user} are typing"; "lng_users_typing" = "{user} and {second_user} are typing";
"lng_many_typing" = "{count:_not_used_|# is|# are} typing"; "lng_many_typing" = "{count:_not_used_|# is|# are} typing";
"lng_send_action_record_video" = "recording video"; "lng_send_action_record_video" = "recording a video";
"lng_user_action_record_video" = "{user} is recording video"; "lng_user_action_record_video" = "{user} is recording a video";
"lng_send_action_upload_video" = "sending video"; "lng_send_action_upload_video" = "sending a video";
"lng_user_action_upload_video" = "{user} is sending video"; "lng_user_action_upload_video" = "{user} is sending a video";
"lng_send_action_record_audio" = "recording audio"; "lng_send_action_record_audio" = "recording a voice message";
"lng_user_action_record_audio" = "{user} is recording audio"; "lng_user_action_record_audio" = "{user} is recording a voice message";
"lng_send_action_upload_audio" = "sending audio"; "lng_send_action_upload_audio" = "sending a voice message";
"lng_user_action_upload_audio" = "{user} is sending audio"; "lng_user_action_upload_audio" = "{user} is sending a voice message";
"lng_send_action_upload_photo" = "sending photo"; "lng_send_action_upload_photo" = "sending a photo";
"lng_user_action_upload_photo" = "{user} is sending photo"; "lng_user_action_upload_photo" = "{user} is sending a photo";
"lng_send_action_upload_file" = "sending file"; "lng_send_action_upload_file" = "sending a file";
"lng_user_action_upload_file" = "{user} is sending file"; "lng_user_action_upload_file" = "{user} is sending a file";
"lng_send_action_geo_location" = "picking location"; "lng_send_action_geo_location" = "picking a location";
"lng_user_action_geo_location" = "{user} is picking location"; "lng_user_action_geo_location" = "{user} is picking a location";
"lng_send_action_choose_contact" = "choosing contact"; "lng_send_action_choose_contact" = "choosing a contact";
"lng_user_action_choose_contact" = "{user} is choosing contact"; "lng_user_action_choose_contact" = "{user} is choosing a contact";
"lng_unread_bar" = "{count:_not_used_|# unread message|# unread messages}"; "lng_unread_bar" = "{count:_not_used_|# unread message|# unread messages}";
"lng_maps_point" = "Location"; "lng_maps_point" = "Location";
"lng_save_photo" = "Save image"; "lng_save_photo" = "Save image";
"lng_save_video" = "Save video"; "lng_save_video" = "Save video file";
"lng_save_audio" = "Save audio"; "lng_save_audio_file" = "Save audio file";
"lng_save_audio" = "Save voice message";
"lng_save_file" = "Save file"; "lng_save_file" = "Save file";
"lng_save_downloaded" = "{ready} / {total} {mb}"; "lng_save_downloaded" = "{ready} / {total} {mb}";
"lng_duration_and_size" = "{duration}, {size}"; "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_group" = "View group info";
"lng_context_view_channel" = "View channel info"; "lng_context_view_channel" = "View channel info";
"lng_context_open_link" = "Open Link";
"lng_context_copy_link" = "Copy 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_copy_email" = "Copy email address";
"lng_context_open_hashtag" = "Search by hashtag";
"lng_context_copy_hashtag" = "Copy hashtag"; "lng_context_copy_hashtag" = "Copy hashtag";
"lng_context_open_mention" = "Open profile";
"lng_context_copy_mention" = "Copy username"; "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_forward_image" = "Forward Image";
"lng_context_delete_image" = "Delete Image"; "lng_context_delete_image" = "Delete Image";
"lng_context_copy_image" = "Copy 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_cancel_download" = "Cancel Download";
"lng_context_show_in_folder" = "Show in Folder"; "lng_context_show_in_folder" = "Show in Folder";
"lng_context_show_in_finder" = "Show in Finder"; "lng_context_show_in_finder" = "Show in Finder";
"lng_context_open_video" = "Open Video"; "lng_context_save_video" = "Save Video File As...";
"lng_context_save_video" = "Save Video As.."; "lng_context_save_audio_file" = "Save Audio File As...";
"lng_context_open_audio" = "Open Audio"; "lng_context_save_audio" = "Save Voice Message As...";
"lng_context_save_audio" = "Save Audio As..";
"lng_context_pack_info" = "Pack Info"; "lng_context_pack_info" = "Pack Info";
"lng_context_pack_add" = "Add Stickers"; "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_forward_file" = "Forward File";
"lng_context_delete_file" = "Delete File"; "lng_context_delete_file" = "Delete File";
"lng_context_close_file" = "Close 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_save_gif" = "Save GIF";
"lng_context_to_msg" = "Go To Message"; "lng_context_to_msg" = "Go To Message";
"lng_context_reply_msg" = "Reply"; "lng_context_reply_msg" = "Reply";
"lng_context_edit_msg" = "Edit";
"lng_context_forward_msg" = "Forward Message"; "lng_context_forward_msg" = "Forward Message";
"lng_context_delete_msg" = "Delete Message"; "lng_context_delete_msg" = "Delete Message";
"lng_context_select_msg" = "Select 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_cancel_upload" = "Cancel Upload";
"lng_context_copy_selected" = "Copy Selected Text"; "lng_context_copy_selected" = "Copy Selected Text";
"lng_context_forward_selected" = "Forward Selected"; "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_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_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_cant" = "Sorry, no way to forward here :(";
"lng_forward_confirm" = "Forward to {recipient}?"; "lng_forward_confirm" = "Forward to {recipient}?";
"lng_forward_share_contact" = "Share contact 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_group_title" = "Edit group name";
"lng_edit_contact_title" = "Edit contact name"; "lng_edit_contact_title" = "Edit contact name";
"lng_edit_channel_title" = "Edit channel"; "lng_edit_channel_title" = "Edit channel";
"lng_edit_sign_messages" = "Sign messages";
"lng_edit_group" = "Edit group"; "lng_edit_group" = "Edit group";
"lng_edit_self_title" = "Edit your name"; "lng_edit_self_title" = "Edit your name";
"lng_confirm_contact_data" = "New Contact"; "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_delete" = "Delete";
"lng_selected_forward" = "Forward"; "lng_selected_forward" = "Forward";
"lng_selected_count" = "{count:_not_used_|# message|# messages}"; "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_this" = "Do you want to delete this message?";
"lng_selected_delete_sure" = "Do you want to delete {count:_not_used_|# message|# messages}?"; "lng_selected_delete_sure" = "Do you want to delete {count:_not_used_|# message|# messages}?";
"lng_box_delete" = "Delete"; "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_search_global_results" = "Global search results";
"lng_media_save_progress" = "{ready} of {total} {mb}"; "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_copy" = "Copy";
"lng_mediaview_forward" = "Forward"; "lng_mediaview_forward" = "Forward";
"lng_mediaview_delete" = "Delete"; "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_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_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"; "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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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'; defaultFontFamily: 'Open Sans';
semibold: 'Open Sans Semibold'; semibold: 'Open Sans Semibold';
@ -51,7 +51,10 @@ color7: #2996ad; // sea
color8: #ce671b; // orange color8: #ce671b; // orange
wndMinWidth: 380px; wndMinWidth: 380px;
wideModeWidth: 640px;
adaptiveNormalWidth: 640px;
adaptiveWideWidth: 1366px;
wndMinHeight: 480px; wndMinHeight: 480px;
wndDefWidth: 800px; wndDefWidth: 800px;
wndDefHeight: 600px; wndDefHeight: 600px;
@ -64,6 +67,13 @@ layerBg: black;
overBg: #edf2f5; overBg: #edf2f5;
labelDefFlat: flatLabel {
font: font(fsize);
minWidth: 100px;
width: 0px;
align: align(left);
}
boxBg: white; boxBg: white;
boxVerticalMargin: 10px; boxVerticalMargin: 10px;
boxWidth: 320px; boxWidth: 320px;
@ -72,6 +82,8 @@ boxPadding: margins(26px, 30px, 34px, 8px);
boxMaxListHeight: 600px; boxMaxListHeight: 600px;
boxFontSize: 14px; boxFontSize: 14px;
boxTextFont: font(boxFontSize); boxTextFont: font(boxFontSize);
boxLittleSkip: 10px;
boxMediumSkip: 20px;
boxTitleFg: #444444; boxTitleFg: #444444;
boxTitleFont: font(boxFontSize bold); boxTitleFont: font(boxFontSize bold);
@ -123,6 +135,10 @@ redBoxLinkButton: linkButton(defaultBoxLinkButton) {
overColor: #d15948; overColor: #d15948;
downColor: #db6352; downColor: #db6352;
} }
boxLabel: flatLabel(labelDefFlat) {
font: font(boxFontSize);
align: align(topleft);
}
defaultInputArea: InputArea { defaultInputArea: InputArea {
textFg: black; textFg: black;
@ -269,6 +285,21 @@ defaultPopupMenu: PopupMenu {
widthMin: 180px; widthMin: 180px;
widthMax: 300px; 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; almostTransparent: #ffffff0d;
boxScroll: flatScroll(solidScroll) { boxScroll: flatScroll(solidScroll) {
width: 18px; width: 18px;
@ -593,13 +624,6 @@ scrollCountries: flatScroll(scrollDef) {
lnkText: #0f7dc7; lnkText: #0f7dc7;
labelDefFlat: flatLabel {
font: font(fsize);
minWidth: 100px;
width: 0px;
align: align(left);
}
introBtnTop: 288px; introBtnTop: 288px;
introSkip: 45px; introSkip: 45px;
introFinishSkip: 15px; introFinishSkip: 15px;
@ -937,6 +961,7 @@ dlgActiveUnreadColor: #5b94bf;
dlgActiveUnreadBG: white; dlgActiveUnreadBG: white;
dlgActiveColor: white; dlgActiveColor: white;
dlgActiveDateColor: #d3e2ee; dlgActiveDateColor: #d3e2ee;
dlgActiveUnreadMutedBG: dlgActiveDateColor;
topBarHeight: 54px; topBarHeight: 54px;
topBarBG: white; topBarBG: white;
@ -950,6 +975,21 @@ topBarBackAlpha: 0.8;
topBarBackImg: sprite(65px, 112px, 9px, 16px); topBarBackImg: sprite(65px, 112px, 9px, 16px);
topBarBackColor: #005faf; topBarBackColor: #005faf;
topBarBackFont: font(16px); 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; topBarMinPadding: 5px;
topBarButton: flatButton(btnDefFlat) { topBarButton: flatButton(btnDefFlat) {
color: btnYesColor; color: btnYesColor;
@ -1009,10 +1049,11 @@ msgServiceNameFont: semiboldFont;
msgServicePhotoWidth: 100px; msgServicePhotoWidth: 100px;
msgDateFont: font(13px); msgDateFont: font(13px);
msgMinWidth: 190px; msgMinWidth: 190px;
msgPhotoSize: 30px; msgPhotoSize: 33px;
msgPhotoSkip: 40px; msgPhotoSkip: 40px;
msgPadding: margins(13px, 7px, 13px, 8px); 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 msgLnkPadding: 2px; // for media open / save links
msgBorder: #f0f0f0; msgBorder: #f0f0f0;
msgInBg: #fff; msgInBg: #fff;
@ -1044,11 +1085,27 @@ msgInReplyBarColor: #2fa9e2;
msgOutReplyBarSelColor: #4da79f; msgOutReplyBarSelColor: #4da79f;
msgInReplyBarSelColor: #2fa9e2; 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; msgServiceBg: #89a0b47f;
msgServiceSelectBg: #bbc8d4a2; msgServiceSelectBg: #bbc8d4a2;
msgServiceColor: #FFF; msgServiceColor: #FFF;
msgServicePadding: margins(12px, 3px, 12px, 4px); msgServicePadding: margins(12px, 3px, 12px, 4px);
msgServiceMargin: margins(10px, 7px, 80px, 7px); msgServiceMargin: margins(10px, 10px, 80px, 2px);
msgColor: #000; msgColor: #000;
msgDateColor: #000; msgDateColor: #000;
@ -1107,7 +1164,7 @@ collapseButton: flatButton(btnDefFlat) {
textTop: 3px; textTop: 3px;
overTextTop: 3px; overTextTop: 3px;
downTextTop: 3px; downTextTop: 3px;
height: 24px; height: 25px;
} }
collapseHideDuration: 200; collapseHideDuration: 200;
collapseShowDuration: 200; collapseShowDuration: 200;
@ -1144,6 +1201,24 @@ outTextStyle: textStyle(defaultTextStyle) {
selectBg: msgOutBgSelected; selectBg: msgOutBgSelected;
selectOverlay: msgSelectOverlay; 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) { medviewSaveAsTextStyle: textStyle(defaultTextStyle) {
linkFg: #91d9ff; linkFg: #91d9ff;
linkFgDown: #91d9ff; linkFgDown: #91d9ff;
@ -1265,11 +1340,21 @@ msgFileBlue: sprite(60px, 425px, 20px, 20px);
msgFileOverDuration: 200; msgFileOverDuration: 200;
msgFileRadialLine: 3px; msgFileRadialLine: 3px;
msgFileExtPadding: 8px;
msgFileExtTop: 30px;
msgVideoSize: size(320px, 240px); 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; sendPadding: 9px;
btnSend: flatButton(btnDefFlat) { btnSend: flatButton(btnDefFlat) {
color: btnYesColor; color: btnYesColor;
@ -1349,7 +1434,7 @@ broadcastToggle: flatCheckbox {
bgColor: white; bgColor: white;
disColor: black; disColor: black;
width: 36px; width: 34px;
height: 46px; height: 46px;
duration: 200; duration: 200;
bgFunc: transition(easeOutCirc); bgFunc: transition(easeOutCirc);
@ -1364,13 +1449,23 @@ broadcastToggle: flatCheckbox {
disImageRect: sprite(18px, 125px, 22px, 21px); disImageRect: sprite(18px, 125px, 22px, 21px);
chkDisImageRect: 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); btnRecordAudio: sprite(379px, 390px, 16px, 24px);
btnRecordAudioActive: sprite(379px, 366px, 16px, 24px); btnRecordAudioActive: sprite(379px, 366px, 16px, 24px);
recordSignalColor: #f17077; recordSignalColor: #f17077;
recordSignalMin: 5px; recordSignalMin: 5px;
recordSignalMax: 10px; recordSignalMax: 12px;
recordCancel: #aaa; recordCancel: #aaa;
recordCancelActive: #ec6466; recordCancelActive: #ec6466;
recordFont: font(13px); recordFont: font(13px);
@ -1383,6 +1478,7 @@ replyTop: 8px;
replyBottom: 6px; replyBottom: 6px;
replyIconPos: point(13px, 13px); replyIconPos: point(13px, 13px);
replyIcon: sprite(343px, 197px, 24px, 24px); replyIcon: sprite(343px, 197px, 24px, 24px);
editIcon: sprite(371px, 286px, 24px, 24px);
replyCancel: iconedButton(btnDefIconed) { replyCancel: iconedButton(btnDefIconed) {
icon: sprite(165px, 24px, 14px, 14px); icon: sprite(165px, 24px, 14px, 14px);
iconPos: point(17px, 17px); iconPos: point(17px, 17px);
@ -1447,6 +1543,7 @@ reportSpamBg: #fffffff0;
newMsgSound: ':/gui/art/newmsg.wav'; newMsgSound: ':/gui/art/newmsg.wav';
unreadBarHeight: 32px; unreadBarHeight: 32px;
unreadBarMargin: 8px;
unreadBarFont: semiboldFont; unreadBarFont: semiboldFont;
unreadBarBG: #fcfbfa; unreadBarBG: #fcfbfa;
unreadBarBorder: shadowColor; unreadBarBorder: shadowColor;
@ -2017,17 +2114,17 @@ verifiedCheckInv: sprite(299px, 221px, 14px, 14px);
verifiedCheckPos: point(4px, 2px); verifiedCheckPos: point(4px, 2px);
botKbDuration: 200; botKbDuration: 200;
botKbBg: #f7f7f7; botKbBg: #edf1f5;
botKbOverBg: #e8ecef; botKbOverBg: #d8e2ec;
botKbDownBg: #dfe3e6; botKbDownBg: #d8e2ec;
botKbColor: #8a8a8f; botKbColor: #4b565f;
botKbFont: font(16px); botKbFont: font(15px semibold);
botKbButton: botKeyboardButton { botKbButton: botKeyboardButton {
margin: 10px; margin: 10px;
padding: 10px; padding: 10px;
height: 36px; height: 38px;
textTop: 8px; textTop: 9px;
downTextTop: 9px; downTextTop: 10px;
} }
botKbTinyButton: botKeyboardButton { botKbTinyButton: botKeyboardButton {
margin: 4px; margin: 4px;
@ -2045,6 +2142,7 @@ minPhotoSize: 100px;
maxMediaSize: 420px; maxMediaSize: 420px;
maxStickerSize: 256px; maxStickerSize: 256px;
maxGifSize: 320px; maxGifSize: 320px;
maxSignatureSize: 144px;
mvBgColor: #222; mvBgColor: #222;
mvBgOpacity: 0.92; mvBgOpacity: 0.92;
@ -2180,6 +2278,9 @@ overviewFileStatusTop: 27px;
overviewFileDateTop: 49px; overviewFileDateTop: 49px;
overviewFileChecked: #2fa9e2; overviewFileChecked: #2fa9e2;
overviewFileCheck: #00000066; overviewFileCheck: #00000066;
overviewFileExtPadding: 5px;
overviewFileExtTop: 24px;
overviewFileExtFont: font(18px semibold);
// Mac specific // Mac specific
@ -2376,7 +2477,7 @@ linksDateMargin: margins(0px, 15px, 0px, 2px);
linksPhotoCheck: sprite(184px, 196px, 16px, 16px); linksPhotoCheck: sprite(184px, 196px, 16px, 16px);
linksPhotoChecked: sprite(168px, 196px, 16px, 16px); linksPhotoChecked: sprite(168px, 196px, 16px, 16px);
inlineResultsLeft: 15px; inlineResultsLeft: 11px;
inlineResultsSkip: 3px; inlineResultsSkip: 3px;
inlineMediaHeight: 96px; inlineMediaHeight: 96px;
inlineThumbSize: 64px; inlineThumbSize: 64px;
@ -2385,5 +2486,12 @@ inlineDescriptionFg: #8a8a8a;
inlineRowMargin: 6px; inlineRowMargin: 6px;
inlineRowBorder: linksBorder; inlineRowBorder: linksBorder;
inlineRowBorderFg: linksBorderFg; inlineRowBorderFg: linksBorderFg;
inlineRowFileNameTop: 2px;
inlineRowFileDescriptionTop: 23px;
inlineResultsMinWidth: 64px; inlineResultsMinWidth: 64px;
inlineDurationMargin: 3px; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 { textStyle {
linkFlags: font; linkFlags: font;
@ -272,6 +272,20 @@ PopupMenu {
widthMax: number; widthMax: number;
} }
Tooltip {
textBg: color;
textFg: color;
textFont: font;
textBorder: color;
textPadding: margins;
shift: point;
skip: number;
widthMax: number;
linesMax: number;
}
botKeyboardButton { botKeyboardButton {
margin: number; margin: number;
padding: 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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" #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\ to link the code of portions of this program with the OpenSSL library.\n\
\n\ \n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\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"; */\n";
tcpp << "#include \"stdafx.h\"\n#include \"gui/emoji_config.h\"\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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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/QMap>
#include <QtCore/QVector> #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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" #include "genlang.h"
@ -391,7 +391,7 @@ bool genLang(const QString &lang_in, const QString &lang_out) {
th.setCodec("ISO 8859-1"); th.setCodec("ISO 8859-1");
th << "\ th << "\
/*\n\ /*\n\
Created from \'/Resources/lang.txt\' by \'/MetaLang\' project\n\ Created from \'/Resources/lang.strings\' by \'/MetaLang\' project\n\
\n\ \n\
WARNING! All changes made in this file will be lost!\n\ WARNING! All changes made in this file will be lost!\n\
\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\ to link the code of portions of this program with the OpenSSL library.\n\
\n\ \n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\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"; */\n";
th << "#pragma once\n\n"; th << "#pragma once\n\n";
@ -475,7 +475,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
tcpp << "\ tcpp << "\
/*\n\ /*\n\
Created from \'/Resources/lang.txt\' by \'/MetaLang\' project\n\ Created from \'/Resources/lang.strings\' by \'/MetaLang\' project\n\
\n\ \n\
WARNING! All changes made in this file will be lost!\n\ WARNING! All changes made in this file will be lost!\n\
\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\ to link the code of portions of this program with the OpenSSL library.\n\
\n\ \n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\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"; */\n";
tcpp << "#include \"stdafx.h\"\n#include \"lang.h\"\n\n"; tcpp << "#include \"stdafx.h\"\n#include \"lang.h\"\n\n";
tcpp << "namespace {\n"; tcpp << "namespace {\n";
@ -606,13 +606,22 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
++depth; ++depth;
current += ich; 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) << "if (ch + " << depth << " == e) {\n";
tcpp << tab.repeated(depth + 1) << "\treturn lt_" << tag << ";\n"; tcpp << tab.repeated(depth + 1) << "\treturn lt_" << tag << ";\n";
tcpp << tab.repeated(depth + 1) << "}\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); } while (true);
++j; ++j;
} }
@ -637,7 +646,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
tcpp << "\tswitch (*(ch + " << depth << ")) {\n"; tcpp << "\tswitch (*(ch + " << depth << ")) {\n";
for (LangKeys::const_iterator i = keys.cbegin(), j = i + 1, e = keys.cend(); i != e; ++i) { for (LangKeys::const_iterator i = keys.cbegin(), j = i + 1, e = keys.cend(); i != e; ++i) {
QByteArray key = i.key(); QByteArray key = i.key();
while (key.mid(0, depth) != current) { while (depth > 0 && key.mid(0, depth) != current) {
tcpp << tab.repeated(depth - 3) << "}\n"; tcpp << tab.repeated(depth - 3) << "}\n";
current.chop(1); current.chop(1);
--depth; --depth;
@ -661,13 +670,22 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\
++depth; ++depth;
current += ich; 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) << "if (ch + " << depth << " == e) {\n";
tcpp << tab.repeated(depth - 3) << "\treturn " << key << (keysTags[key].isEmpty() ? "" : "__tagged") << ";\n"; tcpp << tab.repeated(depth - 3) << "\treturn " << key << (keysTags[key].isEmpty() ? "" : "__tagged") << ";\n";
tcpp << tab.repeated(depth - 3) << "}\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); } while (true);
++j; ++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"; tcpp << "\tif (index >= lngtags_max_counted_values) return lngkeys_cnt;\n\n";
if (!tags.isEmpty()) { if (!tags.isEmpty()) {
tcpp << "\tswitch (key) {\n"; tcpp << "\tswitch (key) {\n";
for (int i = 0, l = keysOrder.size(); i < l; ++i) { for (auto key : keysOrder) {
QVector<QByteArray> &tagsList(keysTags[keysOrder[i]]); QVector<QByteArray> &tagsList(keysTags[key]);
if (tagsList.isEmpty()) continue; if (tagsList.isEmpty()) continue;
QMap<QByteArray, QVector<QString> > &countedTags(keysCounted[keysOrder[i]]); QMap<QByteArray, QVector<QString> > &countedTags(keysCounted[key]);
tcpp << "\tcase " << keysOrder[i] << "__tagged: {\n"; 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"; tcpp << "\t\tswitch (tag) {\n";
for (int j = 0, s = tagsList.size(); j < s; ++j) { for (auto tag : tagsList) {
if (!countedTags[tagsList[j]].isEmpty()) { if (!countedTags[tag].isEmpty()) {
tcpp << "\t\tcase lt_" << tagsList[j] << ": return LangKey(" << keysOrder[i] << "__" << tagsList[j] << "0 + index);\n"; tcpp << "\t\tcase lt_" << tag << ": return LangKey(" << key << "__" << tag << "0 + index);\n";
} }
} }
tcpp << "\t\t}\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 << "\t}\n\n";
} }
tcpp << "\treturn lngkeys_cnt;"; tcpp << "\treturn lngkeys_cnt;\n";
tcpp << "}\n\n"; tcpp << "}\n\n";
tcpp << "bool LangLoader::feedKeyValue(LangKey key, const QString &value) {\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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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/QMap>
#include <QtCore/QVector> #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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" #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\ to link the code of portions of this program with the OpenSSL library.\n\
\n\ \n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\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"; */\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) { for (int i = 0, l = byIndex.size(); i < l; ++i) {
ClassData &cls(byIndex[i]); ClassData &cls(byIndex[i]);
classes.insert(cls.name, cls); 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\ to link the code of portions of this program with the OpenSSL library.\n\
\n\ \n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\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"; */\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 << "\ tcpp << "\
/*\n\ /*\n\
Created from \'/Resources/style.txt\' by \'/MetaStyle\' project\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\ to link the code of portions of this program with the OpenSSL library.\n\
\n\ \n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\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"; */\n";
tcpp << "#include \"stdafx.h\"\n#include \"style_auto.h\"\n\nnamespace {\n"; tcpp << "#include \"stdafx.h\"\n#include \"style_auto.h\"\n\nnamespace {\n";
for (int i = 0, l = scalars.size(); i < l; ++i) { 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\ to link the code of portions of this program with the OpenSSL library.\n\
\n\ \n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\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"; */\n";
tnum << "#include \"stdafx.h\"\n#include \"numbers.h\"\n\n"; tnum << "#include \"stdafx.h\"\n#include \"numbers.h\"\n\n";
tnum << "QVector<int> phoneNumberParse(const QString &number) {\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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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/QMap>
#include <QtCore/QVector> #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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" #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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> #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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" #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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> #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "msmain.h"
#include <QtCore/QDir> #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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> #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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" #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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" #include "updater.h"
@ -255,7 +255,7 @@ bool update() {
} else { } else {
break; break;
} }
} while (copyTries < 30); } while (copyTries < 100);
if (!copyResult) { if (!copyResult) {
writeLog(L"Error: failed to copy, asking to retry.."); writeLog(L"Error: failed to copy, asking to retry..");
WCHAR errMsg[2048]; WCHAR errMsg[2048];
@ -328,14 +328,11 @@ void updateRegistry() {
} }
} }
#include <ShlObj.h>
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) { int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) {
openLog(); openLog();
#ifdef _NEED_WIN_GENERATE_DUMP
_oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter); _oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter);
#endif // CAPIHook apiHook("kernel32.dll", "SetUnhandledExceptionFilter", (PROC)RedirectedSetUnhandledExceptionFilter);
writeLog(L"Updaters started.."); 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); 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(); closeLog();
return 0; 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 *_programName = L"Telegram Desktop"; // folder in APPDATA, if current path is unavailable for writing
static const WCHAR *_exeName = L"Updater.exe"; static const WCHAR *_exeName = L"Updater.exe";
@ -486,13 +482,18 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) {
static const int maxFileLen = MAX_PATH * 10; static const int maxFileLen = MAX_PATH * 10;
WCHAR szPath[maxFileLen]; WCHAR szPath[maxFileLen];
wsprintf(szPath, L"%stdumps\\", path); wsprintf(szPath, L"%stdata\\", path);
if (!CreateDirectory(szPath, NULL)) { if (!CreateDirectory(szPath, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) { if (GetLastError() != ERROR_ALREADY_EXISTS) {
return 0; return 0;
} }
} }
wsprintf(szPath, L"%sdumps\\", path);
if (!CreateDirectory(szPath, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
return 0;
}
}
WCHAR szFileName[maxFileLen]; WCHAR szFileName[maxFileLen];
WCHAR szExeName[maxFileLen]; WCHAR szExeName[maxFileLen];
@ -564,4 +565,10 @@ LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers) {
return _oldWndExceptionFilter ? (*_oldWndExceptionFilter)(pExceptionPointers) : EXCEPTION_CONTINUE_SEARCH; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
#include <windows.h> #include <windows.h>
#include <string> #include <string>
#pragma warning(push)
#pragma warning(disable:4091)
#include <DbgHelp.h> #include <DbgHelp.h>
#include <ShlObj.h>
#pragma warning(pop)
#include <Shellapi.h> #include <Shellapi.h>
#include <Shlwapi.h> #include <Shlwapi.h>
@ -32,12 +38,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
using std::deque; using std::deque;
using std::wstring; using std::wstring;
#define _NEED_WIN_GENERATE_DUMP
#ifdef _NEED_WIN_GENERATE_DUMP
extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter; extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter;
LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers); 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 int updaterVersion = 1000;
static const WCHAR *updaterVersionStr = L"0.1.0"; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 <cstdio>
#include <sys/stat.h> #include <sys/stat.h>
@ -324,7 +324,7 @@ bool update() {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
bool needupdate = true, autostart = false, debug = false, tosettings = false, startintray = false, testmode = false; 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) { for (int i = 1; i < argc; ++i) {
if (equal(argv[i], "-noupdate")) { if (equal(argv[i], "-noupdate")) {
needupdate = false; needupdate = false;
@ -342,7 +342,9 @@ int main(int argc, char *argv[]) {
key = argv[i]; key = argv[i];
} else if (equal(argv[i], "-workpath") && ++i < argc) { } else if (equal(argv[i], "-workpath") && ++i < argc) {
workDir = argv[i]; workDir = argv[i];
} } else if (equal(argv[i], "-crashreport") && ++i < argc) {
crashreport = argv[i];
}
} }
openLog(); 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"; 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; int argIndex = 0;
args[argIndex++] = path; args[argIndex++] = path;
args[argIndex++] = p_noupdate; if (crashreport) {
if (autostart) args[argIndex++] = p_autostart; args[argIndex++] = crashreport;
if (debug) args[argIndex++] = p_debug; } else {
if (startintray) args[argIndex++] = p_startintray; args[argIndex++] = p_noupdate;
if (testmode) args[argIndex++] = p_testmode; if (autostart) args[argIndex++] = p_autostart;
if (tosettings) args[argIndex++] = p_tosettings; if (debug) args[argIndex++] = p_debug;
if (key) { if (startintray) args[argIndex++] = p_startintray;
args[argIndex++] = p_key; if (testmode) args[argIndex++] = p_testmode;
args[argIndex++] = key; if (tosettings) args[argIndex++] = p_tosettings;
} if (key) {
args[argIndex++] = p_key;
args[argIndex++] = key;
}
}
pid_t pid = fork(); pid_t pid = fork();
switch (pid) { switch (pid) {
case -1: writeLog("fork() failed!"); return 1; case -1: writeLog("fork() failed!"); return 1;
case 0: execv(path, args); return 1; case 0: execv(path, args); return 1;
} }
writeLog("Executed Telegram, closing log and quiting.."); writeLog("Executed Telegram, closing log and quitting..");
closeLog(); closeLog();
return 0; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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> #import <Cocoa/Cocoa.h>
NSString *appName = @"Telegram.app"; NSString *appName = @"Telegram.app";
NSString *appDir = nil; NSString *appDir = nil;
NSString *workDir = nil; NSString *workDir = nil;
NSString *crashReportArg = nil;
#ifdef _DEBUG #ifdef _DEBUG
BOOL _debug = YES; BOOL _debug = YES;
@ -101,6 +102,10 @@ int main(int argc, const char * argv[]) {
[formatter setNumberStyle:NSNumberFormatterDecimalStyle]; [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
procId = [[formatter numberFromString:[NSString stringWithUTF8String:argv[i]]] intValue]; 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]]]) { } else if ([@"-noupdate" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
update = NO; update = NO;
} else if ([@"-tosettings" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) { } 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:@""]; NSString *appPath = [[NSArray arrayWithObjects:appDir, appRealName, nil] componentsJoinedByString:@""];
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:@"-noupdate", nil]; NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: crashReportArg ? crashReportArg : @"-noupdate", nil];
if (toSettings) [args addObject:@"-tosettings"]; if (!crashReportArg) {
if (_debug) [args addObject:@"-debug"]; if (toSettings) [args addObject:@"-tosettings"];
if (startInTray) [args addObject:@"-startintray"]; if (_debug) [args addObject:@"-debug"];
if (testMode) [args addObject:@"-testmode"]; if (startInTray) [args addObject:@"-startintray"];
if (autoStart) [args addObject:@"-autostart"]; if (testMode) [args addObject:@"-testmode"];
if (key) { if (autoStart) [args addObject:@"-autostart"];
[args addObject:@"-key"]; if (key) {
[args addObject:key]; [args addObject:@"-key"];
[args addObject:key];
}
} }
writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]); writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]);
NSError *error = nil; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "style.h" #include "gui/style.h"
#include "lang.h" #include "lang.h"
#include "application.h" #include "application.h"
@ -29,89 +29,65 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "localstorage.h" #include "localstorage.h"
ApiWrap::ApiWrap(QObject *parent) : QObject(parent) { ApiWrap::ApiWrap(QObject *parent) : QObject(parent)
, _messageDataResolveDelayed(new SingleDelayedCall(this, "resolveMessageDatas")) {
App::initBackground(); App::initBackground();
connect(&_replyToTimer, SIGNAL(timeout()), this, SLOT(resolveReplyTo()));
connect(&_webPagesTimer, SIGNAL(timeout()), this, SLOT(resolveWebPages())); connect(&_webPagesTimer, SIGNAL(timeout()), this, SLOT(resolveWebPages()));
} }
void ApiWrap::init() { void ApiWrap::init() {
} }
void ApiWrap::itemRemoved(HistoryItem *item) { void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback *callback) {
if (HistoryReply *reply = item->toHistoryReply()) { MessageDataRequest::CallbackPtr pcallback(callback);
ChannelData *channel = reply->history()->peer->asChannel(); MessageDataRequest &req(channel ? _channelMessageDataRequests[channel][msgId] : _messageDataRequests[msgId]);
ReplyToRequests *requests(replyToRequests(channel, true)); req.callbacks.append(pcallback);
if (requests) { if (!req.req) _messageDataResolveDelayed->call();
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::requestReplyTo(HistoryReply *reply, ChannelData *channel, MsgId id) { ApiWrap::MessageIds ApiWrap::collectMessageIds(const MessageDataRequests &requests) {
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) {
MessageIds result; MessageIds result;
result.reserve(requests.size()); 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; if (i.value().req > 0) continue;
result.push_back(MTP_int(i.key())); result.push_back(MTP_int(i.key()));
} }
return result; return result;
} }
ApiWrap::ReplyToRequests *ApiWrap::replyToRequests(ChannelData *channel, bool onlyExisting) { ApiWrap::MessageDataRequests *ApiWrap::messageDataRequests(ChannelData *channel, bool onlyExisting) {
if (channel) { if (channel) {
ChannelReplyToRequests::iterator i = _channelReplyToRequests.find(channel); ChannelMessageDataRequests::iterator i = _channelMessageDataRequests.find(channel);
if (i == _channelReplyToRequests.cend()) { if (i == _channelMessageDataRequests.cend()) {
if (onlyExisting) return 0; if (onlyExisting) return 0;
i = _channelReplyToRequests.insert(channel, ReplyToRequests()); i = _channelMessageDataRequests.insert(channel, MessageDataRequests());
} }
return &i.value(); return &i.value();
} }
return &_replyToRequests; return &_messageDataRequests;
} }
void ApiWrap::resolveReplyTo() { void ApiWrap::resolveMessageDatas() {
if (_replyToRequests.isEmpty() && _channelReplyToRequests.isEmpty()) return; if (_messageDataRequests.isEmpty() && _channelMessageDataRequests.isEmpty()) return;
MessageIds ids = collectMessageIds(_replyToRequests); MessageIds ids = collectMessageIds(_messageDataRequests);
if (!ids.isEmpty()) { if (!ids.isEmpty()) {
mtpRequestId req = MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotReplyTo, (ChannelData*)0), RPCFailHandlerPtr(), 0, 5); mtpRequestId req = MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotMessageDatas, (ChannelData*)nullptr), RPCFailHandlerPtr(), 0, 5);
for (ReplyToRequests::iterator i = _replyToRequests.begin(); i != _replyToRequests.cend(); ++i) { for (MessageDataRequests::iterator i = _messageDataRequests.begin(); i != _messageDataRequests.cend(); ++i) {
if (i.value().req > 0) continue; if (i.value().req > 0) continue;
i.value().req = req; 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()) { if (j->isEmpty()) {
j = _channelReplyToRequests.erase(j); j = _channelMessageDataRequests.erase(j);
continue; continue;
} }
MessageIds ids = collectMessageIds(j.value()); MessageIds ids = collectMessageIds(j.value());
if (!ids.isEmpty()) { if (!ids.isEmpty()) {
mtpRequestId req = MTP::send(MTPchannels_GetMessages(j.key()->inputChannel, MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotReplyTo, j.key()), RPCFailHandlerPtr(), 0, 5); mtpRequestId req = MTP::send(MTPchannels_GetMessages(j.key()->inputChannel, MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotMessageDatas, j.key()), RPCFailHandlerPtr(), 0, 5);
for (ReplyToRequests::iterator i = j->begin(); i != j->cend(); ++i) { for (MessageDataRequests::iterator i = j->begin(); i != j->cend(); ++i) {
if (i.value().req > 0) continue; if (i.value().req > 0) continue;
i.value().req = req; 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()) { switch (msgs.type()) {
case mtpc_messages_messages: { case mtpc_messages_messages: {
const MTPDmessages_messages &d(msgs.c_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) { if (channel) {
channel->ptsReceived(d.vpts.v); channel->ptsReceived(d.vpts.v);
} else { } 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 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); App::feedUsers(d.vusers);
@ -152,16 +128,12 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs,
App::feedMsgs(d.vmessages, NewMessageExisting); App::feedMsgs(d.vmessages, NewMessageExisting);
} break; } break;
} }
ReplyToRequests *requests(replyToRequests(channel, true)); MessageDataRequests *requests(messageDataRequests(channel, true));
if (requests) { 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) { if (i.value().req == req) {
for (QList<HistoryReply*>::const_iterator j = i.value().replies.cbegin(), e = i.value().replies.cend(); j != e; ++j) { for (MessageDataRequest::Callbacks::const_iterator j = i.value().callbacks.cbegin(), e = i.value().callbacks.cend(); j != e; ++j) {
if (*j) { (*j)->call(channel, i.key());
(*j)->updateReplyTo(true);
} else {
App::main()->updateReplyTo();
}
} }
i = requests->erase(i); i = requests->erase(i);
} else { } else {
@ -169,7 +141,7 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs,
} }
} }
if (channel && requests->isEmpty()) { 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 (f.has_migrated_from_chat_id()) {
if (!channel->mgInfo) { if (!channel->mgInfo) {
channel->flags |= MTPDchannel::flag_megagroup; channel->flags |= MTPDchannel::Flag::f_megagroup;
channel->flagsUpdated(); channel->flagsUpdated();
} }
ChatData *cfrom = App::chat(peerFromChat(f.vmigrated_from_chat_id)); 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()) { if (!h->isEmpty()) {
h->clear(true); h->clear(true);
} }
if (!hto->dialogs.isEmpty() && !h->dialogs.isEmpty()) { if (hto->inChatList() && h->inChatList()) {
App::removeDialog(h); App::removeDialog(h);
} }
} }
@ -317,6 +289,13 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
h->asChannelHistory()->unreadCountAll = f.vunread_count.v; 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(); channel->fullUpdated();
App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), f.vnotify_settings); 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) { void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result, mtpRequestId req) {
const MTPDuserFull &d(result.c_userFull()); const MTPDuserFull &d(result.c_userFull());
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser), false); 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::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); if (d.has_bot_info()) {
peer->asUser()->blocked = mtpIsTrue(d.vblocked) ? UserIsBlocked : UserIsNotBlocked; 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) { if (req) {
QMap<PeerData*, mtpRequestId>::iterator i = _fullPeerRequests.find(peer); QMap<PeerData*, mtpRequestId>::iterator i = _fullPeerRequests.find(peer);
@ -419,13 +407,13 @@ void ApiWrap::requestLastParticipants(ChannelData *peer, bool fromStart) {
return; 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); _participantsRequests.insert(peer, fromStart ? req : -req);
} }
void ApiWrap::requestBots(ChannelData *peer) { void ApiWrap::requestBots(ChannelData *peer) {
if (!peer || !peer->isMegagroup() || _botsRequests.contains(peer)) return; 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) { 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); UserData *u = App::user(userId);
if (bots) { if (bots) {
if (u->botInfo) { if (u->botInfo) {
peer->mgInfo->bots.insert(u, true); peer->mgInfo->bots.insert(u);
botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
if (!u->botInfo->inited) { if (!u->botInfo->inited) {
needBotsInfos = true; needBotsInfos = true;
@ -536,9 +524,9 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP
} else { } else {
if (peer->mgInfo->lastParticipants.indexOf(u) < 0) { if (peer->mgInfo->lastParticipants.indexOf(u) < 0) {
peer->mgInfo->lastParticipants.push_back(u); peer->mgInfo->lastParticipants.push_back(u);
if (admin) peer->mgInfo->lastAdmins.insert(u, true); if (admin) peer->mgInfo->lastAdmins.insert(u);
if (u->botInfo) { if (u->botInfo) {
peer->mgInfo->bots.insert(u, true); peer->mgInfo->bots.insert(u);
if (peer->mgInfo->botStatus != 0 && peer->mgInfo->botStatus < 2) { if (peer->mgInfo->botStatus != 0 && peer->mgInfo->botStatus < 2) {
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); int32 i = kick.first->asChannel()->mgInfo->lastParticipants.indexOf(kick.second);
if (i >= 0) { if (i >= 0) {
kick.first->asChannel()->mgInfo->lastParticipants.removeAt(i); 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) { if (kick.first->asChannel()->count > 1) {
kick.first->asChannel()->count--; --kick.first->asChannel()->count;
} else { } else {
kick.first->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated; kick.first->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
kick.first->asChannel()->mgInfo->lastParticipantsCount = 0; 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); emit fullPeerUpdated(kick.first);
} }
@ -672,9 +668,9 @@ void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) {
void ApiWrap::requestStickerSets() { void ApiWrap::requestStickerSets() {
for (QMap<uint64, QPair<uint64, mtpRequestId> >::iterator i = _stickerSetRequests.begin(), j = i, e = _stickerSetRequests.end(); i != e; i = j) { 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; if (i.value().second) continue;
++j;
int32 wait = (j == e) ? 0 : 10; 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); 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; if (d.vset.type() != mtpc_stickerSet) return;
const MTPDstickerSet &s(d.vset.c_stickerSet()); const MTPDstickerSet &s(d.vset.c_stickerSet());
StickerSets &sets(cRefStickerSets()); Stickers::Sets &sets(Global::RefStickerSets());
StickerSets::iterator it = sets.find(setId); auto it = sets.find(setId);
if (it == sets.cend()) return; if (it == sets.cend()) return;
it->access = s.vaccess_hash.v; it->access = s.vaccess_hash.v;
@ -700,7 +696,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
it->flags = s.vflags.v; it->flags = s.vflags.v;
const QVector<MTPDocument> &d_docs(d.vdocuments.c_vector().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; StickerPack pack;
pack.reserve(d_docs.size()); pack.reserve(d_docs.size());
@ -731,12 +727,32 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
++i; ++i;
} }
} }
if (pack.isEmpty()) { if (pack.isEmpty()) {
int32 removeIndex = cStickerSetsOrder().indexOf(setId); int removeIndex = Global::StickerSetsOrder().indexOf(setId);
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex);
sets.erase(it); sets.erase(it);
} else { } else {
it->stickers = pack; 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) { 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) { 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 (HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), NewMessageExisting)) {
if (item) { item->setPendingInitDimensions();
item->initDimensions();
Notify::historyItemResized(item);
} }
} }
@ -902,8 +916,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
WebPageItems::const_iterator j = items.constFind(i.key()); WebPageItems::const_iterator j = items.constFind(i.key());
if (j != items.cend()) { if (j != items.cend()) {
for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) { for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) {
k.key()->initDimensions(); k.key()->setPendingInitDimensions();
Notify::historyItemResized(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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -28,9 +28,8 @@ public:
ApiWrap(QObject *parent); ApiWrap(QObject *parent);
void init(); void init();
void itemRemoved(HistoryItem *item); typedef SharedCallback<void, ChannelData*, MsgId> RequestMessageDataCallback;
void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback *callback);
void requestReplyTo(HistoryReply *reply, ChannelData *channel, MsgId id);
void requestFullPeer(PeerData *peer); void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer); void requestPeer(PeerData *peer);
@ -59,28 +58,30 @@ signals:
public slots: public slots:
void resolveReplyTo(); void resolveMessageDatas();
void resolveWebPages(); void resolveWebPages();
void delayedRequestParticipantsCount(); void delayedRequestParticipantsCount();
private: private:
void gotReplyTo(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
struct ReplyToRequest { struct MessageDataRequest {
ReplyToRequest() : req(0) { MessageDataRequest() : req(0) {
} }
typedef SharedCallback<void, ChannelData*, MsgId>::Ptr CallbackPtr;
typedef QList<CallbackPtr> Callbacks;
mtpRequestId req; mtpRequestId req;
QList<HistoryReply*> replies; Callbacks callbacks;
}; };
typedef QMap<MsgId, ReplyToRequest> ReplyToRequests; typedef QMap<MsgId, MessageDataRequest> MessageDataRequests;
ReplyToRequests _replyToRequests; MessageDataRequests _messageDataRequests;
typedef QMap<ChannelData*, ReplyToRequests> ChannelReplyToRequests; typedef QMap<ChannelData*, MessageDataRequests> ChannelMessageDataRequests;
ChannelReplyToRequests _channelReplyToRequests; ChannelMessageDataRequests _channelMessageDataRequests;
SingleTimer _replyToTimer; SingleDelayedCall *_messageDataResolveDelayed;
typedef QVector<MTPint> MessageIds; typedef QVector<MTPint> MessageIds;
MessageIds collectMessageIds(const ReplyToRequests &requests); MessageIds collectMessageIds(const MessageDataRequests &requests);
ReplyToRequests *replyToRequests(ChannelData *channel, bool onlyExisting = false); MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req); void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
void gotUserFull(PeerData *peer, const MTPUserFull &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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
#include "types.h" #include "basic_types.h"
class Application; class AppClass;
class Window; class Window;
class MainWidget; class MainWidget;
class SettingsWidget; class SettingsWidget;
@ -36,30 +36,18 @@ class FileUploader;
typedef QMap<HistoryItem*, NullType> HistoryItemsMap; typedef QMap<HistoryItem*, NullType> HistoryItemsMap;
typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems; typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems;
typedef QHash<VideoData*, HistoryItemsMap> VideoItems;
typedef QHash<AudioData*, HistoryItemsMap> AudioItems;
typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems; typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems;
typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems; typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems;
typedef QHash<int32, HistoryItemsMap> SharedContactItems; typedef QHash<int32, HistoryItemsMap> SharedContactItems;
typedef QHash<ClipReader*, HistoryItem*> GifItems; typedef QHash<ClipReader*, HistoryItem*> GifItems;
typedef QHash<PhotoId, PhotoData*> PhotosData; typedef QHash<PhotoId, PhotoData*> PhotosData;
typedef QHash<VideoId, VideoData*> VideosData;
typedef QHash<AudioId, AudioData*> AudiosData;
typedef QHash<DocumentId, DocumentData*> DocumentsData; typedef QHash<DocumentId, DocumentData*> DocumentsData;
struct ReplyMarkup {
ReplyMarkup(int32 flags = 0) : flags(flags) {
}
typedef QList<QList<QString> > Commands;
Commands commands;
int32 flags;
};
class LayeredWidget; class LayeredWidget;
namespace App { namespace App {
Application *app(); AppClass *app();
Window *wnd(); Window *wnd();
MainWidget *main(); MainWidget *main();
SettingsWidget *settings(); SettingsWidget *settings();
@ -68,7 +56,6 @@ namespace App {
ApiWrap *api(); ApiWrap *api();
void logOut(); void logOut();
bool loggedOut();
QString formatPhone(QString phone); QString formatPhone(QString phone);
@ -85,6 +72,7 @@ namespace App {
void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true); void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true);
void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &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 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 addSavedGif(DocumentData *doc);
void checkSavedGif(HistoryItem *item); void checkSavedGif(HistoryItem *item);
void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type); 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, const PreparedPhotoThumbs &thumbs);
PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0); PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0);
PhotoData *feedPhoto(const MTPDphoto &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, const QPixmap &thumb);
DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0); DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0);
DocumentData *feedDocument(const MTPDdocument &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 MTPDwebPagePending &webpage, WebPageData *convert = 0);
WebPageData *feedWebPage(const MTPWebPage &webpage); WebPageData *feedWebPage(const MTPWebPage &webpage);
PeerData *peerLoaded(const PeerId &id); PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
UserData *userLoaded(const PeerId &id); inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
ChatData *chatLoaded(const PeerId &id); return asUser(peer(id, restriction));
ChannelData *channelLoaded(const PeerId &id); }
UserData *userLoaded(int32 user); inline ChatData *chat(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
ChatData *chatLoaded(int32 chat); return asChat(peer(id, restriction));
ChannelData *channelLoaded(int32 channel); }
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(); UserData *self();
PeerData *peerByName(const QString &username); PeerData *peerByName(const QString &username);
QString peerName(const PeerData *peer, bool forDialogs = false); QString peerName(const PeerData *peer, bool forDialogs = false);
PhotoData *photo(const PhotoId &photo); 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); 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 *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); 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 *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); 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); LocationData *location(const LocationCoords &coords);
ImageLinkData *imageLinkSet(const QString &imageLink, ImageLinkType type, const QString &url);
void forgetMedia(); void forgetMedia();
MTPPhoto photoFromUserPhoto(MTPint userId, MTPint date, const MTPUserProfilePhoto &photo); 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 *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead);
History *historyLoaded(const PeerId &peer); History *historyLoaded(const PeerId &peer);
HistoryItem *histItemById(ChannelId channelId, MsgId itemId); 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) { inline HistoryItem *histItemById(const FullMsgId &msgId) {
return histItemById(msgId.channel, msgId.msg); return histItemById(msgId.channel, msgId.msg);
} }
void historyRegItem(HistoryItem *item); void historyRegItem(HistoryItem *item);
void historyItemDetached(HistoryItem *item); void historyItemDetached(HistoryItem *item);
void historyUnregItem(HistoryItem *item); void historyUnregItem(HistoryItem *item);
void historyUpdateDependent(HistoryItem *item);
void historyClearMsgs(); void historyClearMsgs();
void historyClearItems(); void historyClearItems();
void historyRegReply(HistoryReply *reply, HistoryItem *to); void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency);
void historyUnregReply(HistoryReply *reply, HistoryItem *to); void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency);
void historyRegRandom(uint64 randomId, const FullMsgId &itemId); void historyRegRandom(uint64 randomId, const FullMsgId &itemId);
void historyUnregRandom(uint64 randomId); void historyUnregRandom(uint64 randomId);
@ -202,9 +219,15 @@ namespace App {
bool isValidPhone(QString phone); bool isValidPhone(QString phone);
enum LaunchState {
Launched = 0,
QuitRequested = 1,
QuitProcessed = 2,
};
void quit(); void quit();
bool quiting(); bool quitting();
void setQuiting(); LaunchState launchState();
void setLaunchState(LaunchState state);
QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0); 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); 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 PhotoItems &photoItems();
const PhotosData &photosData(); 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 regDocumentItem(DocumentData *data, HistoryItem *item);
void unregDocumentItem(DocumentData *data, HistoryItem *item); void unregDocumentItem(DocumentData *data, HistoryItem *item);
const DocumentItems &documentItems(); const DocumentItems &documentItems();
@ -246,16 +259,10 @@ namespace App {
void unregMuted(PeerData *peer); void unregMuted(PeerData *peer);
void updateMuted(); 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); void setProxySettings(QNetworkAccessManager &manager);
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxy getHttpProxySettings(); QNetworkProxy getHttpProxySettings();
#endif
void setProxySettings(QTcpSocket &socket); void setProxySettings(QTcpSocket &socket);
QImage **cornersMask(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QNetworkReply>
#include "window.h" #include "window.h"
#include "pspecific.h" #include "pspecific.h"
class MainWidget; class UpdateChecker;
class FileUploader; class Application : public QApplication {
class Translator;
class UpdateDownloader;
class Application : public PsApplication, public RPCSender {
Q_OBJECT Q_OBJECT
public: public:
Application(int &argc, char **argv); Application(int &argc, char **argv);
~Application();
static Application *app(); // Single instance application
static Window *wnd(); public slots:
static QString language();
static int32 languageId(); void socketConnected();
static MainWidget *main(); 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 { enum UpdatingState {
UpdatingNone, UpdatingNone,
@ -52,11 +74,87 @@ public:
UpdatingReady, UpdatingReady,
}; };
UpdatingState updatingState(); UpdatingState updatingState();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
int32 updatingSize(); int32 updatingSize();
int32 updatingReady(); 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(); 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(); FileUploader *uploader();
void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId); void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
@ -85,14 +183,6 @@ public:
signals: 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 peerPhotoDone(PeerId peer);
void peerPhotoFail(PeerId peer); void peerPhotoFail(PeerId peer);
@ -100,31 +190,9 @@ signals:
public slots: 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 doMtpUnpause();
void readClients(); void photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
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 onSwitchDebugMode(); void onSwitchDebugMode();
void onSwitchTestMode(); void onSwitchTestMode();
@ -132,6 +200,8 @@ public slots:
void killDownloadSessions(); void killDownloadSessions();
void onAppStateChanged(Qt::ApplicationState state); void onAppStateChanged(Qt::ApplicationState state);
void call_handleHistoryUpdate();
private: private:
QMap<FullMsgId, PeerId> photoUpdates; QMap<FullMsgId, PeerId> photoUpdates;
@ -139,35 +209,12 @@ private:
QMap<int32, uint64> killDownloadSessionTimes; QMap<int32, uint64> killDownloadSessionTimes;
SingleTimer killDownloadSessionsTimer; SingleTimer killDownloadSessionsTimer;
void startApp(); uint64 _lastActionTime;
typedef QPair<QLocalSocket*, QByteArray> ClientSocket; Window *_window;
typedef QVector<ClientSocket> ClientSockets; FileUploader *_uploader;
Translator *_translator;
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
SingleTimer _mtpUnpauseTimer; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
#include "types.h" #include "basic_types.h"
void audioInit(); void audioInit();
bool audioWorks(); bool audioWorks();
@ -56,7 +56,7 @@ public:
void play(const AudioMsgId &audio, int64 position = 0); void play(const AudioMsgId &audio, int64 position = 0);
void play(const SongMsgId &song, int64 position = 0); void play(const SongMsgId &song, int64 position = 0);
void pauseresume(MediaOverviewType type, bool fast = false); void pauseresume(MediaOverviewType type, bool fast = false);
void seek(int64 position); // type == OverviewDocuments void seek(int64 position); // type == OverviewFiles
void stop(MediaOverviewType type); void stop(MediaOverviewType type);
void stopAndClear(); void stopAndClear();
@ -201,8 +201,8 @@ signals:
void captureOnStart(); void captureOnStart();
void captureOnStop(bool needResult); void captureOnStop(bool needResult);
void onDone(QByteArray data, qint32 samples); void onDone(QByteArray data, VoiceWaveform waveform, qint32 samples);
void onUpdate(qint16 level, qint32 samples); void onUpdate(quint16 level, qint32 samples);
void onError(); void onError();
private: private:
@ -338,8 +338,8 @@ public:
signals: signals:
void error(); void error();
void update(qint16 level, qint32 samples); void update(quint16 level, qint32 samples);
void done(QByteArray data, qint32 samples); void done(QByteArray data, VoiceWaveform waveform, qint32 samples);
public slots: public slots:
@ -360,3 +360,4 @@ private:
}; };
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "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 "application.h"
#include "pspecific.h" #include "pspecific.h"
#include "autoupdater.h"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE #ifndef TDESKTOP_DISABLE_AUTOUPDATE
@ -34,7 +47,7 @@ typedef int VerInt;
typedef wchar_t VerChar; typedef wchar_t VerChar;
#endif #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; updateUrl = url;
moveToThread(thread); moveToThread(thread);
manager.moveToThread(thread); manager.moveToThread(thread);
@ -44,14 +57,14 @@ UpdateDownloader::UpdateDownloader(QThread *thread, const QString &url) : reply(
initOutput(); initOutput();
} }
void UpdateDownloader::initOutput() { void UpdateChecker::initOutput() {
QString fileName; QString fileName;
QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl); QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl);
if (m.hasMatch()) { if (m.hasMatch()) {
fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString()); fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString());
} }
if (fileName.isEmpty()) { 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/"); QString dirStr = cWorkingDir() + qsl("tupdates/");
fileName = dirStr + fileName; fileName = dirStr + fileName;
@ -99,11 +112,11 @@ void UpdateDownloader::initOutput() {
} }
} }
void UpdateDownloader::start() { void UpdateChecker::start() {
sendRequest(); sendRequest();
} }
void UpdateDownloader::sendRequest() { void UpdateChecker::sendRequest() {
QNetworkRequest req(updateUrl); QNetworkRequest req(updateUrl);
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-"; QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";
req.setRawHeader("Range", rangeHeaderValue); req.setRawHeader("Range", rangeHeaderValue);
@ -115,7 +128,7 @@ void UpdateDownloader::sendRequest() {
connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot())); connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot()));
} }
void UpdateDownloader::partMetaGot() { void UpdateChecker::partMetaGot() {
typedef QList<QNetworkReply::RawHeaderPair> Pairs; typedef QList<QNetworkReply::RawHeaderPair> Pairs;
Pairs pairs = reply->rawHeaderPairs(); Pairs pairs = reply->rawHeaderPairs();
for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) { for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) {
@ -126,23 +139,24 @@ void UpdateDownloader::partMetaGot() {
QMutexLocker lock(&mutex); QMutexLocker lock(&mutex);
full = m.captured(1).toInt(); full = m.captured(1).toInt();
} }
emit App::app()->updateDownloading(already, full);
Sandbox::updateProgress(already, full);
} }
} }
} }
} }
int32 UpdateDownloader::ready() { int32 UpdateChecker::ready() {
QMutexLocker lock(&mutex); QMutexLocker lock(&mutex);
return already; return already;
} }
int32 UpdateDownloader::size() { int32 UpdateChecker::size() {
QMutexLocker lock(&mutex); QMutexLocker lock(&mutex);
return full; return full;
} }
void UpdateDownloader::partFinished(qint64 got, qint64 total) { void UpdateChecker::partFinished(qint64 got, qint64 total) {
if (!reply) return; if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
@ -179,11 +193,11 @@ void UpdateDownloader::partFinished(qint64 got, qint64 total) {
outputFile.close(); outputFile.close();
unpackUpdate(); unpackUpdate();
} else { } 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; if (!reply) return;
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); 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)); 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(); clearAll();
emit App::app()->updateFailed(); Sandbox::updateFailed();
} }
void UpdateDownloader::clearAll() { void UpdateChecker::clearAll() {
psDeleteDir(cWorkingDir() + qsl("tupdates")); psDeleteDir(cWorkingDir() + qsl("tupdates"));
} }
@ -225,7 +239,7 @@ void UpdateDownloader::clearAll() {
// return QString::fromWCharArray(errMsg); // return QString::fromWCharArray(errMsg);
//} //}
void UpdateDownloader::unpackUpdate() { void UpdateChecker::unpackUpdate() {
QByteArray packed; QByteArray packed;
if (!outputFile.open(QIODevice::ReadOnly)) { if (!outputFile.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read updates file!")); LOG(("Update Error: cant read updates file!"));
@ -465,10 +479,10 @@ void UpdateDownloader::unpackUpdate() {
} }
outputFile.remove(); outputFile.remove();
emit App::app()->updateReady(); Sandbox::updateReady();
} }
UpdateDownloader::~UpdateDownloader() { UpdateChecker::~UpdateChecker() {
delete reply; delete reply;
reply = 0; reply = 0;
} }
@ -477,7 +491,7 @@ bool checkReadyUpdate() {
QString readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"), readyPath = cWorkingDir() + qsl("tupdates/temp"); QString readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"), readyPath = cWorkingDir() + qsl("tupdates/temp");
if (!QFile(readyFilePath).exists()) { if (!QFile(readyFilePath).exists()) {
if (QDir(cWorkingDir() + qsl("tupdates/ready")).exists() || QDir(cWorkingDir() + qsl("tupdates/temp")).exists()) { if (QDir(cWorkingDir() + qsl("tupdates/ready")).exists() || QDir(cWorkingDir() + qsl("tupdates/temp")).exists()) {
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
} }
return false; return false;
} }
@ -488,30 +502,30 @@ bool checkReadyUpdate() {
QFile fVersion(versionPath); QFile fVersion(versionPath);
if (!fVersion.open(QIODevice::ReadOnly)) { if (!fVersion.open(QIODevice::ReadOnly)) {
LOG(("Update Error: cant read version file '%1'").arg(versionPath)); LOG(("Update Error: cant read version file '%1'").arg(versionPath));
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
VerInt versionNum; VerInt versionNum;
if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) { if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) {
LOG(("Update Error: cant read version from file '%1'").arg(versionPath)); LOG(("Update Error: cant read version from file '%1'").arg(versionPath));
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
if (versionNum == 0x7FFFFFFF) { // beta version if (versionNum == 0x7FFFFFFF) { // beta version
quint64 betaVersion = 0; quint64 betaVersion = 0;
if (fVersion.read((char*)&betaVersion, sizeof(quint64)) != sizeof(quint64)) { if (fVersion.read((char*)&betaVersion, sizeof(quint64)) != sizeof(quint64)) {
LOG(("Update Error: cant read beta version from file '%1'").arg(versionPath)); LOG(("Update Error: cant read beta version from file '%1'").arg(versionPath));
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
if (!cBetaVersion() || betaVersion <= cBetaVersion()) { if (!cBetaVersion() || betaVersion <= cBetaVersion()) {
LOG(("Update Error: cant install beta version %1 having beta version %2").arg(betaVersion).arg(cBetaVersion())); LOG(("Update Error: cant install beta version %1 having beta version %2").arg(betaVersion).arg(cBetaVersion()));
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
} else if (versionNum <= AppVersion) { } else if (versionNum <= AppVersion) {
LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion)); LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion));
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
fVersion.close(); fVersion.close();
@ -530,11 +544,11 @@ bool checkReadyUpdate() {
if (!updater.exists()) { if (!updater.exists()) {
QFileInfo current(curUpdater); QFileInfo current(curUpdater);
if (!current.exists()) { if (!current.exists()) {
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) { if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) {
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
} }
@ -545,24 +559,24 @@ bool checkReadyUpdate() {
cSetWriteProtected(true); cSetWriteProtected(true);
return true; return true;
} else { } else {
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
} }
if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) { if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) {
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
#elif defined Q_OS_MAC #elif defined Q_OS_MAC
QDir().mkpath(QFileInfo(curUpdater).absolutePath()); 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)) { if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) {
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
#elif defined Q_OS_LINUX #elif defined Q_OS_LINUX
if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) { if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) {
UpdateDownloader::clearAll(); UpdateChecker::clearAll();
return false; return false;
} }
#endif #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -26,11 +26,11 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include <QtNetwork/QLocalServer> #include <QtNetwork/QLocalServer>
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
class UpdateDownloader : public QObject { class UpdateChecker : public QObject {
Q_OBJECT Q_OBJECT
public: public:
UpdateDownloader(QThread *thread, const QString &url); UpdateChecker(QThread *thread, const QString &url);
void unpackUpdate(); void unpackUpdate();
@ -39,7 +39,7 @@ public:
static void clearAll(); static void clearAll();
~UpdateDownloader(); ~UpdateChecker();
public slots: public slots:
@ -66,6 +66,11 @@ private:
bool checkReadyUpdate(); bool checkReadyUpdate();
#else
class UpdateChecker : public QObject {
Q_OBJECT
};
#endif #endif
QString countBetaVersionSignature(uint64 version); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "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" #include "application.h"
uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 }; uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
@ -35,6 +45,10 @@ uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
// Base types compile-time check // Base types compile-time check
#ifdef TDESKTOP_CUSTOM_NULLPTR
NullPointerClass nullptr;
#endif
namespace { namespace {
template <typename T, int N> template <typename T, int N>
class _TypeSizeCheckerHelper { class _TypeSizeCheckerHelper {
@ -106,8 +120,8 @@ namespace {
} }
} }
int32 myunixtime() { TimeId myunixtime() {
return (int32)time(NULL); return (TimeId)time(NULL);
} }
void unixtimeInit() { void unixtimeInit() {
@ -135,19 +149,19 @@ void unixtimeSet(int32 serverTime, bool force) {
_initMsgIdConstants(); _initMsgIdConstants();
} }
int32 unixtime() { TimeId unixtime() {
int32 result = myunixtime(); TimeId result = myunixtime();
QReadLocker locker(&unixtimeLock); QReadLocker locker(&unixtimeLock);
return result + unixtimeDelta; return result + unixtimeDelta;
} }
int32 fromServerTime(const MTPint &serverTime) { TimeId fromServerTime(const MTPint &serverTime) {
QReadLocker locker(&unixtimeLock); QReadLocker locker(&unixtimeLock);
return serverTime.v - unixtimeDelta; return serverTime.v - unixtimeDelta;
} }
MTPint toServerTime(const int32 &clientTime) { MTPint toServerTime(const TimeId &clientTime) {
QReadLocker locker(&unixtimeLock); QReadLocker locker(&unixtimeLock);
return MTP_int(clientTime + unixtimeDelta); return MTP_int(clientTime + unixtimeDelta);
} }
@ -187,6 +201,32 @@ namespace {
delete l; 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 _msFreq;
float64 _msgIdCoef; float64 _msgIdCoef;
int64 _msStart = 0, _msAddToMsStart = 0, _msAddToUnixtime = 0; int64 _msStart = 0, _msAddToMsStart = 0, _msAddToUnixtime = 0;
@ -238,36 +278,51 @@ namespace {
_MsStarter _msStarter; _MsStarter _msStarter;
} }
InitOpenSSL::InitOpenSSL() { namespace ThirdParty {
if (!RAND_status()) { // should be always inited in all modern OS
char buf[16]; void start() {
memcpy(buf, &_msStart, 8); PlatformSpecific::ThirdParty::start();
memcpy(buf + 8, &_msFreq, 8);
uchar sha256Buffer[32]; if (!RAND_status()) { // should be always inited in all modern OS
RAND_seed(hashSha256(buf, 16, sha256Buffer), 32); char buf[16];
if (!RAND_status()) { memcpy(buf, &_msStart, 8);
LOG(("MTP Error: Could not init OpenSSL rand, RAND_status() is 0..")); 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(); void finish() {
if (numLocks) { av_lockmgr_register(0);
_sslLocks = new QMutex[numLocks];
CRYPTO_set_locking_callback(_sslLockingCallback); delete[] _sslLocks;
} else { _sslLocks = 0;
LOG(("MTP Error: Could not init OpenSSL threads, CRYPTO_num_locks() returned zero!"));
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() { bool checkms() {
@ -640,10 +695,7 @@ char *hashMd5Hex(const int32 *hashmd5, void *dest) {
} }
void memset_rand(void *data, uint32 len) { void memset_rand(void *data, uint32 len) {
if (!_sslInited) { t_assert(_sslInited);
LOG(("Critical Error: memset_rand() called before OpenSSL init!"));
exit(-1);
}
RAND_bytes((uchar*)data, len); RAND_bytes((uchar*)data, len);
} }
@ -777,8 +829,7 @@ QString translitRusEng(const QString &rus) {
result.reserve(rus.size() * 2); result.reserve(rus.size() * 2);
int32 toSkip = 0; int32 toSkip = 0;
for (QString::const_iterator i = rus.cbegin(), e = rus.cend(); i != e;) { for (QString::const_iterator i = rus.cbegin(), e = rus.cend(); i != e; i += toSkip) {
i += toSkip;
result += translitLetterRusEng(*i, (i + 1 == e) ? ' ' : *(i + 1), toSkip); result += translitLetterRusEng(*i, (i + 1 == e) ? ' ' : *(i + 1), toSkip);
} }
return result; return result;
@ -982,3 +1033,33 @@ MimeType mimeTypeForData(const QByteArray &data) {
} }
return MimeType(QMimeDatabase().mimeTypeForData(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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -44,6 +44,8 @@ AboutBox::AboutBox() : AbstractBox(st::aboutWidth)
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
prepare(); prepare();
setAcceptDrops(true);
} }
void AboutBox::hideAll() { void AboutBox::hideAll() {
@ -82,7 +84,7 @@ void AboutBox::onVersion() {
} }
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(countBetaVersionSignature(cRealBetaVersion()))); 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.")); Ui::showLayer(new InformBox("The link to the current private beta version of Telegram Desktop was copied to the clipboard."));
} else { } else {
@ -105,10 +107,39 @@ void AboutBox::paintEvent(QPaintEvent *e) {
paintTitle(p, qsl("Telegram Desktop")); 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 telegramFaqLink() {
QString result = qsl("https://telegram.org/faq"); QString result = qsl("https://telegram.org/faq");
if (cLang() > languageDefault && cLang() < languageCount) { 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) { if (qstr("de") == code || qstr("es") == code || qstr("it") == code || qstr("ko") == code) {
result += qsl("/") + code; result += qsl("/") + code;
} else if (qstr("pt_BR") == 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -32,6 +32,9 @@ public:
void keyPressEvent(QKeyEvent *e); void keyPressEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
public slots: public slots:
void onVersion(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -178,6 +178,14 @@ void AbstractBox::resizeMaxHeight(int32 newWidth, int32 maxHeight) {
_maxHeight = maxHeight; _maxHeight = maxHeight;
resize(newWidth, countHeight()); resize(newWidth, countHeight());
if (parentWidget()) { 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()))); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -188,11 +188,11 @@ void AddContactBox::onSave() {
} }
_sentName = firstName; _sentName = firstName;
if (_user) { 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))); 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)); _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector<MTPInputContact>(v), MTP_bool(false)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveUserFail));
} else { } 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))); 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)); _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); App::feedUsers(d.vusers);
const QVector<MTPImportedContact> &v(d.vimported.c_vector().v); const QVector<MTPImportedContact> &v(d.vimported.c_vector().v);
int32 uid = 0; UserData *user = nullptr;
if (!v.isEmpty()) { if (!v.isEmpty()) {
const MTPDimportedContact &c(v.front().c_importedContact()); const MTPDimportedContact &c(v.front().c_importedContact());
if (c.vclient_id.v != _contactId) return; if (c.vclient_id.v != _contactId) return;
uid = c.vuser_id.v; user = App::userLoaded(c.vuser_id.v);
if (uid && !App::userLoaded(uid)) {
uid = 0;
}
} }
if (uid) { if (user) {
Notify::userIsContactChanged(App::userLoaded(peerFromUser(uid)), true); Notify::userIsContactChanged(user, true);
Ui::hideLayer(); Ui::hideLayer();
} else { } else {
_save.hide(); _save.hide();
@ -275,7 +272,7 @@ NewGroupBox::NewGroupBox() : AbstractBox(),
_group(this, qsl("group_type"), 0, lang(lng_create_group_title), true), _group(this, qsl("group_type"), 0, lang(lng_create_group_title), true),
_channel(this, qsl("group_type"), 1, lang(lng_create_channel_title)), _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()), _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), _aboutChannel(st::normalFont, lang(lng_create_channel_about), _defaultOptions, _aboutGroupWidth),
_next(this, lang(lng_create_group_next), st::defaultBoxButton), _next(this, lang(lng_create_group_next), st::defaultBoxButton),
_cancel(this, lang(lng_cancel), st::cancelBoxButton) { _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
@ -499,8 +496,8 @@ void GroupInfoBox::onNext() {
Ui::showLayer(new ContactsBox(title, _photoBig), KeepOtherLayers); Ui::showLayer(new ContactsBox(title, _photoBig), KeepOtherLayers);
} else { } else {
bool mega = false; bool mega = false;
int32 flags = mega ? MTPchannels_CreateChannel::flag_megagroup : MTPchannels_CreateChannel::flag_broadcast; MTPchannels_CreateChannel::Flags flags = mega ? MTPchannels_CreateChannel::Flag::f_megagroup : MTPchannels_CreateChannel::Flag::f_broadcast;
_creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(flags), MTP_string(title), MTP_string(description)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); _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.setFocus();
_title.showError(); _title.showError();
return true; return true;
} else if (error.type() == qstr("USER_RESTRICTED")) {
Ui::showLayer(new InformBox(lang(lng_cant_do_this)));
return true;
} }
return false; return false;
} }
@ -605,12 +605,12 @@ void GroupInfoBox::onPhotoReady(const QImage &img) {
SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : AbstractBox() SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : AbstractBox()
, _channel(channel) , _channel(channel)
, _existing(existing) , _existing(existing)
, _public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true) , _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(lng_create_private_channel_title)) , _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) , _comments(this, lang(lng_create_channel_comments), false)
, _aboutPublicWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x()) , _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) , _aboutPublic(st::normalFont, lang(channel->isMegagroup() ? lng_create_public_group_about : lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth)
, _aboutPrivate(st::normalFont, lang(lng_create_private_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) , _aboutComments(st::normalFont, lang(lng_create_channel_comments_about), _defaultOptions, _aboutPublicWidth)
, _link(this, st::defaultInputField, QString(), channel->username, true) , _link(this, st::defaultInputField, QString(), channel->username, true)
, _linkOver(false) , _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)); _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail));
_aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth); _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(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose()));
@ -669,6 +669,14 @@ void SetupChannelBox::showDone() {
_link.setFocus(); _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) { void SetupChannelBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (_link.hasFocus()) { 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); //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()); //_aboutComments.drawLeft(p, aboutComments.x(), aboutComments.y(), aboutComments.width(), width());
p.setPen(st::black); if (!_channel->isMegagroup() || !_link.isHidden()) {
p.setFont(st::newGroupLinkFont); p.setPen(st::black);
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)); 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()) { if (_link.isHidden()) {
QTextOption option(style::al_left); if (!_channel->isMegagroup()) {
option.setWrapMode(QTextOption::WrapAnywhere); QTextOption option(style::al_left);
p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont); option.setWrapMode(QTextOption::WrapAnywhere);
p.setPen(st::btnDefLink.color); p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont);
p.drawText(_invitationLink, _channel->invitationUrl, option); p.setPen(st::btnDefLink.color);
if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) { p.drawText(_invitationLink, _channel->invitationUrl, option);
p.setOpacity(a_goodOpacity.current()); if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) {
p.setPen(st::setGoodColor); p.setOpacity(a_goodOpacity.current());
p.setFont(st::boxTextFont); p.setPen(st::setGoodColor);
p.drawTextRight(st::boxPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink); p.setFont(st::boxTextFont);
p.setOpacity(1); p.drawTextRight(st::boxPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink);
p.setOpacity(1);
}
} }
} else { } else {
if (!_errorText.isEmpty()) { if (!_errorText.isEmpty()) {
@ -750,7 +762,7 @@ void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) {
void SetupChannelBox::mousePressEvent(QMouseEvent *e) { void SetupChannelBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e); mouseMoveEvent(e);
if (_linkOver) { if (_linkOver) {
App::app()->clipboard()->setText(_channel->invitationUrl); Application::clipboard()->setText(_channel->invitationUrl);
_goodTextLink = lang(lng_create_channel_link_copied); _goodTextLink = lang(lng_create_channel_link_copied);
a_goodOpacity = anim::fvalue(1, 0); a_goodOpacity = anim::fvalue(1, 0);
_a_goodFade.start(); _a_goodFade.start();
@ -827,7 +839,7 @@ void SetupChannelBox::onChange() {
} }
_checkTimer.stop(); _checkTimer.stop();
} else { } else {
int32 i, len = name.size(); int32 len = name.size();
for (int32 i = 0; i < len; ++i) { for (int32 i = 0; i < len; ++i) {
QChar ch = name.at(i); QChar ch = name.at(i);
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') { if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') {
@ -879,6 +891,9 @@ void SetupChannelBox::onPrivacyChange() {
_link.hide(); _link.hide();
setFocus(); setFocus();
} }
if (_channel->isMegagroup()) {
updateMaxHeight();
}
update(); update();
} }
@ -929,7 +944,10 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) {
_checkRequestId = 0; _checkRequestId = 0;
QString err(error.type()); 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) { if (_existing) {
Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing))); Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
} else { } else {
@ -938,11 +956,11 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) {
onPrivacyChange(); onPrivacyChange();
} }
return true; return true;
} else if (err == "USERNAME_INVALID") { } else if (err == qstr("USERNAME_INVALID")) {
_errorText = lang(lng_create_channel_link_invalid); _errorText = lang(lng_create_channel_link_invalid);
update(); update();
return true; 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); _errorText = lang(lng_create_channel_link_occupied);
update(); update();
return true; return true;
@ -957,7 +975,10 @@ bool SetupChannelBox::onFirstCheckFail(const RPCError &error) {
_checkRequestId = 0; _checkRequestId = 0;
QString err(error.type()); 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) { if (_existing) {
Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing))); Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
} else { } else {
@ -1094,7 +1115,8 @@ void EditNameTitleBox::onSave() {
} }
_sentName = first; _sentName = first;
if (_peer == App::self()) { 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()) { } else if (_peer->isChat()) {
_requestId = MTP::send(MTPmessages_EditChatTitle(_peer->asChat()->inputChat, MTP_string(first)), rpcDone(&EditNameTitleBox::onSaveChatDone), rpcFail(&EditNameTitleBox::onSaveChatFail)); _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(); emit closed();
} }
EditChannelBox::EditChannelBox(ChannelData *channel) : EditChannelBox::EditChannelBox(ChannelData *channel) : AbstractBox()
_channel(channel), , _channel(channel)
_save(this, lang(lng_settings_save), st::defaultBoxButton), , _save(this, lang(lng_settings_save), st::defaultBoxButton)
_cancel(this, lang(lng_cancel), st::cancelBoxButton), , _cancel(this, lang(lng_cancel), st::cancelBoxButton)
_title(this, st::defaultInputField, lang(lng_dlg_new_channel_name), _channel->name), , _title(this, st::defaultInputField, lang(lng_dlg_new_channel_name), _channel->name)
_description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about), , _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), , _sign(this, lang(lng_edit_sign_messages), channel->addsSignature())
_saveTitleRequestId(0), _saveDescriptionRequestId(0) { , _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*))); connect(App::main(), SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(peerUpdated(PeerData*)));
setMouseTracking(true); setMouseTracking(true);
@ -1183,6 +1208,7 @@ _saveTitleRequestId(0), _saveDescriptionRequestId(0) {
void EditChannelBox::hideAll() { void EditChannelBox::hideAll() {
_title.hide(); _title.hide();
_description.hide(); _description.hide();
_sign.hide();
_save.hide(); _save.hide();
_cancel.hide(); _cancel.hide();
_publicLink.hide(); _publicLink.hide();
@ -1193,10 +1219,15 @@ void EditChannelBox::showAll() {
_description.show(); _description.show();
_save.show(); _save.show();
_cancel.show(); _cancel.show();
if (_channel->isMegagroup()) { if (_channel->canEditUsername()) {
_publicLink.hide();
} else {
_publicLink.show(); _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) { void EditChannelBox::peerUpdated(PeerData *peer) {
if (peer == _channel) { if (peer == _channel) {
_publicLink.setText(lang(_channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link)); _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() { void EditChannelBox::updateMaxHeight() {
int32 h = st::boxTitleHeight + st::newGroupInfoPadding.top() + _title.height(); int32 h = st::boxTitleHeight + st::newGroupInfoPadding.top() + _title.height();
h += st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); 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(); h += st::boxPadding.bottom() + st::newGroupInfoPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom();
setMaxHeight(h); 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()); _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()); _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height());
_cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y());
} }
void EditChannelBox::onSave() { void EditChannelBox::onSave() {
if (_saveTitleRequestId || _saveDescriptionRequestId) return; if (_saveTitleRequestId || _saveDescriptionRequestId || _saveSignRequestId) return;
QString title = prepareText(_title.getLastText()), description = prepareText(_description.getLastText(), true); QString title = prepareText(_title.getLastText()), description = prepareText(_description.getLastText(), true);
if (title.isEmpty()) { if (title.isEmpty()) {
@ -1263,7 +1306,11 @@ void EditChannelBox::onSave() {
} }
_sentTitle = title; _sentTitle = title;
_sentDescription = description; _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() { void EditChannelBox::onPublicLink() {
@ -1271,7 +1318,19 @@ void EditChannelBox::onPublicLink() {
} }
void EditChannelBox::saveDescription() { 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) { bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) {
@ -1295,24 +1354,46 @@ bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) {
_saveDescriptionRequestId = 0; _saveDescriptionRequestId = 0;
if (err == qstr("CHAT_ABOUT_NOT_MODIFIED")) { if (err == qstr("CHAT_ABOUT_NOT_MODIFIED")) {
_channel->about = _sentDescription; _channel->about = _sentDescription;
if (App::api()) emit App::api()->fullPeerUpdated(_channel); if (App::api()) {
onClose(); emit App::api()->fullPeerUpdated(_channel);
}
saveSign();
return true;
} else { } else {
_description.setFocus(); _description.setFocus();
} }
} else if (req == _saveSignRequestId) {
_saveSignRequestId = 0;
if (err == qstr("CHAT_NOT_MODIFIED")) {
onClose();
return true;
}
} }
return true; return true;
} }
void EditChannelBox::onSaveTitleDone(const MTPUpdates &updates) { void EditChannelBox::onSaveTitleDone(const MTPUpdates &updates) {
_saveTitleRequestId = 0; _saveTitleRequestId = 0;
App::main()->sentUpdatesReceived(updates); if (App::main()) {
App::main()->sentUpdatesReceived(updates);
}
saveDescription(); saveDescription();
} }
void EditChannelBox::onSaveDescriptionDone(const MTPBool &result) { void EditChannelBox::onSaveDescriptionDone(const MTPBool &result) {
_saveDescriptionRequestId = 0; _saveDescriptionRequestId = 0;
_channel->about = _sentDescription; _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(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -211,6 +211,8 @@ private:
bool onCheckFail(const RPCError &error); bool onCheckFail(const RPCError &error);
bool onFirstCheckFail(const RPCError &error); bool onFirstCheckFail(const RPCError &error);
void updateMaxHeight();
ChannelData *_channel; ChannelData *_channel;
bool _existing; bool _existing;
@ -315,18 +317,21 @@ private:
void onSaveTitleDone(const MTPUpdates &updates); void onSaveTitleDone(const MTPUpdates &updates);
void onSaveDescriptionDone(const MTPBool &result); void onSaveDescriptionDone(const MTPBool &result);
void onSaveSignDone(const MTPUpdates &updates);
bool onSaveFail(const RPCError &e, mtpRequestId req); bool onSaveFail(const RPCError &e, mtpRequestId req);
void saveDescription(); void saveDescription();
void saveSign();
ChannelData *_channel; ChannelData *_channel;
BoxButton _save, _cancel; BoxButton _save, _cancel;
InputField _title; InputField _title;
InputArea _description; InputArea _description;
Checkbox _sign;
LinkButton _publicLink; LinkButton _publicLink;
mtpRequestId _saveTitleRequestId, _saveDescriptionRequestId; mtpRequestId _saveTitleRequestId, _saveDescriptionRequestId, _saveSignRequestId;
QString _sentTitle, _sentDescription; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -34,19 +34,19 @@ TextParseOptions _confirmBoxTextOptions = {
Qt::LayoutDirectionAuto, // dir 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), ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style::BoxButton &doneStyle, const QString &cancelText, const style::BoxButton &cancelStyle) : AbstractBox(st::boxWidth)
_informative(false), , _informative(false)
_text(100), , _text(100)
_confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle), , _confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle)
_cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, cancelStyle) { , _cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, cancelStyle) {
init(text); init(text);
} }
ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style::BoxButton &doneStyle, bool informative) : AbstractBox(st::boxWidth), ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style::BoxButton &doneStyle, bool informative) : AbstractBox(st::boxWidth)
_informative(true), , _informative(true)
_text(100), , _text(100)
_confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle), , _confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle)
_cancel(this, QString(), st::cancelBoxButton) { , _cancel(this, QString(), st::cancelBoxButton) {
init(text); init(text);
} }
@ -83,33 +83,30 @@ void ConfirmBox::mouseMoveEvent(QMouseEvent *e) {
void ConfirmBox::mousePressEvent(QMouseEvent *e) { void ConfirmBox::mousePressEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateHover(); updateHover();
if (textlnkOver()) { ClickHandler::pressed();
textlnkDown(textlnkOver());
update();
}
return LayeredWidget::mousePressEvent(e); return LayeredWidget::mousePressEvent(e);
} }
void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) { void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateHover(); updateHover();
if (textlnkOver() && textlnkOver() == textlnkDown()) { if (ClickHandlerPtr activated = ClickHandler::unpressed()) {
Ui::hideLayer(); Ui::hideLayer();
textlnkOver()->onClick(e->button()); App::activateClickHandler(activated, e->button());
} }
textlnkDown(TextLinkPtr());
} }
void ConfirmBox::leaveEvent(QEvent *e) { void ConfirmBox::leaveEvent(QEvent *e) {
if (_myLink) { ClickHandler::clearActive(this);
if (textlnkOver() == _myLink) { }
textlnkOver(TextLinkPtr());
update(); void ConfirmBox::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
} setCursor(active ? style::cur_pointer : style::cur_default);
_myLink = TextLinkPtr(); update();
setCursor(style::cur_default); }
update();
} void ConfirmBox::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
update();
} }
void ConfirmBox::updateLink() { void ConfirmBox::updateLink() {
@ -119,17 +116,12 @@ void ConfirmBox::updateLink() {
void ConfirmBox::updateHover() { void ConfirmBox::updateHover() {
QPoint m(mapFromGlobal(_lastMousePos)); QPoint m(mapFromGlobal(_lastMousePos));
bool wasMy = (_myLink == textlnkOver());
textstyleSet(&st::boxTextStyle); 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(); textstyleRestore();
if (_myLink != textlnkOver()) {
if (wasMy || _myLink || rect().contains(m)) { ClickHandler::setActive(handler, this);
textlnkOver(_myLink);
}
setCursor(_myLink ? style::cur_pointer : style::cur_default);
update();
}
} }
void ConfirmBox::closePressed() { void ConfirmBox::closePressed() {
@ -174,22 +166,29 @@ void ConfirmBox::resizeEvent(QResizeEvent *e) {
_cancel.moveToRight(st::boxButtonPadding.right() + _confirm.width() + st::boxButtonPadding.left(), _confirm.y()); _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())); connect(this, SIGNAL(confirmed()), this, SLOT(onOpenLink()));
} }
void ConfirmLinkBox::onOpenLink() { void ConfirmLinkBox::onOpenLink() {
if (reMailStart().match(_url).hasMatch()) {
EmailLink(_url).onClick(Qt::LeftButton);
} else {
TextLink(_url).onClick(Qt::LeftButton);
}
Ui::hideLayer(); Ui::hideLayer();
UrlClickHandler::doOpen(_url);
} }
MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth) MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth)
, _close(this, lang(lng_box_ok), st::defaultBoxButton) , _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) , _link(link)
, _linkOver(false) , _linkOver(false)
, a_goodOpacity(0, 0) , a_goodOpacity(0, 0)
@ -212,7 +211,7 @@ void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
void MaxInviteBox::mousePressEvent(QMouseEvent *e) { void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e); mouseMoveEvent(e);
if (_linkOver) { if (_linkOver) {
App::app()->clipboard()->setText(_link); Application::clipboard()->setText(_link);
_goodTextLink = lang(lng_create_channel_link_copied); _goodTextLink = lang(lng_create_channel_link_copied);
a_goodOpacity = anim::fvalue(1, 0); a_goodOpacity = anim::fvalue(1, 0);
_a_good.start(); _a_good.start();
@ -279,3 +278,228 @@ void MaxInviteBox::resizeEvent(QResizeEvent *e) {
_close.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close.height()); _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); _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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
#include "abstractbox.h" #include "abstractbox.h"
class InformBox; class InformBox;
class ConfirmBox : public AbstractBox { class ConfirmBox : public AbstractBox, public ClickHandlerHost {
Q_OBJECT Q_OBJECT
public: public:
@ -38,6 +38,10 @@ public:
void leaveEvent(QEvent *e); void leaveEvent(QEvent *e);
void updateLink(); void updateLink();
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active);
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed);
public slots: public slots:
void onCancel(); void onCancel();
@ -69,7 +73,6 @@ private:
void updateHover(); void updateHover();
QPoint _lastMousePos; QPoint _lastMousePos;
TextLinkPtr _myLink;
BoxButton _confirm, _cancel; 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 { class ConfirmLinkBox : public ConfirmBox {
Q_OBJECT Q_OBJECT
@ -133,3 +153,100 @@ private:
anim::fvalue a_goodOpacity; anim::fvalue a_goodOpacity;
Animation _a_good; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -201,8 +201,10 @@ void ConnectionBox::onSave() {
} else { } else {
cSetConnectionType(dbictAuto); cSetConnectionType(dbictAuto);
cSetConnectionProxy(ConnectionProxy()); cSetConnectionProxy(ConnectionProxy());
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
QNetworkProxyFactory::setUseSystemConfiguration(false); QNetworkProxyFactory::setUseSystemConfiguration(false);
QNetworkProxyFactory::setUseSystemConfiguration(true); QNetworkProxyFactory::setUseSystemConfiguration(true);
#endif
} }
if (cPlatform() == dbipWindows && cTryIPv6() != _tryIPv6.checked()) { if (cPlatform() == dbipWindows && cTryIPv6() != _tryIPv6.checked()) {
cSetTryIPv6(_tryIPv6.checked()); cSetTryIPv6(_tryIPv6.checked());
@ -313,9 +315,11 @@ void AutoDownloadBox::onSave() {
bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups)); bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups));
cSetAutoDownloadAudio(autoDownloadAudio); cSetAutoDownloadAudio(autoDownloadAudio);
if (enabledPrivate || enabledGroups) { if (enabledPrivate || enabledGroups) {
const AudiosData &data(App::audiosData()); const DocumentsData &data(App::documentsData());
for (AudiosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) { for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged(); if (i.value()->voice()) {
i.value()->automaticLoadSettingsChanged();
}
} }
} }
changed = true; changed = true;
@ -328,7 +332,9 @@ void AutoDownloadBox::onSave() {
if (enabledPrivate || enabledGroups) { if (enabledPrivate || enabledGroups) {
const DocumentsData &data(App::documentsData()); const DocumentsData &data(App::documentsData());
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) { 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(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -33,6 +33,10 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "confirmbox.h" #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() ContactsInner::ContactsInner(CreatingGroupType creating) : TWidget()
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0) , _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
@ -224,7 +228,7 @@ void ContactsInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &old
void ContactsInner::onAddBot() { void ContactsInner::onAddBot() {
if (_bot->botInfo && !_bot->botInfo->startGroupToken.isEmpty()) { 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 { } else {
App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot)); App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot));
} }
@ -257,6 +261,18 @@ void ContactsInner::addAdminDone(const MTPUpdates &result, mtpRequestId req) {
if (req != _addAdminRequestId) return; if (req != _addAdminRequestId) return;
_addAdminRequestId = 0; _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(); if (_addAdminBox) _addAdminBox->onClose();
emit adminAdded(); emit adminAdded();
} }
@ -272,6 +288,8 @@ bool ContactsInner::addAdminFail(const RPCError &error, mtpRequestId req) {
Ui::showLayer(new MaxInviteBox(_channel->invitationUrl), KeepOtherLayers); Ui::showLayer(new MaxInviteBox(_channel->invitationUrl), KeepOtherLayers);
} else if (error.type() == "ADMINS_TOO_MUCH") { } else if (error.type() == "ADMINS_TOO_MUCH") {
Ui::showLayer(new InformBox(lang(lng_channel_admins_too_much)), KeepOtherLayers); 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 { } else {
emit adminAdded(); emit adminAdded();
} }
@ -350,7 +368,7 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) {
preloadFrom != _contacts->list.end && (_newItemHeight + preloadFrom->pos * _rowHeight) < yTo; preloadFrom != _contacts->list.end && (_newItemHeight + preloadFrom->pos * _rowHeight) < yTo;
preloadFrom = preloadFrom->next preloadFrom = preloadFrom->next
) { ) {
preloadFrom->history->peer->photo->load(); preloadFrom->history->peer->loadUserpic();
} }
} }
} else if (!_filtered.isEmpty()) { } else if (!_filtered.isEmpty()) {
@ -361,7 +379,7 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) {
if (to > _filtered.size()) to = _filtered.size(); if (to > _filtered.size()) to = _filtered.size();
for (; from < to; ++from) { 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; sel = false;
} }
} else { } else {
if (data->inchat || data->check || selectedCount() >= ((_channel && _channel->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())) { if (data->inchat || data->check || selectedCount() >= Global::MegagroupSizeMax()) {
sel = false; sel = false;
} }
} }
p.fillRect(0, 0, width(), _rowHeight, inverse ? st::contactsBgActive : (sel ? st::contactsBgOver : st::white)); p.fillRect(0, 0, width(), _rowHeight, inverse ? st::contactsBgActive : (sel ? st::contactsBgOver : st::white));
p.setPen(inverse ? st::white : st::black); 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 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int32 iconw = (_chat || _creating != CreatingGroupNone) ? (st::contactsCheckPosition.x() * 2 + st::contactsCheckIcon.pxWidth()) : 0; 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; data->check = false;
_checkedContacts.remove(peer); _checkedContacts.remove(peer);
--_selCount; --_selCount;
} else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())) { } else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
data->check = true; data->check = true;
_checkedContacts.insert(peer, true); _checkedContacts.insert(peer, true);
++_selCount; ++_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(); if (cnt != _selCount) emit chosenChanged();
} }
@ -1535,7 +1557,7 @@ void ContactsBox::paintEvent(QPaintEvent *e) {
paintTitle(p, lang(lng_channel_admins)); paintTitle(p, lang(lng_channel_admins));
} else if (_inner.chat() || _inner.creating() != CreatingGroupNone) { } else if (_inner.chat() || _inner.creating() != CreatingGroupNone) {
QString title(lang(addingAdmin ? lng_channel_add_admin : lng_profile_add_participant)); 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); paintTitle(p, title, additional);
} else if (_inner.bot()) { } else if (_inner.bot()) {
paintTitle(p, lang(lng_bot_choose_group)); paintTitle(p, lang(lng_bot_choose_group));
@ -1652,12 +1674,15 @@ void ContactsBox::getAdminsDone(const MTPmessages_ChatFull &result) {
} }
} }
_saveRequestId = 0; _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) { for_const (UserData *user, appoint) {
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); 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(); _saveRequestId = curadmins.size() + appoint.size();
if (!_saveRequestId) { if (!_saveRequestId) {
onClose(); onClose();
@ -1669,7 +1694,7 @@ void ContactsBox::setAdminDone(UserData *user, const MTPBool &result) {
if (_inner.chat()->noParticipantInfo()) { if (_inner.chat()->noParticipantInfo()) {
App::api()->requestFullPeer(_inner.chat()); App::api()->requestFullPeer(_inner.chat());
} else { } else {
_inner.chat()->admins.insert(user, true); _inner.chat()->admins.insert(user);
} }
} }
--_saveRequestId; --_saveRequestId;
@ -1704,7 +1729,13 @@ bool ContactsBox::editAdminFail(const RPCError &error) {
if (mtpIsFlood(error)) return true; if (mtpIsFlood(error)) return true;
--_saveRequestId; --_saveRequestId;
_inner.chat()->invalidateParticipants(); _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; return false;
} }
@ -1749,7 +1780,10 @@ bool ContactsBox::creationFail(const RPCError &error) {
_filter.showError(); _filter.showError();
return true; return true;
} else if (error.type() == "PEER_FLOOD") { } 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 true;
} }
return false; return false;
@ -1757,7 +1791,7 @@ bool ContactsBox::creationFail(const RPCError &error) {
MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget() MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget()
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _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) , _newItemSel(false)
, _channel(channel) , _channel(channel)
, _filter(filter) , _filter(filter)
@ -1787,7 +1821,7 @@ MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget
void MembersInner::load() { void MembersInner::load() {
if (!_loadingRequestId) { 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); paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown);
p.translate(0, _rowHeight); 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); p.setPen(st::stickersReorderFg);
_about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center); _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(); UserData *user = peer->asUser();
p.fillRect(0, 0, width(), _rowHeight, (sel ? st::contactsBgOver : st::white)->b); 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); p.setPen(st::black);
@ -1980,7 +2014,7 @@ void MembersInner::loadProfilePhotos(int32 yFrom) {
if (to > _rows.size()) to = _rows.size(); if (to > _rows.size()) to = _rows.size();
for (; from < to; ++from) { for (; from < to; ++from) {
_rows[from]->photo->load(); _rows[from]->loadUserpic();
} }
} }
} }
@ -2005,7 +2039,7 @@ void MembersInner::refresh() {
} else { } else {
_about.setText(st::boxTextFont, lng_channel_only_last_shown(lt_count, _rows.size())); _about.setText(st::boxTextFont, lng_channel_only_last_shown(lt_count, _rows.size()));
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); _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; _aboutHeight = 0;
} }
resize(width(), st::membersPadding.top() + _newItemHeight + _rows.size() * _rowHeight + st::membersPadding.bottom() + _aboutHeight); 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); _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()) { if (_rows.isEmpty()) {
_rows.push_back(App::self()); _rows.push_back(App::self());
@ -2297,7 +2341,7 @@ void MembersBox::onScroll() {
} }
void MembersBox::onAdd() { 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); Ui::showLayer(new MaxInviteBox(_inner.channel()->invitationUrl), KeepOtherLayers);
return; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -28,6 +28,8 @@ enum MembersFilter {
}; };
typedef QMap<UserData*, bool> MembersAlreadyIn; typedef QMap<UserData*, bool> MembersAlreadyIn;
QString cantInviteError();
class ConfirmBox; class ConfirmBox;
class ContactsInner : public TWidget, public RPCSender { class ContactsInner : public TWidget, public RPCSender {
Q_OBJECT 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -46,12 +46,12 @@ _close(this, lang(lng_box_ok), st::defaultBoxButton) {
for (int32 i = 0; i < languageCount; ++i) { for (int32 i = 0; i < languageCount; ++i) {
LangLoaderResult result; LangLoaderResult result;
if (i) { 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(); result = loader.found();
} else { } else {
result.insert(lng_language_name, langOriginal(lng_language_name)); 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); _langs.back()->move(st::boxPadding.left() + st::boxOptionListPadding.left(), y);
y += _langs.back()->height() + st::boxOptionListPadding.top(); y += _langs.back()->height() + st::boxOptionListPadding.top();
connect(_langs.back(), SIGNAL(changed()), this, SLOT(onChange())); connect(_langs.back(), SIGNAL(changed()), this, SLOT(onChange()));
@ -82,14 +82,14 @@ void LanguageBox::showAll() {
void LanguageBox::mousePressEvent(QMouseEvent *e) { void LanguageBox::mousePressEvent(QMouseEvent *e) {
if ((e->modifiers() & Qt::CTRL) && (e->modifiers() & Qt::ALT) && (e->modifiers() & Qt::SHIFT)) { if ((e->modifiers() & Qt::CTRL) && (e->modifiers() & Qt::ALT) && (e->modifiers() & Qt::SHIFT)) {
for (int32 i = 1; i < languageCount; ++i) { 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()) { 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; return;
} else if (!loader.warnings().isEmpty()) { } else if (!loader.warnings().isEmpty()) {
QString warn = loader.warnings(); QString warn = loader.warnings();
if (warn.size() > 256) warn = warn.mid(0, 254) + qsl(".."); if (warn.size() > 256) warn = warn.mid(0, 253) + qsl("...");
Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i] + qsl("\" warnings :(\n\nWarnings: ") + warn)); Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i].c_str() + qsl("\" warnings :(\n\nWarnings: ") + warn));
return; return;
} }
} }
@ -112,7 +112,7 @@ void LanguageBox::onChange() {
if (_langs[i]->checked() && langId != cLang()) { if (_langs[i]->checked() && langId != cLang()) {
LangLoaderResult result; LangLoaderResult result;
if (langId > 0) { 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(); result = loader.found();
} else if (langId == languageTest) { } else if (langId == languageTest) {
LangLoaderPlain loader(cLangFile(), LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok)); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -400,12 +400,12 @@ void PasscodeBox::onSave(bool force) {
if (!_oldPasscode.isHidden()) { if (!_oldPasscode.isHidden()) {
hashSha256(oldPasswordData.constData(), oldPasswordData.size(), oldPasswordHash.data()); 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()) { 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))); 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_string(oldPasswordHash), settings), rpcDone(&PasscodeBox::setPasswordDone), rpcFail(&PasscodeBox::setPasswordFail)); _setRequest = MTP::send(MTPaccount_UpdatePasswordSettings(MTP_bytes(oldPasswordHash), settings), rpcDone(&PasscodeBox::setPasswordDone), rpcFail(&PasscodeBox::setPasswordFail));
} }
} else { } else {
cSetPasscodeBadTries(0); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "style.h" #include "gui/style.h"
#include "lang.h" #include "lang.h"
#include "application.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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "style.h" #include "gui/style.h"
#include "lang.h" #include "lang.h"
#include "localstorage.h" #include "localstorage.h"
@ -69,8 +69,8 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
if (_animated) { if (_animated) {
int32 limitW = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); int32 limitW = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
int32 limitH = st::confirmMaxHeight; int32 limitH = st::confirmMaxHeight;
maxW = dimensions.width(); maxW = qMax(dimensions.width(), 1);
maxH = dimensions.height(); maxH = qMax(dimensions.height(), 1);
if (maxW * limitH > maxH * limitW) { if (maxW * limitH > maxH * limitW) {
if (maxW < limitW) { if (maxW < limitW) {
maxH = maxH * limitW / maxW; maxH = maxH * limitW / maxW;
@ -82,7 +82,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
maxH = limitH; 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 { } else {
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) { for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
if (i->width() >= maxW && i->height() >= maxH) { if (i->width() >= maxW && i->height() >= maxH) {
@ -124,7 +124,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
} else { } else {
_thumbw = st::msgFileThumbSize; _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); _name.setText(st::semiboldFont, _file->filename, _textNameOptions);
@ -274,7 +274,7 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
p.drawSpriteCenter(inner, _isImage ? st::msgFileOutImage : st::msgFileOutFile); p.drawSpriteCenter(inner, _isImage ? st::msgFileOutImage : st::msgFileOutFile);
} else { } 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.setFont(st::semiboldFont);
p.setPen(st::black); p.setPen(st::black);
@ -359,3 +359,330 @@ void PhotoSendBox::onSend(bool ctrlShiftEnter) {
_confirmed = true; _confirmed = true;
onClose(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -42,11 +42,6 @@ public:
} }
} }
signals:
void confirmed();
void cancelled();
public slots: public slots:
void onCompressedChange(); void onCompressedChange();
@ -87,3 +82,57 @@ private:
bool _confirmed; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -29,9 +29,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "localstorage.h" #include "localstorage.h"
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget()
_loaded(false), _setId(0), _setAccess(0), _setCount(0), _setHash(0), _setFlags(0), _bottom(0), , _loaded(false)
_input(set), _installRequest(0) { , _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())); connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
switch (set.type()) { switch (set.type()) {
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break; 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)); MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&StickerSetInner::gotSet), rpcFail(&StickerSetInner::failedSet));
App::main()->updateStickers(); App::main()->updateStickers();
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
} }
void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_pack.clear(); _pack.clear();
_emoji.clear();
if (set.type() == mtpc_messages_stickerSet) { if (set.type() == mtpc_messages_stickerSet) {
const MTPDmessages_stickerSet &d(set.c_messages_stickerSet()); const MTPDmessages_stickerSet &d(set.c_messages_stickerSet());
const QVector<MTPDocument> &v(d.vdocuments.c_vector().v); const QVector<MTPDocument> &v(d.vdocuments.c_vector().v);
@ -53,6 +65,23 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_pack.push_back(doc); _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) { if (d.vset.type() == mtpc_stickerSet) {
const MTPDstickerSet &s(d.vset.c_stickerSet()); const MTPDstickerSet &s(d.vset.c_stickerSet());
_setTitle = stickerSetTitle(s); _setTitle = stickerSetTitle(s);
@ -88,12 +117,17 @@ bool StickerSetInner::failedSet(const RPCError &error) {
} }
void StickerSetInner::installDone(const MTPBool &result) { void StickerSetInner::installDone(const MTPBool &result) {
StickerSets &sets(cRefStickerSets()); Stickers::Sets &sets(Global::RefStickerSets());
_setFlags &= ~MTPDstickerSet::flag_disabled; _setFlags &= ~MTPDstickerSet::Flag::f_disabled;
sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)).value().stickers = _pack; 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); int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId);
if (currentIndex != insertAtIndex) { if (currentIndex != insertAtIndex) {
if (currentIndex > 0) { if (currentIndex > 0) {
@ -102,7 +136,7 @@ void StickerSetInner::installDone(const MTPBool &result) {
order.insert(insertAtIndex, _setId); order.insert(insertAtIndex, _setId);
} }
StickerSets::iterator custom = sets.find(CustomStickerSetId); auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) { if (custom != sets.cend()) {
for (int32 i = 0, l = _pack.size(); i < l; ++i) { for (int32 i = 0, l = _pack.size(); i < l; ++i) {
int32 removeIndex = custom->stickers.indexOf(_pack.at(i)); int32 removeIndex = custom->stickers.indexOf(_pack.at(i));
@ -125,6 +159,47 @@ bool StickerSetInner::installFailed(const RPCError &error) {
return true; 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) { void StickerSetInner::paintEvent(QPaintEvent *e) {
QRect r(e->rect()); QRect r(e->rect());
Painter p(this); Painter p(this);
@ -149,12 +224,8 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
if (doc->status == FileReady) { if (doc->status == FileReady) {
doc->automaticLoad(0); doc->automaticLoad(0);
} }
if (doc->sticker()->img->isNull() && doc->loaded() && doc->loaded(true)) { if (doc->sticker()->img->isNull() && doc->loaded(DocumentData::FilePathResolveChecked)) {
if (doc->data().isEmpty()) { doc->sticker()->img = doc->data().isEmpty() ? ImagePtr(doc->filepath()) : ImagePtr(doc->data());
doc->sticker()->img = ImagePtr(doc->already());
} else {
doc->sticker()->img = ImagePtr(doc->data());
}
} }
} }
@ -185,8 +256,8 @@ bool StickerSetInner::loaded() const {
int32 StickerSetInner::notInstalled() const { int32 StickerSetInner::notInstalled() const {
if (!_loaded) return 0; if (!_loaded) return 0;
StickerSets::const_iterator it = cStickerSets().constFind(_setId); auto it = Global::StickerSets().constFind(_setId);
if (it == cStickerSets().cend() || (it->flags & MTPDstickerSet::flag_disabled)) return _pack.size(); if (it == Global::StickerSets().cend() || (it->flags & MTPDstickerSet::Flag::f_disabled)) return _pack.size();
return 0; 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); int32 namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x() - qMax(qMax(_returnWidth, _removeWidth), _restoreWidth);
clear(); clear();
const StickerSetsOrder &order(cStickerSetsOrder()); const Stickers::Order &order(Global::StickerSetsOrder());
_animStartTimes.reserve(order.size()); _animStartTimes.reserve(order.size());
const StickerSets &sets(cStickerSets()); const Stickers::Sets &sets(Global::StickerSets());
for (int32 i = 0, l = order.size(); i < l; ++i) { for (int i = 0, l = order.size(); i < l; ++i) {
StickerSets::const_iterator it = sets.constFind(order.at(i)); auto it = sets.constFind(order.at(i));
if (it != sets.cend()) { 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); DocumentData *sticker = it->stickers.isEmpty() ? 0 : it->stickers.at(0);
int32 pixw = 0, pixh = 0; int32 pixw = 0, pixh = 0;
@ -643,10 +714,10 @@ void StickersInner::rebuild() {
if (titleWidth > namew) { if (titleWidth > namew) {
title = st::contactsNameFont->elided(title, 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)); (disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, official, disabled, pixw, pixh));
_animStartTimes.push_back(0); _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); App::api()->scheduleStickerSetRequest(it->id, it->access);
} }
} }
@ -661,8 +732,8 @@ QVector<uint64> StickersInner::getOrder() const {
result.reserve(_rows.size()); result.reserve(_rows.size());
for (int32 i = 0, l = _rows.size(); i < l; ++i) { for (int32 i = 0, l = _rows.size(); i < l; ++i) {
if (_rows.at(i)->disabled) { if (_rows.at(i)->disabled) {
StickerSets::const_iterator it = cStickerSets().constFind(_rows.at(i)->id); auto it = Global::StickerSets().constFind(_rows.at(i)->id);
if (it == cStickerSets().cend() || !(it->flags & MTPDstickerSet::flag_official)) { if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_official)) {
continue; continue;
} }
} }
@ -704,6 +775,7 @@ StickersBox::StickersBox() : ItemListBox(st::boxScroll)
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated())); connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated()));
App::main()->updateStickers();
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
@ -761,7 +833,7 @@ void StickersBox::reorderDone(const MTPBool &result) {
bool StickersBox::reorderFail(const RPCError &result) { bool StickersBox::reorderFail(const RPCError &result) {
if (mtpIsFlood(result)) return false; if (mtpIsFlood(result)) return false;
_reorderRequest = 0; _reorderRequest = 0;
cSetLastStickersUpdate(0); Global::SetLastStickersUpdate(0);
App::main()->updateStickers(); App::main()->updateStickers();
onClose(); onClose();
return true; return true;
@ -785,12 +857,12 @@ void StickersBox::closePressed() {
MTP::cancel(i.key()); MTP::cancel(i.key());
} }
_disenableRequests.clear(); _disenableRequests.clear();
cSetLastStickersUpdate(0); Global::SetLastStickersUpdate(0);
App::main()->updateStickers(); App::main()->updateStickers();
} else if (_reorderRequest) { } else if (_reorderRequest) {
MTP::cancel(_reorderRequest); MTP::cancel(_reorderRequest);
_reorderRequest = 0; _reorderRequest = 0;
cSetLastStickersUpdate(0); Global::SetLastStickersUpdate(0);
App::main()->updateStickers(); App::main()->updateStickers();
} }
} }
@ -842,11 +914,11 @@ void StickersBox::onSave() {
bool writeRecent = false; bool writeRecent = false;
RecentStickerPack &recent(cGetRecentStickers()); RecentStickerPack &recent(cGetRecentStickers());
StickerSets &sets(cRefStickerSets()); Stickers::Sets &sets(Global::RefStickerSets());
QVector<uint64> reorder = _inner.getOrder(), disabled = _inner.getDisabledSets(); QVector<uint64> reorder = _inner.getOrder(), disabled = _inner.getDisabledSets();
for (int32 i = 0, l = disabled.size(); i < l; ++i) { 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()) { if (it != sets.cend()) {
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) { for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) { if (it->stickers.indexOf(i->first) >= 0) {
@ -856,35 +928,35 @@ void StickersBox::onSave() {
++i; ++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)); 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()); _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 { } else {
_disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); _disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType());
int32 removeIndex = cStickerSetsOrder().indexOf(it->id); int removeIndex = Global::StickerSetsOrder().indexOf(it->id);
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex);
sets.erase(it); sets.erase(it);
} }
} }
} }
} }
StickerSetsOrder &order(cRefStickerSetsOrder()); Stickers::Order &order(Global::RefStickerSetsOrder());
order.clear(); order.clear();
for (int32 i = 0, l = reorder.size(); i < l; ++i) { for (int i = 0, l = reorder.size(); i < l; ++i) {
StickerSets::iterator it = sets.find(reorder.at(i)); auto it = sets.find(reorder.at(i));
if (it != sets.cend()) { 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)); 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()); _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)); order.push_back(reorder.at(i));
} }
} }
for (StickerSets::iterator it = sets.begin(); it != sets.cend();) { for (auto it = sets.begin(); it != sets.cend();) {
if (it->id == CustomStickerSetId || it->id == RecentStickerSetId || order.contains(it->id)) { if (it->id == Stickers::CustomSetId || it->id == Stickers::RecentSetId || order.contains(it->id)) {
++it; ++it;
} else { } else {
it = sets.erase(it); it = sets.erase(it);
@ -920,12 +992,12 @@ void StickersBox::showAll() {
int32 stickerPacksCount(bool includeDisabledOfficial) { int32 stickerPacksCount(bool includeDisabledOfficial) {
int32 result = 0; int32 result = 0;
const StickerSetsOrder &order(cStickerSetsOrder()); const Stickers::Order &order(Global::StickerSetsOrder());
const StickerSets &sets(cStickerSets()); const Stickers::Sets &sets(Global::StickerSets());
for (int32 i = 0, l = order.size(); i < l; ++i) { for (int i = 0, l = order.size(); i < l; ++i) {
StickerSets::const_iterator it = sets.constFind(order.at(i)); auto it = sets.constFind(order.at(i));
if (it != sets.cend()) { 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; ++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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -29,7 +29,9 @@ public:
StickerSetInner(const MTPInputStickerSet &set); StickerSetInner(const MTPInputStickerSet &set);
void init(); void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
@ -42,10 +44,12 @@ public:
void setScrollBottom(int32 bottom); void setScrollBottom(int32 bottom);
void install(); void install();
QString getTitle() const;
~StickerSetInner(); ~StickerSetInner();
public slots:
void onPreview();
signals: signals:
void updateButtons(); void updateButtons();
@ -53,6 +57,8 @@ signals:
private: private:
int32 stickerFromGlobalPos(const QPoint &p) const;
void gotSet(const MTPmessages_StickerSet &set); void gotSet(const MTPmessages_StickerSet &set);
bool failedSet(const RPCError &error); bool failedSet(const RPCError &error);
@ -60,15 +66,20 @@ private:
bool installFailed(const RPCError &error); bool installFailed(const RPCError &error);
StickerPack _pack; StickerPack _pack;
StickersByEmojiMap _emoji;
bool _loaded; bool _loaded;
uint64 _setId, _setAccess; uint64 _setId, _setAccess;
QString _title, _setTitle, _setShortName; QString _title, _setTitle, _setShortName;
int32 _setCount, _setHash, _setFlags; int32 _setCount, _setHash;
MTPDstickerSet::Flags _setFlags;
int32 _bottom; int32 _bottom;
MTPInputStickerSet _input; MTPInputStickerSet _input;
mtpRequestId _installRequest; mtpRequestId _installRequest;
QTimer _previewTimer;
int32 _previewShown;
}; };
class StickerSetBox : public ScrollableBox, public RPCSender { 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "lang.h" #include "lang.h"
@ -160,7 +160,7 @@ void UsernameBox::onChanged() {
} }
_checkTimer.stop(); _checkTimer.stop();
} else { } else {
int32 i, len = name.size(); int32 len = name.size();
for (int32 i = 0; i < len; ++i) { for (int32 i = 0; i < len; ++i) {
QChar ch = name.at(i); QChar ch = name.at(i);
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_' && (ch != '@' || i > 0)) { 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() { 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); _copiedTextLink = lang(lng_username_copied);
update(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
static const int32 AppVersion = 9017; static const int32 AppVersion = 9040;
static const wchar_t *AppVersionStr = L"0.9.17"; static const wchar_t *AppVersionStr = L"0.9.40";
static const bool DevVersion = false; 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 *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop"; static const wchar_t *AppName = L"Telegram Desktop";
@ -51,11 +51,11 @@ enum {
MTPIPv4ConnectionWaitTimeout = 1000, // 1 seconds waiting for ipv4, until we accept ipv6 MTPIPv4ConnectionWaitTimeout = 1000, // 1 seconds waiting for ipv4, until we accept ipv6
MTPMillerRabinIterCount = 30, // 30 Miller-Rabin iterations for dh_prime primality check MTPMillerRabinIterCount = 30, // 30 Miller-Rabin iterations for dh_prime primality check
MTPUploadSessionsCount = 4, // max 4 upload sessions is created MTPUploadSessionsCount = 2, // max 2 upload sessions is created
MTPDownloadSessionsCount = 4, // max 4 download sessions is created MTPDownloadSessionsCount = 2, // max 2 download sessions is created
MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill 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 MTPDebugBufferSize = 1024 * 1024, // 1 mb start size
@ -101,6 +101,9 @@ enum {
MediaOverviewStartPerPage = 5, MediaOverviewStartPerPage = 5,
MediaOverviewPreloadCount = 4, MediaOverviewPreloadCount = 4,
// a new message from the same sender is attached to previous within 15 minutes
AttachMessageToPreviousSecondsDelta = 900,
AudioVoiceMsgSimultaneously = 4, AudioVoiceMsgSimultaneously = 4,
AudioSongSimultaneously = 4, AudioSongSimultaneously = 4,
AudioCheckPositionTimeout = 100, // 100ms per check audio pos 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 AudioVoiceMsgInMemory = 2 * 1024 * 1024, // 2 Mb audio is hold in memory and auto loaded
AudioPauseDeviceTimeout = 3000, // pause in 3 secs after playing is over 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 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 StickerMaxSize = 2048, // 2048x2048 is a max image size for sticker
@ -127,12 +132,13 @@ enum {
MaxZoomLevel = 7, // x8 MaxZoomLevel = 7, // x8
ZoomToScreenLevel = 1024, // just constant 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 PreloadHeightsCount = 3, // when 3 screens to scroll left make a preload request
EmojiPanPerRow = 7, EmojiPanPerRow = 7,
EmojiPanRowsPerPage = 6, EmojiPanRowsPerPage = 6,
StickerPanPerRow = 5, StickerPanPerRow = 5,
StickerPanRowsPerPage = 4, StickerPanRowsPerPage = 4,
SavedGifsMaxPerRow = 4,
StickersUpdateTimeout = 3600000, // update not more than once in an hour StickersUpdateTimeout = 3600000, // update not more than once in an hour
SearchPeopleLimit = 5, SearchPeopleLimit = 5,
@ -140,9 +146,9 @@ enum {
MaxUsernameLength = 32, MaxUsernameLength = 32,
UsernameCheckTimeout = 200, UsernameCheckTimeout = 200,
MaxChannelDescription = 120, MaxChannelDescription = 255,
MaxGroupChannelTitle = 255, MaxGroupChannelTitle = 255,
MaxPhotoCaption = 140, MaxPhotoCaption = 200,
MaxMessageSize = 4096, MaxMessageSize = 4096,
MaxHttpRedirects = 5, // when getting external data/images 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 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 ReloadChannelMembersTimeout = 1000, // 1 second wait before reload members in channel after adding
PinnedMessageTextLimit = 16,
}; };
inline bool isNotificationsUser(uint64 id) { inline bool isNotificationsUser(uint64 id) {
@ -191,7 +199,7 @@ inline const char *cGUIDStr() {
return gGuidStr; return gGuidStr;
} }
inline const char **cPublicRSAKeys(uint32 &cnt) { inline const char **cPublicRSAKeys(int &keysCount) {
static const char *(keys[]) = {"\ static const char *(keys[]) = {"\
-----BEGIN RSA PUBLIC KEY-----\n\ -----BEGIN RSA PUBLIC KEY-----\n\
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n\ MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n\
@ -201,7 +209,7 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n\
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\ 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\
-----END RSA PUBLIC KEY-----"}; -----END RSA PUBLIC KEY-----"};
cnt = sizeof(keys) / sizeof(const char*); keysCount = arraysize(keys);
return 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "style.h" #include "gui/style.h"
#include "lang.h" #include "lang.h"
#include "application.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); History *history = App::history(peer->id);
if (peer->migrateTo()) { PeerData *userpicPeer = (peer->migrateTo() ? peer->migrateTo() : peer);
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, peer->migrateTo()->photo->pix(st::dlgPhotoSize)); userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth());
} else {
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, peer->photo->pix(st::dlgPhotoSize));
}
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
int32 namewidth = w - nameleft - st::dlgPaddingHor; int32 namewidth = w - nameleft - st::dlgPaddingHor;
QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height); QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
// draw chat icon // 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)); 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); rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
} else if (peer->isChannel()) { } else if (peer->isChannel()) {
@ -299,7 +296,7 @@ void DialogsInner::searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) c
p.fillRect(fullRect, st::dlgBG->b); p.fillRect(fullRect, st::dlgBG->b);
if (onlyBackground) return; 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 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
int32 namewidth = w - nameleft - st::dlgPaddingHor * 2 - st::btnCancelSearch.width; 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) { void DialogsInner::createDialog(History *history) {
bool creating = history->dialogs.isEmpty(); bool creating = !history->inChatList();
if (creating) { if (creating) {
history->dialogs = dialogs.addToEnd(history); DialogRow *mainRow = history->addToChatList(dialogs);
contactsNoDialogs.del(history->peer, history->dialogs[0]); contactsNoDialogs.del(history->peer, mainRow);
} }
RefPair(int32, movedFrom, int32, movedTo) = history->adjustByPosInChatsList(dialogs);
History::DialogLinks links = history->dialogs;
int32 movedFrom = links[0]->pos * st::dlgHeight;
dialogs.adjustByPos(links);
int32 movedTo = links[0]->pos * st::dlgHeight;
emit dialogMoved(movedFrom, movedTo); emit dialogMoved(movedFrom, movedTo);
@ -471,8 +464,7 @@ void DialogsInner::removeDialog(History *history) {
if (sel && sel->history == history) { if (sel && sel->history == history) {
sel = 0; sel = 0;
} }
dialogs.del(history->peer); history->removeFromChatList(dialogs);
history->dialogs = History::DialogLinks();
history->clearNotifications(); history->clearNotifications();
if (App::wnd()) App::wnd()->notifyClear(history); if (App::wnd()) App::wnd()->notifyClear(history);
if (contacts.list.rowByPeer.constFind(history->peer->id) != contacts.list.rowByPeer.cend()) { 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 (_state == DefaultState) {
if (peer) { if (peer) {
if (History *h = App::historyLoaded(peer->id)) { if (History *h = App::historyLoaded(peer->id)) {
if (h->dialogs.contains(0)) { if (h->inChatList()) {
update(0, h->dialogs.value(0)->pos * st::dlgHeight, fullWidth(), st::dlgHeight); update(0, h->posInChatList() * st::dlgHeight, fullWidth(), st::dlgHeight);
} }
} }
} else if (sel) { } else if (sel) {
@ -624,7 +616,7 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) {
if (_menuPeer->isUser()) { if (_menuPeer->isUser()) {
_menu->addAction(lang(lng_profile_clear_history), this, SLOT(onContextClearHistory()))->setEnabled(true); _menu->addAction(lang(lng_profile_clear_history), this, SLOT(onContextClearHistory()))->setEnabled(true);
_menu->addAction(lang(lng_profile_delete_conversation), this, SLOT(onContextDeleteAndLeave()))->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); _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*))); connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData*)));
} }
@ -651,7 +643,7 @@ void DialogsInner::onContextProfile() {
void DialogsInner::onContextToggleNotifications() { void DialogsInner::onContextToggleNotifications() {
if (!_menuPeer) return; if (!_menuPeer) return;
App::main()->updateNotifySetting(_menuPeer, menuPeerMuted()); App::main()->updateNotifySetting(_menuPeer, menuPeerMuted() ? NotifySettingSetNotify : NotifySettingSetMuted);
} }
void DialogsInner::onContextSearch() { void DialogsInner::onContextSearch() {
@ -963,7 +955,9 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) {
case mtpc_dialog: { case mtpc_dialog: {
const MTPDdialog &d(i->c_dialog()); const MTPDdialog &d(i->c_dialog());
history = App::historyFromDialog(peerFromMTP(d.vpeer), d.vunread_count.v, d.vread_inbox_max_id.v); 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; } break;
case mtpc_dialogChannel: { 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) { if (!history->isMegagroup() && d.vtop_message.v > d.vtop_important_message.v) {
history->setNotLoadedAtBottom(); 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; } break;
} }
@ -1015,7 +1011,7 @@ void DialogsInner::addSavedPeersAfter(const QDateTime &date) {
SavedPeersByTime &saved(cRefSavedPeersByTime()); SavedPeersByTime &saved(cRefSavedPeersByTime());
while (!saved.isEmpty() && (date.isNull() || date < saved.lastKey())) { while (!saved.isEmpty() && (date.isNull() || date < saved.lastKey())) {
History *history = App::history(saved.last()->id); History *history = App::history(saved.last()->id);
history->setPosInDialogsDate(saved.lastKey()); history->setChatsListDate(saved.lastKey());
contactsNoDialogs.del(history->peer); contactsNoDialogs.del(history->peer);
saved.remove(saved.lastKey(), saved.last()); saved.remove(saved.lastKey(), saved.last());
} }
@ -1040,13 +1036,16 @@ bool DialogsInner::searchReceived(const QVector<MTPMessage> &messages, DialogsSe
_lastSearchDate = lastDateFound; _lastSearchDate = lastDateFound;
} }
} }
if (type == DialogsSearchFromStart || type == DialogsSearchFromOffset) { if (item) {
_lastSearchPeer = item->history()->peer; if (type == DialogsSearchFromStart || type == DialogsSearchFromOffset) {
_lastSearchPeer = item->history()->peer;
}
} }
MsgId msgId = item ? item->id : idFromMessage(*i);
if (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset) { if (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset) {
_lastSearchMigratedId = item->id; _lastSearchMigratedId = msgId;
} else { } else {
_lastSearchId = item->id; _lastSearchId = msgId;
} }
} }
if (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset) { if (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset) {
@ -1067,8 +1066,11 @@ void DialogsInner::peopleReceived(const QString &query, const QVector<MTPPeer> &
_peopleResults.reserve(people.size()); _peopleResults.reserve(people.size());
for (QVector<MTPPeer>::const_iterator i = people.cbegin(), e = people.cend(); i != e; ++i) { for (QVector<MTPPeer>::const_iterator i = people.cbegin(), e = people.cend(); i != e; ++i) {
PeerId peerId = peerFromMTP(*i); PeerId peerId = peerFromMTP(*i);
History *h = App::historyLoaded(peerId); if (History *h = App::historyLoaded(peerId)) {
if (h && !h->dialogs.isEmpty()) continue; // skip dialogs if (h->inChatList()) {
continue; // skip existing chats
}
}
_peopleResults.push_back(App::peer(peerId)); _peopleResults.push_back(App::peer(peerId));
} }
@ -1359,6 +1361,8 @@ void DialogsInner::selectSkipPage(int32 pixels, int32 direction) {
} }
void DialogsInner::loadPeerPhotos(int32 yFrom) { void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (!parentWidget()) return;
int32 yTo = yFrom + parentWidget()->height() * 5; int32 yTo = yFrom + parentWidget()->height() * 5;
MTP::clearLoaderPriorities(); MTP::clearLoaderPriorities();
if (_state == DefaultState) { if (_state == DefaultState) {
@ -1366,7 +1370,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (yFrom < otherStart) { if (yFrom < otherStart) {
dialogs.list.adjustCurrent(yFrom, st::dlgHeight); dialogs.list.adjustCurrent(yFrom, st::dlgHeight);
for (DialogRow *row = dialogs.list.current; row != dialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) { 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; yFrom = 0;
} else { } else {
@ -1376,7 +1380,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (yTo > 0) { if (yTo > 0) {
contactsNoDialogs.list.adjustCurrent(yFrom, st::dlgHeight); contactsNoDialogs.list.adjustCurrent(yFrom, st::dlgHeight);
for (DialogRow *row = contactsNoDialogs.list.current; row != contactsNoDialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) { 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) { } else if (_state == FilteredState || _state == SearchedState) {
@ -1387,7 +1391,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
if (to > _filterResults.size()) to = _filterResults.size(); if (to > _filterResults.size()) to = _filterResults.size();
for (; from < to; ++from) { 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(); if (to > _peopleResults.size()) to = _peopleResults.size();
for (; from < to; ++from) { 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(); 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(); if (to > _searchResults.size()) to = _searchResults.size();
for (; from < to; ++from) { 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 { void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
if (!inPeer) {
outPeer = 0;
outMsg = 0;
return;
}
if (_state == DefaultState) { if (_state == DefaultState) {
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id); DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id);
if (i == dialogs.list.rowByPeer.constEnd()) { 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 { void DialogsInner::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
if (!inPeer) {
outPeer = 0;
outMsg = 0;
return;
}
if (_state == DefaultState) { if (_state == DefaultState) {
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id); DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id);
if (i == dialogs.list.rowByPeer.constEnd()) { if (i == dialogs.list.rowByPeer.constEnd()) {
@ -1777,11 +1791,11 @@ void DialogsWidget::activate() {
} }
void DialogsWidget::createDialog(History *history) { void DialogsWidget::createDialog(History *history) {
bool creating = history->dialogs.isEmpty(); bool creating = !history->inChatList();
_inner.createDialog(history); _inner.createDialog(history);
if (creating && history->peer->migrateFrom()) { if (creating && history->peer->migrateFrom()) {
if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) { if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) {
if (!h->dialogs.isEmpty()) { if (h->inChatList()) {
removeDialog(h); removeDialog(h);
} }
} }
@ -2038,8 +2052,11 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
MTP::cancel(_searchRequest); MTP::cancel(_searchRequest);
} }
if (_searchInPeer) { if (_searchInPeer) {
int32 flags = (_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) ? MTPmessages_Search::flag_important_only : 0; MTPmessages_Search::Flags flags = 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)); 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 { } 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)); _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) { void DialogsWidget::searchMessages(const QString &query, PeerData *inPeer) {
if ((_filter.getLastText() != query) || (inPeer && inPeer != _searchInPeer && inPeer->migrateTo() != _searchInPeer)) { if ((_filter.getLastText() != query) || (inPeer && inPeer != _searchInPeer && inPeer->migrateTo() != _searchInPeer)) {
if (inPeer) { if (inPeer) {
onCancelSearch();
_searchInPeer = inPeer->migrateTo() ? inPeer->migrateTo() : inPeer; _searchInPeer = inPeer->migrateTo() ? inPeer->migrateTo() : inPeer;
_searchInMigrated = _searchInPeer ? _searchInPeer->migrateFrom() : 0; _searchInMigrated = _searchInPeer ? _searchInPeer->migrateFrom() : 0;
_inner.searchInPeer(_searchInPeer); _inner.searchInPeer(_searchInPeer);
@ -2098,8 +2116,11 @@ void DialogsWidget::onSearchMore() {
PeerData *offsetPeer = _inner.lastSearchPeer(); PeerData *offsetPeer = _inner.lastSearchPeer();
MsgId offsetId = _inner.lastSearchId(); MsgId offsetId = _inner.lastSearchId();
if (_searchInPeer) { if (_searchInPeer) {
int32 flags = (_searchInPeer->isChannel() && !_searchInPeer->isMegagroup()) ? MTPmessages_Search::flag_important_only : 0; MTPmessages_Search::Flags flags = 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)); 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 { } 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)); _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) { } else if (_searchInMigrated && !_searchFullMigrated) {
MsgId offsetMigratedId = _inner.lastSearchMigratedId(); MsgId offsetMigratedId = _inner.lastSearchMigratedId();
int32 flags = (_searchInMigrated->isChannel() && !_searchInMigrated->isMegagroup()) ? MTPmessages_Search::flag_important_only : 0; MTPmessages_Search::Flags flags = 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)); 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")); _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-link"));
if (!_dragForward) _dragForward = e->mimeData()->hasFormat(qsl("application/x-td-forward-pressed")); 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) { if (_dragForward) {
e->setDropAction(Qt::CopyAction); e->setDropAction(Qt::CopyAction);
e->accept(); e->accept();
@ -2540,7 +2564,7 @@ bool DialogsWidget::onCancelSearch() {
_searchRequest = 0; _searchRequest = 0;
} }
if (_searchInPeer && !clearing) { if (_searchInPeer && !clearing) {
if (!cWideMode()) { if (Adaptive::OneColumn()) {
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId); Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
} }
_searchInPeer = _searchInMigrated = 0; _searchInPeer = _searchInMigrated = 0;
@ -2560,7 +2584,7 @@ void DialogsWidget::onCancelSearchInPeer() {
_searchRequest = 0; _searchRequest = 0;
} }
if (_searchInPeer) { if (_searchInPeer) {
if (!cWideMode() && !App::main()->selectingPeer()) { if (Adaptive::OneColumn() && !App::main()->selectingPeer()) {
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId); Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
} }
_searchInPeer = _searchInMigrated = 0; _searchInPeer = _searchInMigrated = 0;
@ -2570,7 +2594,7 @@ void DialogsWidget::onCancelSearchInPeer() {
_filter.clear(); _filter.clear();
_filter.updatePlaceholder(); _filter.updatePlaceholder();
onFilterUpdate(); onFilterUpdate();
if (cWideMode() && !App::main()->selectingPeer()) { if (!Adaptive::OneColumn() && !App::main()->selectingPeer()) {
emit cancelled(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -67,7 +67,6 @@ public:
void selectSkipPage(int32 pixels, int32 direction); void selectSkipPage(int32 pixels, int32 direction);
void createDialog(History *history); void createDialog(History *history);
void moveDialogToTop(const History::DialogLinks &links);
void dlgUpdated(DialogRow *row); void dlgUpdated(DialogRow *row);
void dlgUpdated(History *row, MsgId msgId); void dlgUpdated(History *row, MsgId msgId);
void removeDialog(History *history); void removeDialog(History *history);
@ -220,15 +219,15 @@ public:
void searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req); void searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req);
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req); void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req);
void dragEnterEvent(QDragEnterEvent *e); void dragEnterEvent(QDragEnterEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e); void dragMoveEvent(QDragMoveEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e); void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e); void dropEvent(QDropEvent *e) override;
void updateDragInScroll(bool inScroll); void updateDragInScroll(bool inScroll);
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e); void keyPressEvent(QKeyEvent *e) override;
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e) override;
void searchInPeer(PeerData *peer); void searchInPeer(PeerData *peer);
@ -260,6 +259,11 @@ public:
void updateNotifySettings(PeerData *peer); void updateNotifySettings(PeerData *peer);
void rpcClear() override {
_inner.rpcClear();
RPCSender::rpcClear();
}
void notify_userIsContactChanged(UserData *user, bool fromThisApp); void notify_userIsContactChanged(UserData *user, bool fromThisApp);
signals: 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -157,8 +157,21 @@ private:
}; };
class EmojiPanel; namespace InlineBots {
static const int EmojiColorsCount = 5; 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 { class EmojiColorPicker : public TWidget {
Q_OBJECT Q_OBJECT
@ -222,6 +235,7 @@ private:
}; };
class EmojiPanel;
class EmojiPanInner : public TWidget { class EmojiPanInner : public TWidget {
Q_OBJECT Q_OBJECT
@ -359,8 +373,8 @@ public:
uint64 currentSet(int yOffset) const; uint64 currentSet(int yOffset) const;
void ui_repaintInlineItem(const LayoutInlineItem *layout); void ui_repaintInlineItem(const InlineItem *layout);
bool ui_isInlineItemVisible(const LayoutInlineItem *layout); bool ui_isInlineItemVisible(const InlineItem *layout);
bool ui_isInlineItemBeingChosen(); bool ui_isInlineItemBeingChosen();
bool inlineResultsShown() const { bool inlineResultsShown() const {
@ -368,11 +382,7 @@ public:
} }
int32 countHeight(bool plain = false); int32 countHeight(bool plain = false);
~StickerPanInner() { ~StickerPanInner();
clearInlineRows(true);
deleteUnusedGifLayouts();
deleteUnusedInlineLayouts();
}
public slots: public slots:
@ -385,7 +395,7 @@ signals:
void selected(DocumentData *sticker); void selected(DocumentData *sticker);
void selected(PhotoData *photo); void selected(PhotoData *photo);
void selected(InlineResult *result, UserData *bot); void selected(InlineBots::Result *result, UserData *bot);
void removing(quint64 setId); void removing(quint64 setId);
@ -420,10 +430,10 @@ private:
int32 _top; int32 _top;
struct DisplayedSet { 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; uint64 id;
int32 flags; MTPDstickerSet::Flags flags;
QString title; QString title;
QVector<float64> hovers; QVector<float64> hovers;
StickerPack pack; StickerPack pack;
@ -439,7 +449,7 @@ private:
QTimer _updateInlineItems; QTimer _updateInlineItems;
bool _inlineWithThumb; bool _inlineWithThumb;
typedef QVector<LayoutInlineItem*> InlineItems; typedef QVector<InlineItem*> InlineItems;
struct InlineRow { struct InlineRow {
InlineRow() : height(0) { InlineRow() : height(0) {
} }
@ -450,13 +460,13 @@ private:
InlineRows _inlineRows; InlineRows _inlineRows;
void clearInlineRows(bool resultsDeleted); void clearInlineRows(bool resultsDeleted);
typedef QMap<DocumentData*, LayoutInlineGif*> GifLayouts; using GifLayouts = QMap<DocumentData*, InlineItem*>;
GifLayouts _gifLayouts; 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; 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 inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false); bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
@ -469,7 +479,6 @@ private:
int32 validateExistingInlineRows(const InlineResults &results); int32 validateExistingInlineRows(const InlineResults &results);
int32 _selected, _pressedSel; int32 _selected, _pressedSel;
QPoint _lastMousePos; QPoint _lastMousePos;
TextLinkPtr _linkOver, _linkDown;
LinkButton _settings; LinkButton _settings;
@ -482,7 +491,7 @@ class EmojiPanel : public TWidget {
public: 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 setText(const QString &text);
void setDeleteVisible(bool isVisible); void setDeleteVisible(bool isVisible);
@ -532,6 +541,8 @@ protected:
}; };
} // namespace internal
class EmojiPan : public TWidget, public RPCSender { class EmojiPan : public TWidget, public RPCSender {
Q_OBJECT Q_OBJECT
@ -580,8 +591,8 @@ public:
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); ).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
} }
void ui_repaintInlineItem(const LayoutInlineItem *layout); void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemVisible(const LayoutInlineItem *layout); bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemBeingChosen(); bool ui_isInlineItemBeingChosen();
bool inlineResultsShown() const { bool inlineResultsShown() const {
@ -622,7 +633,7 @@ signals:
void emojiSelected(EmojiPtr emoji); void emojiSelected(EmojiPtr emoji);
void stickerSelected(DocumentData *sticker); void stickerSelected(DocumentData *sticker);
void photoSelected(PhotoData *photo); void photoSelected(PhotoData *photo);
void inlineResultSelected(InlineResult *result, UserData *bot); void inlineResultSelected(InlineBots::Result *result, UserData *bot);
void updateStickers(); void updateStickers();
@ -642,7 +653,7 @@ private:
void updateIcons(); void updateIcons();
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab); 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 showAll();
void hideAll(); void hideAll();
@ -661,7 +672,7 @@ private:
BoxShadow _shadow; BoxShadow _shadow;
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols; FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
QList<StickerIcon> _icons; QList<internal::StickerIcon> _icons;
QVector<float64> _iconHovers; QVector<float64> _iconHovers;
int32 _iconOver, _iconSel, _iconDown; int32 _iconOver, _iconSel, _iconDown;
bool _iconsDragging; bool _iconsDragging;
@ -681,13 +692,13 @@ private:
Animation _a_slide; Animation _a_slide;
ScrollArea e_scroll; ScrollArea e_scroll;
EmojiPanInner e_inner; internal::EmojiPanInner e_inner;
QVector<EmojiPanel*> e_panels; QVector<internal::EmojiPanel*> e_panels;
EmojiSwitchButton e_switch; internal::EmojiSwitchButton e_switch;
ScrollArea s_scroll; ScrollArea s_scroll;
StickerPanInner s_inner; internal::StickerPanInner s_inner;
QVector<EmojiPanel*> s_panels; QVector<internal::EmojiPanel*> s_panels;
EmojiSwitchButton s_switch; internal::EmojiSwitchButton s_switch;
uint64 _removingSetId; uint64 _removingSetId;
@ -699,13 +710,9 @@ private:
clearResults(); clearResults();
} }
QString nextOffset; QString nextOffset;
InlineResults results; QString switchPmText, switchPmStartParam;
void clearResults() { internal::InlineResults results;
for (int32 i = 0, l = results.size(); i < l; ++i) { void clearResults();
delete results.at(i);
}
results.clear();
}
}; };
typedef QMap<QString, InlineCacheEntry*> InlineCache; typedef QMap<QString, InlineCacheEntry*> InlineCache;
InlineCache _inlineCache; InlineCache _inlineCache;
@ -734,18 +741,20 @@ class MentionsInner : public TWidget {
public: 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 paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
void enterEvent(QEvent *e); void enterEvent(QEvent *e);
void leaveEvent(QEvent *e); void leaveEvent(QEvent *e);
void mousePressEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void clearSel(); void clearSel(bool hidden = false);
bool moveSel(int direction); bool moveSel(int key);
bool select(); bool select();
void setRecentInlineBotsInRows(int32 bots); void setRecentInlineBotsInRows(int32 bots);
@ -755,27 +764,35 @@ public:
signals: signals:
void chosen(QString mentionOrHashtag); void chosen(QString mentionOrHashtag);
void selected(DocumentData *sticker);
void mustScrollTo(int scrollToTop, int scrollToBottom); void mustScrollTo(int scrollToTop, int scrollToBottom);
public slots: public slots:
void onParentGeometryChanged(); void onParentGeometryChanged();
void onUpdateSelected(bool force = false); void onUpdateSelected(bool force = false);
void onPreview();
private: private:
void updateSelectedRow();
void setSel(int sel, bool scroll = false); void setSel(int sel, bool scroll = false);
MentionsDropdown *_parent; MentionsDropdown *_parent;
MentionRows *_mrows; MentionRows *_mrows;
HashtagRows *_hrows; HashtagRows *_hrows;
BotCommandRows *_brows; BotCommandRows *_brows;
int32 _recentInlineBotsInRows; StickerPack *_srows;
int32 _sel; int32 _stickersPerRow, _recentInlineBotsInRows;
int32 _sel, _down;
bool _mouseSel; bool _mouseSel;
QPoint _mousePos; QPoint _mousePos;
bool _overDelete; bool _overDelete;
bool _previewShown;
QTimer _previewTimer;
}; };
class MentionsDropdown : public TWidget { class MentionsDropdown : public TWidget {
@ -791,7 +808,8 @@ public:
bool clearFilteredBotCommands(); bool clearFilteredBotCommands();
void showFiltered(PeerData *peer, QString query, bool start); 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 setBoundings(QRect boundings);
void step_appearance(float64 ms, bool timer); void step_appearance(float64 ms, bool timer);
@ -807,6 +825,10 @@ public:
bool eventFilter(QObject *obj, QEvent *e); bool eventFilter(QObject *obj, QEvent *e);
QString getSelected() const; QString getSelected() const;
bool stickersShown() const {
return !_srows.isEmpty();
}
bool overlaps(const QRect &globalRect) { bool overlaps(const QRect &globalRect) {
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false; if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false;
@ -818,6 +840,7 @@ public:
signals: signals:
void chosen(QString mentionOrHashtag); void chosen(QString mentionOrHashtag);
void stickerSelected(DocumentData *sticker);
public slots: public slots:
@ -828,14 +851,15 @@ public slots:
private: private:
void recount(bool toDown = false); void recount(bool resetScroll = false);
QPixmap _cache; QPixmap _cache;
MentionRows _mrows; MentionRows _mrows;
HashtagRows _hrows; HashtagRows _hrows;
BotCommandRows _brows; 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; ScrollArea _scroll;
MentionsInner _inner; MentionsInner _inner;
@ -843,6 +867,7 @@ private:
ChatData *_chat; ChatData *_chat;
UserData *_user; UserData *_user;
ChannelData *_channel; ChannelData *_channel;
EmojiPtr _emoji;
QString _filter; QString _filter;
QRect _boundings; QRect _boundings;
bool _addInlineBots; 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "window.h" #include "window.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "application.h"
#include "boxes/confirmbox.h"
#include "layerwidget.h" #include "layerwidget.h"
#include "lang.h"
Q_DECLARE_METATYPE(ClickHandlerPtr);
Q_DECLARE_METATYPE(Qt::MouseButton);
namespace App { namespace App {
void sendBotCommand(const QString &cmd, MsgId replyTo) { void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) {
if (MainWidget *m = main()) m->sendBotCommand(cmd, replyTo); if (MainWidget *m = main()) m->sendBotCommand(peer, cmd, replyTo);
} }
bool insertBotCommand(const QString &cmd, bool specialGif) { bool insertBotCommand(const QString &cmd, bool specialGif) {
@ -36,12 +43,55 @@ namespace App {
return false; return false;
} }
void searchByHashtag(const QString &tag, PeerData *inPeer) { void activateBotCommand(const HistoryItem *msg, int row, int col) {
if (MainWidget *m = main()) m->searchMessages(tag + ' ', (inPeer && inPeer->isChannel()) ? inPeer : 0); 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) { void searchByHashtag(const QString &tag, PeerData *inPeer) {
if (MainWidget *m = main()) m->openPeerByName(username, toProfile, startToken); 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) { void joinGroupByHash(const QString &hash) {
@ -62,11 +112,29 @@ namespace App {
} }
void removeDialog(History *history) { void removeDialog(History *history) {
if (MainWidget *m = main()) m->removeDialog(history); if (MainWidget *m = main()) {
m->removeDialog(history);
}
} }
void showSettings() { 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 { namespace Ui {
void showStickerPreview(DocumentData *sticker) { void showStickerPreview(DocumentData *sticker) {
if (MainWidget *m = App::main()) m->ui_showStickerPreview(sticker); if (Window *w = App::wnd()) {
w->ui_showStickerPreview(sticker);
}
} }
void hideStickerPreview() { void hideStickerPreview() {
if (MainWidget *m = App::main()) m->ui_hideStickerPreview(); if (Window *w = App::wnd()) {
w->ui_hideStickerPreview();
}
} }
void showLayer(LayeredWidget *box, ShowLayerOptions options) { void showLayer(LayeredWidget *box, ShowLayerOptions options) {
@ -113,16 +185,22 @@ namespace Ui {
if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item); 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 (!layout) return;
if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout); 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); if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout);
return false; 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) { void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) {
if (MainWidget *m = App::main()) m->ui_showPeerHistory(peer, msgId, 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 { namespace Notify {
@ -153,6 +254,12 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting); 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) { void migrateUpdated(PeerData *peer) {
if (MainWidget *m = App::main()) m->notify_migrateUpdated(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); 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) { void historyItemLayoutChanged(const HistoryItem *item) {
if (MainWidget *m = App::main()) m->notify_historyItemLayoutChanged(item); if (MainWidget *m = App::main()) m->notify_historyItemLayoutChanged(item);
} }
@ -173,4 +276,263 @@ namespace Notify {
if (MainWidget *m = App::main()) m->notify_automaticLoadSettingsChangedGif(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -24,10 +24,11 @@ class LayeredWidget;
namespace App { 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); 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 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 joinGroupByHash(const QString &hash);
void stickersBox(const QString &name); void stickersBox(const QString &name);
void openLocalUrl(const QString &url); void openLocalUrl(const QString &url);
@ -35,9 +36,21 @@ namespace App {
void removeDialog(History *history); void removeDialog(History *history);
void showSettings(); 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 showStickerPreview(DocumentData *sticker);
void hideStickerPreview(); void hideStickerPreview();
@ -49,8 +62,9 @@ namespace Ui { // openssl doesn't allow me to use UI :(
bool isInlineItemBeingChosen(); bool isInlineItemBeingChosen();
void repaintHistoryItem(const HistoryItem *item); void repaintHistoryItem(const HistoryItem *item);
void repaintInlineItem(const LayoutInlineItem *layout); void repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
bool isInlineItemVisible(const LayoutInlineItem *reader); bool isInlineItemVisible(const InlineBots::Layout::ItemBase *reader);
void autoplayMediaInlineAsync(const FullMsgId &msgId);
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false); void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
inline void showPeerHistory(const PeerData *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() { inline void showChatsList() {
showPeerHistory(PeerId(0), 0); 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 botCommandsChanged(UserData *user);
void inlineBotRequesting(bool requesting); void inlineBotRequesting(bool requesting);
void replyMarkupUpdated(const HistoryItem *item);
void migrateUpdated(PeerData *peer); void migrateUpdated(PeerData *peer);
void clipStopperHidden(ClipStopperType type); void clipStopperHidden(ClipStopperType type);
void historyItemResized(const HistoryItem *item, bool scrollToIt = false);
inline void historyItemsResized() {
historyItemResized(0);
}
void historyItemLayoutChanged(const HistoryItem *item); void historyItemLayoutChanged(const HistoryItem *item);
void automaticLoadSettingsChangedGif(); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "fileuploader.h" #include "fileuploader.h"
@ -32,7 +32,7 @@ FileUploader::FileUploader() : sentSize(0) {
void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &media) { void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &media) {
if (media.type == PreparePhoto) { if (media.type == PreparePhoto) {
App::feedPhoto(media.photo, media.photoThumbs); App::feedPhoto(media.photo, media.photoThumbs);
} else if (media.type == PrepareDocument) { } else if (media.type == PrepareDocument || media.type == PrepareAudio) {
DocumentData *document; DocumentData *document;
if (media.photoThumbs.isEmpty()) { if (media.photoThumbs.isEmpty()) {
document = App::feedDocument(media.document); 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 = App::feedDocument(media.document, media.photoThumbs.begin().value());
} }
document->status = FileUploading; document->status = FileUploading;
if (!media.data.isEmpty()) {
document->setData(media.data);
}
if (!media.file.isEmpty()) { if (!media.file.isEmpty()) {
document->setLocation(FileLocation(StorageFilePartial, media.file)); 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)); queue.insert(msgId, File(media));
sendNext(); sendNext();
@ -56,7 +55,7 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
if (file->type == PreparePhoto) { if (file->type == PreparePhoto) {
PhotoData *photo = App::feedPhoto(file->photo, file->photoThumbs); PhotoData *photo = App::feedPhoto(file->photo, file->photoThumbs);
photo->uploadingData = new PhotoData::UploadingData(file->partssize); photo->uploadingData = new PhotoData::UploadingData(file->partssize);
} else if (file->type == PrepareDocument) { } else if (file->type == PrepareDocument || file->type == PrepareAudio) {
DocumentData *document; DocumentData *document;
if (file->thumb.isNull()) { if (file->thumb.isNull()) {
document = App::feedDocument(file->document); 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 = App::feedDocument(file->document, file->thumb);
} }
document->status = FileUploading; document->status = FileUploading;
if (!file->content.isEmpty()) {
document->setData(file->content);
}
if (!file->filepath.isEmpty()) { if (!file->filepath.isEmpty()) {
document->setLocation(FileLocation(StorageFilePartial, file->filepath)); 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)); queue.insert(msgId, File(file));
sendNext(); sendNext();
@ -87,12 +85,6 @@ void FileUploader::currentFailed() {
doc->status = FileUploadFailed; doc->status = FileUploadFailed;
} }
emit documentFailed(j.key()); 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); queue.erase(j);
} }
@ -111,7 +103,7 @@ void FileUploader::currentFailed() {
void FileUploader::killSessions() { void FileUploader::killSessions() {
for (int i = 0; i < MTPUploadSessionsCount; ++i) { 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 (parts.isEmpty()) {
if (i->docSentParts >= i->docPartsCount) { if (i->docSentParts >= i->docPartsCount) {
if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) { if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) {
bool silent = i->file && i->file->to.silent;
if (i->type() == PreparePhoto) { 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))); 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) { } else if (i->type() == PrepareDocument || i->type() == PrepareAudio) {
QByteArray docMd5(32, Qt::Uninitialized); QByteArray docMd5(32, Qt::Uninitialized);
hashMd5Hex(i->md5Hash.result(), docMd5.data()); 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) { 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 { } 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); queue.remove(uploading);
uploading = FullMsgId(); uploading = FullMsgId();
@ -200,9 +187,9 @@ void FileUploader::sendNext() {
} }
mtpRequestId requestId; mtpRequestId requestId;
if (i->docSize > UseBigFilesFrom) { 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 { } 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); docRequestsSent.insert(requestId, i->docSentParts);
dcMap.insert(requestId, todc); dcMap.insert(requestId, todc);
@ -213,7 +200,7 @@ void FileUploader::sendNext() {
} else { } else {
UploadFileParts::iterator part = parts.begin(); 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()); requestsSent.insert(requestId, part.value());
dcMap.insert(requestId, todc); dcMap.insert(requestId, todc);
sentSize += part.value().size(); sentSize += part.value().size();
@ -259,7 +246,7 @@ void FileUploader::clear() {
dcMap.clear(); dcMap.clear();
sentSize = 0; sentSize = 0;
for (int32 i = 0; i < MTPUploadSessionsCount; ++i) { for (int32 i = 0; i < MTPUploadSessionsCount; ++i) {
MTP::stopSession(MTP::upl[i]); MTP::stopSession(MTP::uplDcId(i));
sentSizes[i] = 0; sentSizes[i] = 0;
} }
killSessionsTimer.stop(); killSessionsTimer.stop();
@ -303,7 +290,7 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
photo->uploadingData->offset = k->fileSentSize; photo->uploadingData->offset = k->fileSentSize;
} }
emit photoProgress(k.key()); emit photoProgress(k.key());
} else if (k->type() == PrepareDocument) { } else if (k->type() == PrepareDocument || k->type() == PrepareAudio) {
DocumentData *doc = App::document(k->id()); DocumentData *doc = App::document(k->id());
if (doc->uploading()) { if (doc->uploading()) {
doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize; doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
@ -312,15 +299,6 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
} }
} }
emit documentProgress(k.key()); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
@ -48,18 +48,15 @@ public slots:
signals: signals:
void photoReady(const FullMsgId &msgId, const MTPInputFile &file); void photoReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void documentReady(const FullMsgId &msgId, const MTPInputFile &file); void documentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void thumbDocumentReady(const FullMsgId &msgId, const MTPInputFile &file, const MTPInputFile &thumb); void thumbDocumentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file, const MTPInputFile &thumb);
void audioReady(const FullMsgId &msgId, const MTPInputFile &file);
void photoProgress(const FullMsgId &msgId); void photoProgress(const FullMsgId &msgId);
void documentProgress(const FullMsgId &msgId); void documentProgress(const FullMsgId &msgId);
void audioProgress(const FullMsgId &msgId);
void photoFailed(const FullMsgId &msgId); void photoFailed(const FullMsgId &msgId);
void documentFailed(const FullMsgId &msgId); void documentFailed(const FullMsgId &msgId);
void audioFailed(const FullMsgId &msgId);
private: 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 "stdafx.h"
#include "animation.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 "mainwidget.h"
#include "window.h" #include "window.h"
@ -93,6 +100,7 @@ namespace anim {
if (!_clipThreads.isEmpty()) { if (!_clipThreads.isEmpty()) {
for (int32 i = 0, l = _clipThreads.size(); i < l; ++i) { for (int32 i = 0, l = _clipThreads.size(); i < l; ++i) {
_clipThreads.at(i)->quit(); _clipThreads.at(i)->quit();
DEBUG_LOG(("Waiting for clipThread to finish: %1").arg(i));
_clipThreads.at(i)->wait(); _clipThreads.at(i)->wait();
delete _clipManagers.at(i); delete _clipManagers.at(i);
delete _clipThreads.at(i); delete _clipThreads.at(i);
@ -142,7 +150,7 @@ void AnimationManager::stop(Animation *obj) {
if (_iterating) { if (_iterating) {
_stopping.insert(obj, NullType()); _stopping.insert(obj, NullType());
if (!_starting.isEmpty()) { if (!_starting.isEmpty()) {
_starting.insert(obj, NullType()); _starting.remove(obj);
} }
} else { } else {
AnimatingObjects::iterator i = _objects.find(obj); AnimatingObjects::iterator i = _objects.find(obj);
@ -159,7 +167,9 @@ void AnimationManager::timeout() {
_iterating = true; _iterating = true;
uint64 ms = getms(); uint64 ms = getms();
for (AnimatingObjects::const_iterator i = _objects.begin(), e = _objects.end(); i != e; ++i) { 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; _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); bool needOuter = (request.outerw != request.framew) || (request.outerh != request.frameh);
if (badSize || needOuter || hasAlpha || request.rounded) { if (badSize || needOuter || hasAlpha || request.rounded) {
int32 factor(request.factor); int32 factor(request.factor);
bool fill = false; bool newcache = (cache.width() != request.outerw || cache.height() != request.outerh);
if (cache.width() != request.outerw || cache.height() != request.outerh) { if (newcache) {
cache = QImage(request.outerw, request.outerh, QImage::Format_ARGB32_Premultiplied); 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); cache.setDevicePixelRatio(factor);
} }
{ {
Painter p(&cache); Painter p(&cache);
if (fill) { if (newcache) {
p.fillRect(0, 0, cache.width() / factor, cache.height() / factor, st::black); 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)); QPoint position((request.outerw - request.framew) / (2 * factor), (request.outerh - request.frameh) / (2 * factor));
if (badSize) { if (badSize) {
@ -235,7 +252,7 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
_clipManagers.push_back(new ClipReadManager(_clipThreads.back())); _clipManagers.push_back(new ClipReadManager(_clipThreads.back()));
_clipThreads.back()->start(); _clipThreads.back()->start();
} else { } else {
_threadIndex = int32(MTP::nonce<uint32>() % _clipThreads.size()); _threadIndex = int32(rand_value<uint32>() % _clipThreads.size());
int32 loadLevel = 0x7FFFFFFF; int32 loadLevel = 0x7FFFFFFF;
for (int32 i = 0, l = _clipThreads.size(); i < l; ++i) { for (int32 i = 0, l = _clipThreads.size(); i < l; ++i) {
int32 level = _clipManagers.at(i)->loadLevel(); 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; frame->request.outerh = outerh * factor;
QImage cacheForResize; QImage cacheForResize;
frame->original.setDevicePixelRatio(factor);
frame->pix = QPixmap(); frame->pix = QPixmap();
frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize); frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize);
@ -418,7 +436,6 @@ void ClipReader::stop() {
} }
void ClipReader::error() { void ClipReader::error() {
_private = 0;
_state = ClipError; _state = ClipError;
} }
@ -477,7 +494,7 @@ public:
, _frameDelay(0) { , _frameDelay(0) {
} }
bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) { bool readNextFrame() {
if (_reader) _frameDelay = _reader->nextImageDelay(); if (_reader) _frameDelay = _reader->nextImageDelay();
if (_framesLeft < 1 && !jumpToStart()) { if (_framesLeft < 1 && !jumpToStart()) {
return false; return false;
@ -587,6 +604,11 @@ public:
} }
bool readNextFrame() { bool readNextFrame() {
if (_frameRead) {
av_frame_unref(_frame);
_frameRead = false;
}
int res; int res;
while (true) { while (true) {
if (_avpkt.size > 0) { // previous packet not finished if (_avpkt.size > 0) { // previous packet not finished
@ -638,6 +660,20 @@ public:
} }
if (got_frame) { 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; _hadFrame = _frameRead = true;
return 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); av_frame_unref(_frame);
return true; return true;
} }
@ -792,6 +814,10 @@ public:
} }
~FFMpegReaderImplementation() { ~FFMpegReaderImplementation() {
if (_frameRead) {
av_frame_unref(_frame);
_frameRead = false;
}
if (_ioContext) av_free(_ioContext); if (_ioContext) av_free(_ioContext);
if (_codecContext) avcodec_close(_codecContext); if (_codecContext) avcodec_close(_codecContext);
if (_swsContext) sws_freeContext(_swsContext); 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. to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE 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 #pragma once
#include "types.h" #include "basic_types.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtGui/QColor> #include <QtGui/QColor>
@ -208,10 +208,10 @@ class AnimationCreator {
public: public:
AnimationCreator(AnimationImplementation *ptr) : _ptr(ptr) {} AnimationCreator(AnimationImplementation *ptr) : _ptr(ptr) {}
AnimationCreator(const AnimationCreator &other) : _ptr(other.create()) {} AnimationCreator(const AnimationCreator &other) : _ptr(other.create()) {}
AnimationImplementation *create() const { return exchange(_ptr); } AnimationImplementation *create() const { return getPointerAndReset(_ptr); }
~AnimationCreator() { deleteAndMark(_ptr); } ~AnimationCreator() { deleteAndMark(_ptr); }
private: private:
AnimationCreator &operator=(const AnimationCreator &other); AnimationCreator &operator=(const AnimationCreator &other) = delete;
mutable AnimationImplementation *_ptr; mutable AnimationImplementation *_ptr;
}; };
class AnimationCallbacks { class AnimationCallbacks {
@ -222,7 +222,7 @@ public:
~AnimationCallbacks() { deleteAndMark(_implementation); } ~AnimationCallbacks() { deleteAndMark(_implementation); }
private: private:
AnimationCallbacks(const AnimationCallbacks &other); AnimationCallbacks(const AnimationCallbacks &other);
AnimationCallbacks &operator=(const AnimationCallbacks &other); AnimationCallbacks &operator=(const AnimationCallbacks &other) = delete;
AnimationImplementation *_implementation; AnimationImplementation *_implementation;
}; };

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