upload: import Ayu initial
Co-authored-by: SharapaGorg <sharapov.savely@yandex.ru>
BIN
.github/AyuGram.png
vendored
Normal file
After Width: | Height: | Size: 4.1 KiB |
90
README.md
|
@ -1,81 +1,37 @@
|
|||
# [Telegram Desktop][telegram_desktop] – Official Messenger
|
||||
# AyuGram
|
||||
|
||||
This is the complete source code and the build instructions for the official [Telegram][telegram] messenger desktop client, based on the [Telegram API][telegram_api] and the [MTProto][telegram_proto] secure protocol.
|
||||

|
||||
|
||||
[](https://github.com/telegramdesktop/tdesktop/releases)
|
||||
[](https://github.com/telegramdesktop/tdesktop/actions)
|
||||
[](https://github.com/telegramdesktop/tdesktop/actions)
|
||||
[](https://github.com/telegramdesktop/tdesktop/actions)
|
||||
## Features
|
||||
|
||||
[![Preview of Telegram Desktop][preview_image]][preview_image_url]
|
||||
- Disable read packets sending
|
||||
- Disable online packets sending
|
||||
- Disable typing & upload packets sending
|
||||
- Auto offline
|
||||
- Messages history (+ deleted ones)
|
||||
- Using scheduled messages to keep offline
|
||||
|
||||
The source code is published under GPLv3 with OpenSSL exception, the license is available [here][license].
|
||||
Technically, we have the **Ghost mode** starter pack.
|
||||
|
||||
## Supported systems
|
||||
Also, we have a cool **purple icon**.
|
||||
|
||||
The latest version is available for
|
||||
## Downloads? / FAQ?
|
||||
|
||||
* [Windows 7 and above (64 bit)](https://telegram.org/dl/desktop/win64) ([portable](https://telegram.org/dl/desktop/win64_portable))
|
||||
* [Windows 7 and above (32 bit)](https://telegram.org/dl/desktop/win) ([portable](https://telegram.org/dl/desktop/win_portable))
|
||||
* [macOS 10.12 and above](https://telegram.org/dl/desktop/mac)
|
||||
* [Linux static build for 64 bit](https://telegram.org/dl/desktop/linux)
|
||||
* [Snap](https://snapcraft.io/telegram-desktop)
|
||||
* [Flatpak](https://flathub.org/apps/details/org.telegram.desktop)
|
||||
We have both **Windows** and **Linux** builds.
|
||||
|
||||
## Old system versions
|
||||
Follow our [Telegram channel](https://t.me/ayugram1338). FAQ can be found here.
|
||||
|
||||
Version **2.4.4** was the last that supports older systems
|
||||
## May I get banned?
|
||||
|
||||
* [OS X 10.10 and 10.11](https://updates.tdesktop.com/tosx/tsetup-osx.2.4.4.dmg)
|
||||
* [Linux static build for 32 bit](https://updates.tdesktop.com/tlinux32/tsetup32.2.4.4.tar.xz)
|
||||
Well, *you* **can't**, because you're just an ordinary user.
|
||||
|
||||
Version **1.8.15** was the last that supports older systems
|
||||
## How to build
|
||||
|
||||
* [Windows XP and Vista](https://updates.tdesktop.com/tsetup/tsetup.1.8.15.exe) ([portable](https://updates.tdesktop.com/tsetup/tportable.1.8.15.zip))
|
||||
* [OS X 10.8 and 10.9](https://updates.tdesktop.com/tmac/tsetup.1.8.15.dmg)
|
||||
* [OS X 10.6 and 10.7](https://updates.tdesktop.com/tmac32/tsetup32.1.8.15.dmg)
|
||||
Follow [official guide](https://github.com/AyuGram/AyuGramDesktop/blob/dev/docs/building-win-x64.md).
|
||||
|
||||
## Third-party
|
||||
### Remarks
|
||||
|
||||
* Qt 6 ([LGPL](http://doc.qt.io/qt-6/lgpl.html)) and Qt 5.15 ([LGPL](http://doc.qt.io/qt-5/lgpl.html)) slightly patched
|
||||
* OpenSSL 1.1.1 and 1.0.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
|
||||
* WebRTC ([New BSD License](https://github.com/desktop-app/tg_owt/blob/master/LICENSE))
|
||||
* zlib 1.2.11 ([zlib License](http://www.zlib.net/zlib_license.html))
|
||||
* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))
|
||||
* liblzma ([public domain](http://tukaani.org/xz/))
|
||||
* Google Breakpad ([License](https://chromium.googlesource.com/breakpad/breakpad/+/master/LICENSE))
|
||||
* Google Crashpad ([Apache License 2.0](https://chromium.googlesource.com/crashpad/crashpad/+/master/LICENSE))
|
||||
* GYP ([BSD License](https://github.com/bnoordhuis/gyp/blob/master/LICENSE))
|
||||
* Ninja ([Apache License 2.0](https://github.com/ninja-build/ninja/blob/master/COPYING))
|
||||
* OpenAL Soft ([LGPL](https://github.com/kcat/openal-soft/blob/master/COPYING))
|
||||
* Opus codec ([BSD License](http://www.opus-codec.org/license/))
|
||||
* FFmpeg ([LGPL](https://www.ffmpeg.org/legal.html))
|
||||
* Guideline Support Library ([MIT License](https://github.com/Microsoft/GSL/blob/master/LICENSE))
|
||||
* Range-v3 ([Boost License](https://github.com/ericniebler/range-v3/blob/master/LICENSE.txt))
|
||||
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
|
||||
* Vazir font ([SIL Open Font License 1.1](https://github.com/rastikerdar/vazir-font/blob/master/OFL.txt))
|
||||
* Emoji alpha codes ([MIT License](https://github.com/emojione/emojione/blob/master/extras/alpha-codes/LICENSE.md))
|
||||
* Catch test framework ([Boost License](https://github.com/philsquared/Catch/blob/master/LICENSE.txt))
|
||||
* xxHash ([BSD License](https://github.com/Cyan4973/xxHash/blob/dev/LICENSE))
|
||||
* QR Code generator ([MIT License](https://github.com/nayuki/QR-Code-generator#license))
|
||||
* CMake ([New BSD License](https://github.com/Kitware/CMake/blob/master/Copyright.txt))
|
||||
* Hunspell ([LGPL](https://github.com/hunspell/hunspell/blob/master/COPYING.LESSER))
|
||||
|
||||
## Build instructions
|
||||
|
||||
* Windows [(32-bit)][win32] [(64-bit)][win64]
|
||||
* [macOS][mac]
|
||||
* [GNU/Linux using Docker][linux]
|
||||
|
||||
[//]: # (LINKS)
|
||||
[telegram]: https://telegram.org
|
||||
[telegram_desktop]: https://desktop.telegram.org
|
||||
[telegram_api]: https://core.telegram.org
|
||||
[telegram_proto]: https://core.telegram.org/mtproto
|
||||
[license]: LICENSE
|
||||
[win32]: docs/building-win.md
|
||||
[win64]: docs/building-win-x64.md
|
||||
[mac]: docs/building-mac.md
|
||||
[linux]: docs/building-linux.md
|
||||
[preview_image]: https://github.com/telegramdesktop/tdesktop/blob/dev/docs/assets/preview.png "Preview of Telegram Desktop"
|
||||
[preview_image_url]: https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/docs/assets/preview.png
|
||||
Make sure you have these components installed with VS Build Tools:
|
||||
- C++ MFC latest (x86 & x64)
|
||||
- C++ ATL latest (x86 & x64)
|
||||
- latest Windows 11 SDK
|
||||
|
|
|
@ -95,6 +95,30 @@ nice_target_sources(Telegram ${src_loc}
|
|||
PRIVATE
|
||||
${style_files}
|
||||
|
||||
ayu/qserializer.h
|
||||
ayu/ayu_state.cpp
|
||||
ayu/ayu_state.h
|
||||
ayu/ayu_settings.cpp
|
||||
ayu/ayu_settings.h
|
||||
ayu/boxes/confirmation_box.cpp
|
||||
ayu/boxes/confirmation_box.h
|
||||
ayu/boxes/edit_deleted_mark.cpp
|
||||
ayu/boxes/edit_deleted_mark.h
|
||||
ayu/boxes/edit_edited_mark.cpp
|
||||
ayu/boxes/edit_edited_mark.h
|
||||
ayu/context_menu/context_menu.cpp
|
||||
ayu/context_menu/context_menu.h
|
||||
ayu/context_menu/message_history_box.cpp
|
||||
ayu/context_menu/message_history_box.h
|
||||
ayu/settings/settings_ayu.cpp
|
||||
ayu/settings/settings_ayu.h
|
||||
ayu/sqlite/sqlite3.c
|
||||
ayu/sqlite/sqlite3.h
|
||||
ayu/sqlite/sqlite_orm.h
|
||||
ayu/database/entities.h
|
||||
ayu/database/ayu_database.cpp
|
||||
ayu/database/ayu_database.h
|
||||
|
||||
api/api_attached_stickers.cpp
|
||||
api/api_attached_stickers.h
|
||||
api/api_authorizations.cpp
|
||||
|
@ -1560,9 +1584,9 @@ else()
|
|||
set(bundle_identifier "com.tdesktop.Telegram$<$<CONFIG:Debug>:Debug>")
|
||||
set(bundle_entitlements "Telegram.entitlements")
|
||||
if (LINUX AND DESKTOP_APP_USE_PACKAGED)
|
||||
set(output_name "telegram-desktop")
|
||||
set(output_name "ayugram-desktop")
|
||||
else()
|
||||
set(output_name "Telegram")
|
||||
set(output_name "AyuGram")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -1601,7 +1625,7 @@ PRIVATE
|
|||
if (APPLE
|
||||
OR "${CMAKE_GENERATOR}" STREQUAL "Ninja Multi-Config"
|
||||
OR NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL ""
|
||||
OR NOT "${output_name}" STREQUAL "Telegram")
|
||||
OR NOT "${output_name}" STREQUAL "AyuGram")
|
||||
set(output_folder ${CMAKE_BINARY_DIR})
|
||||
else()
|
||||
set(output_folder ${CMAKE_BINARY_DIR}/bin)
|
||||
|
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 507 B |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 921 B |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 921 B |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 6.3 KiB |
|
@ -60,11 +60,11 @@ BEGIN
|
|||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "CompanyName", "Radolyn Labs"
|
||||
VALUE "FileDescription", "AyuGram Desktop"
|
||||
VALUE "FileVersion", "4.8.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.8.3.0"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -51,11 +51,11 @@ BEGIN
|
|||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "CompanyName", "Radolyn Labs"
|
||||
VALUE "FileDescription", "AyuGram Desktop Updater"
|
||||
VALUE "FileVersion", "4.8.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductName", "AyuGram Desktop"
|
||||
VALUE "ProductVersion", "4.8.3.0"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -15,6 +15,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_peer_values.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
|
@ -112,6 +114,14 @@ void SendProgressManager::send(const Key &key, int progress) {
|
|||
if (skipRequest(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// AyuGram sendUploadProgress
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (!settings->sendUploadProgress) {
|
||||
DEBUG_LOG(("[AyuGram] Don't send upload progress"));
|
||||
return;
|
||||
}
|
||||
|
||||
using Type = SendProgressType;
|
||||
const auto action = [&]() -> MTPsendMessageAction {
|
||||
const auto p = MTP_int(progress);
|
||||
|
|
|
@ -57,6 +57,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "apiwrap.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
|
@ -899,8 +901,17 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
|
|||
Core::App().checkAutoLock(lastNonIdleTime);
|
||||
});
|
||||
|
||||
const auto &config = _session->serverConfig();
|
||||
bool isOnline = Core::App().hasActiveWindow(&session());
|
||||
// AyuGram sendOnlinePackets
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
const auto &config = _session->serverConfig();
|
||||
bool isOnlineOrig = Core::App().hasActiveWindow(&session());
|
||||
bool isOnline = settings->sendOnlinePackets && isOnlineOrig;
|
||||
|
||||
// AyuGram sendOfflinePacketAfterOnline
|
||||
if (settings->sendOfflinePacketAfterOnline && _lastWasOnline) {
|
||||
isOnline = false;
|
||||
}
|
||||
|
||||
int updateIn = config.onlineUpdatePeriod;
|
||||
Assert(updateIn >= 0);
|
||||
if (isOnline) {
|
||||
|
@ -922,7 +933,7 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
|
|||
|| (isOnline && gotOtherOffline)) {
|
||||
api().request(base::take(_onlineRequest)).cancel();
|
||||
|
||||
_lastWasOnline = isOnline;
|
||||
_lastWasOnline = isOnlineOrig;
|
||||
_lastSetOnline = ms;
|
||||
if (!Core::Quitting()) {
|
||||
_onlineRequest = api().request(MTPaccount_UpdateStatus(
|
||||
|
@ -943,7 +954,7 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
|
|||
session().changes().peerUpdated(
|
||||
self,
|
||||
Data::PeerUpdate::Flag::OnlineStatus);
|
||||
if (!isOnline) { // Went offline, so we need to save message draft to the cloud.
|
||||
if (!isOnlineOrig) { // Went offline, so we need to save message draft to the cloud.
|
||||
api().saveCurrentDraftToCloud();
|
||||
session().data().maybeStopWatchForOffline(self);
|
||||
}
|
||||
|
@ -953,6 +964,22 @@ void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
|
|||
updateIn = qMin(updateIn, int(_lastSetOnline + config.onlineUpdatePeriod - ms));
|
||||
Assert(updateIn >= 0);
|
||||
}
|
||||
|
||||
// AyuGram sendOfflinePacketAfterOnline
|
||||
if (settings->sendOfflinePacketAfterOnline) {
|
||||
session().api().requestFullPeer(session().user());
|
||||
if (session().user()->onlineTill > base::unixtime::now()) {
|
||||
DEBUG_LOG(("[AyuGram] User likely appeared online"));
|
||||
|
||||
_onlineRequest = api().request(MTPaccount_UpdateStatus(
|
||||
MTP_bool(true)
|
||||
)).send();
|
||||
}
|
||||
|
||||
DEBUG_LOG(("[AyuGram] Decreasing updateIn because of enabled features"));
|
||||
updateIn = 1250;
|
||||
}
|
||||
|
||||
_onlineTimer.callOnce(updateIn);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/storage_media_prepare.h"
|
||||
#include "storage/storage_account.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Save draft to the cloud with 1 sec extra delay.
|
||||
|
@ -3483,6 +3485,14 @@ void ApiWrap::sendUploadedPhoto(
|
|||
Api::RemoteFileInfo info,
|
||||
Api::SendOptions options) {
|
||||
if (const auto item = _session->data().message(localId)) {
|
||||
// AyuGram useScheduledMessages
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->useScheduledMessages && !options.scheduled) {
|
||||
DEBUG_LOG(("[AyuGram] Scheduling message"));
|
||||
auto current = base::unixtime::now();
|
||||
options.scheduled = current + 18; // using 18 seconds because photo can be big
|
||||
}
|
||||
|
||||
const auto media = Api::PrepareUploadedPhoto(item, std::move(info));
|
||||
if (const auto groupId = item->groupId()) {
|
||||
uploadAlbumMedia(item, groupId, media);
|
||||
|
@ -3500,6 +3510,15 @@ void ApiWrap::sendUploadedDocument(
|
|||
if (!item->media() || !item->media()->document()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// AyuGram useScheduledMessages
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->useScheduledMessages && !options.scheduled) {
|
||||
DEBUG_LOG(("[AyuGram] Scheduling message"));
|
||||
auto current = base::unixtime::now();
|
||||
options.scheduled = current + 60; // well, a document can be really big...
|
||||
}
|
||||
|
||||
const auto media = Api::PrepareUploadedDocument(
|
||||
item,
|
||||
std::move(info));
|
||||
|
@ -3911,6 +3930,14 @@ void ApiWrap::sendMediaWithRandomId(
|
|||
const MTPInputMedia &media,
|
||||
Api::SendOptions options,
|
||||
uint64 randomId) {
|
||||
// AyuGram useScheduledMessages
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->useScheduledMessages && !options.scheduled) {
|
||||
DEBUG_LOG(("[AyuGram] Scheduling message"));
|
||||
auto current = base::unixtime::now();
|
||||
options.scheduled = current + 12;
|
||||
}
|
||||
|
||||
const auto history = item->history();
|
||||
const auto replyTo = item->replyToId();
|
||||
const auto topicRootId = item->topicRootId();
|
||||
|
@ -4003,6 +4030,15 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
|||
_sendingAlbums.remove(groupId);
|
||||
return;
|
||||
}
|
||||
|
||||
// AyuGram useScheduledMessages
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->useScheduledMessages && !album->options.scheduled) {
|
||||
DEBUG_LOG(("[AyuGram] Scheduling message"));
|
||||
auto current = base::unixtime::now();
|
||||
album->options.scheduled = current + 12;
|
||||
}
|
||||
|
||||
auto sample = (HistoryItem*)nullptr;
|
||||
auto medias = QVector<MTPInputSingleMedia>();
|
||||
medias.reserve(album->items.size());
|
||||
|
|
43
Telegram/SourceFiles/ayu/ayu_settings.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "ayu_settings.h"
|
||||
|
||||
namespace AyuSettings {
|
||||
const QString filename = "tdata/ayu_settings.json";
|
||||
const int latestMigration = 1;
|
||||
std::optional<AyuGramSettings> settings = std::nullopt;
|
||||
|
||||
AyuGramSettings &getInstance() {
|
||||
if (!settings.has_value()) {
|
||||
settings = std::optional(AyuGramSettings());
|
||||
}
|
||||
return settings.value();
|
||||
}
|
||||
|
||||
void load() {
|
||||
QFile file(filename);
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QByteArray json = file.readAll();
|
||||
file.close();
|
||||
|
||||
if (!settings.has_value()) {
|
||||
settings = std::optional(AyuGramSettings());
|
||||
}
|
||||
settings->fromJson(json);
|
||||
}
|
||||
|
||||
void save() {
|
||||
if (!settings.has_value()) {
|
||||
settings = std::optional(AyuGramSettings());
|
||||
}
|
||||
|
||||
settings->migrationVersion = latestMigration;
|
||||
QByteArray json = settings->toRawJson();
|
||||
|
||||
QFile file(filename);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(json);
|
||||
file.close();
|
||||
}
|
||||
}
|
103
Telegram/SourceFiles/ayu/ayu_settings.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
#pragma once
|
||||
|
||||
#define QS_HAS_JSON
|
||||
|
||||
#include <lang_auto.h>
|
||||
#include "qserializer.h"
|
||||
|
||||
namespace AyuSettings {
|
||||
class AyuGramSettings : public QSerializer {
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
AyuGramSettings() {
|
||||
migrationVersion = 0;
|
||||
|
||||
sendReadPackets = true;
|
||||
sendOnlinePackets = true;
|
||||
sendOfflinePacketAfterOnline = false;
|
||||
sendUploadProgress = true;
|
||||
useScheduledMessages = false;
|
||||
keepDeletedMessages = false;
|
||||
keepMessagesHistory = false;
|
||||
deletedMark = "🧹";
|
||||
editedMark = tr::lng_edited(tr::now);
|
||||
ghostMode = true;
|
||||
}
|
||||
|
||||
QS_SERIALIZABLE
|
||||
|
||||
QS_FIELD(int, migrationVersion)
|
||||
|
||||
QS_FIELD(bool, sendReadPackets)
|
||||
|
||||
QS_FIELD(bool, sendOnlinePackets)
|
||||
|
||||
QS_FIELD(bool, sendOfflinePacketAfterOnline)
|
||||
|
||||
QS_FIELD(bool, sendUploadProgress)
|
||||
|
||||
QS_FIELD(bool, useScheduledMessages)
|
||||
|
||||
QS_FIELD(bool, keepDeletedMessages)
|
||||
|
||||
QS_FIELD(bool, keepMessagesHistory)
|
||||
|
||||
QS_FIELD(QString, deletedMark)
|
||||
|
||||
QS_FIELD(QString, editedMark)
|
||||
|
||||
QS_FIELD(bool, ghostMode)
|
||||
|
||||
public:
|
||||
void set_migrationVersion(int val) {
|
||||
migrationVersion = val;
|
||||
}
|
||||
|
||||
void set_sendReadPackets(bool val) {
|
||||
sendReadPackets = val;
|
||||
}
|
||||
|
||||
void set_sendOnlinePackets(bool val) {
|
||||
sendOnlinePackets = val;
|
||||
}
|
||||
|
||||
void set_sendOfflinePacketAfterOnline(bool val) {
|
||||
sendOfflinePacketAfterOnline = val;
|
||||
}
|
||||
|
||||
void set_sendUploadProgress(bool val) {
|
||||
sendUploadProgress = val;
|
||||
}
|
||||
|
||||
void set_useScheduledMessages(bool val) {
|
||||
useScheduledMessages = val;
|
||||
}
|
||||
|
||||
void set_keepDeletedMessages(bool val) {
|
||||
keepDeletedMessages = val;
|
||||
}
|
||||
|
||||
void set_keepMessagesHistory(bool val) {
|
||||
keepMessagesHistory = val;
|
||||
}
|
||||
|
||||
void set_deletedMark(QString val) {
|
||||
deletedMark = val;
|
||||
}
|
||||
|
||||
void set_editedMark(QString val) {
|
||||
editedMark = val;
|
||||
}
|
||||
|
||||
void set_ghostMode(bool val) {
|
||||
ghostMode = val;
|
||||
}
|
||||
};
|
||||
|
||||
AyuGramSettings &getInstance();
|
||||
|
||||
void load();
|
||||
|
||||
void save();
|
||||
}
|
13
Telegram/SourceFiles/ayu/ayu_state.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "ayu_state.h"
|
||||
|
||||
namespace AyuState {
|
||||
void setAllowSendReadPacket(bool val, int resetAfter) {
|
||||
allowSendReadPacket.val = val;
|
||||
allowSendReadPacket.resetAfter = resetAfter;
|
||||
}
|
||||
|
||||
bool getAllowSendPacket() {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
return settings->sendReadPackets || processVariable(allowSendReadPacket);
|
||||
}
|
||||
}
|
33
Telegram/SourceFiles/ayu/ayu_state.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "ayu_settings.h"
|
||||
|
||||
namespace AyuState {
|
||||
namespace {
|
||||
class AyuStateVariable {
|
||||
public:
|
||||
bool val;
|
||||
int resetAfter;
|
||||
};
|
||||
|
||||
AyuStateVariable allowSendReadPacket;
|
||||
|
||||
bool processVariable(AyuStateVariable& variable) {
|
||||
if (variable.resetAfter == -1) {
|
||||
return variable.val;
|
||||
}
|
||||
|
||||
variable.resetAfter -= 1;
|
||||
auto val = variable.val;
|
||||
|
||||
if (variable.resetAfter == 0) {
|
||||
variable.val = false;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
void setAllowSendReadPacket(bool val, int resetAfter = 1);
|
||||
bool getAllowSendPacket();
|
||||
}
|
38
Telegram/SourceFiles/ayu/boxes/confirmation_box.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include "confirmation_box.h"
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "lang_auto.h"
|
||||
|
||||
namespace AyuUi {
|
||||
ConfirmationBox::ConfirmationBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController *> controller) : _controller(controller) {
|
||||
//
|
||||
}
|
||||
|
||||
void ConfirmationBox::prepare() {
|
||||
setTitle(rpl::single(QString("Confirmation for SRead")));
|
||||
setDimensions(st::boxWideWidth, st::boxPadding.top());
|
||||
|
||||
addButton(rpl::single(QString("OK")), [=, this] {
|
||||
ReadAllPeers();
|
||||
closeBox();
|
||||
});
|
||||
addButton(tr::lng_cancel(), [=, this] { closeBox(); });
|
||||
}
|
||||
|
||||
void ConfirmationBox::ReadAllPeers() {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
auto prev = settings->sendReadPackets;
|
||||
settings->set_sendReadPackets(true);
|
||||
|
||||
auto chats = _controller->session().data().chatsList();
|
||||
Window::MarkAsReadChatListHack(chats);
|
||||
|
||||
settings->set_sendReadPackets(prev);
|
||||
}
|
||||
}
|
14
Telegram/SourceFiles/ayu/boxes/confirmation_box.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include "ui/layers/box_content.h"
|
||||
#include "window/window_main_menu.h"
|
||||
|
||||
namespace AyuUi {
|
||||
class ConfirmationBox : public Ui::BoxContent {
|
||||
public:
|
||||
ConfirmationBox(QWidget*, not_null<Window::SessionController *> controller);
|
||||
protected:
|
||||
void prepare() override;
|
||||
private:
|
||||
void ReadAllPeers();
|
||||
not_null<Window::SessionController*> _controller;
|
||||
};
|
||||
}
|
82
Telegram/SourceFiles/ayu/boxes/edit_deleted_mark.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "edit_deleted_mark.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "base/random.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/fields/special_fields.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "data/data_cloud_file.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include "storage/localstorage.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
EditDeletedMarkBox::EditDeletedMarkBox(QWidget *) :
|
||||
_text(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
rpl::single(QString("Deleted Mark")),
|
||||
AyuSettings::getInstance().deletedMark) {
|
||||
}
|
||||
|
||||
void EditDeletedMarkBox::prepare() {
|
||||
const auto defaultDeletedMark = "🧹";
|
||||
auto newHeight = st::contactPadding.top() + _text->height();
|
||||
|
||||
setTitle(rpl::single(QString("Edit Deleted Mark")));
|
||||
|
||||
newHeight += st::boxPadding.bottom() + st::contactPadding.bottom();
|
||||
setDimensions(st::boxWidth, newHeight);
|
||||
|
||||
addLeftButton(rpl::single(QString("Reset")), [=] { _text->setText(defaultDeletedMark); });
|
||||
|
||||
addButton(tr::lng_settings_save(), [=] { save(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
connect(_text, &Ui::InputField::submitted, [=] { submit(); });
|
||||
}
|
||||
|
||||
void EditDeletedMarkBox::setInnerFocus() {
|
||||
_text->setFocusFast();
|
||||
}
|
||||
|
||||
void EditDeletedMarkBox::submit() {
|
||||
if (_text->getLastText().trimmed().isEmpty()) {
|
||||
_text->setFocus();
|
||||
_text->showError();
|
||||
} else {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
void EditDeletedMarkBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_text->resize(
|
||||
width()
|
||||
- st::boxPadding.left()
|
||||
- st::newGroupInfoPadding.left()
|
||||
- st::boxPadding.right(),
|
||||
_text->height());
|
||||
|
||||
const auto left = st::boxPadding.left() + st::newGroupInfoPadding.left();
|
||||
_text->moveToLeft(left, st::contactPadding.top());
|
||||
}
|
||||
|
||||
void EditDeletedMarkBox::save() {
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
settings->deletedMark = _text->getLastText();
|
||||
Local::writeSettings();
|
||||
|
||||
closeBox();
|
||||
}
|
22
Telegram/SourceFiles/ayu/boxes/edit_deleted_mark.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class EditDeletedMarkBox : public Ui::BoxContent {
|
||||
public:
|
||||
EditDeletedMarkBox(QWidget*);
|
||||
|
||||
protected:
|
||||
void setInnerFocus() override;
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
void submit();
|
||||
void save();
|
||||
|
||||
object_ptr<Ui::InputField> _text;
|
||||
};
|
85
Telegram/SourceFiles/ayu/boxes/edit_edited_mark.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include "edit_edited_mark.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "base/random.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/fields/special_fields.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "data/data_cloud_file.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include "storage/localstorage.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
EditEditedMarkBox::EditEditedMarkBox(QWidget *) :
|
||||
_text(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
rpl::single(QString("Edited mark")),
|
||||
AyuSettings::getInstance().editedMark) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EditEditedMarkBox::prepare() {
|
||||
const auto defaultEditedMark = tr::lng_edited(tr::now);
|
||||
auto newHeight = st::contactPadding.top() + _text->height();
|
||||
|
||||
setTitle(rpl::single(QString("Edit edited Mark")));
|
||||
|
||||
newHeight += st::boxPadding.bottom() + st::contactPadding.bottom();
|
||||
setDimensions(st::boxWidth, newHeight);
|
||||
|
||||
addLeftButton(rpl::single(QString("Reset")), [=] { _text->setText(defaultEditedMark); });
|
||||
addButton(tr::lng_settings_save(), [=] { save(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
connect(_text, &Ui::InputField::submitted, [=] { submit(); });
|
||||
}
|
||||
|
||||
|
||||
void EditEditedMarkBox::setInnerFocus() {
|
||||
_text->setFocusFast();
|
||||
}
|
||||
|
||||
void EditEditedMarkBox::submit() {
|
||||
if (_text->getLastText().trimmed().isEmpty()) {
|
||||
_text->setFocus();
|
||||
_text->showError();
|
||||
} else {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
void EditEditedMarkBox::resizeEvent(QResizeEvent *e) {
|
||||
BoxContent::resizeEvent(e);
|
||||
|
||||
_text->resize(
|
||||
width()
|
||||
- st::boxPadding.left()
|
||||
- st::newGroupInfoPadding.left()
|
||||
- st::boxPadding.right(),
|
||||
_text->height());
|
||||
|
||||
const auto left = st::boxPadding.left() + st::newGroupInfoPadding.left();
|
||||
_text->moveToLeft(left, st::contactPadding.top());
|
||||
}
|
||||
|
||||
void EditEditedMarkBox::save() {
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
settings->editedMark = _text->getLastText();
|
||||
Local::writeSettings();
|
||||
|
||||
closeBox();
|
||||
}
|
22
Telegram/SourceFiles/ayu/boxes/edit_edited_mark.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class EditEditedMarkBox : public Ui::BoxContent {
|
||||
public:
|
||||
EditEditedMarkBox(QWidget*);
|
||||
|
||||
protected:
|
||||
void setInnerFocus() override;
|
||||
void prepare() override;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private:
|
||||
void submit();
|
||||
void save();
|
||||
|
||||
object_ptr<Ui::InputField> _text;
|
||||
};
|
44
Telegram/SourceFiles/ayu/context_menu/context_menu.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "context_menu.h"
|
||||
#include "history/history_inner_widget.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "message_history_box.h"
|
||||
#include "ayu/database/ayu_database.h"
|
||||
#include "ayu/ayu_state.h"
|
||||
|
||||
namespace AyuUi {
|
||||
AyuPopupMenu::AyuPopupMenu(HistoryInner *parent) {
|
||||
_ayuSubMenu = std::make_unique<Ui::PopupMenu>(parent, st::popupMenuWithIcons);
|
||||
}
|
||||
|
||||
void AyuPopupMenu::addHistoryAction(HistoryItem *item) {
|
||||
if (AyuDatabase::editedMessagesTableExists() && !((AyuDatabase::getEditedMessages(item)).empty())) {
|
||||
_ayuSubMenu->addAction(QString("History"), [=] {
|
||||
auto box = Box<MessageHistoryBox>(item);
|
||||
Ui::show(std::move(box));
|
||||
}, &st::menuIconInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void AyuPopupMenu::addHideMessageAction(HistoryItem *item) const {
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
const auto history = item->history();
|
||||
_ayuSubMenu->addAction(QString("Hide"), [=]() {
|
||||
const auto initKeepDeleted = settings->keepDeletedMessages;
|
||||
|
||||
settings->set_keepDeletedMessages(false);
|
||||
history->destroyMessage(item);
|
||||
settings->set_keepDeletedMessages(initKeepDeleted);
|
||||
}, &st::menuIconClear);
|
||||
}
|
||||
|
||||
void AyuPopupMenu::addReadUntilAction(HistoryItem *item) const {
|
||||
const auto history = item->history();
|
||||
_ayuSubMenu->addAction(QString("Read until"), [=]() {
|
||||
AyuState::setAllowSendReadPacket(true);
|
||||
history->session().data().histories().readInboxOnNewMessage(item);
|
||||
}, &st::menuIconShowInChat);
|
||||
}
|
||||
} // namespace AyuUi
|
92
Telegram/SourceFiles/ayu/context_menu/context_menu.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include "history/history_inner_widget.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/effects/path_shift_gradient.h"
|
||||
#include "ui/effects/message_sending_animation_controller.h"
|
||||
#include "ui/effects/reaction_fly_animation.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
#include "ui/boxes/report_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/controls/delete_message_context_action.h"
|
||||
#include "ui/controls/who_reacted_context_action.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "ui/inactive_press.h"
|
||||
#include "window/window_adaptive.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "boxes/about_sponsored_box.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "boxes/report_messages_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "boxes/translate_box.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "chat_helpers/emoji_interactions.h"
|
||||
#include "history/history_widget.h"
|
||||
#include "history/view/history_view_translate_tracker.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/qt/qt_common_adapters.h"
|
||||
#include "base/qt/qt_key_modifiers.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "mainwindow.h"
|
||||
#include "layout/layout_selection.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "main/session/send_as_peers.h"
|
||||
#include "menu/menu_item_download_files.h"
|
||||
#include "core/application.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_file_click_handler.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_sponsored_messages.h"
|
||||
#include "dialogs/ui/dialogs_video_userpic.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_window.h" // st::windowMinWidth
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
#include "history/view/history_view_context_menu.h"
|
||||
|
||||
#include <styles/style_info.h>
|
||||
#include <ayu/ayu_settings.h>
|
||||
|
||||
namespace AyuUi {
|
||||
class AyuPopupMenu {
|
||||
|
||||
public:
|
||||
AyuPopupMenu(HistoryInner *parent);
|
||||
|
||||
void addHistoryAction(HistoryItem *item);
|
||||
|
||||
void addHideMessageAction(HistoryItem *item) const;
|
||||
|
||||
void addReadUntilAction(HistoryItem *item) const;
|
||||
|
||||
std::unique_ptr<Ui::PopupMenu> _ayuSubMenu;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#include <styles/style_layers.h>
|
||||
#include <styles/style_boxes.h>
|
||||
#include <ui/effects/scroll_content_shadow.h>
|
||||
#include <styles/style_settings.h>
|
||||
#include "message_history_box.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/database/ayu_database.h"
|
||||
#include "history/history.h"
|
||||
|
||||
using namespace Settings;
|
||||
|
||||
namespace AyuUi {
|
||||
MessageHistoryBox::MessageHistoryBox(QWidget *, HistoryItem *item)
|
||||
: _content(this), _scroll(base::make_unique_q<Ui::ScrollArea>(this, st::boxScroll)) {
|
||||
setupControls();
|
||||
addEditedMessagesToLayout(item);
|
||||
}
|
||||
|
||||
void MessageHistoryBox::setupControls() {
|
||||
_content.create(this);
|
||||
|
||||
_content->resizeToWidth(st::boxWideWidth);
|
||||
_content->moveToLeft(0, 0);
|
||||
|
||||
_content->heightValue(
|
||||
) | rpl::start_to_stream(_contentHeight, _content->lifetime());
|
||||
|
||||
_scroll->setOwnedWidget(
|
||||
object_ptr<Ui::RpWidget>::fromRaw(_content));
|
||||
}
|
||||
|
||||
void MessageHistoryBox::resizeEvent(QResizeEvent *e) {
|
||||
_scroll->resize(width(), height() - st::boxPhotoPadding.top() - st::boxPadding.bottom());
|
||||
_scroll->move(0, st::boxPadding.top());
|
||||
|
||||
if (_content) {
|
||||
_content->resize(_scroll->width(), _content->height());
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHistoryBox::prepare() {
|
||||
setTitle(rpl::single(QString("Message history")));
|
||||
|
||||
// setDimensionsToContent(st::boxWideWidth, _content);
|
||||
setDimensions(st::boxWideWidth, 900);
|
||||
Ui::SetupShadowsToScrollContent(this, _scroll, _contentHeight.events());
|
||||
}
|
||||
|
||||
void MessageHistoryBox::addEditedMessagesToLayout(HistoryItem *item) {
|
||||
auto messages = AyuDatabase::getEditedMessages(item);
|
||||
if (messages.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& message : messages) {
|
||||
AddSkip(_content);
|
||||
AddDividerText(_content, rpl::single(QString::fromStdString(message.text)));
|
||||
AddSkip(_content);
|
||||
}
|
||||
}
|
||||
}
|
22
Telegram/SourceFiles/ayu/context_menu/message_history_box.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <ui/layers/box_content.h>
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "history/history_item.h"
|
||||
|
||||
namespace AyuUi {
|
||||
class MessageHistoryBox : public Ui::BoxContent {
|
||||
public:
|
||||
MessageHistoryBox(QWidget*, HistoryItem *item);
|
||||
protected:
|
||||
void prepare() override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
private:
|
||||
void setupControls();
|
||||
void addEditedMessagesToLayout(HistoryItem *item);
|
||||
|
||||
object_ptr<Ui::VerticalLayout> _content;
|
||||
const base::unique_qptr<Ui::ScrollArea> _scroll;
|
||||
|
||||
rpl::event_stream<int> _contentHeight;
|
||||
};
|
||||
}
|
74
Telegram/SourceFiles/ayu/database/ayu_database.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include "ayu_database.h"
|
||||
|
||||
#include "entities.h"
|
||||
#include "ayu/sqlite/sqlite_orm.h"
|
||||
#include "QtCore/QString"
|
||||
#include "main/main_session.h"
|
||||
|
||||
using namespace sqlite_orm;
|
||||
auto storage = make_storage("ayugram.db",
|
||||
make_table("editedmessage",
|
||||
make_column("userId", &EditedMessage::userId),
|
||||
make_column("dialogId", &EditedMessage::dialogId),
|
||||
make_column("messageId", &EditedMessage::messageId),
|
||||
make_column("text", &EditedMessage::text),
|
||||
make_column("isDocument", &EditedMessage::isDocument),
|
||||
make_column("path", &EditedMessage::path),
|
||||
make_column("date", &EditedMessage::date)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
namespace AyuDatabase {
|
||||
void addEditedMessage(
|
||||
long userId,
|
||||
long dialogId,
|
||||
long messageId,
|
||||
const QString &text,
|
||||
bool isDocument,
|
||||
QString path,
|
||||
long date) {
|
||||
|
||||
EditedMessage entity;
|
||||
entity.userId = userId;
|
||||
entity.dialogId = dialogId;
|
||||
entity.messageId = messageId;
|
||||
entity.text = text.toStdString();
|
||||
entity.isDocument = isDocument;
|
||||
entity.path = path.toStdString();
|
||||
entity.date = date;
|
||||
|
||||
storage.sync_schema();
|
||||
|
||||
storage.begin_transaction();
|
||||
storage.insert(entity);
|
||||
storage.commit();
|
||||
}
|
||||
|
||||
std::vector<EditedMessage> getEditedMessages(
|
||||
long userId,
|
||||
long dialogId,
|
||||
long messageId
|
||||
) {
|
||||
|
||||
return storage.get_all<EditedMessage>(
|
||||
where(
|
||||
c(&EditedMessage::userId) == userId and
|
||||
c(&EditedMessage::dialogId) == dialogId and
|
||||
c(&EditedMessage::messageId) == messageId)
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<EditedMessage> getEditedMessages(HistoryItem *item) {
|
||||
auto userId = item->displayFrom()->id.value;
|
||||
auto dialogId = item->history()->peer->id.value;
|
||||
auto msgId = item->id.bare;
|
||||
// auto some = &item->history()->session().account();
|
||||
|
||||
return getEditedMessages((long) userId, (long) dialogId, (long) msgId);
|
||||
}
|
||||
|
||||
bool editedMessagesTableExists() {
|
||||
return storage.table_exists("editedmessage");
|
||||
}
|
||||
}
|
26
Telegram/SourceFiles/ayu/database/ayu_database.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "entities.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history.h"
|
||||
|
||||
namespace AyuDatabase {
|
||||
void addEditedMessage(
|
||||
long userId,
|
||||
long dialogId,
|
||||
long messageId,
|
||||
const QString& text,
|
||||
bool isDocument,
|
||||
QString path,
|
||||
long date);
|
||||
|
||||
std::vector<EditedMessage> getEditedMessages(
|
||||
long userId,
|
||||
long dialogId,
|
||||
long messageId
|
||||
);
|
||||
|
||||
std::vector<EditedMessage> getEditedMessages(HistoryItem *item);
|
||||
|
||||
bool editedMessagesTableExists();
|
||||
}
|
17
Telegram/SourceFiles/ayu/database/entities.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
// https://github.com/AyuGram/AyuGram4A/blob/main/TMessagesProj/src/main/java/com/radolyn/ayugram/database/entities/EditedMessage.java
|
||||
class EditedMessage {
|
||||
public:
|
||||
long userId;
|
||||
long dialogId;
|
||||
long messageId;
|
||||
|
||||
std::string text;
|
||||
bool isDocument;
|
||||
std::string path;
|
||||
long date;
|
||||
};
|
849
Telegram/SourceFiles/ayu/qserializer.h
Normal file
|
@ -0,0 +1,849 @@
|
|||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2021 Agadzhanov Vladimir
|
||||
Portions Copyright (c) 2021 Jerry Jacobs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QSERIALIZER_H
|
||||
#define QSERIALIZER_H
|
||||
|
||||
/* JSON */
|
||||
#ifdef QS_HAS_JSON
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
#endif
|
||||
|
||||
/* XML */
|
||||
#ifdef QS_HAS_XML
|
||||
#include <QtXml/QDomDocument>
|
||||
#include <QtXml/QDomElement>
|
||||
#endif
|
||||
|
||||
/* META OBJECT SYSTEM */
|
||||
#include <QVariant>
|
||||
#include <QMetaProperty>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaType>
|
||||
|
||||
#include <type_traits>
|
||||
#include <QDebug>
|
||||
|
||||
#define QS_VERSION "1.2"
|
||||
|
||||
/* Generate metaObject method */
|
||||
#define QS_META_OBJECT_METHOD \
|
||||
virtual const QMetaObject * metaObject() const { \
|
||||
return &this->staticMetaObject; \
|
||||
} \
|
||||
|
||||
#define QSERIALIZABLE \
|
||||
Q_GADGET \
|
||||
QS_META_OBJECT_METHOD
|
||||
|
||||
/* Mark class as serializable */
|
||||
#define QS_SERIALIZABLE QS_META_OBJECT_METHOD
|
||||
|
||||
#ifdef QS_HAS_XML
|
||||
Q_DECLARE_METATYPE(QDomNode)
|
||||
Q_DECLARE_METATYPE(QDomElement)
|
||||
#endif
|
||||
|
||||
class QSerializer {
|
||||
Q_GADGET
|
||||
QS_SERIALIZABLE
|
||||
public:
|
||||
virtual ~QSerializer() = default;
|
||||
|
||||
#ifdef QS_HAS_JSON
|
||||
/*! \brief Convert QJsonValue in QJsonDocument as QByteArray. */
|
||||
static QByteArray toByteArray(const QJsonValue & value){
|
||||
return QJsonDocument(value.toObject()).toJson();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef QS_HAS_XML
|
||||
/*! \brief Convert QDomNode in QDomDocument as QByteArray. */
|
||||
static QByteArray toByteArray(const QDomNode & value) {
|
||||
QDomDocument doc = value.toDocument();
|
||||
return doc.toByteArray();
|
||||
}
|
||||
|
||||
/*! \brief Make xml processing instruction (hat) and returns new XML QDomDocument. On deserialization procedure all processing instructions will be ignored. */
|
||||
static QDomDocument appendXmlHat(const QDomNode &node, const QString & encoding, const QString & version = "1.0"){
|
||||
QDomDocument doc = node.toDocument();
|
||||
QDomNode xmlNode = doc.createProcessingInstruction("xml", QString("version=\"%1\" encoding=\"%2\"").arg(version).arg(encoding));
|
||||
doc.insertBefore(xmlNode, doc.firstChild());
|
||||
return doc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef QS_HAS_JSON
|
||||
/*! \brief Serialize all accessed JSON propertyes for this object. */
|
||||
QJsonObject toJson() const {
|
||||
QJsonObject json;
|
||||
for(int i = 0; i < metaObject()->propertyCount(); i++)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
if(QString(metaObject()->property(i).typeName()) != QMetaType::typeName(qMetaTypeId<QJsonValue>())) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if(metaObject()->property(i).metaType().id() != QMetaType::QJsonValue) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
json.insert(metaObject()->property(i).name(), metaObject()->property(i).readOnGadget(this).toJsonValue());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
/*! \brief Returns QByteArray representation this object using json-serialization. */
|
||||
QByteArray toRawJson() const {
|
||||
return toByteArray(toJson());
|
||||
}
|
||||
|
||||
/*! \brief Deserialize all accessed XML propertyes for this object. */
|
||||
void fromJson(const QJsonValue & val) {
|
||||
if(val.isObject())
|
||||
{
|
||||
QJsonObject json = val.toObject();
|
||||
QStringList keys = json.keys();
|
||||
int propCount = metaObject()->propertyCount();
|
||||
for(int i = 0; i < propCount; i++)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
if(QString(metaObject()->property(i).typeName()) != QMetaType::typeName(qMetaTypeId<QJsonValue>())) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if(metaObject()->property(i).metaType().id() != QMetaType::QJsonValue) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(auto key : json.keys())
|
||||
{
|
||||
if(key == metaObject()->property(i).name())
|
||||
{
|
||||
metaObject()->property(i).writeOnGadget(this, json.value(key));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Deserialize all accessed JSON propertyes for this object. */
|
||||
void fromJson(const QByteArray & data) {
|
||||
fromJson(QJsonDocument::fromJson(data).object());
|
||||
}
|
||||
#endif // QS_HAS_JSON
|
||||
|
||||
#ifdef QS_HAS_XML
|
||||
/*! \brief Serialize all accessed XML propertyes for this object. */
|
||||
QDomNode toXml() const {
|
||||
QDomDocument doc;
|
||||
QDomElement el = doc.createElement(metaObject()->className());
|
||||
for(int i = 0; i < metaObject()->propertyCount(); i++)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
if(QString(metaObject()->property(i).typeName()) != QMetaType::typeName(qMetaTypeId<QDomNode>())) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if(metaObject()->property(i).metaType().id() != qMetaTypeId<QDomNode>()) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
el.appendChild(QDomNode(metaObject()->property(i).readOnGadget(this).value<QDomNode>()));
|
||||
}
|
||||
doc.appendChild(el);
|
||||
return doc;
|
||||
}
|
||||
|
||||
/*! \brief Returns QByteArray representation this object using xml-serialization. */
|
||||
QByteArray toRawXml() const {
|
||||
return toByteArray(toXml());
|
||||
}
|
||||
|
||||
/*! \brief Deserialize all accessed XML propertyes for this object. */
|
||||
void fromXml(const QDomNode & val) {
|
||||
QDomNode doc = val;
|
||||
|
||||
auto n = doc.firstChildElement(metaObject()->className());
|
||||
|
||||
if(!n.isNull()) {
|
||||
for(int i = 0; i < metaObject()->propertyCount(); i++) {
|
||||
QString name = metaObject()->property(i).name();
|
||||
QDomElement tmp = metaObject()->property(i).readOnGadget(this).value<QDomNode>().firstChildElement();
|
||||
|
||||
auto f = n.firstChildElement(tmp.tagName());
|
||||
metaObject()->property(i).writeOnGadget(this, QVariant::fromValue<QDomNode>(f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < metaObject()->propertyCount(); i++) {
|
||||
QString name = metaObject()->property(i).name();
|
||||
auto f = doc.firstChildElement(name);
|
||||
metaObject()->property(i).writeOnGadget(this, QVariant::fromValue<QDomNode>(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Deserialize all accessed XML propertyes for this object. */
|
||||
void fromXml(const QByteArray & data) {
|
||||
QDomDocument d;
|
||||
d.setContent(data);
|
||||
fromXml(d);
|
||||
}
|
||||
#endif // QS_HAS_XML
|
||||
};
|
||||
|
||||
#define GET(prefix, name) get_##prefix##_##name
|
||||
#define SET(prefix, name) set_##prefix##_##name
|
||||
|
||||
/* Create variable */
|
||||
#define QS_DECLARE_MEMBER(type, name) \
|
||||
public : \
|
||||
type name = type(); \
|
||||
|
||||
/* Create JSON property and methods for primitive type field*/
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_FIELD(type, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json, name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonValue val = QJsonValue::fromVariant(QVariant(name)); \
|
||||
return val; \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname){ \
|
||||
name = varname.toVariant().value<type>(); \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_FIELD(type, name)
|
||||
#endif
|
||||
|
||||
/* Create XML property and methods for primitive type field*/
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_FIELD(type, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
QDomDocument doc; \
|
||||
QString strname = #name; \
|
||||
QDomElement element = doc.createElement(strname); \
|
||||
QDomText valueOfProp = doc.createTextNode(QVariant(name).toString()); \
|
||||
element.appendChild(valueOfProp); \
|
||||
doc.appendChild(element); \
|
||||
return QDomNode(doc); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode &node) { \
|
||||
if(!node.isNull() && node.isElement()){ \
|
||||
QDomElement domElement = node.toElement(); \
|
||||
if(domElement.tagName() == #name) \
|
||||
name = QVariant(domElement.text()).value<type>(); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_FIELD(type, name)
|
||||
#endif
|
||||
|
||||
/* Generate JSON-property and methods for primitive type objects */
|
||||
/* This collection must be provide method append(T) (it's can be QList, QVector) */
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_ARRAY(itemType, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json, name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonArray val; \
|
||||
for(int i = 0; i < name.size(); i++) \
|
||||
val.push_back(name.at(i)); \
|
||||
return QJsonValue::fromVariant(val); \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname) { \
|
||||
if(!varname.isArray()) \
|
||||
return; \
|
||||
name.clear(); \
|
||||
QJsonArray val = varname.toArray(); \
|
||||
for(auto item : val) { \
|
||||
itemType tmp; \
|
||||
tmp = item.toVariant().value<itemType>(); \
|
||||
name.append(tmp); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_ARRAY(itemType, name)
|
||||
#endif
|
||||
|
||||
/* Generate XML-property and methods for primitive type objects */
|
||||
/* This collection must be provide method append(T) (it's can be QList, QVector) */
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_ARRAY(itemType, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
QDomDocument doc; \
|
||||
QString strname = #name; \
|
||||
QDomElement arrayXml = doc.createElement(QString(strname)); \
|
||||
arrayXml.setAttribute("type", "array"); \
|
||||
\
|
||||
for(int i = 0; i < name.size(); i++) { \
|
||||
itemType item = name.at(i); \
|
||||
QDomElement itemXml = doc.createElement("item"); \
|
||||
itemXml.setAttribute("type", #itemType); \
|
||||
itemXml.setAttribute("index", i); \
|
||||
itemXml.appendChild(doc.createTextNode(QVariant(item).toString())); \
|
||||
arrayXml.appendChild(itemXml); \
|
||||
} \
|
||||
\
|
||||
doc.appendChild(arrayXml); \
|
||||
return QDomNode(doc); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode & node) { \
|
||||
QDomNode domNode = node.firstChild(); \
|
||||
name.clear(); \
|
||||
while(!domNode.isNull()) { \
|
||||
if(domNode.isElement()) { \
|
||||
QDomElement domElement = domNode.toElement(); \
|
||||
name.append(QVariant(domElement.text()).value<itemType>()); \
|
||||
} \
|
||||
domNode = domNode.nextSibling(); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_ARRAY(itemType, name)
|
||||
#endif
|
||||
|
||||
|
||||
/* Generate JSON-property and methods for some custom class */
|
||||
/* Custom type must be provide methods fromJson and toJson or inherit from QSerializer */
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_OBJECT(type, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json, name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonObject val = name.toJson(); \
|
||||
return QJsonValue(val); \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname) { \
|
||||
if(!varname.isObject()) \
|
||||
return; \
|
||||
name.fromJson(varname); \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_OBJECT(type, name)
|
||||
#endif
|
||||
|
||||
/* Generate XML-property and methods for some custom class */
|
||||
/* Custom type must be provide methods fromJson and toJson or inherit from QSerializer */
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_OBJECT(type, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
return name.toXml(); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode & node){ \
|
||||
name.fromXml(node); \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_OBJECT(type, name)
|
||||
#endif
|
||||
|
||||
/* Generate JSON-property and methods for collection of custom type objects */
|
||||
/* Custom item type must be provide methods fromJson and toJson or inherit from QSerializer */
|
||||
/* This collection must be provide method append(T) (it's can be QList, QVector) */
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_ARRAY_OBJECTS(itemType, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json, name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonArray val; \
|
||||
for(int i = 0; i < name.size(); i++) \
|
||||
val.push_back(name.at(i).toJson()); \
|
||||
return QJsonValue::fromVariant(val); \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname) { \
|
||||
if(!varname.isArray()) \
|
||||
return; \
|
||||
name.clear(); \
|
||||
QJsonArray val = varname.toArray(); \
|
||||
for(int i = 0; i < val.size(); i++) { \
|
||||
itemType tmp; \
|
||||
tmp.fromJson(val.at(i)); \
|
||||
name.append(tmp); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_ARRAY_OBJECTS(itemType, name)
|
||||
#endif
|
||||
|
||||
/* Generate XML-property and methods for collection of custom type objects */
|
||||
/* Custom type must be provide methods fromXml and toXml or inherit from QSerializer */
|
||||
/* This collection must be provide method append(T) (it's can be QList, QVector) */
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_ARRAY_OBJECTS(itemType, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
QDomDocument doc; \
|
||||
QDomElement element = doc.createElement(#name); \
|
||||
element.setAttribute("type", "array"); \
|
||||
for(int i = 0; i < name.size(); i++) \
|
||||
element.appendChild(name.at(i).toXml()); \
|
||||
doc.appendChild(element); \
|
||||
return QDomNode(doc); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode & node) { \
|
||||
name.clear(); \
|
||||
QDomNodeList nodesList = node.childNodes(); \
|
||||
for(int i = 0; i < nodesList.size(); i++) { \
|
||||
itemType tmp; \
|
||||
tmp.fromXml(nodesList.at(i)); \
|
||||
name.append(tmp); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_ARRAY_OBJECTS(itemType, name)
|
||||
#endif
|
||||
|
||||
/* Generate JSON-property and methods for dictionary of simple fields (int, bool, QString, ...) */
|
||||
/* Custom type must be inherit from QSerializer */
|
||||
/* This collection must be provide method insert(KeyT, ValueT) (it's can be QMap, QHash) */
|
||||
/* THIS IS FOR QT DICTIONARY TYPES, for example QMap<int, QString>, QMap<int,int>, ...*/
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_QT_DICT(map, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json,name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonObject val; \
|
||||
for(auto p = name.constBegin(); p != name.constEnd(); ++p) { \
|
||||
val.insert( \
|
||||
QVariant(p.key()).toString(), \
|
||||
QJsonValue::fromVariant(QVariant(p.value()))); \
|
||||
} \
|
||||
return val; \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname) { \
|
||||
QJsonObject val = varname.toObject(); \
|
||||
name.clear(); \
|
||||
for(auto p = val.constBegin() ;p != val.constEnd(); ++p) { \
|
||||
name.insert( \
|
||||
QVariant(p.key()).value<map::key_type>(), \
|
||||
QVariant(p.value()).value<map::mapped_type>()); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_QT_DICT(map, name)
|
||||
#endif
|
||||
|
||||
/* Generate XML-property and methods for dictionary of simple fields (int, bool, QString, ...) */
|
||||
/* Custom type must be inherit from QSerializer */
|
||||
/* This collection must be provide method insert(KeyT, ValueT) (it's can be QMap, QHash) */
|
||||
/* THIS IS FOR QT DICTIONARY TYPES, for example QMap<int, QString>, QMap<int,int>, ...*/
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_QT_DICT(map, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
QDomDocument doc; \
|
||||
QDomElement element = doc.createElement(#name); \
|
||||
element.setAttribute("type", "map"); \
|
||||
for(auto p = name.begin(); p != name.end(); ++p) \
|
||||
{ \
|
||||
QDomElement e = doc.createElement("item"); \
|
||||
e.setAttribute("key", QVariant(p.key()).toString()); \
|
||||
e.setAttribute("value", QVariant(p.value()).toString()); \
|
||||
element.appendChild(e); \
|
||||
} \
|
||||
doc.appendChild(element); \
|
||||
return QDomNode(doc); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode & node) { \
|
||||
if(!node.isNull() && node.isElement()) \
|
||||
{ \
|
||||
QDomElement root = node.toElement(); \
|
||||
if(root.tagName() == #name) \
|
||||
{ \
|
||||
QDomNodeList childs = root.childNodes(); \
|
||||
\
|
||||
for(int i = 0; i < childs.size(); ++i) { \
|
||||
QDomElement item = childs.at(i).toElement(); \
|
||||
name.insert(QVariant(item.attributeNode("key").value()).value<map::key_type>(), \
|
||||
QVariant(item.attributeNode("value").value()).value<map::mapped_type>()); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_QT_DICT(map, name)
|
||||
#endif
|
||||
|
||||
|
||||
/* Generate JSON-property and methods for dictionary of custom type objects */
|
||||
/* Custom type must be inherit from QSerializer */
|
||||
/* This collection must be provide method inserv(KeyT, ValueT) (it's can be QMap, QHash) */
|
||||
/* THIS IS FOR QT DICTIONARY TYPES, for example QMap<int, CustomSerializableType> */
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_QT_DICT_OBJECTS(map, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json,name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonObject val; \
|
||||
for(auto p = name.begin(); p != name.end(); ++p) { \
|
||||
val.insert( \
|
||||
QVariant::fromValue(p.key()).toString(), \
|
||||
p.value().toJson()); \
|
||||
} \
|
||||
return val; \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname) { \
|
||||
QJsonObject val = varname.toObject(); \
|
||||
name.clear(); \
|
||||
for(auto p = val.constBegin();p != val.constEnd(); ++p) { \
|
||||
map::mapped_type tmp; \
|
||||
tmp.fromJson(p.value()); \
|
||||
name.insert( \
|
||||
QVariant(p.key()).value<map::key_type>(), \
|
||||
tmp); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_QT_DICT_OBJECTS(map, name)
|
||||
#endif
|
||||
|
||||
/* Generate XML-property and methods for dictionary of custom type objects */
|
||||
/* Custom type must be inherit from QSerializer */
|
||||
/* This collection must be provide method insert(KeyT, ValueT) (it's can be QMap, QHash) */
|
||||
/* THIS IS FOR QT DICTIONARY TYPES, for example QMap<int, CustomSerializableType> */
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_QT_DICT_OBJECTS(map, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
QDomDocument doc; \
|
||||
QDomElement element = doc.createElement(#name); \
|
||||
element.setAttribute("type", "map"); \
|
||||
for(auto p = name.begin(); p != name.end(); ++p) \
|
||||
{ \
|
||||
QDomElement e = doc.createElement("item"); \
|
||||
e.setAttribute("key", QVariant(p.key()).toString()); \
|
||||
e.appendChild(p.value().toXml()); \
|
||||
element.appendChild(e); \
|
||||
} \
|
||||
doc.appendChild(element); \
|
||||
return QDomNode(doc); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode & node) { \
|
||||
if(!node.isNull() && node.isElement()) \
|
||||
{ \
|
||||
QDomElement root = node.toElement(); \
|
||||
if(root.tagName() == #name) \
|
||||
{ \
|
||||
QDomNodeList childs = root.childNodes(); \
|
||||
\
|
||||
for(int i = 0; i < childs.size(); ++i) { \
|
||||
QDomElement item = childs.at(i).toElement(); \
|
||||
map::mapped_type tmp; \
|
||||
tmp.fromXml(item.firstChild()); \
|
||||
name.insert(QVariant(item.attributeNode("key").value()).value<map::key_type>(), \
|
||||
tmp); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_QT_DICT_OBJECTS(map, name)
|
||||
#endif
|
||||
|
||||
/* Generate JSON-property and methods for dictionary of simple fields (int, bool, QString, ...) */
|
||||
/* Custom type must be inherit from QSerializer */
|
||||
/* This collection must be provide method insert(KeyT, ValueT) (it's can be std::map) */
|
||||
/* THIS IS FOR STL DICTIONARY TYPES, for example std::map<int, QString>, std::map<int,int>, ...*/
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_STL_DICT(map, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json,name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonObject val; \
|
||||
for(auto p : name){ \
|
||||
val.insert( \
|
||||
QVariant::fromValue(p.first).toString(), \
|
||||
QJsonValue::fromVariant(QVariant(p.second))); \
|
||||
} \
|
||||
return val; \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname) { \
|
||||
QJsonObject val = varname.toObject(); \
|
||||
name.clear(); \
|
||||
for(auto p = val.constBegin();p != val.constEnd(); ++p) { \
|
||||
name.insert(std::pair<map::key_type, map::mapped_type>( \
|
||||
QVariant(p.key()).value<map::key_type>(), \
|
||||
QVariant(p.value()).value<map::mapped_type>())); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_STL_DICT(map, name)
|
||||
#endif
|
||||
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_STL_DICT(map, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
QDomDocument doc; \
|
||||
QDomElement element = doc.createElement(#name); \
|
||||
element.setAttribute("type", "map"); \
|
||||
for(auto p : name) \
|
||||
{ \
|
||||
QDomElement e = doc.createElement("item"); \
|
||||
e.setAttribute("key", QVariant(p.first).toString()); \
|
||||
e.setAttribute("value", QVariant(p.second).toString()); \
|
||||
element.appendChild(e); \
|
||||
} \
|
||||
doc.appendChild(element); \
|
||||
return QDomNode(doc); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode & node) { \
|
||||
if(!node.isNull() && node.isElement()) \
|
||||
{ \
|
||||
QDomElement root = node.toElement(); \
|
||||
if(root.tagName() == #name) \
|
||||
{ \
|
||||
QDomNodeList childs = root.childNodes(); \
|
||||
\
|
||||
for(int i = 0; i < childs.size(); ++i) { \
|
||||
QDomElement item = childs.at(i).toElement(); \
|
||||
name.insert(std::pair<map::key_type, map::mapped_type>( \
|
||||
QVariant(item.attributeNode("key").value()).value<map::key_type>(), \
|
||||
QVariant(item.attributeNode("value").value()).value<map::mapped_type>())); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_STL_DICT(map, name)
|
||||
#endif
|
||||
|
||||
/* Generate JSON-property and methods for dictionary of custom type objects */
|
||||
/* Custom type must be inherit from QSerializer */
|
||||
/* This collection must be provide method insert(KeyT, ValueT) (it's can be std::map) */
|
||||
/* THIS IS FOR STL DICTIONARY TYPES, for example std::map<int, CustomSerializableType> */
|
||||
#ifdef QS_HAS_JSON
|
||||
#define QS_JSON_STL_DICT_OBJECTS(map, name) \
|
||||
Q_PROPERTY(QJsonValue name READ GET(json, name) WRITE SET(json,name)) \
|
||||
private: \
|
||||
QJsonValue GET(json, name)() const { \
|
||||
QJsonObject val; \
|
||||
for(auto p : name){ \
|
||||
val.insert( \
|
||||
QVariant::fromValue(p.first).toString(), \
|
||||
p.second.toJson()); \
|
||||
} \
|
||||
return val; \
|
||||
} \
|
||||
void SET(json, name)(const QJsonValue & varname) { \
|
||||
QJsonObject val = varname.toObject(); \
|
||||
name.clear(); \
|
||||
for(auto p = val.constBegin(); p != val.constEnd(); ++p) { \
|
||||
map::mapped_type tmp; \
|
||||
tmp.fromJson(p.value()); \
|
||||
name.insert(std::pair<map::key_type, map::mapped_type>( \
|
||||
QVariant(p.key()).value<map::key_type>(), \
|
||||
tmp)); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_JSON_STL_DICT_OBJECTS(map, name)
|
||||
#endif
|
||||
|
||||
/* Generate XML-property and methods for dictionary of custom type objects */
|
||||
/* Custom type must be inherit from QSerializer */
|
||||
/* This collection must be provide method insert(KeyT, ValueT) (it's can be std::map) */
|
||||
/* THIS IS FOR STL DICTIONARY TYPES, for example std::map<int, CustomSerializableType> */
|
||||
#ifdef QS_HAS_XML
|
||||
#define QS_XML_STL_DICT_OBJECTS(map, name) \
|
||||
Q_PROPERTY(QDomNode name READ GET(xml, name) WRITE SET(xml, name)) \
|
||||
private: \
|
||||
QDomNode GET(xml, name)() const { \
|
||||
QDomDocument doc; \
|
||||
QDomElement element = doc.createElement(#name); \
|
||||
element.setAttribute("type", "map"); \
|
||||
for(auto p : name) \
|
||||
{ \
|
||||
QDomElement e = doc.createElement("item"); \
|
||||
e.setAttribute("key", QVariant(p.first).toString()); \
|
||||
e.appendChild(p.second.toXml()); \
|
||||
element.appendChild(e); \
|
||||
} \
|
||||
doc.appendChild(element); \
|
||||
return QDomNode(doc); \
|
||||
} \
|
||||
void SET(xml, name)(const QDomNode & node) { \
|
||||
if(!node.isNull() && node.isElement()) \
|
||||
{ \
|
||||
QDomElement root = node.toElement(); \
|
||||
if(root.tagName() == #name) \
|
||||
{ \
|
||||
QDomNodeList childs = root.childNodes(); \
|
||||
\
|
||||
for(int i = 0; i < childs.size(); ++i) { \
|
||||
QDomElement item = childs.at(i).toElement(); \
|
||||
map::mapped_type tmp; \
|
||||
tmp.fromXml(item.firstChild()); \
|
||||
name.insert(std::pair<map::key_type, map::mapped_type> ( \
|
||||
QVariant(item.attributeNode("key").value()).value<map::key_type>(), \
|
||||
tmp)); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define QS_XML_STL_DICT_OBJECTS(map, name)
|
||||
#endif
|
||||
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for primitive type field */
|
||||
#define QS_BIND_FIELD(type, name) \
|
||||
QS_JSON_FIELD(type, name) \
|
||||
QS_XML_FIELD(type, name) \
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for collection of primitive type fields */
|
||||
#define QS_BIND_COLLECTION(itemType, name) \
|
||||
QS_JSON_ARRAY(itemType, name) \
|
||||
QS_XML_ARRAY(itemType, name) \
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for custom type object */
|
||||
#define QS_BIND_OBJECT(type, name) \
|
||||
QS_JSON_OBJECT(type, name) \
|
||||
QS_XML_OBJECT(type, name) \
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for collection of custom type objects */
|
||||
#define QS_BIND_COLLECTION_OBJECTS(itemType, name) \
|
||||
QS_JSON_ARRAY_OBJECTS(itemType, name) \
|
||||
QS_XML_ARRAY_OBJECTS(itemType, name) \
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for dictionary with primitive value type for QT DICTIONARY TYPES */
|
||||
#define QS_BIND_QT_DICT(map, name) \
|
||||
QS_JSON_QT_DICT(map, name) \
|
||||
QS_XML_QT_DICT(map, name) \
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for dictionary of custom type objects for QT DICTIONARY TYPES */
|
||||
#define QS_BIND_QT_DICT_OBJECTS(map, name) \
|
||||
QS_JSON_QT_DICT_OBJECTS(map, name) \
|
||||
QS_XML_QT_DICT_OBJECTS(map,name) \
|
||||
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for dictionary with primitive value type for STL DICTIONARY TYPES */
|
||||
#define QS_BIND_STL_DICT(map, name) \
|
||||
QS_JSON_STL_DICT(map, name) \
|
||||
QS_XML_STL_DICT(map, name) \
|
||||
|
||||
|
||||
/* BIND: */
|
||||
/* generate serializable propertyes JSON and XML for dictionary of custom type objects for STL DICTIONARY TYPES */
|
||||
#define QS_BIND_STL_DICT_OBJECTS(map, name) \
|
||||
QS_JSON_STL_DICT_OBJECTS(map, name) \
|
||||
QS_XML_STL_DICT_OBJECTS(map,name) \
|
||||
|
||||
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make primitive field and generate serializable propertyes */
|
||||
/* For example: QS_FIELD(int, digit), QS_FIELD(bool, flag) */
|
||||
#define QS_FIELD(type, name) \
|
||||
QS_DECLARE_MEMBER(type, name) \
|
||||
QS_BIND_FIELD(type, name) \
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make collection of primitive type objects [collectionType<itemType> name] and generate serializable propertyes for this collection */
|
||||
/* This collection must be provide method append(T) (it's can be QList, QVector) */
|
||||
#define QS_COLLECTION(collectionType, itemType, name) \
|
||||
QS_DECLARE_MEMBER(collectionType<itemType>, name) \
|
||||
QS_BIND_COLLECTION(itemType, name) \
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make custom class object and bind serializable propertyes */
|
||||
/* This class must be inherited from QSerializer */
|
||||
#define QS_OBJECT(type,name) \
|
||||
QS_DECLARE_MEMBER(type, name) \
|
||||
QS_BIND_OBJECT(type, name) \
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make collection of custom class objects [collectionType<itemType> name] and bind serializable propertyes */
|
||||
/* This collection must be provide method append(T) (it's can be QList, QVector) */
|
||||
#define QS_COLLECTION_OBJECTS(collectionType, itemType, name) \
|
||||
QS_DECLARE_MEMBER(collectionType<itemType>, name) \
|
||||
QS_BIND_COLLECTION_OBJECTS(itemType, name) \
|
||||
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make dictionary collection of simple types [dictionary<key, itemType> name] and bind serializable propertyes */
|
||||
/* This collection must be QT DICTIONARY TYPE */
|
||||
#define QS_QT_DICT(map, first, second, name) \
|
||||
public: \
|
||||
typedef map<first,second> dict_##name##_t; \
|
||||
dict_##name##_t name = dict_##name##_t(); \
|
||||
QS_BIND_QT_DICT(dict_##name##_t, name) \
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make dictionary collection of custom class objects [dictionary<key, itemType> name] and bind serializable propertyes */
|
||||
/* This collection must be QT DICTIONARY TYPE */
|
||||
#define QS_QT_DICT_OBJECTS(map, first, second, name) \
|
||||
public: \
|
||||
typedef map<first,second> dict_##name##_t; \
|
||||
dict_##name##_t name = dict_##name##_t(); \
|
||||
QS_BIND_QT_DICT_OBJECTS(dict_##name##_t, name) \
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make dictionary collection of simple types [dictionary<key, itemType> name] and bind serializable propertyes */
|
||||
/* This collection must be STL DICTIONARY TYPE */
|
||||
#define QS_STL_DICT(map, first, second, name) \
|
||||
public: \
|
||||
typedef map<first,second> dict_##name##_t; \
|
||||
dict_##name##_t name = dict_##name##_t(); \
|
||||
QS_BIND_STL_DICT(dict_##name##_t, name) \
|
||||
|
||||
/* CREATE AND BIND: */
|
||||
/* Make dictionary collection of custom class objects [dictionary<key, itemType> name] and bind serializable propertyes */
|
||||
/* This collection must be STL DICTIONARY TYPE */
|
||||
#define QS_STL_DICT_OBJECTS(map, first, second, name) \
|
||||
public: \
|
||||
typedef map<first,second> dict_##name##_t; \
|
||||
dict_##name##_t name = dict_##name##_t(); \
|
||||
QS_BIND_STL_DICT_OBJECTS(dict_##name##_t, name) \
|
||||
|
||||
|
||||
|
||||
#endif // QSERIALIZER_H
|
188
Telegram/SourceFiles/ayu/settings/settings_ayu.cpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
#include "ayu/boxes/edit_edited_mark.h"
|
||||
#include "ayu/boxes/edit_deleted_mark.h"
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/settings/settings_ayu.h"
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "boxes/connection_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "lang/lang_instance.h"
|
||||
#include "core/application.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
rpl::producer<QString> Ayu::title() {
|
||||
return rpl::single(QString("AyuGram Settings"));
|
||||
}
|
||||
|
||||
Ayu::Ayu(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController *> controller)
|
||||
: Section(parent) {
|
||||
setupContent(controller);
|
||||
}
|
||||
|
||||
void Ayu::SetupAyuGramSettings(not_null<Ui::VerticalLayout *> container,
|
||||
not_null<Window::SessionController *> controller) {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
|
||||
AddSubsectionTitle(container, rpl::single(QString("General")));
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send read packets")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendReadPackets)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->sendReadPackets);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_sendReadPackets(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send online packets")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendOnlinePackets)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->sendOnlinePackets);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_sendOnlinePackets(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send offline packet after online")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendOfflinePacketAfterOnline)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->sendOfflinePacketAfterOnline);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_sendOfflinePacketAfterOnline(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send typing & upload progress")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendUploadProgress)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->sendUploadProgress);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_sendUploadProgress(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Use scheduled messages to keep offline")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->useScheduledMessages)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->useScheduledMessages);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_useScheduledMessages(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Keep deleted messages")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->keepDeletedMessages)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->keepDeletedMessages);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_keepDeletedMessages(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Keep messages' history")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->keepMessagesHistory)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->keepMessagesHistory);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_keepMessagesHistory(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
auto currentDeletedMark = lifetime().make_state<rpl::variable<QString>>();
|
||||
|
||||
auto btn = AddButtonWithLabel(
|
||||
container,
|
||||
rpl::single(QString("Deleted Mark")),
|
||||
currentDeletedMark->changes(),
|
||||
st::settingsButtonNoIcon
|
||||
);
|
||||
btn->addClickHandler([=]() {
|
||||
auto box = Box<EditDeletedMarkBox>();
|
||||
box->boxClosing() | rpl::start_with_next([=]() {
|
||||
*currentDeletedMark = settings->deletedMark;
|
||||
}, container->lifetime());
|
||||
|
||||
Ui::show(std::move(box));
|
||||
});
|
||||
*currentDeletedMark = settings->deletedMark;
|
||||
|
||||
auto currentEditedMark = lifetime().make_state<rpl::variable<QString>>();
|
||||
|
||||
auto btn2 = AddButtonWithLabel(
|
||||
container,
|
||||
rpl::single(QString("Edited Mark")),
|
||||
currentEditedMark->changes(),
|
||||
st::settingsButtonNoIcon
|
||||
);
|
||||
btn2->addClickHandler([=]() {
|
||||
auto box = Box<EditEditedMarkBox>();
|
||||
box->boxClosing() | rpl::start_with_next([=]() {
|
||||
*currentEditedMark = settings->editedMark;
|
||||
}, container->lifetime());
|
||||
|
||||
Ui::show(std::move(box));
|
||||
});
|
||||
*currentEditedMark = settings->editedMark;
|
||||
|
||||
AddDividerText(container, rpl::single(QString("AyuGram developed and maintained by Radolyn Labs")));
|
||||
}
|
||||
|
||||
void Ayu::setupContent(not_null<Window::SessionController *> controller) {
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
|
||||
SetupAyuGramSettings(content, controller);
|
||||
|
||||
Ui::ResizeFitChild(this, content);
|
||||
}
|
||||
} // namespace Settings
|
||||
|
32
Telegram/SourceFiles/ayu/settings/settings_ayu.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
This file is part of 64Gram Desktop,
|
||||
the unofficial app based on Telegram Desktop.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/TDesktop-x64/tdesktop/blob/dev/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "settings/settings_common.h"
|
||||
|
||||
class BoxContent;
|
||||
|
||||
namespace Window {
|
||||
class Controller;
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Settings {
|
||||
class Ayu : public Section<Ayu> {
|
||||
public:
|
||||
Ayu(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController *> controller);
|
||||
[[nodiscard]] rpl::producer<QString> title() override;
|
||||
|
||||
private:
|
||||
void SetupAyuGramSettings(not_null<Ui::VerticalLayout *> container, not_null<Window::SessionController *> null);
|
||||
void setupContent(not_null<Window::SessionController *> controller);
|
||||
};
|
||||
|
||||
} // namespace Settings
|
247629
Telegram/SourceFiles/ayu/sqlite/sqlite3.c
Normal file
13068
Telegram/SourceFiles/ayu/sqlite/sqlite3.h
Normal file
19520
Telegram/SourceFiles/ayu/sqlite/sqlite_orm.h
Normal file
|
@ -40,11 +40,11 @@ rpl::producer<TextWithEntities> Text2() {
|
|||
lt_gpl_link,
|
||||
rpl::single(Ui::Text::Link(
|
||||
"GNU GPL",
|
||||
"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE")),
|
||||
"https://github.com/AyuGram/AyuGramDesktop/blob/master/LICENSE")),
|
||||
lt_github_link,
|
||||
rpl::single(Ui::Text::Link(
|
||||
"GitHub",
|
||||
"https://github.com/telegramdesktop/tdesktop")),
|
||||
"https://github.com/AyuGram/AyuGramDesktop")),
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ AboutBox::AboutBox(QWidget *parent)
|
|||
}
|
||||
|
||||
void AboutBox::prepare() {
|
||||
setTitle(rpl::single(u"Telegram Desktop"_q));
|
||||
setTitle(rpl::single(u"AyuGram Desktop"_q));
|
||||
|
||||
addButton(tr::lng_close(), [this] { closeBox(); });
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "base/unixtime.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxMessageLength = 4096;
|
||||
|
@ -1335,6 +1338,14 @@ bool SendFilesBox::validateLength(const QString &text) const {
|
|||
void SendFilesBox::send(
|
||||
Api::SendOptions options,
|
||||
bool ctrlShiftEnter) {
|
||||
// AyuGram useScheduledMessages
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->useScheduledMessages && !options.scheduled) {
|
||||
DEBUG_LOG(("[AyuGram] Scheduling files"));
|
||||
auto current = base::unixtime::now();
|
||||
options.scheduled = current + 60; // well, files can be really big...
|
||||
}
|
||||
|
||||
if ((_sendType == Api::SendType::Scheduled
|
||||
|| _sendType == Api::SendType::ScheduledToUser)
|
||||
&& !options.scheduled) {
|
||||
|
|
|
@ -21,9 +21,9 @@ enum {
|
|||
|
||||
AutoSearchTimeout = 900, // 0.9 secs
|
||||
|
||||
PreloadHeightsCount = 3, // when 3 screens to scroll left make a preload request
|
||||
PreloadHeightsCount = 4, // when 4 screens to scroll left make a preload request
|
||||
|
||||
SearchPeopleLimit = 5,
|
||||
SearchPeopleLimit = 20,
|
||||
|
||||
MaxMessageSize = 4096,
|
||||
|
||||
|
|
|
@ -1775,7 +1775,7 @@ void Application::RegisterUrlScheme() {
|
|||
: QString(),
|
||||
.protocol = u"tg"_q,
|
||||
.protocolName = u"Telegram Link"_q,
|
||||
.shortAppName = u"tdesktop"_q,
|
||||
.shortAppName = u"AyuGram"_q,
|
||||
.longAppName = QCoreApplication::applicationName(),
|
||||
.displayAppName = AppName.utf16(),
|
||||
.displayAppDescription = AppName.utf16(),
|
||||
|
|
|
@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "calls/group/calls_group_common.h"
|
||||
#include "spellcheck/spellcheck_types.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
|
||||
|
@ -344,6 +346,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
|||
return;
|
||||
}
|
||||
|
||||
AyuSettings::load();
|
||||
|
||||
QDataStream stream(serialized);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ PreLaunchWindow::PreLaunchWindow(QString title) {
|
|||
setWindowIcon(Window::CreateIcon());
|
||||
setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
|
||||
|
||||
setWindowTitle(title.isEmpty() ? u"Telegram"_q : title);
|
||||
setWindowTitle(title.isEmpty() ? u"AyuGram"_q : title);
|
||||
|
||||
QPalette p(palette());
|
||||
p.setColor(QPalette::Window, QColor(255, 255, 255));
|
||||
|
@ -205,7 +205,7 @@ NotStartedWindow::NotStartedWindow()
|
|||
: _label(this)
|
||||
, _log(this)
|
||||
, _close(this) {
|
||||
_label.setText(u"Could not start Telegram Desktop!\nYou can see complete log below:"_q);
|
||||
_label.setText(u"Could not start AyuGram Desktop!\nYou can see complete log below:"_q);
|
||||
|
||||
_log.setPlainText(Logs::full());
|
||||
|
||||
|
@ -348,9 +348,9 @@ LastCrashedWindow::LastCrashedWindow(
|
|||
[=] { networkSettings(); });
|
||||
|
||||
if (_sendingState == SendingNoReport) {
|
||||
_label.setText(u"Last time Telegram Desktop was not closed properly."_q);
|
||||
_label.setText(u"Last time AyuGram Desktop was not closed properly."_q);
|
||||
} else {
|
||||
_label.setText(u"Last time Telegram Desktop crashed :("_q);
|
||||
_label.setText(u"Last time AyuGram Desktop crashed :("_q);
|
||||
}
|
||||
|
||||
if (_updaterData) {
|
||||
|
@ -441,9 +441,9 @@ LastCrashedWindow::LastCrashedWindow(
|
|||
});
|
||||
_saveReport.setText(u"SAVE TO FILE"_q);
|
||||
connect(&_saveReport, &QPushButton::clicked, [=] { saveReport(); });
|
||||
_getApp.setText(u"GET THE LATEST OFFICIAL VERSION OF TELEGRAM DESKTOP"_q);
|
||||
_getApp.setText(u"GET THE LATEST OFFICIAL VERSION OF AyuGram DESKTOP"_q);
|
||||
connect(&_getApp, &QPushButton::clicked, [=] {
|
||||
QDesktopServices::openUrl(u"https://desktop.telegram.org"_q);
|
||||
QDesktopServices::openUrl(u"https://github.com/AyuGram/AyuGramDesktop"_q);
|
||||
});
|
||||
|
||||
_send.setText(u"SEND CRASH REPORT"_q);
|
||||
|
@ -461,7 +461,7 @@ LastCrashedWindow::LastCrashedWindow(
|
|||
}
|
||||
|
||||
void LastCrashedWindow::saveReport() {
|
||||
QString to = QFileDialog::getSaveFileName(0, u"Telegram Crash Report"_q, QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + u"/report.telegramcrash"_q, u"Telegram crash report (*.telegramcrash)"_q);
|
||||
QString to = QFileDialog::getSaveFileName(0, u"AyuGram Crash Report"_q, QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + u"/report.telegramcrash"_q, u"Telegram crash report (*.telegramcrash)"_q);
|
||||
if (!to.isEmpty()) {
|
||||
QFile file(to);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
|
@ -869,7 +869,7 @@ void LastCrashedWindow::updateControls() {
|
|||
h += _networkSettings.height() + padding;
|
||||
}
|
||||
|
||||
QSize s(2 * padding + QFontMetrics(_label.font()).horizontalAdvance(u"Last time Telegram Desktop was not closed properly."_q) + padding + _networkSettings.width(), h);
|
||||
QSize s(2 * padding + QFontMetrics(_label.font()).horizontalAdvance(u"Last time AyuGram Desktop was not closed properly."_q) + padding + _networkSettings.width(), h);
|
||||
if (s == size()) {
|
||||
resizeEvent(0);
|
||||
} else {
|
||||
|
|
|
@ -414,7 +414,7 @@ StartResult Start() {
|
|||
fclose(f);
|
||||
|
||||
LOG(("Opened '%1' for reading, the previous "
|
||||
"Telegram Desktop launch was not finished properly :( "
|
||||
"AyuGram Desktop launch was not finished properly :( "
|
||||
"Crash log size: %2").arg(ReportPath).arg(lastdump.size()));
|
||||
|
||||
return lastdump;
|
||||
|
|
|
@ -300,7 +300,7 @@ void Launcher::init() {
|
|||
prepareSettings();
|
||||
initQtMessageLogging();
|
||||
|
||||
QApplication::setApplicationName(u"TelegramDesktop"_q);
|
||||
QApplication::setApplicationName(u"AyuGramDesktop"_q);
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
// fallback session management is useless for tdesktop since it doesn't have
|
||||
|
|
|
@ -18,10 +18,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#endif // TDESKTOP_ALLOW_CLOSED_ALPHA
|
||||
|
||||
// used in Updater.cpp and Setup.iss for Windows
|
||||
constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
|
||||
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
|
||||
constexpr auto AppName = "AyuGram Desktop"_cs;
|
||||
constexpr auto AppFile = "AyuGram"_cs;
|
||||
constexpr auto AppVersion = 4008003;
|
||||
constexpr auto AppVersionStr = "4.8.3";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
|
|
|
@ -24,6 +24,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/application.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/ayu_state.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
|
@ -173,6 +176,15 @@ void Histories::readInboxTill(
|
|||
|
||||
Core::App().notifications().clearIncomingFromHistory(history);
|
||||
|
||||
// AyuGram sendReadPackets
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
auto allow = settings->sendReadPackets;
|
||||
auto reallyAllow = AyuState::getAllowSendPacket(); // will return true if `allow`
|
||||
if (!reallyAllow) {
|
||||
DEBUG_LOG(("[AyuGram] Don't read messages"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto needsRequest = history->readInboxTillNeedsRequest(tillId);
|
||||
if (!needsRequest && !force) {
|
||||
DEBUG_LOG(("Reading: readInboxTill finish 1."));
|
||||
|
@ -194,8 +206,8 @@ void Histories::readInboxTill(
|
|||
sendPendingReadInbox(history);
|
||||
}
|
||||
return;
|
||||
} else if (!needsRequest
|
||||
&& (!maybeState || !maybeState->willReadTill)) {
|
||||
} else if (!needsRequest && (allow != reallyAllow && !force)
|
||||
&& (!maybeState || !maybeState->willReadTill)) {
|
||||
return;
|
||||
}
|
||||
const auto stillUnread = history->countStillUnreadLocal(tillId);
|
||||
|
|
|
@ -80,6 +80,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/random.h"
|
||||
#include "styles/style_boxes.h" // st::backgroundSize
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/database/ayu_database.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
|
@ -2160,6 +2163,101 @@ void Session::updateEditedMessage(const MTPMessage &data) {
|
|||
Reactions::CheckUnknownForUnread(this, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// AyuGram keepMessagesHistory
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
HistoryMessageEdition edit;
|
||||
|
||||
if (data.type() != mtpc_message) {
|
||||
goto proceed;
|
||||
}
|
||||
edit = HistoryMessageEdition(_session, data.c_message());
|
||||
if (settings->keepMessagesHistory && !existing->isLocal() && !existing->author()->isSelf() && !edit.isEditHide) {
|
||||
const auto history = existing->history();
|
||||
const auto msg = existing->originalText();
|
||||
|
||||
const auto media = existing->media();
|
||||
|
||||
if (edit.textWithEntities == msg) {
|
||||
// check if media changed
|
||||
|
||||
if (!edit.mtpMedia) {
|
||||
goto proceed;
|
||||
}
|
||||
|
||||
if (edit.mtpMedia->type() == mtpc_messageMediaPhoto
|
||||
&& media->photo()
|
||||
&& edit.mtpMedia->c_messageMediaPhoto().vphoto()->c_photo().vaccess_hash() == media->photo()->mtpInput().c_inputPhoto().vaccess_hash()) {
|
||||
goto proceed;
|
||||
}
|
||||
|
||||
if (edit.mtpMedia->type() == mtpc_messageMediaDocument
|
||||
&& media->document()
|
||||
&& edit.mtpMedia->c_messageMediaDocument().vdocument()->c_document().vaccess_hash() == media->document()->mtpInput().c_inputDocument().vaccess_hash()) {
|
||||
goto proceed;
|
||||
}
|
||||
}
|
||||
|
||||
auto flags = MessageFlag::HasFromId
|
||||
| MessageFlag::HasReplyInfo
|
||||
| MessageFlag::HasPostAuthor;
|
||||
|
||||
if (existing->isPost()) {
|
||||
flags |= MessageFlag::Post;
|
||||
}
|
||||
|
||||
// adding msg data to local ayu db (table:editedMessage)
|
||||
auto userId = existing->displayFrom()->id.value;
|
||||
auto dialogId = history->peer->id.value;
|
||||
auto msgId = existing->id.bare;
|
||||
bool isDocument = media && media->document();
|
||||
|
||||
AyuDatabase::addEditedMessage((long) userId, (long) dialogId, (long) msgId, msg.text, isDocument, QString(""), (long) crl::now());
|
||||
|
||||
if (!media || !(media->photo() || media->document())) {
|
||||
// history->addNewLocalMessage(
|
||||
// history->nextNonHistoryEntryId(),
|
||||
// flags,
|
||||
// UserId(),
|
||||
// existing->id,
|
||||
// base::unixtime::now(),
|
||||
// existing->author()->id,
|
||||
// "AyuGram"_q,
|
||||
// msg,
|
||||
// MTP_messageMediaEmpty(),
|
||||
// HistoryMessageMarkupData(),
|
||||
// existing->groupId().empty() ? 0 : existing->groupId().value);
|
||||
} else {
|
||||
if (media->photo()) {
|
||||
// history->addNewLocalMessage(
|
||||
// history->nextNonHistoryEntryId(),
|
||||
// flags,
|
||||
// UserId(),
|
||||
// existing->id,
|
||||
// base::unixtime::now(),
|
||||
// existing->author()->id,
|
||||
// "AyuGram"_q,
|
||||
// media->photo(),
|
||||
// existing->originalText(),
|
||||
// HistoryMessageMarkupData());
|
||||
} else if (media->document()) {
|
||||
// history->addNewLocalMessage(
|
||||
// history->nextNonHistoryEntryId(),
|
||||
// flags,
|
||||
// UserId(),
|
||||
// existing->id,
|
||||
// base::unixtime::now(),
|
||||
// existing->author()->id,
|
||||
// "AyuGram"_q,
|
||||
// media->document(),
|
||||
// existing->originalText(),
|
||||
// HistoryMessageMarkupData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proceed:
|
||||
|
||||
if (existing->isLocalUpdateMedia() && data.type() == mtpc_message) {
|
||||
updateExistingMessage(data.c_message());
|
||||
}
|
||||
|
|
|
@ -938,7 +938,7 @@ auto HtmlWriter::Wrap::pushMessage(
|
|||
dialog,
|
||||
basePath,
|
||||
"This message is not supported by this version "
|
||||
"of Telegram Desktop. Please update the application.") };
|
||||
"of AyuGram Desktop. Please update the application.") };
|
||||
}
|
||||
|
||||
const auto wrapReplyToLink = [&](const QByteArray &text) {
|
||||
|
|
|
@ -63,6 +63,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/qt/qt_common_adapters.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kNewBlockEachMessage = 50;
|
||||
|
@ -477,6 +479,49 @@ not_null<HistoryItem*> History::insertItem(
|
|||
void History::destroyMessage(not_null<HistoryItem*> item) {
|
||||
Expects(item->isHistoryEntry() || !item->mainView());
|
||||
|
||||
// AyuGram keepDeletedMessages
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->keepDeletedMessages && item->isRegular() && !item->isGroupMigrate()) {
|
||||
if (!item->isService()) {
|
||||
item->setPostAuthor(settings->deletedMark);
|
||||
} else {
|
||||
const auto msg = TextWithEntities{
|
||||
"Message deleted",
|
||||
{
|
||||
EntityInText(
|
||||
EntityType::Italic,
|
||||
0,
|
||||
15,
|
||||
"Message deleted"
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
auto flags = MessageFlag::HasFromId
|
||||
| MessageFlag::HasReplyInfo
|
||||
| MessageFlag::HasPostAuthor;
|
||||
|
||||
if (item->isPost()) {
|
||||
flags |= MessageFlag::Post;
|
||||
}
|
||||
|
||||
addNewLocalMessage(
|
||||
session().data().nextLocalMessageId(),
|
||||
flags,
|
||||
UserId(),
|
||||
item->id,
|
||||
base::unixtime::now(),
|
||||
item->author()->id,
|
||||
"AyuGram"_q,
|
||||
msg,
|
||||
MTP_messageMediaEmpty(),
|
||||
HistoryMessageMarkupData(),
|
||||
uint64(0));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto peerId = peer->id;
|
||||
if (item->isHistoryEntry()) {
|
||||
// All this must be done for all items manually in History::clear()!
|
||||
|
|
|
@ -106,6 +106,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtWidgets/QApplication>
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
#include "ayu/context_menu/context_menu.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kScrollDateHideTimeout = 1000;
|
||||
|
@ -2232,6 +2234,14 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
Window::ToggleMessagePinned(controller, pinItemId, !isPinned);
|
||||
}), isPinned ? &st::menuIconUnpin : &st::menuIconPin);
|
||||
}
|
||||
|
||||
// ayu context menu options
|
||||
auto ayuSubMenu = AyuUi::AyuPopupMenu(this);
|
||||
ayuSubMenu.addHistoryAction(item);
|
||||
ayuSubMenu.addHideMessageAction(item);
|
||||
ayuSubMenu.addReadUntilAction(item);
|
||||
|
||||
_menu->addAction(QString("Ayu"), std::move(ayuSubMenu._ayuSubMenu), &st::menuIconSettings, &st::menuIconSettings);
|
||||
};
|
||||
const auto addPhotoActions = [&](not_null<PhotoData*> photo, HistoryItem *item) {
|
||||
const auto media = photo->activeMediaView();
|
||||
|
|
|
@ -73,6 +73,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kNotificationTextLimit = 255;
|
||||
|
@ -2386,6 +2388,11 @@ void HistoryItem::setForwardsCount(int count) {
|
|||
}
|
||||
|
||||
void HistoryItem::setPostAuthor(const QString &author) {
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->keepDeletedMessages && !(_flags & MessageFlag::HasPostAuthor)) {
|
||||
_flags |= MessageFlag::HasPostAuthor;
|
||||
}
|
||||
|
||||
auto msgsigned = Get<HistoryMessageSigned>();
|
||||
if (author.isEmpty()) {
|
||||
if (!msgsigned) {
|
||||
|
@ -2404,6 +2411,11 @@ void HistoryItem::setPostAuthor(const QString &author) {
|
|||
msgsigned->author = author;
|
||||
msgsigned->isAnonymousRank = !isDiscussionPost()
|
||||
&& this->author()->isMegagroup();
|
||||
|
||||
if (settings->keepDeletedMessages) {
|
||||
history()->owner().requestItemViewRefresh(this);
|
||||
}
|
||||
|
||||
history()->owner().requestItemResize(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -172,6 +172,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtGui/QWindow>
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMessagesPerPageFirst = 30;
|
||||
|
@ -3863,6 +3865,14 @@ Api::SendAction HistoryWidget::prepareSendAction(
|
|||
}
|
||||
|
||||
void HistoryWidget::send(Api::SendOptions options) {
|
||||
// AyuGram useScheduledMessages
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
if (settings->useScheduledMessages && !options.scheduled) {
|
||||
DEBUG_LOG(("[AyuGram] Scheduling message"));
|
||||
auto current = base::unixtime::now();
|
||||
options.scheduled = current + 12;
|
||||
}
|
||||
|
||||
if (!_history) {
|
||||
return;
|
||||
} else if (_editMsgId) {
|
||||
|
|
|
@ -28,6 +28,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_chat.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
struct BottomInfo::Reaction {
|
||||
|
@ -461,9 +463,12 @@ void BottomInfo::layout() {
|
|||
}
|
||||
|
||||
void BottomInfo::layoutDateText() {
|
||||
const auto edited = (_data.flags & Data::Flag::Edited)
|
||||
? (tr::lng_edited(tr::now) + ' ')
|
||||
: QString();
|
||||
const auto ayuSettings = &AyuSettings::getInstance();
|
||||
auto editedMarkValue = ayuSettings->editedMark;
|
||||
|
||||
const auto edited = (_data.flags & Data::Flag::Edited)
|
||||
? (editedMarkValue + ' ')
|
||||
: QString();
|
||||
const auto author = _data.author;
|
||||
const auto prefix = !author.isEmpty() ? u", "_q : QString();
|
||||
const auto date = edited + QLocale().toString(
|
||||
|
|
|
@ -73,6 +73,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/database/ayu_database.h"
|
||||
#include "ayu/context_menu/message_history_box.h"
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
|
@ -1075,6 +1079,23 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
|||
}
|
||||
}
|
||||
|
||||
if (AyuDatabase::editedMessagesTableExists() && !((AyuDatabase::getEditedMessages(item)).empty())) {
|
||||
result->addAction(QString("History"), [=] {
|
||||
auto box = Box<AyuUi::MessageHistoryBox>(item);
|
||||
Ui::show(std::move(box));
|
||||
}, &st::menuIconInfo);
|
||||
}
|
||||
|
||||
const auto settings = &AyuSettings::getInstance();
|
||||
const auto history = item->history();
|
||||
result->addAction(QString("Hide"), [=]() {
|
||||
const auto initKeepDeleted = settings->keepDeletedMessages;
|
||||
|
||||
settings->set_keepDeletedMessages(false);
|
||||
history->destroyMessage(item);
|
||||
settings->set_keepDeletedMessages(initKeepDeleted);
|
||||
}, &st::menuIconClear);
|
||||
|
||||
if (!view || !list->hasCopyRestriction(view->data())) {
|
||||
AddCopyLinkAction(result, link);
|
||||
}
|
||||
|
|
|
@ -1387,7 +1387,7 @@ Element *Element::previousInBlocks() const {
|
|||
|
||||
Element *Element::previousDisplayedInBlocks() const {
|
||||
auto result = previousInBlocks();
|
||||
while (result && (result->data()->isEmpty() || result->isHidden())) {
|
||||
while (result && (result->data()->isEmpty() || result->isHidden() || result->data()->isLocal())) {
|
||||
result = result->previousInBlocks();
|
||||
}
|
||||
return result;
|
||||
|
@ -1408,7 +1408,7 @@ Element *Element::nextInBlocks() const {
|
|||
|
||||
Element *Element::nextDisplayedInBlocks() const {
|
||||
auto result = nextInBlocks();
|
||||
while (result && (result->data()->isEmpty() || result->isHidden())) {
|
||||
while (result && (result->data()->isEmpty() || result->isHidden() || result->data()->isLocal())) {
|
||||
result = result->nextInBlocks();
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -24,7 +24,7 @@ StartWidget::StartWidget(
|
|||
not_null<Data*> data)
|
||||
: Step(parent, account, data, true) {
|
||||
setMouseTracking(true);
|
||||
setTitleText(rpl::single(u"Telegram Desktop"_q));
|
||||
setTitleText(rpl::single(u"AyuGram Desktop"_q));
|
||||
setDescriptionText(tr::lng_intro_about());
|
||||
show();
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ public:
|
|||
std::unique_ptr<Account> account;
|
||||
};
|
||||
|
||||
static constexpr auto kMaxAccounts = 3;
|
||||
static constexpr auto kPremiumMaxAccounts = 6;
|
||||
static constexpr auto kMaxAccounts = 666;
|
||||
static constexpr auto kPremiumMaxAccounts = 1338;
|
||||
|
||||
explicit Domain(const QString &dataName);
|
||||
~Domain();
|
||||
|
|
|
@ -301,7 +301,7 @@ void MainWindow::createGlobalMenu() {
|
|||
});
|
||||
|
||||
auto quit = file->addAction(
|
||||
tr::lng_mac_menu_quit_telegram(tr::now, lt_telegram, u"Telegram"_q),
|
||||
tr::lng_mac_menu_quit_telegram(tr::now, lt_telegram, u"AyuGram"_q),
|
||||
this,
|
||||
[=] { quitFromTray(); },
|
||||
QKeySequence::Quit);
|
||||
|
@ -462,7 +462,7 @@ void MainWindow::createGlobalMenu() {
|
|||
tr::lng_mac_menu_about_telegram(
|
||||
tr::now,
|
||||
lt_telegram,
|
||||
u"Telegram"_q),
|
||||
u"AyuGram"_q),
|
||||
[=] {
|
||||
ensureWindowShown();
|
||||
controller().show(Box<AboutBox>());
|
||||
|
|
|
@ -302,7 +302,7 @@ void MainWindow::createGlobalMenu() {
|
|||
}
|
||||
};
|
||||
|
||||
auto main = psMainMenu.addMenu(u"Telegram"_q);
|
||||
auto main = psMainMenu.addMenu(u"AyuGram"_q);
|
||||
{
|
||||
auto callback = [=] {
|
||||
ensureWindowShown();
|
||||
|
@ -312,7 +312,7 @@ void MainWindow::createGlobalMenu() {
|
|||
tr::lng_mac_menu_about_telegram(
|
||||
tr::now,
|
||||
lt_telegram,
|
||||
u"Telegram"_q),
|
||||
u"AyuGram"_q),
|
||||
std::move(callback))
|
||||
->setMenuRole(QAction::AboutQtRole);
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ void PreviewWindowTitle(Painter &p, const style::palette &palette, QRect body, i
|
|||
p.setPen(st::titleFgActive[palette]);
|
||||
p.setFont(font);
|
||||
|
||||
p.drawText(titleRect, u"Telegram"_q, style::al_center);
|
||||
p.drawText(titleRect, u"AyuGram"_q, style::al_center);
|
||||
|
||||
auto isGraphite = ([NSColor currentControlTint] == NSGraphiteControlTint);
|
||||
auto buttonSkip = 8;
|
||||
|
|
|
@ -321,10 +321,10 @@ void psDoFixPrevious() {
|
|||
HRESULT userDesktopRes = SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, 0, SHGFP_TYPE_CURRENT, userDesktopFolder);
|
||||
HRESULT commonDesktopRes = SHGetFolderPath(0, CSIDL_COMMON_DESKTOPDIRECTORY, 0, SHGFP_TYPE_CURRENT, commonDesktopFolder);
|
||||
if (SUCCEEDED(userDesktopRes)) {
|
||||
userDesktopLnk = QString::fromWCharArray(userDesktopFolder) + "\\Telegram.lnk";
|
||||
userDesktopLnk = QString::fromWCharArray(userDesktopFolder) + "\\AyuGram.lnk";
|
||||
}
|
||||
if (SUCCEEDED(commonDesktopRes)) {
|
||||
commonDesktopLnk = QString::fromWCharArray(commonDesktopFolder) + "\\Telegram.lnk";
|
||||
commonDesktopLnk = QString::fromWCharArray(commonDesktopFolder) + "\\AyuGram.lnk";
|
||||
}
|
||||
QFile userDesktopFile(userDesktopLnk), commonDesktopFile(commonDesktopLnk);
|
||||
if (QFile::exists(userDesktopLnk) && QFile::exists(commonDesktopLnk) && userDesktopLnk != commonDesktopLnk) {
|
||||
|
|
|
@ -188,7 +188,7 @@ QString systemShortcutPath() {
|
|||
void cleanupShortcut() {
|
||||
static const int maxFileLen = MAX_PATH * 10;
|
||||
|
||||
QString path = systemShortcutPath() + u"Telegram.lnk"_q;
|
||||
QString path = systemShortcutPath() + u"AyuGram.lnk"_q;
|
||||
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
|
||||
|
||||
DWORD attributes = GetFileAttributes(p.c_str());
|
||||
|
@ -316,19 +316,19 @@ bool validateShortcut() {
|
|||
}
|
||||
|
||||
if (cAlphaVersion()) {
|
||||
path += u"TelegramAlpha.lnk"_q;
|
||||
path += u"AyuGramAlpha.lnk"_q;
|
||||
if (validateShortcutAt(path)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const auto installed = u"Telegram Desktop/Telegram.lnk"_q;
|
||||
const auto old = u"Telegram Win (Unofficial)/Telegram.lnk"_q;
|
||||
const auto installed = u"AyuGram Desktop/AyuGram.lnk"_q;
|
||||
const auto old = u"AyuGram for Windows/AyuGram.lnk"_q;
|
||||
if (validateShortcutAt(path + installed)
|
||||
|| validateShortcutAt(path + old)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
path += u"Telegram.lnk"_q;
|
||||
path += u"AyuGram.lnk"_q;
|
||||
if (validateShortcutAt(path)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#include "ayu/settings/settings_ayu.h"
|
||||
|
||||
namespace Settings {
|
||||
namespace {
|
||||
|
||||
|
@ -392,6 +394,10 @@ void SetupSections(
|
|||
tr::lng_settings_section_call_settings(),
|
||||
Calls::Id(),
|
||||
{ &st::settingsIconCalls, kIconGreen });
|
||||
addSection(
|
||||
rpl::single(QString("AyuGram Settings")),
|
||||
Ayu::Id(),
|
||||
{ &st::settingsPremiumIconStar, kIconPurple });
|
||||
|
||||
SetupPowerSavingButton(&controller->window(), container);
|
||||
SetupLanguageButton(&controller->window(), container);
|
||||
|
|
|
@ -309,7 +309,7 @@ void NotificationsCount::prepareNotificationSampleLarge() {
|
|||
p.setPen(st::dialogsNameFg);
|
||||
p.setFont(st::msgNameFont);
|
||||
|
||||
auto notifyTitle = st::msgNameFont->elided(u"Telegram Desktop"_q, rectForName.width());
|
||||
auto notifyTitle = st::msgNameFont->elided(u"AyuGram Desktop"_q, rectForName.width());
|
||||
p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
|
||||
|
||||
st::notifyClose.icon.paint(p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w);
|
||||
|
|
|
@ -32,6 +32,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include <QtCore/QDirIterator>
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
#include <unistd.h>
|
||||
#endif // Q_OS_WIN
|
||||
|
@ -441,6 +443,8 @@ void writeSettings() {
|
|||
|
||||
if (!QDir().exists(_basePath)) QDir().mkpath(_basePath);
|
||||
|
||||
AyuSettings::save();
|
||||
|
||||
// We dropped old test authorizations when migrated to multi auth.
|
||||
//const auto name = cTestMode() ? u"settings_test"_q : u"settings"_q;
|
||||
const auto name = u"settings"_q;
|
||||
|
|
|
@ -859,7 +859,7 @@ void MainWindow::updateTitle() {
|
|||
: Dialogs::Key();
|
||||
const auto thread = key ? key.thread() : nullptr;
|
||||
if (!thread) {
|
||||
setTitle((user.isEmpty() ? u"Telegram"_q : user) + added);
|
||||
setTitle((user.isEmpty() ? u"AyuGram"_q : user) + added);
|
||||
return;
|
||||
}
|
||||
const auto history = thread->owningHistory();
|
||||
|
|
|
@ -983,7 +983,7 @@ void Notification::updateNotifyDisplay() {
|
|||
: TextWithEntities{ name };
|
||||
};
|
||||
auto title = options.hideNameAndPhoto
|
||||
? TextWithEntities{ u"Telegram Desktop"_q }
|
||||
? TextWithEntities{ u"AyuGram Desktop"_q }
|
||||
: reminder
|
||||
? tr::lng_notification_reminder(tr::now, Ui::Text::WithEntities)
|
||||
: topicWithChat();
|
||||
|
|
|
@ -75,6 +75,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/boxes/confirmation_box.h"
|
||||
|
||||
namespace Window {
|
||||
namespace {
|
||||
|
||||
|
@ -759,6 +762,26 @@ void MainMenu::setupMenu() {
|
|||
)->setClickedCallback([=] {
|
||||
controller->showPeerHistory(controller->session().user());
|
||||
});
|
||||
addAction(
|
||||
rpl::single(QString("LRead Messages")),
|
||||
{ &st::settingsIconForward, kIconPurple }
|
||||
)->setClickedCallback([=] {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
auto prev = settings->sendReadPackets;
|
||||
settings->set_sendReadPackets(false);
|
||||
|
||||
auto chats = controller->session().data().chatsList();
|
||||
MarkAsReadChatListHack(chats);
|
||||
|
||||
settings->set_sendReadPackets(prev);
|
||||
});
|
||||
addAction(
|
||||
rpl::single(QString("SRead Messages")),
|
||||
{ &st::settingsIconForward, kIconPurple }
|
||||
)->setClickedCallback([=] {
|
||||
auto box = Box<AyuUi::ConfirmationBox>(controller);
|
||||
Ui::show(std::move(box));
|
||||
});
|
||||
} else {
|
||||
addAction(
|
||||
tr::lng_profile_add_contact(),
|
||||
|
|
|
@ -1285,6 +1285,10 @@ void Filler::fillArchiveActions() {
|
|||
|
||||
} // namespace
|
||||
|
||||
void MarkAsReadChatListHack(not_null<Dialogs::MainList*> list) {
|
||||
MarkAsReadChatList(list);
|
||||
}
|
||||
|
||||
void PeerMenuExportChat(not_null<PeerData*> peer) {
|
||||
Core::App().exportManager().start(peer);
|
||||
}
|
||||
|
|
|
@ -180,4 +180,6 @@ void MarkAsReadThread(not_null<Data::Thread*> thread);
|
|||
|
||||
void AddSeparatorAndShiftUp(const PeerMenuCallback &addAction);
|
||||
|
||||
void MarkAsReadChatListHack(not_null<Dialogs::MainList*> list);
|
||||
|
||||
} // namespace Window
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#define MyAppShortName "Telegram"
|
||||
#define MyAppName "Telegram Desktop"
|
||||
#define MyAppPublisher "Telegram FZ-LLC"
|
||||
#define MyAppURL "https://desktop.telegram.org"
|
||||
#define MyAppExeName "Telegram.exe"
|
||||
#define MyAppId "53F49750-6209-4FBF-9CA8-7A333C87D1ED"
|
||||
#define MyAppShortName "AyuGram"
|
||||
#define MyAppName "AyuGram Desktop"
|
||||
#define MyAppPublisher "Radolyn Labs"
|
||||
#define MyAppURL "https://github.com/AyuGram"
|
||||
#define MyAppExeName "AyuGram.exe"
|
||||
#define MyAppId "53F49750-6209-4FBF-9CA8-7A333C87D666"
|
||||
#define CurrentYear GetDateTimeString('yyyy','','')
|
||||
|
||||
[Setup]
|
||||
|
@ -37,11 +37,11 @@ DisableProgramGroupPage=no
|
|||
#if MyBuildTarget == "win64"
|
||||
ArchitecturesAllowed="x64 arm64"
|
||||
ArchitecturesInstallIn64BitMode="x64 arm64"
|
||||
OutputBaseFilename=tsetup-x64.{#MyAppVersionFull}
|
||||
OutputBaseFilename=ayusetup-x64.{#MyAppVersionFull}
|
||||
#define ArchModulesFolder "x64"
|
||||
AppVerName={#MyAppName} {#MyAppVersion} 64bit
|
||||
#else
|
||||
OutputBaseFilename=tsetup.{#MyAppVersionFull}
|
||||
OutputBaseFilename=ayusetup.{#MyAppVersionFull}
|
||||
#define ArchModulesFolder "x86"
|
||||
AppVerName={#MyAppName} {#MyAppVersion} 32bit
|
||||
#endif
|
||||
|
|
|
@ -28,14 +28,14 @@ You will require **api_id** and **api_hash** to access the Telegram API servers.
|
|||
|
||||
Open **x64 Native Tools Command Prompt for VS 2022.bat**, go to ***BuildPath*** and run
|
||||
|
||||
git clone --recursive https://github.com/telegramdesktop/tdesktop.git
|
||||
git clone --recursive https://github.com/AyuGram/AyuGramDesktop.git tdesktop
|
||||
tdesktop\Telegram\build\prepare\win.bat
|
||||
|
||||
## Build the project
|
||||
|
||||
Go to ***BuildPath*\\tdesktop\\Telegram** and run (using [your **api_id** and **api_hash**](#obtain-your-api-credentials))
|
||||
Go to ***BuildPath*\\tdesktop\\Telegram** and run
|
||||
|
||||
configure.bat x64 -D TDESKTOP_API_ID=YOUR_API_ID -D TDESKTOP_API_HASH=YOUR_API_HASH
|
||||
configure.bat x64 -D TDESKTOP_API_ID=2040 -D TDESKTOP_API_HASH=b18441a1ff607e10a989891a5462e627
|
||||
|
||||
* Open ***BuildPath*\\tdesktop\\out\\Telegram.sln** in Visual Studio 2022
|
||||
* Select Telegram project and press Build > Build Telegram (Debug and Release configurations)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
[Desktop Entry]
|
||||
Name=Telegram Desktop
|
||||
Comment=Official desktop version of Telegram messaging app
|
||||
Name=AyuGram Desktop
|
||||
Comment=Unofficial desktop version of Telegram messaging app
|
||||
TryExec=telegram-desktop
|
||||
Exec=telegram-desktop -- %u
|
||||
Icon=telegram
|
||||
Terminal=false
|
||||
StartupWMClass=TelegramDesktop
|
||||
StartupWMClass=AyuGram
|
||||
Type=Application
|
||||
Categories=Chat;Network;InstantMessaging;Qt;
|
||||
MimeType=x-scheme-handler/tg;
|
||||
|
|