diff --git a/.eslintrc.js b/.eslintrc.js index 4327cd6..f2c6764 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,6 +12,7 @@ module.exports = { rules: { }, globals: { - "RecordRTC": true + "RecordRTC": true, + "Twilio": true } }; diff --git a/app/components/audio-recorder/styles.styl b/app/components/audio-recorder/styles.styl index 701aefd..3864143 100644 --- a/app/components/audio-recorder/styles.styl +++ b/app/components/audio-recorder/styles.styl @@ -14,7 +14,10 @@ .btn:hover background: rgba(off-white, 1) -.btn:active - background: hot-pink - opacity: 1 +.record-button + color: slate + +.record-button:active color: off-white + background: rgba(red, 0.6) + opacity: 1 diff --git a/app/components/audio-recorder/template.hbs b/app/components/audio-recorder/template.hbs index f833fc2..dbe9b2f 100644 --- a/app/components/audio-recorder/template.hbs +++ b/app/components/audio-recorder/template.hbs @@ -1,9 +1,10 @@ {{ui/icon-button + class='record-button' loading=saving disabled=saving mouseDown=(action 'startRecording') mouseUp=(action 'stopRecording') - leftIcon="microphone"}} + leftIcon="circle"}} {{#if hasAudio}} {{ui/icon-button diff --git a/app/components/communication/video-chat/component.js b/app/components/communication/video-chat/component.js index 085a101..9a39ebe 100644 --- a/app/components/communication/video-chat/component.js +++ b/app/components/communication/video-chat/component.js @@ -4,7 +4,7 @@ const Video = Twilio.Video; export default Ember.Component.extend({ startVideo() { - const { token, identity } = this.get("twilioData"); + const { token } = this.get("twilioData"); Video.connect(token, {name: "my-room"}) .then(room => { @@ -15,8 +15,8 @@ export default Ember.Component.extend({ room.on('participantConnected', ::this.participantConnected); room.on('participantDisconnected', ::this.participantDisconnected); - room.once('disconnected', error => room.participants.forEach(::this.participantDisconnected)); - }, e => console.log(e)); + room.once('disconnected', () => room.participants.forEach(::this.participantDisconnected)); + }); }, attachTracks(tracks, container) { diff --git a/app/components/conversation-group/component.js b/app/components/conversation-group/component.js index 473ed4e..85d7520 100644 --- a/app/components/conversation-group/component.js +++ b/app/components/conversation-group/component.js @@ -1,7 +1,6 @@ import Ember from 'ember'; -import computed from 'ember-computed-decorators'; -const { isPresent, computed: { alias, sort, gt } } = Ember; +const { computed: { alias, sort, gt } } = Ember; export default Ember.Component.extend({ sortAsc: ["position:asc"], diff --git a/app/components/conversation-group/styles.styl b/app/components/conversation-group/styles.styl index eca0332..05ae7b8 100644 --- a/app/components/conversation-group/styles.styl +++ b/app/components/conversation-group/styles.styl @@ -1,6 +1,9 @@ & margin-top: 3em +.conversation-container + padding: 0 2em + .create-conversation width: 100% padding: 1em diff --git a/app/components/flash-card-group/component.js b/app/components/flash-card-group/component.js index d5aebf0..f9d7897 100644 --- a/app/components/flash-card-group/component.js +++ b/app/components/flash-card-group/component.js @@ -1,11 +1,10 @@ import Ember from 'ember'; -import computed from 'ember-computed-decorators'; -const { isPresent, computed: { alias, sort, gt } } = Ember; +const { computed: { alias, sort, gt } } = Ember; export default Ember.Component.extend({ classNames: ['card-1'], - + sortAsc: ["position:asc"], sortedFlashCards: sort('model.activeFlashCards', 'sortAsc'), flashCardCount: alias("sortedFlashCards.length"), diff --git a/app/components/flash-card/component.js b/app/components/flash-card/component.js index abcd94f..4fe660c 100644 --- a/app/components/flash-card/component.js +++ b/app/components/flash-card/component.js @@ -1,6 +1,5 @@ import Ember from 'ember'; import _ from 'lodash'; -import computed from 'ember-computed-decorators'; const TONE_REGEX = /([aeiouAEIOU][1234])/g; @@ -56,10 +55,6 @@ const TONE_MAPPING = { "U4": "Ù" }; -const { - computed: { notEmpty } -} = Ember; - export default Ember.Component.extend({ classNames: ['card-2', 'stretch'], @@ -69,7 +64,7 @@ export default Ember.Component.extend({ }, actions: { - processChange(str) { + processChange(model, str) { const editor = this.$(".pinyinEditor")[0]; let cursorPosition = editor.selectionStart; let newStr = str; @@ -80,16 +75,16 @@ export default Ember.Component.extend({ cursorPosition = cursorPosition - matches.length; } - this.set("model.pinyin", newStr); + model.set("text", newStr); - this.get("saveModel")(this.get("model")); + this.get("saveModel")(model); Ember.run.scheduleOnce('afterRender', this, this.setSelection, editor, cursorPosition, cursorPosition); }, - handleUpdate(key, str) { - this.get("model").set(key, str); - this.get("saveModel")(this.get("model")); + handleUpdate(model, str) { + model.set('text', str); + this.get("saveModel")(model); } } }); diff --git a/app/components/flash-card/styles.styl b/app/components/flash-card/styles.styl index 91e868b..02091e0 100644 --- a/app/components/flash-card/styles.styl +++ b/app/components/flash-card/styles.styl @@ -4,6 +4,8 @@ min-width: 18em width: 18em margin: 0.5em + border-bottom-left-radius: 10px + border-bottom-right-radius: 10px .inputContainer margin-left: 1em @@ -20,8 +22,6 @@ textarea background: rgba(white, 0.75) .fieldsContainer - // margin: 0.5em - +below(700px) flex-direction: column diff --git a/app/components/flash-card/template.hbs b/app/components/flash-card/template.hbs index 322488f..ae305cf 100644 --- a/app/components/flash-card/template.hbs +++ b/app/components/flash-card/template.hbs @@ -15,9 +15,9 @@
- {{one-way-textarea model.chinese + {{one-way-textarea model.chinese.text placeholder='汉语...' - update=(action "handleUpdate" "chinese") + update=(action "handleUpdate" model.chinese) autocomplete="off" autocorrect="off" autocapitalize="off" @@ -25,10 +25,10 @@
- {{one-way-textarea model.pinyin + {{one-way-textarea model.pinyin.text placeholder='Pinyin...' class="pinyinEditor" - update=(action 'processChange') + update=(action 'processChange' model.pinyin) autocomplete="off" autocorrect="off" autocapitalize="off" @@ -36,9 +36,9 @@
- {{one-way-textarea model.english + {{one-way-textarea model.english.text placeholder='English...' - update=(action "handleUpdate" "english") + update=(action "handleUpdate" model.english) autocomplete="off" autocorrect="off" autocapitalize="off" @@ -47,7 +47,7 @@
- {{audio-recorder + {{audio-recorder model=model created=(action onAudioCreated model)}}
diff --git a/app/index.html b/app/index.html index e2b628a..4c5f01a 100644 --- a/app/index.html +++ b/app/index.html @@ -12,11 +12,10 @@ - - - + + {{content-for "head-footer"}} diff --git a/app/models/conversation.js b/app/models/conversation.js index 0a3f425..afff6c7 100644 --- a/app/models/conversation.js +++ b/app/models/conversation.js @@ -1,7 +1,7 @@ import DS from 'ember-data'; -import computed from 'ember-computed-decorators'; +import Ember from 'ember'; -const { empty, filterBy } = Ember.computed; +const { filterBy, empty } = Ember.computed; export default DS.Model.extend({ title: DS.attr('string'), diff --git a/app/models/flash-card.js b/app/models/flash-card.js index 7b0463d..58ad7df 100644 --- a/app/models/flash-card.js +++ b/app/models/flash-card.js @@ -1,9 +1,10 @@ import DS from 'ember-data'; export default DS.Model.extend({ - pinyin: DS.attr('string'), - chinese: DS.attr('string'), - english: DS.attr('string'), + pinyin: DS.belongsTo('translation', {inverse: null}), + chinese: DS.belongsTo('translation', {inverse: null}), + english: DS.belongsTo('translation', {inverse: null}), + audioUrl: DS.attr('string'), ts: DS.attr('number'), position: DS.attr('number', {defaultValue: 1}), diff --git a/app/models/translation.js b/app/models/translation.js new file mode 100644 index 0000000..6729906 --- /dev/null +++ b/app/models/translation.js @@ -0,0 +1,7 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + text: DS.attr('string'), + lang: DS.attr('string'), + flashCard: DS.belongsTo('flash-card', {inverse: null}) +}); diff --git a/app/routes/lesson.js b/app/routes/lesson.js index 6aff8b2..df32d4c 100644 --- a/app/routes/lesson.js +++ b/app/routes/lesson.js @@ -1,8 +1,6 @@ import Ember from 'ember'; import firebase from 'firebase'; import { v4 as uuid } from 'uuid'; -import moment from 'moment'; -import _ from 'lodash'; export default Ember.Route.extend({ setupController(controller, model) { @@ -21,14 +19,27 @@ export default Ember.Route.extend({ const record = await this.store.findRecord('lesson', params.id) .catch(() => { - const lesson = this.store.createRecord('lesson', {id:params.id, date:new Date()}), - conversation = this.store.createRecord('conversation', {lesson}), - flashCard = this.store.createRecord('flash-card', {conversation}); + + const chinese = this.store.createRecord('translation', { flashCard, lang: 'chinese' }); + const pinyin = this.store.createRecord('translation', { flashCard, lang: 'pinyin' }); + const english = this.store.createRecord('translation', { flashCard, lang: 'english' }); + + const lesson = this.store.createRecord('lesson', {id:params.id, date:new Date()}); + const conversation = this.store.createRecord('conversation', {lesson}); + + const flashCard = this.store + .createRecord('flash-card', { + conversation, + chinese, + pinyin, + english + }); return lesson.save() - .then(lesson => conversation.save()) - .then(conversation => flashCard.save()) - .then(flashCard => lesson); + .then(() => conversation.save()) + .then(() => flashCard.save()) + .then(() => Ember.RSVP.all([chinese.save(), pinyin.save(), english.save()])) + .then(() => lesson); }); return { @@ -70,11 +81,21 @@ export default Ember.Route.extend({ const conversation = this.store .createRecord('conversation', { lesson, position: newPosition }); + const chinese = this.store.createRecord('translation', { flashCard, lang: 'chinese' }); + const pinyin = this.store.createRecord('translation', { flashCard, lang: 'pinyin' }); + const english = this.store.createRecord('translation', { flashCard, lang: 'english' }); + const flashCard = this.store - .createRecord('flash-card', { conversation }); + .createRecord('flash-card', { + conversation, + chinese, + pinyin, + english + }); await conversation.save(); await flashCard.save(); + await Ember.RSVP.all([chinese.save(), pinyin.save(), english.save()]); await lesson.save(); }, @@ -97,17 +118,30 @@ export default Ember.Route.extend({ }, saveModel(model) { - model.save(); + if(model.then !== undefined) { + model.then(res => res.save()); + } else { + model.save(); + } }, async destroyFlashCard(conversation, flashCard) { flashCard.deleteRecord(); + const chinese = await flashCard.get('chinese'); + const pinyin = await flashCard.get('pinyin'); + const english = await flashCard.get('english'); + + chinese.deleteRecord(); + pinyin.deleteRecord(); + english.deleteRecord(); + if(conversation.get("isEmpty")) { conversation.deleteRecord(); } await flashCard.save(); + await Ember.RSVP.all([chinese.save(), pinyin.save(), english.save()]); await conversation.save(); }, @@ -144,10 +178,21 @@ export default Ember.Route.extend({ newPosition = 1; } + const chinese = this.store.createRecord('translation', { flashCard, lang: 'chinese' }); + const pinyin = this.store.createRecord('translation', { flashCard, lang: 'pinyin' }); + const english = this.store.createRecord('translation', { flashCard, lang: 'english' }); + const flashCard = this.store - .createRecord('flash-card', { conversation, position: newPosition }); + .createRecord('flash-card', { + conversation, + position: newPosition, + chinese, + pinyin, + english + }); await flashCard.save(); + await Ember.RSVP.all([chinese.save(), pinyin.save(), english.save()]); await conversation.save(); } } diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js index fbf2555..8fea8da 100644 --- a/tests/.eslintrc.js +++ b/tests/.eslintrc.js @@ -1,5 +1,9 @@ module.exports = { env: { embertest: true + }, + globals: { + "RecordRTC": true, + "Twilio": true } }; diff --git a/tests/integration/components/communication/video-chat/component-test.js b/tests/integration/components/communication/video-chat/component-test.js deleted file mode 100644 index cd0028e..0000000 --- a/tests/integration/components/communication/video-chat/component-test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { moduleForComponent, test } from 'ember-qunit'; -import hbs from 'htmlbars-inline-precompile'; - -moduleForComponent('communication/video-chat', 'Integration | Component | communication/video chat', { - integration: true -}); - -test('it renders', function(assert) { - - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.on('myAction', function(val) { ... }); - - this.render(hbs`{{communication/video-chat}}`); - - assert.equal(this.$().text().trim(), ''); - - // Template block usage: - this.render(hbs` - {{#communication/video-chat}} - template block text - {{/communication/video-chat}} - `); - - assert.equal(this.$().text().trim(), 'template block text'); -}); diff --git a/tests/integration/components/conversation-group/component-test.js b/tests/integration/components/conversation-group/component-test.js deleted file mode 100644 index 54fd555..0000000 --- a/tests/integration/components/conversation-group/component-test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { moduleForComponent, test } from 'ember-qunit'; -import hbs from 'htmlbars-inline-precompile'; - -moduleForComponent('conversation-group', 'Integration | Component | conversation group', { - integration: true -}); - -test('it renders', function(assert) { - - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.on('myAction', function(val) { ... }); - - this.render(hbs`{{conversation-group}}`); - - assert.equal(this.$().text().trim(), ''); - - // Template block usage: - this.render(hbs` - {{#conversation-group}} - template block text - {{/conversation-group}} - `); - - assert.equal(this.$().text().trim(), 'template block text'); -}); diff --git a/tests/integration/components/flash-card-group/component-test.js b/tests/integration/components/flash-card-group/component-test.js deleted file mode 100644 index ce1651e..0000000 --- a/tests/integration/components/flash-card-group/component-test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { moduleForComponent, test } from 'ember-qunit'; -import hbs from 'htmlbars-inline-precompile'; - -moduleForComponent('flash-card-group', 'Integration | Component | flash card group', { - integration: true -}); - -test('it renders', function(assert) { - - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.on('myAction', function(val) { ... }); - - this.render(hbs`{{flash-card-group}}`); - - assert.equal(this.$().text().trim(), ''); - - // Template block usage: - this.render(hbs` - {{#flash-card-group}} - template block text - {{/flash-card-group}} - `); - - assert.equal(this.$().text().trim(), 'template block text'); -}); diff --git a/tests/integration/components/flash-card/component-test.js b/tests/integration/components/flash-card/component-test.js deleted file mode 100644 index ba170b3..0000000 --- a/tests/integration/components/flash-card/component-test.js +++ /dev/null @@ -1,11 +0,0 @@ -import { moduleForComponent, test } from 'ember-qunit'; -import hbs from 'htmlbars-inline-precompile'; - -moduleForComponent('flash-card', 'Integration | Component | flash card', { - integration: true -}); - -test('The index shows in reverse', function(assert) { - this.render(hbs`{{flash-card total=10 index=0}}`); - assert.equal(this.$('.index').text().trim(), '10.'); -}); diff --git a/tests/unit/controllers/lesson-test.js b/tests/unit/controllers/lesson-test.js deleted file mode 100644 index 00f3651..0000000 --- a/tests/unit/controllers/lesson-test.js +++ /dev/null @@ -1,12 +0,0 @@ -import { moduleFor, test } from 'ember-qunit'; - -moduleFor('controller:lesson', 'Unit | Controller | lesson', { - // Specify the other units that are required for this test. - // needs: ['controller:foo'] -}); - -// Replace this with your real tests. -test('it exists', function(assert) { - let controller = this.subject(); - assert.ok(controller); -}); diff --git a/tests/unit/models/flash-card-test.js b/tests/unit/models/flash-card-test.js index fa7f6c6..bd8042c 100644 --- a/tests/unit/models/flash-card-test.js +++ b/tests/unit/models/flash-card-test.js @@ -2,7 +2,7 @@ import { moduleForModel, test } from 'ember-qunit'; moduleForModel('flash-card', 'Unit | Model | flash card', { // Specify the other units that are required for this test. - needs: ['model:lesson'] + needs: ['model:conversation', 'model:translation'] }); test('it exists', function(assert) { diff --git a/tests/unit/models/lesson-test.js b/tests/unit/models/lesson-test.js index 03560fa..8b89994 100644 --- a/tests/unit/models/lesson-test.js +++ b/tests/unit/models/lesson-test.js @@ -2,7 +2,7 @@ import { moduleForModel, test } from 'ember-qunit'; moduleForModel('lesson', 'Unit | Model | lesson', { // Specify the other units that are required for this test. - needs: ['model:flash-card'] + needs: ['model:conversation'] }); test('it exists', function(assert) { diff --git a/tests/unit/models/translation-test.js b/tests/unit/models/translation-test.js new file mode 100644 index 0000000..d679895 --- /dev/null +++ b/tests/unit/models/translation-test.js @@ -0,0 +1,12 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('translation', 'Unit | Model | translation', { + // Specify the other units that are required for this test. + needs: ['model:flash-card'] +}); + +test('it exists', function(assert) { + let model = this.subject(); + // let store = this.store(); + assert.ok(!!model); +});