Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions app/components/layertimeline/layertimeline.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@
Animated vector drawable(s)
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="ctrl.onExportAVDsAttrs($event)" ng-disabled="!ctrl.animations.length">
Animated vector drawable(s) with Attrs & Colors & Styles
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="ctrl.onExportAttrsXml($event)" ng-disabled="!ctrl.animations.length">
Attrs xml
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="ctrl.onExportColorsXml($event)" ng-disabled="!ctrl.animations.length">
Colors xml
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="ctrl.onExportStylesXml($event)" ng-disabled="!ctrl.animations.length">
Styles xml
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<div flex></div>
Expand Down
34 changes: 33 additions & 1 deletion app/components/layertimeline/layertimeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,39 @@ class LayerTimelineController {
*/
onExportAVDs() {
ga('send', 'event', 'export', 'exportVectorAnimated');
this.studioState_.exportAVDs();
this.studioState_.exportAVDs(false);
}

/**
* Handles export to animated vector drawable format with attrs for colors.
*/
onExportAVDsAttrs() {
ga('send', 'event', 'export', 'exportVectorAnimatedAttrs');
this.studioState_.exportAVDs(true);
}

/**
* Handles export to xml with colors.
*/
onExportColorsXml() {
ga('send', 'event', 'export', 'exportColorsXml');
this.studioState_.exportColorsXml();
}

/**
* Handles export to xml with attrs.
*/
onExportAttrsXml() {
ga('send', 'event', 'export', 'exportAttrsXml');
this.studioState_.exportAttrsXml();
}

/**
* Handles export to xml with attrs.
*/
onExportStylesXml() {
ga('send', 'event', 'export', 'exportAttrsXml');
this.studioState_.exportStylesXml();
}

/**
Expand Down
188 changes: 145 additions & 43 deletions app/pages/studio/studiostate.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,25 @@
* limitations under the License.
*/

import {default as zip} from 'zipjs-browserify';

import {Artwork, Animation, AnimationBlock, BaseLayer} from 'model';
import {AnimationRenderer} from 'AnimationRenderer';
import {AvdSerializer} from 'AvdSerializer';
import {ModelUtil} from 'ModelUtil';
import {
default as zip
} from 'zipjs-browserify';

import {
Artwork,
Animation,
AnimationBlock,
BaseLayer
} from 'model';
import {
AnimationRenderer
} from 'AnimationRenderer';
import {
AvdSerializer
} from 'AvdSerializer';
import {
ModelUtil
} from 'ModelUtil';


const CHANGES_TAG = '$$studioState::CHANGES';
Expand All @@ -32,8 +45,7 @@ const BLANK_ARTWORK = {
id: new Artwork().typeIdPrefix,
width: 24,
height: 24,
layers: [
]
layers: []
};


Expand Down Expand Up @@ -93,7 +105,9 @@ class StudioStateService {

set playing(playing) {
this.playing_ = playing;
this.broadcastChanges_({playing: true});
this.broadcastChanges_({
playing: true
});
}

get artwork() {
Expand All @@ -106,7 +120,9 @@ class StudioStateService {

set artwork(artwork) {
this.artwork_ = artwork;
this.artworkChanged({noUndo:true});
this.artworkChanged({
noUndo: true
});
}

get animations() {
Expand All @@ -128,18 +144,26 @@ class StudioStateService {
animChanged(options = {}) {
this.dirty_ = true;
this.rebuildRenderer_();
this.broadcastChanges_({animations: true});
this.broadcastChanges_({
animations: true
});
if (!options.noUndo) {
this.saveUndoState_({debounce:true});
this.saveUndoState_({
debounce: true
});
}
}

artworkChanged(options = {}) {
this.dirty_ = true;
this.rebuildRenderer_();
this.broadcastChanges_({artwork: true});
this.broadcastChanges_({
artwork: true
});
if (!options.noUndo) {
this.saveUndoState_({debounce:true});
this.saveUndoState_({
debounce: true
});
}
}

Expand All @@ -166,7 +190,7 @@ class StudioStateService {
// (commit the current state after N millisec of inactivity)
if (options.debounce) {
this.debouncedSaveUndoPromise_ = this.timeout_(
() => this.commitUndoStateToTopSlot_(), UNDO_DEBOUNCE_MS);
() => this.commitUndoStateToTopSlot_(), UNDO_DEBOUNCE_MS);
} else {
this.commitUndoStateToTopSlot_();
}
Expand All @@ -185,12 +209,16 @@ class StudioStateService {
let state = this.undoStates_[this.currentUndoState_];
this.artwork_ = new Artwork(state.artwork);
this.animations_ = state.animations.map(anim => new Animation(anim));
this.activeAnimation_ = (this.animations_.length > 0 && state.activeAnimationIndex >= 0)
? this.animations_[state.activeAnimationIndex]
: null;
this.activeAnimation_ = (this.animations_.length > 0 && state.activeAnimationIndex >= 0) ?
this.animations_[state.activeAnimationIndex] :
null;
this.selection = [];
this.artworkChanged({noUndo:true});
this.animChanged({noUndo:true});
this.artworkChanged({
noUndo: true
});
this.animChanged({
noUndo: true
});
}

tryUndo() {
Expand Down Expand Up @@ -241,15 +269,17 @@ class StudioStateService {

this.activeAnimation_ = activeAnimation;
this.rebuildRenderer_();
this.broadcastChanges_({activeAnimation: true});
this.broadcastChanges_({
activeAnimation: true
});
}

rebuildRenderer_() {
this.animationRenderer_ = null;
if (this.activeAnimation) {
this.animationRenderer_ = new AnimationRenderer(
this.artwork,
this.activeAnimation);
this.artwork,
this.activeAnimation);
this.animationRenderer_.setAnimationTime(this.activeTime_);
}
}
Expand All @@ -263,12 +293,14 @@ class StudioStateService {
if (this.animationRenderer_) {
this.animationRenderer_.setAnimationTime(activeTime);
}
this.broadcastChanges_({activeTime: true});
this.broadcastChanges_({
activeTime: true
});
}

getSelectionByType_(type) {
return (this.selection_ && this.selection_.length && this.selection_[0] instanceof type)
? this.selection_ : [];
return (this.selection_ && this.selection_.length && this.selection_[0] instanceof type) ?
this.selection_ : [];
}

get selectedLayers() {
Expand Down Expand Up @@ -300,13 +332,15 @@ class StudioStateService {
this.selection_.forEach(item => delete item.selected_);
this.selection_ = selection ? selection.slice() : [];
this.selection_.forEach(item => item.selected_ = true);
this.broadcastChanges_({selection: true});
this.broadcastChanges_({
selection: true
});
}

areItemsMultiselectCompatible_(item1, item2) {
return !!(!item1 || !item2
|| item1.constructor === item2.constructor
|| item1 instanceof BaseLayer && item2 instanceof BaseLayer);
return !!(!item1 || !item2 ||
item1.constructor === item2.constructor ||
item1 instanceof BaseLayer && item2 instanceof BaseLayer);
}

selectItem(item) {
Expand Down Expand Up @@ -351,7 +385,9 @@ class StudioStateService {
}
}

this.broadcastChanges_({selection: true});
this.broadcastChanges_({
selection: true
});
}

deleteLayers(layersToDelete) {
Expand Down Expand Up @@ -423,7 +459,7 @@ class StudioStateService {
}

onChange(fn, $scope) {
let watcher = this.rootScope_.$on(CHANGES_TAG, function() {
let watcher = this.rootScope_.$on(CHANGES_TAG, function () {
// window.setTimeout(() => $scope.$apply(() => fn.apply(this, arguments)), 0);
fn.apply(this, arguments);
});
Expand All @@ -435,7 +471,9 @@ class StudioStateService {
let anchor = $('<a>').hide().appendTo(document.body);
let blob = content;
if (!(content instanceof Blob)) {
blob = new Blob([content], {type: 'octet/stream'});
blob = new Blob([content], {
type: 'octet/stream'
});
}
let url = window.URL.createObjectURL(blob);
anchor.attr({
Expand Down Expand Up @@ -494,33 +532,97 @@ class StudioStateService {
this.downloadFile_(xmlStr, `${this.artwork.id}.xml`);
}

exportAVDs() {
exportAttrsXml() {
let xmlStr = AvdSerializer.colorToAttrsXmlString(this.artwork);
this.downloadFile_(xmlStr, `attrs.xml`);
}

exportColorsXml() {
let xmlStr = AvdSerializer.colorToColorsXmlString(this.artwork);
this.downloadFile_(xmlStr, `colors.xml`);
}

exportStylesXml() {
let xmlStr = AvdSerializer.colorToStylesXmlString(this.artwork);
this.downloadFile_(xmlStr, `styles.xml`);
}

exportAVDs(withColorsAttrs) {
if (this.animations.length) {
let exportedAnimations = this.animations.map(animation => ({
animation,
filename: `avd_${this.artwork.id}_${animation.id}.xml`,
xmlStr: AvdSerializer.artworkAnimationToAvdXmlString(this.artwork, animation)
xmlStr: AvdSerializer.artworkAnimationToAvdXmlString(this.artwork, animation, withColorsAttrs)
}));


if (exportedAnimations.length == 1) {
// download a single XML
this.downloadFile_(exportedAnimations[0].xmlStr, exportedAnimations[0].filename);
if (withColorsAttrs) {
// download a ZIP
zip.createWriter(new zip.BlobWriter(), writer => {
// add next file
writer.add(
exportedAnimations[0].filename,
new zip.TextReader(exportedAnimations[0].xmlStr),
() => {
writer.add(
'attrs.xml',
new zip.TextReader(AvdSerializer.colorToAttrsXmlString(this.artwork)),
() => {
writer.add(
'colors.xml',
new zip.TextReader(AvdSerializer.colorToColorsXmlString(this.artwork)),
() => {
writer.add(
'styles.xml',
new zip.TextReader(AvdSerializer.colorToStylesXmlString(this.artwork)),
() => {
writer.close(blob => this.downloadFile_(blob, `avd_${this.artwork.id}.zip`));
});
});
});
});
}, error => console.error(error));
} else {
// download a single XML
this.downloadFile_(exportedAnimations[0].xmlStr, exportedAnimations[0].filename);
}
} else {
// download a ZIP
zip.createWriter(new zip.BlobWriter(), writer => {
let i = -1;
let next_ = () => {
++i;
if (i >= exportedAnimations.length) {
// close
writer.close(blob => this.downloadFile_(blob, `avd_${this.artwork.id}.zip`));
if (withColorsAttrs) {
writer.add(
'attrs.xml',
new zip.TextReader(AvdSerializer.colorToAttrsXmlString(this.artwork)),
() => {
writer.add(
'colors.xml',
new zip.TextReader(AvdSerializer.colorToColorsXmlString(this.artwork)),
() => {
writer.add(
'styles.xml',
new zip.TextReader(AvdSerializer.colorToStylesXmlString(this.artwork)),
() => {
// close
writer.close(blob => this.downloadFile_(blob, `avd_${this.artwork.id}.zip`));
});
});
});
} else {
// close
writer.close(blob => this.downloadFile_(blob, `avd_${this.artwork.id}.zip`));
}
} else {
// add next file
let exportedAnimation = exportedAnimations[i];
writer.add(
exportedAnimation.filename,
new zip.TextReader(exportedAnimation.xmlStr),
next_);
exportedAnimation.filename,
new zip.TextReader(exportedAnimation.xmlStr),
next_);
}
};
next_();
Expand All @@ -531,4 +633,4 @@ class StudioStateService {
}


angular.module('AVDStudio').service('StudioStateService', StudioStateService);
angular.module('AVDStudio').service('StudioStateService', StudioStateService);
Loading