@rafaelaugusto/jolt 0.1.0-beta.1 → 0.1.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/README.md +367 -18
  2. package/dist/animate.d.ts +19 -3
  3. package/dist/animate.d.ts.map +1 -1
  4. package/dist/animate.js +186 -14
  5. package/dist/animate.js.map +1 -1
  6. package/dist/color.d.ts +11 -0
  7. package/dist/color.d.ts.map +1 -0
  8. package/dist/color.js +73 -0
  9. package/dist/color.js.map +1 -0
  10. package/dist/config.d.ts +31 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +73 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/decay.d.ts +11 -0
  15. package/dist/decay.d.ts.map +1 -0
  16. package/dist/decay.js +22 -0
  17. package/dist/decay.js.map +1 -0
  18. package/dist/decoration.d.ts +18 -0
  19. package/dist/decoration.d.ts.map +1 -0
  20. package/dist/decoration.js +155 -0
  21. package/dist/decoration.js.map +1 -0
  22. package/dist/drag-input.d.ts +15 -0
  23. package/dist/drag-input.d.ts.map +1 -0
  24. package/dist/drag-input.js +66 -0
  25. package/dist/drag-input.js.map +1 -0
  26. package/dist/drag-physics.d.ts +20 -0
  27. package/dist/drag-physics.d.ts.map +1 -0
  28. package/dist/drag-physics.js +75 -0
  29. package/dist/drag-physics.js.map +1 -0
  30. package/dist/drag.d.ts +58 -0
  31. package/dist/drag.d.ts.map +1 -0
  32. package/dist/drag.js +324 -0
  33. package/dist/drag.js.map +1 -0
  34. package/dist/driver/android-color.d.ts +20 -0
  35. package/dist/driver/android-color.d.ts.map +1 -0
  36. package/dist/driver/android-color.js +136 -0
  37. package/dist/driver/android-color.js.map +1 -0
  38. package/dist/driver/android-decoration.d.ts +22 -0
  39. package/dist/driver/android-decoration.d.ts.map +1 -0
  40. package/dist/driver/android-decoration.js +139 -0
  41. package/dist/driver/android-decoration.js.map +1 -0
  42. package/dist/driver/android-playback.d.ts +13 -0
  43. package/dist/driver/android-playback.d.ts.map +1 -0
  44. package/dist/driver/android-playback.js +141 -0
  45. package/dist/driver/android-playback.js.map +1 -0
  46. package/dist/driver/android.d.ts +1 -1
  47. package/dist/driver/android.d.ts.map +1 -1
  48. package/dist/driver/android.js +165 -13
  49. package/dist/driver/android.js.map +1 -1
  50. package/dist/driver/index.d.ts +25 -2
  51. package/dist/driver/index.d.ts.map +1 -1
  52. package/dist/driver/index.js.map +1 -1
  53. package/dist/driver/ios-color.d.ts +16 -0
  54. package/dist/driver/ios-color.d.ts.map +1 -0
  55. package/dist/driver/ios-color.js +392 -0
  56. package/dist/driver/ios-color.js.map +1 -0
  57. package/dist/driver/ios-decoration.d.ts +17 -0
  58. package/dist/driver/ios-decoration.d.ts.map +1 -0
  59. package/dist/driver/ios-decoration.js +271 -0
  60. package/dist/driver/ios-decoration.js.map +1 -0
  61. package/dist/driver/ios-layout.d.ts +9 -0
  62. package/dist/driver/ios-layout.d.ts.map +1 -0
  63. package/dist/driver/ios-layout.js +52 -0
  64. package/dist/driver/ios-layout.js.map +1 -0
  65. package/dist/driver/ios-playback.d.ts +10 -0
  66. package/dist/driver/ios-playback.d.ts.map +1 -0
  67. package/dist/driver/ios-playback.js +47 -0
  68. package/dist/driver/ios-playback.js.map +1 -0
  69. package/dist/driver/ios-shadow.d.ts +6 -0
  70. package/dist/driver/ios-shadow.d.ts.map +1 -0
  71. package/dist/driver/ios-shadow.js +52 -0
  72. package/dist/driver/ios-shadow.js.map +1 -0
  73. package/dist/driver/ios.d.ts.map +1 -1
  74. package/dist/driver/ios.js +163 -28
  75. package/dist/driver/ios.js.map +1 -1
  76. package/dist/engine.d.ts +75 -5
  77. package/dist/engine.d.ts.map +1 -1
  78. package/dist/engine.js +293 -23
  79. package/dist/engine.js.map +1 -1
  80. package/dist/haptics.d.ts +21 -0
  81. package/dist/haptics.d.ts.map +1 -0
  82. package/dist/haptics.js +120 -0
  83. package/dist/haptics.js.map +1 -0
  84. package/dist/image-effect-native.d.ts +26 -0
  85. package/dist/image-effect-native.d.ts.map +1 -0
  86. package/dist/image-effect-native.js +73 -0
  87. package/dist/image-effect-native.js.map +1 -0
  88. package/dist/image-effect.d.ts +50 -0
  89. package/dist/image-effect.d.ts.map +1 -0
  90. package/dist/image-effect.js +290 -0
  91. package/dist/image-effect.js.map +1 -0
  92. package/dist/image-owner.d.ts +3 -0
  93. package/dist/image-owner.d.ts.map +1 -0
  94. package/dist/image-owner.js +11 -0
  95. package/dist/image-owner.js.map +1 -0
  96. package/dist/index.d.ts +43 -2
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +20 -1
  99. package/dist/index.js.map +1 -1
  100. package/dist/interaction-surface.d.ts +12 -0
  101. package/dist/interaction-surface.d.ts.map +1 -0
  102. package/dist/interaction-surface.js +36 -0
  103. package/dist/interaction-surface.js.map +1 -0
  104. package/dist/items.d.ts +20 -0
  105. package/dist/items.d.ts.map +1 -0
  106. package/dist/items.js +109 -0
  107. package/dist/items.js.map +1 -0
  108. package/dist/keyboard.d.ts +41 -0
  109. package/dist/keyboard.d.ts.map +1 -0
  110. package/dist/keyboard.js +256 -0
  111. package/dist/keyboard.js.map +1 -0
  112. package/dist/label.d.ts +7 -0
  113. package/dist/label.d.ts.map +1 -0
  114. package/dist/label.js +60 -0
  115. package/dist/label.js.map +1 -0
  116. package/dist/layout.d.ts +13 -0
  117. package/dist/layout.d.ts.map +1 -0
  118. package/dist/layout.js +348 -0
  119. package/dist/layout.js.map +1 -0
  120. package/dist/liquid-grid.d.ts +3 -0
  121. package/dist/liquid-grid.d.ts.map +1 -0
  122. package/dist/liquid-grid.js +24 -0
  123. package/dist/liquid-grid.js.map +1 -0
  124. package/dist/liquid.d.ts +18 -0
  125. package/dist/liquid.d.ts.map +1 -0
  126. package/dist/liquid.js +234 -0
  127. package/dist/liquid.js.map +1 -0
  128. package/dist/loader.d.ts +19 -0
  129. package/dist/loader.d.ts.map +1 -0
  130. package/dist/loader.js +173 -0
  131. package/dist/loader.js.map +1 -0
  132. package/dist/motion-scope.d.ts +39 -0
  133. package/dist/motion-scope.d.ts.map +1 -0
  134. package/dist/motion-scope.js +238 -0
  135. package/dist/motion-scope.js.map +1 -0
  136. package/dist/motion-states.d.ts +36 -0
  137. package/dist/motion-states.d.ts.map +1 -0
  138. package/dist/motion-states.js +165 -0
  139. package/dist/motion-states.js.map +1 -0
  140. package/dist/particles.d.ts +39 -0
  141. package/dist/particles.d.ts.map +1 -0
  142. package/dist/particles.js +265 -0
  143. package/dist/particles.js.map +1 -0
  144. package/dist/path.d.ts +12 -0
  145. package/dist/path.d.ts.map +1 -0
  146. package/dist/path.js +90 -0
  147. package/dist/path.js.map +1 -0
  148. package/dist/playback-group.d.ts +6 -0
  149. package/dist/playback-group.d.ts.map +1 -0
  150. package/dist/playback-group.js +141 -0
  151. package/dist/playback-group.js.map +1 -0
  152. package/dist/playback.d.ts +25 -0
  153. package/dist/playback.d.ts.map +1 -0
  154. package/dist/playback.js +35 -0
  155. package/dist/playback.js.map +1 -0
  156. package/dist/press.d.ts.map +1 -1
  157. package/dist/press.js +23 -7
  158. package/dist/press.js.map +1 -1
  159. package/dist/properties.d.ts +6 -3
  160. package/dist/properties.d.ts.map +1 -1
  161. package/dist/properties.js +26 -2
  162. package/dist/properties.js.map +1 -1
  163. package/dist/reveal.d.ts +25 -0
  164. package/dist/reveal.d.ts.map +1 -0
  165. package/dist/reveal.js +294 -0
  166. package/dist/reveal.js.map +1 -0
  167. package/dist/roll-diff.d.ts +22 -0
  168. package/dist/roll-diff.d.ts.map +1 -0
  169. package/dist/roll-diff.js +36 -0
  170. package/dist/roll-diff.js.map +1 -0
  171. package/dist/roll.d.ts +29 -0
  172. package/dist/roll.d.ts.map +1 -0
  173. package/dist/roll.js +442 -0
  174. package/dist/roll.js.map +1 -0
  175. package/dist/scroll-linked.d.ts +10 -0
  176. package/dist/scroll-linked.d.ts.map +1 -0
  177. package/dist/scroll-linked.js +58 -0
  178. package/dist/scroll-linked.js.map +1 -0
  179. package/dist/sequence.d.ts +10 -5
  180. package/dist/sequence.d.ts.map +1 -1
  181. package/dist/sequence.js +208 -14
  182. package/dist/sequence.js.map +1 -1
  183. package/dist/shimmer.d.ts +12 -0
  184. package/dist/shimmer.d.ts.map +1 -0
  185. package/dist/shimmer.js +161 -0
  186. package/dist/shimmer.js.map +1 -0
  187. package/dist/svg-path.d.ts +14 -0
  188. package/dist/svg-path.d.ts.map +1 -0
  189. package/dist/svg-path.js +281 -0
  190. package/dist/svg-path.js.map +1 -0
  191. package/dist/symbol-effect.d.ts +23 -0
  192. package/dist/symbol-effect.d.ts.map +1 -0
  193. package/dist/symbol-effect.js +187 -0
  194. package/dist/symbol-effect.js.map +1 -0
  195. package/dist/text-layout.d.ts +30 -0
  196. package/dist/text-layout.d.ts.map +1 -0
  197. package/dist/text-layout.js +185 -0
  198. package/dist/text-layout.js.map +1 -0
  199. package/dist/text.d.ts +17 -0
  200. package/dist/text.d.ts.map +1 -0
  201. package/dist/text.js +263 -0
  202. package/dist/text.js.map +1 -0
  203. package/dist/track.d.ts +3 -1
  204. package/dist/track.d.ts.map +1 -1
  205. package/dist/track.js +266 -13
  206. package/dist/track.js.map +1 -1
  207. package/dist/transition.d.ts +17 -1
  208. package/dist/transition.d.ts.map +1 -1
  209. package/dist/transition.js +41 -6
  210. package/dist/transition.js.map +1 -1
  211. package/dist/types.d.ts +48 -1
  212. package/dist/types.d.ts.map +1 -1
  213. package/dist/vue/index.d.ts +95 -0
  214. package/dist/vue/index.d.ts.map +1 -0
  215. package/dist/vue/index.js +163 -0
  216. package/dist/vue/index.js.map +1 -0
  217. package/dist/zoom-native.d.ts +30 -0
  218. package/dist/zoom-native.d.ts.map +1 -0
  219. package/dist/zoom-native.js +56 -0
  220. package/dist/zoom-native.js.map +1 -0
  221. package/dist/zoomable.d.ts +48 -0
  222. package/dist/zoomable.d.ts.map +1 -0
  223. package/dist/zoomable.js +249 -0
  224. package/dist/zoomable.js.map +1 -0
  225. package/package.json +29 -5
  226. package/platforms/android/include.gradle +7 -0
  227. package/platforms/android/java/org/rafaelaugusto/jolt/ColorTarget.java +102 -0
  228. package/platforms/android/java/org/rafaelaugusto/jolt/DecorationTarget.java +154 -0
  229. package/platforms/android/java/org/rafaelaugusto/jolt/ImageEffect.java +288 -0
  230. package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardFollower.java +91 -0
  231. package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardObserver.java +97 -0
  232. package/platforms/android/java/org/rafaelaugusto/jolt/NumberRoll.java +190 -0
  233. package/platforms/android/java/org/rafaelaugusto/jolt/PhotoZoom.java +250 -0
  234. package/platforms/android/java/org/rafaelaugusto/jolt/TextReveal.java +180 -0
  235. package/platforms/android/proguard-rules.pro +19 -0
  236. package/platforms/ios/build.xcconfig +1 -0
  237. package/platforms/ios/src/JoltImageEffect.h +25 -0
  238. package/platforms/ios/src/JoltImageEffect.mm +242 -0
  239. package/platforms/ios/src/JoltInteractiveAnimation.h +18 -0
  240. package/platforms/ios/src/JoltInteractiveAnimation.m +123 -0
  241. package/platforms/ios/src/JoltPhotoZoom.h +23 -0
  242. package/platforms/ios/src/JoltPhotoZoom.m +229 -0
  243. package/platforms/ios/src/module.modulemap +6 -0
  244. package/src/android-plugin.d.ts +155 -0
  245. package/src/animate.ts +249 -36
  246. package/src/color.ts +101 -0
  247. package/src/config.ts +84 -0
  248. package/src/decay.ts +45 -0
  249. package/src/decoration.ts +180 -0
  250. package/src/drag-input.ts +74 -0
  251. package/src/drag-physics.ts +110 -0
  252. package/src/drag.ts +395 -0
  253. package/src/driver/android-color.ts +170 -0
  254. package/src/driver/android-decoration.ts +182 -0
  255. package/src/driver/android-playback.ts +157 -0
  256. package/src/driver/android.ts +208 -20
  257. package/src/driver/index.ts +37 -2
  258. package/src/driver/ios-color.ts +441 -0
  259. package/src/driver/ios-decoration.ts +332 -0
  260. package/src/driver/ios-layout.ts +63 -0
  261. package/src/driver/ios-playback.ts +51 -0
  262. package/src/driver/ios-shadow.ts +50 -0
  263. package/src/driver/ios.ts +193 -33
  264. package/src/engine.ts +321 -27
  265. package/src/haptics.ts +148 -0
  266. package/src/image-effect-native.ts +129 -0
  267. package/src/image-effect.ts +336 -0
  268. package/src/image-owner.ts +12 -0
  269. package/src/index.ts +59 -2
  270. package/src/interaction-surface.ts +41 -0
  271. package/src/ios-plugin.d.ts +81 -0
  272. package/src/items.ts +140 -0
  273. package/src/keyboard.ts +291 -0
  274. package/src/label.ts +76 -0
  275. package/src/layout.ts +408 -0
  276. package/src/liquid-grid.ts +28 -0
  277. package/src/liquid.ts +287 -0
  278. package/src/loader.ts +202 -0
  279. package/src/motion-scope.ts +279 -0
  280. package/src/motion-states.ts +215 -0
  281. package/src/particles.ts +323 -0
  282. package/src/path.ts +124 -0
  283. package/src/playback-group.ts +143 -0
  284. package/src/playback.ts +62 -0
  285. package/src/press.ts +26 -10
  286. package/src/properties.ts +32 -6
  287. package/src/reveal.ts +374 -0
  288. package/src/roll-diff.ts +57 -0
  289. package/src/roll.ts +515 -0
  290. package/src/scroll-linked.ts +73 -0
  291. package/src/sequence.ts +204 -14
  292. package/src/shimmer.ts +180 -0
  293. package/src/svg-path.ts +355 -0
  294. package/src/symbol-effect.ts +226 -0
  295. package/src/text-layout.ts +228 -0
  296. package/src/text.ts +279 -0
  297. package/src/track.ts +347 -12
  298. package/src/transition.ts +63 -6
  299. package/src/types.ts +49 -1
  300. package/src/vue/index.ts +231 -0
  301. package/src/zoom-native.ts +124 -0
  302. package/src/zoomable.ts +330 -0
