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"
69 "%lld", std::chrono::system_clock::now().time_since_epoch().count()),
72 fileName.Mkdir(0700, wxPATH_MKDIR_FULL);
74 if (fileName.Exists())
76 if (!wxRemoveFile(fileName.GetFullPath()))
80 return fileName.GetFullPath();
85 XO(
"Anyone will be able to listen to this audio.");
89 "Only you and people you share a link with will be able to listen to this audio.");
119 mCancelled.store(
true, std::memory_order_release);
138 return mCancelled.load(std::memory_order_acquire);
148 mProgress.store(value, std::memory_order_release);
153 constexpr auto ProgressSteps = 1000ull;
169 parent, wxID_ANY,
XO(
"Share Audio"), wxDefaultPosition, { 480, 250 },
170 wxDEFAULT_DIALOG_STYLE)
172 , mInitialStatePanel(*
this)
173 , mServices(std::make_unique<Services>())
179 s.StartVerticalLay();
189 const auto size = GetSize();
192 SetMaxSize({
size.x, -1 });
194 mContinueAction = [
this]()
196 if (mInitialStatePanel.root->IsShown())
197 StartUploadProcess();
204 if (!IsEscapeKey(evt))
273 this,
XO(
"Are you sure you want to cancel?"),
XO(
"Cancel upload to Audio.com"),
274 wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT | wxSTAY_ON_TOP);
276 const auto result = dlgMessage.ShowModal();
278 if (result != wxID_YES)
290 mServices->uploadPromise->DiscardResult();
292 EndModal(wxID_CANCEL);
305 return std::all_of(range.begin(), range.end(), [](
const WaveTrack *track){
306 return IsMono(*track) && track->GetPan() == 0;
315 const double t0 = 0.0;
316 const double t1 =
tracks.GetEndTime();
320 auto hasMimeType = [](
const auto&& mimeTypes,
const std::string& mimeType)
322 return std::find(mimeTypes.begin(), mimeTypes.end(), mimeType) != mimeTypes.end();
327 for(
const auto& preferredMimeType :
GetServiceConfig().GetPreferredAudioFormats())
331 auto pluginIt = std::find_if(registry.begin(), registry.end(), [&](
auto t)
333 auto [plugin, formatIndex] = t;
335 return hasMimeType(plugin->GetMimeTypes(formatIndex), preferredMimeType) &&
336 plugin->ParseConfig(formatIndex, config, parameters);
339 if(pluginIt == registry.end())
342 const auto [plugin, formatIndex] = *pluginIt;
344 const auto formatInfo = plugin->GetFormatInfo(formatIndex);
363 auto exportTask = builder.Build(
mProject);
365 auto f = exportTask.get_future();
370 while(f.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
378 if(!success && wxFileExists(path))
422 [
this](
const auto& result)
429 if (result.result == UploadOperationCompleted::Result::Success)
432 assert(std::holds_alternative<UploadSuccessfulPayload>(result.payload));
436 std::get_if<UploadSuccessfulPayload>(&result.payload))
437 HandleUploadSucceeded(*payload);
439 HandleUploadSucceeded({});
443 result.result != UploadOperationCompleted::Result::Aborted)
447 std::get_if<UploadFailedPayload>(&result.payload))
448 HandleUploadFailed(*payload);
450 HandleUploadFailed({});
454 [
this](
auto current,
auto total)
457 [
this, current, total]()
459 UpdateProgress(current, total);
464void ShareAudioDialog::HandleUploadSucceeded(
467 EndModal(wxID_CLOSE);
473 EndModal(wxID_ABORT);
484 message =
XO(
"Error: %s").Format(
details);
489 "We are unable to upload this file. Please try again and make sure to link to your audio.com account before uploading.");
493 {},
XO(
"Upload error"),
500void ShareAudioDialog::HandleExportFailure()
502 EndModal(wxID_ABORT);
505 {},
XO(
"Export error"),
506 XO(
"We are unable to prepare this file for uploading."), {},
510void ShareAudioDialog::ResetProgress()
512 mStageStartTime = Clock::now();
513 mLastUIUpdateTime = mStageStartTime;
515 mProgressPanel.elapsedTime->SetLabel(
" 00:00:00");
516 mProgressPanel.remainingTime->SetLabel(
" 00:00:00");
517 mProgressPanel.progress->SetValue(0);
519 mLastProgressValue = 0;
521 mExportProgressUpdater.reset();
530 wxTimeSpan tsElapsed(0, 0, 0, time.count());
532 label->SetLabel(tsElapsed.Format(
wxT(
" %H:%M:%S")));
538void ShareAudioDialog::UpdateProgress(uint64_t current, uint64_t total)
540 using namespace std::chrono;
542 const auto now = Clock::now();
550 if (mLastProgressValue != current)
552 constexpr int scale = 10000;
554 mLastProgressValue =
static_cast<int>(current);
556 mProgressPanel.progress->SetRange(scale);
557 mProgressPanel.progress->SetValue((current * scale) / total);
559 if (current == total && mServices->uploadPromise)
561 mProgressPanel.timePanel->Hide();
562 mProgressPanel.title->SetLabel(
XO(
"Finalizing upload...").Translation());
566 const auto elapsedSinceUIUpdate = now - mLastUIUpdateTime;
568 constexpr auto uiUpdateTimeout = 500ms;
570 if (elapsedSinceUIUpdate < uiUpdateTimeout && current < total)
573 mLastUIUpdateTime = now;
575 const auto elapsed = duration_cast<milliseconds>(now - mStageStartTime);
579 const auto estimate = elapsed * total / current;
580 const auto remains = estimate - elapsed;
583 mProgressPanel.remainingTime,
584 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);
748 const auto result = locationDialog.ShowDialog();
757 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()
ShareAudioDialog(AudacityProject &project, wxWindow *parent=nullptr)
std::unique_ptr< Services > mServices
void Populate(ShuttleGui &s)
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.