diff --git a/libraries/lib-cloud-audiocom/ServiceConfig.cpp b/libraries/lib-cloud-audiocom/ServiceConfig.cpp index 71fec36c3880..e75b567050c3 100644 --- a/libraries/lib-cloud-audiocom/ServiceConfig.cpp +++ b/libraries/lib-cloud-audiocom/ServiceConfig.cpp @@ -46,11 +46,17 @@ std::string ServiceConfig::GetAPIUrl(std::string_view apiURI) const std::string ServiceConfig::GetFinishUploadPage( std::string_view audioID, std::string_view token) const { - return "http://audio.com/audacity/upload?audioId=" + std::string(audioID) + + return "https://audio.com/audacity/upload?audioId=" + std::string(audioID) + "&token=" + std::string(token) + "&clientId=" + std::string(GetOAuthClientID()); } +std::string ServiceConfig::GetAudioURL( + std::string_view userSlug, std::string_view audioSlug) const +{ + return "https://audio.com/" + std::string(userSlug) + "/audio/" + std::string(audioSlug) + "/edit"; +} + std::chrono::milliseconds ServiceConfig::GetProgressCallbackTimeout() const { return std::chrono::seconds(3); diff --git a/libraries/lib-cloud-audiocom/ServiceConfig.h b/libraries/lib-cloud-audiocom/ServiceConfig.h index 8eaeb81036ab..092fb4c5ef76 100644 --- a/libraries/lib-cloud-audiocom/ServiceConfig.h +++ b/libraries/lib-cloud-audiocom/ServiceConfig.h @@ -35,6 +35,8 @@ class CLOUD_AUDIOCOM_API ServiceConfig final std::string GetAPIUrl(std::string_view apiURI) const; //! Helper to construct the page URL for the anonymous upload last stage std::string GetFinishUploadPage(std::string_view audioID, std::string_view token) const; + //! Helper to construct the page URL for the authorised upload + std::string GetAudioURL(std::string_view userSlug, std::string_view audioSlug) const; //! Timeout between progress callbacks std::chrono::milliseconds GetProgressCallbackTimeout() const; //! Preferred audio format diff --git a/libraries/lib-cloud-audiocom/UploadService.cpp b/libraries/lib-cloud-audiocom/UploadService.cpp index 071dd19a5329..633ea8901871 100644 --- a/libraries/lib-cloud-audiocom/UploadService.cpp +++ b/libraries/lib-cloud-audiocom/UploadService.cpp @@ -206,6 +206,7 @@ struct AudiocomUploadOperation final : std::string mAudioID; std::string mUploadToken; + std::string mUserName; std::string mAudioSlug; @@ -264,10 +265,14 @@ struct AudiocomUploadOperation final : if (mCompletedCallback) { + const auto uploadURL = + mAuthToken.empty() ? + mServiceConfig.GetFinishUploadPage(mAudioID, mUploadToken) : + mServiceConfig.GetAudioURL(mUserName, mAudioSlug); mCompletedCallback( { UploadOperationCompleted::Result::Success, - UploadSuccessfulPayload { mAudioID, mAudioSlug } }); + UploadSuccessfulPayload { mAudioID, mAudioSlug, mUploadToken, uploadURL } }); } mProgressCallback = {}; @@ -395,6 +400,8 @@ struct AudiocomUploadOperation final : if (extra.HasMember("token")) mUploadToken = extra["token"].GetString(); + + mUserName = extra["audio"]["username"].GetString(); } const auto encType = document.HasMember("enctype") ? @@ -579,7 +586,7 @@ UploadOperationHandle UploadService::Upload( mServiceConfig, fileName, projectName, isPublic, std::move(completedCallback), std::move(progressCallback)); - mOAuthService.ValidateAuth([operation](std::string_view authToken) + mOAuthService.ValidateAuth([operation, this](std::string_view authToken) { operation->InitiateUpload(authToken); }); return UploadOperationHandle { operation }; diff --git a/libraries/lib-cloud-audiocom/UploadService.h b/libraries/lib-cloud-audiocom/UploadService.h index 23aa20080149..55f61e3427d7 100644 --- a/libraries/lib-cloud-audiocom/UploadService.h +++ b/libraries/lib-cloud-audiocom/UploadService.h @@ -43,6 +43,10 @@ struct CLOUD_AUDIOCOM_API UploadSuccessfulPayload final std::string audioId; //! "Slug" to be used for shareable URL construction std::string audioSlug; + //! Upload token, if any + std::string uploadToken; + //! URL to the uploaded audio + std::string audioUrl; }; //! Message that is sent when upload is finished. diff --git a/src/cloud/audiocom/ShareAudioDialog.cpp b/src/cloud/audiocom/ShareAudioDialog.cpp index df55f3a32ca4..31c94a6b1673 100644 --- a/src/cloud/audiocom/ShareAudioDialog.cpp +++ b/src/cloud/audiocom/ShareAudioDialog.cpp @@ -240,13 +240,29 @@ void ShareAudioDialog::Populate(ShuttleGui& s) mContinueButton = s.AddButton(XXO("C&ontinue")); mContinueButton->Bind(wxEVT_BUTTON, [this](auto) { OnContinue(); }); - mContinueButton->Enable(mIsAuthorised); } s.EndHorizontalLay(); } s.EndInvisiblePanel(); } s.EndHorizontalLay(); + + const auto title = mProject.GetProjectName(); + + if (!title.empty()) + { + mInitialStatePanel.trackTitle->SetValue(title); + mInitialStatePanel.trackTitle->SetInsertionPoint(title.length()); + } + + mContinueButton->Enable(mIsAuthorised && mInitialStatePanel.HasValidTitle()); + + mInitialStatePanel.trackTitle->Bind( + wxEVT_TEXT, + [this](auto&) { + mContinueButton->Enable( + mIsAuthorised && mInitialStatePanel.HasValidTitle()); + }); } void ShareAudioDialog::OnCancel() @@ -389,7 +405,7 @@ void ShareAudioDialog::StartUploadProcess() mServices->uploadPromise = mServices->uploadService.Upload( mFilePath, - mProject.GetProjectName(), + mInitialStatePanel.GetTrackTitle(), false, [this](const auto& result) { @@ -436,28 +452,8 @@ void ShareAudioDialog::StartUploadProcess() void ShareAudioDialog::HandleUploadSucceeded( const UploadSuccessfulPayload& payload) { - mProgressPanel.timePanel->Hide(); - mProgressPanel.title->SetLabel(XO("Upload complete!").Translation()); - mProgressPanel.info->Show(); - - mProgressPanel.info->SetLabel( - "By pressing continue, you will be taken to audio.com and given a shareable link."); - mProgressPanel.info->Wrap(mProgressPanel.root->GetSize().GetWidth()); - - mContinueAction = [this, slug = std::string(payload.audioSlug)]() - { - EndModal(wxID_CLOSE); - auto url = wxString::Format( - "https://audio.com/%s/%s/edit", GetUserService().GetUserSlug(), - audacity::ToWXString(slug)); - - OpenInDefaultBrowser(url); - }; - - mContinueButton->Show(); - - Layout(); - Fit(); + EndModal(wxID_CLOSE); + OpenInDefaultBrowser(wxString { payload.audioUrl }); } void ShareAudioDialog::HandleUploadFailed(const UploadFailedPayload& payload) @@ -466,12 +462,7 @@ void ShareAudioDialog::HandleUploadFailed(const UploadFailedPayload& payload) TranslatableString message; - if (payload.status == 401) - { - message = XO( - "We are unable to upload this file. Please try again and make sure to link to your audio.com account before uploading."); - } - else + if (!payload.message.empty()) { auto details = payload.message; @@ -480,6 +471,11 @@ void ShareAudioDialog::HandleUploadFailed(const UploadFailedPayload& payload) message = XO("Error: %s").Format(details); } + else + { + message = XO( + "We are unable to upload this file. Please try again and make sure to link to your audio.com account before uploading."); + } BasicUI::ShowErrorDialog( {}, XO("Upload error"), @@ -623,35 +619,43 @@ void ShareAudioDialog::InitialStatePanel::PopulateInitialStatePanel( s.SetBorder(0); s.AddWindow(safenew wxStaticLine { s.GetParent() }, wxEXPAND); - - s.AddSpace(16); - s.StartInvisiblePanel(); + + s.StartInvisiblePanel(16); { - anonInfoPanel = s.StartInvisiblePanel(); + s.StartInvisiblePanel(); { - s.SetBorder(30); - - AccessibleLinksFormatter privacyPolicy(XO( - "Your audio will be uploaded to our sharing service: %s,%%which requires a free account to use.")); + s.AddFixedText(XO("Track Title")); + s.AddSpace(8); + trackTitle = s.AddTextBox({}, {}, 60); + trackTitle->SetName(XO("Track Title").Translation()); + trackTitle->SetFocus(); + trackTitle->SetMaxLength(100); + s.AddSpace(16); + + anonInfoPanel = s.StartInvisiblePanel(); + { + AccessibleLinksFormatter privacyPolicy(XO( + "Your audio will be uploaded to our sharing service: %s,%%which requires a free account to use.")); - privacyPolicy.FormatLink( - L"%s", XO("audio.com"), "https://audio.com"); + privacyPolicy.FormatLink( + L"%s", XO("audio.com"), "https://audio.com"); - privacyPolicy.FormatLink( - L"%%", TranslatableString {}, - AccessibleLinksFormatter::LinkClickedHandler {}); + privacyPolicy.FormatLink( + L"%%", TranslatableString {}, + AccessibleLinksFormatter::LinkClickedHandler {}); - privacyPolicy.Populate(s); - } - s.EndInvisiblePanel(); + privacyPolicy.Populate(s); + } + s.EndInvisiblePanel(); - authorizedInfoPanel = s.StartInvisiblePanel(); - s.StartHorizontalLay(wxEXPAND, 1); - { - s.AddSpace(30); - s.AddFixedText(XO("Press \"Continue\" to upload to audio.com")); + authorizedInfoPanel = s.StartInvisiblePanel(); + s.StartHorizontalLay(wxEXPAND, 1); + { + s.AddFixedText(XO("Press \"Continue\" to upload to audio.com")); + } + s.EndHorizontalLay(); + s.EndInvisiblePanel(); } - s.EndHorizontalLay(); s.EndInvisiblePanel(); } s.EndInvisiblePanel(); @@ -675,6 +679,8 @@ void ShareAudioDialog::InitialStatePanel::UpdateUserData() rootParent->Layout(); rootParent->Thaw(); + + rootParent->Refresh(); }); auto& oauthService = GetOAuthService(); @@ -714,9 +720,9 @@ void ShareAudioDialog::InitialStatePanel::UpdateUserData() anonInfoPanel->Hide(); authorizedInfoPanel->Show(); - + if (parent.mContinueButton != nullptr) - parent.mContinueButton->Enable(); + parent.mContinueButton->Enable(!trackTitle->GetValue().empty()); } void ShareAudioDialog::InitialStatePanel::OnLinkButtonPressed() @@ -755,6 +761,18 @@ void ShareAudioDialog::InitialStatePanel::SetAnonymousState() parent.mContinueButton->Enable(false); } +wxString ShareAudioDialog::InitialStatePanel::GetTrackTitle() const +{ + wxString ret { trackTitle->GetValue() }; + ret.Trim(true).Trim(false); + return ret; +} + +bool ShareAudioDialog::InitialStatePanel::HasValidTitle() const +{ + return !GetTrackTitle().empty(); +} + void ShareAudioDialog::ProgressPanel::PopulateProgressPanel(ShuttleGui& s) { root = s.StartInvisiblePanel(16); diff --git a/src/cloud/audiocom/ShareAudioDialog.h b/src/cloud/audiocom/ShareAudioDialog.h index a6ad83715370..9e3460f15078 100644 --- a/src/cloud/audiocom/ShareAudioDialog.h +++ b/src/cloud/audiocom/ShareAudioDialog.h @@ -79,6 +79,7 @@ class ShareAudioDialog final : wxButton* oauthButton { nullptr }; wxPanel* anonInfoPanel { nullptr }; wxPanel* authorizedInfoPanel { nullptr }; + wxTextCtrl* trackTitle { nullptr }; Observer::Subscription mUserDataChangedSubscription; @@ -89,6 +90,8 @@ class ShareAudioDialog final : void SetAnonymousState(); + wxString GetTrackTitle() const; + bool HasValidTitle() const; } mInitialStatePanel; struct ProgressPanel final