001/* 002 * #%L 003 * GwtMaterial 004 * %% 005 * Copyright (C) 2015 - 2017 GwtMaterialDesign 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package gwt.material.design.client.ui.animate; 021 022import com.google.gwt.user.client.Timer; 023import com.google.gwt.user.client.ui.Widget; 024import gwt.material.design.client.base.HasDelayTransition; 025import gwt.material.design.client.base.HasDurationTransition; 026import gwt.material.design.client.constants.CssName; 027import gwt.material.design.client.js.JsMaterialElement; 028import gwt.material.design.client.ui.html.ListItem; 029import gwt.material.design.client.ui.html.UnorderedList; 030import gwt.material.design.jquery.client.api.Functions; 031 032import static gwt.material.design.client.js.JsMaterialElement.$; 033 034/** 035 * Stateful object holding animation details. 036 * Default behaviour is a bounce transition for 800ms. 037 */ 038public class MaterialAnimation implements HasDurationTransition, HasDelayTransition { 039 040 private Widget widget; 041 private Transition transition = Transition.BOUNCE; 042 private int delay = 0; 043 private int duration = 800; 044 private boolean infinite; 045 046 private Timer startTimer, endTimer; 047 048 public MaterialAnimation() { 049 } 050 051 public MaterialAnimation(Widget widget) { 052 this.widget = widget; 053 } 054 055 public MaterialAnimation transition(Transition transition) { 056 this.transition = transition; 057 return this; 058 } 059 060 public MaterialAnimation delay(int delay) { 061 this.delay = delay; 062 return this; 063 } 064 065 public MaterialAnimation duration(int duration) { 066 this.duration = duration; 067 return this; 068 } 069 070 public MaterialAnimation infinite(boolean infinite) { 071 this.infinite = infinite; 072 return this; 073 } 074 075 public void animate() { 076 animate(widget); 077 } 078 079 public void animate(Widget widget) { 080 animate(widget, null); 081 } 082 083 public void animate(Functions.Func callback) { 084 animate(widget, callback); 085 } 086 087 public void animate(Widget widget, Functions.Func callback) { 088 if(widget != null) { 089 this.widget = widget; 090 } else { 091 throw new NullPointerException("Cannot animate on a null widget."); 092 } 093 094 if(startTimer != null) { 095 // Exit early since we are already animating. 096 return; 097 } 098 099 final JsMaterialElement element = $(widget.getElement()); 100 101 element.css("animation-duration", duration + "ms"); 102 element.css("-webkit-animation-duration", duration + "ms"); 103 104 switch (transition) { 105 case SHOW_STAGGERED_LIST: 106 if (widget instanceof UnorderedList) { 107 UnorderedList ul = (UnorderedList) widget; 108 109 for (Widget li : ul) { 110 if (li instanceof ListItem) { 111 li.getElement().getStyle().setOpacity(0); 112 } 113 } 114 } 115 break; 116 case SHOW_GRID: 117 widget.getElement().getStyle().setOpacity(0); 118 break; 119 default: 120 break; 121 } 122 123 startTimer = new Timer() { 124 @Override 125 public void run() { 126 switch (transition) { 127 case SHOW_STAGGERED_LIST: 128 JsMaterialElement.showStaggeredList(element); 129 break; 130 case FADE_IN_IMAGE: 131 JsMaterialElement.fadeInImage(element); 132 break; 133 case SHOW_GRID: 134 widget.addStyleName(CssName.DISPLAY_ANIMATION); 135 JsMaterialElement.showGrid(element); 136 break; 137 case CLOSE_GRID: 138 widget.addStyleName(CssName.DISPLAY_ANIMATION); 139 JsMaterialElement.closeGrid(element); 140 break; 141 default: 142 // For core animation components 143 if (infinite) { 144 widget.addStyleName(CssName.INFINITE); 145 } 146 widget.addStyleName("animated " + transition.getCssName()); 147 148 // Only start the end timer if its not already active. 149 if(endTimer == null) { 150 endTimer = new Timer() { 151 @Override 152 public void run() { 153 if (callback != null) { 154 callback.call(); 155 } 156 if (!infinite) { 157 $(element).removeClass("animated " + transition.getCssName()); 158 } 159 160 endTimer = null; 161 startTimer = null; 162 } 163 }; 164 endTimer.schedule(duration); 165 } 166 break; 167 } 168 } 169 }; 170 if(delay < 1) { 171 startTimer.run(); 172 } else { 173 startTimer.schedule(delay); 174 } 175 176 widget.removeStyleName(CssName.MATERIALIZE_CSS); 177 } 178 179 /** 180 * Stop an animation. 181 */ 182 public void stopAnimation() { 183 if(widget != null) { 184 widget.removeStyleName("animated"); 185 widget.removeStyleName(transition.getCssName()); 186 widget.removeStyleName(CssName.INFINITE); 187 } 188 } 189 190 public Widget getWidget() { 191 return widget; 192 } 193 194 public Transition getTransition() { 195 return transition; 196 } 197 198 public void setTransition(Transition transition) { 199 this.transition = transition; 200 } 201 202 @Override 203 public void setDelay(int delay) { 204 this.delay = delay; 205 } 206 207 @Override 208 public int getDelay() { 209 return delay; 210 } 211 212 @Override 213 public void setDuration(int duration) { 214 this.duration = duration; 215 } 216 217 @Override 218 public int getDuration() { 219 return duration; 220 } 221 222 public boolean isInfinite() { 223 return infinite; 224 } 225 226 public void setInfinite(boolean infinite) { 227 this.infinite = infinite; 228 stopAnimation(); 229 } 230}