212 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
This file is part of Telegram Desktop,
 | 
						|
the official desktop application for the Telegram messaging service.
 | 
						|
 | 
						|
For license and copyright information please follow this link:
 | 
						|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
						|
*/
 | 
						|
#include "media/stories/media_stories_share.h"
 | 
						|
 | 
						|
#include "api/api_common.h"
 | 
						|
#include "apiwrap.h"
 | 
						|
#include "base/random.h"
 | 
						|
#include "boxes/share_box.h"
 | 
						|
#include "chat_helpers/compose/compose_show.h"
 | 
						|
#include "data/business/data_shortcut_messages.h"
 | 
						|
#include "data/data_chat_participant_status.h"
 | 
						|
#include "data/data_forum_topic.h"
 | 
						|
#include "data/data_histories.h"
 | 
						|
#include "data/data_peer.h"
 | 
						|
#include "data/data_session.h"
 | 
						|
#include "data/data_stories.h"
 | 
						|
#include "data/data_thread.h"
 | 
						|
#include "data/data_user.h"
 | 
						|
#include "history/history.h"
 | 
						|
#include "history/history_item_helpers.h" // GetErrorTextForSending.
 | 
						|
#include "history/view/history_view_context_menu.h" // CopyStoryLink.
 | 
						|
#include "lang/lang_keys.h"
 | 
						|
#include "main/main_session.h"
 | 
						|
#include "ui/boxes/confirm_box.h"
 | 
						|
#include "ui/text/text_utilities.h"
 | 
						|
#include "styles/style_calls.h"
 | 
						|
 | 
						|
namespace Media::Stories {
 | 
						|
 | 
						|
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareShareBox(
 | 
						|
		std::shared_ptr<ChatHelpers::Show> show,
 | 
						|
		FullStoryId id,
 | 
						|
		bool viewerStyle) {
 | 
						|
	const auto session = &show->session();
 | 
						|
	const auto resolve = [=] {
 | 
						|
		const auto maybeStory = session->data().stories().lookup(id);
 | 
						|
		return maybeStory ? maybeStory->get() : nullptr;
 | 
						|
	};
 | 
						|
	const auto story = resolve();
 | 
						|
	if (!story) {
 | 
						|
		return { nullptr };
 | 
						|
	}
 | 
						|
	const auto canCopyLink = story->hasDirectLink();
 | 
						|
 | 
						|
	auto copyCallback = [=] {
 | 
						|
		const auto story = resolve();
 | 
						|
		if (!story) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		if (story->hasDirectLink()) {
 | 
						|
			using namespace HistoryView;
 | 
						|
			CopyStoryLink(show, story->fullId());
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	struct State {
 | 
						|
		int requests = 0;
 | 
						|
	};
 | 
						|
	const auto state = std::make_shared<State>();
 | 
						|
	auto filterCallback = [=](not_null<Data::Thread*> thread) {
 | 
						|
		if (const auto user = thread->peer()->asUser()) {
 | 
						|
			if (user->canSendIgnoreRequirePremium()) {
 | 
						|
				return true;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return Data::CanSend(thread, ChatRestriction::SendPhotos)
 | 
						|
			&& Data::CanSend(thread, ChatRestriction::SendVideos);
 | 
						|
	};
 | 
						|
	auto copyLinkCallback = canCopyLink
 | 
						|
		? Fn<void()>(std::move(copyCallback))
 | 
						|
		: Fn<void()>();
 | 
						|
	auto submitCallback = [=](
 | 
						|
			std::vector<not_null<Data::Thread*>> &&result,
 | 
						|
			TextWithTags &&comment,
 | 
						|
			Api::SendOptions options,
 | 
						|
			Data::ForwardOptions forwardOptions,
 | 
						|
			Data::GroupingOptions groupingOptions) {
 | 
						|
		if (state->requests) {
 | 
						|
			return; // Share clicked already.
 | 
						|
		}
 | 
						|
		const auto story = resolve();
 | 
						|
		if (!story) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		const auto peer = story->peer();
 | 
						|
		const auto error = [&] {
 | 
						|
			for (const auto thread : result) {
 | 
						|
				const auto error = GetErrorTextForSending(
 | 
						|
					thread,
 | 
						|
					{ .story = story, .text = &comment });
 | 
						|
				if (!error.isEmpty()) {
 | 
						|
					return std::make_pair(error, thread);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return std::make_pair(QString(), result.front());
 | 
						|
		}();
 | 
						|
		if (!error.first.isEmpty()) {
 | 
						|
			auto text = TextWithEntities();
 | 
						|
			if (result.size() > 1) {
 | 
						|
				text.append(
 | 
						|
					Ui::Text::Bold(error.second->chatListName())
 | 
						|
				).append("\n\n");
 | 
						|
			}
 | 
						|
			text.append(error.first);
 | 
						|
			show->showBox(Ui::MakeInformBox(text));
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		const auto api = &story->owner().session().api();
 | 
						|
		auto &histories = story->owner().histories();
 | 
						|
		for (const auto thread : result) {
 | 
						|
			const auto action = Api::SendAction(thread, options);
 | 
						|
			if (!comment.text.isEmpty()) {
 | 
						|
				auto message = Api::MessageToSend(action);
 | 
						|
				message.textWithTags = comment;
 | 
						|
				message.action.clearDraft = false;
 | 
						|
				api->sendMessage(std::move(message));
 | 
						|
			}
 | 
						|
			const auto session = &thread->session();
 | 
						|
			const auto threadPeer = thread->peer();
 | 
						|
			const auto threadHistory = thread->owningHistory();
 | 
						|
			const auto randomId = base::RandomValue<uint64>();
 | 
						|
			auto sendFlags = MTPmessages_SendMedia::Flags(0);
 | 
						|
			if (action.replyTo) {
 | 
						|
				sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
 | 
						|
			}
 | 
						|
			const auto silentPost = ShouldSendSilent(
 | 
						|
				threadPeer,
 | 
						|
				action.options);
 | 
						|
			if (silentPost) {
 | 
						|
				sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
 | 
						|
			}
 | 
						|
			if (options.scheduled) {
 | 
						|
				sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
 | 
						|
			}
 | 
						|
			if (options.shortcutId) {
 | 
						|
				sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
 | 
						|
			}
 | 
						|
			const auto done = [=] {
 | 
						|
				if (!--state->requests) {
 | 
						|
					if (show->valid()) {
 | 
						|
						show->showToast(tr::lng_share_done(tr::now));
 | 
						|
						show->hideLayer();
 | 
						|
					}
 | 
						|
				}
 | 
						|
			};
 | 
						|
			histories.sendPreparedMessage(
 | 
						|
				threadHistory,
 | 
						|
				action.replyTo,
 | 
						|
				randomId,
 | 
						|
				Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
 | 
						|
					MTP_flags(sendFlags),
 | 
						|
					threadPeer->input,
 | 
						|
					Data::Histories::ReplyToPlaceholder(),
 | 
						|
					MTP_inputMediaStory(peer->input, MTP_int(id.story)),
 | 
						|
					MTPstring(),
 | 
						|
					MTP_long(randomId),
 | 
						|
					MTPReplyMarkup(),
 | 
						|
					MTPVector<MTPMessageEntity>(),
 | 
						|
					MTP_int(action.options.scheduled),
 | 
						|
					MTP_inputPeerEmpty(),
 | 
						|
					Data::ShortcutIdToMTP(session, action.options.shortcutId)
 | 
						|
				), [=](
 | 
						|
						const MTPUpdates &result,
 | 
						|
						const MTP::Response &response) {
 | 
						|
					done();
 | 
						|
				}, [=](const MTP::Error &error, const MTP::Response &response) {
 | 
						|
					api->sendMessageFail(error, threadPeer, randomId);
 | 
						|
					done();
 | 
						|
				});
 | 
						|
			++state->requests;
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	const auto viewerScheduleStyle = [&] {
 | 
						|
		auto date = Ui::ChooseDateTimeStyleArgs();
 | 
						|
		date.labelStyle = &st::groupCallBoxLabel;
 | 
						|
		date.dateFieldStyle = &st::groupCallScheduleDateField;
 | 
						|
		date.timeFieldStyle = &st::groupCallScheduleTimeField;
 | 
						|
		date.separatorStyle = &st::callMuteButtonLabel;
 | 
						|
		date.atStyle = &st::callMuteButtonLabel;
 | 
						|
		date.calendarStyle = &st::groupCallCalendarColors;
 | 
						|
 | 
						|
		auto st = HistoryView::ScheduleBoxStyleArgs();
 | 
						|
		st.topButtonStyle = &st::groupCallMenuToggle;
 | 
						|
		st.popupMenuStyle = &st::groupCallPopupMenu;
 | 
						|
		st.chooseDateTimeArgs = std::move(date);
 | 
						|
		return st;
 | 
						|
	};
 | 
						|
 | 
						|
	return Box<ShareBox>(ShareBox::Descriptor{
 | 
						|
		.session = session,
 | 
						|
		.copyCallback = std::move(copyLinkCallback),
 | 
						|
		.submitCallback = std::move(submitCallback),
 | 
						|
		.filterCallback = std::move(filterCallback),
 | 
						|
		.stMultiSelect = viewerStyle ? &st::groupCallMultiSelect : nullptr,
 | 
						|
		.stComment = viewerStyle ? &st::groupCallShareBoxComment : nullptr,
 | 
						|
		.st = viewerStyle ? &st::groupCallShareBoxList : nullptr,
 | 
						|
		.stLabel = viewerStyle ? &st::groupCallField : nullptr,
 | 
						|
		.scheduleBoxStyle = (viewerStyle
 | 
						|
			? viewerScheduleStyle()
 | 
						|
			: HistoryView::ScheduleBoxStyleArgs()),
 | 
						|
		.premiumRequiredError = SharePremiumRequiredError(),
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
} // namespace Media::Stories
 |