@@ -0,0 +1,250 @@
1
+ package org.rafaelaugusto.jolt;
2
+
3
+ import android.animation.ValueAnimator;
4
+ import android.graphics.RectF;
5
+ import android.view.*;
6
+ import android.widget.ImageView;
7
+
8
+ /** Focal zoom, bounds, pan and dismissal; no pointer/frame callback crosses to JS. */
9
+ public final class PhotoZoom implements View.OnTouchListener, View.OnLayoutChangeListener {
10
+ public interface Listener {
11
+ void onDismiss(float x,float y,float scale,float velocity,float progress);
12
+ void onSettled(float x,float y,float scale);
13
+ }
14
+ private final ImageView image;
15
+ private final View viewport,backdrop,chrome;
16
+ private final Listener listener;
17
+ private final View.OnTouchListener previousTouch,previousImageTouch;
18
+ private final ScaleGestureDetector pinch;
19
+ private final GestureDetector taps;
20
+ private final float minimum,maximum,doubleTap,density,slop;
21
+ private final float bitmapWidth,bitmapHeight;
22
+ private final boolean dismiss,originalClickable,originalImageClickable,originalClip,originalClipPadding;
23
+ private final float originalScaleX,originalScaleY,originalX,originalY,backdropAlpha,chromeAlpha;
24
+ private final RectF content=new RectF();
25
+ private float anchorX,anchorY,width,height,x,y,scale,progress;
26
+ private float lastX,lastY,downX,downY,lastFocusX,lastFocusY,vx,vy;
27
+ private float rawPanX,rawPanY,pinchFloor;
28
+ private int pointer=-1,mode; // 0 undecided, 1 pan, 2 dismiss, 3 handed to parent
29
+ private boolean disposed,pending,reduced,active=true;
30
+ private VelocityTracker velocity;
31
+ private ValueAnimator animation;
32
+
33
+ public PhotoZoom(ImageView image,View viewport,float bitmapWidth,float bitmapHeight,float minimum,float maximum,float doubleTap,
34
+ boolean dismiss,boolean reduced,View backdrop,View chrome,
35
+ View.OnTouchListener previousTouch,View.OnTouchListener previousImageTouch,Listener listener) {
36
+ this.image=image;this.viewport=viewport;this.minimum=minimum;this.maximum=maximum;
37
+ this.bitmapWidth=bitmapWidth;this.bitmapHeight=bitmapHeight;
38
+ this.doubleTap=doubleTap;this.dismiss=dismiss;this.reduced=reduced;
39
+ this.backdrop=backdrop;this.chrome=chrome;this.previousTouch=previousTouch;this.listener=listener;
40
+ this.previousImageTouch=previousImageTouch;
41
+ density=image.getResources().getDisplayMetrics().density;
42
+ slop=ViewConfiguration.get(image.getContext()).getScaledTouchSlop();
43
+ originalScaleX=image.getScaleX();originalScaleY=image.getScaleY();
44
+ originalX=image.getTranslationX();originalY=image.getTranslationY();
45
+ originalClickable=viewport.isClickable();
46
+ originalImageClickable=image.isClickable();
47
+ originalClip=!(viewport instanceof ViewGroup)||((ViewGroup)viewport).getClipChildren();
48
+ originalClipPadding=!(viewport instanceof ViewGroup)||((ViewGroup)viewport).getClipToPadding();
49
+ backdropAlpha=backdrop==null?1:backdrop.getAlpha();chromeAlpha=chrome==null?1:chrome.getAlpha();
50
+ scale=minimum;
51
+ pinch=new ScaleGestureDetector(image.getContext(),new ScaleGestureDetector.SimpleOnScaleGestureListener(){
52
+ @Override public boolean onScaleBegin(ScaleGestureDetector detector){
53
+ if(pending || disposed) return false;
54
+ cancelAnimation();mode=1;pinchFloor=Math.min(minimum,scale);
55
+ lastFocusX=detector.getFocusX();lastFocusY=detector.getFocusY();
56
+ disallow(true);return true;
57
+ }
58
+ @Override public boolean onScale(ScaleGestureDetector detector){
59
+ float next=clamp(scale*detector.getScaleFactor(),pinchFloor,maximum);
60
+ float fx=detector.getFocusX(),fy=detector.getFocusY();
61
+ x=fx-anchorX-(lastFocusX-anchorX-x)*next/scale;
62
+ y=fy-anchorY-(lastFocusY-anchorY-y)*next/scale;
63
+ scale=next;lastFocusX=fx;lastFocusY=fy;
64
+ progress=clamp((minimum-scale)/(minimum*.15f),0,1);
65
+ rebasePan();
66
+ apply();return true;
67
+ }
68
+ });
69
+ taps=new GestureDetector(image.getContext(),new GestureDetector.SimpleOnGestureListener(){
70
+ @Override public boolean onDown(MotionEvent e){return true;}
71
+ @Override public boolean onDoubleTap(MotionEvent e){
72
+ if(!pending) zoom(scale>minimum+.01f?minimum:Math.min(maximum,doubleTap),e.getX(),e.getY(),true);
73
+ return true;
74
+ }
75
+ @Override public boolean onSingleTapConfirmed(MotionEvent e){viewport.performClick();return true;}
76
+ });
77
+ viewport.setClickable(true);viewport.setOnTouchListener(this);
78
+ image.setClickable(true);image.setOnTouchListener((v,event)->{
79
+ MotionEvent local=MotionEvent.obtain(event);
80
+ local.transform(image.getMatrix());
81
+ local.offsetLocation(image.getLeft()-viewport.getScrollX(),image.getTop()-viewport.getScrollY());
82
+ boolean consumed=onTouch(viewport,local);local.recycle();return consumed;
83
+ });
84
+ if(viewport instanceof ViewGroup){((ViewGroup)viewport).setClipChildren(true);((ViewGroup)viewport).setClipToPadding(true);}
85
+ viewport.addOnLayoutChangeListener(this);image.addOnLayoutChangeListener(this);
86
+ measure();apply();
87
+ }
88
+ public float getX(){return x/density;}
89
+ public float getY(){return y/density;}
90
+ public float getScale(){return scale;}
91
+ public float getDismissProgress(){return progress;}
92
+ public boolean isDismissPending(){return pending;}
93
+ public void setReduced(boolean value){reduced=value;if(value){if(pending)reset(false);else settle(false);}}
94
+ public void setActive(boolean value){active=value;if(!value){cancelAnimation();endTouch();pending=false;settle(false);}}
95
+ public void zoom(float value,float focusX,float focusY,boolean animated){
96
+ if(disposed || pending) return;
97
+ cancelAnimation();
98
+ float next=clamp(value,minimum,maximum);
99
+ float tx=focusX-anchorX-(focusX-anchorX-x)*next/scale;
100
+ float ty=focusY-anchorY-(focusY-anchorY-y)*next/scale;
101
+ float[] bounds=bounds(next);
102
+ spring(clamp(tx,bounds[0],bounds[1]),clamp(ty,bounds[2],bounds[3]),next,0,0,animated,false);
103
+ }
104
+ public void reset(boolean animated){
105
+ if(disposed)return;
106
+ pending=false;mode=0;float[] b=bounds(minimum);
107
+ spring(clamp(0,b[0],b[1]),clamp(0,b[2],b[3]),minimum,0,0,animated,false);
108
+ }
109
+ public void requestDismiss(){
110
+ if(disposed || pending || !dismiss)return;
111
+ // Programmatic close normalizes zoom before emitting one route intent.
112
+ float[] b=bounds(minimum);
113
+ spring(clamp(0,b[0],b[1]),clamp(0,b[2],b[3]),minimum,0,0,true,true);
114
+ }
115
+ public void stop(){
116
+ if(disposed)return;
117
+ disposed=true;cancelAnimation();endTouch();
118
+ viewport.setOnTouchListener(previousTouch);viewport.setClickable(originalClickable);
119
+ image.setOnTouchListener(previousImageTouch);image.setClickable(originalImageClickable);
120
+ if(viewport instanceof ViewGroup){((ViewGroup)viewport).setClipChildren(originalClip);((ViewGroup)viewport).setClipToPadding(originalClipPadding);}
121
+ viewport.removeOnLayoutChangeListener(this);image.removeOnLayoutChangeListener(this);
122
+ image.setScaleX(originalScaleX);image.setScaleY(originalScaleY);
123
+ image.setTranslationX(originalX);image.setTranslationY(originalY);
124
+ if(backdrop!=null)backdrop.setAlpha(backdropAlpha);if(chrome!=null)chrome.setAlpha(chromeAlpha);
125
+ }
126
+ private void measure(){
127
+ width=viewport.getWidth();height=viewport.getHeight();
128
+ float iw=image.getWidth(),ih=image.getHeight();
129
+ float left=image.getPaddingLeft(),top=image.getPaddingTop();
130
+ float cw=iw-left-image.getPaddingRight(),ch=ih-top-image.getPaddingBottom();
131
+ float dw=Math.max(1,bitmapWidth),dh=Math.max(1,bitmapHeight);
132
+ ImageView.ScaleType fit=image.getScaleType();
133
+ float factor=fit==ImageView.ScaleType.CENTER_CROP?Math.max(cw/dw,ch/dh):Math.min(cw/dw,ch/dh);
134
+ if(fit==ImageView.ScaleType.FIT_XY){dw=cw;dh=ch;}
135
+ else if(fit!=ImageView.ScaleType.CENTER && fit!=ImageView.ScaleType.MATRIX){dw*=factor;dh*=factor;}
136
+ anchorX=image.getLeft()+image.getPivotX()+originalX;
137
+ anchorY=image.getTop()+image.getPivotY()+originalY;
138
+ // ImageView clips the raster before its outer transform is applied.
139
+ float ox=left+(fit==ImageView.ScaleType.MATRIX?0:(cw-dw)/2),oy=top+(fit==ImageView.ScaleType.MATRIX?0:(ch-dh)/2);
140
+ content.set((Math.max(left,ox)-image.getPivotX())*originalScaleX,
141
+ (Math.max(top,oy)-image.getPivotY())*originalScaleY,
142
+ (Math.min(left+cw,ox+dw)-image.getPivotX())*originalScaleX,
143
+ (Math.min(top+ch,oy+dh)-image.getPivotY())*originalScaleY);
144
+ }
145
+ private float[] bounds(float s){
146
+ float loX=width-anchorX-content.right*s,hiX=-anchorX-content.left*s;
147
+ float loY=height-anchorY-content.bottom*s,hiY=-anchorY-content.top*s;
148
+ if(loX>hiX)loX=hiX=(loX+hiX)/2;
149
+ if(loY>hiY)loY=hiY=(loY+hiY)/2;
150
+ return new float[]{loX,hiX,loY,hiY};
151
+ }
152
+ private void apply(){
153
+ image.setScaleX(originalScaleX*scale);image.setScaleY(originalScaleY*scale);
154
+ image.setTranslationX(originalX+x);image.setTranslationY(originalY+y);
155
+ if(backdrop!=null)backdrop.setAlpha(backdropAlpha*(1-progress));
156
+ if(chrome!=null)chrome.setAlpha(chromeAlpha*(1-progress));
157
+ }
158
+ private void settle(boolean animated){
159
+ if(disposed)return;
160
+ float s=clamp(scale,minimum,maximum),b[]=bounds(s);
161
+ float tx=clamp(x,b[0],b[1]),ty=clamp(y,b[2],b[3]);
162
+ if(mode==2){s=minimum;b=bounds(s);tx=clamp(0,b[0],b[1]);ty=clamp(0,b[2],b[3]);}
163
+ else {tx=clamp(tx+vx*.12f,b[0],b[1]);ty=clamp(ty+vy*.12f,b[2],b[3]);}
164
+ spring(tx,ty,s,vx,vy,animated,false);
165
+ }
166
+ private void cancelAnimation(){if(animation!=null){animation.cancel();animation=null;}}
167
+ private void spring(float tx,float ty,float targetScale,float velocityX,float velocityY,boolean animated,boolean close){
168
+ cancelAnimation();
169
+ final float sx=x,sy=y,ss=scale,sp=progress;
170
+ if(!animated || reduced){x=tx;y=ty;scale=targetScale;progress=0;apply();if(close)emitDismiss(0);else listener.onSettled(x/density,y/density,scale);return;}
171
+ animation=ValueAnimator.ofFloat(0,1);animation.setDuration(550);
172
+ animation.setInterpolator(new android.view.animation.LinearInterpolator());
173
+ animation.addUpdateListener(a->{
174
+ float fraction=(float)a.getAnimatedValue(),t=fraction*.55f;
175
+ float decay=(float)Math.exp(-16*t);
176
+ x=tx+((sx-tx)+(velocityX+16*(sx-tx))*t)*decay;
177
+ y=ty+((sy-ty)+(velocityY+16*(sy-ty))*t)*decay;
178
+ scale=targetScale+(ss-targetScale)*(1+16*t)*decay;
179
+ progress=sp*(1+16*t)*decay;
180
+ if(fraction>=1){x=tx;y=ty;scale=targetScale;progress=0;}
181
+ apply();
182
+ if(fraction>=1){animation=null;if(close)emitDismiss(0);else listener.onSettled(x/density,y/density,scale);}
183
+ });animation.start();
184
+ }
185
+ private void emitDismiss(float velocityY){
186
+ if(pending || disposed)return;
187
+ pending=true;listener.onDismiss(x/density,y/density,scale,velocityY/density,progress);
188
+ }
189
+ private void disallow(boolean value){if(viewport.getParent()!=null)viewport.getParent().requestDisallowInterceptTouchEvent(value);}
190
+ private void endTouch(){pointer=-1;if(velocity!=null){velocity.recycle();velocity=null;}disallow(false);}
191
+ @Override public boolean onTouch(View view,MotionEvent event){
192
+ if(disposed || !active || pending)return false;
193
+ int action=event.getActionMasked();
194
+ if(action==MotionEvent.ACTION_DOWN){
195
+ cancelAnimation();mode=0;vx=vy=0;
196
+ pointer=event.getPointerId(0);lastX=downX=event.getX();lastY=downY=event.getY();
197
+ rebasePan();
198
+ if(velocity!=null)velocity.recycle();velocity=VelocityTracker.obtain();disallow(true);
199
+ }
200
+ if(velocity!=null)velocity.addMovement(event);
201
+ pinch.onTouchEvent(event);taps.onTouchEvent(event);
202
+ int index=event.findPointerIndex(pointer);
203
+ if(action==MotionEvent.ACTION_MOVE && !pinch.isInProgress() && event.getPointerCount()==1 && index>=0){
204
+ float px=event.getX(index),py=event.getY(index),totalX=px-downX,totalY=py-downY;
205
+ if(mode==0 && Math.hypot(totalX,totalY)>slop){
206
+ if(scale<=minimum+.001f){
207
+ if(dismiss && Math.abs(totalY)>Math.abs(totalX)*1.2f)mode=2;
208
+ else {mode=3;disallow(false);return false;}
209
+ }else mode=1;
210
+ }
211
+ if(mode==1){
212
+ float[] b=bounds(scale);
213
+ rawPanX+=px-lastX;rawPanY+=py-lastY;
214
+ x=rubber(rawPanX,b[0],b[1],width);y=rubber(rawPanY,b[2],b[3],height);
215
+ }else if(mode==2){
216
+ x+= (px-lastX)*.4f;y+=py-lastY;
217
+ progress=clamp(Math.abs(y)/Math.max(height*.5f,1),0,1);
218
+ scale=minimum*(1-progress*.15f);
219
+ }
220
+ lastX=px;lastY=py;apply();
221
+ }
222
+ if(action==MotionEvent.ACTION_POINTER_UP){
223
+ int next=event.getActionIndex()==0?1:0;
224
+ if(next<event.getPointerCount()){pointer=event.getPointerId(next);lastX=downX=event.getX(next);lastY=downY=event.getY(next);rebasePan();}
225
+ }
226
+ if(action==MotionEvent.ACTION_UP || action==MotionEvent.ACTION_CANCEL){
227
+ if(velocity!=null){velocity.computeCurrentVelocity(1000);vx=velocity.getXVelocity(pointer);vy=velocity.getYVelocity(pointer);}
228
+ boolean commit=action==MotionEvent.ACTION_UP && mode==2 && (progress>.35f || (Math.abs(vy)>1000*density && y*vy>0));
229
+ boolean wasAnimation=animation!=null;
230
+ endTouch();
231
+ if(commit)emitDismiss(vy);
232
+ else if(mode!=3 && !wasAnimation)settle(true);
233
+ }
234
+ return mode!=3;
235
+ }
236
+ @Override public void onLayoutChange(View v,int l,int t,int r,int b,int ol,int ot,int or,int ob){
237
+ if(disposed || (l==ol&&t==ot&&r==or&&b==ob))return;
238
+ cancelAnimation();pending=false;measure();vx=vy=0;mode=0;settle(false);
239
+ }
240
+ private static float clamp(float v,float lo,float hi){return Math.max(lo,Math.min(hi,v));}
241
+ private void rebasePan(){float[] b=bounds(scale);rawPanX=unrubber(x,b[0],b[1],width);rawPanY=unrubber(y,b[2],b[3],height);}
242
+ private static float unrubber(float v,float lo,float hi,float dimension){
243
+ float edge=clamp(v,lo,hi),d=v-edge,size=Math.max(1,dimension);
244
+ return edge+d/(.55f*Math.max(.001f,1-Math.abs(d)/size));
245
+ }
246
+ private static float rubber(float value,float lo,float hi,float dimension){
247
+ float edge=clamp(value,lo,hi),d=value-edge;
248
+ return edge+Math.signum(d)*dimension*(1-1/(Math.abs(d)*.55f/Math.max(1,dimension)+1));
249
+ }
250
+ }
@@ -0,0 +1,180 @@
1
+ package org.rafaelaugusto.jolt;
2
+
3
+ import android.animation.Animator;
4
+ import android.animation.AnimatorListenerAdapter;
5
+ import android.animation.ValueAnimator;
6
+ import android.text.SpannableStringBuilder;
7
+ import android.text.Spanned;
8
+ import android.text.TextPaint;
9
+ import android.text.method.TransformationMethod;
10
+ import android.text.style.CharacterStyle;
11
+ import android.text.style.UpdateAppearance;
12
+ import android.view.animation.Interpolator;
13
+ import android.view.animation.LinearInterpolator;
14
+ import android.view.animation.PathInterpolator;
15
+ import android.widget.TextView;
16
+ import java.text.BreakIterator;
17
+ import java.util.ArrayList;
18
+ import java.util.List;
19
+
20
+ /** Fades a TextView's text in piece by piece. Layout, truncation and the real text stay as they are. */
21
+ public final class TextReveal {
22
+ public interface Callback {
23
+ void onEnd(boolean finished);
24
+ }
25
+
26
+ private static final int MAX_PIECES = 256;
27
+ private static final Interpolator EASE_OUT = new PathInterpolator(0f, 0f, 0.58f, 1f);
28
+ private final TextView view;
29
+ private final long duration;
30
+ private final long stagger;
31
+ private final long delay;
32
+ private final float offset;
33
+ private final Callback callback;
34
+ private final CharSequence original;
35
+ private final CharSequence shown;
36
+ private final TransformationMethod method;
37
+ private final Piece[] pieces;
38
+ private ValueAnimator animator;
39
+ private boolean settled;
40
+
41
+ public TextReveal(TextView view, boolean byWord, long duration, long stagger, long delay, float offset, Callback callback) {
42
+ this.view = view;
43
+ this.duration = Math.max(duration, 1);
44
+ this.stagger = stagger;
45
+ this.delay = delay;
46
+ this.offset = offset;
47
+ this.callback = callback;
48
+ CharSequence text = view.getText();
49
+ this.original = text == null ? "" : text;
50
+ // NativeScript's transformation method rebuilds the displayed text from its own model,
51
+ // so pieces are measured on what is drawn and the spans go on that text.
52
+ this.method = view.getTransformationMethod();
53
+ CharSequence displayed = method != null ? method.getTransformation(original, view) : original;
54
+ this.shown = displayed == null ? "" : displayed;
55
+ this.pieces = split(shown.toString(), byWord);
56
+ }
57
+
58
+ public boolean isSupported() {
59
+ return pieces.length <= MAX_PIECES;
60
+ }
61
+
62
+ public void start() {
63
+ if (settled || animator != null) return;
64
+ if (pieces.length == 0) {
65
+ settle(true);
66
+ return;
67
+ }
68
+ SpannableStringBuilder spannable = new SpannableStringBuilder(shown);
69
+ for (Piece piece : pieces) {
70
+ piece.alpha = 0f;
71
+ piece.shift = offset;
72
+ spannable.setSpan(piece, piece.start, piece.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
73
+ }
74
+ if (method != null) view.setTransformationMethod(null);
75
+ view.setText(spannable);
76
+ final long total = delay + duration + (pieces.length - 1) * stagger;
77
+ animator = ValueAnimator.ofFloat(0f, 1f);
78
+ animator.setDuration(total);
79
+ animator.setInterpolator(new LinearInterpolator());
80
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
81
+ @Override
82
+ public void onAnimationUpdate(ValueAnimator animation) {
83
+ update(animation.getAnimatedFraction() * total);
84
+ view.invalidate();
85
+ }
86
+ });
87
+ animator.addListener(new AnimatorListenerAdapter() {
88
+ @Override
89
+ public void onAnimationEnd(Animator animation) {
90
+ settle(true);
91
+ }
92
+ });
93
+ animator.start();
94
+ }
95
+
96
+ public void cancel() {
97
+ settle(false);
98
+ }
99
+
100
+ private void update(float time) {
101
+ for (int i = 0; i < pieces.length; i++) {
102
+ float local = (time - delay - i * stagger) / duration;
103
+ float eased = local <= 0f ? 0f : local >= 1f ? 1f : EASE_OUT.getInterpolation(local);
104
+ pieces[i].alpha = eased;
105
+ pieces[i].shift = offset * (1f - eased);
106
+ }
107
+ }
108
+
109
+ private void settle(boolean finished) {
110
+ if (settled) return;
111
+ settled = true;
112
+ ValueAnimator running = animator;
113
+ animator = null;
114
+ if (running != null) running.cancel();
115
+ CharSequence current = view.getText();
116
+ // An app change already replaced the spans; its text wins.
117
+ if (current instanceof Spanned && ((Spanned) current).getSpans(0, current.length(), Piece.class).length > 0) {
118
+ view.setText(original);
119
+ }
120
+ if (method != null && view.getTransformationMethod() == null) view.setTransformationMethod(method);
121
+ callback.onEnd(finished);
122
+ }
123
+
124
+ private static Piece[] split(String text, boolean byWord) {
125
+ List<Piece> pieces = new ArrayList<>();
126
+ BreakIterator iterator = byWord ? BreakIterator.getWordInstance() : BreakIterator.getCharacterInstance();
127
+ iterator.setText(text);
128
+ int start = iterator.first();
129
+ for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) {
130
+ if (byWord ? isWord(text, start, end) : !isBlank(text, start, end)) pieces.add(new Piece(start, end));
131
+ }
132
+ if (byWord) {
133
+ // Spaces and punctuation stay with the word before them, so every visible mark is revealed.
134
+ for (int i = 0; i < pieces.size(); i++) {
135
+ Piece piece = pieces.get(i);
136
+ if (i == 0) piece.start = 0;
137
+ piece.end = i + 1 < pieces.size() ? pieces.get(i + 1).start : text.length();
138
+ }
139
+ if (pieces.isEmpty() && !isBlank(text, 0, text.length())) pieces.add(new Piece(0, text.length()));
140
+ }
141
+ return pieces.toArray(new Piece[0]);
142
+ }
143
+
144
+ private static boolean isWord(String text, int start, int end) {
145
+ for (int i = start; i < end; ) {
146
+ int point = text.codePointAt(i);
147
+ if (Character.isLetterOrDigit(point)) return true;
148
+ i += Character.charCount(point);
149
+ }
150
+ return false;
151
+ }
152
+
153
+ private static boolean isBlank(String text, int start, int end) {
154
+ for (int i = start; i < end; ) {
155
+ int point = text.codePointAt(i);
156
+ if (!Character.isWhitespace(point) && !Character.isSpaceChar(point)) return false;
157
+ i += Character.charCount(point);
158
+ }
159
+ return true;
160
+ }
161
+
162
+ /** Only changes how its range is drawn, so the TextView's layout never sees it. */
163
+ private static final class Piece extends CharacterStyle implements UpdateAppearance {
164
+ int start;
165
+ int end;
166
+ float alpha;
167
+ float shift;
168
+
169
+ Piece(int start, int end) {
170
+ this.start = start;
171
+ this.end = end;
172
+ }
173
+
174
+ @Override
175
+ public void updateDrawState(TextPaint paint) {
176
+ paint.setAlpha(Math.round(paint.getAlpha() * alpha));
177
+ paint.baselineShift += Math.round(shift);
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,19 @@
1
+ -keep class org.rafaelaugusto.jolt.ColorTarget { *; }
2
+ -keep class org.nativescript.widgets.BorderDrawable { *; }
3
+ -keepnames class org.nativescript.widgets.BoxShadowDrawable
4
+ -keepclassmembers class org.nativescript.widgets.BoxShadowDrawable {
5
+ public android.graphics.drawable.Drawable getWrappedDrawable();
6
+ }
7
+ -keep class org.rafaelaugusto.jolt.DecorationTarget { *; }
8
+ -keep class org.rafaelaugusto.jolt.KeyboardFollower { *; }
9
+ -keep class org.rafaelaugusto.jolt.KeyboardFollower$* { *; }
10
+ -keep class org.rafaelaugusto.jolt.KeyboardObserver { *; }
11
+ -keep class org.rafaelaugusto.jolt.KeyboardObserver$* { *; }
12
+ -keep class org.rafaelaugusto.jolt.TextReveal { *; }
13
+ -keep class org.rafaelaugusto.jolt.TextReveal$* { *; }
14
+ -keep class org.rafaelaugusto.jolt.NumberRoll { *; }
15
+ -keep class org.rafaelaugusto.jolt.NumberRoll$* { *; }
16
+ -keep class org.rafaelaugusto.jolt.ImageEffect { *; }
17
+ -keep class org.rafaelaugusto.jolt.ImageEffect$* { *; }
18
+ -keep class org.rafaelaugusto.jolt.PhotoZoom { *; }
19
+ -keep class org.rafaelaugusto.jolt.PhotoZoom$* { *; }
@@ -0,0 +1 @@
1
+ OTHER_LDFLAGS = $(inherited) -framework Metal -framework MetalKit
@@ -0,0 +1,25 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+ @interface JoltImageEffect : NSObject
5
+ + (nullable instancetype)createWithView:(UIImageView *)view
6
+ destination:(nullable UIImage *)destination
7
+ mode:(NSInteger)mode
8
+ originX:(double)x originY:(double)y
9
+ amplitude:(double)amplitude radius:(double)radius
10
+ duration:(double)duration seed:(double)seed
11
+ listener:(void (^)(BOOL, double))listener;
12
+ @property(nonatomic, readonly) double progress;
13
+ @property(nonatomic, readonly) BOOL paused;
14
+ @property(nonatomic, readonly) NSUInteger frames;
15
+ @property(nonatomic, readonly) double longestFrame;
16
+ @property(nonatomic, readonly) NSUInteger textureBytes;
17
+ - (void)play:(double)endpoint;
18
+ - (void)pause;
19
+ - (void)resume;
20
+ - (void)seek:(double)progress;
21
+ - (void)finish:(double)endpoint;
22
+ - (void)stop;
23
+ - (void)stopPreservingImage;
24
+ @end
25
+ NS_ASSUME_NONNULL_END