Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ce8d9f0b7 | ||
|
|
b23ffe6c94 | ||
|
|
276ef42c8f | ||
|
|
79a41d541d | ||
|
|
61e3f9000b | ||
|
|
a4c13e0720 | ||
|
|
a09460dc84 | ||
|
|
4bcfee22ef | ||
|
|
880c2697d1 | ||
|
|
188e1b61c5 | ||
|
|
696c5df092 | ||
|
|
408b38b41f | ||
|
|
4a6b6fad77 | ||
|
|
f7fa13899f | ||
|
|
f370e2b85d | ||
|
|
5d649f750b | ||
|
|
cfcf4d2336 | ||
|
|
922ab40c75 | ||
|
|
2532245413 |
@@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.6.10
|
||||
AppVersion=6010
|
||||
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
|
||||
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
|
||||
|
||||
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinuxupd$AppVersion" ]; then
|
||||
echo "tlinuxupd$AppVersion not found!";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.6.10
|
||||
AppVersion=6010
|
||||
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
|
||||
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
|
||||
|
||||
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinux32upd$AppVersion" ]; then
|
||||
echo "tlinux32upd$AppVersion not found!"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.6.10
|
||||
AppVersion=6010
|
||||
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
|
||||
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
|
||||
|
||||
if [ ! -f "./../Mac/Release/deploy/$AppVersionStr/tmacupd$AppVersion" ]; then
|
||||
echo "tmacupd$AppVersion not found!"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.6.10
|
||||
AppVersion=6010
|
||||
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
|
||||
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
|
||||
|
||||
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr/tupdate$AppVersion" ]; then
|
||||
echo "tupdate$AppVersion not found!"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.6.10
|
||||
AppVersion=6010
|
||||
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
|
||||
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
|
||||
|
||||
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
|
||||
echo "Deploy folder for version $AppVersionStr already exists!"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.6.10
|
||||
AppVersion=6010
|
||||
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
|
||||
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
|
||||
|
||||
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
|
||||
echo "Deploy folder for version $AppVersionStr already exists!"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.6.10
|
||||
AppVersion=6010
|
||||
AppVersion=`./Version.sh | awk -F " " '{print $1}'`
|
||||
AppVersionStr=`./Version.sh | awk -F " " '{print $2}'`
|
||||
|
||||
echo ""
|
||||
echo "Preparing version $AppVersionStr.."
|
||||
@@ -20,11 +20,6 @@ if [ ! -d "./../Mac/Release/Telegram.app" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "./../Mac/Release/Telegram.app/Contents/_CodeSignature" ]; then
|
||||
echo "Telegram signature not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "./../Mac/Release/Telegram.app/Contents/Resources/Icon.icns" ]; then
|
||||
echo "Icon.icns not found in Resources!"
|
||||
exit 1
|
||||
@@ -41,6 +36,12 @@ if [ ! -f "./../Mac/Release/Telegram.app/Contents/Frameworks/Updater" ]; then
|
||||
fi
|
||||
|
||||
cd ./../Mac/Release && codesign --force --deep --sign "Developer ID Application: John Preston" Telegram.app && cd ./../../Telegram
|
||||
|
||||
if [ ! -d "./../Mac/Release/Telegram.app/Contents/_CodeSignature" ]; then
|
||||
echo "Telegram signature not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ./../Mac/Release
|
||||
temppath=`hdiutil attach -readwrite tsetup.dmg | awk -F "\t" 'END {print $3}'`
|
||||
cp -R ./Telegram.app "$temppath/"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
@echo OFF
|
||||
|
||||
set "AppVersionStr=0.6.10"
|
||||
set "AppVersionStrSmall=0.6.13"
|
||||
set "AppVersionStr=0.6.13"
|
||||
set "AppVersionStrFull=0.6.13.0"
|
||||
|
||||
echo.
|
||||
echo Preparing version %AppVersionStr%..
|
||||
echo.
|
||||
@@ -14,7 +17,7 @@ if %errorlevel% neq 0 goto error1
|
||||
call ..\..\..\TelegramPrivate\Sign.bat Updater.exe
|
||||
if %errorlevel% neq 0 goto error1
|
||||
|
||||
iscc ..\..\Telegram\Setup.iss
|
||||
iscc /dMyAppVersion=%AppVersionStrSmall% /dMyAppVersionZero=%AppVersionStr% /dMyAppFullVersion=%AppVersionStrFull% ..\..\Telegram\Setup.iss
|
||||
if %errorlevel% neq 0 goto error1
|
||||
|
||||
call ..\..\..\TelegramPrivate\Sign.bat tsetup.%AppVersionStr%.exe
|
||||
|
||||
@@ -62,6 +62,7 @@ lng_connecting: "Connecting..";
|
||||
lng_reconnecting: "Reconnect in %1 s..";
|
||||
lng_reconnecting_try_now: "Try now";
|
||||
|
||||
lng_status_service_notifications: "service notifications";
|
||||
lng_status_offline: "last seen a long time ago";
|
||||
lng_status_recently: "last seen recently";
|
||||
lng_status_last_week: "last seen within a week";
|
||||
@@ -219,6 +220,15 @@ lng_download_path_clearing: "Clearing..";
|
||||
lng_download_path_cleared: "Cleared!";
|
||||
lng_download_path_clear_failed: "Clear failed :(";
|
||||
|
||||
lng_settings_section_cache: "Local storage";
|
||||
lng_settings_no_images_cached: "No cached images found!";
|
||||
lng_settings_image_cached: "Cached: {count} image, {size}";
|
||||
lng_settings_images_cached: "Cached: {count} images, {size}";
|
||||
lng_local_images_clear: "Clear All";
|
||||
lng_local_images_clearing: "Clearing..";
|
||||
lng_local_images_cleared: "Cleared!";
|
||||
lng_local_images_clear_failed: "Clear failed :(";
|
||||
|
||||
lng_settings_section_advanced: "Advanced";
|
||||
lng_connection_type: "Connection type:";
|
||||
lng_connection_auto_connecting: "Default (connecting..)";
|
||||
|
||||
@@ -1642,5 +1642,5 @@ usernameCancel: flatButton(btnSelectCancel) {
|
||||
}
|
||||
|
||||
youtubeIcon: sprite(336px, 221px, 60px, 60px);
|
||||
instagramIcon: sprite(336px, 283px, 60px, 60px);
|
||||
vimeoIcon: sprite(336px, 283px, 60px, 60px);
|
||||
locationSize: size(320, 240);
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
|
||||
#define MyAppShortName "Telegram"
|
||||
#define MyAppName "Telegram Desktop"
|
||||
#define MyAppVersion "0.6.10"
|
||||
#define MyAppVersionZero "0.6.10"
|
||||
#define MyAppFullVersion "0.6.10.0"
|
||||
#define MyAppPublisher "Telegram Messenger LLP"
|
||||
#define MyAppURL "https://tdesktop.com"
|
||||
#define MyAppExeName "Telegram.exe"
|
||||
@@ -28,7 +25,7 @@ DefaultGroupName={#MyAppName}
|
||||
AllowNoIcons=yes
|
||||
OutputDir=.\..\Win32\Deploy
|
||||
OutputBaseFilename=tsetup.{#MyAppVersionZero}
|
||||
SetupIconFile=.\SourceFiles\art\iconround256.ico
|
||||
SetupIconFile=.\SourceFiles\art\icon256.ico
|
||||
UninstallDisplayIcon={app}\Telegram.exe
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
|
||||
@@ -78,11 +78,11 @@ EmojiReplace replaces[] = {
|
||||
{0xD83DDE37U, ":X"},
|
||||
{0xD83DDE1AU, ":-*"},
|
||||
{0xD83DDE08U, "}:)"},
|
||||
{0x2764FE0FU, "<3"},
|
||||
{0x2764U, "<3"},
|
||||
{0xD83DDC4DU, ":like:"},
|
||||
{0xD83DDC4EU, ":dislike:"},
|
||||
{0x261DFE0FU, ":up:"},
|
||||
{0x270CFE0FU, ":v:"},
|
||||
{0x261DU, ":up:"},
|
||||
{0x270CU, ":v:"},
|
||||
{0xD83DDC4CU, ":ok:"}
|
||||
};
|
||||
const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace);
|
||||
@@ -102,7 +102,7 @@ uint64 emojiCategory0[] = {
|
||||
0xD83DDE03LLU,
|
||||
0xD83DDE00LLU,
|
||||
0xD83DDE0ALLU,
|
||||
0x263AFE0FLLU,
|
||||
0x263ALLU,
|
||||
0xD83DDE09LLU,
|
||||
0xD83DDE0DLLU,
|
||||
0xD83DDE18LLU,
|
||||
@@ -208,7 +208,7 @@ uint64 emojiCategory0[] = {
|
||||
0xD83DDC4CLLU,
|
||||
0xD83DDC4ALLU,
|
||||
0x270ALLU,
|
||||
0x270CFE0FLLU,
|
||||
0x270CLLU,
|
||||
0xD83DDC4BLLU,
|
||||
0x270BLLU,
|
||||
0xD83DDC50LLU,
|
||||
@@ -218,7 +218,7 @@ uint64 emojiCategory0[] = {
|
||||
0xD83DDC48LLU,
|
||||
0xD83DDE4CLLU,
|
||||
0xD83DDE4FLLU,
|
||||
0x261DFE0FLLU,
|
||||
0x261DLLU,
|
||||
0xD83DDC4FLLU,
|
||||
0xD83DDCAALLU,
|
||||
0xD83DDEB6LLU,
|
||||
@@ -270,7 +270,7 @@ uint64 emojiCategory0[] = {
|
||||
0xD83DDC99LLU,
|
||||
0xD83DDC9CLLU,
|
||||
0xD83DDC9ALLU,
|
||||
0x2764FE0FLLU,
|
||||
0x2764LLU,
|
||||
0xD83DDC94LLU,
|
||||
0xD83DDC97LLU,
|
||||
0xD83DDC93LLU,
|
||||
@@ -395,12 +395,12 @@ uint64 emojiCategory1[] = {
|
||||
0xD83CDF0CLLU,
|
||||
0xD83CDF20LLU,
|
||||
0x2B50LLU,
|
||||
0x2600FE0FLLU,
|
||||
0x2600LLU,
|
||||
0x26C5LLU,
|
||||
0x2601FE0FLLU,
|
||||
0x2601LLU,
|
||||
0x26A1LLU,
|
||||
0x2614LLU,
|
||||
0x2744FE0FLLU,
|
||||
0x2744LLU,
|
||||
0x26C4LLU,
|
||||
0xD83CDF00LLU,
|
||||
0xD83CDF01LLU,
|
||||
@@ -440,7 +440,7 @@ uint64 emojiCategory2[] = {
|
||||
0xD83DDCBELLU,
|
||||
0xD83DDCBBLLU,
|
||||
0xD83DDCF1LLU,
|
||||
0x260EFE0FLLU,
|
||||
0x260ELLU,
|
||||
0xD83DDCDELLU,
|
||||
0xD83DDCDFLLU,
|
||||
0xD83DDCE0LLU,
|
||||
@@ -497,7 +497,7 @@ uint64 emojiCategory2[] = {
|
||||
0xD83DDCE7LLU,
|
||||
0xD83DDCE5LLU,
|
||||
0xD83DDCE4LLU,
|
||||
0x2709FE0FLLU,
|
||||
0x2709LLU,
|
||||
0xD83DDCE9LLU,
|
||||
0xD83DDCE8LLU,
|
||||
0xD83DDCEFLLU,
|
||||
@@ -521,11 +521,11 @@ uint64 emojiCategory2[] = {
|
||||
0xD83DDCC7LLU,
|
||||
0xD83DDCC1LLU,
|
||||
0xD83DDCC2LLU,
|
||||
0x2702FE0FLLU,
|
||||
0x2702LLU,
|
||||
0xD83DDCCCLLU,
|
||||
0xD83DDCCELLU,
|
||||
0x2712FE0FLLU,
|
||||
0x270FFE0FLLU,
|
||||
0x2712LLU,
|
||||
0x270FLLU,
|
||||
0xD83DDCCFLLU,
|
||||
0xD83DDCD0LLU,
|
||||
0xD83DDCD5LLU,
|
||||
@@ -564,7 +564,7 @@ uint64 emojiCategory2[] = {
|
||||
0xD83CDFC8LLU,
|
||||
0xD83CDFC0LLU,
|
||||
0x26BDLLU,
|
||||
0x26BEFE0FLLU,
|
||||
0x26BELLU,
|
||||
0xD83CDFBELLU,
|
||||
0xD83CDFB1LLU,
|
||||
0xD83CDFC9LLU,
|
||||
@@ -680,7 +680,7 @@ uint64 emojiCategory3[] = {
|
||||
0xD83DDEA3LLU,
|
||||
0x2693LLU,
|
||||
0xD83DDE80LLU,
|
||||
0x2708FE0FLLU,
|
||||
0x2708LLU,
|
||||
0xD83DDCBALLU,
|
||||
0xD83DDE81LLU,
|
||||
0xD83DDE82LLU,
|
||||
@@ -721,13 +721,13 @@ uint64 emojiCategory3[] = {
|
||||
0xD83CDFABLLU,
|
||||
0xD83DDEA6LLU,
|
||||
0xD83DDEA5LLU,
|
||||
0x26A0FE0FLLU,
|
||||
0x26A0LLU,
|
||||
0xD83DDEA7LLU,
|
||||
0xD83DDD30LLU,
|
||||
0x26FDLLU,
|
||||
0xD83CDFEELLU,
|
||||
0xD83CDFB0LLU,
|
||||
0x2668FE0FLLU,
|
||||
0x2668LLU,
|
||||
0xD83DDDFFLLU,
|
||||
0xD83CDFAALLU,
|
||||
0xD83CDFADLLU,
|
||||
@@ -760,33 +760,33 @@ uint64 emojiCategory4[] = {
|
||||
0xD83DDD22LLU,
|
||||
0x2320E3LLU,
|
||||
0xD83DDD23LLU,
|
||||
0x2B06FE0FLLU,
|
||||
0x2B07FE0FLLU,
|
||||
0x2B05FE0FLLU,
|
||||
0x27A1FE0FLLU,
|
||||
0x2B06LLU,
|
||||
0x2B07LLU,
|
||||
0x2B05LLU,
|
||||
0x27A1LLU,
|
||||
0xD83DDD20LLU,
|
||||
0xD83DDD21LLU,
|
||||
0xD83DDD24LLU,
|
||||
0x2197FE0FLLU,
|
||||
0x2196FE0FLLU,
|
||||
0x2198FE0FLLU,
|
||||
0x2199FE0FLLU,
|
||||
0x2194FE0FLLU,
|
||||
0x2195FE0FLLU,
|
||||
0x2197LLU,
|
||||
0x2196LLU,
|
||||
0x2198LLU,
|
||||
0x2199LLU,
|
||||
0x2194LLU,
|
||||
0x2195LLU,
|
||||
0xD83DDD04LLU,
|
||||
0x25C0FE0FLLU,
|
||||
0x25B6FE0FLLU,
|
||||
0x25C0LLU,
|
||||
0x25B6LLU,
|
||||
0xD83DDD3CLLU,
|
||||
0xD83DDD3DLLU,
|
||||
0x21A9FE0FLLU,
|
||||
0x21AAFE0FLLU,
|
||||
0x2139FE0FLLU,
|
||||
0x21A9LLU,
|
||||
0x21AALLU,
|
||||
0x2139LLU,
|
||||
0x23EALLU,
|
||||
0x23E9LLU,
|
||||
0x23EBLLU,
|
||||
0x23ECLLU,
|
||||
0x2935FE0FLLU,
|
||||
0x2934FE0FLLU,
|
||||
0x2935LLU,
|
||||
0x2934LLU,
|
||||
0xD83CDD97LLU,
|
||||
0xD83DDD00LLU,
|
||||
0xD83DDD01LLU,
|
||||
@@ -802,8 +802,8 @@ uint64 emojiCategory4[] = {
|
||||
0xD83CDE2FLLU,
|
||||
0xD83CDE33LLU,
|
||||
0xD83CDE35LLU,
|
||||
0xD83CDE32LLU,
|
||||
0xD83CDE34LLU,
|
||||
0xD83CDE32LLU,
|
||||
0xD83CDE50LLU,
|
||||
0xD83CDE39LLU,
|
||||
0xD83CDE3ALLU,
|
||||
@@ -822,14 +822,14 @@ uint64 emojiCategory4[] = {
|
||||
0xD83CDE37LLU,
|
||||
0xD83CDE38LLU,
|
||||
0xD83CDE02LLU,
|
||||
0x24C2FE0FLLU,
|
||||
0x24C2LLU,
|
||||
0xD83DDEC2LLU,
|
||||
0xD83DDEC4LLU,
|
||||
0xD83DDEC5LLU,
|
||||
0xD83DDEC3LLU,
|
||||
0xD83CDE51LLU,
|
||||
0x3299FE0FLLU,
|
||||
0x3297FE0FLLU,
|
||||
0x3299LLU,
|
||||
0x3297LLU,
|
||||
0xD83CDD91LLU,
|
||||
0xD83CDD98LLU,
|
||||
0xD83CDD94LLU,
|
||||
@@ -842,11 +842,11 @@ uint64 emojiCategory4[] = {
|
||||
0xD83DDEB7LLU,
|
||||
0xD83DDEB8LLU,
|
||||
0x26D4LLU,
|
||||
0x2733FE0FLLU,
|
||||
0x2747FE0FLLU,
|
||||
0x2733LLU,
|
||||
0x2747LLU,
|
||||
0x274ELLU,
|
||||
0x2705LLU,
|
||||
0x2734FE0FLLU,
|
||||
0x2734LLU,
|
||||
0xD83DDC9FLLU,
|
||||
0xD83CDD9ALLU,
|
||||
0xD83DDCF3LLU,
|
||||
@@ -857,7 +857,7 @@ uint64 emojiCategory4[] = {
|
||||
0xD83CDD7ELLU,
|
||||
0xD83DDCA0LLU,
|
||||
0x27BFLLU,
|
||||
0x267BFE0FLLU,
|
||||
0x267BLLU,
|
||||
0x2648LLU,
|
||||
0x2649LLU,
|
||||
0x264ALLU,
|
||||
@@ -880,8 +880,8 @@ uint64 emojiCategory4[] = {
|
||||
0xAELLU,
|
||||
0x2122LLU,
|
||||
0x274CLLU,
|
||||
0x203CFE0FLLU,
|
||||
0x2049FE0FLLU,
|
||||
0x203CLLU,
|
||||
0x2049LLU,
|
||||
0x2757LLU,
|
||||
0x2753LLU,
|
||||
0x2755LLU,
|
||||
@@ -921,26 +921,26 @@ uint64 emojiCategory4[] = {
|
||||
0x2795LLU,
|
||||
0x2796LLU,
|
||||
0x2797LLU,
|
||||
0x2660FE0FLLU,
|
||||
0x2665FE0FLLU,
|
||||
0x2663FE0FLLU,
|
||||
0x2666FE0FLLU,
|
||||
0x2660LLU,
|
||||
0x2665LLU,
|
||||
0x2663LLU,
|
||||
0x2666LLU,
|
||||
0xD83DDCAELLU,
|
||||
0xD83DDCAFLLU,
|
||||
0x2714FE0FLLU,
|
||||
0x2611FE0FLLU,
|
||||
0x2714LLU,
|
||||
0x2611LLU,
|
||||
0xD83DDD18LLU,
|
||||
0xD83DDD17LLU,
|
||||
0x27B0LLU,
|
||||
0x3030LLU,
|
||||
0x303DFE0FLLU,
|
||||
0x303DLLU,
|
||||
0xD83DDD31LLU,
|
||||
0x25FCFE0FLLU,
|
||||
0x25FBFE0FLLU,
|
||||
0x25FCLLU,
|
||||
0x25FBLLU,
|
||||
0x25FELLU,
|
||||
0x25FDLLU,
|
||||
0x25AAFE0FLLU,
|
||||
0x25ABFE0FLLU,
|
||||
0x25AALLU,
|
||||
0x25ABLLU,
|
||||
0xD83DDD3ALLU,
|
||||
0xD83DDD32LLU,
|
||||
0xD83DDD33LLU,
|
||||
@@ -957,61 +957,105 @@ uint64 emojiCategory4[] = {
|
||||
0xD83DDD39LLU,
|
||||
};
|
||||
|
||||
uint64 emojiClones[] = {
|
||||
0x263ALLU,
|
||||
0x270CLLU,
|
||||
0x261DLLU,
|
||||
0x2764LLU,
|
||||
0x2600LLU,
|
||||
0x2601LLU,
|
||||
0x2744LLU,
|
||||
0x260ELLU,
|
||||
0x2709LLU,
|
||||
0x2702LLU,
|
||||
0x2712LLU,
|
||||
0x270FLLU,
|
||||
0x26BELLU,
|
||||
0x2708LLU,
|
||||
0x26A0LLU,
|
||||
0x2668LLU,
|
||||
0x2B06LLU,
|
||||
0x2B07LLU,
|
||||
0x2B05LLU,
|
||||
0x27A1LLU,
|
||||
0x2197LLU,
|
||||
0x2196LLU,
|
||||
0x2198LLU,
|
||||
0x2199LLU,
|
||||
0x2194LLU,
|
||||
0x2195LLU,
|
||||
0x25C0LLU,
|
||||
0x25B6LLU,
|
||||
0x21A9LLU,
|
||||
0x21AALLU,
|
||||
0x2139LLU,
|
||||
0x2935LLU,
|
||||
0x2934LLU,
|
||||
0x24C2LLU,
|
||||
0x3299LLU,
|
||||
0x3297LLU,
|
||||
0x2733LLU,
|
||||
0x2747LLU,
|
||||
0x2734LLU,
|
||||
0x267BLLU,
|
||||
uint64 emojiPostfixed[] = {
|
||||
0x203CLLU,
|
||||
0x2049LLU,
|
||||
0x2660LLU,
|
||||
0x2665LLU,
|
||||
0x2663LLU,
|
||||
0x2666LLU,
|
||||
0x2714LLU,
|
||||
0x2611LLU,
|
||||
0x303DLLU,
|
||||
0x25FCLLU,
|
||||
0x25FBLLU,
|
||||
0x2139LLU,
|
||||
0x2194LLU,
|
||||
0x2195LLU,
|
||||
0x2196LLU,
|
||||
0x2197LLU,
|
||||
0x2198LLU,
|
||||
0x2199LLU,
|
||||
0x21A9LLU,
|
||||
0x21AALLU,
|
||||
0x231ALLU,
|
||||
0x231BLLU,
|
||||
0x24C2LLU,
|
||||
0x25AALLU,
|
||||
0x25ABLLU,
|
||||
0x25B6LLU,
|
||||
0x25C0LLU,
|
||||
0x25FBLLU,
|
||||
0x25FCLLU,
|
||||
0x25FDLLU,
|
||||
0x25FELLU,
|
||||
0x2600LLU,
|
||||
0x2601LLU,
|
||||
0x260ELLU,
|
||||
0x2611LLU,
|
||||
0x2614LLU,
|
||||
0x2615LLU,
|
||||
0x261DLLU,
|
||||
0x263ALLU,
|
||||
0x2648LLU,
|
||||
0x2649LLU,
|
||||
0x264ALLU,
|
||||
0x264BLLU,
|
||||
0x264CLLU,
|
||||
0x264DLLU,
|
||||
0x264ELLU,
|
||||
0x264FLLU,
|
||||
0x2650LLU,
|
||||
0x2651LLU,
|
||||
0x2652LLU,
|
||||
0x2653LLU,
|
||||
0x2660LLU,
|
||||
0x2663LLU,
|
||||
0x2665LLU,
|
||||
0x2666LLU,
|
||||
0x2668LLU,
|
||||
0x267BLLU,
|
||||
0x267FLLU,
|
||||
0x2693LLU,
|
||||
0x26A0LLU,
|
||||
0x26A1LLU,
|
||||
0x26AALLU,
|
||||
0x26ABLLU,
|
||||
0x26BDLLU,
|
||||
0x26BELLU,
|
||||
0x26C4LLU,
|
||||
0x26C5LLU,
|
||||
0x26D4LLU,
|
||||
0x26EALLU,
|
||||
0x26F2LLU,
|
||||
0x26F3LLU,
|
||||
0x26F5LLU,
|
||||
0x26FALLU,
|
||||
0x26FDLLU,
|
||||
0x2702LLU,
|
||||
0x2708LLU,
|
||||
0x2709LLU,
|
||||
0x270CLLU,
|
||||
0x270FLLU,
|
||||
0x2712LLU,
|
||||
0x2714LLU,
|
||||
0x2716LLU,
|
||||
0x2733LLU,
|
||||
0x2734LLU,
|
||||
0x2744LLU,
|
||||
0x2747LLU,
|
||||
0x2757LLU,
|
||||
0x2764LLU,
|
||||
0x27A1LLU,
|
||||
0x2934LLU,
|
||||
0x2935LLU,
|
||||
0x2B05LLU,
|
||||
0x2B06LLU,
|
||||
0x2B07LLU,
|
||||
0x2B50LLU,
|
||||
0x2B55LLU,
|
||||
0x2B1BLLU,
|
||||
0x2B1CLLU,
|
||||
0x303DLLU,
|
||||
0x3297LLU,
|
||||
0x3299LLU,
|
||||
0xD83CDC04LLU,
|
||||
0xD83CDD7FLLU,
|
||||
0xD83CDE1ALLU,
|
||||
0xD83CDE2FLLU,
|
||||
};
|
||||
QMap<uint64, bool> emojiWithPostfixes;
|
||||
|
||||
uint32 firstCode(uint64 fullCode) {
|
||||
return (fullCode > 0xFFFFFFFFLLU) ? uint32(fullCode >> 32) : (fullCode & 0xFFFFFFFFU);
|
||||
@@ -1046,7 +1090,7 @@ void writeEmojiCategory(QTextStream &tcpp, uint64 *emojiCategory, uint32 size, c
|
||||
|
||||
bool genEmoji(QString emoji_in, const QString &emoji_out, const QString &emoji_png) {
|
||||
int currentRow = 0, currentColumn = 0;
|
||||
uint32 min1 = 0xFFFFFFFFU, max1 = 0, min2 = 0xFFFFFFFFU, max2 = 0, min3 = 0xFFFFFFFFU, max3 = 0;
|
||||
uint32 min1 = 0xFFFFFFFFU, max1 = 0, min2 = 0xFFFFFFFFU, max2 = 0;
|
||||
|
||||
QImage sprites[5];
|
||||
int emojisInRow[] = { 27, 29, 33, 34, 34 }; // [[7,27],[4,29],[7,33],[3,34],[6,34]]
|
||||
@@ -1100,13 +1144,8 @@ bool genEmoji(QString emoji_in, const QString &emoji_out, const QString &emoji_p
|
||||
}
|
||||
} else if (high == 35 || (high >= 48 && high < 58)) { // digits
|
||||
} else {
|
||||
if (high < 0xD000) {
|
||||
if (data.code < min2) min2 = data.code;
|
||||
if (data.code > max2) max2 = data.code;
|
||||
} else {
|
||||
if (data.code < min3) min3 = data.code;
|
||||
if (data.code > max3) max3 = data.code;
|
||||
}
|
||||
if (data.code < min2) min2 = data.code;
|
||||
if (data.code > max2) max2 = data.code;
|
||||
}
|
||||
EmojisData::const_iterator k = emojisData.constFind(data.code);
|
||||
if (k != emojisData.cend()) {
|
||||
@@ -1170,23 +1209,8 @@ bool genEmoji(QString emoji_in, const QString &emoji_out, const QString &emoji_p
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0, l = sizeof(emojiClones) / sizeof(emojiClones[0]); i < l; ++i) {
|
||||
uint64 cloneCode = emojiClones[i], originalCode = (cloneCode << 16) | 0xFE0F;
|
||||
EmojisData::const_iterator j = emojisData.constFind(originalCode);
|
||||
if (j == emojisData.cend()) {
|
||||
cout << "Could not find data for emoji clone 0x" << QString::number(cloneCode, 16).toUpper().toUtf8().constData() << "!\n";
|
||||
return false;
|
||||
}
|
||||
EmojiData clone;
|
||||
clone.code = firstCode(cloneCode);
|
||||
clone.code2 = secondCode(cloneCode);
|
||||
clone.category = -1;
|
||||
clone.index = -1;
|
||||
clone.x = j->x;
|
||||
clone.y = j->y;
|
||||
emojisData.insert(cloneCode, clone);
|
||||
if (clone.code < min1) min1 = clone.code;
|
||||
if (clone.code > max1) max1 = clone.code;
|
||||
for (int i = 0, l = sizeof(emojiPostfixed) / sizeof(emojiPostfixed[0]); i < l; ++i) {
|
||||
emojiWithPostfixes.insert(emojiPostfixed[i], true);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -1229,7 +1253,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com\n\
|
||||
tcpp << "\tEmojiData *toFill = emojis = (EmojiData*)emojisData;\n\n";
|
||||
for (EmojisData::const_iterator i = emojisData.cbegin(), e = emojisData.cend(); i != e; ++i) {
|
||||
int len = i->code2 ? 4 : ((i->code >> 16) ? 2 : 1);
|
||||
tcpp << "\tnew (toFill++) EmojiData(" << (i->x * imSize) << ", " << (i->y * imSize) << ", 0x" << QString("%1").arg(i->code, 0, 16).toUpper().toUtf8().constData() << "U, 0x" << QString("%1").arg(i->code2, 0, 16).toUpper().toUtf8().constData() << "U, " << len << ");\n";
|
||||
bool withPostfix = emojiWithPostfixes.constFind(i->code) != emojiWithPostfixes.constEnd();
|
||||
tcpp << "\tnew (toFill++) EmojiData(" << (i->x * imSize) << ", " << (i->y * imSize) << ", 0x" << QString("%1").arg(i->code, 0, 16).toUpper().toUtf8().constData() << "U, 0x" << QString("%1").arg(i->code2, 0, 16).toUpper().toUtf8().constData() << "U, " << len << (withPostfix ? ", 0xFE0F" : "") << ");\n";
|
||||
}
|
||||
tcpp << "}\n\n";
|
||||
}
|
||||
@@ -1283,18 +1308,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com\n\
|
||||
tcpp << "\t\treturn 0;\n";
|
||||
tcpp << "\t}\n\n";
|
||||
|
||||
tcpp << "\tif (code >= 0x" << QString("%1").arg(min2, 0, 16).toUpper().toUtf8().constData() << "U && code <= 0x" << QString("%1").arg(max2, 0, 16).toUpper().toUtf8().constData() << "U) {\n";
|
||||
tcpp << "\t\tif ((code & 0xFFFFU) != 0xFE0F) return 0;\n\n";
|
||||
tcpp << "\t\tswitch (code) {\n";
|
||||
for (; i != e; ++i) {
|
||||
if (i->code2 || ((i->code >> 16) >= 0xD000)) break;
|
||||
tcpp << "\t\t\tcase 0x" << QString("%1").arg(i->code, 0, 16).toUpper().toUtf8().constData() << "U: return &emojis[" << (index++) << "];\n";
|
||||
}
|
||||
tcpp << "\t\t}\n\n";
|
||||
tcpp << "\t\treturn 0;\n";
|
||||
tcpp << "\t}\n\n";
|
||||
|
||||
tcpp << "\tif (code < 0x" << QString("%1").arg(min3, 0, 16).toUpper().toUtf8().constData() << "U || code > 0x" << QString("%1").arg(max3, 0, 16).toUpper().toUtf8().constData() << "U) return 0;\n\n";
|
||||
tcpp << "\tif (code < 0x" << QString("%1").arg(min2, 0, 16).toUpper().toUtf8().constData() << "U || code > 0x" << QString("%1").arg(max2, 0, 16).toUpper().toUtf8().constData() << "U) return 0;\n\n";
|
||||
tcpp << "\tswitch (code) {\n";
|
||||
for (; i != e; ++i) {
|
||||
tcpp << "\tcase 0x" << QString("%1").arg(i->code, 0, 16).toUpper().toUtf8().constData() << "U: return &emojis[" << (index++) << "];\n";
|
||||
|
||||
@@ -26,6 +26,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "mainwidget.h"
|
||||
#include <libexif/exif-data.h>
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
bool quiting = false;
|
||||
|
||||
@@ -114,7 +116,7 @@ namespace App {
|
||||
bool loggedOut() {
|
||||
Window *w(wnd());
|
||||
if (w) {
|
||||
w->tempDirDelete();
|
||||
w->tempDirDelete(Local::ClearManagerAll);
|
||||
w->notifyClearFast();
|
||||
w->setupIntro(true);
|
||||
}
|
||||
@@ -170,7 +172,7 @@ namespace App {
|
||||
switch (online) {
|
||||
case -2: {
|
||||
QDate yesterday(date(now).date());
|
||||
yesterday.addDays(-1);
|
||||
yesterday.addDays(-3);
|
||||
return int32(QDateTime(yesterday).toTime_t());
|
||||
} break;
|
||||
|
||||
@@ -207,7 +209,11 @@ namespace App {
|
||||
return dNow.secsTo(dTomorrow);
|
||||
}
|
||||
|
||||
QString onlineText(int32 online, int32 now, bool precise) {
|
||||
QString onlineText(UserData *user, int32 now, bool precise) {
|
||||
if (isServiceUser(user->id)) {
|
||||
return lang(lng_status_service_notifications);
|
||||
}
|
||||
int32 online = user->onlineTill;
|
||||
if (online <= 0) {
|
||||
switch (online) {
|
||||
case 0: return lang(lng_status_offline);
|
||||
@@ -337,7 +343,7 @@ namespace App {
|
||||
data->input = MTP_inputPeerForeign(d.vid, d.vaccess_hash);
|
||||
data->inputUser = MTP_inputUserForeign(d.vid, d.vaccess_hash);
|
||||
data->setPhone(qs(d.vphone));
|
||||
data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), (data->id != 333000 && !data->phone.isEmpty()) ? formatPhone(data->phone) : QString(), textOneLine(qs(d.vusername)));
|
||||
data->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), (!isServiceUser(data->id) && !data->phone.isEmpty()) ? formatPhone(data->phone) : QString(), textOneLine(qs(d.vusername)));
|
||||
data->setPhoto(d.vphoto);
|
||||
data->access = d.vaccess_hash.v;
|
||||
wasContact = (data->contact > 0);
|
||||
@@ -683,7 +689,7 @@ namespace App {
|
||||
App::main()->removeContact(user);
|
||||
}
|
||||
}
|
||||
user->setName(textOneLine(user->firstName), textOneLine(user->lastName), (user->contact || user->id == 333000 || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone), textOneLine(user->username));
|
||||
user->setName(textOneLine(user->firstName), textOneLine(user->lastName), (user->contact || isServiceUser(user->id) || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone), textOneLine(user->username));
|
||||
if (App::main()) App::main()->peerUpdated(user);
|
||||
}
|
||||
}
|
||||
@@ -1103,7 +1109,6 @@ namespace App {
|
||||
result = new ImageLinkData(imageLink);
|
||||
imageLinksData.insert(imageLink, result);
|
||||
result->type = type;
|
||||
result->openl = TextLinkPtr(new TextLink(url));
|
||||
} else {
|
||||
result = i.value();
|
||||
}
|
||||
@@ -1655,7 +1660,7 @@ namespace App {
|
||||
}
|
||||
QByteArray encrypted(16 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data
|
||||
hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data());
|
||||
aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 16, fullSize, &MTP::localKey(), encrypted.constData());
|
||||
aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 16, fullSize, &Local::oldKey(), encrypted.constData());
|
||||
|
||||
DEBUG_LOG(("App Info: writing user config file"));
|
||||
QDataStream configStream(&configFile);
|
||||
@@ -1706,7 +1711,7 @@ namespace App {
|
||||
}
|
||||
|
||||
cSetLocalSalt(salt);
|
||||
MTP::createLocalKey(QByteArray(), &salt);
|
||||
Local::createOldKey(&salt);
|
||||
|
||||
if (data.size() <= 16 || (data.size() & 0x0F)) {
|
||||
LOG(("App Error: bad encrypted part size: %1").arg(data.size()));
|
||||
@@ -1715,7 +1720,7 @@ namespace App {
|
||||
uint32 fullDataLen = data.size() - 16;
|
||||
decrypted.resize(fullDataLen);
|
||||
const char *dataKey = data.constData(), *encrypted = data.constData() + 16;
|
||||
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &MTP::localKey(), dataKey);
|
||||
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &Local::oldKey(), dataKey);
|
||||
uchar sha1Buffer[20];
|
||||
if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), dataKey, 16)) {
|
||||
LOG(("App Error: bad decrypt key, data from user-config not decrypted"));
|
||||
@@ -1942,7 +1947,6 @@ namespace App {
|
||||
::quiting = true;
|
||||
}
|
||||
|
||||
|
||||
QImage readImage(QByteArray data, QByteArray *format) {
|
||||
QByteArray tmpFormat;
|
||||
QImage result;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace App {
|
||||
|
||||
int32 onlineForSort(int32 online, int32 now);
|
||||
int32 onlineWillChangeIn(int32 onlineOnServer, int32 nowOnServer);
|
||||
QString onlineText(int32 onlineOnServer, int32 nowOnServer, bool precise = false);
|
||||
QString onlineText(UserData *user, int32 nowOnServer, bool precise = false);
|
||||
|
||||
void feedUsers(const MTPVector<MTPUser> &users);
|
||||
void feedChats(const MTPVector<MTPChat> &chats);
|
||||
|
||||
@@ -28,6 +28,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "langloaderplain.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
Application *mainApp = 0;
|
||||
FileUploader *uploader = 0;
|
||||
@@ -131,6 +133,7 @@ Application::Application(int &argc, char **argv) : PsApplication(argc, argv),
|
||||
}
|
||||
}
|
||||
|
||||
Local::start();
|
||||
style::startManager();
|
||||
anim::startManager();
|
||||
historyInit();
|
||||
@@ -617,9 +620,11 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
|
||||
}
|
||||
|
||||
void Application::startApp() {
|
||||
Local::ReadMapState state = Local::readMap(QByteArray());
|
||||
|
||||
App::readUserConfig();
|
||||
if (!MTP::localKey().created()) {
|
||||
MTP::createLocalKey(QByteArray());
|
||||
if (!Local::oldKey().created()) {
|
||||
Local::createOldKey();
|
||||
cSetNeedConfigResave(true);
|
||||
}
|
||||
if (cNeedConfigResave()) {
|
||||
@@ -765,6 +770,7 @@ Application::~Application() {
|
||||
delete window;
|
||||
|
||||
style::stopManager();
|
||||
Local::stop();
|
||||
}
|
||||
|
||||
Application *Application::app() {
|
||||
|
||||
@@ -80,6 +80,8 @@ signals:
|
||||
void peerPhotoDone(PeerId peer);
|
||||
void peerPhotoFail(PeerId peer);
|
||||
|
||||
void adjustSingleTimers();
|
||||
|
||||
public slots:
|
||||
|
||||
void startUpdateCheck(bool forceWait = false);
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 35 KiB |
BIN
Telegram/SourceFiles/art/icon128.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
Telegram/SourceFiles/art/icon128@2x.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
Telegram/SourceFiles/art/icon16.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/SourceFiles/art/icon16@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/SourceFiles/art/icon2.ico
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
Telegram/SourceFiles/art/icon256.ico
Normal file
|
After Width: | Height: | Size: 361 KiB |
BIN
Telegram/SourceFiles/art/icon256.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
Telegram/SourceFiles/art/icon256@2x.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Telegram/SourceFiles/art/icon32.ico
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
Telegram/SourceFiles/art/icon32.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/SourceFiles/art/icon32@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Telegram/SourceFiles/art/icon48.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/SourceFiles/art/icon48@2x.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Telegram/SourceFiles/art/icon512.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Telegram/SourceFiles/art/icon512@2x.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
Telegram/SourceFiles/art/icon64.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Telegram/SourceFiles/art/icon64@2x.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 655 B |
|
Before Width: | Height: | Size: 361 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 361 KiB |
|
Before Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 96 KiB |
@@ -118,7 +118,7 @@ AddParticipantInner::ContactData *AddParticipantInner::contactData(DialogRow *ro
|
||||
data->inchat = _chat->participants.constFind(user) != _chat->participants.cend();
|
||||
data->check = false;
|
||||
data->name.setText(st::profileListNameFont, user->name, _textNameOptions);
|
||||
data->online = App::onlineText(user->onlineTill, _time);
|
||||
data->online = App::onlineText(user, _time);
|
||||
} else {
|
||||
data = i.value();
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) {
|
||||
if (i == _contactsData.cend()) {
|
||||
_contactsData.insert(user, data = new ContactData());
|
||||
data->name.setText(st::profileListNameFont, user->name, _textNameOptions);
|
||||
data->online = App::onlineText(user->onlineTill, _time);
|
||||
data->online = App::onlineText(user, _time);
|
||||
} else {
|
||||
data = i.value();
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ NewGroupInner::ContactData *NewGroupInner::contactData(DialogRow *row) {
|
||||
_contactsData.insert(user, data = new ContactData());
|
||||
data->check = false;
|
||||
data->name.setText(st::profileListNameFont, user->name, _textNameOptions);
|
||||
data->online = App::onlineText(user->onlineTill, _time);
|
||||
data->online = App::onlineText(user, _time);
|
||||
} else {
|
||||
data = i.value();
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
static const int32 AppVersion = 6010;
|
||||
static const wchar_t *AppVersionStr = L"0.6.10";
|
||||
static const int32 AppVersion = 6013;
|
||||
static const wchar_t *AppVersionStr = L"0.6.13";
|
||||
|
||||
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
|
||||
static const wchar_t *AppName = L"Telegram Desktop";
|
||||
@@ -101,8 +101,16 @@ enum {
|
||||
|
||||
MaxMessageSize = 4096,
|
||||
MaxHttpRedirects = 5, // when getting external data/images
|
||||
|
||||
WriteMapTimeout = 1000,
|
||||
SaveDraftTimeout = 1000, // save draft after 1 secs of not changing text
|
||||
SaveDraftAnywayTimeout = 5000, // or save anyway each 5 secs
|
||||
};
|
||||
|
||||
inline bool isServiceUser(uint64 id) {
|
||||
return (id == 333000) || (id == 777000);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
inline const GUID &cGUID() {
|
||||
static const GUID gGuid = { 0x87a94ab0, 0xe370, 0x4cde, { 0x98, 0xd3, 0xac, 0xc1, 0x10, 0xc5, 0x96, 0x7d } };
|
||||
|
||||
@@ -227,7 +227,7 @@ QString FlatTextarea::getText(int32 start, int32 end) const {
|
||||
uint32 index = imageName.mid(8).toUInt(0, 16);
|
||||
const EmojiData *emoji = getEmoji(index);
|
||||
if (emoji) {
|
||||
emojiText.reserve(emoji->len);
|
||||
emojiText.reserve(emoji->len + (emoji->postfix ? 1 : 0));
|
||||
switch (emoji->len) {
|
||||
case 1: emojiText.append(QChar(emoji->code & 0xFFFF)); break;
|
||||
case 2:
|
||||
@@ -241,6 +241,7 @@ QString FlatTextarea::getText(int32 start, int32 end) const {
|
||||
emojiText.append(QChar(emoji->code2 & 0xFFFF));
|
||||
break;
|
||||
}
|
||||
if (emoji->postfix) emojiText.append(QChar(emoji->postfix));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,7 +296,7 @@ void FlatTextarea::insertEmoji(EmojiPtr emoji, QTextCursor c) {
|
||||
}
|
||||
|
||||
void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
||||
int32 emojiPosition = 0;
|
||||
int32 emojiPosition = 0, emojiLen = 0;
|
||||
const EmojiData *emoji = 0;
|
||||
|
||||
QTextDocument *doc(document());
|
||||
@@ -317,13 +318,14 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
||||
|
||||
QString t(fragment.text());
|
||||
for (const QChar *ch = t.constData(), *e = ch + t.size(); ch != e; ++ch) {
|
||||
if (ch + 1 < e && (ch->isHighSurrogate() || (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3) || (ch + 1)->unicode() == 0xFE0F)) {
|
||||
if (ch + 1 < e && (ch->isHighSurrogate() || (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3))) {
|
||||
emoji = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
|
||||
if (emoji) {
|
||||
if (emoji->len == 4 && (ch + 3 >= e || ((uint32((ch + 2)->unicode()) << 16) | uint32((ch + 3)->unicode())) != emoji->code2)) {
|
||||
emoji = 0;
|
||||
} else {
|
||||
emojiPosition = p + (ch - t.constData());
|
||||
emojiLen = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -332,6 +334,7 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
||||
emoji = getEmoji(ch->unicode());
|
||||
if (emoji) {
|
||||
emojiPosition = p + (ch - t.constData());
|
||||
emojiLen = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -342,7 +345,7 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
||||
}
|
||||
if (emoji) {
|
||||
QTextCursor c(doc->docHandle(), emojiPosition);
|
||||
c.setPosition(emojiPosition + emoji->len, QTextCursor::KeepAnchor);
|
||||
c.setPosition(emojiPosition + emojiLen, QTextCursor::KeepAnchor);
|
||||
int32 removedUpto = c.position();
|
||||
|
||||
insertEmoji(emoji, c);
|
||||
|
||||
@@ -29,18 +29,9 @@ namespace {
|
||||
return img;
|
||||
}
|
||||
|
||||
typedef QMap<QByteArray, StorageImage*> StorageImages;
|
||||
typedef QMap<StorageKey, StorageImage*> StorageImages;
|
||||
StorageImages storageImages;
|
||||
|
||||
QByteArray storageKey(int32 dc, const int64 &volume, int32 local, const int64 &secret) {
|
||||
QByteArray result(24, Qt::Uninitialized);
|
||||
memcpy(result.data(), &dc, 4);
|
||||
memcpy(result.data() + 4, &volume, 8);
|
||||
memcpy(result.data() + 12, &local, 4);
|
||||
memcpy(result.data() + 16, &secret, 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
int64 globalAquiredSize = 0;
|
||||
}
|
||||
|
||||
@@ -480,7 +471,7 @@ bool StorageImage::loaded() const {
|
||||
}
|
||||
|
||||
StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) {
|
||||
QByteArray key(storageKey(dc, volume, local, secret));
|
||||
StorageKey key(storageKey(dc, volume, local));
|
||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
||||
if (i == storageImages.cend()) {
|
||||
i = storageImages.insert(key, new StorageImage(width, height, dc, volume, local, secret, size));
|
||||
@@ -489,7 +480,7 @@ StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume,
|
||||
}
|
||||
|
||||
StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes) {
|
||||
QByteArray key(storageKey(dc, volume, local, secret));
|
||||
StorageKey key(storageKey(dc, volume, local));
|
||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
||||
if (i == storageImages.cend()) {
|
||||
QByteArray bytesArr(bytes);
|
||||
|
||||
@@ -53,6 +53,13 @@ public:
|
||||
void forget() const;
|
||||
void restore() const;
|
||||
|
||||
QByteArray savedFormat() const {
|
||||
return format;
|
||||
}
|
||||
QByteArray savedData() const {
|
||||
return saved;
|
||||
}
|
||||
|
||||
virtual ~Image() {
|
||||
invalidateSizeCache();
|
||||
}
|
||||
@@ -106,6 +113,24 @@ private:
|
||||
LocalImage *getImage(const QString &file);
|
||||
LocalImage *getImage(const QPixmap &pixmap, QByteArray format);
|
||||
|
||||
typedef QPair<uint64, uint64> StorageKey;
|
||||
inline uint64 storageMix32To64(int32 a, int32 b) {
|
||||
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
|
||||
}
|
||||
inline StorageKey storageKey(int32 dc, const int64 &volume, int32 local) {
|
||||
return StorageKey(storageMix32To64(dc, local), volume);
|
||||
}
|
||||
inline StorageKey storageKey(const MTPDfileLocation &location) {
|
||||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
||||
}
|
||||
struct StorageImageSaved {
|
||||
StorageImageSaved() : type(mtpc_storage_fileUnknown) {
|
||||
}
|
||||
StorageImageSaved(mtpTypeId type, const QByteArray &data) : type(type), data(data) {
|
||||
}
|
||||
mtpTypeId type;
|
||||
QByteArray data;
|
||||
};
|
||||
class StorageImage : public Image {
|
||||
public:
|
||||
|
||||
@@ -123,7 +148,7 @@ public:
|
||||
void load(bool loadFirst = false, bool prior = true) {
|
||||
if (loader) {
|
||||
loader->start(loadFirst, prior);
|
||||
check();
|
||||
if (loader) check();
|
||||
}
|
||||
}
|
||||
void checkload() const {
|
||||
@@ -131,7 +156,7 @@ public:
|
||||
if (!loader->loading()) {
|
||||
loader->start(true);
|
||||
}
|
||||
check();
|
||||
if (loader) check();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -563,12 +563,6 @@ public:
|
||||
ch = *ptr;
|
||||
chInt = (chInt << 16) | 0x20E3;
|
||||
}
|
||||
} else if (ptr + 1 < end && (ptr + 1)->unicode() == 0xFE0F) { // check for 32bit not surrogate emoji
|
||||
_t->_text.push_back(ch);
|
||||
skipBack = -1;
|
||||
++ptr;
|
||||
ch = *ptr;
|
||||
chInt = (chInt << 16) | 0xFE0F;
|
||||
}
|
||||
|
||||
lastSkipped = skip;
|
||||
@@ -602,8 +596,13 @@ public:
|
||||
_t->_text.push_back(*++ptr);
|
||||
}
|
||||
}
|
||||
int emojiLen = e->len;
|
||||
if (ptr + 1 < end && (ptr + 1)->unicode() == 0xFE0F) {
|
||||
_t->_text.push_back(*++ptr);
|
||||
++emojiLen;
|
||||
}
|
||||
|
||||
createBlock(-e->len);
|
||||
createBlock(-emojiLen);
|
||||
emoji = e;
|
||||
}
|
||||
|
||||
@@ -4045,18 +4044,30 @@ bool textSplit(QString &sendingText, QString &leftText, int32 limit) {
|
||||
}
|
||||
}
|
||||
}
|
||||
EmojiPtr e = 0;
|
||||
if (ch->isHighSurrogate()) {
|
||||
if (ch + 1 < end && (ch + 1)->isLowSurrogate()) {
|
||||
++ch;
|
||||
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
|
||||
if (!e) {
|
||||
++ch;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ch + 1 < end && ((((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3) || (ch + 1)->unicode() == 0xFE0F)) {
|
||||
if (getEmoji((ch->unicode() << 16) | (ch + 1)->unicode())) {
|
||||
++ch;
|
||||
++s;
|
||||
if (ch + 1 < end) {
|
||||
if (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3) {
|
||||
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
|
||||
} else if ((ch + 1)->unicode() == 0xFE0F) {
|
||||
e = getEmoji(ch->unicode());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e) {
|
||||
ch += (e->len - 1);
|
||||
if (ch + 1 < end && (ch + 1)->unicode() == 0xFE0F) {
|
||||
++ch;
|
||||
++s;
|
||||
}
|
||||
}
|
||||
if (s >= limit) {
|
||||
sendingText = leftText.mid(0, good - start);
|
||||
leftText = leftText.mid(good - start);
|
||||
|
||||
@@ -27,6 +27,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "gui/filedialog.h"
|
||||
|
||||
#include "audio.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
TextParseOptions _textNameOptions = {
|
||||
0, // flags
|
||||
@@ -2132,6 +2133,10 @@ const QString HistoryPhoto::inDialogsText() const {
|
||||
return lang(lng_in_dlg_photo);
|
||||
}
|
||||
|
||||
const QString HistoryPhoto::inHistoryText() const {
|
||||
return qsl("[ ") + lang(lng_in_dlg_photo) + qsl(" ]");
|
||||
}
|
||||
|
||||
bool HistoryPhoto::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
return (x >= 0 && y >= 0 && x < width && y < _height);
|
||||
@@ -2149,6 +2154,40 @@ HistoryMedia *HistoryPhoto::clone() const {
|
||||
return new HistoryPhoto(*this);
|
||||
}
|
||||
|
||||
void HistoryPhoto::updateFrom(const MTPMessageMedia &media) {
|
||||
if (media.type() == mtpc_messageMediaPhoto) {
|
||||
const MTPPhoto &photo(media.c_messageMediaPhoto().vphoto);
|
||||
if (photo.type() == mtpc_photo) {
|
||||
const QVector<MTPPhotoSize> &sizes(photo.c_photo().vsizes.c_vector().v);
|
||||
for (QVector<MTPPhotoSize>::const_iterator i = sizes.cbegin(), e = sizes.cend(); i != e; ++i) {
|
||||
char size = 0;
|
||||
const MTPFileLocation *loc = 0;
|
||||
switch (i->type()) {
|
||||
case mtpc_photoSize: {
|
||||
const string &s(i->c_photoSize().vtype.c_string().v);
|
||||
loc = &i->c_photoSize().vlocation;
|
||||
if (s.size()) size = s[0];
|
||||
} break;
|
||||
|
||||
case mtpc_photoCachedSize: {
|
||||
const string &s(i->c_photoCachedSize().vtype.c_string().v);
|
||||
loc = &i->c_photoSize().vlocation;
|
||||
if (s.size()) size = s[0];
|
||||
} break;
|
||||
}
|
||||
if (!loc || loc->type() != mtpc_fileLocation) continue;
|
||||
if (size == 's') {
|
||||
Local::writeImage(storageKey(loc->c_fileLocation()), data->thumb);
|
||||
} else if (size == 'm') {
|
||||
Local::writeImage(storageKey(loc->c_fileLocation()), data->medium);
|
||||
} else if (size == 'x') {
|
||||
Local::writeImage(storageKey(loc->c_fileLocation()), data->full);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryPhoto::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
data->full->load(false, false);
|
||||
@@ -2314,6 +2353,10 @@ const QString HistoryVideo::inDialogsText() const {
|
||||
return lang(lng_in_dlg_video);
|
||||
}
|
||||
|
||||
const QString HistoryVideo::inHistoryText() const {
|
||||
return qsl("[ ") + lang(lng_in_dlg_video) + qsl(" ]");
|
||||
}
|
||||
|
||||
bool HistoryVideo::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
if (width >= _maxw) {
|
||||
@@ -2611,6 +2654,10 @@ const QString HistoryAudio::inDialogsText() const {
|
||||
return lang(lng_in_dlg_audio);
|
||||
}
|
||||
|
||||
const QString HistoryAudio::inHistoryText() const {
|
||||
return qsl("[ ") + lang(lng_in_dlg_audio) + qsl(" ]");
|
||||
}
|
||||
|
||||
bool HistoryAudio::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
if (width >= _maxw) {
|
||||
@@ -2862,6 +2909,10 @@ const QString HistoryDocument::inDialogsText() const {
|
||||
return data->name.isEmpty() ? lang(lng_in_dlg_document) : data->name;
|
||||
}
|
||||
|
||||
const QString HistoryDocument::inHistoryText() const {
|
||||
return qsl("[ ") + lang(lng_in_dlg_document) + (data->name.isEmpty() ? QString() : (qsl(" : ") + data->name)) + qsl(" ]");
|
||||
}
|
||||
|
||||
bool HistoryDocument::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
if (width >= _maxw) {
|
||||
@@ -2962,6 +3013,10 @@ const QString HistoryContact::inDialogsText() const {
|
||||
return lang(lng_in_dlg_contact);
|
||||
}
|
||||
|
||||
const QString HistoryContact::inHistoryText() const {
|
||||
return qsl("[ ") + lang(lng_in_dlg_contact) + qsl(" : ") + name.original(0, 0xFFFF, false) + qsl(", ") + phone + qsl(" ]");
|
||||
}
|
||||
|
||||
bool HistoryContact::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
return (x >= 0 && y <= 0 && x < w && y < _height);
|
||||
@@ -3060,9 +3115,10 @@ void HistoryContact::updateFrom(const MTPMessageMedia &media) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
QRegularExpression reYouTube1(qsl("^(https?://)?(www\\.)?youtube\\.com/watch\\?v=([a-z0-9_-]+)(&|$)"), QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression reYouTube2(qsl("^(https?://)?(www\\.)?youtu\\.be/([a-z0-9_-]+)(\\?|$)"), QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression reInstagram(qsl("^(https?://)?(www\\.)?instagram\\.com/p/([a-z0-9_-]+)(/|$)"), QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression reYouTube1(qsl("^(https?://)?(www\\.|m\\.)?youtube\\.com/watch\\?([^#]+&)?v=([a-z0-9_-]+)(&[^\\s]*)?$"), QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression reYouTube2(qsl("^(https?://)?(www\\.)?youtu\\.be/([a-z0-9_-]+)([/\\?][^\\s]*)?$"), QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression reInstagram(qsl("^(https?://)?(www\\.)?instagram\\.com/p/([a-z0-9_-]+)([/\\?][^\\s]*)?$"), QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression reVimeo(qsl("^(https?://)?(www\\.)?vimeo\\.com/([0-9]+)([/\\?][^\\s]*)?$"), QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
ImageLinkManager manager;
|
||||
}
|
||||
@@ -3128,6 +3184,11 @@ void ImageLinkManager::getData(ImageLinkData *data) {
|
||||
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
|
||||
dataLoadings[reply] = data;
|
||||
} break;
|
||||
case VimeoLink: {
|
||||
url = qsl("https://vimeo.com/api/v2/video/") + data->id.mid(6) + qsl(".json");
|
||||
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
|
||||
dataLoadings[reply] = data;
|
||||
} break;
|
||||
case InstagramLink: {
|
||||
//url = qsl("https://api.instagram.com/oembed?url=http://instagr.am/p/") + data->id.mid(10) + '/';
|
||||
url = qsl("https://instagram.com/p/") + data->id.mid(10) + qsl("/media/?size=l");
|
||||
@@ -3207,9 +3268,9 @@ void ImageLinkManager::onFinished(QNetworkReply *reply) {
|
||||
DEBUG_LOG(("JSON Error: Bad json received in onFinished() for image link"));
|
||||
return onFailed(reply);
|
||||
}
|
||||
QJsonObject obj = doc.object();
|
||||
switch (d->type) {
|
||||
case YouTubeLink: {
|
||||
QJsonObject obj = doc.object();
|
||||
QString thumb;
|
||||
int32 seconds = 0;
|
||||
QJsonObject::const_iterator entryIt = obj.constFind(qsl("entry"));
|
||||
@@ -3305,6 +3366,39 @@ void ImageLinkManager::onFinished(QNetworkReply *reply) {
|
||||
imageLoadings.insert(manager->get(QNetworkRequest(thumb)), d);
|
||||
}
|
||||
} break;
|
||||
|
||||
case VimeoLink: {
|
||||
QString thumb;
|
||||
int32 seconds = 0;
|
||||
QJsonArray arr = doc.array();
|
||||
if (!arr.isEmpty()) {
|
||||
QJsonObject obj = arr.at(0).toObject();
|
||||
QJsonObject::const_iterator titleIt = obj.constFind(qsl("title"));
|
||||
if (titleIt != obj.constEnd() && titleIt.value().isString()) {
|
||||
d->title = titleIt.value().toString();
|
||||
}
|
||||
QJsonObject::const_iterator thumbnailsIt = obj.constFind(qsl("thumbnail_large"));
|
||||
if (thumbnailsIt != obj.constEnd() && thumbnailsIt.value().isString()) {
|
||||
thumb = thumbnailsIt.value().toString();
|
||||
}
|
||||
QJsonObject::const_iterator secondsIt = obj.constFind(qsl("duration"));
|
||||
if (secondsIt != obj.constEnd()) {
|
||||
if (secondsIt.value().isDouble()) {
|
||||
seconds = qRound(secondsIt.value().toDouble());
|
||||
} else if (secondsIt.value().isString()) {
|
||||
seconds = qRound(secondsIt.value().toString().toDouble());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (seconds > 0) {
|
||||
d->duration = formatDurationText(seconds);
|
||||
}
|
||||
if (thumb.isEmpty()) {
|
||||
failed(d);
|
||||
} else {
|
||||
imageLoadings.insert(manager->get(QNetworkRequest(thumb)), d);
|
||||
}
|
||||
} break;
|
||||
|
||||
case InstagramLink: failed(d); break;
|
||||
case GoogleMapsLink: failed(d); break;
|
||||
@@ -3373,19 +3467,33 @@ void ImageLinkData::load() {
|
||||
|
||||
HistoryImageLink::HistoryImageLink(const QString &url, int32 width) : HistoryMedia(width) {
|
||||
if (url.startsWith(qsl("location:"))) {
|
||||
data = App::imageLink(url, GoogleMapsLink, qsl("https://maps.google.com/maps?q=") + url.mid(9) + qsl("&ll=") + url.mid(9) + qsl("&z=17"));
|
||||
QString lnk = qsl("https://maps.google.com/maps?q=") + url.mid(9) + qsl("&ll=") + url.mid(9) + qsl("&z=17");
|
||||
link.reset(new TextLink(lnk));
|
||||
|
||||
data = App::imageLink(url, GoogleMapsLink, lnk);
|
||||
} else {
|
||||
link.reset(new TextLink(url));
|
||||
|
||||
int matchIndex = 4;
|
||||
QRegularExpressionMatch m = reYouTube1.match(url);
|
||||
if (!m.hasMatch()) m = reYouTube2.match(url);
|
||||
if (!m.hasMatch()) {
|
||||
m = reYouTube2.match(url);
|
||||
matchIndex = 3;
|
||||
}
|
||||
if (m.hasMatch()) {
|
||||
data = App::imageLink(qsl("youtube:") + m.captured(3), YouTubeLink, url);
|
||||
data = App::imageLink(qsl("youtube:") + m.captured(matchIndex), YouTubeLink, url);
|
||||
} else {
|
||||
m = reInstagram.match(url);
|
||||
m = reVimeo.match(url);
|
||||
if (m.hasMatch()) {
|
||||
data = App::imageLink(qsl("instagram:") + m.captured(3), InstagramLink, url);
|
||||
data->title = qsl("instagram.com/p/") + m.captured(3);
|
||||
data = App::imageLink(qsl("vimeo:") + m.captured(3), VimeoLink, url);
|
||||
} else {
|
||||
data = 0;
|
||||
m = reInstagram.match(url);
|
||||
if (m.hasMatch()) {
|
||||
data = App::imageLink(qsl("instagram:") + m.captured(3), InstagramLink, url);
|
||||
data->title = qsl("instagram.com/p/") + m.captured(3);
|
||||
} else {
|
||||
data = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3395,6 +3503,7 @@ int32 HistoryImageLink::fullWidth() const {
|
||||
if (data) {
|
||||
switch (data->type) {
|
||||
case YouTubeLink: return 640;
|
||||
case VimeoLink: return 640;
|
||||
case InstagramLink: return 640;
|
||||
case GoogleMapsLink: return st::locationSize.width();
|
||||
}
|
||||
@@ -3406,6 +3515,7 @@ int32 HistoryImageLink::fullHeight() const {
|
||||
if (data) {
|
||||
switch (data->type) {
|
||||
case YouTubeLink: return 480;
|
||||
case VimeoLink: return 480;
|
||||
case InstagramLink: return 640;
|
||||
case GoogleMapsLink: return st::locationSize.height();
|
||||
}
|
||||
@@ -3460,7 +3570,7 @@ void HistoryImageLink::draw(QPainter &p, const HistoryItem *parent, bool selecte
|
||||
if (data) {
|
||||
switch (data->type) {
|
||||
case YouTubeLink: p.drawPixmap(QPoint((width - st::youtubeIcon.pxWidth()) / 2, (_height - st::youtubeIcon.pxHeight()) / 2), App::sprite(), st::youtubeIcon); break;
|
||||
// case InstagramLink: p.drawPixmap(QPoint((width - st::instagramIcon.pxWidth()) / 2, (_height - st::instagramIcon.pxHeight()) / 2), App::sprite(), st::instagramIcon); break;
|
||||
case VimeoLink: p.drawPixmap(QPoint((width - st::youtubeIcon.pxWidth()) / 2, (_height - st::youtubeIcon.pxHeight()) / 2), App::sprite(), st::vimeoIcon); break;
|
||||
}
|
||||
if (!data->title.isEmpty() || !data->duration.isEmpty()) {
|
||||
p.fillRect(0, 0, width, st::msgDateFont->height + 2 * st::msgDateImgPadding.y(), st::msgDateImgBg->b);
|
||||
@@ -3545,6 +3655,7 @@ const QString HistoryImageLink::inDialogsText() const {
|
||||
if (data) {
|
||||
switch (data->type) {
|
||||
case YouTubeLink: return qsl("YouTube Video");
|
||||
case VimeoLink: return qsl("Vimeo Video");
|
||||
case InstagramLink: return qsl("Instagram Link");
|
||||
case GoogleMapsLink: return lang(lng_maps_point);
|
||||
}
|
||||
@@ -3552,6 +3663,18 @@ const QString HistoryImageLink::inDialogsText() const {
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QString HistoryImageLink::inHistoryText() const {
|
||||
if (data) {
|
||||
switch (data->type) {
|
||||
case YouTubeLink: return qsl("[ YouTube Video : ") + link->text() + qsl(" ]");
|
||||
case VimeoLink: return qsl("[ Vimeo Video : ") + link->text() + qsl(" ]");
|
||||
case InstagramLink: return qsl("[ Instagram Link : ") + link->text() + qsl(" ]");
|
||||
case GoogleMapsLink: return qsl("[ ") + lang(lng_maps_point) + qsl(" : ") + link->text() + qsl(" ]");
|
||||
}
|
||||
}
|
||||
return qsl("[ Link : ") + link->text() + qsl(" ]");
|
||||
}
|
||||
|
||||
bool HistoryImageLink::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
return (x >= 0 && y >= 0 && x < width && y < _height);
|
||||
@@ -3560,7 +3683,7 @@ bool HistoryImageLink::hasPoint(int32 x, int32 y, const HistoryItem *parent, int
|
||||
TextLinkPtr HistoryImageLink::getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
if (width < 0) width = w;
|
||||
if (x >= 0 && y >= 0 && x < width && y < _height && data) {
|
||||
return data->openl;
|
||||
return link;
|
||||
}
|
||||
return TextLinkPtr();
|
||||
}
|
||||
@@ -3624,7 +3747,7 @@ void HistoryMessage::initMedia(const MTPMessageMedia &media, QString ¤tTex
|
||||
switch (media.type()) {
|
||||
case mtpc_messageMediaEmpty: {
|
||||
QString lnk = currentText.trimmed();
|
||||
if (reYouTube1.match(currentText).hasMatch() || reYouTube2.match(currentText).hasMatch() || reInstagram.match(currentText).hasMatch()) {
|
||||
if (reYouTube1.match(currentText).hasMatch() || reYouTube2.match(currentText).hasMatch() || reInstagram.match(currentText).hasMatch() || reVimeo.match(currentText).hasMatch()) {
|
||||
_media = new HistoryImageLink(lnk);
|
||||
currentText = QString();
|
||||
}
|
||||
@@ -3705,7 +3828,7 @@ bool HistoryMessage::uploading() const {
|
||||
|
||||
QString HistoryMessage::selectedText(uint32 selection) const {
|
||||
if (_media && selection == FullItemSel) {
|
||||
return _text.original(0, 0xFFFF) + '[' + _media->inDialogsText() + ']';
|
||||
return _text.original(0, 0xFFFF) + _media->inHistoryText();
|
||||
}
|
||||
uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF;
|
||||
uint16 selectedTo = (selection == FullItemSel) ? 0xFFFF : (selection & 0xFFFF);
|
||||
@@ -3849,7 +3972,10 @@ int32 HistoryMessage::resize(int32 width, bool dontRecountText, const HistoryIte
|
||||
|
||||
bool HistoryMessage::hasPoint(int32 x, int32 y) const {
|
||||
int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth;
|
||||
if (_media && _media->maxWidth() > mwidth) mwidth = _media->maxWidth();
|
||||
if (_media) {
|
||||
if (_media->maxWidth() > mwidth) mwidth = _media->maxWidth();
|
||||
if (_media->currentWidth() < mwidth) mwidth = _media->currentWidth();
|
||||
}
|
||||
if (width > mwidth) {
|
||||
if (_out) left += width - mwidth;
|
||||
width = mwidth;
|
||||
@@ -3876,7 +4002,10 @@ void HistoryMessage::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y)
|
||||
lnk = TextLinkPtr();
|
||||
|
||||
int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right(), mwidth = st::msgMaxWidth;
|
||||
if (_media && _media->maxWidth() > mwidth) mwidth = _media->maxWidth();
|
||||
if (_media) {
|
||||
if (_media->maxWidth() > mwidth) mwidth = _media->maxWidth();
|
||||
if (_media->currentWidth() < mwidth) mwidth = _media->currentWidth();
|
||||
}
|
||||
if (width > mwidth) {
|
||||
if (_out) left += width - mwidth;
|
||||
width = mwidth;
|
||||
|
||||
@@ -629,6 +629,34 @@ inline MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
|
||||
return MTPMessagesFilter();
|
||||
}
|
||||
|
||||
struct MessageCursor {
|
||||
MessageCursor() : position(0), anchor(0), scroll(QFIXED_MAX) {
|
||||
}
|
||||
MessageCursor(int position, int anchor, int scroll) : position(position), anchor(anchor), scroll(scroll) {
|
||||
}
|
||||
MessageCursor(const QTextEdit &edit) {
|
||||
fillFrom(edit);
|
||||
}
|
||||
void fillFrom(const QTextEdit &edit) {
|
||||
QTextCursor c = edit.textCursor();
|
||||
position = c.position();
|
||||
anchor = c.anchor();
|
||||
QScrollBar *s = edit.verticalScrollBar();
|
||||
scroll = s ? s->value() : QFIXED_MAX;
|
||||
}
|
||||
void applyTo(QTextEdit &edit, bool *lock = 0) {
|
||||
if (lock) *lock = true;
|
||||
QTextCursor c = edit.textCursor();
|
||||
c.setPosition(anchor, QTextCursor::MoveAnchor);
|
||||
c.setPosition(position, QTextCursor::KeepAnchor);
|
||||
edit.setTextCursor(c);
|
||||
QScrollBar *s = edit.verticalScrollBar();
|
||||
if (s) s->setValue(scroll);
|
||||
if (lock) *lock = false;
|
||||
}
|
||||
int position, anchor, scroll;
|
||||
};
|
||||
|
||||
class HistoryMedia;
|
||||
class HistoryMessage;
|
||||
class HistoryUnreadBar;
|
||||
@@ -732,7 +760,7 @@ struct History : public QList<HistoryBlock*> {
|
||||
}
|
||||
|
||||
QString draft;
|
||||
QTextCursor draftCur;
|
||||
MessageCursor draftCursor;
|
||||
int32 lastWidth, lastScrollTop;
|
||||
bool mute;
|
||||
|
||||
@@ -1223,6 +1251,7 @@ public:
|
||||
|
||||
virtual HistoryMediaType type() const = 0;
|
||||
virtual const QString inDialogsText() const = 0;
|
||||
virtual const QString inHistoryText() const = 0;
|
||||
virtual bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const = 0;
|
||||
virtual int32 countHeight(const HistoryItem *parent, int32 width = -1) const {
|
||||
return height();
|
||||
@@ -1276,6 +1305,7 @@ public:
|
||||
return MediaTypePhoto;
|
||||
}
|
||||
const QString inDialogsText() const;
|
||||
const QString inHistoryText() const;
|
||||
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
HistoryMedia *clone() const;
|
||||
@@ -1284,6 +1314,8 @@ public:
|
||||
return data;
|
||||
}
|
||||
|
||||
void updateFrom(const MTPMessageMedia &media);
|
||||
|
||||
TextLinkPtr lnk() const {
|
||||
return openl;
|
||||
}
|
||||
@@ -1312,6 +1344,7 @@ public:
|
||||
return MediaTypeVideo;
|
||||
}
|
||||
const QString inDialogsText() const;
|
||||
const QString inHistoryText() const;
|
||||
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
bool uploading() const {
|
||||
@@ -1344,6 +1377,7 @@ public:
|
||||
return MediaTypeAudio;
|
||||
}
|
||||
const QString inDialogsText() const;
|
||||
const QString inHistoryText() const;
|
||||
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
bool uploading() const {
|
||||
@@ -1376,6 +1410,7 @@ public:
|
||||
return MediaTypeDocument;
|
||||
}
|
||||
const QString inDialogsText() const;
|
||||
const QString inHistoryText() const;
|
||||
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
int32 countHeight(const HistoryItem *parent, int32 width = -1) const;
|
||||
bool uploading() const {
|
||||
@@ -1418,6 +1453,7 @@ public:
|
||||
return MediaTypeContact;
|
||||
}
|
||||
const QString inDialogsText() const;
|
||||
const QString inHistoryText() const;
|
||||
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const;
|
||||
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const;
|
||||
HistoryMedia *clone() const;
|
||||
@@ -1426,7 +1462,7 @@ public:
|
||||
|
||||
private:
|
||||
int32 userId;
|
||||
int32 w, phonew;
|
||||
int32 phonew;
|
||||
Text name;
|
||||
QString phone;
|
||||
UserData *contact;
|
||||
@@ -1439,6 +1475,7 @@ void deinitImageLinkManager();
|
||||
enum ImageLinkType {
|
||||
InvalidImageLink = 0,
|
||||
YouTubeLink,
|
||||
VimeoLink,
|
||||
InstagramLink,
|
||||
GoogleMapsLink
|
||||
};
|
||||
@@ -1449,7 +1486,6 @@ struct ImageLinkData {
|
||||
QString id;
|
||||
QString title, duration;
|
||||
ImagePtr thumb;
|
||||
TextLinkPtr openl;
|
||||
ImageLinkType type;
|
||||
bool loading;
|
||||
|
||||
@@ -1498,12 +1534,14 @@ public:
|
||||
return MediaTypeImageLink;
|
||||
}
|
||||
const QString inDialogsText() const;
|
||||
const QString inHistoryText() const;
|
||||
bool hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
|
||||
HistoryMedia *clone() const;
|
||||
|
||||
private:
|
||||
ImageLinkData *data;
|
||||
TextLinkPtr link;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "fileuploader.h"
|
||||
#include "supporttl.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
||||
|
||||
HistoryList::HistoryList(HistoryWidget *historyWidget, ScrollArea *scroll, History *history) : QWidget(0)
|
||||
@@ -633,106 +635,98 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
}
|
||||
|
||||
_contextMenuLnk = textlnkOver();
|
||||
if (_contextMenuLnk && dynamic_cast<TextLink*>(_contextMenuLnk.data())) {
|
||||
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
|
||||
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
|
||||
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
|
||||
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
|
||||
if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument) {
|
||||
_menu = new ContextMenu(historyWidget);
|
||||
if (isUponSelected > 0) {
|
||||
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_open_link), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_link), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else if (_contextMenuLnk && dynamic_cast<EmailLink*>(_contextMenuLnk.data())) {
|
||||
_menu = new ContextMenu(historyWidget);
|
||||
if (isUponSelected > 0) {
|
||||
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_open_email), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_email), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else if (_contextMenuLnk && dynamic_cast<HashtagLink*>(_contextMenuLnk.data())) {
|
||||
_menu = new ContextMenu(historyWidget);
|
||||
if (isUponSelected > 0) {
|
||||
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_open_hashtag), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_hashtag), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else {
|
||||
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
|
||||
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
|
||||
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
|
||||
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
|
||||
if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument) {
|
||||
_menu = new ContextMenu(historyWidget);
|
||||
if (isUponSelected > 0) {
|
||||
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
|
||||
}
|
||||
if (lnkPhoto) {
|
||||
_menu->addAction(lang(lng_context_open_image), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_save_image), this, SLOT(saveContextImage()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_image), this, SLOT(copyContextImage()))->setEnabled(true);
|
||||
if (lnkPhoto) {
|
||||
_menu->addAction(lang(lng_context_open_image), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_save_image), this, SLOT(saveContextImage()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_image), this, SLOT(copyContextImage()))->setEnabled(true);
|
||||
} else {
|
||||
if ((lnkVideo && lnkVideo->video()->loader) || (lnkAudio && lnkAudio->audio()->loader) || (lnkDocument && lnkDocument->document()->loader)) {
|
||||
_menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true);
|
||||
} else {
|
||||
if ((lnkVideo && lnkVideo->video()->loader) || (lnkAudio && lnkAudio->audio()->loader) || (lnkDocument && lnkDocument->document()->loader)) {
|
||||
_menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true);
|
||||
} else {
|
||||
if ((lnkVideo && !lnkVideo->video()->already(true).isEmpty()) || (lnkAudio && !lnkAudio->audio()->already(true).isEmpty()) || (lnkDocument && !lnkDocument->document()->already(true).isEmpty())) {
|
||||
_menu->addAction(lang(cPlatform() == dbipMac ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkAudio ? lng_context_open_audio : lng_context_open_document)), this, SLOT(openContextFile()))->setEnabled(true);
|
||||
_menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkAudio ? lng_context_save_audio : lng_context_save_document)), this, SLOT(saveContextFile()))->setEnabled(true);
|
||||
if ((lnkVideo && !lnkVideo->video()->already(true).isEmpty()) || (lnkAudio && !lnkAudio->audio()->already(true).isEmpty()) || (lnkDocument && !lnkDocument->document()->already(true).isEmpty())) {
|
||||
_menu->addAction(lang(cPlatform() == dbipMac ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkAudio ? lng_context_open_audio : lng_context_open_document)), this, SLOT(openContextFile()))->setEnabled(true);
|
||||
_menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkAudio ? lng_context_save_audio : lng_context_save_document)), this, SLOT(saveContextFile()))->setEnabled(true);
|
||||
}
|
||||
if (isUponSelected > 1) {
|
||||
_menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected()));
|
||||
_menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected()));
|
||||
_menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected()));
|
||||
} else if (App::hoveredLinkItem()) {
|
||||
if (isUponSelected != -2) {
|
||||
if (dynamic_cast<HistoryMessage*>(App::hoveredLinkItem())) {
|
||||
_menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
|
||||
App::contextItem(App::hoveredLinkItem());
|
||||
}
|
||||
} else { // maybe cursor on some text history item?
|
||||
HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem();
|
||||
bool canDelete = (item && item->itemType() == HistoryItem::MsgType);
|
||||
bool canForward = canDelete && (item->id > 0) && !item->serviceMsg();
|
||||
|
||||
HistoryMessage *msg = dynamic_cast<HistoryMessage*>(item);
|
||||
HistoryServiceMsg *srv = dynamic_cast<HistoryServiceMsg*>(item);
|
||||
|
||||
if (isUponSelected > 0) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
|
||||
} else if (item && !isUponSelected && !_contextMenuLnk) {
|
||||
QString contextMenuText = item->selectedText(FullItemSel);
|
||||
if (!contextMenuText.isEmpty()) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
_menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (isUponSelected > 1) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
_menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected()));
|
||||
_menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected()));
|
||||
_menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected()));
|
||||
} else {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
if (isUponSelected != -2) {
|
||||
if (canForward) {
|
||||
_menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true);
|
||||
}
|
||||
|
||||
if (canDelete) {
|
||||
_menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true);
|
||||
}
|
||||
}
|
||||
_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
|
||||
}
|
||||
App::contextItem(item);
|
||||
}
|
||||
if (isUponSelected > 1) {
|
||||
_menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected()));
|
||||
_menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected()));
|
||||
_menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected()));
|
||||
} else if (App::hoveredLinkItem()) {
|
||||
if (isUponSelected != -2) {
|
||||
if (dynamic_cast<HistoryMessage*>(App::hoveredLinkItem())) {
|
||||
_menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
|
||||
App::contextItem(App::hoveredLinkItem());
|
||||
}
|
||||
} else { // maybe cursor on some text history item?
|
||||
HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem();
|
||||
bool canDelete = (item && item->itemType() == HistoryItem::MsgType);
|
||||
bool canForward = canDelete && (item->id > 0) && !item->serviceMsg();
|
||||
|
||||
HistoryMessage *msg = dynamic_cast<HistoryMessage*>(item);
|
||||
HistoryServiceMsg *srv = dynamic_cast<HistoryServiceMsg*>(item);
|
||||
|
||||
if (isUponSelected > 0) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
|
||||
} else if (item && !isUponSelected && !_contextMenuLnk) {
|
||||
QString contextMenuText = item->selectedText(FullItemSel);
|
||||
if (!contextMenuText.isEmpty()) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
_menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (_contextMenuLnk && dynamic_cast<TextLink*>(_contextMenuLnk.data())) {
|
||||
if (!_menu) _menu = new ContextMenu(historyWidget);
|
||||
_menu->addAction(lang(lng_context_open_link), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_link), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else if (_contextMenuLnk && dynamic_cast<EmailLink*>(_contextMenuLnk.data())) {
|
||||
if (!_menu) _menu = new ContextMenu(historyWidget);
|
||||
_menu->addAction(lang(lng_context_open_email), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_email), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else if (_contextMenuLnk && dynamic_cast<HashtagLink*>(_contextMenuLnk.data())) {
|
||||
if (!_menu) _menu = new ContextMenu(historyWidget);
|
||||
_menu->addAction(lang(lng_context_open_hashtag), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_hashtag), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else {
|
||||
}
|
||||
if (isUponSelected > 1) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
_menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected()));
|
||||
_menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected()));
|
||||
_menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected()));
|
||||
} else {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
if (isUponSelected != -2) {
|
||||
if (canForward) {
|
||||
_menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true);
|
||||
}
|
||||
|
||||
if (canDelete) {
|
||||
_menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true);
|
||||
}
|
||||
}
|
||||
_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
|
||||
}
|
||||
App::contextItem(item);
|
||||
}
|
||||
|
||||
if (_menu) {
|
||||
_menu->deleteOnHide();
|
||||
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
|
||||
@@ -1535,7 +1529,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
|
||||
, _attachDragDocument(this)
|
||||
, _attachDragPhoto(this)
|
||||
, imageLoader(this)
|
||||
, noTypingUpdate(false)
|
||||
, _synthedTextUpdate(false)
|
||||
, loadingChatId(0)
|
||||
, loadingRequestId(0)
|
||||
, serviceImageCacheSize(0)
|
||||
@@ -1545,7 +1539,9 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
|
||||
, bg(st::msgBG)
|
||||
, hiderOffered(false)
|
||||
, _scrollDelta(0)
|
||||
, _typingRequest(0) {
|
||||
, _typingRequest(0)
|
||||
, _saveDraftStart(0)
|
||||
, _saveDraftText(false) {
|
||||
_scroll.setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
setAcceptDrops(true);
|
||||
@@ -1575,6 +1571,11 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
|
||||
_animActiveTimer.setSingleShot(false);
|
||||
connect(&_animActiveTimer, SIGNAL(timeout()), this, SLOT(onAnimActiveStep()));
|
||||
|
||||
_saveDraftTimer.setSingleShot(true);
|
||||
connect(&_saveDraftTimer, SIGNAL(timeout()), this, SLOT(onDraftSave()));
|
||||
connect(_field.verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onDraftSaveDelayed()));
|
||||
connect(&_field, SIGNAL(cursorPositionChanged()), this, SLOT(onDraftSaveDelayed()));
|
||||
|
||||
_scroll.hide();
|
||||
_scroll.move(0, 0);
|
||||
|
||||
@@ -1605,6 +1606,43 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
|
||||
|
||||
void HistoryWidget::onTextChange() {
|
||||
updateTyping();
|
||||
|
||||
if (!hist || _synthedTextUpdate) return;
|
||||
_saveDraftText = true;
|
||||
onDraftSave(true);
|
||||
}
|
||||
|
||||
void HistoryWidget::onDraftSaveDelayed() {
|
||||
if (!hist || _synthedTextUpdate) return;
|
||||
if (!_field.textCursor().anchor() && !_field.textCursor().position() && !_field.verticalScrollBar()->value()) {
|
||||
if (!Local::hasDraftPositions(hist->peer->id)) return;
|
||||
}
|
||||
onDraftSave(true);
|
||||
}
|
||||
|
||||
void HistoryWidget::onDraftSave(bool delayed) {
|
||||
if (!hist) return;
|
||||
if (delayed) {
|
||||
uint64 ms = getms();
|
||||
if (!_saveDraftStart) {
|
||||
_saveDraftStart = ms;
|
||||
return _saveDraftTimer.start(SaveDraftTimeout);
|
||||
} else if (ms - _saveDraftStart < SaveDraftAnywayTimeout) {
|
||||
return _saveDraftTimer.start(SaveDraftTimeout);
|
||||
}
|
||||
}
|
||||
writeDraft();
|
||||
}
|
||||
|
||||
void HistoryWidget::writeDraft(const QString *text, const MessageCursor *cursor) {
|
||||
bool save = hist && (_saveDraftStart > 0);
|
||||
_saveDraftStart = 0;
|
||||
_saveDraftTimer.stop();
|
||||
if (_saveDraftText) {
|
||||
if (save) Local::writeDraft(hist->peer->id, text ? (*text) : _field.getText());
|
||||
_saveDraftText = false;
|
||||
}
|
||||
if (save) Local::writeDraftPositions(hist->peer->id, cursor ? (*cursor) : MessageCursor(_field));
|
||||
}
|
||||
|
||||
void HistoryWidget::cancelTyping() {
|
||||
@@ -1616,7 +1654,7 @@ void HistoryWidget::cancelTyping() {
|
||||
|
||||
void HistoryWidget::updateTyping(bool typing) {
|
||||
uint64 ms = getms(true) + 10000;
|
||||
if (noTypingUpdate || !hist || (typing && (hist->myTyping + 5000 > ms)) || (!typing && (hist->myTyping + 5000 <= ms))) return;
|
||||
if (_synthedTextUpdate || !hist || (typing && (hist->myTyping + 5000 > ms)) || (!typing && (hist->myTyping + 5000 <= ms))) return;
|
||||
|
||||
hist->myTyping = typing ? ms : 0;
|
||||
cancelTyping();
|
||||
@@ -1725,7 +1763,10 @@ void HistoryWidget::showPeer(const PeerId &peer, MsgId msgId, bool force, bool l
|
||||
}
|
||||
if (hist) {
|
||||
hist->draft = _field.getText();
|
||||
hist->draftCur = _field.textCursor();
|
||||
hist->draftCursor.fillFrom(_field);
|
||||
|
||||
writeDraft(&hist->draft, &hist->draftCursor);
|
||||
|
||||
if (hist->readyForWork() && _scroll.scrollTop() + 1 <= _scroll.scrollTopMax()) {
|
||||
hist->lastWidth = _list->width();
|
||||
} else {
|
||||
@@ -1803,13 +1844,19 @@ void HistoryWidget::showPeer(const PeerId &peer, MsgId msgId, bool force, bool l
|
||||
|
||||
App::main()->peerUpdated(histPeer);
|
||||
|
||||
noTypingUpdate = true;
|
||||
setFieldText(hist->draft);
|
||||
_field.setFocus();
|
||||
if (!hist->draft.isEmpty()) {
|
||||
_field.setTextCursor(hist->draftCur);
|
||||
setFieldText(hist->draft);
|
||||
_field.setFocus();
|
||||
hist->draftCursor.applyTo(_field, &_synthedTextUpdate);
|
||||
} else {
|
||||
QString draft = Local::readDraft(hist->peer->id);
|
||||
setFieldText(draft);
|
||||
_field.setFocus();
|
||||
if (!draft.isEmpty()) {
|
||||
MessageCursor cur = Local::readDraftPositions(hist->peer->id);
|
||||
cur.applyTo(_field, &_synthedTextUpdate);
|
||||
}
|
||||
}
|
||||
noTypingUpdate = false;
|
||||
|
||||
connect(&_scroll, SIGNAL(geometryChanged()), _list, SLOT(onParentGeometryChanged()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), _list, SLOT(onUpdateSelected()));
|
||||
@@ -2223,6 +2270,10 @@ void HistoryWidget::onSend(bool ctrlShiftEnter) {
|
||||
App::main()->sendPreparedText(hist, prepareMessage(_field.getText()));
|
||||
|
||||
setFieldText(QString());
|
||||
_saveDraftText = true;
|
||||
_saveDraftStart = getms();
|
||||
onDraftSave();
|
||||
|
||||
if (!_attachType.isHidden()) _attachType.hideStart();
|
||||
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
|
||||
}
|
||||
@@ -2688,7 +2739,7 @@ void HistoryWidget::updateOnlineDisplay(int32 x, int32 w) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
text = App::onlineText(histPeer->asUser()->onlineTill, t);
|
||||
text = App::onlineText(histPeer->asUser(), t);
|
||||
}
|
||||
if (titlePeerText != text) {
|
||||
titlePeerText = text;
|
||||
@@ -3164,9 +3215,9 @@ void HistoryWidget::onFieldTabbed() {
|
||||
}
|
||||
|
||||
void HistoryWidget::setFieldText(const QString &text) {
|
||||
noTypingUpdate = true;
|
||||
_synthedTextUpdate = true;
|
||||
_field.setPlainText(text);
|
||||
noTypingUpdate = false;
|
||||
_synthedTextUpdate = false;
|
||||
}
|
||||
|
||||
void HistoryWidget::onCancel() {
|
||||
|
||||
@@ -396,6 +396,9 @@ public slots:
|
||||
|
||||
void onAnimActiveStep();
|
||||
|
||||
void onDraftSaveDelayed();
|
||||
void onDraftSave(bool delayed = false);
|
||||
|
||||
private:
|
||||
|
||||
bool messagesFailed(const RPCError &error, mtpRequestId requestId);
|
||||
@@ -404,6 +407,7 @@ private:
|
||||
void addMessagesToBack(const QVector<MTPMessage> &messages);
|
||||
void chatLoaded(const MTPmessages_ChatFull &res);
|
||||
|
||||
void writeDraft(const QString *text = 0, const MessageCursor *cursor = 0);
|
||||
void setFieldText(const QString &text);
|
||||
|
||||
QStringList getMediasFromMime(const QMimeData *d);
|
||||
@@ -440,7 +444,7 @@ private:
|
||||
int32 _selCount; // < 0 - text selected, focus list, not _field
|
||||
|
||||
LocalImageLoader imageLoader;
|
||||
bool noTypingUpdate;
|
||||
bool _synthedTextUpdate;
|
||||
|
||||
PeerId loadingChatId;
|
||||
mtpRequestId loadingRequestId;
|
||||
@@ -470,5 +474,9 @@ private:
|
||||
mtpRequestId _typingRequest;
|
||||
QTimer _typingStopTimer;
|
||||
|
||||
uint64 _saveDraftStart;
|
||||
bool _saveDraftText;
|
||||
QTimer _saveDraftTimer;
|
||||
|
||||
};
|
||||
|
||||
|
||||
988
Telegram/SourceFiles/localstorage.cpp
Normal file
@@ -0,0 +1,988 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop 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.
|
||||
|
||||
It 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.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef quint64 FileKey;
|
||||
|
||||
static const char tdfMagic[] = { 'T', 'D', 'F', '$' };
|
||||
static const int32 tdfMagicLen = sizeof(tdfMagic);
|
||||
|
||||
QString toFilePart(FileKey val) {
|
||||
QString result;
|
||||
result.reserve(0x10);
|
||||
for (int32 i = 0; i < 0x10; ++i) {
|
||||
uchar v = (val & 0x0F);
|
||||
result.push_back((v < 0x0A) ? ('0' + v) : ('A' + (v - 0x0A)));
|
||||
val >>= 4;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FileKey fromFilePart(const QString &val) {
|
||||
FileKey result = 0;
|
||||
int32 i = val.size();
|
||||
if (i != 0x10) return 0;
|
||||
|
||||
while (i > 0) {
|
||||
--i;
|
||||
result <<= 4;
|
||||
|
||||
uint16 ch = val.at(i).unicode();
|
||||
if (ch >= 'A' && ch <= 'F') {
|
||||
result |= (ch - 'A') + 0x0A;
|
||||
} else if (ch >= '0' && ch <= '9') {
|
||||
result |= (ch - '0');
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString _basePath;
|
||||
|
||||
bool _started = false;
|
||||
_local_inner::Manager *_manager = 0;
|
||||
|
||||
bool _working() {
|
||||
return _manager && !_basePath.isEmpty();
|
||||
}
|
||||
|
||||
bool keyAlreadyUsed(QString &name) {
|
||||
name += '0';
|
||||
if (QFileInfo(name).exists()) return true;
|
||||
name[name.size() - 1] = '1';
|
||||
return QFileInfo(name).exists();
|
||||
}
|
||||
|
||||
FileKey genKey() {
|
||||
if (!_working()) return 0;
|
||||
|
||||
FileKey result;
|
||||
QString path;
|
||||
path.reserve(_basePath.size() + 0x11);
|
||||
path += _basePath;
|
||||
do {
|
||||
result = MTP::nonce<FileKey>();
|
||||
path.resize(_basePath.size());
|
||||
path += toFilePart(result);
|
||||
} while (keyAlreadyUsed(path));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void clearKey(const FileKey &key, bool safe = true) {
|
||||
if (!_working()) return;
|
||||
|
||||
QString name;
|
||||
name.reserve(_basePath.size() + 0x11);
|
||||
name += _basePath;
|
||||
name += toFilePart(key);
|
||||
name += '0';
|
||||
QFile::remove(name);
|
||||
if (safe) {
|
||||
name[name.size() - 1] = '1';
|
||||
QFile::remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray _passKeySalt, _passKeyEncrypted;
|
||||
|
||||
mtpAuthKey _oldKey, _passKey, _localKey;
|
||||
void createLocalKey(const QByteArray &pass, QByteArray *salt, mtpAuthKey *result) {
|
||||
uchar key[LocalEncryptKeySize] = { 0 };
|
||||
int32 iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password
|
||||
QByteArray newSalt;
|
||||
if (!salt) {
|
||||
newSalt.resize(LocalEncryptSaltSize);
|
||||
memset_rand(newSalt.data(), newSalt.size());
|
||||
salt = &newSalt;
|
||||
|
||||
cSetLocalSalt(newSalt);
|
||||
}
|
||||
|
||||
PKCS5_PBKDF2_HMAC_SHA1(pass.constData(), pass.size(), (uchar*)salt->data(), salt->size(), iterCount, LocalEncryptKeySize, key);
|
||||
|
||||
result->setKey(key);
|
||||
}
|
||||
|
||||
struct FileReadDescriptor {
|
||||
FileReadDescriptor() : version(0) {
|
||||
}
|
||||
int32 version;
|
||||
QByteArray data;
|
||||
QBuffer buffer;
|
||||
QDataStream stream;
|
||||
~FileReadDescriptor() {
|
||||
if (version) {
|
||||
stream.setDevice(0);
|
||||
if (buffer.isOpen()) buffer.close();
|
||||
buffer.setBuffer(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct EncryptedDescriptor {
|
||||
EncryptedDescriptor() {
|
||||
}
|
||||
EncryptedDescriptor(uint32 size) {
|
||||
uint32 fullSize = sizeof(uint32) + size;
|
||||
if (fullSize & 0x0F) fullSize += 0x10 - (fullSize & 0x0F);
|
||||
data.reserve(fullSize);
|
||||
|
||||
data.resize(sizeof(uint32));
|
||||
buffer.setBuffer(&data);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
buffer.seek(sizeof(uint32));
|
||||
stream.setDevice(&buffer);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
}
|
||||
QByteArray data;
|
||||
QBuffer buffer;
|
||||
QDataStream stream;
|
||||
void finish() {
|
||||
if (stream.device()) stream.setDevice(0);
|
||||
if (buffer.isOpen()) buffer.close();
|
||||
buffer.setBuffer(0);
|
||||
}
|
||||
~EncryptedDescriptor() {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
struct FileWriteDescriptor {
|
||||
FileWriteDescriptor(const FileKey &key, bool safe = true) : dataSize(0) {
|
||||
init(toFilePart(key), safe);
|
||||
}
|
||||
FileWriteDescriptor(const QString &name, bool safe = true) : dataSize(0) {
|
||||
init(name, safe);
|
||||
}
|
||||
void init(const QString &name, bool safe) {
|
||||
if (!_working()) return;
|
||||
|
||||
// detect order of read attempts and file version
|
||||
QString toTry[2];
|
||||
toTry[0] = _basePath + name + '0';
|
||||
if (safe) {
|
||||
toTry[1] = _basePath + name + '1';
|
||||
QFileInfo toTry0(toTry[0]);
|
||||
QFileInfo toTry1(toTry[1]);
|
||||
if (toTry0.exists()) {
|
||||
if (toTry1.exists()) {
|
||||
QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified();
|
||||
if (mod0 > mod1) {
|
||||
qSwap(toTry[0], toTry[1]);
|
||||
}
|
||||
} else {
|
||||
qSwap(toTry[0], toTry[1]);
|
||||
}
|
||||
toDelete = toTry[1];
|
||||
} else if (toTry1.exists()) {
|
||||
toDelete = toTry[1];
|
||||
}
|
||||
}
|
||||
|
||||
file.setFileName(toTry[0]);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(tdfMagic, tdfMagicLen);
|
||||
qint32 version = AppVersion;
|
||||
file.write((const char*)&version, sizeof(version));
|
||||
|
||||
stream.setDevice(&file);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
}
|
||||
}
|
||||
bool writeData(const QByteArray &data) {
|
||||
if (!file.isOpen()) return false;
|
||||
|
||||
stream << data;
|
||||
quint32 len = data.isNull() ? 0xffffffff : data.size();
|
||||
if (QSysInfo::ByteOrder != QSysInfo::BigEndian) {
|
||||
len = qbswap(len);
|
||||
}
|
||||
md5.feed(&len, sizeof(len));
|
||||
md5.feed(data.constData(), data.size());
|
||||
dataSize += sizeof(len) + data.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
QByteArray prepareEncrypted(EncryptedDescriptor &data, const mtpAuthKey &key = _localKey) {
|
||||
data.finish();
|
||||
QByteArray &toEncrypt(data.data);
|
||||
|
||||
// prepare for encryption
|
||||
uint32 size = toEncrypt.size(), fullSize = size;
|
||||
if (fullSize & 0x0F) {
|
||||
fullSize += 0x10 - (fullSize & 0x0F);
|
||||
toEncrypt.resize(fullSize);
|
||||
memset_rand(toEncrypt.data() + size, fullSize - size);
|
||||
}
|
||||
*(uint32*)toEncrypt.data() = size;
|
||||
QByteArray encrypted(0x10 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data
|
||||
hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data());
|
||||
aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 0x10, fullSize, &key, encrypted.constData());
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
bool writeEncrypted(EncryptedDescriptor &data, const mtpAuthKey &key = _localKey) {
|
||||
return writeData(prepareEncrypted(data, key));
|
||||
}
|
||||
void finish() {
|
||||
if (!file.isOpen()) return;
|
||||
|
||||
stream.setDevice(0);
|
||||
|
||||
md5.feed(&dataSize, sizeof(dataSize));
|
||||
qint32 version = AppVersion;
|
||||
md5.feed(&version, sizeof(version));
|
||||
md5.feed(tdfMagic, tdfMagicLen);
|
||||
file.write((const char*)md5.result(), 0x10);
|
||||
file.close();
|
||||
|
||||
if (!toDelete.isEmpty()) {
|
||||
QFile::remove(toDelete);
|
||||
}
|
||||
}
|
||||
QFile file;
|
||||
QDataStream stream;
|
||||
|
||||
QString toDelete;
|
||||
|
||||
HashMd5 md5;
|
||||
int32 dataSize;
|
||||
|
||||
~FileWriteDescriptor() {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
bool readFile(FileReadDescriptor &result, const QString &name, bool safe = true) {
|
||||
if (!_working()) return false;
|
||||
|
||||
// detect order of read attempts
|
||||
QString toTry[2];
|
||||
toTry[0] = _basePath + name + '0';
|
||||
if (safe) {
|
||||
QFileInfo toTry0(toTry[0]);
|
||||
if (toTry0.exists()) {
|
||||
toTry[1] = _basePath + name + '1';
|
||||
QFileInfo toTry1(toTry[1]);
|
||||
if (toTry1.exists()) {
|
||||
QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified();
|
||||
if (mod0 < mod1) {
|
||||
qSwap(toTry[0], toTry[1]);
|
||||
}
|
||||
} else {
|
||||
toTry[1] = QString();
|
||||
}
|
||||
} else {
|
||||
toTry[0][toTry[0].size() - 1] = '1';
|
||||
}
|
||||
}
|
||||
for (int32 i = 0; i < 2; ++i) {
|
||||
QString fname(toTry[i]);
|
||||
if (fname.isEmpty()) break;
|
||||
|
||||
QFile f(fname);
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
DEBUG_LOG(("App Info: failed to open '%1' for reading").arg(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
// check magic
|
||||
char magic[tdfMagicLen];
|
||||
if (f.read(magic, tdfMagicLen) != tdfMagicLen) {
|
||||
DEBUG_LOG(("App Info: failed to read magic from '%1'").arg(name));
|
||||
continue;
|
||||
}
|
||||
if (memcmp(magic, tdfMagic, tdfMagicLen)) {
|
||||
DEBUG_LOG(("App Info: bad magic %1 in '%2'").arg(mb(magic, tdfMagicLen).str()).arg(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
// read app version
|
||||
qint32 version;
|
||||
if (f.read((char*)&version, sizeof(version)) != sizeof(version)) {
|
||||
DEBUG_LOG(("App Info: failed to read version from '%1'").arg(name));
|
||||
continue;
|
||||
}
|
||||
if (version > AppVersion) {
|
||||
DEBUG_LOG(("App Info: version too big %1 for '%2', my version %3").arg(version).arg(name).arg(AppVersion));
|
||||
continue;
|
||||
}
|
||||
|
||||
// read data
|
||||
QByteArray bytes = f.read(f.size());
|
||||
int32 dataSize = bytes.size() - 16;
|
||||
if (dataSize < 0) {
|
||||
DEBUG_LOG(("App Info: bad file '%1', could not read sign part").arg(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
// check signature
|
||||
HashMd5 md5;
|
||||
md5.feed(bytes.constData(), dataSize);
|
||||
md5.feed(&dataSize, sizeof(dataSize));
|
||||
md5.feed(&version, sizeof(version));
|
||||
md5.feed(magic, tdfMagicLen);
|
||||
if (memcmp(md5.result(), bytes.constData() + dataSize, 16)) {
|
||||
DEBUG_LOG(("App Info: bad file '%1', signature did not match").arg(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
bytes.resize(dataSize);
|
||||
result.data = bytes;
|
||||
bytes = QByteArray();
|
||||
|
||||
result.version = version;
|
||||
result.buffer.setBuffer(&result.data);
|
||||
result.buffer.open(QIODevice::ReadOnly);
|
||||
result.stream.setDevice(&result.buffer);
|
||||
result.stream.setVersion(QDataStream::Qt_5_1);
|
||||
|
||||
if ((i == 0 && !toTry[1].isEmpty()) || i == 1) {
|
||||
QFile::remove(toTry[1 - i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, const mtpAuthKey &key = _localKey) {
|
||||
if (encrypted.size() <= 16 || (encrypted.size() & 0x0F)) {
|
||||
LOG(("App Error: bad encrypted part size: %1").arg(encrypted.size()));
|
||||
return false;
|
||||
}
|
||||
uint32 fullLen = encrypted.size() - 16;
|
||||
|
||||
QByteArray decrypted;
|
||||
decrypted.resize(fullLen);
|
||||
const char *encryptedKey = encrypted.constData(), *encryptedData = encrypted.constData() + 16;
|
||||
aesDecryptLocal(encryptedData, decrypted.data(), fullLen, &key, encryptedKey);
|
||||
uchar sha1Buffer[20];
|
||||
if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), encryptedKey, 16)) {
|
||||
LOG(("App Error: bad decrypt key, data not decrypted"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 dataLen = *(const uint32*)decrypted.constData();
|
||||
if (dataLen > uint32(decrypted.size()) || dataLen <= fullLen - 16 || dataLen < sizeof(uint32)) {
|
||||
LOG(("App Error: bad decrypted part size: %1, fullLen: %2, decrypted size: %3").arg(dataLen).arg(fullLen).arg(decrypted.size()));
|
||||
return false;
|
||||
}
|
||||
|
||||
decrypted.resize(dataLen);
|
||||
result.data = decrypted;
|
||||
decrypted = QByteArray();
|
||||
|
||||
result.buffer.setBuffer(&result.data);
|
||||
result.buffer.open(QIODevice::ReadOnly);
|
||||
result.buffer.seek(sizeof(uint32)); // skip len
|
||||
result.stream.setDevice(&result.buffer);
|
||||
result.stream.setVersion(QDataStream::Qt_5_1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readEncryptedFile(FileReadDescriptor &result, const QString &name, bool safe = true) {
|
||||
if (!readFile(result, name, safe)) {
|
||||
return false;
|
||||
}
|
||||
QByteArray encrypted;
|
||||
result.stream >> encrypted;
|
||||
|
||||
EncryptedDescriptor data;
|
||||
if (!decryptLocal(data, encrypted)) {
|
||||
result.stream.setDevice(0);
|
||||
if (result.buffer.isOpen()) result.buffer.close();
|
||||
result.buffer.setBuffer(0);
|
||||
result.data = QByteArray();
|
||||
result.version = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
result.stream.setDevice(0);
|
||||
if (result.buffer.isOpen()) result.buffer.close();
|
||||
result.buffer.setBuffer(0);
|
||||
result.data = data.data;
|
||||
result.buffer.setBuffer(&result.data);
|
||||
result.buffer.open(QIODevice::ReadOnly);
|
||||
result.buffer.seek(data.buffer.pos());
|
||||
result.stream.setDevice(&result.buffer);
|
||||
result.stream.setVersion(QDataStream::Qt_5_1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum { // Local Storage Keys
|
||||
lskUserMap = 0,
|
||||
lskDraft, // data: PeerId peer
|
||||
lskDraftPosition, // data: PeerId peer
|
||||
lskStorage, // data: StorageKey location
|
||||
};
|
||||
|
||||
typedef QMap<PeerId, FileKey> DraftsMap;
|
||||
DraftsMap _draftsMap, _draftsPositionsMap;
|
||||
typedef QMap<PeerId, bool> DraftsNotReadMap;
|
||||
DraftsNotReadMap _draftsNotReadMap;
|
||||
|
||||
typedef QPair<FileKey, qint32> FileDesc; // file, size
|
||||
typedef QMap<StorageKey, FileDesc> StorageMap;
|
||||
StorageMap _storageMap;
|
||||
int32 _storageFilesSize = 0;
|
||||
|
||||
bool _mapChanged = false;
|
||||
|
||||
Local::ReadMapState _readMap(const QByteArray &pass) {
|
||||
uint64 ms = getms();
|
||||
QByteArray dataNameUtf8 = cDataFile().toUtf8();
|
||||
uint64 dataNameHash[2];
|
||||
hashMd5(dataNameUtf8.constData(), dataNameUtf8.size(), dataNameHash);
|
||||
_basePath = cWorkingDir() + qsl("tdata/") + toFilePart(dataNameHash[0]) + QChar('/');
|
||||
|
||||
FileReadDescriptor mapData;
|
||||
if (!readFile(mapData, qsl("map"))) {
|
||||
return Local::ReadMapFailed;
|
||||
}
|
||||
|
||||
QByteArray salt, keyEncrypted, mapEncrypted;
|
||||
mapData.stream >> salt >> keyEncrypted >> mapEncrypted;
|
||||
if (mapData.stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: could not read salt / key from map file - corrupted?..").arg(mapData.stream.status()));
|
||||
return Local::ReadMapFailed;
|
||||
}
|
||||
if (salt.size() != LocalEncryptSaltSize) {
|
||||
LOG(("App Error: bad salt in map file, size: %1").arg(salt.size()));
|
||||
return Local::ReadMapFailed;
|
||||
}
|
||||
createLocalKey(pass, &salt, &_passKey);
|
||||
|
||||
EncryptedDescriptor keyData, map;
|
||||
if (!decryptLocal(keyData, keyEncrypted, _passKey)) {
|
||||
LOG(("App Error: could not decrypt pass-protected key from map file, maybe bad password.."));
|
||||
return Local::ReadMapPassNeeded;
|
||||
}
|
||||
uchar key[LocalEncryptKeySize] = { 0 };
|
||||
if (keyData.stream.readRawData((char*)key, LocalEncryptKeySize) != LocalEncryptKeySize || !keyData.stream.atEnd()) {
|
||||
LOG(("App Error: could not read pass-protected key from map file"));
|
||||
return Local::ReadMapFailed;
|
||||
}
|
||||
_localKey.setKey(key);
|
||||
|
||||
_passKeyEncrypted = keyEncrypted;
|
||||
_passKeySalt = salt;
|
||||
|
||||
if (!decryptLocal(map, mapEncrypted)) {
|
||||
LOG(("App Error: could not decrypt map."));
|
||||
return Local::ReadMapFailed;
|
||||
}
|
||||
|
||||
DraftsMap draftsMap, draftsPositionsMap;
|
||||
DraftsNotReadMap draftsNotReadMap;
|
||||
StorageMap storageMap;
|
||||
qint64 storageFilesSize = 0;
|
||||
while (!map.stream.atEnd()) {
|
||||
quint32 keyType;
|
||||
map.stream >> keyType;
|
||||
switch (keyType) {
|
||||
case lskDraft: {
|
||||
quint32 count = 0;
|
||||
map.stream >> count;
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
FileKey key;
|
||||
quint64 p;
|
||||
map.stream >> key >> p;
|
||||
draftsMap.insert(p, key);
|
||||
draftsNotReadMap.insert(p, true);
|
||||
}
|
||||
} break;
|
||||
case lskDraftPosition: {
|
||||
quint32 count = 0;
|
||||
map.stream >> count;
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
FileKey key;
|
||||
quint64 p;
|
||||
map.stream >> key >> p;
|
||||
draftsPositionsMap.insert(p, key);
|
||||
}
|
||||
} break;
|
||||
case lskStorage: {
|
||||
quint32 count = 0;
|
||||
map.stream >> count;
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
FileKey key;
|
||||
quint64 first, second;
|
||||
qint32 size;
|
||||
map.stream >> key >> first >> second >> size;
|
||||
storageMap.insert(StorageKey(first, second), FileDesc(key, size));
|
||||
storageFilesSize += size;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
|
||||
return Local::ReadMapFailed;
|
||||
}
|
||||
if (map.stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: reading encrypted map bad status: %1").arg(map.stream.status()));
|
||||
return Local::ReadMapFailed;
|
||||
}
|
||||
}
|
||||
_draftsMap = draftsMap;
|
||||
_draftsPositionsMap = draftsPositionsMap;
|
||||
_draftsNotReadMap = draftsNotReadMap;
|
||||
_storageMap = storageMap;
|
||||
_storageFilesSize = storageFilesSize;
|
||||
_mapChanged = false;
|
||||
LOG(("Map read time: %1").arg(getms() - ms));
|
||||
return Local::ReadMapDone;
|
||||
}
|
||||
|
||||
enum WriteMapWhen {
|
||||
WriteMapNow,
|
||||
WriteMapFast,
|
||||
WriteMapSoon,
|
||||
};
|
||||
void _writeMap(WriteMapWhen when = WriteMapSoon) {
|
||||
if (when != WriteMapNow) {
|
||||
_manager->writeMap(when == WriteMapFast);
|
||||
return;
|
||||
}
|
||||
_manager->writingMap();
|
||||
if (!_mapChanged) return;
|
||||
if (_basePath.isEmpty()) {
|
||||
LOG(("App Error: _basePath is empty in writeMap()"));
|
||||
return;
|
||||
}
|
||||
|
||||
QDir().mkpath(_basePath);
|
||||
|
||||
FileWriteDescriptor map(qsl("map"));
|
||||
if (_passKeySalt.isEmpty() || _passKeyEncrypted.isEmpty()) {
|
||||
uchar local5Key[LocalEncryptKeySize] = { 0 };
|
||||
QByteArray pass(LocalEncryptKeySize, Qt::Uninitialized), salt(LocalEncryptSaltSize, Qt::Uninitialized);
|
||||
memset_rand(pass.data(), pass.size());
|
||||
memset_rand(salt.data(), salt.size());
|
||||
createLocalKey(pass, &salt, &_localKey);
|
||||
|
||||
_passKeySalt.resize(LocalEncryptSaltSize);
|
||||
memset_rand(_passKeySalt.data(), _passKeySalt.size());
|
||||
createLocalKey(QByteArray(), &_passKeySalt, &_passKey);
|
||||
|
||||
EncryptedDescriptor passKeyData(LocalEncryptKeySize);
|
||||
_localKey.write(passKeyData.stream);
|
||||
_passKeyEncrypted = map.prepareEncrypted(passKeyData, _passKey);
|
||||
}
|
||||
map.writeData(_passKeySalt);
|
||||
map.writeData(_passKeyEncrypted);
|
||||
|
||||
uint32 mapSize = 0;
|
||||
if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
|
||||
if (!_draftsPositionsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsPositionsMap.size() * sizeof(quint64) * 2;
|
||||
if (!_storageMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _storageMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
|
||||
EncryptedDescriptor mapData(mapSize);
|
||||
if (!_draftsMap.isEmpty()) {
|
||||
mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size());
|
||||
for (DraftsMap::const_iterator i = _draftsMap.cbegin(), e = _draftsMap.cend(); i != e; ++i) {
|
||||
mapData.stream << quint64(i.value()) << quint64(i.key());
|
||||
}
|
||||
}
|
||||
if (!_draftsPositionsMap.isEmpty()) {
|
||||
mapData.stream << quint32(lskDraftPosition) << quint32(_draftsPositionsMap.size());
|
||||
for (DraftsMap::const_iterator i = _draftsPositionsMap.cbegin(), e = _draftsPositionsMap.cend(); i != e; ++i) {
|
||||
mapData.stream << quint64(i.value()) << quint64(i.key());
|
||||
}
|
||||
}
|
||||
if (!_storageMap.isEmpty()) {
|
||||
mapData.stream << quint32(lskStorage) << quint32(_storageMap.size());
|
||||
for (StorageMap::const_iterator i = _storageMap.cbegin(), e = _storageMap.cend(); i != e; ++i) {
|
||||
mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second);
|
||||
}
|
||||
}
|
||||
map.writeEncrypted(mapData);
|
||||
|
||||
map.finish();
|
||||
|
||||
_mapChanged = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace _local_inner {
|
||||
|
||||
Manager::Manager() {
|
||||
_mapWriteTimer.setSingleShot(true);
|
||||
connect(&_mapWriteTimer, SIGNAL(timeout()), this, SLOT(mapWriteTimeout()));
|
||||
}
|
||||
|
||||
void Manager::writeMap(bool fast) {
|
||||
if (!_mapWriteTimer.isActive() || fast) {
|
||||
_mapWriteTimer.start(fast ? 1 : WriteMapTimeout);
|
||||
} else if (_mapWriteTimer.remainingTime() <= 0) {
|
||||
mapWriteTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::writingMap() {
|
||||
_mapWriteTimer.stop();
|
||||
}
|
||||
|
||||
void Manager::mapWriteTimeout() {
|
||||
_writeMap(WriteMapNow);
|
||||
}
|
||||
|
||||
void Manager::finish() {
|
||||
if (_mapWriteTimer.isActive()) {
|
||||
mapWriteTimeout();
|
||||
_mapWriteTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Local {
|
||||
|
||||
mtpAuthKey &oldKey() {
|
||||
return _oldKey;
|
||||
}
|
||||
|
||||
void createOldKey(QByteArray *salt) {
|
||||
createLocalKey(QByteArray(), salt, &_oldKey);
|
||||
}
|
||||
|
||||
void start() {
|
||||
if (!_started) {
|
||||
_started = true;
|
||||
_manager = new _local_inner::Manager();
|
||||
}
|
||||
}
|
||||
|
||||
void stop() {
|
||||
if (_manager) {
|
||||
_writeMap(WriteMapNow);
|
||||
_manager->finish();
|
||||
_manager->deleteLater();
|
||||
_manager = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ReadMapState readMap(const QByteArray &pass) {
|
||||
ReadMapState result = _readMap(pass);
|
||||
if (result == ReadMapFailed) {
|
||||
_mapChanged = true;
|
||||
_writeMap(WriteMapNow);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void writeDraft(const PeerId &peer, const QString &text) {
|
||||
if (!_working()) return;
|
||||
|
||||
if (text.isEmpty()) {
|
||||
DraftsMap::iterator i = _draftsMap.find(peer);
|
||||
if (i != _draftsMap.cend()) {
|
||||
clearKey(i.value());
|
||||
_draftsMap.erase(i);
|
||||
_mapChanged = true;
|
||||
_writeMap();
|
||||
}
|
||||
|
||||
_draftsNotReadMap.remove(peer);
|
||||
} else {
|
||||
DraftsMap::const_iterator i = _draftsMap.constFind(peer);
|
||||
if (i == _draftsMap.cend()) {
|
||||
i = _draftsMap.insert(peer, genKey());
|
||||
_mapChanged = true;
|
||||
_writeMap(WriteMapFast);
|
||||
}
|
||||
QString to = _basePath + toFilePart(i.value());
|
||||
EncryptedDescriptor data(sizeof(quint64) + sizeof(quint32) + text.size() * sizeof(QChar));
|
||||
data.stream << quint64(peer) << text;
|
||||
FileWriteDescriptor file(i.value());
|
||||
file.writeEncrypted(data);
|
||||
|
||||
_draftsNotReadMap.remove(peer);
|
||||
}
|
||||
}
|
||||
|
||||
QString readDraft(const PeerId &peer) {
|
||||
if (!_draftsNotReadMap.remove(peer)) return QString();
|
||||
|
||||
DraftsMap::iterator j = _draftsMap.find(peer);
|
||||
if (j == _draftsMap.cend()) {
|
||||
return QString();
|
||||
}
|
||||
FileReadDescriptor draft;
|
||||
if (!readEncryptedFile(draft, toFilePart(j.value()))) {
|
||||
clearKey(j.value());
|
||||
_draftsMap.erase(j);
|
||||
return QString();
|
||||
}
|
||||
|
||||
quint64 draftPeer;
|
||||
QString draftText;
|
||||
draft.stream >> draftPeer >> draftText;
|
||||
return (draftPeer == peer) ? draftText : QString();
|
||||
}
|
||||
|
||||
void writeDraftPositions(const PeerId &peer, const MessageCursor &cur) {
|
||||
if (!_working()) return;
|
||||
|
||||
if (cur.position == 0 && cur.anchor == 0 && cur.scroll == 0) {
|
||||
DraftsMap::iterator i = _draftsPositionsMap.find(peer);
|
||||
if (i != _draftsPositionsMap.cend()) {
|
||||
clearKey(i.value());
|
||||
_draftsPositionsMap.erase(i);
|
||||
_mapChanged = true;
|
||||
_writeMap();
|
||||
}
|
||||
} else {
|
||||
DraftsMap::const_iterator i = _draftsPositionsMap.constFind(peer);
|
||||
if (i == _draftsPositionsMap.cend()) {
|
||||
i = _draftsPositionsMap.insert(peer, genKey());
|
||||
_mapChanged = true;
|
||||
_writeMap(WriteMapFast);
|
||||
}
|
||||
QString to = _basePath + toFilePart(i.value());
|
||||
EncryptedDescriptor data(sizeof(quint64) + sizeof(qint32) * 3);
|
||||
data.stream << quint64(peer) << qint32(cur.position) << qint32(cur.anchor) << qint32(cur.scroll);
|
||||
FileWriteDescriptor file(i.value());
|
||||
file.writeEncrypted(data);
|
||||
}
|
||||
}
|
||||
|
||||
MessageCursor readDraftPositions(const PeerId &peer) {
|
||||
DraftsMap::iterator j = _draftsPositionsMap.find(peer);
|
||||
if (j == _draftsPositionsMap.cend()) {
|
||||
return MessageCursor();
|
||||
}
|
||||
FileReadDescriptor draft;
|
||||
if (!readEncryptedFile(draft, toFilePart(j.value()))) {
|
||||
clearKey(j.value());
|
||||
_draftsPositionsMap.erase(j);
|
||||
return MessageCursor();
|
||||
}
|
||||
|
||||
quint64 draftPeer;
|
||||
qint32 curPosition, curAnchor, curScroll;
|
||||
draft.stream >> draftPeer >> curPosition >> curAnchor >> curScroll;
|
||||
|
||||
return (draftPeer == peer) ? MessageCursor(curPosition, curAnchor, curScroll) : MessageCursor();
|
||||
}
|
||||
|
||||
bool hasDraftPositions(const PeerId &peer) {
|
||||
return (_draftsPositionsMap.constFind(peer) != _draftsPositionsMap.cend());
|
||||
}
|
||||
|
||||
qint32 _storageImageSize(qint32 rawlen) {
|
||||
// fulllen + storagekey + type + len + data
|
||||
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + rawlen;
|
||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
||||
return result;
|
||||
}
|
||||
|
||||
void writeImage(const StorageKey &location, const ImagePtr &image) {
|
||||
if (image->isNull() || !image->loaded()) return;
|
||||
if (_storageMap.constFind(location) != _storageMap.cend()) return;
|
||||
|
||||
QByteArray fmt = image->savedFormat();
|
||||
mtpTypeId format = 0;
|
||||
if (fmt == "JPG") {
|
||||
format = mtpc_storage_fileJpeg;
|
||||
} else if (fmt == "PNG") {
|
||||
format = mtpc_storage_filePng;
|
||||
} else if (fmt == "GIF") {
|
||||
format = mtpc_storage_fileGif;
|
||||
}
|
||||
if (format) {
|
||||
image->forget();
|
||||
writeImage(location, StorageImageSaved(format, image->savedData()), false);
|
||||
}
|
||||
}
|
||||
|
||||
void writeImage(const StorageKey &location, const StorageImageSaved &image, bool overwrite) {
|
||||
if (!_working()) return;
|
||||
|
||||
qint32 size = _storageImageSize(image.data.size());
|
||||
StorageMap::const_iterator i = _storageMap.constFind(location);
|
||||
if (i == _storageMap.cend()) {
|
||||
i = _storageMap.insert(location, FileDesc(genKey(), size));
|
||||
_storageFilesSize += size;
|
||||
_mapChanged = true;
|
||||
_writeMap();
|
||||
} else if (!overwrite) {
|
||||
return;
|
||||
}
|
||||
EncryptedDescriptor data(sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + image.data.size());
|
||||
data.stream << quint64(location.first) << quint64(location.second) << quint32(image.type) << image.data;
|
||||
FileWriteDescriptor file(i.value().first, false);
|
||||
file.writeEncrypted(data);
|
||||
if (i.value().second != size) {
|
||||
_storageFilesSize += size;
|
||||
_storageFilesSize -= i.value().second;
|
||||
_storageMap[location].second = size;
|
||||
}
|
||||
}
|
||||
|
||||
StorageImageSaved readImage(const StorageKey &location) {
|
||||
StorageMap::iterator j = _storageMap.find(location);
|
||||
if (j == _storageMap.cend()) {
|
||||
return StorageImageSaved();
|
||||
}
|
||||
FileReadDescriptor draft;
|
||||
if (!readEncryptedFile(draft, toFilePart(j.value().first), false)) {
|
||||
clearKey(j.value().first, false);
|
||||
_storageFilesSize -= j.value().second;
|
||||
_storageMap.erase(j);
|
||||
return StorageImageSaved();
|
||||
}
|
||||
|
||||
QByteArray imageData;
|
||||
quint64 locFirst, locSecond;
|
||||
quint32 imageType;
|
||||
draft.stream >> locFirst >> locSecond >> imageType >> imageData;
|
||||
|
||||
return (locFirst == location.first && locSecond == location.second) ? StorageImageSaved(imageType, imageData) : StorageImageSaved();
|
||||
}
|
||||
|
||||
int32 hasImages() {
|
||||
return _storageMap.size();
|
||||
}
|
||||
|
||||
qint64 storageFilesSize() {
|
||||
return _storageFilesSize;
|
||||
}
|
||||
|
||||
struct ClearManagerData {
|
||||
QThread *thread;
|
||||
StorageMap images;
|
||||
QMutex mutex;
|
||||
QList<int> tasks;
|
||||
bool working;
|
||||
};
|
||||
|
||||
ClearManager::ClearManager() : data(new ClearManagerData()) {
|
||||
data->thread = new QThread();
|
||||
data->working = true;
|
||||
}
|
||||
|
||||
bool ClearManager::addTask(int task) {
|
||||
QMutexLocker lock(&data->mutex);
|
||||
if (!data->working) return false;
|
||||
|
||||
if (!data->tasks.isEmpty() && (data->tasks.at(0) == ClearManagerAll)) return true;
|
||||
if (task == ClearManagerAll) {
|
||||
data->tasks.clear();
|
||||
} else {
|
||||
if (task & ClearManagerImages) {
|
||||
if (data->images.isEmpty()) {
|
||||
data->images = _storageMap;
|
||||
} else {
|
||||
for (StorageMap::const_iterator i = _storageMap.cbegin(), e = _storageMap.cend(); i != e; ++i) {
|
||||
StorageKey k = i.key();
|
||||
while (data->images.constFind(k) != data->images.cend()) {
|
||||
++k.second;
|
||||
}
|
||||
data->images.insert(k, i.value());
|
||||
}
|
||||
}
|
||||
_storageMap.clear();
|
||||
_storageFilesSize = 0;
|
||||
_mapChanged = true;
|
||||
_writeMap();
|
||||
}
|
||||
for (int32 i = 0, l = data->tasks.size(); i < l; ++i) {
|
||||
if (data->tasks.at(i) == task) return true;
|
||||
}
|
||||
}
|
||||
data->tasks.push_back(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClearManager::hasTask(ClearManagerTask task) {
|
||||
QMutexLocker lock(&data->mutex);
|
||||
if (data->tasks.isEmpty()) return false;
|
||||
if (data->tasks.at(0) == ClearManagerAll) return true;
|
||||
for (int32 i = 0, l = data->tasks.size(); i < l; ++i) {
|
||||
if (data->tasks.at(i) == task) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClearManager::start() {
|
||||
moveToThread(data->thread);
|
||||
connect(data->thread, SIGNAL(started()), this, SLOT(onStart()));
|
||||
data->thread->start();
|
||||
}
|
||||
|
||||
ClearManager::~ClearManager() {
|
||||
data->thread->deleteLater();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void ClearManager::onStart() {
|
||||
while (true) {
|
||||
int task = 0;
|
||||
bool result = false;
|
||||
StorageMap images;
|
||||
{
|
||||
QMutexLocker lock(&data->mutex);
|
||||
if (data->tasks.isEmpty()) {
|
||||
data->working = false;
|
||||
break;
|
||||
}
|
||||
task = data->tasks.at(0);
|
||||
images = data->images;
|
||||
}
|
||||
switch (task) {
|
||||
case ClearManagerAll:
|
||||
result = (QDir(cTempDir()).removeRecursively() && QDir(_basePath).removeRecursively());
|
||||
break;
|
||||
case ClearManagerDownloads:
|
||||
result = QDir(cTempDir()).removeRecursively();
|
||||
break;
|
||||
case ClearManagerImages:
|
||||
for (StorageMap::const_iterator i = images.cbegin(), e = images.cend(); i != e; ++i) {
|
||||
clearKey(i.value().first, false);
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
{
|
||||
QMutexLocker lock(&data->mutex);
|
||||
if (data->tasks.at(0) == task) {
|
||||
data->tasks.pop_front();
|
||||
if (data->tasks.isEmpty()) {
|
||||
data->working = false;
|
||||
}
|
||||
}
|
||||
if (result) {
|
||||
emit succeed(task, data->working ? 0 : this);
|
||||
} else {
|
||||
emit failed(task, data->working ? 0 : this);
|
||||
}
|
||||
if (!data->working) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
102
Telegram/SourceFiles/localstorage.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop 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.
|
||||
|
||||
It 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.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace _local_inner {
|
||||
|
||||
class Manager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Manager();
|
||||
|
||||
void writeMap(bool fast);
|
||||
void writingMap();
|
||||
void finish();
|
||||
|
||||
public slots:
|
||||
|
||||
void mapWriteTimeout();
|
||||
|
||||
private:
|
||||
|
||||
QTimer _mapWriteTimer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Local {
|
||||
|
||||
mtpAuthKey &oldKey();
|
||||
void createOldKey(QByteArray *salt = 0);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
enum ClearManagerTask {
|
||||
ClearManagerAll = 0xFFFF,
|
||||
ClearManagerDownloads = 0x01,
|
||||
ClearManagerImages = 0x02,
|
||||
};
|
||||
|
||||
struct ClearManagerData;
|
||||
class ClearManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClearManager();
|
||||
bool addTask(int task);
|
||||
bool hasTask(ClearManagerTask task);
|
||||
void start();
|
||||
~ClearManager();
|
||||
|
||||
public slots:
|
||||
void onStart();
|
||||
|
||||
signals:
|
||||
void succeed(int task, void *manager);
|
||||
void failed(int task, void *manager);
|
||||
|
||||
private:
|
||||
ClearManagerData *data;
|
||||
|
||||
};
|
||||
|
||||
enum ReadMapState {
|
||||
ReadMapFailed = 0,
|
||||
ReadMapDone = 1,
|
||||
ReadMapPassNeeded = 2,
|
||||
};
|
||||
ReadMapState readMap(const QByteArray &pass);
|
||||
|
||||
void writeDraft(const PeerId &peer, const QString &text);
|
||||
QString readDraft(const PeerId &peer);
|
||||
void writeDraftPositions(const PeerId &peer, const MessageCursor &cur);
|
||||
MessageCursor readDraftPositions(const PeerId &peer);
|
||||
bool hasDraftPositions(const PeerId &peer);
|
||||
|
||||
void writeImage(const StorageKey &location, const ImagePtr &img);
|
||||
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
|
||||
StorageImageSaved readImage(const StorageKey &location);
|
||||
int32 hasImages();
|
||||
qint64 storageFilesSize();
|
||||
|
||||
};
|
||||
@@ -73,7 +73,7 @@ void debugLogWrite(const char *file, int32 line, const QString &v) {
|
||||
(*debugLogStream) << msg;
|
||||
debugLogStream->flush();
|
||||
#ifdef Q_OS_WIN
|
||||
OutputDebugString(reinterpret_cast<const wchar_t *>(msg.utf16()));
|
||||
// OutputDebugString(reinterpret_cast<const wchar_t *>(msg.utf16()));
|
||||
#elif defined Q_OS_MAC
|
||||
objc_outputDebugString(msg);
|
||||
#elif defined Q_OS_LINUX && defined _DEBUG
|
||||
|
||||
@@ -143,7 +143,7 @@ void TopBarWidget::enableShadow(bool enable) {
|
||||
|
||||
void TopBarWidget::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
if (e->rect().top() < st::topBarHeight) {
|
||||
if (e->rect().top() < st::topBarHeight) { // optimize shadow-only drawing
|
||||
p.fillRect(QRect(0, 0, width(), st::topBarHeight), st::topBarBG->b);
|
||||
if (_clearSelection.isHidden()) {
|
||||
p.save();
|
||||
@@ -154,8 +154,6 @@ void TopBarWidget::paintEvent(QPaintEvent *e) {
|
||||
p.setPen(st::btnDefLink.color->p);
|
||||
p.drawText(st::topBarSelectedPos.x(), st::topBarSelectedPos.y() + st::linkFont->ascent, _selStr);
|
||||
}
|
||||
} else {
|
||||
int a = 0; // optimize shadow-only drawing
|
||||
}
|
||||
if (_drawShadow) {
|
||||
p.fillRect(st::titleShadow, st::topBarHeight, width() - st::titleShadow, st::titleShadow, st::titleShadowColor->b);
|
||||
@@ -1734,7 +1732,6 @@ void MainWidget::gotState(const MTPupdates_State &state) {
|
||||
MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived));
|
||||
_lastUpdateTime = getms(true);
|
||||
noUpdatesTimer.start(NoUpdatesTimeout);
|
||||
LOG(("Started no updates timeout, %1").arg(_lastUpdateTime));
|
||||
updInited = true;
|
||||
|
||||
dialogs.loadDialogs();
|
||||
@@ -1752,7 +1749,7 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
|
||||
MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived));
|
||||
_lastUpdateTime = getms(true);
|
||||
noUpdatesTimer.start(NoUpdatesTimeout);
|
||||
LOG(("Started no updates timeout, %1").arg(_lastUpdateTime));
|
||||
|
||||
updInited = true;
|
||||
} break;
|
||||
case mtpc_updates_differenceSlice: {
|
||||
@@ -2000,6 +1997,8 @@ int32 MainWidget::dlgsWidth() const {
|
||||
}
|
||||
|
||||
MainWidget::~MainWidget() {
|
||||
if (App::main() == this) history.showPeer(0, 0, true);
|
||||
|
||||
delete hider;
|
||||
MTP::clearGlobalHandlers();
|
||||
App::deinitMedia(false);
|
||||
@@ -2043,7 +2042,6 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
|
||||
|
||||
_lastUpdateTime = getms(true);
|
||||
noUpdatesTimer.start(NoUpdatesTimeout);
|
||||
LOG(("Started no updates timeout, %1").arg(_lastUpdateTime));
|
||||
|
||||
handleUpdates(updates);
|
||||
} catch(mtpErrorUnexpected &e) { // just some other type
|
||||
|
||||
@@ -273,6 +273,7 @@ void MediaView::onDownload() {
|
||||
if (cur.isEmpty()) {
|
||||
_save.hide();
|
||||
} else {
|
||||
if (!QDir().exists(path)) QDir().mkpath(path);
|
||||
toName = filedialogNextFilename(_doc->name, cur, path);
|
||||
if (toName != cur && !QFile(cur).copy(toName)) {
|
||||
toName = QString();
|
||||
@@ -282,6 +283,7 @@ void MediaView::onDownload() {
|
||||
if (!_photo || !_photo->full->loaded()) {
|
||||
_save.hide();
|
||||
} else {
|
||||
if (!QDir().exists(path)) QDir().mkpath(path);
|
||||
toName = filedialogDefaultName(qsl("photo"), qsl(".jpg"), path);
|
||||
if (!_photo->full->pix().toImage().save(toName, "JPG")) {
|
||||
toName = QString();
|
||||
@@ -468,7 +470,6 @@ void MediaView::showPhoto(PhotoData *photo) {
|
||||
_doc = 0;
|
||||
_zoom = 0;
|
||||
MTP::clearLoaderPriorities();
|
||||
_photo->full->load();
|
||||
_full = -1;
|
||||
_current = QPixmap();
|
||||
_down = OverNone;
|
||||
@@ -490,6 +491,7 @@ void MediaView::showPhoto(PhotoData *photo) {
|
||||
_width = _w;
|
||||
_from = App::user(_photo->user);
|
||||
updateControls();
|
||||
_photo->full->load();
|
||||
if (isHidden()) {
|
||||
psUpdateOverlayed(this);
|
||||
show();
|
||||
|
||||
@@ -18,6 +18,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "stdafx.h"
|
||||
#include "mtp.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
typedef QMap<int32, MTProtoSessionPtr> Sessions;
|
||||
Sessions sessions;
|
||||
@@ -61,8 +63,6 @@ namespace {
|
||||
MTPSessionResetHandler sessionResetHandler = 0;
|
||||
_mtp_internal::RequestResender *resender = 0;
|
||||
|
||||
mtpAuthKey _localKey;
|
||||
|
||||
void importDone(const MTPauth_Authorization &result, mtpRequestId req) {
|
||||
QMutexLocker locker1(&requestByDCLock);
|
||||
|
||||
@@ -564,31 +564,11 @@ namespace _mtp_internal {
|
||||
};
|
||||
|
||||
namespace MTP {
|
||||
mtpAuthKey &localKey() {
|
||||
return _localKey;
|
||||
}
|
||||
|
||||
void createLocalKey(const QByteArray &pass, QByteArray *salt) {
|
||||
uchar key[LocalEncryptKeySize] = { 0 };
|
||||
int32 iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password
|
||||
QByteArray newSalt;
|
||||
if (!salt) {
|
||||
newSalt.resize(LocalEncryptSaltSize);
|
||||
memset_rand(newSalt.data(), newSalt.size());
|
||||
salt = &newSalt;
|
||||
|
||||
cSetLocalSalt(newSalt);
|
||||
}
|
||||
|
||||
PKCS5_PBKDF2_HMAC_SHA1(pass.constData(), pass.size(), (uchar*)salt->data(), salt->size(), iterCount, LocalEncryptKeySize, key);
|
||||
|
||||
_localKey.setKey(key);
|
||||
}
|
||||
|
||||
void start() {
|
||||
unixtimeInit();
|
||||
|
||||
if (!localKey().created()) {
|
||||
if (!Local::oldKey().created()) {
|
||||
LOG(("App Error: trying to start MTP without local key!"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,9 +63,6 @@ namespace _mtp_internal {
|
||||
|
||||
namespace MTP {
|
||||
|
||||
mtpAuthKey &localKey();
|
||||
void createLocalKey(const QByteArray &pass, QByteArray *salt = 0);
|
||||
|
||||
static const uint32 cfg = 1 * _mtp_internal::dcShift; // send(MTPhelp_GetConfig(), MTP::cfg + dc) - for dc enum
|
||||
static const uint32 dld[MTPDownloadSessionsCount] = { // send(req, callbacks, MTP::dld[i] + dc) - for download
|
||||
0x10 * _mtp_internal::dcShift,
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
return _keyId;
|
||||
}
|
||||
|
||||
void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send = true) {
|
||||
void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send = true) const {
|
||||
if (!_isset) throw mtpErrorKeyNotReady(QString("prepareAES(.., %1)").arg(logBool(send)));
|
||||
|
||||
uint32 x = send ? 0 : 8;
|
||||
@@ -112,14 +112,14 @@ inline void aesEncrypt(const void *src, void *dst, uint32 len, void *key, void *
|
||||
AES_ige_encrypt((const uchar*)src, (uchar*)dst, len, &aes, aes_iv, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
inline void aesEncrypt(const void *src, void *dst, uint32 len, mtpAuthKeyPtr authKey, const MTPint128 &msgKey) {
|
||||
inline void aesEncrypt(const void *src, void *dst, uint32 len, const mtpAuthKeyPtr &authKey, const MTPint128 &msgKey) {
|
||||
MTPint256 aesKey, aesIV;
|
||||
authKey->prepareAES(msgKey, aesKey, aesIV);
|
||||
|
||||
return aesEncrypt(src, dst, len, &aesKey, &aesIV);
|
||||
}
|
||||
|
||||
inline void aesEncryptLocal(const void *src, void *dst, uint32 len, mtpAuthKey *authKey, const void *key128) {
|
||||
inline void aesEncryptLocal(const void *src, void *dst, uint32 len, const mtpAuthKey *authKey, const void *key128) {
|
||||
MTPint256 aesKey, aesIV;
|
||||
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);
|
||||
|
||||
@@ -136,14 +136,14 @@ inline void aesDecrypt(const void *src, void *dst, uint32 len, void *key, void *
|
||||
AES_ige_encrypt((const uchar*)src, (uchar*)dst, len, &aes, aes_iv, AES_DECRYPT);
|
||||
}
|
||||
|
||||
inline void aesDecrypt(const void *src, void *dst, uint32 len, mtpAuthKeyPtr authKey, const MTPint128 &msgKey) {
|
||||
inline void aesDecrypt(const void *src, void *dst, uint32 len, const mtpAuthKeyPtr &authKey, const MTPint128 &msgKey) {
|
||||
MTPint256 aesKey, aesIV;
|
||||
authKey->prepareAES(msgKey, aesKey, aesIV, false);
|
||||
|
||||
return aesDecrypt(src, dst, len, &aesKey, &aesIV);
|
||||
}
|
||||
|
||||
inline void aesDecryptLocal(const void *src, void *dst, uint32 len, mtpAuthKey *authKey, const void *key128) {
|
||||
inline void aesDecryptLocal(const void *src, void *dst, uint32 len, const mtpAuthKey *authKey, const void *key128) {
|
||||
MTPint256 aesKey, aesIV;
|
||||
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);
|
||||
|
||||
|
||||
@@ -707,15 +707,6 @@ void MTPautoConnection::tcpSend(mtpBuffer &buffer) {
|
||||
TCP_LOG(("TCP Info: write %1 packet %2 bytes").arg(packetNum).arg(len));
|
||||
|
||||
sock.write((const char*)&buffer[0], len);
|
||||
//int64 b = sock.bytesToWrite();
|
||||
//if (b > 100000) {
|
||||
// int a = 0;
|
||||
//}
|
||||
//sock.flush();
|
||||
//int64 b2 = sock.bytesToWrite();
|
||||
//if (b2 > 0) {
|
||||
// TCP_LOG(("TCP Info: writing many, %1 left to write").arg(b2));
|
||||
//}
|
||||
}
|
||||
|
||||
void MTPautoConnection::httpSend(mtpBuffer &buffer) {
|
||||
@@ -1127,7 +1118,9 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
|
||||
connect(this, SIGNAL(needToReceive()), sessionData->owner(), SLOT(tryToReceive()));
|
||||
connect(this, SIGNAL(stateChanged(qint32)), sessionData->owner(), SLOT(onConnectionStateChange(qint32)));
|
||||
connect(sessionData->owner(), SIGNAL(needToSend()), this, SLOT(tryToSend()));
|
||||
connect(this, SIGNAL(needToSendAsync()), sessionData->owner(), SIGNAL(needToSend()));
|
||||
connect(this, SIGNAL(sessionResetDone()), sessionData->owner(), SLOT(onResetDone()));
|
||||
connect(this, SIGNAL(sendAnythingAsync(quint64)), sessionData->owner(), SLOT(sendAnything(quint64)));
|
||||
}
|
||||
|
||||
void MTProtoConnectionPrivate::onConfigLoaded() {
|
||||
@@ -1415,7 +1408,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
||||
toSendPingId = 0;
|
||||
} else {
|
||||
int32 st = getState();
|
||||
DEBUG_LOG(("MTP Info: trying to send after ping, state: %1").arg(st));
|
||||
DEBUG_LOG(("MTP Info: dc %1 trying to send after ping, state: %2").arg(dc).arg(st));
|
||||
if (st != MTProtoConnection::Connected) {
|
||||
return; // just do nothing, if is not connected yet
|
||||
}
|
||||
@@ -1960,7 +1953,7 @@ void MTProtoConnectionPrivate::handleReceived() {
|
||||
uint32 toAckSize = ackRequestData.size();
|
||||
if (toAckSize) {
|
||||
DEBUG_LOG(("MTP Info: will send %1 acks, ids: %2").arg(toAckSize).arg(logVectorLong(ackRequestData)));
|
||||
sessionData->owner()->sendAnything(MTPAckSendWaiting);
|
||||
emit sendAnythingAsync(MTPAckSendWaiting);
|
||||
}
|
||||
|
||||
bool emitSignal = false;
|
||||
@@ -1988,7 +1981,7 @@ void MTProtoConnectionPrivate::handleReceived() {
|
||||
|
||||
if (!wasConnected) {
|
||||
if (getState() == MTProtoConnection::Connected) {
|
||||
emit sessionData->owner()->needToSendAsync();
|
||||
emit needToSendAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3199,7 +3192,7 @@ void MTProtoConnectionPrivate::authKeyCreated() {
|
||||
|
||||
toSendPingId = MTP::nonce<uint64>(); // get server_salt
|
||||
|
||||
emit sessionData->owner()->needToSendAsync();
|
||||
emit needToSendAsync();
|
||||
|
||||
// disconnect(&pinger, SIGNAL(timeout()), 0, 0);
|
||||
// connect(&pinger, SIGNAL(timeout()), this, SLOT(sendPing()));
|
||||
|
||||
@@ -309,6 +309,8 @@ signals:
|
||||
void needToRestart();
|
||||
void stateChanged(qint32 newState);
|
||||
void sessionResetDone();
|
||||
void needToSendAsync();
|
||||
void sendAnythingAsync(quint64);
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "mtpDC.h"
|
||||
#include "mtp.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
|
||||
MTProtoDCMap gDCs;
|
||||
@@ -65,7 +67,7 @@ namespace {
|
||||
QByteArray data, decrypted;
|
||||
stream >> data;
|
||||
|
||||
if (!MTP::localKey().created()) {
|
||||
if (!Local::oldKey().created()) {
|
||||
LOG(("MTP Error: reading encrypted keys without local key!"));
|
||||
continue;
|
||||
}
|
||||
@@ -77,7 +79,7 @@ namespace {
|
||||
uint32 fullDataLen = data.size() - 16;
|
||||
decrypted.resize(fullDataLen);
|
||||
const char *dataKey = data.constData(), *encrypted = data.constData() + 16;
|
||||
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &MTP::localKey(), dataKey);
|
||||
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &Local::oldKey(), dataKey);
|
||||
uchar sha1Buffer[20];
|
||||
if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), dataKey, 16)) {
|
||||
LOG(("MTP Error: bad decrypt key, data from user-config not decrypted"));
|
||||
@@ -271,7 +273,7 @@ namespace {
|
||||
}
|
||||
QByteArray encrypted(16 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data
|
||||
hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data());
|
||||
aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 16, fullSize, &MTP::localKey(), encrypted.constData());
|
||||
aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 16, fullSize, &Local::oldKey(), encrypted.constData());
|
||||
|
||||
DEBUG_LOG(("MTP Info: keys file opened for writing %1 keys").arg(keysToWrite.size()));
|
||||
QDataStream keysStream(&keysFile);
|
||||
|
||||
@@ -20,6 +20,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "window.h"
|
||||
|
||||
#include "application.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
int32 _priority = 1;
|
||||
@@ -44,9 +45,9 @@ namespace {
|
||||
}
|
||||
|
||||
mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) : prev(0), next(0),
|
||||
priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
|
||||
priority(0), inQueue(false), complete(false), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
|
||||
dc(dc), locationType(0), volume(volume), local(local), secret(secret),
|
||||
id(0), access(0), fileIsOpen(false), size(size), type(MTP_storage_fileUnknown()) {
|
||||
id(0), access(0), fileIsOpen(false), size(size), type(mtpc_storage_fileUnknown) {
|
||||
LoaderQueues::iterator i = queues.find(dc);
|
||||
if (i == queues.cend()) {
|
||||
i = queues.insert(dc, mtpFileLoaderQueue());
|
||||
@@ -55,9 +56,9 @@ id(0), access(0), fileIsOpen(false), size(size), type(MTP_storage_fileUnknown())
|
||||
}
|
||||
|
||||
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size) : prev(0), next(0),
|
||||
priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
|
||||
priority(0), inQueue(false), complete(false), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
|
||||
dc(dc), locationType(locType),
|
||||
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(false), size(size), type(MTP_storage_fileUnknown()) {
|
||||
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(false), size(size), type(mtpc_storage_fileUnknown) {
|
||||
LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
|
||||
if (i == queues.cend()) {
|
||||
i = queues.insert(MTP::dld[0] + dc, mtpFileLoaderQueue());
|
||||
@@ -66,9 +67,9 @@ id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(
|
||||
}
|
||||
|
||||
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size, bool todata) : prev(0), next(0),
|
||||
priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
|
||||
priority(0), inQueue(false), complete(false), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
|
||||
dc(dc), locationType(locType),
|
||||
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(todata), size(size), type(MTP_storage_fileUnknown()) {
|
||||
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(todata), size(size), type(mtpc_storage_fileUnknown) {
|
||||
LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
|
||||
if (i == queues.cend()) {
|
||||
i = queues.insert(MTP::dld[0] + dc, mtpFileLoaderQueue());
|
||||
@@ -85,7 +86,7 @@ bool mtpFileLoader::done() const {
|
||||
}
|
||||
|
||||
mtpTypeId mtpFileLoader::fileType() const {
|
||||
return type.type();
|
||||
return type;
|
||||
}
|
||||
|
||||
const QByteArray &mtpFileLoader::bytes() const {
|
||||
@@ -130,7 +131,7 @@ void mtpFileLoader::loadNext() {
|
||||
void mtpFileLoader::finishFail() {
|
||||
bool started = currentOffset(true) > 0;
|
||||
cancelRequests();
|
||||
type = MTP_storage_fileUnknown();
|
||||
type = mtpc_storage_fileUnknown;
|
||||
complete = true;
|
||||
if (fileIsOpen) {
|
||||
file.close();
|
||||
@@ -186,7 +187,7 @@ bool mtpFileLoader::loadPart() {
|
||||
|
||||
void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRequestId req) {
|
||||
Requests::iterator i = requests.find(req);
|
||||
if (i == requests.cend()) return;
|
||||
if (i == requests.cend()) return loadNext();
|
||||
|
||||
int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize;
|
||||
int32 dcIndex = i.value();
|
||||
@@ -239,7 +240,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
|
||||
return finishFail();
|
||||
}
|
||||
}
|
||||
type = d.vtype;
|
||||
type = d.vtype.type();
|
||||
complete = true;
|
||||
if (fileIsOpen) {
|
||||
file.close();
|
||||
@@ -249,10 +250,13 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
|
||||
removeFromQueue();
|
||||
App::wnd()->update();
|
||||
App::wnd()->notifyUpdateAllPhotos();
|
||||
|
||||
if (!queue->queries && dcIndex) {
|
||||
App::app()->killDownloadSessionsStart(dc);
|
||||
}
|
||||
|
||||
if (!locationType && triedLocal && (fname.isEmpty() || duplicateInData)) {
|
||||
Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(type, data));
|
||||
}
|
||||
}
|
||||
emit progress(this);
|
||||
loadNext();
|
||||
@@ -287,12 +291,38 @@ void mtpFileLoader::pause() {
|
||||
|
||||
void mtpFileLoader::start(bool loadFirst, bool prior) {
|
||||
if (complete) return;
|
||||
if (!locationType && !triedLocal) {
|
||||
triedLocal = true;
|
||||
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
|
||||
if (cached.type != mtpc_storage_fileUnknown) {
|
||||
data = cached.data;
|
||||
if (!fname.isEmpty() && duplicateInData) {
|
||||
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
|
||||
if (!fileIsOpen) {
|
||||
return finishFail();
|
||||
}
|
||||
if (file.write(data) != qint64(data.size())) {
|
||||
return finishFail();
|
||||
}
|
||||
}
|
||||
type = cached.type;
|
||||
complete = true;
|
||||
if (fileIsOpen) {
|
||||
file.close();
|
||||
fileIsOpen = false;
|
||||
psPostprocessFile(QFileInfo(file).absoluteFilePath());
|
||||
}
|
||||
App::wnd()->update();
|
||||
App::wnd()->notifyUpdateAllPhotos();
|
||||
emit progress(this);
|
||||
return loadNext();
|
||||
}
|
||||
}
|
||||
|
||||
if (!fname.isEmpty() && !duplicateInData && !fileIsOpen) {
|
||||
fileIsOpen = file.open(QIODevice::WriteOnly);
|
||||
if (!fileIsOpen) {
|
||||
finishFail();
|
||||
return;
|
||||
return finishFail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +416,7 @@ void mtpFileLoader::start(bool loadFirst, bool prior) {
|
||||
|
||||
void mtpFileLoader::cancel() {
|
||||
cancelRequests();
|
||||
type = MTP_storage_fileUnknown();
|
||||
type = mtpc_storage_fileUnknown;
|
||||
complete = true;
|
||||
if (fileIsOpen) {
|
||||
file.close();
|
||||
|
||||
@@ -60,7 +60,7 @@ signals:
|
||||
private:
|
||||
|
||||
mtpFileLoaderQueue *queue;
|
||||
bool inQueue, complete;
|
||||
bool inQueue, complete, triedLocal;
|
||||
|
||||
void cancelRequests();
|
||||
|
||||
@@ -96,6 +96,6 @@ private:
|
||||
QByteArray data;
|
||||
|
||||
int32 size;
|
||||
MTPstorage_FileType type;
|
||||
mtpTypeId type;
|
||||
|
||||
};
|
||||
|
||||
@@ -83,9 +83,6 @@ void MTProtoSession::start(int32 dcenter, uint32 connects) {
|
||||
timeouter.start(1000);
|
||||
|
||||
connect(&sender, SIGNAL(timeout()), this, SIGNAL(needToSend()));
|
||||
connect(this, SIGNAL(startSendTimer(int)), &sender, SLOT(start(int)));
|
||||
connect(this, SIGNAL(stopSendTimer()), &sender, SLOT(stop()));
|
||||
connect(this, SIGNAL(needToSendAsync()), this, SIGNAL(needToSend()));
|
||||
|
||||
MTProtoDCMap &dcs(mtpDCMap());
|
||||
|
||||
@@ -135,7 +132,7 @@ void MTProtoSession::stop() {
|
||||
}
|
||||
}
|
||||
|
||||
void MTProtoSession::sendAnything(uint64 msCanWait) {
|
||||
void MTProtoSession::sendAnything(quint64 msCanWait) {
|
||||
uint64 ms = getms(true);
|
||||
if (msSendCall) {
|
||||
if (ms > msSendCall + msWait) {
|
||||
@@ -150,13 +147,14 @@ void MTProtoSession::sendAnything(uint64 msCanWait) {
|
||||
msWait = msCanWait;
|
||||
}
|
||||
if (msWait) {
|
||||
DEBUG_LOG(("MTP Info: dc %1 can wait for %2ms from current %3").arg(dcId).arg(msWait).arg(msSendCall));
|
||||
msSendCall = ms;
|
||||
emit startSendTimer(msWait);
|
||||
DEBUG_LOG(("MTP Info: can wait for %1ms from current %2").arg(msWait).arg(msSendCall));
|
||||
sender.start(msWait);
|
||||
} else {
|
||||
emit stopSendTimer();
|
||||
DEBUG_LOG(("MTP Info: dc %1 stopped send timer, can wait for %2ms from current %3").arg(dcId).arg(msWait).arg(msSendCall));
|
||||
sender.stop();
|
||||
msSendCall = 0;
|
||||
emit needToSendAsync();
|
||||
emit needToSend();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,6 @@ public:
|
||||
|
||||
template <typename TRequest>
|
||||
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, bool needsLayer = false, bool toMainDC = false, mtpRequestId after = 0); // send mtp request
|
||||
void sendAnything(uint64 msCanWait);
|
||||
|
||||
void cancel(mtpRequestId requestId, mtpMsgId msgId);
|
||||
int32 requestState(mtpRequestId requestId) const;
|
||||
@@ -253,10 +252,6 @@ signals:
|
||||
void authKeyCreated();
|
||||
|
||||
void needToSend();
|
||||
void needToSendAsync(); // emit this signal, to emit needToSend() in MTProtoSession thread
|
||||
|
||||
void startSendTimer(int msec); // manipulating timer from all threads
|
||||
void stopSendTimer();
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -268,6 +263,8 @@ public slots:
|
||||
void onConnectionStateChange(qint32 newState);
|
||||
void onResetDone();
|
||||
|
||||
void sendAnything(quint64 msCanWait);
|
||||
|
||||
private:
|
||||
|
||||
typedef QList<MTProtoConnection*> MTProtoConnections;
|
||||
|
||||
@@ -367,7 +367,7 @@ void ProfileInner::reorderParticipants() {
|
||||
} else {
|
||||
_participants.clear();
|
||||
if (_peerUser) {
|
||||
_onlineText = App::onlineText(_peerUser->onlineTill, t, true);
|
||||
_onlineText = App::onlineText(_peerUser, t, true);
|
||||
} else {
|
||||
_onlineText = lang(lng_chat_no_members);
|
||||
}
|
||||
@@ -520,7 +520,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
|
||||
if (!data) {
|
||||
data = _participantsData[cnt] = new ParticipantData();
|
||||
data->name.setText(st::profileListNameFont, user->name, _textNameOptions);
|
||||
data->online = App::onlineText(user->onlineTill, l_time);
|
||||
data->online = App::onlineText(user, l_time);
|
||||
data->cankick = (user != App::self()) && (_chatAdmin || (_peerChat->cankick.constFind(user) != _peerChat->cankick.cend()));
|
||||
}
|
||||
p.setPen(st::profileListNameColor->p);
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace {
|
||||
};
|
||||
|
||||
PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent),
|
||||
posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/iconround256.png")), wndIcon(QPixmap::fromImage(icon256)) {
|
||||
posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/icon256.png")), wndIcon(QPixmap::fromImage(icon256)) {
|
||||
connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
|
||||
psIdleTimer.setSingleShot(false);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ void MacPrivate::notifyReplied(unsigned long long peer, const char *str) {
|
||||
}
|
||||
|
||||
PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent),
|
||||
posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/iconround256.png")), wndIcon(QPixmap(qsl(":/gui/art/iconbig128.png"))),
|
||||
posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/icon256.png")), wndIcon(QPixmap(qsl(":/gui/art/icon256.png"))),
|
||||
psLogout(0), psUndo(0), psRedo(0), psCut(0), psCopy(0), psPaste(0), psDelete(0), psSelectAll(0), psContacts(0), psNewGroup(0), psShowTelegram(0) {
|
||||
QImage tray(qsl(":/gui/art/osxtray.png"));
|
||||
trayImg = tray.copy(0, cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
|
||||
|
||||
@@ -860,7 +860,7 @@ namespace {
|
||||
|
||||
};
|
||||
|
||||
PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), ps_hWnd(0), ps_menu(0), icon256(qsl(":/gui/art/iconround256.png")), wndIcon(QPixmap::fromImage(icon256)),
|
||||
PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), ps_hWnd(0), ps_menu(0), icon256(qsl(":/gui/art/icon256.png")), wndIcon(QPixmap::fromImage(icon256)),
|
||||
ps_iconBig(0), ps_iconSmall(0), ps_iconOverlay(0), trayIcon(0), trayIconMenu(0), posInited(false), ps_tbHider_hWnd(createTaskbarHider()), psIdle(false) {
|
||||
tbCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
|
||||
connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
|
||||
|
||||
@@ -137,47 +137,59 @@ const RecentEmojiPack &cGetRecentEmojis() {
|
||||
cSetRecentEmojisPreload(RecentEmojiPreload());
|
||||
r.reserve(p.size());
|
||||
for (RecentEmojiPreload::const_iterator i = p.cbegin(), e = p.cend(); i != e; ++i) {
|
||||
EmojiPtr ep(getEmoji(i->first));
|
||||
if (ep) {
|
||||
r.push_back(qMakePair(ep, i->second));
|
||||
uint32 code = ((i->first & 0xFFFFU) == 0xFE0FU) ? ((i->first >> 16) & 0xFFFFU) : i->first;
|
||||
EmojiPtr ep(getEmoji(code));
|
||||
if (!ep) continue;
|
||||
|
||||
if (ep->postfix) {
|
||||
int32 j = 0, l = r.size();
|
||||
for (; j < l; ++j) {
|
||||
if (r[j].first->code == code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < l) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r.push_back(qMakePair(ep, i->second));
|
||||
}
|
||||
}
|
||||
uint32 defaultRecent[] = {
|
||||
0xD83DDE02,
|
||||
0xD83DDE18,
|
||||
0x2764,
|
||||
0xD83DDE0D,
|
||||
0xD83DDE0A,
|
||||
0xD83DDE01,
|
||||
0xD83DDC4D,
|
||||
0x263A,
|
||||
0xD83DDE14,
|
||||
0xD83DDE04,
|
||||
0xD83DDE2D,
|
||||
0xD83DDC8B,
|
||||
0xD83DDE12,
|
||||
0xD83DDE33,
|
||||
0xD83DDE1C,
|
||||
0xD83DDE48,
|
||||
0xD83DDE09,
|
||||
0xD83DDE03,
|
||||
0xD83DDE22,
|
||||
0xD83DDE1D,
|
||||
0xD83DDE31,
|
||||
0xD83DDE21,
|
||||
0xD83DDE0F,
|
||||
0xD83DDE1E,
|
||||
0xD83DDE05,
|
||||
0xD83DDE1A,
|
||||
0xD83DDE4A,
|
||||
0xD83DDE0C,
|
||||
0xD83DDE00,
|
||||
0xD83DDE0B,
|
||||
0xD83DDE06,
|
||||
0xD83DDC4C,
|
||||
0xD83DDE10,
|
||||
0xD83DDE15,
|
||||
0xD83DDE02U,
|
||||
0xD83DDE18U,
|
||||
0x2764U,
|
||||
0xD83DDE0DU,
|
||||
0xD83DDE0AU,
|
||||
0xD83DDE01U,
|
||||
0xD83DDC4DU,
|
||||
0x263AU,
|
||||
0xD83DDE14U,
|
||||
0xD83DDE04U,
|
||||
0xD83DDE2DU,
|
||||
0xD83DDC8BU,
|
||||
0xD83DDE12U,
|
||||
0xD83DDE33U,
|
||||
0xD83DDE1CU,
|
||||
0xD83DDE48U,
|
||||
0xD83DDE09U,
|
||||
0xD83DDE03U,
|
||||
0xD83DDE22U,
|
||||
0xD83DDE1DU,
|
||||
0xD83DDE31U,
|
||||
0xD83DDE21U,
|
||||
0xD83DDE0FU,
|
||||
0xD83DDE1EU,
|
||||
0xD83DDE05U,
|
||||
0xD83DDE1AU,
|
||||
0xD83DDE4AU,
|
||||
0xD83DDE0CU,
|
||||
0xD83DDE00U,
|
||||
0xD83DDE0BU,
|
||||
0xD83DDE06U,
|
||||
0xD83DDC4CU,
|
||||
0xD83DDE10U,
|
||||
0xD83DDE15U,
|
||||
};
|
||||
for (int32 i = 0, s = sizeof(defaultRecent) / sizeof(defaultRecent[0]); i < s; ++i) {
|
||||
if (r.size() >= EmojiPadPerRow * EmojiPadRowsPerPage) break;
|
||||
|
||||
@@ -124,11 +124,12 @@ T convertScale(T v) {
|
||||
DeclareSetting(DBIEmojiTab, EmojiTab);
|
||||
|
||||
struct EmojiData {
|
||||
EmojiData(int32 x, int32 y, uint32 code, uint32 code2, int32 len) : x(x), y(y), code(code), code2(code2), len(len) {
|
||||
EmojiData(uint16 x, uint16 y, uint32 code, uint32 code2, uint16 len, uint16 postfix = 0) : x(x), y(y), code(code), code2(code2), len(len), postfix(postfix) {
|
||||
}
|
||||
int32 x, y;
|
||||
uint16 x, y;
|
||||
uint32 code, code2;
|
||||
int32 len;
|
||||
uint16 len;
|
||||
uint16 postfix;
|
||||
};
|
||||
|
||||
typedef const EmojiData *EmojiPtr;
|
||||
|
||||
@@ -31,6 +31,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "boxes/usernamebox.h"
|
||||
#include "gui/filedialog.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
Slider::Slider(QWidget *parent, const style::slider &st, int32 count, int32 sel) : QWidget(parent),
|
||||
_count(count), _sel(snap(sel, 0, _count)), _wasSel(_sel), _st(st), _pressed(false) {
|
||||
resize(_st.width, _st.bar.pxHeight());
|
||||
@@ -154,6 +156,12 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
|
||||
|
||||
_catsAndDogs(this, lang(lng_settings_cats_and_dogs), cCatsAndDogs()),
|
||||
|
||||
// local storage
|
||||
_localImagesClear(this, lang(lng_local_images_clear)),
|
||||
_imagesClearingWidth(st::linkFont->m.width(lang(lng_local_images_clearing))),
|
||||
_imagesClearedWidth(st::linkFont->m.width(lang(lng_local_images_cleared))),
|
||||
_imagesClearFailedWidth(st::linkFont->m.width(lang(lng_local_images_clear_failed))),
|
||||
|
||||
// advanced
|
||||
_connectionType(this, lang(lng_connection_auto)),
|
||||
_resetSessions(this, lang(lng_settings_reset)),
|
||||
@@ -231,11 +239,19 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
|
||||
case Window::TempDirExists: _tempDirClearState = TempDirExists; break;
|
||||
case Window::TempDirRemoving: _tempDirClearState = TempDirClearing; break;
|
||||
}
|
||||
connect(App::wnd(), SIGNAL(tempDirCleared()), this, SLOT(onTempDirCleared()));
|
||||
connect(App::wnd(), SIGNAL(tempDirClearFailed()), this, SLOT(onTempDirClearFailed()));
|
||||
connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int)));
|
||||
connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int)));
|
||||
|
||||
connect(&_catsAndDogs, SIGNAL(changed()), this, SLOT(onCatsAndDogs()));
|
||||
|
||||
// local storage
|
||||
connect(&_localImagesClear, SIGNAL(clicked()), this, SLOT(onLocalImagesClear()));
|
||||
switch (App::wnd()->localImagesState()) {
|
||||
case Window::TempDirEmpty: _imagesClearState = TempDirEmpty; break;
|
||||
case Window::TempDirExists: _imagesClearState = TempDirExists; break;
|
||||
case Window::TempDirRemoving: _imagesClearState = TempDirClearing; break;
|
||||
}
|
||||
|
||||
// advanced
|
||||
connect(&_connectionType, SIGNAL(clicked()), this, SLOT(onConnectionType()));
|
||||
connect(&_resetSessions, SIGNAL(clicked()), this, SLOT(onResetSessions()));
|
||||
@@ -456,14 +472,40 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
|
||||
top += st::setSectionSkip;
|
||||
|
||||
top += _catsAndDogs.height();
|
||||
|
||||
// local storage
|
||||
p.setFont(st::setHeaderFont->f);
|
||||
p.setPen(st::setHeaderColor->p);
|
||||
p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_cache));
|
||||
top += st::setHeaderSkip;
|
||||
|
||||
QString localImagesText = lang(lng_settings_no_images_cached);
|
||||
int32 cnt = Local::hasImages();
|
||||
if (cnt) {
|
||||
localImagesText = lang((cnt > 1) ? lng_settings_images_cached : lng_settings_image_cached).replace(qsl("{count}"), QString::number(cnt)).replace(qsl("{size}"), formatSizeText(Local::storageFilesSize()));
|
||||
}
|
||||
p.setFont(st::linkFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawText(_left + st::setHeaderLeft, top + st::linkFont->ascent, localImagesText);
|
||||
QString clearText;
|
||||
int32 clearWidth = 0;
|
||||
switch (_imagesClearState) {
|
||||
case TempDirClearing: clearText = lang(lng_local_images_clearing); clearWidth = _imagesClearingWidth; break;
|
||||
case TempDirCleared: clearText = lang(lng_local_images_cleared); clearWidth = _imagesClearedWidth; break;
|
||||
case TempDirClearFailed: clearText = lang(lng_local_images_clear_failed); clearWidth = _imagesClearFailedWidth; break;
|
||||
}
|
||||
if (clearWidth) {
|
||||
p.drawText(_left + st::setWidth - clearWidth, top + st::linkFont->ascent, clearText);
|
||||
}
|
||||
top += _localImagesClear.height();
|
||||
}
|
||||
|
||||
|
||||
// advanced
|
||||
p.setFont(st::setHeaderFont->f);
|
||||
p.setPen(st::setHeaderColor->p);
|
||||
p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_advanced));
|
||||
top += st::setHeaderSkip;
|
||||
|
||||
|
||||
p.setFont(st::linkFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawText(_left + st::setHeaderLeft, _connectionType.y() + st::linkFont->ascent, _connectionTypeText);
|
||||
@@ -541,6 +583,10 @@ void SettingsInner::resizeEvent(QResizeEvent *e) {
|
||||
}
|
||||
top += st::setSectionSkip;
|
||||
_catsAndDogs.move(_left, top); top += _catsAndDogs.height();
|
||||
|
||||
// local storage
|
||||
top += st::setHeaderSkip;
|
||||
_localImagesClear.move(_left + st::setWidth - _localImagesClear.width(), top); top += _localImagesClear.height();
|
||||
}
|
||||
|
||||
// advanced
|
||||
@@ -754,6 +800,7 @@ void SettingsInner::showAll() {
|
||||
_downloadPathClear.hide();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
_replaceEmojis.hide();
|
||||
_viewEmojis.hide();
|
||||
@@ -763,6 +810,14 @@ void SettingsInner::showAll() {
|
||||
_dontAskDownloadPath.hide();
|
||||
_downloadPathEdit.hide();
|
||||
_downloadPathClear.hide();
|
||||
_localImagesClear.hide();
|
||||
}
|
||||
|
||||
// local storage
|
||||
if (self() && _imagesClearState == TempDirExists) {
|
||||
_localImagesClear.show();
|
||||
} else {
|
||||
_localImagesClear.hide();
|
||||
}
|
||||
|
||||
// advanced
|
||||
@@ -1103,20 +1158,35 @@ void SettingsInner::onDownloadPathClear() {
|
||||
|
||||
void SettingsInner::onDownloadPathClearSure() {
|
||||
App::wnd()->hideLayer();
|
||||
App::wnd()->tempDirDelete();
|
||||
App::wnd()->tempDirDelete(Local::ClearManagerDownloads);
|
||||
_tempDirClearState = TempDirClearing;
|
||||
showAll();
|
||||
update();
|
||||
}
|
||||
|
||||
void SettingsInner::onTempDirCleared() {
|
||||
_tempDirClearState = TempDirCleared;
|
||||
void SettingsInner::onLocalImagesClear() {
|
||||
App::wnd()->tempDirDelete(Local::ClearManagerImages);
|
||||
_imagesClearState = TempDirClearing;
|
||||
showAll();
|
||||
update();
|
||||
}
|
||||
|
||||
void SettingsInner::onTempDirClearFailed() {
|
||||
_tempDirClearState = TempDirClearFailed;
|
||||
void SettingsInner::onTempDirCleared(int task) {
|
||||
if (task & Local::ClearManagerDownloads) {
|
||||
_tempDirClearState = TempDirCleared;
|
||||
} else if (task & Local::ClearManagerImages) {
|
||||
_imagesClearState = TempDirCleared;
|
||||
}
|
||||
showAll();
|
||||
update();
|
||||
}
|
||||
|
||||
void SettingsInner::onTempDirClearFailed(int task) {
|
||||
if (task & Local::ClearManagerDownloads) {
|
||||
_tempDirClearState = TempDirClearFailed;
|
||||
} else if (task & Local::ClearManagerImages) {
|
||||
_imagesClearState = TempDirClearFailed;
|
||||
}
|
||||
showAll();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -122,11 +122,13 @@ public slots:
|
||||
void onDownloadPathEdited();
|
||||
void onDownloadPathClear();
|
||||
void onDownloadPathClearSure();
|
||||
void onTempDirCleared();
|
||||
void onTempDirClearFailed();
|
||||
void onTempDirCleared(int task);
|
||||
void onTempDirClearFailed(int task);
|
||||
|
||||
void onCatsAndDogs();
|
||||
|
||||
void onLocalImagesClear();
|
||||
|
||||
void onUpdateChecking();
|
||||
void onUpdateLatest();
|
||||
void onUpdateDownloading(qint64 ready, qint64 total);
|
||||
@@ -212,6 +214,11 @@ private:
|
||||
TempDirClearState _tempDirClearState;
|
||||
FlatCheckbox _catsAndDogs;
|
||||
|
||||
// local storage
|
||||
LinkButton _localImagesClear;
|
||||
int32 _imagesClearingWidth, _imagesClearedWidth, _imagesClearFailedWidth;
|
||||
TempDirClearState _imagesClearState;
|
||||
|
||||
// advanced
|
||||
LinkButton _connectionType, _resetSessions;
|
||||
FlatButton _logOut;
|
||||
|
||||
@@ -24,7 +24,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "application.h"
|
||||
|
||||
SysBtn::SysBtn(QWidget *parent, const style::sysButton &st, const QString &text) : Button(parent),
|
||||
_st(st), a_color(_st.color->c), _text(text), _overLevel(0) {
|
||||
_st(st), a_color(_st.color->c), _overLevel(0), _text(text) {
|
||||
int32 w = _st.size.width() + (_text.isEmpty() ? 0 : ((_st.size.width() - _st.img.pxWidth()) / 2 + st::titleTextButton.font->m.width(_text)));
|
||||
resize(w, _st.size.height());
|
||||
setCursor(style::cur_default);
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
<file>art/emoji_150x.png</file>
|
||||
<file>art/emoji_200x.png</file>
|
||||
<file>art/blank.gif</file>
|
||||
<file>art/iconround256.png</file>
|
||||
<file>art/iconbig128.png</file>
|
||||
<file>art/icon256.png</file>
|
||||
<file>art/fonts/DejaVuSans.ttf</file>
|
||||
<file>art/osxtray.png</file>
|
||||
</qresource>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<file>art/emoji_150x.png</file>
|
||||
<file>art/emoji_200x.png</file>
|
||||
<file>art/blank.gif</file>
|
||||
<file>art/iconround256.png</file>
|
||||
<file>art/icon256.png</file>
|
||||
<file>art/fonts/DejaVuSans.ttf</file>
|
||||
</qresource>
|
||||
<qresource prefix="/ava">
|
||||
|
||||
@@ -63,12 +63,11 @@ TitleWidget::TitleWidget(Window *window)
|
||||
{
|
||||
|
||||
setGeometry(0, 0, wnd->width(), st::titleHeight);
|
||||
stateChanged();
|
||||
|
||||
_update.hide();
|
||||
if (App::app()->updatingState() == Application::UpdatingReady) {
|
||||
showUpdateBtn();
|
||||
}
|
||||
stateChanged();
|
||||
|
||||
connect(&_settings, SIGNAL(clicked()), window, SLOT(showSettings()));
|
||||
connect(&_contacts, SIGNAL(clicked()), this, SLOT(onContacts()));
|
||||
|
||||
@@ -17,6 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "application.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#elif defined Q_OS_MAC
|
||||
#include <mach/mach_time.h>
|
||||
@@ -216,7 +218,7 @@ bool checkms() {
|
||||
_msAddToUnixtime = ((ms - unixms) / 1000LL) * 1000LL;
|
||||
} else if (unixms > ms + 1000LL) {
|
||||
_msAddToMsStart += ((unixms - ms) / 1000LL) * 1000LL;
|
||||
adjustSingleTimers();
|
||||
if (App::app()) emit App::app()->adjustSingleTimers();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -243,27 +245,24 @@ uint64 getms(bool checked) {
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace {
|
||||
QSet<SingleTimer*> _activeSingleTimers;
|
||||
QMutex _activeSingleTimersMutex;
|
||||
}
|
||||
|
||||
void regSingleTimer(SingleTimer *timer) {
|
||||
QMutexLocker lock(&_activeSingleTimersMutex);
|
||||
_activeSingleTimers.insert(timer);
|
||||
}
|
||||
|
||||
void unregSingleTimer(SingleTimer *timer) {
|
||||
QMutexLocker lock(&_activeSingleTimersMutex);
|
||||
_activeSingleTimers.remove(timer);
|
||||
}
|
||||
|
||||
void adjustSingleTimers() {
|
||||
for (QSet<SingleTimer*>::const_iterator i = _activeSingleTimers.cbegin(), e = _activeSingleTimers.cend(); i != e; ++i) {
|
||||
emit (*i)->callAdjust();
|
||||
SingleTimer::SingleTimer() : _finishing(0), _inited(false) {
|
||||
QTimer::setSingleShot(true);
|
||||
if (App::app()) {
|
||||
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
|
||||
_inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SingleTimer::start(int msec) {
|
||||
_finishing = getms(true) + (msec < 0 ? 0 : uint64(msec));
|
||||
if (!_inited && App::app()) {
|
||||
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
|
||||
_inited = true;
|
||||
}
|
||||
QTimer::start(msec);
|
||||
}
|
||||
|
||||
|
||||
uint64 msgid() {
|
||||
#ifdef Q_OS_WIN
|
||||
LARGE_INTEGER li;
|
||||
|
||||
@@ -101,45 +101,19 @@ inline void mylocaltime(struct tm * _Tm, const time_t * _Time) {
|
||||
bool checkms(); // returns true if time has changed
|
||||
uint64 getms(bool checked = false);
|
||||
|
||||
class SingleTimer;
|
||||
void regSingleTimer(SingleTimer *timer);
|
||||
void unregSingleTimer(SingleTimer *timer);
|
||||
void adjustSingleTimers();
|
||||
|
||||
class SingleTimer : public QTimer { // single shot timer with check
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SingleTimer() : _finishing(0) {
|
||||
QTimer::setSingleShot(true);
|
||||
connect(this, SIGNAL(callAdjust()), this, SLOT(adjust()));
|
||||
connect(this, SIGNAL(timeout()), this, SLOT(unreg()));
|
||||
}
|
||||
|
||||
void start(int msec) {
|
||||
_finishing = getms(true) + (msec < 0 ? 0 : uint64(msec));
|
||||
QTimer::start(msec);
|
||||
regSingleTimer(this);
|
||||
}
|
||||
void stop() {
|
||||
QTimer::stop();
|
||||
unreg();
|
||||
}
|
||||
SingleTimer();
|
||||
|
||||
void setSingleShot(bool); // is not available
|
||||
void start(); // is not available
|
||||
|
||||
~SingleTimer() {
|
||||
unreg();
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
void callAdjust();
|
||||
|
||||
public slots:
|
||||
|
||||
void start(int msec);
|
||||
void adjust() {
|
||||
uint64 n = getms(true);
|
||||
if (isActive()) {
|
||||
@@ -150,12 +124,10 @@ public slots:
|
||||
}
|
||||
}
|
||||
}
|
||||
void unreg() {
|
||||
unregSingleTimer(this);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64 _finishing;
|
||||
bool _inited;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "boxes/confirmbox.h"
|
||||
|
||||
#include "mediaview.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent), _shadow(st::boxShadow), _reconnect(this, QString()) {
|
||||
set(text, reconnect);
|
||||
@@ -66,20 +67,6 @@ void ConnectingWidget::onReconnect() {
|
||||
MTP::restart();
|
||||
}
|
||||
|
||||
TempDirDeleter::TempDirDeleter(QThread *thread) {
|
||||
moveToThread(thread);
|
||||
connect(thread, SIGNAL(started()), this, SLOT(onStart()));
|
||||
}
|
||||
|
||||
void TempDirDeleter::onStart() {
|
||||
if (QDir(cTempDir()).removeRecursively()) {
|
||||
emit succeed();
|
||||
} else {
|
||||
emit failed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NotifyWindow::NotifyWindow(HistoryItem *msg, int32 x, int32 y) : history(msg->history()), item(msg)
|
||||
#ifdef Q_OS_WIN
|
||||
, started(GetTickCount())
|
||||
@@ -101,7 +88,7 @@ NotifyWindow::NotifyWindow(HistoryItem *msg, int32 x, int32 y) : history(msg->hi
|
||||
inputTimer.setSingleShot(true);
|
||||
connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput()));
|
||||
|
||||
connect(&close, SIGNAL(clicked()), this, SLOT(unlinkHistory()));
|
||||
connect(&close, SIGNAL(clicked()), this, SLOT(unlinkHistoryAndNotify()));
|
||||
close.setAcceptBoth(true);
|
||||
close.move(st::notifyWidth - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y());
|
||||
close.show();
|
||||
@@ -241,16 +228,20 @@ void NotifyWindow::updatePeerPhoto() {
|
||||
|
||||
void NotifyWindow::itemRemoved(HistoryItem *del) {
|
||||
if (item == del) {
|
||||
unlinkHistory();
|
||||
unlinkHistoryAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyWindow::unlinkHistoryAndNotify() {
|
||||
unlinkHistory();
|
||||
App::wnd()->notifyShowNext();
|
||||
}
|
||||
|
||||
void NotifyWindow::unlinkHistory(History *hist) {
|
||||
if (!hist || hist == history) {
|
||||
animHide(st::notifyFastAnim, st::notifyFastAnimFunc);
|
||||
history = 0;
|
||||
item = 0;
|
||||
App::wnd()->notifyShowNext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,12 +261,14 @@ void NotifyWindow::startHiding() {
|
||||
|
||||
void NotifyWindow::mousePressEvent(QMouseEvent *e) {
|
||||
if (!history) return;
|
||||
PeerId peer = history->peer->id;
|
||||
|
||||
if (e->button() == Qt::RightButton) {
|
||||
unlinkHistory();
|
||||
unlinkHistoryAndNotify();
|
||||
} else if (history) {
|
||||
App::wnd()->showFromTray();
|
||||
App::wnd()->hideSettings();
|
||||
App::main()->showPeer(history->peer->id, 0, false, true);
|
||||
App::main()->showPeer(peer, 0, false, true);
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
@@ -338,7 +331,7 @@ NotifyWindow::~NotifyWindow() {
|
||||
|
||||
Window::Window(QWidget *parent) : PsMainWindow(parent),
|
||||
intro(0), main(0), settings(0), layerBG(0), _topWidget(0),
|
||||
_connecting(0), _tempDeleter(0), _tempDeleterThread(0), dragging(false), _inactivePress(false), _mediaView(0) {
|
||||
_connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _mediaView(0) {
|
||||
|
||||
icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation);
|
||||
icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation);
|
||||
@@ -944,40 +937,56 @@ void Window::resizeEvent(QResizeEvent *e) {
|
||||
}
|
||||
|
||||
Window::TempDirState Window::tempDirState() {
|
||||
if (_tempDeleter) {
|
||||
if (_clearManager && _clearManager->hasTask(Local::ClearManagerDownloads)) {
|
||||
return TempDirRemoving;
|
||||
}
|
||||
return QDir(cTempDir()).exists() ? TempDirExists : TempDirEmpty;
|
||||
}
|
||||
|
||||
void Window::tempDirDelete() {
|
||||
if (_tempDeleter) return;
|
||||
_tempDeleterThread = new QThread();
|
||||
_tempDeleter = new TempDirDeleter(_tempDeleterThread);
|
||||
connect(_tempDeleter, SIGNAL(succeed()), this, SLOT(onTempDirCleared()));
|
||||
connect(_tempDeleter, SIGNAL(failed()), this, SLOT(onTempDirClearFailed()));
|
||||
_tempDeleterThread->start();
|
||||
Window::TempDirState Window::localImagesState() {
|
||||
if (_clearManager && _clearManager->hasTask(Local::ClearManagerImages)) {
|
||||
return TempDirRemoving;
|
||||
}
|
||||
return Local::hasImages() ? TempDirExists : TempDirEmpty;
|
||||
}
|
||||
|
||||
void Window::onTempDirCleared() {
|
||||
_tempDeleter->deleteLater();
|
||||
_tempDeleter = 0;
|
||||
_tempDeleterThread->deleteLater();
|
||||
_tempDeleterThread = 0;
|
||||
emit tempDirCleared();
|
||||
void Window::tempDirDelete(int task) {
|
||||
if (_clearManager) {
|
||||
if (_clearManager->addTask(task)) {
|
||||
return;
|
||||
} else {
|
||||
_clearManager->deleteLater();
|
||||
_clearManager = 0;
|
||||
}
|
||||
}
|
||||
_clearManager = new Local::ClearManager();
|
||||
_clearManager->addTask(task);
|
||||
connect(_clearManager, SIGNAL(succeed(int,void*)), this, SLOT(onClearFinished(int,void*)));
|
||||
connect(_clearManager, SIGNAL(failed(int,void*)), this, SLOT(onClearFailed(int,void*)));
|
||||
_clearManager->start();
|
||||
}
|
||||
|
||||
void Window::onTempDirClearFailed() {
|
||||
_tempDeleter->deleteLater();
|
||||
_tempDeleter = 0;
|
||||
_tempDeleterThread->deleteLater();
|
||||
_tempDeleterThread = 0;
|
||||
emit tempDirClearFailed();
|
||||
void Window::onClearFinished(int task, void *manager) {
|
||||
if (manager && manager == _clearManager) {
|
||||
_clearManager->deleteLater();
|
||||
_clearManager = 0;
|
||||
}
|
||||
emit tempDirCleared(task);
|
||||
}
|
||||
|
||||
void Window::onClearFailed(int task, void *manager) {
|
||||
if (manager && manager == _clearManager) {
|
||||
_clearManager->deleteLater();
|
||||
_clearManager = 0;
|
||||
}
|
||||
emit tempDirClearFailed(task);
|
||||
}
|
||||
|
||||
void Window::quit() {
|
||||
delete _mediaView;
|
||||
_mediaView = 0;
|
||||
delete main;
|
||||
main = 0;
|
||||
notifyClearFast();
|
||||
}
|
||||
|
||||
@@ -1042,6 +1051,7 @@ void Window::notifyClear(History *history) {
|
||||
psClearNotifies(history->peer->id);
|
||||
notifyWhenMaps.remove(history);
|
||||
notifyWhenAlerts.remove(history);
|
||||
notifyShowNext();
|
||||
}
|
||||
|
||||
void Window::notifyClearFast() {
|
||||
@@ -1405,8 +1415,7 @@ void Window::changingMsgId(HistoryItem *row, MsgId newId) {
|
||||
|
||||
Window::~Window() {
|
||||
notifyClearFast();
|
||||
delete _tempDeleter;
|
||||
delete _tempDeleterThread;
|
||||
delete _clearManager;
|
||||
delete _connecting;
|
||||
delete _mediaView;
|
||||
delete trayIcon;
|
||||
|
||||
@@ -29,6 +29,9 @@ class MainWidget;
|
||||
class SettingsWidget;
|
||||
class BackgroundWidget;
|
||||
class LayeredWidget;
|
||||
namespace Local {
|
||||
class ClearManager;
|
||||
}
|
||||
|
||||
class ConnectingWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
@@ -52,21 +55,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class TempDirDeleter : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TempDirDeleter(QThread *thread);
|
||||
|
||||
public slots:
|
||||
void onStart();
|
||||
|
||||
signals:
|
||||
void succeed();
|
||||
void failed();
|
||||
|
||||
};
|
||||
|
||||
|
||||
class NotifyWindow : public QWidget, public Animated {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -94,6 +82,8 @@ public:
|
||||
return history ? _index : -1;
|
||||
}
|
||||
|
||||
void unlinkHistory(History *hist = 0);
|
||||
|
||||
~NotifyWindow();
|
||||
|
||||
public slots:
|
||||
@@ -101,7 +91,7 @@ public slots:
|
||||
void hideByTimer();
|
||||
void checkLastInput();
|
||||
|
||||
void unlinkHistory(History *hist = 0);
|
||||
void unlinkHistoryAndNotify();
|
||||
|
||||
private:
|
||||
|
||||
@@ -205,7 +195,8 @@ public:
|
||||
TempDirEmpty,
|
||||
};
|
||||
TempDirState tempDirState();
|
||||
void tempDirDelete();
|
||||
TempDirState localImagesState();
|
||||
void tempDirDelete(int task);
|
||||
|
||||
void quit();
|
||||
|
||||
@@ -243,8 +234,8 @@ public slots:
|
||||
|
||||
void onInactiveTimer();
|
||||
|
||||
void onTempDirCleared();
|
||||
void onTempDirClearFailed();
|
||||
void onClearFinished(int task, void *manager);
|
||||
void onClearFailed(int task, void *manager);
|
||||
|
||||
void notifyFire();
|
||||
void updateTrayMenu(bool force = false);
|
||||
@@ -257,8 +248,8 @@ public slots:
|
||||
signals:
|
||||
|
||||
void resized(const QSize &size);
|
||||
void tempDirCleared();
|
||||
void tempDirClearFailed();
|
||||
void tempDirCleared(int task);
|
||||
void tempDirClearFailed(int task);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -281,8 +272,7 @@ private:
|
||||
QWidget *_topWidget; // temp hack for CountrySelect
|
||||
ConnectingWidget *_connecting;
|
||||
|
||||
TempDirDeleter *_tempDeleter;
|
||||
QThread *_tempDeleterThread;
|
||||
Local::ClearManager *_clearManager;
|
||||
|
||||
void clearWidgets();
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.6.10</string>
|
||||
<string>0.6.13</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NOTE</key>
|
||||
|
||||
@@ -93,6 +93,7 @@ SOURCES += \
|
||||
./SourceFiles/overviewwidget.cpp \
|
||||
./SourceFiles/profilewidget.cpp \
|
||||
./SourceFiles/localimageloader.cpp \
|
||||
./SourceFiles/localstorage.cpp \
|
||||
./SourceFiles/logs.cpp \
|
||||
./SourceFiles/mainwidget.cpp \
|
||||
./SourceFiles/settings.cpp \
|
||||
@@ -168,6 +169,7 @@ HEADERS += \
|
||||
./SourceFiles/overviewwidget.h \
|
||||
./SourceFiles/profilewidget.h \
|
||||
./SourceFiles/localimageloader.h \
|
||||
./SourceFiles/localstorage.h \
|
||||
./SourceFiles/logs.h \
|
||||
./SourceFiles/mainwidget.h \
|
||||
./SourceFiles/settings.h \
|
||||
|
||||
@@ -270,6 +270,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_localstorage.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_mainwidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -486,6 +490,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_localstorage.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_mainwidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -711,6 +719,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_localstorage.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_mainwidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
@@ -852,6 +864,7 @@
|
||||
<ClCompile Include="SourceFiles\langloaderplain.cpp" />
|
||||
<ClCompile Include="SourceFiles\layerwidget.cpp" />
|
||||
<ClCompile Include="SourceFiles\localimageloader.cpp" />
|
||||
<ClCompile Include="SourceFiles\localstorage.cpp" />
|
||||
<ClCompile Include="SourceFiles\logs.cpp" />
|
||||
<ClCompile Include="SourceFiles\main.cpp" />
|
||||
<ClCompile Include="SourceFiles\mainwidget.cpp" />
|
||||
@@ -1502,6 +1515,20 @@
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="SourceFiles\langloaderplain.h" />
|
||||
<CustomBuild Include="SourceFiles\localstorage.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing localstorage.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/localstorage.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing localstorage.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/localstorage.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing localstorage.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/localstorage.h" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="SourceFiles\logs.h" />
|
||||
<CustomBuild Include="SourceFiles\mtproto\mtpConnection.h">
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing mtpConnection.h...</Message>
|
||||
@@ -1715,7 +1742,8 @@
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="SourceFiles\art\iconround256.ico" />
|
||||
<Image Include="sourcefiles\art\icon2.ico" />
|
||||
<Image Include="SourceFiles\art\icon256.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Telegram.rc" />
|
||||
|
||||
@@ -752,6 +752,18 @@
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_types.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SourceFiles\localstorage.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_localstorage.cpp">
|
||||
<Filter>Generated Files\Deploy</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_localstorage.cpp">
|
||||
<Filter>Generated Files\Debug</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_localstorage.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SourceFiles\stdafx.h">
|
||||
@@ -1005,9 +1017,13 @@
|
||||
<CustomBuild Include="SourceFiles\types.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="SourceFiles\localstorage.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="SourceFiles\art\iconround256.ico" />
|
||||
<Image Include="SourceFiles\art\icon256.ico" />
|
||||
<Image Include="sourcefiles\art\icon2.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Telegram.rc" />
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
07539B1D1A1416AF00083EFC /* moc_history.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07539B1C1A1416AF00083EFC /* moc_history.cpp */; };
|
||||
07A69332199277BA0099CB9F /* mediaview.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07A69330199277BA0099CB9F /* mediaview.cpp */; };
|
||||
07A6933519927B160099CB9F /* moc_mediaview.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07A6933419927B160099CB9F /* moc_mediaview.cpp */; };
|
||||
07BE850F1A2093C9008ACB9F /* localstorage.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07BE850D1A2093C9008ACB9F /* localstorage.cpp */; };
|
||||
07BE85121A20961F008ACB9F /* moc_localstorage.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07BE85111A20961F008ACB9F /* moc_localstorage.cpp */; };
|
||||
07C4753B1967DF1C00CAAFE9 /* switcher.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07C475391967DF1C00CAAFE9 /* switcher.cpp */; };
|
||||
07C4753F1967E37300CAAFE9 /* moc_switcher.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07C4753E1967E37300CAAFE9 /* moc_switcher.cpp */; };
|
||||
07D7034B19B8755A00C4EED2 /* audio.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07D7034919B8755A00C4EED2 /* audio.cpp */; };
|
||||
@@ -260,6 +262,9 @@
|
||||
07A69330199277BA0099CB9F /* mediaview.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mediaview.cpp; path = SourceFiles/mediaview.cpp; sourceTree = SOURCE_ROOT; };
|
||||
07A69331199277BA0099CB9F /* mediaview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mediaview.h; path = SourceFiles/mediaview.h; sourceTree = SOURCE_ROOT; };
|
||||
07A6933419927B160099CB9F /* moc_mediaview.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_mediaview.cpp; path = GeneratedFiles/Debug/moc_mediaview.cpp; sourceTree = SOURCE_ROOT; };
|
||||
07BE850D1A2093C9008ACB9F /* localstorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = localstorage.cpp; path = SourceFiles/localstorage.cpp; sourceTree = SOURCE_ROOT; };
|
||||
07BE850E1A2093C9008ACB9F /* localstorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = localstorage.h; path = SourceFiles/localstorage.h; sourceTree = SOURCE_ROOT; };
|
||||
07BE85111A20961F008ACB9F /* moc_localstorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_localstorage.cpp; path = GeneratedFiles/Debug/moc_localstorage.cpp; sourceTree = SOURCE_ROOT; };
|
||||
07C3AF24194335ED0016CFF1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Telegram/Images.xcassets; sourceTree = SOURCE_ROOT; };
|
||||
07C3AF27194336B90016CFF1 /* pspecific_mac_p.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pspecific_mac_p.h; path = SourceFiles/pspecific_mac_p.h; sourceTree = SOURCE_ROOT; };
|
||||
07C3AF2819433ABF0016CFF1 /* lang.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = lang.txt; path = Resources/lang.txt; sourceTree = SOURCE_ROOT; };
|
||||
@@ -853,6 +858,7 @@
|
||||
0732E4A7199E262300D50FE7 /* overviewwidget.cpp */,
|
||||
CF32DF59C7823E4F3397EF3C /* profilewidget.cpp */,
|
||||
5A7F88F9C7F08D3DDE6EEF6B /* localimageloader.cpp */,
|
||||
07BE850D1A2093C9008ACB9F /* localstorage.cpp */,
|
||||
974DB34EEB8F83B91614C0B0 /* logs.cpp */,
|
||||
047DAFB0A7DE92C63033A43C /* mainwidget.cpp */,
|
||||
8A28F7789408AA839F48A5F2 /* settings.cpp */,
|
||||
@@ -885,6 +891,7 @@
|
||||
0732E4A8199E262300D50FE7 /* overviewwidget.h */,
|
||||
220B97F8F62C720E6059A64B /* profilewidget.h */,
|
||||
AD0C395D671BC024083A5FC7 /* localimageloader.h */,
|
||||
07BE850E1A2093C9008ACB9F /* localstorage.h */,
|
||||
0CAA815FFFEDCD84808E11F5 /* logs.h */,
|
||||
FE8FD20832B4C226E345CFBA /* mainwidget.h */,
|
||||
2EA58EF6CDF368B0132BAEB9 /* settings.h */,
|
||||
@@ -1036,6 +1043,7 @@
|
||||
801973D3334D0FCA849CF485 /* Debug */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
07BE85111A20961F008ACB9F /* moc_localstorage.cpp */,
|
||||
07539B1C1A1416AF00083EFC /* moc_history.cpp */,
|
||||
074756181A1372C600CA07F7 /* moc_types.cpp */,
|
||||
07D8510719F8340A00623D75 /* moc_usernamebox.cpp */,
|
||||
@@ -1402,6 +1410,7 @@
|
||||
D7EF8F129FCCE9AB3F3F081F /* button.cpp in Compile Sources */,
|
||||
B3CD52E504409DC1B560024F /* countrycodeinput.cpp in Compile Sources */,
|
||||
C03447C9A7D9FF73463B8BB5 /* countryinput.cpp in Compile Sources */,
|
||||
07BE850F1A2093C9008ACB9F /* localstorage.cpp in Compile Sources */,
|
||||
CDB0266A8B7CB20A95266BCD /* emoji_config.cpp in Compile Sources */,
|
||||
0732E4AC199E268A00D50FE7 /* moc_overviewwidget.cpp in Compile Sources */,
|
||||
7C2B2DEE467A4C4679F1C3C9 /* filedialog.cpp in Compile Sources */,
|
||||
@@ -1483,6 +1492,7 @@
|
||||
D6874C00733283846ACA9AB2 /* moc_confirmbox.cpp in Compile Sources */,
|
||||
ED2557A57C6782721DC494AF /* moc_connectionbox.cpp in Compile Sources */,
|
||||
5FC914F652D1B16FDA8F0634 /* moc_contactsbox.cpp in Compile Sources */,
|
||||
07BE85121A20961F008ACB9F /* moc_localstorage.cpp in Compile Sources */,
|
||||
49C3C1BF153F7FC078A25CE4 /* moc_downloadpathbox.cpp in Compile Sources */,
|
||||
9D294F23E02CFDF22C288382 /* moc_emojibox.cpp in Compile Sources */,
|
||||
0F0FC25286E16E5F78962FEE /* moc_newgroupbox.cpp in Compile Sources */,
|
||||
@@ -1521,7 +1531,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.6.10;
|
||||
CURRENT_PROJECT_VERSION = 0.6.13;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
@@ -1539,7 +1549,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 0.6.10;
|
||||
CURRENT_PROJECT_VERSION = 0.6.13;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
|
||||
@@ -1565,10 +1575,10 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.6.10;
|
||||
CURRENT_PROJECT_VERSION = 0.6.13;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.6;
|
||||
DYLIB_CURRENT_VERSION = 0.6.10;
|
||||
DYLIB_CURRENT_VERSION = 0.6.13;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
@@ -1708,10 +1718,10 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.6.10;
|
||||
CURRENT_PROJECT_VERSION = 0.6.13;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.6;
|
||||
DYLIB_CURRENT_VERSION = 0.6.10;
|
||||
DYLIB_CURRENT_VERSION = 0.6.13;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
|
||||
@@ -34,7 +34,7 @@ check: first
|
||||
compilers: GeneratedFiles/qrc_telegram.cpp GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp\
|
||||
GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp\
|
||||
GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp\
|
||||
GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_mainwidget.cpp\
|
||||
GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp\
|
||||
GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp\
|
||||
GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp\
|
||||
GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp\
|
||||
@@ -62,7 +62,7 @@ GeneratedFiles/qrc_telegram.cpp: SourceFiles/telegram.qrc \
|
||||
SourceFiles/art/bg.png \
|
||||
SourceFiles/art/sprite_150x.png \
|
||||
SourceFiles/art/sprite.png \
|
||||
SourceFiles/art/iconround256.png \
|
||||
SourceFiles/art/icon256.png \
|
||||
SourceFiles/art/emoji_150x.png \
|
||||
SourceFiles/art/bg_150x.png \
|
||||
SourceFiles/art/sprite_200x.png \
|
||||
@@ -91,9 +91,9 @@ GeneratedFiles/qrc_telegram.cpp: SourceFiles/telegram.qrc \
|
||||
SourceFiles/art/chatcolor2.png
|
||||
/usr/local/Qt-5.3.1/bin/rcc -name telegram SourceFiles/telegram.qrc -o GeneratedFiles/qrc_telegram.cpp
|
||||
|
||||
compiler_moc_header_make_all: GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_addparticipantbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_newgroupbox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_usernamebox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
|
||||
compiler_moc_header_make_all: GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_addparticipantbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_newgroupbox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_usernamebox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
|
||||
compiler_moc_header_clean:
|
||||
-$(DEL_FILE) GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_addparticipantbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_newgroupbox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_usernamedbox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
|
||||
-$(DEL_FILE) GeneratedFiles/Debug/moc_application.cpp GeneratedFiles/Debug/moc_audio.cpp GeneratedFiles/Debug/moc_dialogswidget.cpp GeneratedFiles/Debug/moc_dropdown.cpp GeneratedFiles/Debug/moc_fileuploader.cpp GeneratedFiles/Debug/moc_history.cpp GeneratedFiles/Debug/moc_historywidget.cpp GeneratedFiles/Debug/moc_layerwidget.cpp GeneratedFiles/Debug/moc_mediaview.cpp GeneratedFiles/Debug/moc_overviewwidget.cpp GeneratedFiles/Debug/moc_profilewidget.cpp GeneratedFiles/Debug/moc_localimageloader.cpp GeneratedFiles/Debug/moc_localstorage.cpp GeneratedFiles/Debug/moc_mainwidget.cpp GeneratedFiles/Debug/moc_settingswidget.cpp GeneratedFiles/Debug/moc_sysbuttons.cpp GeneratedFiles/Debug/moc_title.cpp GeneratedFiles/Debug/moc_types.cpp GeneratedFiles/Debug/moc_window.cpp GeneratedFiles/Debug/moc_mtp.cpp GeneratedFiles/Debug/moc_mtpConnection.cpp GeneratedFiles/Debug/moc_mtpDC.cpp GeneratedFiles/Debug/moc_mtpFileLoader.cpp GeneratedFiles/Debug/moc_mtpSession.cpp GeneratedFiles/Debug/moc_animation.cpp GeneratedFiles/Debug/moc_button.cpp GeneratedFiles/Debug/moc_contextmenu.cpp GeneratedFiles/Debug/moc_countrycodeinput.cpp GeneratedFiles/Debug/moc_countryinput.cpp GeneratedFiles/Debug/moc_flatbutton.cpp GeneratedFiles/Debug/moc_flatcheckbox.cpp GeneratedFiles/Debug/moc_flatinput.cpp GeneratedFiles/Debug/moc_flatlabel.cpp GeneratedFiles/Debug/moc_flattextarea.cpp GeneratedFiles/Debug/moc_switcher.cpp GeneratedFiles/Debug/moc_phoneinput.cpp GeneratedFiles/Debug/moc_scrollarea.cpp GeneratedFiles/Debug/moc_twidget.cpp GeneratedFiles/Debug/moc_aboutbox.cpp GeneratedFiles/Debug/moc_addcontactbox.cpp GeneratedFiles/Debug/moc_addparticipantbox.cpp GeneratedFiles/Debug/moc_confirmbox.cpp GeneratedFiles/Debug/moc_connectionbox.cpp GeneratedFiles/Debug/moc_contactsbox.cpp GeneratedFiles/Debug/moc_downloadpathbox.cpp GeneratedFiles/Debug/moc_emojibox.cpp GeneratedFiles/Debug/moc_newgroupbox.cpp GeneratedFiles/Debug/moc_photocropbox.cpp GeneratedFiles/Debug/moc_photosendbox.cpp GeneratedFiles/Debug/moc_usernamedbox.cpp GeneratedFiles/Debug/moc_intro.cpp GeneratedFiles/Debug/moc_introcode.cpp GeneratedFiles/Debug/moc_introphone.cpp GeneratedFiles/Debug/moc_introsignup.cpp GeneratedFiles/Debug/moc_pspecific_mac.cpp
|
||||
GeneratedFiles/Debug/moc_application.cpp: ../../Libraries/QtStatic/qtbase/include/QtNetwork/QLocalSocket \
|
||||
../../Libraries/QtStatic/qtbase/include/QtNetwork/QLocalServer \
|
||||
../../Libraries/QtStatic/qtbase/include/QtNetwork/QNetworkReply \
|
||||
@@ -162,6 +162,9 @@ GeneratedFiles/Debug/moc_profilewidget.cpp: SourceFiles/profilewidget.h
|
||||
GeneratedFiles/Debug/moc_localimageloader.cpp: SourceFiles/localimageloader.h
|
||||
/usr/local/Qt-5.3.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.3.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.3.1/include/QtGui/5.3.1/QtGui -I/usr/local/Qt-5.3.1/include/QtCore/5.3.1/QtCore -I/usr/local/Qt-5.3.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.3.1/include -I/usr/local/Qt-5.3.1/include/QtMultimedia -I/usr/local/Qt-5.3.1/include/QtWidgets -I/usr/local/Qt-5.3.1/include/QtNetwork -I/usr/local/Qt-5.3.1/include/QtGui -I/usr/local/Qt-5.3.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/localimageloader.h -o GeneratedFiles/Debug/moc_localimageloader.cpp
|
||||
|
||||
GeneratedFiles/Debug/moc_localstorage.cpp: SourceFiles/localstorage.h
|
||||
/usr/local/Qt-5.3.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.3.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.3.1/include/QtGui/5.3.1/QtGui -I/usr/local/Qt-5.3.1/include/QtCore/5.3.1/QtCore -I/usr/local/Qt-5.3.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.3.1/include -I/usr/local/Qt-5.3.1/include/QtMultimedia -I/usr/local/Qt-5.3.1/include/QtWidgets -I/usr/local/Qt-5.3.1/include/QtNetwork -I/usr/local/Qt-5.3.1/include/QtGui -I/usr/local/Qt-5.3.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/localstorage.h -o GeneratedFiles/Debug/moc_localstorage.cpp
|
||||
|
||||
GeneratedFiles/Debug/moc_mainwidget.cpp: ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \
|
||||
SourceFiles/gui/flatbutton.h \
|
||||
SourceFiles/gui/button.h \
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 21 KiB |