Skip to content

Commit

Permalink
modal popup to download a book via a code
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakeii committed Jul 10, 2016
1 parent 74b3def commit f763fd6
Show file tree
Hide file tree
Showing 12 changed files with 441 additions and 34 deletions.
3 changes: 3 additions & 0 deletions app/pods/application/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export default Ember.Controller.extend({
return this.transitionToRoute('/');
}
history.back();
},
refreshIndex(books) {
this.store.pushPayload('book', books);
}
}
});
5 changes: 5 additions & 0 deletions app/pods/application/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mi
export default Ember.Route.extend(ApplicationRouteMixin, {
session: Ember.inject.service('session'),
nav: Ember.inject.service('nav'),
bookManager: Ember.inject.service(),

beforeModel() {
return this.get('bookManager').updateIndex().then(this._super);
},

actions: {
back() {
Expand Down
2 changes: 1 addition & 1 deletion app/pods/application/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
{{liquid-outlet class="row"}}
</main>

{{bootstrap-modal content=modal}}
{{bootstrap-modal content=modal refreshIndex=(action 'refreshIndex')}}
272 changes: 272 additions & 0 deletions app/pods/book-manager/service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
/* global BackgroundTransfer */
import Ember from 'ember';
import ENV from 'funzo-app/config/environment';

export default Ember.Service.extend(Ember.Evented, {
downloadProgress: 0,
unzipProgress: 0,

status: 'idle',

init() {
if (window.cordova) {
this.set('baseDir', window.cordova.file.externalDataDirectory);
} else {
return;
// window.webkitRequestFileSystem(window.PERMENANT, 10 * 1024 * 1024 , (fs) => { console.log(fs); }, () => {});
}

this.set('contentDir', `${this.get('baseDir')}content`);
this.set('downloadDir', `${this.get('baseDir')}downloads`);

this.set('bookDownloadDir', `${this.get('downloadDir')}/books`);
this.set('bookDir', `${this.get('contentDir')}/books`);

this.set('tmpDir', `${this.get('baseDir')}tmp`);

this.createDirectory(this.get('tmpDir'));

this.createDirectory(this.get('contentDir'))
.then(this.createDirectory(this.get('bookDir'), this.get('contentDir')));

this.createDirectory(this.get('downloadDir'))
.then(this.createDirectory(this.get('bookDownloadDir'), this.get('downloadDir')));
},

reset() {
this.setProperties({
status: 'idle',
downloadProgress: 0,
unzipProgress: 0,
download: null
});
},

addBook(code) {
this.set('status', 'downloading');
return this.downloadBook(code)
.then(() => {
this.set('status', 'unzipping');
return this.unzipBook(code);
})
.then(() => this.updateIndex())
.then(() => {
this.set('status', 'complete');
}, (err) => {
this.set('status', 'error');
this.set('error', err);
});
},

updateIndex() {
return this.resolveFileURL(this.get('bookDir'))
.then((bookDir) => {
return this.readFolderContents(bookDir)
.then((bookFolders) => {
return Ember.RSVP.all(bookFolders.filterBy('isDirectory', true).map((bookFolder) => {
return this.resolveFileURL(`${this.get('bookDir')}/${bookFolder.name}/book.json`)
.then((file) => this.readFileContents(file));
}));
}).then((bookMetas) => {
return Ember.RSVP.resolve(`[${bookMetas.join(',')}]`);
}).then((indexContent) => {
return this.createFile(bookDir, 'index.json')
.then((indexFile) => this.writeFileContents(indexFile, indexContent))
.then((indexContent) => {
let json = JSON.parse(indexContent);
this.trigger('booksUpdated', json);
return Ember.RSVP.resolve(json);
});
});
});
},

/**
* Get the url from a code
*
* @param code {String}
* @return {String} the url
**/

urlForBook(code) {
if (code === 'demo' || code === 'demo-ndl') {
return 'https://www.dropbox.com/s/tbfvbbotoaxp4m5/demo.zip?dl=1';
}
return `${ENV.APP.bookURLBase}${code}`;
},

/**
* Start download of a book
*
* @param code {String}
* @return {Promise}
**/

downloadBook(code) {
let url = this.urlForBook(code);
if (code === 'demo-ndl') {
return Ember.RSVP.resolve();
}
return this.fileTransfer(url, `${this.get('bookDownloadDir')}/${code}.zip`);
},

/**
* Unzip the book
* unzip to a tmp location
* read permalink
* move to books/permalink
**/
unzipBook(code) {
let zipPath = `${this.get('bookDownloadDir')}/${code}.zip`;
let unzipDest = `${this.get('tmpDir')}/${code}`;

return this.createDirectory(code, this.get('tmpDir'))
.then(() => this.unzip(zipPath, unzipDest))
.then(() => this.resolveFileURL(unzipDest + '/book.json'))
.then((file) => this.readFileContents(file))
.then((bookJSON) => {
let bookMeta = JSON.parse(bookJSON);
let permalink = bookMeta.permalink;

return Ember.RSVP.hash({
destFolder: this.resolveFileURL(this.get('bookDir')),
unzipFolder: this.resolveFileURL(unzipDest)
}).then((res) => {
return this.moveFile(res.unzipFolder, res.destFolder, permalink);
});
});
},

createDirectory(folder, dest = '') {
dest = (dest ? `${dest}` : this.get('baseDir'));

return new Ember.RSVP.Promise((resolve, reject) => {
window.resolveLocalFileSystemURL(dest, function(dir) {
dir.getDirectory(folder, { create: true }, function(file) {
if (file) {
return resolve(file);
}
return reject();
});
});
});
},

fileTransfer(uri, destPath) {
return new Ember.RSVP.Promise((res, rej) => {
let fileTransfer = new window.FileTransfer();
uri = encodeURI(uri);

fileTransfer.onprogress = (e) => {
if (e.lengthComputable) {
this.set('downloadProgress', Math.ceil(100 * e.loaded / e.total));
} else {
this.incrementProperty('downloadProgress');
}
};

fileTransfer.download(uri, destPath, res, rej, false);
this.set('download', fileTransfer);

});
// let downloader = new BackgroundTransfer.BackgroundDownloader();
// let onprogress = (e) => {
// this.set('downloadProgress', Math.ceil(100 * e.bytesReceived / e.totalBytesToReceive));
// };

// return this.resolveFileURL(destDir)
// .then(dir => this.createFile(dir, destFileName))
// .then(file => {
// let download = downloader.createDownload(uri, file);
// this.set('download', download);
// return new Ember.RSVP.Promise((res, rej) => {
// download.startAsync().then(res, rej, onprogress);
// });
// });
},

unzip(source, dest) {
return new Ember.RSVP.Promise((resolve, reject) => window.zip.unzip(source, dest, (result) => (result < 0) ? reject() : resolve(), (e) => {
if (e.lengthComputable) {
this.set('zipProgress', Math.ceil(100 * e.loaded / e.total));
} else {
this.incrementProperty('zipProgress');
}
}));
},

resolveFileURL(url) {
return new Ember.RSVP.Promise((res, rej) => {
window.resolveLocalFileSystemURL(url, (file) => res(file), rej);
});
},

createFile(dir, file) {
return new Ember.RSVP.Promise((resolve) => {
dir.getFile(file, { create: true }, resolve);
});
},

getFile(dir, file) {
return new Ember.RSVP.Promise((resolve) => {
dir.getFile(file, resolve);
});
},

moveFile(file, dest, newName) {
return new Ember.RSVP.Promise((res) => {
file.moveTo(dest, newName);
res();
});
},

readFolderContents(dir) {
return new Ember.RSVP.Promise(function(res, rej) {
let reader = dir.createReader();
let entries = [];
let readEntries = function() {
reader.readEntries(function(results) {
if (!results.length) {
res(entries.sort());
} else {
entries = entries.concat(Array.prototype.slice.call(results || [], 0));
readEntries();
}
}, rej);
};
readEntries();
});
},

readFileContents(file) {
return new Ember.RSVP.Promise(function(res, rej) {
file.file((file) => {
let reader = new FileReader();

reader.onload = (e) => {
res(e.target.result);
};

reader.readAsText(file);
}, rej);
});
},

writeFileContents(file, content) {
return new Ember.RSVP.Promise((res, rej) => {
file.createWriter((fileWriter) => {
let blob = new Blob([content], { type: 'text/plain' });

fileWriter.onwriteend = () => {
res(content);
};

file.onerror = (e) => {
rej(e.toString());
};

fileWriter.write(blob);
});
});
}
});
12 changes: 10 additions & 2 deletions app/pods/book/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ import DS from 'ember-data';

export default DS.RESTAdapter.extend({
urlForFindAll() {
return 'content/books/index.json';
let url = 'content/books/index.json';
if (window.cordova) {
url = window.cordova.file.externalDataDirectory + url;
}
return url;
},

urlForFindRecord(permalink) {
return `content/books/${permalink}/book.json`;
let url = `content/books/${permalink}/book.json`;
if (window.cordova) {
url = window.cordova.file.externalDataDirectory + url;
}
return url;
},

urlForFindHasMany(id, modelName, snapshot) {
Expand Down
48 changes: 48 additions & 0 deletions app/pods/components/add-book/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Ember from 'ember';

export default Ember.Component.extend({
bookManager: Ember.inject.service(),

classNames: ['modal-dialog'],
downloadProgress: Ember.computed.alias('bookManager.downloadProgress'),
zipProgress: Ember.computed.alias('bookManager.zipProgress'),
status: Ember.computed.alias('bookManager.status'),

isIdle: Ember.computed.equal('status', 'idle'),
isDownloading: Ember.computed.equal('status', 'downloading'),
isUnzipping: Ember.computed.equal('status', 'unzipping'),
isComplete: Ember.computed.equal('status', 'complete'),
isError: Ember.computed.equal('status', 'error'),

title: 'Add A Book',

code: 'demo',

didInsertElement() {
this.get('bookManager').reset();
},

actions: {
submit() {
if (!window.cordova) {
return alert('only works in app');
}

this.get('bookManager').addBook(this.get('code'))
.then(() => {
Ember.$('.modal').modal('hide');
});
// }, (error) => {
// console.log('download error source ' + error.source);
// console.log('download error target ' + error.target);
// console.log('upload error code' + error.code);
// });
},
cancel() {
if (this.get('bookManager.download') && this.get('isDownloading')) {
this.get('bookManager.download').abort();
}
this.get('bookManager').reset();
}
}
});
Loading

0 comments on commit f763fd6

Please sign in to comment.