mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-08 08:04:08 +02:00
Show additional information in userpic suggest / accept.
This commit is contained in:
parent
076f0e0800
commit
2364b0ad4e
12 changed files with 256 additions and 117 deletions
|
@ -31,11 +31,25 @@ photoEditorButtonIconFgOver: mediaviewPipControlsFgOver;
|
||||||
photoEditorButtonIconFgActive: lightButtonFg;
|
photoEditorButtonIconFgActive: lightButtonFg;
|
||||||
photoEditorButtonIconFgInactive: mediaviewPipPlaybackInactive;
|
photoEditorButtonIconFgInactive: mediaviewPipPlaybackInactive;
|
||||||
|
|
||||||
photoEditorButtonBarHeight: 50px;
|
photoEditorButtonBarHeight: 48px;
|
||||||
photoEditorButtonBarWidth: windowMinWidth;
|
photoEditorButtonBarWidth: 422px;
|
||||||
photoEditorButtonBarPadding: margins(2px, 0px, 2px, 0px);
|
photoEditorButtonBarPadding: margins(2px, 0px, 2px, 0px);
|
||||||
photoEditorTextButtonPadding: margins(22px, 0px, 22px, 0px);
|
photoEditorTextButtonPadding: margins(22px, 0px, 22px, 0px);
|
||||||
|
|
||||||
|
photoEditorButtonStyle: TextStyle(semiboldTextStyle) {
|
||||||
|
font: font(14px semibold);
|
||||||
|
linkFont: font(14px semibold);
|
||||||
|
linkFontOver: font(14px semibold underline);
|
||||||
|
}
|
||||||
|
photoEditorButtonTextTop: 15px;
|
||||||
|
|
||||||
|
photoEditorAbout: FlatLabel(defaultFlatLabel) {
|
||||||
|
textFg: mediaviewCaptionFg;
|
||||||
|
minWidth: 240px;
|
||||||
|
align: align(top);
|
||||||
|
}
|
||||||
|
photoEditorAboutMargin: margins(10px, 22px, 10px, 0px);
|
||||||
|
|
||||||
photoEditorRotateButton: IconButton(defaultIconButton) {
|
photoEditorRotateButton: IconButton(defaultIconButton) {
|
||||||
width: photoEditorButtonBarHeight;
|
width: photoEditorButtonBarHeight;
|
||||||
height: photoEditorButtonBarHeight;
|
height: photoEditorButtonBarHeight;
|
||||||
|
@ -43,7 +57,7 @@ photoEditorRotateButton: IconButton(defaultIconButton) {
|
||||||
icon: icon {{ "photo_editor/rotate", photoEditorButtonIconFg }};
|
icon: icon {{ "photo_editor/rotate", photoEditorButtonIconFg }};
|
||||||
iconOver: icon {{ "photo_editor/rotate", photoEditorButtonIconFgOver }};
|
iconOver: icon {{ "photo_editor/rotate", photoEditorButtonIconFgOver }};
|
||||||
|
|
||||||
rippleAreaPosition: point(5px, 5px);
|
rippleAreaPosition: point(4px, 4px);
|
||||||
rippleAreaSize: 40px;
|
rippleAreaSize: 40px;
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: shadowFg;
|
color: shadowFg;
|
||||||
|
|
|
@ -67,11 +67,12 @@ PhotoEditor::PhotoEditor(
|
||||||
photo,
|
photo,
|
||||||
_modifications,
|
_modifications,
|
||||||
_controllers,
|
_controllers,
|
||||||
std::move(data)))
|
data))
|
||||||
, _controls(base::make_unique_q<PhotoEditorControls>(
|
, _controls(base::make_unique_q<PhotoEditorControls>(
|
||||||
this,
|
this,
|
||||||
_controllers,
|
_controllers,
|
||||||
_modifications))
|
_modifications,
|
||||||
|
data))
|
||||||
, _colorPicker(std::make_unique<ColorPicker>(
|
, _colorPicker(std::make_unique<ColorPicker>(
|
||||||
this,
|
this,
|
||||||
Deserialize(Core::App().settings().photoEditorBrush()))) {
|
Deserialize(Core::App().settings().photoEditorBrush()))) {
|
||||||
|
@ -81,12 +82,18 @@ PhotoEditor::PhotoEditor(
|
||||||
if (size.isEmpty()) {
|
if (size.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto geometry = QRect(QPoint(), size);
|
_content->setGeometry(rect() - st::photoEditorContentMargins);
|
||||||
const auto contentRect = geometry - st::photoEditorContentMargins;
|
}, lifetime());
|
||||||
_content->setGeometry(contentRect);
|
|
||||||
const auto contentBottom = contentRect.top() + contentRect.height();
|
_content->innerRect(
|
||||||
const auto controlsRect = geometry
|
) | rpl::start_with_next([=](QRect inner) {
|
||||||
- style::margins(0, contentBottom, 0, 0);
|
if (inner.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto innerTop = _content->y() + inner.top();
|
||||||
|
const auto skip = st::photoEditorCropPointSize;
|
||||||
|
const auto controlsRect = rect()
|
||||||
|
- style::margins(0, innerTop + inner.height() + skip, 0, 0);
|
||||||
_controls->setGeometry(controlsRect);
|
_controls->setGeometry(controlsRect);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ struct EditorData {
|
||||||
RoundedRect,
|
RoundedRect,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TextWithEntities about;
|
||||||
|
QString confirm;
|
||||||
CropType cropType = CropType::Rect;
|
CropType cropType = CropType::Rect;
|
||||||
bool keepAspectRatio = false;
|
bool keepAspectRatio = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,6 +80,8 @@ PhotoEditorContent::PhotoEditorContent(
|
||||||
mods.angle,
|
mods.angle,
|
||||||
mods.flipped, imageSizeF);
|
mods.flipped, imageSizeF);
|
||||||
_paint->applyTransform(geometry, mods.angle, mods.flipped);
|
_paint->applyTransform(geometry, mods.angle, mods.flipped);
|
||||||
|
|
||||||
|
_innerRect = geometry;
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
paintRequest(
|
paintRequest(
|
||||||
|
|
|
@ -37,6 +37,10 @@ public:
|
||||||
|
|
||||||
void setupDragArea();
|
void setupDragArea();
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<QRect> innerRect() const {
|
||||||
|
return _innerRect.value();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const QSize _photoSize;
|
const QSize _photoSize;
|
||||||
|
@ -44,6 +48,7 @@ private:
|
||||||
const base::unique_qptr<Crop> _crop;
|
const base::unique_qptr<Crop> _crop;
|
||||||
const std::shared_ptr<Image> _photo;
|
const std::shared_ptr<Image> _photo;
|
||||||
|
|
||||||
|
rpl::variable<QRect> _innerRect;
|
||||||
rpl::variable<PhotoModifications> _modifications;
|
rpl::variable<PhotoModifications> _modifications;
|
||||||
rpl::event_stream<int> _keyPresses;
|
rpl::event_stream<int> _keyPresses;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/labels.h"
|
||||||
|
#include "ui/wrap/fade_wrap.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "styles/style_editor.h"
|
#include "styles/style_editor.h"
|
||||||
|
|
||||||
|
@ -55,7 +57,7 @@ EdgeButton::EdgeButton(
|
||||||
const style::RippleAnimation &st)
|
const style::RippleAnimation &st)
|
||||||
: Ui::RippleButton(parent, st)
|
: Ui::RippleButton(parent, st)
|
||||||
, _fg(fg)
|
, _fg(fg)
|
||||||
, _text(st::semiboldTextStyle, text)
|
, _text(st::photoEditorButtonStyle, text)
|
||||||
, _width(_text.maxWidth()
|
, _width(_text.maxWidth()
|
||||||
+ st::photoEditorTextButtonPadding.left()
|
+ st::photoEditorTextButtonPadding.left()
|
||||||
+ st::photoEditorTextButtonPadding.right())
|
+ st::photoEditorTextButtonPadding.right())
|
||||||
|
@ -78,7 +80,7 @@ void EdgeButton::init() {
|
||||||
paintRipple(p, _rippleRect.x(), _rippleRect.y());
|
paintRipple(p, _rippleRect.x(), _rippleRect.y());
|
||||||
|
|
||||||
p.setPen(_fg);
|
p.setPen(_fg);
|
||||||
const auto textTop = (height() - _text.minHeight()) / 2;
|
const auto textTop = st::photoEditorButtonTextTop;
|
||||||
_text.draw(p, 0, textTop, width(), style::al_center);
|
_text.draw(p, 0, textTop, width(), style::al_center);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
@ -122,25 +124,49 @@ ButtonBar::ButtonBar(
|
||||||
sizeValue(
|
sizeValue(
|
||||||
) | rpl::start_with_next([=](const QSize &size) {
|
) | rpl::start_with_next([=](const QSize &size) {
|
||||||
const auto children = RpWidget::children();
|
const auto children = RpWidget::children();
|
||||||
if (children.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto widgets = ranges::views::all(
|
const auto widgets = ranges::views::all(
|
||||||
children
|
children
|
||||||
) | ranges::views::filter([](not_null<const QObject*> object) {
|
) | ranges::views::filter([](not_null<const QObject*> object) {
|
||||||
return object->isWidgetType();
|
return object->isWidgetType();
|
||||||
}) | ranges::views::transform([](not_null<QObject*> object) {
|
}) | ranges::views::transform([](not_null<QObject*> object) {
|
||||||
return static_cast<Ui::RpWidget*>(object.get());
|
return static_cast<QWidget*>(object.get());
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
|
if (widgets.size() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto layout = [&](bool symmetrical) {
|
||||||
|
auto widths = widgets | ranges::views::transform(
|
||||||
|
&QWidget::width
|
||||||
|
) | ranges::to_vector;
|
||||||
|
const auto count = int(widths.size());
|
||||||
|
const auto middle = count / 2;
|
||||||
|
if (symmetrical) {
|
||||||
|
for (auto i = 0; i != middle; ++i) {
|
||||||
|
const auto j = count - i - 1;
|
||||||
|
widths[i] = widths[j] = std::max(widths[i], widths[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
const auto residualWidth = size.width()
|
const auto residualWidth = size.width()
|
||||||
- ranges::accumulate(widgets, 0, ranges::plus(), &QWidget::width);
|
- ranges::accumulate(widths, 0);
|
||||||
const auto step = residualWidth / float(widgets.size() - 1);
|
if (symmetrical && residualWidth < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto step = residualWidth / float(count - 1);
|
||||||
|
|
||||||
auto left = 0.;
|
auto left = 0.;
|
||||||
for (const auto &widget : widgets) {
|
auto &&ints = ranges::views::ints(0, ranges::unreachable);
|
||||||
widget->moveToLeft(int(left), 0);
|
auto &&list = ranges::views::zip(widgets, widths, ints);
|
||||||
left += widget->width() + step;
|
for (const auto &[widget, width, index] : list) {
|
||||||
|
widget->move(int((index >= middle)
|
||||||
|
? (left + width - widget->width())
|
||||||
|
: left), 0);
|
||||||
|
left += width + step;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (!layout(true)) {
|
||||||
|
layout(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = QImage(
|
auto result = QImage(
|
||||||
|
@ -165,37 +191,45 @@ PhotoEditorControls::PhotoEditorControls(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
std::shared_ptr<Controllers> controllers,
|
std::shared_ptr<Controllers> controllers,
|
||||||
const PhotoModifications modifications,
|
const PhotoModifications modifications,
|
||||||
bool doneControls)
|
const EditorData &data)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _bg(st::roundedBg)
|
, _bg(st::roundedBg)
|
||||||
, _buttonHeight(st::photoEditorButtonBarHeight)
|
, _buttonHeight(st::photoEditorButtonBarHeight)
|
||||||
, _transformButtons(base::make_unique_q<ButtonBar>(this, _bg))
|
, _transformButtons(base::make_unique_q<ButtonBar>(this, _bg))
|
||||||
, _paintTopButtons(base::make_unique_q<ButtonBar>(this, _bg))
|
, _paintTopButtons(base::make_unique_q<ButtonBar>(this, _bg))
|
||||||
, _paintBottomButtons(base::make_unique_q<ButtonBar>(this, _bg))
|
, _paintBottomButtons(base::make_unique_q<ButtonBar>(this, _bg))
|
||||||
|
, _about(data.about.empty()
|
||||||
|
? nullptr
|
||||||
|
: base::make_unique_q<Ui::FadeWrap<Ui::FlatLabel>>(
|
||||||
|
this,
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
this,
|
||||||
|
rpl::single(data.about),
|
||||||
|
st::photoEditorAbout)))
|
||||||
, _transformCancel(base::make_unique_q<EdgeButton>(
|
, _transformCancel(base::make_unique_q<EdgeButton>(
|
||||||
_transformButtons,
|
_transformButtons,
|
||||||
tr::lng_cancel(tr::now),
|
tr::lng_cancel(tr::now),
|
||||||
_buttonHeight,
|
_buttonHeight,
|
||||||
true,
|
true,
|
||||||
_bg,
|
_bg,
|
||||||
st::activeButtonFg,
|
st::mediaviewCaptionFg,
|
||||||
st::photoEditorRotateButton.ripple))
|
st::photoEditorRotateButton.ripple))
|
||||||
, _rotateButton(base::make_unique_q<Ui::IconButton>(
|
|
||||||
_transformButtons,
|
|
||||||
st::photoEditorRotateButton))
|
|
||||||
, _flipButton(base::make_unique_q<Ui::IconButton>(
|
, _flipButton(base::make_unique_q<Ui::IconButton>(
|
||||||
_transformButtons,
|
_transformButtons,
|
||||||
st::photoEditorFlipButton))
|
st::photoEditorFlipButton))
|
||||||
|
, _rotateButton(base::make_unique_q<Ui::IconButton>(
|
||||||
|
_transformButtons,
|
||||||
|
st::photoEditorRotateButton))
|
||||||
, _paintModeButton(base::make_unique_q<Ui::IconButton>(
|
, _paintModeButton(base::make_unique_q<Ui::IconButton>(
|
||||||
_transformButtons,
|
_transformButtons,
|
||||||
st::photoEditorPaintModeButton))
|
st::photoEditorPaintModeButton))
|
||||||
, _transformDone(base::make_unique_q<EdgeButton>(
|
, _transformDone(base::make_unique_q<EdgeButton>(
|
||||||
_transformButtons,
|
_transformButtons,
|
||||||
tr::lng_box_done(tr::now),
|
(data.confirm.isEmpty() ? tr::lng_box_done(tr::now) : data.confirm),
|
||||||
_buttonHeight,
|
_buttonHeight,
|
||||||
false,
|
false,
|
||||||
_bg,
|
_bg,
|
||||||
st::lightButtonFg,
|
st::mediaviewTextLinkFg,
|
||||||
st::photoEditorRotateButton.ripple))
|
st::photoEditorRotateButton.ripple))
|
||||||
, _paintCancel(base::make_unique_q<EdgeButton>(
|
, _paintCancel(base::make_unique_q<EdgeButton>(
|
||||||
_paintBottomButtons,
|
_paintBottomButtons,
|
||||||
|
@ -203,7 +237,7 @@ PhotoEditorControls::PhotoEditorControls(
|
||||||
_buttonHeight,
|
_buttonHeight,
|
||||||
true,
|
true,
|
||||||
_bg,
|
_bg,
|
||||||
st::activeButtonFg,
|
st::mediaviewCaptionFg,
|
||||||
st::photoEditorRotateButton.ripple))
|
st::photoEditorRotateButton.ripple))
|
||||||
, _undoButton(base::make_unique_q<Ui::IconButton>(
|
, _undoButton(base::make_unique_q<Ui::IconButton>(
|
||||||
_paintTopButtons,
|
_paintTopButtons,
|
||||||
|
@ -225,19 +259,9 @@ PhotoEditorControls::PhotoEditorControls(
|
||||||
_buttonHeight,
|
_buttonHeight,
|
||||||
false,
|
false,
|
||||||
_bg,
|
_bg,
|
||||||
st::lightButtonFg,
|
st::mediaviewTextLinkFg,
|
||||||
st::photoEditorRotateButton.ripple)) {
|
st::photoEditorRotateButton.ripple)) {
|
||||||
|
|
||||||
{
|
|
||||||
const auto &padding = st::photoEditorButtonBarPadding;
|
|
||||||
const auto w = st::photoEditorButtonBarWidth
|
|
||||||
- padding.left()
|
|
||||||
- padding.right();
|
|
||||||
_transformButtons->resize(w, _buttonHeight);
|
|
||||||
_paintBottomButtons->resize(w, _buttonHeight);
|
|
||||||
_paintTopButtons->resize(w, _buttonHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto icon = &st::photoEditorPaintIconActive;
|
const auto icon = &st::photoEditorPaintIconActive;
|
||||||
_paintModeButtonActive->setIconOverride(icon, icon);
|
_paintModeButtonActive->setIconOverride(icon, icon);
|
||||||
|
@ -250,6 +274,14 @@ PhotoEditorControls::PhotoEditorControls(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto &padding = st::photoEditorButtonBarPadding;
|
||||||
|
const auto w = std::min(st::photoEditorButtonBarWidth, size.width())
|
||||||
|
- padding.left()
|
||||||
|
- padding.right();
|
||||||
|
_transformButtons->resize(w, _buttonHeight);
|
||||||
|
_paintBottomButtons->resize(w, _buttonHeight);
|
||||||
|
_paintTopButtons->resize(w, _buttonHeight);
|
||||||
|
|
||||||
const auto buttonsTop = bottomButtonsTop();
|
const auto buttonsTop = bottomButtonsTop();
|
||||||
|
|
||||||
const auto ¤t = _transformButtons->isHidden()
|
const auto ¤t = _transformButtons->isHidden()
|
||||||
|
@ -259,6 +291,16 @@ PhotoEditorControls::PhotoEditorControls(
|
||||||
current->moveToLeft(
|
current->moveToLeft(
|
||||||
(size.width() - current->width()) / 2,
|
(size.width() - current->width()) / 2,
|
||||||
buttonsTop);
|
buttonsTop);
|
||||||
|
|
||||||
|
if (_about) {
|
||||||
|
const auto &margin = st::photoEditorAboutMargin;
|
||||||
|
const auto skip = st::photoEditorCropPointSize;
|
||||||
|
_about->resizeToWidth(
|
||||||
|
size.width() - margin.left() - margin.right());
|
||||||
|
_about->moveToLeft(
|
||||||
|
(size.width() - _about->width()) / 2,
|
||||||
|
margin.top() - skip);
|
||||||
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_mode.changes(
|
_mode.changes(
|
||||||
|
@ -413,6 +455,9 @@ void PhotoEditorControls::showAnimated(
|
||||||
const auto duration = st::photoEditorBarAnimationDuration;
|
const auto duration = st::photoEditorBarAnimationDuration;
|
||||||
|
|
||||||
const auto isTransform = (mode == Mode::Transform);
|
const auto isTransform = (mode == Mode::Transform);
|
||||||
|
if (_about) {
|
||||||
|
_about->toggle(isTransform, animated);
|
||||||
|
}
|
||||||
|
|
||||||
const auto buttonsLeft = (width() - _transformButtons->width()) / 2;
|
const auto buttonsLeft = (width() - _transformButtons->width()) / 2;
|
||||||
const auto buttonsTop = bottomButtonsTop();
|
const auto buttonsTop = bottomButtonsTop();
|
||||||
|
|
|
@ -15,6 +15,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class IconButton;
|
class IconButton;
|
||||||
|
class FlatLabel;
|
||||||
|
template <typename Widget>
|
||||||
|
class FadeWrap;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
|
@ -22,6 +25,7 @@ namespace Editor {
|
||||||
class EdgeButton;
|
class EdgeButton;
|
||||||
class ButtonBar;
|
class ButtonBar;
|
||||||
struct Controllers;
|
struct Controllers;
|
||||||
|
struct EditorData;
|
||||||
|
|
||||||
class PhotoEditorControls final : public Ui::RpWidget {
|
class PhotoEditorControls final : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -29,7 +33,7 @@ public:
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
std::shared_ptr<Controllers> controllers,
|
std::shared_ptr<Controllers> controllers,
|
||||||
const PhotoModifications modifications,
|
const PhotoModifications modifications,
|
||||||
bool doneControls = true);
|
const EditorData &data);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<int> rotateRequests() const;
|
[[nodiscard]] rpl::producer<int> rotateRequests() const;
|
||||||
[[nodiscard]] rpl::producer<> flipRequests() const;
|
[[nodiscard]] rpl::producer<> flipRequests() const;
|
||||||
|
@ -58,9 +62,11 @@ private:
|
||||||
const base::unique_qptr<ButtonBar> _paintTopButtons;
|
const base::unique_qptr<ButtonBar> _paintTopButtons;
|
||||||
const base::unique_qptr<ButtonBar> _paintBottomButtons;
|
const base::unique_qptr<ButtonBar> _paintBottomButtons;
|
||||||
|
|
||||||
|
const base::unique_qptr<Ui::FadeWrap<Ui::FlatLabel>> _about;
|
||||||
|
|
||||||
const base::unique_qptr<EdgeButton> _transformCancel;
|
const base::unique_qptr<EdgeButton> _transformCancel;
|
||||||
const base::unique_qptr<Ui::IconButton> _rotateButton;
|
|
||||||
const base::unique_qptr<Ui::IconButton> _flipButton;
|
const base::unique_qptr<Ui::IconButton> _flipButton;
|
||||||
|
const base::unique_qptr<Ui::IconButton> _rotateButton;
|
||||||
const base::unique_qptr<Ui::IconButton> _paintModeButton;
|
const base::unique_qptr<Ui::IconButton> _paintModeButton;
|
||||||
const base::unique_qptr<EdgeButton> _transformDone;
|
const base::unique_qptr<EdgeButton> _transformDone;
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ void OpenWithPreparedFile(
|
||||||
void PrepareProfilePhoto(
|
void PrepareProfilePhoto(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
not_null<Window::Controller*> controller,
|
not_null<Window::Controller*> controller,
|
||||||
ImageRoundRadius radius,
|
EditorData data,
|
||||||
Fn<void(QImage &&image)> &&doneCallback,
|
Fn<void(QImage &&image)> &&doneCallback,
|
||||||
QImage &&image) {
|
QImage &&image) {
|
||||||
const auto resizeToMinSize = [=](
|
const auto resizeToMinSize = [=](
|
||||||
|
@ -121,12 +121,7 @@ void PrepareProfilePhoto(
|
||||||
controller,
|
controller,
|
||||||
fileImage,
|
fileImage,
|
||||||
PhotoModifications{ .crop = std::move(crop) },
|
PhotoModifications{ .crop = std::move(crop) },
|
||||||
EditorData{
|
data);
|
||||||
.cropType = (radius == ImageRoundRadius::Ellipse
|
|
||||||
? EditorData::CropType::Ellipse
|
|
||||||
: EditorData::CropType::RoundedRect),
|
|
||||||
.keepAspectRatio = true,
|
|
||||||
});
|
|
||||||
const auto raw = editor.get();
|
const auto raw = editor.get();
|
||||||
auto layer = std::make_unique<LayerWidget>(parent, std::move(editor));
|
auto layer = std::make_unique<LayerWidget>(parent, std::move(editor));
|
||||||
InitEditorLayer(layer.get(), raw, std::move(applyModifications));
|
InitEditorLayer(layer.get(), raw, std::move(applyModifications));
|
||||||
|
@ -136,7 +131,7 @@ void PrepareProfilePhoto(
|
||||||
void PrepareProfilePhotoFromFile(
|
void PrepareProfilePhotoFromFile(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
not_null<Window::Controller*> controller,
|
not_null<Window::Controller*> controller,
|
||||||
ImageRoundRadius radius,
|
EditorData data,
|
||||||
Fn<void(QImage &&image)> &&doneCallback) {
|
Fn<void(QImage &&image)> &&doneCallback) {
|
||||||
const auto callback = [=, done = std::move(doneCallback)](
|
const auto callback = [=, done = std::move(doneCallback)](
|
||||||
const FileDialog::OpenResult &result) mutable {
|
const FileDialog::OpenResult &result) mutable {
|
||||||
|
@ -152,7 +147,7 @@ void PrepareProfilePhotoFromFile(
|
||||||
PrepareProfilePhoto(
|
PrepareProfilePhoto(
|
||||||
parent,
|
parent,
|
||||||
controller,
|
controller,
|
||||||
radius,
|
data,
|
||||||
std::move(done),
|
std::move(done),
|
||||||
std::move(image));
|
std::move(image));
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,6 +25,8 @@ class SessionController;
|
||||||
|
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
|
|
||||||
|
struct EditorData;
|
||||||
|
|
||||||
void OpenWithPreparedFile(
|
void OpenWithPreparedFile(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
|
@ -35,14 +37,14 @@ void OpenWithPreparedFile(
|
||||||
void PrepareProfilePhoto(
|
void PrepareProfilePhoto(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
not_null<Window::Controller*> controller,
|
not_null<Window::Controller*> controller,
|
||||||
ImageRoundRadius radius,
|
EditorData data,
|
||||||
Fn<void(QImage &&image)> &&doneCallback,
|
Fn<void(QImage &&image)> &&doneCallback,
|
||||||
QImage &&image);
|
QImage &&image);
|
||||||
|
|
||||||
void PrepareProfilePhotoFromFile(
|
void PrepareProfilePhotoFromFile(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
not_null<Window::Controller*> controller,
|
not_null<Window::Controller*> controller,
|
||||||
ImageRoundRadius radius,
|
EditorData data,
|
||||||
Fn<void(QImage &&image)> &&doneCallback);
|
Fn<void(QImage &&image)> &&doneCallback);
|
||||||
|
|
||||||
} // namespace Editor
|
} // namespace Editor
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_photo_media.h"
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_file_click_handler.h"
|
#include "data/data_file_click_handler.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "editor/photo_editor_common.h"
|
||||||
#include "editor/photo_editor_layer_widget.h"
|
#include "editor/photo_editor_layer_widget.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
@ -31,7 +32,71 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void ShowUserpicSuggestion(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
const std::shared_ptr<Data::PhotoMedia> &media,
|
||||||
|
const FullMsgId itemId,
|
||||||
|
not_null<PeerData*> peer) {
|
||||||
|
const auto photo = media->owner();
|
||||||
|
const auto from = peer->asUser();
|
||||||
|
const auto name = (from && !from->firstName.isEmpty())
|
||||||
|
? from->firstName
|
||||||
|
: peer->name();
|
||||||
|
if (photo->hasVideo()) {
|
||||||
|
const auto done = [=] {
|
||||||
|
using namespace Settings;
|
||||||
|
const auto session = &photo->session();
|
||||||
|
auto &peerPhotos = session->api().peerPhoto();
|
||||||
|
peerPhotos.updateSelf(photo, itemId);
|
||||||
|
controller->showSettings(Information::Id());
|
||||||
|
};
|
||||||
|
controller->show(Ui::MakeConfirmBox({
|
||||||
|
.text = tr::lng_profile_accept_video_sure(
|
||||||
|
tr::now,
|
||||||
|
lt_user,
|
||||||
|
name),
|
||||||
|
.confirmed = done,
|
||||||
|
.confirmText = tr::lng_profile_set_video_button(
|
||||||
|
tr::now),
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
const auto original = std::make_shared<QImage>(
|
||||||
|
media->image(Data::PhotoSize::Large)->original());
|
||||||
|
const auto callback = [=](QImage &&image) {
|
||||||
|
using namespace Settings;
|
||||||
|
const auto session = &photo->session();
|
||||||
|
const auto user = session->user();
|
||||||
|
UpdatePhotoLocally(user, image);
|
||||||
|
auto &peerPhotos = session->api().peerPhoto();
|
||||||
|
if (original->size() == image.size()
|
||||||
|
&& original->constBits() == image.constBits()) {
|
||||||
|
peerPhotos.updateSelf(photo, itemId);
|
||||||
|
} else {
|
||||||
|
peerPhotos.upload(user, std::move(image));
|
||||||
|
}
|
||||||
|
controller->showSettings(Information::Id());
|
||||||
|
};
|
||||||
|
using namespace Editor;
|
||||||
|
PrepareProfilePhoto(
|
||||||
|
controller->content(),
|
||||||
|
&controller->window(),
|
||||||
|
{
|
||||||
|
.about = { tr::lng_profile_accept_photo_sure(
|
||||||
|
tr::now,
|
||||||
|
lt_user,
|
||||||
|
name) },
|
||||||
|
.confirm = tr::lng_profile_set_photo_button(tr::now),
|
||||||
|
.cropType = EditorData::CropType::Ellipse,
|
||||||
|
.keepAspectRatio = true,
|
||||||
|
},
|
||||||
|
callback,
|
||||||
|
base::duplicate(*original));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
UserpicSuggestion::UserpicSuggestion(
|
UserpicSuggestion::UserpicSuggestion(
|
||||||
not_null<Element*> parent,
|
not_null<Element*> parent,
|
||||||
not_null<PeerData*> chat,
|
not_null<PeerData*> chat,
|
||||||
|
@ -84,50 +149,8 @@ ClickHandlerPtr UserpicSuggestion::createViewLink() {
|
||||||
if (out) {
|
if (out) {
|
||||||
PhotoOpenClickHandler(photo, show, itemId).onClick(
|
PhotoOpenClickHandler(photo, show, itemId).onClick(
|
||||||
context);
|
context);
|
||||||
} else if (photo->hasVideo()) {
|
|
||||||
const auto user = peer->asUser();
|
|
||||||
const auto name = (user && !user->firstName.isEmpty())
|
|
||||||
? user->firstName
|
|
||||||
: peer->name();
|
|
||||||
const auto done = [=] {
|
|
||||||
using namespace Settings;
|
|
||||||
const auto session = &photo->session();
|
|
||||||
auto &peerPhotos = session->api().peerPhoto();
|
|
||||||
peerPhotos.updateSelf(photo, itemId);
|
|
||||||
controller->showSettings(Information::Id());
|
|
||||||
};
|
|
||||||
controller->show(Ui::MakeConfirmBox({
|
|
||||||
.text = tr::lng_profile_accept_video_sure(
|
|
||||||
tr::now,
|
|
||||||
lt_user,
|
|
||||||
name),
|
|
||||||
.confirmed = done,
|
|
||||||
.confirmText = tr::lng_profile_set_video_button(
|
|
||||||
tr::now),
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
const auto original = std::make_shared<QImage>(
|
ShowUserpicSuggestion(controller, media, itemId, peer);
|
||||||
media->image(Data::PhotoSize::Large)->original());
|
|
||||||
const auto callback = [=](QImage &&image) {
|
|
||||||
using namespace Settings;
|
|
||||||
const auto session = &photo->session();
|
|
||||||
const auto user = session->user();
|
|
||||||
UpdatePhotoLocally(user, image);
|
|
||||||
auto &peerPhotos = session->api().peerPhoto();
|
|
||||||
if (original->size() == image.size()
|
|
||||||
&& original->constBits() == image.constBits()) {
|
|
||||||
peerPhotos.updateSelf(photo, itemId);
|
|
||||||
} else {
|
|
||||||
peerPhotos.upload(user, std::move(image));
|
|
||||||
}
|
|
||||||
controller->showSettings(Information::Id());
|
|
||||||
};
|
|
||||||
Editor::PrepareProfilePhoto(
|
|
||||||
controller->content(),
|
|
||||||
&controller->window(),
|
|
||||||
ImageRoundRadius::Ellipse,
|
|
||||||
callback,
|
|
||||||
base::duplicate(*original));
|
|
||||||
}
|
}
|
||||||
} else if (!photo->loading()) {
|
} else if (!photo->loading()) {
|
||||||
PhotoSaveClickHandler(photo, itemId).onClick(context);
|
PhotoSaveClickHandler(photo, itemId).onClick(context);
|
||||||
|
|
|
@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_user_photos.h" // UserPhotosViewer.
|
#include "data/data_user_photos.h" // UserPhotosViewer.
|
||||||
|
#include "editor/photo_editor_common.h"
|
||||||
#include "editor/photo_editor_layer_widget.h"
|
#include "editor/photo_editor_layer_widget.h"
|
||||||
#include "history/admin_log/history_admin_log_item.h"
|
#include "history/admin_log/history_admin_log_item.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -1134,10 +1135,15 @@ object_ptr<Ui::RpWidget> ProfilePhotoPrivacyController::setupBelowWidget(
|
||||||
base::call_delayed(
|
base::call_delayed(
|
||||||
st::settingsButton.ripple.hideDuration,
|
st::settingsButton.ripple.hideDuration,
|
||||||
crl::guard(container, [=] {
|
crl::guard(container, [=] {
|
||||||
Editor::PrepareProfilePhotoFromFile(
|
using namespace Editor;
|
||||||
|
PrepareProfilePhotoFromFile(
|
||||||
container,
|
container,
|
||||||
&controller->window(),
|
&controller->window(),
|
||||||
ImageRoundRadius::Ellipse,
|
{
|
||||||
|
.confirm = tr::lng_profile_set_photo_button(tr::now),
|
||||||
|
.cropType = EditorData::CropType::Ellipse,
|
||||||
|
.keepAspectRatio = true,
|
||||||
|
},
|
||||||
[=](QImage &&image) {
|
[=](QImage &&image) {
|
||||||
state->updatePhoto(std::move(image), true);
|
state->updatePhoto(std::move(image), true);
|
||||||
state->hiddenByUser = false;
|
state->hiddenByUser = false;
|
||||||
|
|
|
@ -22,7 +22,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "ui/layers/generic_box.h"
|
#include "ui/layers/generic_box.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
#include "editor/photo_editor_common.h"
|
||||||
#include "editor/photo_editor_layer_widget.h"
|
#include "editor/photo_editor_layer_widget.h"
|
||||||
#include "media/streaming/media_streaming_instance.h"
|
#include "media/streaming/media_streaming_instance.h"
|
||||||
#include "media/streaming/media_streaming_player.h"
|
#include "media/streaming/media_streaming_player.h"
|
||||||
|
@ -70,22 +72,29 @@ void CameraBox(
|
||||||
}
|
}
|
||||||
}, box->lifetime());
|
}, box->lifetime());
|
||||||
|
|
||||||
auto done = [=, done = std::move(doneCallback)](QImage &&image) {
|
auto done = [=, done = std::move(doneCallback)]() mutable {
|
||||||
|
using namespace Editor;
|
||||||
|
auto callback = [=, done = std::move(done)](QImage &&image) {
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
done(std::move(image));
|
done(std::move(image));
|
||||||
};
|
};
|
||||||
|
PrepareProfilePhoto(
|
||||||
box->setTitle(tr::lng_profile_camera_title());
|
|
||||||
box->addButton(tr::lng_continue(), [=, done = std::move(done)]() mutable {
|
|
||||||
Editor::PrepareProfilePhoto(
|
|
||||||
box,
|
box,
|
||||||
controller,
|
controller,
|
||||||
((peer && peer->isForum())
|
{
|
||||||
? ImageRoundRadius::Large
|
.confirm = tr::lng_profile_set_photo_button(tr::now),
|
||||||
: ImageRoundRadius::Ellipse),
|
.cropType = ((peer && peer->isForum())
|
||||||
std::move(done),
|
? EditorData::CropType::RoundedRect
|
||||||
|
: EditorData::CropType::Ellipse),
|
||||||
|
.keepAspectRatio = true,
|
||||||
|
},
|
||||||
|
std::move(callback),
|
||||||
track->frame(FrameRequest()).mirrored(true, false));
|
track->frame(FrameRequest()).mirrored(true, false));
|
||||||
});
|
box->closeBox();
|
||||||
|
};
|
||||||
|
|
||||||
|
box->setTitle(tr::lng_profile_camera_title());
|
||||||
|
box->addButton(tr::lng_continue(), std::move(done));
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,12 +269,35 @@ void UserpicButton::choosePhotoLocally() {
|
||||||
base::call_delayed(
|
base::call_delayed(
|
||||||
_st.changeButton.ripple.hideDuration,
|
_st.changeButton.ripple.hideDuration,
|
||||||
crl::guard(this, [=] {
|
crl::guard(this, [=] {
|
||||||
Editor::PrepareProfilePhotoFromFile(
|
using namespace Editor;
|
||||||
|
const auto user = _peer ? _peer->asUser() : nullptr;
|
||||||
|
const auto name = (user && !user->firstName.isEmpty())
|
||||||
|
? user->firstName
|
||||||
|
: _peer->name();
|
||||||
|
const auto phrase = (type == ChosenType::Suggest)
|
||||||
|
? &tr::lng_profile_suggest_sure
|
||||||
|
: (_peer->isUser() && !_peer->isSelf())
|
||||||
|
? &tr::lng_profile_set_personal_sure
|
||||||
|
: nullptr;
|
||||||
|
PrepareProfilePhotoFromFile(
|
||||||
this,
|
this,
|
||||||
_window,
|
_window,
|
||||||
((_peer && _peer->isForum())
|
{
|
||||||
? ImageRoundRadius::Large
|
.about = (phrase
|
||||||
: ImageRoundRadius::Ellipse),
|
? (*phrase)(
|
||||||
|
tr::now,
|
||||||
|
lt_user,
|
||||||
|
Ui::Text::Bold(name),
|
||||||
|
Ui::Text::WithEntities)
|
||||||
|
: TextWithEntities()),
|
||||||
|
.confirm = ((type == ChosenType::Suggest)
|
||||||
|
? tr::lng_profile_suggest_button(tr::now)
|
||||||
|
: tr::lng_profile_set_photo_button(tr::now)),
|
||||||
|
.cropType = ((_peer && _peer->isForum())
|
||||||
|
? EditorData::CropType::RoundedRect
|
||||||
|
: EditorData::CropType::Ellipse),
|
||||||
|
.keepAspectRatio = true,
|
||||||
|
},
|
||||||
callback(type));
|
callback(type));
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue