upload: import Ayu initial

Co-authored-by: SharapaGorg <sharapov.savely@yandex.ru>
This commit is contained in:
ZavaruKitsu 2023-06-03 19:00:05 +03:00
parent be89e57d27
commit eaba9781a5
86 changed files with 282538 additions and 140 deletions

BIN
.github/AyuGram.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -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.
![AyuGram Logo](.github/AyuGram.png)
[![Version](https://badge.fury.io/gh/telegramdesktop%2Ftdesktop.svg)](https://github.com/telegramdesktop/tdesktop/releases)
[![Build Status](https://github.com/telegramdesktop/tdesktop/workflows/Windows./badge.svg)](https://github.com/telegramdesktop/tdesktop/actions)
[![Build Status](https://github.com/telegramdesktop/tdesktop/workflows/MacOS./badge.svg)](https://github.com/telegramdesktop/tdesktop/actions)
[![Build Status](https://github.com/telegramdesktop/tdesktop/workflows/Linux./badge.svg)](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

View file

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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());

View 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();
}
}

View 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();
}

View 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);
}
}

View 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();
}

View 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);
}
}

View 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;
};
}

View 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();
}

View 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;
};

View 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();
}

View 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;
};

View 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

View 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;
};
}

View file

@ -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);
}
}
}

View 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;
};
}

View 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");
}
}

View 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();
}

View 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;
};

View 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

View 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

View 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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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(); });

View file

@ -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) {

View file

@ -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,

View file

@ -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(),

View file

@ -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);

View file

@ -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 {

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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());
}

View file

@ -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) {

View file

@ -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()!

View file

@ -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();

View file

@ -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);
}

View file

@ -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) {

View file

@ -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(

View file

@ -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);
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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();

View file

@ -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>());

View file

@ -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);
}

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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();

View file

@ -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(),

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;