diff --git a/resources/sql/patches/20130927.audiomacro.sql b/resources/sql/patches/20130927.audiomacro.sql new file mode 100644 index 0000000000..accb4a335c --- /dev/null +++ b/resources/sql/patches/20130927.audiomacro.sql @@ -0,0 +1,8 @@ +ALTER TABLE {$NAMESPACE}_file.file_imagemacro + ADD audioPHID VARCHAR(64) COLLATE utf8_bin; + +ALTER TABLE {$NAMESPACE}_file.file_imagemacro + ADD audioBehavior VARCHAR(64) NOT NULL COLLATE utf8_bin; + +UPDATE {$NAMESPACE}_file.file_imagemacro + SET audioBehavior = 'audio:none' WHERE audioBehavior = ''; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index c903844cd8..884a23f75a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1270,6 +1270,7 @@ phutil_register_library_map(array( 'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php', 'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php', 'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php', + 'PhabricatorMacroAudioController' => 'applications/macro/controller/PhabricatorMacroAudioController.php', 'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php', 'PhabricatorMacroConfigOptions' => 'applications/macro/config/PhabricatorMacroConfigOptions.php', 'PhabricatorMacroController' => 'applications/macro/controller/PhabricatorMacroController.php', @@ -3416,6 +3417,7 @@ phutil_register_library_map(array( 'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase', 'PhabricatorLogoutController' => 'PhabricatorAuthController', + 'PhabricatorMacroAudioController' => 'PhabricatorMacroController', 'PhabricatorMacroCommentController' => 'PhabricatorMacroController', 'PhabricatorMacroConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMacroController' => 'PhabricatorController', diff --git a/src/applications/macro/application/PhabricatorApplicationMacro.php b/src/applications/macro/application/PhabricatorApplicationMacro.php index fa148687d3..d67941b941 100644 --- a/src/applications/macro/application/PhabricatorApplicationMacro.php +++ b/src/applications/macro/application/PhabricatorApplicationMacro.php @@ -34,6 +34,7 @@ final class PhabricatorApplicationMacro extends PhabricatorApplication { 'view/(?P[1-9]\d*)/' => 'PhabricatorMacroViewController', 'comment/(?P[1-9]\d*)/' => 'PhabricatorMacroCommentController', 'edit/(?P[1-9]\d*)/' => 'PhabricatorMacroEditController', + 'audio/(?P[1-9]\d*)/' => 'PhabricatorMacroAudioController', 'disable/(?P[1-9]\d*)/' => 'PhabricatorMacroDisableController', 'meme/' => 'PhabricatorMacroMemeController', 'meme/create/' => 'PhabricatorMacroMemeDialogController', diff --git a/src/applications/macro/constants/PhabricatorMacroTransactionType.php b/src/applications/macro/constants/PhabricatorMacroTransactionType.php index fb1b8013aa..1de00b73cd 100644 --- a/src/applications/macro/constants/PhabricatorMacroTransactionType.php +++ b/src/applications/macro/constants/PhabricatorMacroTransactionType.php @@ -6,4 +6,7 @@ final class PhabricatorMacroTransactionType { const TYPE_DISABLED = 'macro:disabled'; const TYPE_FILE = 'macro:file'; + const TYPE_AUDIO = 'macro:audio'; + const TYPE_AUDIO_BEHAVIOR = 'macro:audiobehavior'; + } diff --git a/src/applications/macro/controller/PhabricatorMacroAudioController.php b/src/applications/macro/controller/PhabricatorMacroAudioController.php new file mode 100644 index 0000000000..21ad01804b --- /dev/null +++ b/src/applications/macro/controller/PhabricatorMacroAudioController.php @@ -0,0 +1,173 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $macro = id(new PhabricatorMacroQuery()) + ->setViewer($viewer) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->withIDs(array($this->id)) + ->executeOne(); + + if (!$macro) { + return new Aphront404Response(); + } + + $errors = array(); + $view_uri = $this->getApplicationURI('/view/'.$macro->getID().'/'); + + $e_file = null; + $file = null; + + if ($request->isFormPost()) { + $xactions = array(); + + if ($request->getBool('behaviorForm')) { + $xactions[] = id(new PhabricatorMacroTransaction()) + ->setTransactionType( + PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR) + ->setNewValue($request->getStr('audioBehavior')); + } else { + $file = null; + if ($request->getFileExists('file')) { + $file = PhabricatorFile::newFromPHPUpload( + $_FILES['file'], + array( + 'name' => $request->getStr('name'), + 'authorPHID' => $viewer->getPHID(), + 'isExplicitUpload' => true, + )); + } + + if ($file) { + if (!$file->isAudio()) { + $errors[] = pht('You must upload audio.'); + $e_file = pht('Invalid'); + } else { + $xactions[] = id(new PhabricatorMacroTransaction()) + ->setTransactionType(PhabricatorMacroTransactionType::TYPE_AUDIO) + ->setNewValue($file->getPHID()); + } + } else { + $errors[] = pht('You must upload an audio file.'); + $e_file = pht('Required'); + } + } + + if (!$errors) { + id(new PhabricatorMacroEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContentSourceFromRequest($request) + ->applyTransactions($macro, $xactions); + + return id(new AphrontRedirectResponse())->setURI($view_uri); + } + } + + if ($errors) { + $error_view = new AphrontErrorView(); + $error_view->setTitle(pht('Form Errors')); + $error_view->setErrors($errors); + } else { + $error_view = null; + } + + $form = id(new AphrontFormView()) + ->addHiddenInput('behaviorForm', 1) + ->setUser($viewer); + + $options = id(new AphrontFormRadioButtonControl()) + ->setLabel(pht('Audio Behavior')) + ->setName('audioBehavior') + ->setValue( + nonempty( + $macro->getAudioBehavior(), + PhabricatorFileImageMacro::AUDIO_BEHAVIOR_NONE)); + + $options->addButton( + PhabricatorFileImageMacro::AUDIO_BEHAVIOR_NONE, + pht('Do Not Play'), + pht('Do not play audio.')); + + $options->addButton( + PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE, + pht('Play Once'), + pht('Play audio once, when the viewer looks at the macro.')); + + $options->addButton( + PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP, + pht('Play Continuously'), + pht( + 'Play audio continuously, treating the macro as an audio source. '. + 'Best for ambient sounds.')); + + $form->appendChild($options); + + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue(pht('Save Audio Behavior')) + ->addCancelButton($view_uri)); + + $crumbs = $this->buildApplicationCrumbs(); + + $title = pht('Edit Audio Behavior'); + $crumb = pht('Edit Audio'); + + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setHref($view_uri) + ->setName(pht('Macro "%s"', $macro->getName()))); + + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setHref($request->getRequestURI()) + ->setName($crumb)); + + $upload_form = id(new AphrontFormView()) + ->setEncType('multipart/form-data') + ->setUser($viewer) + ->appendChild( + id(new AphrontFormFileControl()) + ->setLabel(pht('Audio File')) + ->setName('file')) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue(pht('Upload File'))); + + $upload = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Upload New Audio')) + ->setForm($upload_form); + + $form_box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->setFormError($error_view) + ->setForm($form); + + return $this->buildApplicationPage( + array( + $crumbs, + $form_box, + $upload, + ), + array( + 'title' => $title, + 'device' => true, + )); + } +} diff --git a/src/applications/macro/controller/PhabricatorMacroViewController.php b/src/applications/macro/controller/PhabricatorMacroViewController.php index 2103541b7e..5f1ca4a21e 100644 --- a/src/applications/macro/controller/PhabricatorMacroViewController.php +++ b/src/applications/macro/controller/PhabricatorMacroViewController.php @@ -119,6 +119,12 @@ final class PhabricatorMacroViewController ->setHref($this->getApplicationURI('/edit/'.$macro->getID().'/')) ->setIcon('edit')); + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Audio')) + ->setHref($this->getApplicationURI('/audio/'.$macro->getID().'/')) + ->setIcon('herald')); + if ($macro->getIsDisabled()) { $view->addAction( id(new PhabricatorActionView()) @@ -146,6 +152,25 @@ final class PhabricatorMacroViewController ->setUser($this->getRequest()->getUser()) ->setObject($macro); + switch ($macro->getAudioBehavior()) { + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: + $view->addProperty(pht('Audio Behavior'), pht('Play Once')); + break; + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: + $view->addProperty(pht('Audio Behavior'), pht('Loop')); + break; + } + + $audio_phid = $macro->getAudioPHID(); + if ($audio_phid) { + $this->loadHandles(array($audio_phid)); + + $view->addProperty( + pht('Audio'), + $this->getHandle($audio_phid)->renderLink()); + } + + $view->invokeWillRenderEvent(); if ($file) { diff --git a/src/applications/macro/editor/PhabricatorMacroEditor.php b/src/applications/macro/editor/PhabricatorMacroEditor.php index 9b706ad224..d37e111e66 100644 --- a/src/applications/macro/editor/PhabricatorMacroEditor.php +++ b/src/applications/macro/editor/PhabricatorMacroEditor.php @@ -10,6 +10,8 @@ final class PhabricatorMacroEditor $types[] = PhabricatorMacroTransactionType::TYPE_NAME; $types[] = PhabricatorMacroTransactionType::TYPE_DISABLED; $types[] = PhabricatorMacroTransactionType::TYPE_FILE; + $types[] = PhabricatorMacroTransactionType::TYPE_AUDIO; + $types[] = PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR; return $types; } @@ -25,6 +27,10 @@ final class PhabricatorMacroEditor return $object->getIsDisabled(); case PhabricatorMacroTransactionType::TYPE_FILE: return $object->getFilePHID(); + case PhabricatorMacroTransactionType::TYPE_AUDIO: + return $object->getAudioPHID(); + case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: + return $object->getAudioBehavior(); } } @@ -36,6 +42,8 @@ final class PhabricatorMacroEditor case PhabricatorMacroTransactionType::TYPE_NAME: case PhabricatorMacroTransactionType::TYPE_DISABLED: case PhabricatorMacroTransactionType::TYPE_FILE: + case PhabricatorMacroTransactionType::TYPE_AUDIO: + case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: return $xaction->getNewValue(); } } @@ -54,6 +62,12 @@ final class PhabricatorMacroEditor case PhabricatorMacroTransactionType::TYPE_FILE: $object->setFilePHID($xaction->getNewValue()); break; + case PhabricatorMacroTransactionType::TYPE_AUDIO: + $object->setAudioPHID($xaction->getNewValue()); + break; + case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: + $object->setAudioBehavior($xaction->getNewValue()); + break; } } @@ -72,6 +86,8 @@ final class PhabricatorMacroEditor case PhabricatorMacroTransactionType::TYPE_NAME: case PhabricatorMacroTransactionType::TYPE_DISABLED: case PhabricatorMacroTransactionType::TYPE_FILE: + case PhabricatorMacroTransactionType::TYPE_AUDIO: + case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: return $v; } diff --git a/src/applications/macro/storage/PhabricatorFileImageMacro.php b/src/applications/macro/storage/PhabricatorFileImageMacro.php index 83527ef294..272d5abdd0 100644 --- a/src/applications/macro/storage/PhabricatorFileImageMacro.php +++ b/src/applications/macro/storage/PhabricatorFileImageMacro.php @@ -11,8 +11,15 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO protected $phid; protected $name; protected $isDisabled = 0; + protected $audioPHID; + protected $audioBehavior = self::AUDIO_BEHAVIOR_NONE; private $file = self::ATTACHABLE; + private $audio = self::ATTACHABLE; + + const AUDIO_BEHAVIOR_NONE = 'audio:none'; + const AUDIO_BEHAVIOR_ONCE = 'audio:once'; + const AUDIO_BEHAVIOR_LOOP = 'audio:loop'; public function attachFile(PhabricatorFile $file) { $this->file = $file; @@ -23,6 +30,15 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO return $this->assertAttached($this->file); } + public function attachAudio(PhabricatorFile $audio = null) { + $this->audio = $audio; + return $this; + } + + public function getAudio() { + return $this->assertAttached($this->audio); + } + public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, diff --git a/src/applications/macro/storage/PhabricatorMacroTransaction.php b/src/applications/macro/storage/PhabricatorMacroTransaction.php index 04e8834eba..bcac44ae19 100644 --- a/src/applications/macro/storage/PhabricatorMacroTransaction.php +++ b/src/applications/macro/storage/PhabricatorMacroTransaction.php @@ -27,6 +27,7 @@ final class PhabricatorMacroTransaction switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_FILE: + case PhabricatorMacroTransactionType::TYPE_AUDIO: if ($old !== null) { $phids[] = $old; } @@ -74,6 +75,37 @@ final class PhabricatorMacroTransaction $this->renderHandleLink($author_phid)); } break; + + case PhabricatorMacroTransactionType::TYPE_AUDIO: + if (!$old) { + return pht( + '%s attached audio: %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($new)); + } else { + return pht( + '%s changed the audio for this macro from %s to %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($old), + $this->renderHandleLink($new)); + } + + case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: + switch ($new) { + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: + return pht( + '%s set the audio to play once.', + $this->renderHandleLink($author_phid)); + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: + return pht( + '%s set the audio to loop.', + $this->renderHandleLink($author_phid)); + default: + return pht( + '%s disabled the audio for this macro.', + $this->renderHandleLink($author_phid)); + } + case PhabricatorMacroTransactionType::TYPE_FILE: if ($old === null) { return pht( @@ -131,6 +163,42 @@ final class PhabricatorMacroTransaction $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } + + case PhabricatorMacroTransactionType::TYPE_AUDIO: + if (!$old) { + return pht( + '%s attached audio to %s: %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid), + $this->renderHandleLink($new)); + } else { + return pht( + '%s changed the audio for %s from %s to %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid), + $this->renderHandleLink($old), + $this->renderHandleLink($new)); + } + + case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: + switch ($new) { + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: + return pht( + '%s set the audio for %s to play once.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: + return pht( + '%s set the audio for %s to loop.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + default: + return pht( + '%s disabled the audio for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } + } return parent::getTitleForFeed($story); @@ -159,6 +227,13 @@ final class PhabricatorMacroTransaction } else { return pht('Edited Image'); } + + case PhabricatorMacroTransactionType::TYPE_AUDIO: + return pht('Audio'); + + case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: + return pht('Audio Behavior'); + } return parent::getActionName(); @@ -193,6 +268,8 @@ final class PhabricatorMacroTransaction } else { return 'undo'; } + case PhabricatorMacroTransactionType::TYPE_AUDIO: + return 'herald'; } return parent::getIcon(); diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php index ce31ca05bc..bcb2f5c796 100644 --- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1644,6 +1644,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList { 'type' => 'sql', 'name' => $this->getPatchPath('20130926.dinkeys.sql'), ), + '20130927.audiomacro.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('20130927.audiomacro.sql'), + ), ); } }