13#include <wx/bmpbuttn.h>
15#include <wx/clipbrd.h>
17#include <wx/stattext.h>
18#include <wx/statline.h>
19#include <wx/textctrl.h>
20#include <wx/radiobut.h>
50#ifdef HAS_CUSTOM_URL_HANDLING
76 "%lld", std::chrono::system_clock::now().time_since_epoch().count()),
79 fileName.Mkdir(0700, wxPATH_MKDIR_FULL);
81 if (fileName.Exists())
83 if (!wxRemoveFile(fileName.GetFullPath()))
87 return fileName.GetFullPath();
92 XO(
"Anyone will be able to listen to this audio.");
96 "Only you and people you share a link with will be able to listen to this audio.");
134 unsigned long long numerator,
unsigned long long denominator,
139 const auto now = Clock::now();
143 if ((now -
mLastYield > std::chrono::milliseconds(50)) || (numerator == denominator))
167 using Clock = std::chrono::steady_clock;
175 parent, wxID_ANY,
XO(
"Share Audio"), wxDefaultPosition, { 480, 250 },
176 wxDEFAULT_DIALOG_STYLE)
178 , mServices(std::make_unique<Services>())
184 s.StartVerticalLay();
194 const auto size = GetSize();
197 SetMaxSize({
size.x, -1 });
199 mContinueAction = [
this]()
201 if (mInitialStatePanel.root->IsShown())
202 StartUploadProcess();
209 if (!IsEscapeKey(evt))
215 if (mCancelButton->IsShown())
272 const auto hasUploadStarted = !!
mServices->uploadPromise;
277 this,
XO(
"Are you sure you want to cancel?"),
XO(
"Cancel upload to Audio.com"),
278 wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT | wxSTAY_ON_TOP);
280 const auto result = dlgMessage.ShowModal();
282 if (result != wxID_YES)
294 mServices->uploadPromise->DiscardResult();
296 EndModal(wxID_CANCEL);
306 EndModal(wxID_CLOSE);
326 exporter->OnBeforeExport();
328 auto cleanupExporter =
finally([&]() { exporter->OnAfterExport(); });
334 const double t0 = 0.0;
335 const double t1 = tracks.GetEndTime();
337 const int nChannels = (tracks.Any() - &
Track::IsLeader).empty() ? 1 : 2;
339 const bool success = e.Process(
341 exporter->GetExporterID(),
349 if (!success && wxFileExists(path))
353 return success ? path : wxString {};
393 [
this](
const auto& result)
400 if (result.result == UploadOperationCompleted::Result::Success)
401 HandleUploadSucceeded(result.finishUploadURL, result.audioSlug);
402 else if (result.result != UploadOperationCompleted::Result::Aborted)
403 HandleUploadFailed(result.errorMessage);
406 [
this](
auto current,
auto total)
409 [
this, current, total]()
411 UpdateProgress(current, total);
416void ShareAudioDialog::HandleUploadSucceeded(
417 std::string_view finishUploadURL, std::string_view audioSlug)
419 mProgressPanel.timePanel->Hide();
420 mProgressPanel.title->SetLabel(
XO(
"Upload complete!").Translation());
421 mProgressPanel.info->Show();
422 mProgressPanel.info->SetLabel(
428 mProgressPanel.info->SetLabel(
429 "By pressing continue, you will be taken to audio.com and given a shareable link.");
430 mProgressPanel.info->Wrap(mProgressPanel.root->GetSize().GetWidth());
432 mContinueAction = [
this, url = std::string(finishUploadURL)]()
434 EndModal(wxID_CLOSE);
438 mContinueButton->Show();
442 auto shareableLink = wxString::Format(
447 mCloseButton->Show();
448 mCancelButton->Hide();
452 [
this, url = shareableLink](
auto)
454 EndModal(wxID_CLOSE);
458 mProgressPanel.link->SetValue(shareableLink);
459 mProgressPanel.linkPanel->Show();
466void ShareAudioDialog::HandleUploadFailed(std::string_view errorMessage)
468 EndModal(wxID_ABORT);
471 {},
XO(
"Upload error"),
472 XO(
"We are unable to upload this file. Please try again and make sure to link to your audio.com account before uploading."),
478void ShareAudioDialog::HandleExportFailure()
480 EndModal(wxID_ABORT);
483 {},
XO(
"Export error"),
484 XO(
"We are unable to prepare this file for uploading."), {},
488void ShareAudioDialog::ResetProgress()
490 mStageStartTime = Clock::now();
491 mLastUIUpdateTime = mStageStartTime;
493 mProgressPanel.elapsedTime->SetLabel(
" 00:00:00");
494 mProgressPanel.remainingTime->SetLabel(
" 00:00:00");
495 mProgressPanel.progress->SetValue(0);
497 mLastProgressValue = 0;
506 wxTimeSpan tsElapsed(0, 0, 0, time.count());
508 label->SetLabel(tsElapsed.Format(
wxT(
" %H:%M:%S")));
514void ShareAudioDialog::UpdateProgress(uint64_t current, uint64_t total)
516 using namespace std::chrono;
518 const auto now = Clock::now();
526 if (mLastProgressValue != current)
528 constexpr int scale = 10000;
530 mLastProgressValue =
static_cast<int>(current);
532 mProgressPanel.progress->SetRange(scale);
533 mProgressPanel.progress->SetValue((current * scale) / total);
535 if (current == total && mServices->uploadPromise)
537 mProgressPanel.timePanel->Hide();
538 mProgressPanel.title->SetLabel(
XO(
"Finalizing upload...").Translation());
542 const auto elapsedSinceUIUpdate = now - mLastUIUpdateTime;
544 constexpr auto uiUpdateTimeout = 500ms;
546 if (elapsedSinceUIUpdate < uiUpdateTimeout && current < total)
549 mLastUIUpdateTime = now;
551 const auto elapsed = duration_cast<milliseconds>(now - mStageStartTime);
555 const auto estimate = elapsed * total / current;
556 const auto remains = estimate - elapsed;
559 mProgressPanel.remainingTime,
560 std::chrono::duration_cast<std::chrono::milliseconds>(remains));
563ShareAudioDialog::InitialStatePanel::InitialStatePanel()
564 : mUserDataChangedSubscription(
601 wxEVT_BUTTON, [
this](
auto) { OnLinkButtonPressed(); });
616 constexpr auto maxWidth = 380;
628 .AddRadioButton({}, 0, selectedIndex);
629#if wxUSE_ACCESSIBILITY
641 isPublic->SetValue(
true);
655 .AddRadioButtonToGroup({}, 1, selectedIndex);
657#if wxUSE_ACCESSIBILITY
668 [
this, rbUnlisted](
auto)
670 rbUnlisted->SetValue(
true);
682 PopulateFirstTimeNotice(s);
708 "Your audio will be uploaded to our sharing service: %s,%%which requires a free account to use.\n\nIf you have problems uploading, try the Link Account button."));
711 L
"%s",
XO(
"audio.com"),
712 "https://audio.com");
728 auto parent = root->GetParent();
731 auto layoutUpdater =
finally(
732 [parent = root->GetParent(),
this]()
742 if (!oauthService.HasRefreshToken())
748 if (!oauthService.HasAccessToken())
749 oauthService.ValidateAuth({});
753 if (userService.GetUserSlug().empty())
759 const auto displayName = userService.GetDisplayName();
764 const auto avatarPath = userService.GetAvatarPath();
766 if (!avatarPath.empty())
767 avatar->SetBitmap(avatarPath);
771 oauthButton->SetLabel(
XXO(
"&Unlink Account").Translation());
778 if (oauthService.HasAccessToken())
779 oauthService.UnlinkAccount();
785#ifdef HAS_CUSTOM_URL_HANDLING
797 name->SetLabel(
XO(
"Anonymous").Translation());
799 oauthButton->SetLabel(
XXO(
"&Link Account").Translation());
845 link->SetName(
XO(
"Shareable link").Translation());
846 link->SetEditable(
false);
847 link->SetMinSize({ 360, -1 });
856 if (wxTheClipboard->Open())
858 wxTheClipboard->SetData(
859 safenew wxTextDataObject(link->GetValue()));
860 wxTheClipboard->Close();
876 wxFont font = elapsedTime->GetFont();
879 elapsedTime->SetFont(font);
880 remainingTime->SetFont(font);
Toolkit-neutral facade for basic user interface services.
Declare functions to perform UTF-8 to std::wstring conversions.
const TranslatableString name
static RealtimeEffectState::EffectFactory::Scope scope
Inject a factory for realtime effects.
XXO("&Cut/Copy/Paste Toolbar")
wxString FileExtension
File extension, not including any leading dot.
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
Abstraction of a progress dialog with well defined time-to-completion estimate.
This specialization of Setting for bool adds a Toggle method to negate the saved value.
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
bool Write(const T &value)
Write value to config and return true if successful.
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
Makes temporary changes to preferences, then rolls them back at destruction.
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 SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
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 & Name(const TranslatableString &name)
wxBitmap & Bitmap(int iIndex)
static TrackList & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
bool IsURLHandlingSupported() const noexcept
Returns true, if Audacity can handle custom URLs.
static URLSchemesRegistry & Get()
Retrieves the registry instance.
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
void PopSuppressDialogs()
void PushSuppressDialogs()
AudacityProject & mProject
void Populate(ShuttleGui &s)
void UpdateProgress(uint64_t current, uint64_t total)
wxButton * mContinueButton
void StartUploadProcess()
~ShareAudioDialog() override
struct cloud::audiocom::ShareAudioDialog::InitialStatePanel mInitialStatePanel
ShareAudioDialog(AudacityProject &project, wxWindow *parent=nullptr)
struct cloud::audiocom::ShareAudioDialog::ProgressPanel mProgressPanel
std::function< void()> mContinueAction
std::unique_ptr< BasicUI::ProgressDialog > mExportProgressHelper
std::unique_ptr< Services > mServices
void HandleExportFailure()
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.
std::wstring ToWString(const std::string &str)
wxString ToWXString(const std::string &str)
wxString GenerateTempPath(FileExtension extension)
const auto publicDescriptionText
const auto unlistedDescriptionText
const auto unlistedLabelText
const auto publicLabelText
BoolSetting SharePublicly
void UpdatePublicity(bool value)
void SetTimeLabel(wxStaticText *label, std::chrono::milliseconds time)
StringSetting displayName
AuthorizationHandler & GetAuthorizationHandler()
wxString GetUploadTempPath()
const ServiceConfig & GetServiceConfig()
Returns the instance of the ServiceConfig.
OAuthService & GetOAuthService()
Returns the instance of the OAuthService.
UserService & GetUserService()
std::unique_ptr< cloud::CloudExporterPlugin > CreatePreferredExporter(const MimeTypesList &mimeTypes, const AudacityProject &project)
Options for variations of error dialogs; the default is for modal dialogs.
ShareAudioDialog & mParent
void SetDialogTitle(const TranslatableString &) override
Change the dialog's title.
void SetMessage(const TranslatableString &) override
Change an existing dialog's message.
void Reinit() override
Reset the dialog state.
ExportProgressHelper(ShareAudioDialog &parent)
Clock::time_point mLastYield
BasicUI::ProgressResult Poll(unsigned long long numerator, unsigned long long denominator, const TranslatableString &) override
Update the bar and poll for clicks. Call only on the main thread.
std::chrono::steady_clock Clock
void PopulateFirstTimeNotice(ShuttleGui &s)
void OnLinkButtonPressed()
void PopulateInitialStatePanel(ShuttleGui &s)
void PopulateProgressPanel(ShuttleGui &s)
UploadOperationHandle uploadPromise
UploadService uploadService