14#include <rapidjson/document.h>
16#include <wx/bmpbuttn.h>
18#include <wx/clipbrd.h>
21#include <wx/stattext.h>
22#include <wx/statline.h>
23#include <wx/textctrl.h>
24#include <wx/radiobut.h>
41#include "../UserPanel.h"
70 "%lld", std::chrono::system_clock::now().time_since_epoch().count()),
73 fileName.Mkdir(0700, wxPATH_MKDIR_FULL);
75 if (fileName.Exists())
77 if (!wxRemoveFile(fileName.GetFullPath()))
81 return fileName.GetFullPath();
86 XO(
"Anyone will be able to listen to this audio.");
90 "Only you and people you share a link with will be able to listen to this audio.");
120 mCancelled.store(
true, std::memory_order_release);
139 return mCancelled.load(std::memory_order_acquire);
149 mProgress.store(value, std::memory_order_release);
154 constexpr auto ProgressSteps = 1000ull;
171 parent, wxID_ANY,
XO(
"Share Audio"), wxDefaultPosition, { 480, 250 },
172 wxDEFAULT_DIALOG_STYLE)
174 , mInitialStatePanel(*
this)
175 , mServices(std::make_unique<Services>())
176 , mAudiocomTrace(trace)
182 s.StartVerticalLay();
192 const auto size = GetSize();
195 SetMaxSize({
size.x, -1 });
197 mContinueAction = [
this]() {
198 if (mInitialStatePanel.root->IsShown())
199 StartUploadProcess();
206 if (!IsEscapeKey(evt))
275 this,
XO(
"Are you sure you want to cancel?"),
XO(
"Cancel upload to Audio.com"),
276 wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT | wxSTAY_ON_TOP);
278 const auto result = dlgMessage.ShowModal();
280 if (result != wxID_YES)
292 mServices->uploadPromise->DiscardResult();
294 EndModal(wxID_CANCEL);
307 return std::all_of(range.begin(), range.end(), [](
const WaveTrack *track){
308 return IsMono(*track) && track->GetPan() == 0;
317 const double t0 = 0.0;
318 const double t1 =
tracks.GetEndTime();
322 auto hasMimeType = [](
const auto&& mimeTypes,
const std::string& mimeType)
324 return std::find(mimeTypes.begin(), mimeTypes.end(), mimeType) != mimeTypes.end();
329 for(
const auto& preferredMimeType :
GetServiceConfig().GetPreferredAudioFormats())
333 auto pluginIt = std::find_if(registry.begin(), registry.end(), [&](
auto t)
335 auto [plugin, formatIndex] = t;
337 return hasMimeType(plugin->GetMimeTypes(formatIndex), preferredMimeType) &&
338 plugin->ParseConfig(formatIndex, config, parameters);
341 if(pluginIt == registry.end())
344 const auto [plugin, formatIndex] = *pluginIt;
346 const auto formatInfo = plugin->GetFormatInfo(formatIndex);
365 auto exportTask = builder.Build(
mProject);
367 auto f = exportTask.get_future();
372 while(f.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
380 if(!success && wxFileExists(path))
422 [
this](
const auto& result) {
428 if (result.result == UploadOperationCompleted::Result::Success)
431 assert(std::holds_alternative<UploadSuccessfulPayload>(result.payload));
435 std::get_if<UploadSuccessfulPayload>(&result.payload))
436 HandleUploadSucceeded(*payload);
438 HandleUploadSucceeded({});
442 result.result != UploadOperationCompleted::Result::Aborted)
446 std::get_if<UploadFailedPayload>(&result.payload))
447 HandleUploadFailed(*payload);
449 HandleUploadFailed({});
453 [
this](
auto current,
auto total) {
455 [
this, current, total]()
457 UpdateProgress(current, total);
463void ShareAudioDialog::HandleUploadSucceeded(
466 EndModal(wxID_CLOSE);
472 EndModal(wxID_ABORT);
483 message =
XO(
"Error: %s").Format(
details);
488 "We are unable to upload this file. Please try again and make sure to link to your audio.com account before uploading.");
492 {},
XO(
"Upload error"),
499void ShareAudioDialog::HandleExportFailure()
501 EndModal(wxID_ABORT);
504 {},
XO(
"Export error"),
505 XO(
"We are unable to prepare this file for uploading."), {},
509void ShareAudioDialog::ResetProgress()
511 mStageStartTime = Clock::now();
512 mLastUIUpdateTime = mStageStartTime;
514 mProgressPanel.elapsedTime->SetLabel(
" 00:00:00");
515 mProgressPanel.remainingTime->SetLabel(
" 00:00:00");
516 mProgressPanel.progress->SetValue(0);
518 mLastProgressValue = 0;
520 mExportProgressUpdater.reset();
529 wxTimeSpan tsElapsed(0, 0, 0, time.count());
531 label->SetLabel(tsElapsed.Format(
wxT(
" %H:%M:%S")));
537void ShareAudioDialog::UpdateProgress(uint64_t current, uint64_t total)
539 using namespace std::chrono;
541 const auto now = Clock::now();
549 if (mLastProgressValue != current)
551 constexpr int scale = 10000;
553 mLastProgressValue =
static_cast<int>(current);
555 mProgressPanel.progress->SetRange(scale);
556 mProgressPanel.progress->SetValue((current * scale) / total);
558 if (current == total && mServices->uploadPromise)
560 mProgressPanel.timePanel->Hide();
561 mProgressPanel.title->SetLabel(
XO(
"Finalizing upload...").Translation());
565 const auto elapsedSinceUIUpdate = now - mLastUIUpdateTime;
567 constexpr auto uiUpdateTimeout = 500ms;
569 if (elapsedSinceUIUpdate < uiUpdateTimeout && current < total)
572 mLastUIUpdateTime = now;
574 const auto elapsed = duration_cast<milliseconds>(now - mStageStartTime);
578 const auto estimate = elapsed * total / current;
579 const auto remains = estimate - elapsed;
582 mProgressPanel.remainingTime,
583 std::chrono::duration_cast<std::chrono::milliseconds>(remains));
603 mUserDataChangedSubscription = userPanel->Subscribe(
604 [
this](
auto message) { UpdateUserData(message.IsAuthorized); });
619 trackTitle->SetName(
XO(
"Track Title").Translation());
620 trackTitle->SetFocus();
621 trackTitle->SetMaxLength(100);
628 "Sharing audio requires a free %s account linked to Audacity. %%Press \"Link account\" above to proceed."));
631 L
"%s",
XO(
"audio.com"),
"https://audio.com");
663 parent.mIsAuthorised = authorized;
665 anonInfoPanel->Show(!authorized);
666 authorizedInfoPanel->Show(authorized);
668 if (parent.mContinueButton !=
nullptr)
669 parent.mContinueButton->Enable(authorized && !GetTrackTitle().empty());
671 root->GetParent()->Layout();
676 wxString ret { trackTitle->GetValue() };
677 ret.Trim(
true).Trim(
false);
683 return !GetTrackTitle().empty();
728 wxFont font = elapsedTime->GetFont();
731 elapsedTime->SetFont(font);
732 remainingTime->SetFont(font);
750 const auto result = locationDialog.ShowDialog();
759 shareDialog.ShowModal();
Toolkit-neutral facade for basic user interface services.
Declare functions to perform UTF-8 to std::wstring conversions.
XXO("&Cut/Copy/Paste Toolbar")
wxString FileExtension
File extension, not including any leading dot.
an object holding per-project preferred sample rate
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
accessors for certain important windows associated with each project
declares abstract base class Track, TrackList, and iterators over TrackList
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Wrap wxMessageDialog so that caption IS translatable.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
const wxString & GetProjectName() const
static ExportPluginRegistry & Get()
std::vector< std::tuple< ExportOptionID, ExportValue > > Parameters
ExportTaskBuilder & SetPlugin(const ExportPlugin *plugin, int format=0) noexcept
ExportTaskBuilder & SetParameters(ExportProcessor::Parameters parameters) noexcept
ExportTaskBuilder & SetNumChannels(unsigned numChannels) noexcept
ExportTaskBuilder & SetSampleRate(double sampleRate) noexcept
ExportTaskBuilder & SetFileName(const wxFileName &filename)
ExportTaskBuilder & SetRange(double t0, double t1, bool selectedOnly=false) noexcept
static void RegisterExportHook(ExportHook hook, Priority=DEFAULT_EXPORT_HOOK_PRIORITY)
static ProjectRate & Get(AudacityProject &project)
void SetBorder(int Border)
wxPanel * StartInvisiblePanel(int border=0)
wxTextCtrl * AddTextBox(const TranslatableString &Caption, const wxString &Value, const int nChars)
void StartVerticalLay(int iProp=1)
wxButton * AddButton(const TranslatableString &Text, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
void StartWrapLay(int PositionFlags=wxEXPAND, int iProp=0)
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
wxStaticText * AddVariableText(const TranslatableString &Str, bool bCenter=false, int PositionFlags=0, int wrapWidth=0)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
wxSizerItem * AddSpace(int width, int height, int prop=0)
ShuttleGui & Prop(int iProp)
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
void PopSuppressDialogs()
void PushSuppressDialogs()
rapidjson::Document GetExportConfig(const std::string &exporterName) const
Export configuration suitable for the mime type provided.
std::atomic< bool > mCancelled
void SetStatusString(const TranslatableString &str) override
ShareAudioDialog & mParent
bool IsStopped() const override
void OnProgress(double value) override
bool IsCancelled() const override
ExportResult GetResult() const
ExportProgressUpdater(ShareAudioDialog &parent)
std::atomic< double > mProgress
~ExportProgressUpdater() override
void SetResult(ExportResult result)
void StartUploadProcess()
std::unique_ptr< Services > mServices
void Populate(ShuttleGui &s)
ShareAudioDialog(AudacityProject &project, AudiocomTrace, wxWindow *parent=nullptr)
std::function< void()> mContinueAction
wxButton * mContinueButton
void HandleExportFailure()
void UpdateProgress(uint64_t current, uint64_t total)
struct audacity::cloud::audiocom::ShareAudioDialog::InitialStatePanel mInitialStatePanel
AudacityProject & mProject
~ShareAudioDialog() override
struct audacity::cloud::audiocom::ShareAudioDialog::ProgressPanel mProgressPanel
std::unique_ptr< ExportProgressUpdater > mExportProgressUpdater
A unique_ptr like class that holds a pointer to UploadOperation.
Service, responsible for uploading audio files to audio.com.
bool OpenInDefaultBrowser(const wxString &url)
Open an URL in default browser.
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
void Yield()
Dispatch waiting events, including actions enqueued by CallAfter.
void ExceptionWrappedCall(Callable callable)
ProjectFileIOExtensionRegistry::Extension extension
double GetRate(const Track &track)
const auto unlistedLabelText
wxString GenerateTempPath(FileExtension extension)
const auto unlistedDescriptionText
const auto publicLabelText
const auto publicDescriptionText
int CalculateChannels(const TrackList &trackList)
void SetTimeLabel(wxStaticText *label, std::chrono::milliseconds time)
AuthorizationHandler & GetAuthorizationHandler()
UserService & GetUserService()
OAuthService & GetOAuthService()
Returns the instance of the OAuthService.
wxString GetUploadTempPath()
const ServiceConfig & GetServiceConfig()
Returns the instance of the ServiceConfig.
Options for variations of error dialogs; the default is for modal dialogs.
void PopulateInitialStatePanel(ShuttleGui &s)
bool HasValidTitle() const
void UpdateUserData(bool authorized)
wxString GetTrackTitle() const
void PopulateProgressPanel(ShuttleGui &s)
UploadService uploadService
UploadOperationHandle uploadPromise
This structure represents an upload error as returned by the server.
std::vector< AdditionalError > additionalErrors
This structure represents the payload associated with successful upload.
std::string audioUrl
URL to the uploaded audio.