2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 06:35:14 +00:00

Added initial implementation of fallback photo management in settings.

This commit is contained in:
23rd
2022-12-19 17:36:02 +03:00
committed by John Preston
parent a4d3c694bc
commit 4c181b6d08
8 changed files with 281 additions and 48 deletions

View File

@@ -7,45 +7,55 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "settings/settings_privacy_controllers.h"
#include "settings/settings_common.h"
#include "lang/lang_keys.h"
#include "api/api_peer_photo.h"
#include "apiwrap.h"
#include "main/main_session.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "data/data_changes.h"
#include "data/data_peer_values.h" // Data::AmPremiumValue.
#include "base/call_delayed.h"
#include "base/event_filter.h"
#include "base/unixtime.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/peer_short_info_box.h"
#include "boxes/peers/prepare_short_info_box.h"
#include "calls/calls_instance.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "data/data_changes.h"
#include "data/data_file_origin.h"
#include "data/data_peer_values.h" // Data::AmPremiumValue.
#include "data/data_photo_media.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_user_photos.h" // UserPhotosViewer.
#include "editor/photo_editor_layer_widget.h"
#include "history/admin_log/history_admin_log_item.h"
#include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_components.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_message.h"
#include "history/history_item_components.h"
#include "history/history_item.h"
#include "history/history.h"
#include "calls/calls_instance.h"
#include "base/unixtime.h"
#include "base/event_filter.h"
#include "ui/chat/chat_theme.h"
#include "ui/chat/chat_style.h"
#include "ui/widgets/checkbox.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/image/image_prepare.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "settings/settings_common.h"
#include "settings/settings_privacy_security.h"
#include "ui/boxes/confirm_box.h"
#include "ui/cached_round_corners.h"
#include "ui/chat/chat_style.h"
#include "ui/chat/chat_theme.h"
#include "ui/image/image_prepare.h"
#include "ui/image/image_prepare.h"
#include "ui/painter.h"
#include "ui/text/format_values.h" // Ui::FormatPhone
#include "ui/text/text_utilities.h"
#include "ui/painter.h"
#include "ui/widgets/checkbox.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "window/section_widget.h"
#include "window/window_controller.h"
#include "window/window_session_controller.h"
#include "boxes/peer_list_controllers.h"
#include "ui/boxes/confirm_box.h"
#include "settings/settings_privacy_security.h"
#include "styles/style_chat.h"
#include "styles/style_boxes.h"
#include "styles/style_settings.h"
#include "styles/style_info.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
@@ -744,7 +754,7 @@ auto CallsPrivacyController::exceptionsDescription() const
object_ptr<Ui::RpWidget> CallsPrivacyController::setupBelowWidget(
not_null<Window::SessionController*> controller,
not_null<QWidget*> parent) const {
not_null<QWidget*> parent) {
auto result = object_ptr<Ui::VerticalLayout>(parent);
const auto content = result.data();
@@ -1018,14 +1028,160 @@ rpl::producer<QString> ProfilePhotoPrivacyController::title() const {
return tr::lng_edit_privacy_profile_photo_title();
}
bool ProfilePhotoPrivacyController::hasOption(Option option) const {
return (option != Option::Nobody);
}
rpl::producer<QString> ProfilePhotoPrivacyController::optionsTitleKey() const {
return tr::lng_edit_privacy_profile_photo_header();
}
object_ptr<Ui::RpWidget> ProfilePhotoPrivacyController::setupAboveWidget(
not_null<QWidget*> parent,
rpl::producer<Option> optionValue,
not_null<QWidget*> outerContainer) {
_option = std::move(optionValue);
return nullptr;
}
object_ptr<Ui::RpWidget> ProfilePhotoPrivacyController::setupBelowWidget(
not_null<Window::SessionController*> controller,
not_null<QWidget*> parent) {
const auto self = controller->session().user();
auto widget = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
parent,
object_ptr<Ui::VerticalLayout>(parent));
const auto container = widget->entity();
struct State {
void updatePhoto(QImage &&image, bool local) {
auto result = image.scaled(
userpicSize * style::DevicePixelRatio(),
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
result = Images::Round(
std::move(result),
ImageRoundRadius::Ellipse);
result.setDevicePixelRatio(style::DevicePixelRatio());
(local ? localPhoto : photo) = std::move(result);
if (local) {
localOriginal = std::move(image);
}
hasPhoto.fire(!localPhoto.isNull() || !photo.isNull());
}
rpl::event_stream<bool> hasPhoto;
rpl::variable<bool> hiddenByUser = false;
rpl::variable<QString> setUserpicButtonText;
QSize userpicSize;
QImage photo;
QImage localPhoto;
QImage localOriginal;
};
const auto state = container->lifetime().make_state<State>();
state->userpicSize = QSize(
st::inviteLinkUserpics.size,
st::inviteLinkUserpics.size);
AddSkip(container);
const auto setUserpicButton = AddButton(
container,
state->setUserpicButtonText.value(),
st::settingsButtonLight,
{ &st::settingsIconPhoto, kIconLightBlue });
const auto &stRemoveButton = st::settingsAttentionButtonWithIcon;
const auto removeButton = container->add(
object_ptr<Ui::SlideWrap<Ui::SettingsButton>>(
container,
object_ptr<Ui::SettingsButton>(
parent,
tr::lng_edit_privacy_profile_photo_public_remove(),
stRemoveButton)));
AddSkip(container);
AddDividerText(
container,
tr::lng_edit_privacy_profile_photo_public_about());
const auto userpic = Ui::CreateChild<Ui::RpWidget>(
removeButton->entity());
userpic->resize(state->userpicSize);
userpic->paintRequest(
) | rpl::start_with_next([=](const QRect &r) {
auto p = QPainter(userpic);
p.fillRect(r, Qt::transparent);
if (!state->localPhoto.isNull()) {
p.drawImage(0, 0, state->localPhoto);
} else if (!state->photo.isNull()) {
p.drawImage(0, 0, state->photo);
}
}, userpic->lifetime());
removeButton->entity()->heightValue(
) | rpl::start_with_next([=,
left = stRemoveButton.iconLeft,
width = st::settingsIconPhoto.width()](int height) {
userpic->moveToLeft(
left + (width - userpic->width()) / 2,
(height - userpic->height()) / 2);
}, userpic->lifetime());
removeButton->toggleOn(rpl::combine(
state->hasPhoto.events_starting_with(false),
state->hiddenByUser.value()
) | rpl::map(rpl::mappers::_1 && !rpl::mappers::_2));
(
PrepareShortInfoFallbackUserpic(self, st::shortInfoCover).value
) | rpl::start_with_next([=](PeerShortInfoUserpic info) {
state->updatePhoto(base::take(info.photo), false);
userpic->update();
}, userpic->lifetime());
setUserpicButton->setClickedCallback([=] {
base::call_delayed(
st::settingsButton.ripple.hideDuration,
crl::guard(container, [=] {
Editor::PrepareProfilePhotoFromFile(
container,
&controller->window(),
ImageRoundRadius::Ellipse,
[=](QImage &&image) {
state->updatePhoto(std::move(image), true);
state->hiddenByUser = false;
userpic->update();
});
}));
});
removeButton->entity()->setClickedCallback([=] {
state->hiddenByUser = true;
});
state->setUserpicButtonText = removeButton->toggledValue(
) | rpl::map([](bool toggled) {
return !toggled
? tr::lng_edit_privacy_profile_photo_public_set()
: tr::lng_edit_privacy_profile_photo_public_update();
}) | rpl::flatten_latest();
_saveAdditional = [=] {
if (removeButton->isHidden()) {
const auto photoId = SyncUserFallbackPhotoViewer(self);
if (const auto photo = self->owner().photo(*photoId)) {
controller->session().api().peerPhoto().clear(photo);
}
} else if (!state->localOriginal.isNull()) {
controller->session().api().peerPhoto().uploadFallback(
self,
base::take(state->localOriginal));
}
};
widget->toggleOn(rpl::combine(
_option.value(),
_exceptionsNever.value()
) | rpl::map(rpl::mappers::_1 != Option::Everyone || rpl::mappers::_2));
return widget;
}
void ProfilePhotoPrivacyController::saveAdditional() {
if (_saveAdditional) {
_saveAdditional();
}
}
rpl::producer<QString> ProfilePhotoPrivacyController::exceptionButtonTextKey(
Exception exception) const {
switch (exception) {
@@ -1054,7 +1210,30 @@ rpl::producer<QString> ProfilePhotoPrivacyController::exceptionBoxTitle(
auto ProfilePhotoPrivacyController::exceptionsDescription() const
-> rpl::producer<QString> {
return tr::lng_edit_privacy_profile_photo_exceptions();
return _option.value(
) | rpl::map([](Option option) {
switch (option) {
case Option::Everyone: {
return tr::lng_edit_privacy_forwards_exceptions_everyone();
};
case Option::Contacts: {
return tr::lng_edit_privacy_forwards_exceptions();
};
case Option::Nobody: {
return tr::lng_edit_privacy_forwards_exceptions_nobody();
};
}
Unexpected("Option value in exceptionsDescription.");
}) | rpl::flatten_latest();
}
void ProfilePhotoPrivacyController::handleExceptionsChange(
Exception exception,
rpl::producer<int> value) {
if (exception == Exception::Never) {
_exceptionsNever = std::move(value);
}
}
VoicesPrivacyController::VoicesPrivacyController(