Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Learner view audio translations #3681

Merged
merged 17 commits into from
Aug 3, 2017
Merged

Conversation

tjiang11
Copy link
Contributor

This PR implements minimum viable functionality for audio in the learner view.

@tjiang11 tjiang11 requested a review from seanlip July 27, 2017 06:12
<p>
Pick Language
</p>
<!-- <select2-drdopdown
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Copy link
Member

@seanlip seanlip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Took a first pass.

@@ -107,6 +107,18 @@ oppia.factory('StatesObjectFactory', [
return finalStateNames;
};

States.prototype.getAllAudioLanguageCodes = function() {
var allAudioLanguageCodes = new Set();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set is relatively recent and isn't supported in some slightly older browsers. Might want to consider using an array instead and checking for existing membership with indexOf().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

var allAudioLanguageCodes = new Set();
for (var stateName in this._states) {
var audioTranslationsForState =
this._states[stateName].content.getBindableAudioTranslations()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -107,6 +107,18 @@ oppia.factory('StatesObjectFactory', [
return finalStateNames;
};

States.prototype.getAllAudioLanguageCodes = function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

@@ -838,6 +838,13 @@ oppia.factory('explorationLanguageCodeService', [
}
}
};
child.getLanguageDescription = function(languageCode) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this has anything to do with this factory, actually. You might want to define a separate utility factory for handling global language-related operations that aren't exploration-specific.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved into LanguageUtilService


/**
* @fileoverview Service to manage the current language being
* used for audio translations as well as related modals.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit unclear -- on first reading I thought the service also managed the language being used to display the text on related modals, and thought, hm, this isn't in the spec. I think it's fine to drop the "as well as related modals" bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


<div class="modal-body">
<p>
Pick Language
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -30,6 +33,18 @@ oppia.factory('AudioPlayerService', [
var blobUrl = URL.createObjectURL(audioBlob);
_currentTrack = ngAudio.load(blobUrl);
_currentTrackFilename = filename;

// Doesn't seem to be any way of detecing when native
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detecting (typo)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

// to grab native audio.
// TODO(tjiang11): Find a better way to handle this.
$timeout(function() {
_currentTrack.audio.onended = function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate a bit more (in comments) on the ideas behind the workaround here? I'm not sure I fully understand it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (!_currentTrack) {
return false;
}
return !_currentTrack.paused;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative: return (_currentTrack && !_currentTrack.paused);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
return !_currentTrack.paused;
},
trackLoaded: function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

start with verb. (This one is particularly misleading because "track" is a verb too :P)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@codecov-io
Copy link

codecov-io commented Jul 27, 2017

Codecov Report

Merging #3681 into develop will decrease coverage by 0.01%.
The diff coverage is 18.46%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #3681      +/-   ##
===========================================
- Coverage    45.03%   45.01%   -0.02%     
===========================================
  Files          261      264       +3     
  Lines        20219    20343     +124     
  Branches      3157     3168      +11     
===========================================
+ Hits          9106     9158      +52     
- Misses       11113    11185      +72
Impacted Files Coverage Δ
...lates/dev/head/services/AssetsBackendApiService.js 58.97% <ø> (-1.03%) ⬇️
...ev/head/pages/exploration_player/PlayerServices.js 1.71% <0%> (-0.09%) ⬇️
...xploration_player/ExplorationPlayerStateService.js 5.26% <0%> (-0.62%) ⬇️
.../templates/dev/head/services/AudioPlayerService.js 1.69% <0%> (-0.81%) ⬇️
...ead/pages/exploration_player/TutorCardDirective.js 2.81% <0%> (-0.17%) ⬇️
...s/dev/head/domain/utilities/LanguageUtilService.js 100% <100%> (ø)
...dev/head/domain/exploration/StatesObjectFactory.js 65.75% <100%> (+4.21%) ⬆️
...ploration_player/AudioTranslationManagerService.js 2.77% <2.77%> (ø)
...pages/exploration_player/AudioControlsDirective.js 3.33% <3.33%> (ø)
...d/domain/exploration/SubtitledHtmlObjectFactory.js 90.62% <50%> (-2.71%) ⬇️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bc31014...e026b84. Read the comment docs.

@tjiang11
Copy link
Contributor Author

  • stop audio on switching cards

Copy link
Member

@seanlip seanlip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice, thanks @tjiang11! Mostly trivial comments.

@@ -122,6 +122,24 @@ oppia.factory('ExplorationObjectFactory', [
return this.getState(stateName).content.getHtml();
};

Exploration.prototype.getAudioTranslations = function(stateName) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

var audioTranslationsForState =
this._states[stateName].content.getBindableAudioTranslations();
for (var languageCode in audioTranslationsForState) {
if (allAudioLanguageCodes.indexOf(languageCode) == -1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ===

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return {
restrict: 'E',
scope: {
audioTranslations: '='
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is intended to be readonly (i.e. not modified from within the directive), then use getAudioTranslations: '&audioTranslations' and call $scope.getAudioTranslations() instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

'$scope', 'AudioTranslationManagerService', 'AudioPlayerService',
function(
$scope, AudioTranslationManagerService, AudioPlayerService) {
var filenameOfLastStartedAudio;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize to null?

}
} else {
AudioPlayerService.pause();
if (!isRequestForSameAudioAsLastTime()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still a bit confused by this. Presumably the user has just clicked a button that looks visually like "pause" -- how come we then play?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should only activate when a user has clicked a "play" button on an audio translation that is different from the current audio being played. This way, the audio player pauses the existing audio and immediately starts playing the newly requested audio translation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused about this scenario: "when a user has clicked a 'play' button on an audio translation that is different from the current audio being played". In what circumstances would it happen? Are there ever multiple play buttons available at once?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, my bad: as @tjiang11 clarified in chat, in the future there may be > 1 play button on a page. This handles that correctly, so I don't think further changes are needed here.

};

$scope.arePreviousResponsesShown = false;

$scope.waitingForOppiaFeedback = false;

$scope.currentAudioLanguageCode = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't used or modified?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

@@ -52,14 +52,16 @@ oppia.directive('tutorCard', [
'$scope', '$timeout', 'oppiaPlayerService', 'HintManagerService',
'playerPositionService', 'playerTranscriptService',
'ExplorationPlayerStateService', 'windowDimensionsService',
'urlService', 'TWO_CARD_THRESHOLD_PX', 'CONTENT_FOCUS_LABEL_PREFIX',
'urlService', 'AudioPlayerService', 'AudioTranslationManagerService',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The added deps aren't used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed, except for AudioPlayerService which I use now for stopping audio on changing cards

}

.audio-control-button:hover {
cursor: pointer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

focus-on="<[getContentFocusLabel($index)]>">
<span angular-html-bind="activeCard.contentHtml">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not div? Content may span multiple paragraphs, for instance. Might mean the next bit has to be a div too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@@ -72,6 +72,10 @@ oppia.factory('AssetsBackendApiService', [
};

var _getAudioDownloadUrl = function(explorationId, filename) {
if (GLOBALS.DEV_MODE) {
return '/assets/test/' + filename;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have /assets/test/ be part of constants.js perhaps? Or rather -- have an assets dir prefix that's one thing in dev and another thing (the GCS url prefix) in prod? Better to do the if/else check in just one place if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure how to go about doing the latter implementation while still avoiding an if/else for the url interpolation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I thought about this. It's not straightforward, unfortunately. Here's the reasoning:

constants.js needs to be a static dict (since the backend interprets it as JSON), so it can't have any logic in it. That's a shame, because that's the file for constants shared between frontend and backend. But we can't have an if/else condition there.

The other place we store constants is in feconf, and we can do "if DEV_MODE ... else ..." there. We can then ship it to the frontend as a GLOBALS property -- see how ALLOWED_GADGETS is sent in editor.py, for example. The logic here should then be:

return UrlInterpolationService.interpolateUrl(GLOBALS.AUDIO_URL_PREFIX, {...});

This would be better than doing a one-off thing here, because that way there'll be a single audio url prefix used everywhere. This becomes important when we work on the editor page because audio files need to be uploaded to that same location as well, so this prefix needs to be somehow global.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@seanlip seanlip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh noes -- there's a merge conflict!

Otherwise this looks amazing :) I made a few nit comments and maybe we should change the image files to use material-icons or something but other than that, LGTM!

Feel free to merge once you've fixed the remaining stuff and Travis checks pass. Thanks a lot!

@@ -238,6 +244,10 @@
top: 14px;
}

.audio-controls {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.oppia-player-audio-controls or similar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to conversation-skin-audio-controls

feconf.py Outdated
# files.

if DEV_MODE:
AUDIO_URL_PREFIX = '/assets/test/<exploration_id>/audio/<filename>'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, looks more like AUDIO_URL_TEMPLATE to me?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

function(
$scope, AudioTranslationManagerService, AudioPlayerService) {
var filenameOfLastStartedAudio = null;
var directiveId = Math.random().toString(36).substr(2, 10);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment here to explain what this is used for -- it's not obvious from the naming.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

UrlInterpolationService.getStaticImageUrl(
'/icons/settings.svg'));

var PLAY_AUDIO_BUTTON_IMAGE_URL = (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming: use

IMAGE_URL_AUDIO_SETTINGS
IMAGE_URL_PLAY_AUDIO
IMAGE_URL_PAUSE_AUDIO
IMAGE_URL_REWIND_AUDIO

(basically, start with the type. That way it's easier to see that everything is in a "group of related things".)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

'$scope', 'AudioTranslationManagerService', 'AudioPlayerService',
function(
$scope, AudioTranslationManagerService, AudioPlayerService) {
var filenameOfLastStartedAudio = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you actually still need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

@seanlip seanlip mentioned this pull request Aug 2, 2017
3 tasks
@seanlip
Copy link
Member

seanlip commented Aug 3, 2017

Just FYI, there are merge conflicts (which block the Travis tests from running).

@seanlip
Copy link
Member

seanlip commented Aug 3, 2017

Hi @tjiang11 -- e2e tests are failing rather badly. Any idea why?

Feel free to pick up and use any patterns in my PR if you need them, btw. I'm happy to handle the merges.

@seanlip seanlip merged commit 90f1f2c into oppia:develop Aug 3, 2017
giritheja added a commit to giritheja/oppia that referenced this pull request Aug 8, 2017
* upstream/develop: (39 commits)
  Add a one-off job to list which explorations use gadgets; remove old fallbacks job. (oppia#3717)
  Fix oppia#2998 implement collection skills update commands (oppia#3710)
  Improvements and bug fixes to changes introduced by PR oppia#3671 (oppia#3684)
  Fix oppia#3688: refactoring ExplorationStatusHandler to remove unpublish and publicize functionality as it is not called from frontend. (oppia#3715)
  fix oppia#3698: Shift exception handling for NotLoggedInException so that it does not generate log errors. (oppia#3714)
  Revert "Fix oppia#3707 Change text of collection learner view "start here"" (oppia#3713)
  Fix oppia#3701 Fixed Continue button name issue (oppia#3711)
  Fix oppia#3467: Introduce re-training and add_to_training_queue methods (oppia#3650)
  Fix oppia#3707 Change text of collection learner view "start here" (oppia#3700)
  Audio fixes: make audio download URL safe; don't show flagging modal if all translations are flagged; use templateUrl for modals. (oppia#3709)
  Learner audio updates (oppia#3705)
  Move hint button to left corner for supplemental cards (oppia#3702)
  Make the representation of the learner's 'Continue' answer more conversational. (oppia#3675)
  Add editor for audio translations (oppia#3692)
  Fix oppia#3686 fixed text overflow for contributors list (oppia#3697)
  Fix oppia#3551: Manually set cookie value during language change (oppia#3622)
  Learner view audio translations (oppia#3681)
  The sixth milestone of the learner dashboard. (oppia#3680)
  Routine update of translations. (oppia#3685)
  SiteWide ACL Refactor: Milestone 3.1 (oppia#3682)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants