zkit-ui 2.0.3 → 2.0.5

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 (63) hide show
  1. package/README.md +56 -0
  2. package/android/build.gradle +100 -0
  3. package/android/src/main/AndroidManifest.xml +1 -0
  4. package/android/src/main/java/cn/fontree/zkit/ui/preview/GaleriaModule.kt +43 -0
  5. package/android/src/main/java/cn/fontree/zkit/ui/preview/GaleriaView.kt +305 -0
  6. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryLayoutSupport.java +450 -0
  7. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryMediaItem.java +36 -0
  8. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryPagerAdapter.java +140 -0
  9. package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySharedElementGeometry.java +25 -0
  10. package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySharedElementNames.java +39 -0
  11. package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySharedElementState.java +25 -0
  12. package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySourceViewRegistry.java +115 -0
  13. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryTransitionSnapshotView.java +60 -0
  14. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryVideoPlayerView.java +338 -0
  15. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryViewerOverlayView.java +636 -0
  16. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryViewerPageView.java +357 -0
  17. package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryViewerTransitionController.java +223 -0
  18. package/android/src/main/res/layout/galeria_player_view.xml +9 -0
  19. package/dist/all.d.ts +2 -0
  20. package/dist/all.d.ts.map +1 -1
  21. package/dist/all.js +24 -22
  22. package/dist/ui/NativeImagePreview/NativeImagePreview.d.ts +3 -0
  23. package/dist/ui/NativeImagePreview/NativeImagePreview.d.ts.map +1 -0
  24. package/dist/ui/NativeImagePreview/NativeImagePreview.js +99 -0
  25. package/dist/ui/NativeImagePreview/NativeImagePreview.web.d.ts +3 -0
  26. package/dist/ui/NativeImagePreview/NativeImagePreview.web.d.ts.map +1 -0
  27. package/dist/ui/NativeImagePreview/NativeImagePreview.web.js +56 -0
  28. package/dist/ui/NativeImagePreview/context.d.ts +14 -0
  29. package/dist/ui/NativeImagePreview/context.d.ts.map +1 -0
  30. package/dist/ui/NativeImagePreview/context.js +38 -0
  31. package/dist/ui/NativeImagePreview/index.d.ts +3 -0
  32. package/dist/ui/NativeImagePreview/index.d.ts.map +1 -0
  33. package/dist/ui/NativeImagePreview/index.js +5 -0
  34. package/dist/ui/NativeImagePreview/types.d.ts +66 -0
  35. package/dist/ui/NativeImagePreview/types.d.ts.map +1 -0
  36. package/dist/ui/NativeImagePreview/types.js +2 -0
  37. package/dist/ui/NativeImagePreview/utils.d.ts +8 -0
  38. package/dist/ui/NativeImagePreview/utils.d.ts.map +1 -0
  39. package/dist/ui/NativeImagePreview/utils.js +82 -0
  40. package/expo-module.config.json +11 -0
  41. package/ios/GaleriaModule.swift +46 -0
  42. package/ios/GaleriaView.swift +253 -0
  43. package/ios/GalleryViewer/GaleriaImageLoader.swift +73 -0
  44. package/ios/GalleryViewer/GaleriaImageViewInteraction.swift +245 -0
  45. package/ios/GalleryViewer/GaleriaLayoutSupport.swift +143 -0
  46. package/ios/GalleryViewer/GaleriaMedia.swift +28 -0
  47. package/ios/GalleryViewer/GaleriaSourceViewRegistry.swift +80 -0
  48. package/ios/GalleryViewer/GaleriaVideoPlayerView.swift +437 -0
  49. package/ios/GalleryViewer/GaleriaViewerConfiguration.swift +51 -0
  50. package/ios/GalleryViewer/GaleriaViewerController.swift +745 -0
  51. package/ios/GalleryViewer/GaleriaViewerPageView.swift +623 -0
  52. package/ios/GalleryViewer/GaleriaViewerTransitionCoordinator.swift +312 -0
  53. package/package.json +21 -13
  54. package/src/all.ts +18 -0
  55. package/src/services/ImagePreviewService/README.md +19 -0
  56. package/src/ui/NativeImagePreview/NativeImagePreview.tsx +146 -0
  57. package/src/ui/NativeImagePreview/NativeImagePreview.web.tsx +37 -0
  58. package/src/ui/NativeImagePreview/README.md +111 -0
  59. package/src/ui/NativeImagePreview/context.tsx +22 -0
  60. package/src/ui/NativeImagePreview/index.tsx +18 -0
  61. package/src/ui/NativeImagePreview/types.ts +92 -0
  62. package/src/ui/NativeImagePreview/utils.ts +107 -0
  63. package/zkit-ui.podspec +13 -1
@@ -0,0 +1,636 @@
1
+ package cn.fontree.zkit.ui.preview;
2
+
3
+ import android.content.Context;
4
+ import android.graphics.RectF;
5
+ import android.graphics.drawable.Drawable;
6
+ import android.view.KeyEvent;
7
+ import android.view.MotionEvent;
8
+ import android.view.View;
9
+ import android.view.ViewConfiguration;
10
+ import android.view.ViewGroup;
11
+ import android.view.VelocityTracker;
12
+ import android.view.ViewParent;
13
+ import android.widget.FrameLayout;
14
+ import android.widget.ImageView;
15
+
16
+ import androidx.annotation.NonNull;
17
+ import androidx.annotation.Nullable;
18
+ import androidx.viewpager2.widget.ViewPager2;
19
+
20
+ import java.util.ArrayList;
21
+ import java.util.List;
22
+
23
+ public final class GalleryViewerOverlayView extends FrameLayout implements GalleryViewerPageView.Listener {
24
+ public interface Listener {
25
+ void onOverlayDismissed();
26
+
27
+ void onOverlayIndexChange(int index);
28
+ }
29
+
30
+ private final List<GalleryMediaItem> items;
31
+ @Nullable
32
+ private final String galleryId;
33
+ @Nullable
34
+ private final Listener listener;
35
+ private final boolean lightTheme;
36
+ private final int touchSlop;
37
+ private final int minFlingVelocity;
38
+
39
+ private View backgroundView;
40
+ private FrameLayout contentView;
41
+ private ViewPager2 viewPager;
42
+ private GalleryPagerAdapter pagerAdapter;
43
+ private GalleryViewerTransitionController transitionController;
44
+ private int currentIndex;
45
+ private float downX;
46
+ private float downY;
47
+ private boolean dragging;
48
+ private boolean multiTouchLock;
49
+ private boolean needReanchorAfterMultiTouch;
50
+ private float dragStartRawY;
51
+ private float dragStartTranslationY;
52
+ @Nullable
53
+ private VelocityTracker velocityTracker;
54
+ @Nullable
55
+ private View dragTarget;
56
+ @Nullable
57
+ private GalleryViewerPageView dragPageView;
58
+ @Nullable
59
+ private ImageView hiddenActiveSourceView;
60
+ private float hiddenActiveSourcePreviousAlpha = 1f;
61
+ private boolean closing;
62
+ private boolean openingTransitionStarted;
63
+ private boolean contentPresented;
64
+ private boolean finished;
65
+
66
+ private final Runnable openTransitionReadyWatcher = new Runnable() {
67
+ @Override
68
+ public void run() {
69
+ if (openingTransitionStarted || closing || finished) {
70
+ return;
71
+ }
72
+ GalleryViewerPageView pageView = resolveCurrentPageView();
73
+ if (pageView == null || getWidth() <= 0 || getHeight() <= 0) {
74
+ postOnAnimation(this);
75
+ return;
76
+ }
77
+ startOpenTransition(pageView, pageView.sharedElementState());
78
+ }
79
+ };
80
+
81
+ public GalleryViewerOverlayView(
82
+ @NonNull Context context,
83
+ @NonNull List<GalleryMediaItem> sourceItems,
84
+ int startIndex,
85
+ boolean lightTheme,
86
+ @Nullable String galleryId,
87
+ @Nullable Listener listener
88
+ ) {
89
+ super(context);
90
+ this.items = new ArrayList<>(sourceItems);
91
+ this.currentIndex = Math.max(0, Math.min(startIndex, items.size() - 1));
92
+ this.lightTheme = lightTheme;
93
+ this.galleryId = galleryId;
94
+ this.listener = listener;
95
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
96
+ touchSlop = viewConfiguration.getScaledTouchSlop();
97
+ minFlingVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
98
+ setLayoutParams(new LayoutParams(
99
+ ViewGroup.LayoutParams.MATCH_PARENT,
100
+ ViewGroup.LayoutParams.MATCH_PARENT
101
+ ));
102
+ setClickable(true);
103
+ setFocusable(true);
104
+ setFocusableInTouchMode(true);
105
+ setupUi();
106
+ post(openTransitionReadyWatcher);
107
+ requestFocus();
108
+ }
109
+
110
+ public void requestClose() {
111
+ closeViewer();
112
+ }
113
+
114
+ public void dismissImmediately() {
115
+ finishWithoutAnimation();
116
+ }
117
+
118
+ @Override
119
+ protected void onDetachedFromWindow() {
120
+ if (!finished) {
121
+ cleanup();
122
+ }
123
+ super.onDetachedFromWindow();
124
+ }
125
+
126
+ @Override
127
+ public boolean dispatchKeyEvent(KeyEvent event) {
128
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
129
+ requestClose();
130
+ return true;
131
+ }
132
+ return super.dispatchKeyEvent(event);
133
+ }
134
+
135
+ @Override
136
+ public boolean dispatchTouchEvent(MotionEvent event) {
137
+ if (closing || !contentPresented) {
138
+ super.dispatchTouchEvent(event);
139
+ return true;
140
+ }
141
+
142
+ int action = event.getActionMasked();
143
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
144
+ enterMultiTouchLock();
145
+ super.dispatchTouchEvent(event);
146
+ return true;
147
+ }
148
+ if (action == MotionEvent.ACTION_POINTER_UP) {
149
+ if (multiTouchLock && event.getPointerCount() - 1 <= 1) {
150
+ exitMultiTouchLockAndWaitReanchor();
151
+ }
152
+ super.dispatchTouchEvent(event);
153
+ return true;
154
+ }
155
+ if (multiTouchLock && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
156
+ clearMultiTouchLock();
157
+ super.dispatchTouchEvent(event);
158
+ return true;
159
+ }
160
+ if (multiTouchLock) {
161
+ super.dispatchTouchEvent(event);
162
+ return true;
163
+ }
164
+
165
+ switch (action) {
166
+ case MotionEvent.ACTION_DOWN:
167
+ if (needReanchorAfterMultiTouch) {
168
+ needReanchorAfterMultiTouch = false;
169
+ }
170
+ syncPagerGesturePolicy();
171
+ downX = event.getRawX();
172
+ downY = event.getRawY();
173
+ dragging = false;
174
+ dragTarget = null;
175
+ dragPageView = null;
176
+ ensureVelocityTracker();
177
+ velocityTracker.clear();
178
+ velocityTracker.addMovement(event);
179
+ break;
180
+ case MotionEvent.ACTION_MOVE:
181
+ if (needReanchorAfterMultiTouch) {
182
+ super.dispatchTouchEvent(event);
183
+ return true;
184
+ }
185
+ ensureVelocityTracker();
186
+ velocityTracker.addMovement(event);
187
+ if (!dragging) {
188
+ float dx = event.getRawX() - downX;
189
+ float dy = event.getRawY() - downY;
190
+ GalleryViewerPageView pageView = resolveCurrentPageView();
191
+ if (pageView != null
192
+ && Math.abs(dy) > touchSlop
193
+ && pageView.canBeginVerticalDismiss(dx, dy, event.getRawX(), event.getRawY())) {
194
+ startDragging(pageView, event.getRawY());
195
+ }
196
+ }
197
+ if (dragging) {
198
+ applyDragTransform(event.getRawY());
199
+ return true;
200
+ }
201
+ syncPagerGesturePolicy();
202
+ break;
203
+ case MotionEvent.ACTION_UP:
204
+ case MotionEvent.ACTION_CANCEL:
205
+ if (needReanchorAfterMultiTouch) {
206
+ if (action == MotionEvent.ACTION_CANCEL) {
207
+ needReanchorAfterMultiTouch = false;
208
+ syncPagerGesturePolicy();
209
+ }
210
+ releaseVelocityTracker();
211
+ super.dispatchTouchEvent(event);
212
+ return true;
213
+ }
214
+ if (dragging) {
215
+ ensureVelocityTracker();
216
+ velocityTracker.addMovement(event);
217
+ float velocityY = consumeYVelocity();
218
+ View target = getActiveDragTarget();
219
+ float height = Math.max(1f, getHeight());
220
+ float dismissDistance = height * 0.16f;
221
+ float quickFlingDistance = height * 0.06f;
222
+ float dismissVelocity = Math.max(1300f, minFlingVelocity * 1.6f);
223
+ boolean dismissByDistance = Math.abs(target.getTranslationY()) > dismissDistance;
224
+ boolean dismissByFling = Math.abs(target.getTranslationY()) > quickFlingDistance
225
+ && Math.abs(velocityY) > dismissVelocity;
226
+ dragging = false;
227
+ syncPagerGesturePolicy();
228
+ releaseVelocityTracker();
229
+ if (dismissByDistance || dismissByFling) {
230
+ closeViewer();
231
+ } else {
232
+ animateBackToCenter();
233
+ }
234
+ return true;
235
+ }
236
+ releaseVelocityTracker();
237
+ break;
238
+ default:
239
+ break;
240
+ }
241
+
242
+ super.dispatchTouchEvent(event);
243
+ return true;
244
+ }
245
+
246
+ @Override
247
+ public void onDismissRequested(@NonNull GalleryViewerPageView pageView) {
248
+ if (pageView == resolveCurrentPageView()) {
249
+ closeViewer();
250
+ }
251
+ }
252
+
253
+ @Override
254
+ public void onVideoCloseRequested(@NonNull GalleryViewerPageView pageView) {
255
+ if (pageView == resolveCurrentPageView()) {
256
+ closeViewer();
257
+ }
258
+ }
259
+
260
+ private void setupUi() {
261
+ backgroundView = new View(getContext());
262
+ backgroundView.setLayoutParams(new FrameLayout.LayoutParams(
263
+ ViewGroup.LayoutParams.MATCH_PARENT,
264
+ ViewGroup.LayoutParams.MATCH_PARENT
265
+ ));
266
+ backgroundView.setBackgroundColor(lightTheme ? 0xFFFFFFFF : 0xFF000000);
267
+ backgroundView.setAlpha(0f);
268
+ addView(backgroundView);
269
+
270
+ contentView = new FrameLayout(getContext());
271
+ contentView.setLayoutParams(new FrameLayout.LayoutParams(
272
+ ViewGroup.LayoutParams.MATCH_PARENT,
273
+ ViewGroup.LayoutParams.MATCH_PARENT
274
+ ));
275
+ contentView.setAlpha(0f);
276
+
277
+ viewPager = new ViewPager2(getContext());
278
+ viewPager.setLayoutParams(new FrameLayout.LayoutParams(
279
+ ViewGroup.LayoutParams.MATCH_PARENT,
280
+ ViewGroup.LayoutParams.MATCH_PARENT
281
+ ));
282
+ viewPager.setOffscreenPageLimit(1);
283
+ viewPager.setUserInputEnabled(false);
284
+ pagerAdapter = new GalleryPagerAdapter(this, this::applySourcePlaceholderIfNeeded);
285
+ viewPager.setAdapter(pagerAdapter);
286
+ pagerAdapter.setItems(items);
287
+ viewPager.setCurrentItem(currentIndex, false);
288
+ viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
289
+ @Override
290
+ public void onPageSelected(int position) {
291
+ currentIndex = position;
292
+ if (contentPresented) {
293
+ pagerAdapter.setActiveIndex(position);
294
+ syncPagerGesturePolicy();
295
+ hideActiveSourceViewForCurrentIndex();
296
+ if (listener != null) {
297
+ listener.onOverlayIndexChange(position);
298
+ }
299
+ }
300
+ }
301
+ });
302
+ contentView.addView(viewPager);
303
+ addView(contentView);
304
+
305
+ transitionController = new GalleryViewerTransitionController(this, backgroundView, contentView);
306
+ }
307
+
308
+ private void startOpenTransition(
309
+ @NonNull GalleryViewerPageView pageView,
310
+ @Nullable GallerySharedElementState resolvedPageState
311
+ ) {
312
+ if (openingTransitionStarted) {
313
+ return;
314
+ }
315
+ openingTransitionStarted = true;
316
+ GalleryMediaItem item = items.get(currentIndex);
317
+ String anchorKey = GallerySharedElementNames.forItem(galleryId, item);
318
+ ImageView sourceView = GallerySourceViewRegistry.find(anchorKey);
319
+ GallerySharedElementState sourceState = GalleryLayoutSupport.captureImageViewState(sourceView);
320
+ applySourcePlaceholderIfNeeded(pageView, currentIndex);
321
+ pageView.prepareForOpenTransition();
322
+ pageView.setMediaHidden(true);
323
+
324
+ Drawable fallbackDrawable = sourceState != null ? sourceState.getDrawable() : null;
325
+ RectF overlayBounds = GalleryLayoutSupport.viewBoundsOnScreen(this);
326
+ GallerySharedElementState effectivePageState = usableSharedElementState(resolvedPageState)
327
+ ? resolvedPageState
328
+ : pageView.sharedElementState();
329
+ GallerySharedElementGeometry targetGeometry = usableSharedElementState(effectivePageState)
330
+ ? effectivePageState.getGeometry()
331
+ : defaultOpenGeometryFromSource(sourceState, overlayBounds, pageView, fallbackDrawable);
332
+
333
+ transitionController.performOpenTransition(
334
+ sourceView,
335
+ sourceState,
336
+ targetGeometry,
337
+ () -> finishOpenTransition(pageView)
338
+ );
339
+ }
340
+
341
+ private void finishOpenTransition(@NonNull GalleryViewerPageView pageView) {
342
+ if (contentPresented) {
343
+ return;
344
+ }
345
+ pageView.setMediaHidden(false);
346
+ transitionController.completeOpenTransition(() -> {
347
+ contentPresented = true;
348
+ pagerAdapter.setActiveIndex(currentIndex);
349
+ syncPagerGesturePolicy();
350
+ hideActiveSourceViewForCurrentIndex();
351
+ if (listener != null) {
352
+ listener.onOverlayIndexChange(currentIndex);
353
+ }
354
+ });
355
+ }
356
+
357
+ private void closeViewer() {
358
+ if (closing || finished) {
359
+ return;
360
+ }
361
+ syncCurrentIndexFromPager();
362
+ closing = true;
363
+ dragging = false;
364
+ viewPager.setUserInputEnabled(false);
365
+ viewPager.requestDisallowInterceptTouchEvent(false);
366
+ releaseVelocityTracker();
367
+
368
+ GalleryViewerPageView pageView = resolveCurrentPageView();
369
+ if (pageView == null) {
370
+ finishWithoutAnimation();
371
+ return;
372
+ }
373
+
374
+ pageView.prepareForReturnTransition();
375
+ GallerySharedElementState pageState = pageView.sharedElementState();
376
+ pageView.setMediaHidden(true);
377
+
378
+ GalleryMediaItem item = items.get(currentIndex);
379
+ String anchorKey = GallerySharedElementNames.forItem(galleryId, item);
380
+ ImageView targetView = GallerySourceViewRegistry.find(anchorKey);
381
+ GallerySharedElementState targetState = GalleryLayoutSupport.captureImageViewState(targetView);
382
+ GallerySharedElementGeometry targetGeometry = targetState != null
383
+ ? targetState.getGeometry()
384
+ : GalleryLayoutSupport.captureImageViewGeometry(
385
+ targetView,
386
+ pageState != null ? pageState.getDrawable() : null
387
+ );
388
+
389
+ transitionController.performCloseTransition(
390
+ pageState,
391
+ targetGeometry,
392
+ targetView,
393
+ () -> {
394
+ restoreHiddenActiveSourceView();
395
+ finishWithoutAnimation();
396
+ }
397
+ );
398
+ }
399
+
400
+ @Nullable
401
+ private GalleryViewerPageView resolveCurrentPageView() {
402
+ GalleryViewerPageView pageView = pagerAdapter.findAttachedView(currentIndex);
403
+ if (pageView != null) {
404
+ return pageView;
405
+ }
406
+ return pagerAdapter.findActiveView();
407
+ }
408
+
409
+ @NonNull
410
+ private GallerySharedElementGeometry defaultOpenGeometryFromSource(
411
+ @Nullable GallerySharedElementState sourceState,
412
+ @NonNull RectF overlayBounds,
413
+ @NonNull GalleryViewerPageView pageView,
414
+ @Nullable Drawable fallbackDrawable
415
+ ) {
416
+ if (sourceState != null) {
417
+ RectF sourceContent = sourceState.getGeometry().getContentFrameInVisibleBounds();
418
+ if (sourceContent.width() > 1f && sourceContent.height() > 1f) {
419
+ return GalleryLayoutSupport.defaultGeometryForAspectRatio(
420
+ sourceContent.width(),
421
+ sourceContent.height(),
422
+ overlayBounds
423
+ );
424
+ }
425
+ }
426
+ return pageView.defaultTransitionGeometry(overlayBounds, fallbackDrawable);
427
+ }
428
+
429
+ private boolean usableSharedElementState(@Nullable GallerySharedElementState state) {
430
+ if (state == null) {
431
+ return false;
432
+ }
433
+ RectF visibleFrame = state.getGeometry().getVisibleFrameInWindow();
434
+ RectF contentFrame = state.getGeometry().getContentFrameInVisibleBounds();
435
+ return visibleFrame.width() > 1f
436
+ && visibleFrame.height() > 1f
437
+ && contentFrame.width() > 1f
438
+ && contentFrame.height() > 1f;
439
+ }
440
+
441
+ private void syncCurrentIndexFromPager() {
442
+ if (viewPager == null || items.isEmpty()) {
443
+ return;
444
+ }
445
+ int pagerIndex = viewPager.getCurrentItem();
446
+ currentIndex = Math.max(0, Math.min(pagerIndex, items.size() - 1));
447
+ }
448
+
449
+ private void startDragging(@NonNull GalleryViewerPageView pageView, float rawY) {
450
+ dragging = true;
451
+ dragPageView = pageView;
452
+ dragPageView.prepareForDismissDrag();
453
+ dragTarget = pageView.getDragTarget();
454
+ dragTarget.animate().cancel();
455
+ backgroundView.animate().cancel();
456
+ dragStartRawY = rawY;
457
+ dragStartTranslationY = dragTarget.getTranslationY();
458
+ viewPager.setUserInputEnabled(false);
459
+ viewPager.requestDisallowInterceptTouchEvent(true);
460
+ }
461
+
462
+ private void enterMultiTouchLock() {
463
+ multiTouchLock = true;
464
+ needReanchorAfterMultiTouch = false;
465
+ if (dragging) {
466
+ dragging = false;
467
+ animateBackToCenter();
468
+ }
469
+ dragTarget = null;
470
+ releaseVelocityTracker();
471
+ viewPager.setUserInputEnabled(false);
472
+ viewPager.requestDisallowInterceptTouchEvent(true);
473
+ }
474
+
475
+ private void exitMultiTouchLockAndWaitReanchor() {
476
+ multiTouchLock = false;
477
+ needReanchorAfterMultiTouch = true;
478
+ dragging = false;
479
+ dragTarget = null;
480
+ releaseVelocityTracker();
481
+ viewPager.setUserInputEnabled(false);
482
+ viewPager.requestDisallowInterceptTouchEvent(true);
483
+ }
484
+
485
+ private void clearMultiTouchLock() {
486
+ multiTouchLock = false;
487
+ needReanchorAfterMultiTouch = false;
488
+ dragging = false;
489
+ dragTarget = null;
490
+ dragPageView = null;
491
+ releaseVelocityTracker();
492
+ syncPagerGesturePolicy();
493
+ }
494
+
495
+ private void syncPagerGesturePolicy() {
496
+ GalleryViewerPageView pageView = resolveCurrentPageView();
497
+ boolean canPage = items.size() > 1 && pageView != null && pageView.canPageHorizontally();
498
+ viewPager.setUserInputEnabled(canPage);
499
+ viewPager.requestDisallowInterceptTouchEvent(!canPage);
500
+ if (pageView != null) {
501
+ pageView.setAllowParentInterceptOnImageEdge(canPage);
502
+ }
503
+ }
504
+
505
+ @NonNull
506
+ private View getActiveDragTarget() {
507
+ if (dragTarget != null) {
508
+ return dragTarget;
509
+ }
510
+ return viewPager;
511
+ }
512
+
513
+ private void applyDragTransform(float rawY) {
514
+ View target = getActiveDragTarget();
515
+ float dy = dragStartTranslationY + rawY - dragStartRawY;
516
+ float abs = Math.abs(dy);
517
+ float height = Math.max(1, getHeight());
518
+ float progress = Math.min(1f, abs / height);
519
+ float scale = Math.max(0.84f, 1f - progress * 0.16f);
520
+ target.setTranslationY(dy);
521
+ target.setScaleX(scale);
522
+ target.setScaleY(scale);
523
+ backgroundView.setAlpha(1f - Math.min(0.9f, progress * 1.25f));
524
+ }
525
+
526
+ private void animateBackToCenter() {
527
+ View target = getActiveDragTarget();
528
+ GalleryViewerPageView restorePageView = dragPageView;
529
+ dragPageView = null;
530
+ target.animate()
531
+ .translationY(0f)
532
+ .scaleX(1f)
533
+ .scaleY(1f)
534
+ .setDuration(200L)
535
+ .withEndAction(() -> {
536
+ backgroundView.setAlpha(1f);
537
+ if (restorePageView != null) {
538
+ restorePageView.restoreAfterDismissCancelled();
539
+ }
540
+ })
541
+ .start();
542
+ backgroundView.animate()
543
+ .alpha(1f)
544
+ .setDuration(200L)
545
+ .start();
546
+ }
547
+
548
+ @Nullable
549
+ private ImageView sourceViewForIndex(int index) {
550
+ if (index < 0 || index >= items.size()) {
551
+ return null;
552
+ }
553
+ GalleryMediaItem item = items.get(index);
554
+ String anchorKey = GallerySharedElementNames.forItem(galleryId, item);
555
+ return GallerySourceViewRegistry.find(anchorKey);
556
+ }
557
+
558
+ private void applySourcePlaceholderIfNeeded(@NonNull GalleryViewerPageView pageView, int index) {
559
+ ImageView sourceView = sourceViewForIndex(index);
560
+ if (sourceView == null) {
561
+ return;
562
+ }
563
+ Drawable sourceDrawable = GalleryLayoutSupport.transitionDrawableForImageView(sourceView);
564
+ pageView.setImagePlaceholderIfEmpty(sourceDrawable);
565
+ }
566
+
567
+ private void hideActiveSourceViewForCurrentIndex() {
568
+ if (!contentPresented || closing) {
569
+ return;
570
+ }
571
+ ImageView sourceView = sourceViewForIndex(currentIndex);
572
+ if (hiddenActiveSourceView != sourceView) {
573
+ restoreHiddenActiveSourceView();
574
+ hiddenActiveSourcePreviousAlpha = sourceView != null ? sourceView.getAlpha() : 1f;
575
+ hiddenActiveSourceView = sourceView;
576
+ }
577
+ if (sourceView != null) {
578
+ sourceView.setAlpha(0f);
579
+ }
580
+ }
581
+
582
+ private void restoreHiddenActiveSourceView() {
583
+ if (hiddenActiveSourceView != null) {
584
+ hiddenActiveSourceView.setAlpha(hiddenActiveSourcePreviousAlpha);
585
+ }
586
+ hiddenActiveSourceView = null;
587
+ hiddenActiveSourcePreviousAlpha = 1f;
588
+ }
589
+
590
+ private void ensureVelocityTracker() {
591
+ if (velocityTracker == null) {
592
+ velocityTracker = VelocityTracker.obtain();
593
+ }
594
+ }
595
+
596
+ private float consumeYVelocity() {
597
+ if (velocityTracker == null) {
598
+ return 0f;
599
+ }
600
+ velocityTracker.computeCurrentVelocity(1000);
601
+ return velocityTracker.getYVelocity();
602
+ }
603
+
604
+ private void releaseVelocityTracker() {
605
+ if (velocityTracker == null) {
606
+ return;
607
+ }
608
+ velocityTracker.recycle();
609
+ velocityTracker = null;
610
+ }
611
+
612
+ private void finishWithoutAnimation() {
613
+ if (finished) {
614
+ return;
615
+ }
616
+ finished = true;
617
+ closing = true;
618
+ cleanup();
619
+ ViewParent parent = getParent();
620
+ if (parent instanceof ViewGroup) {
621
+ ((ViewGroup) parent).removeView(this);
622
+ }
623
+ if (listener != null) {
624
+ listener.onOverlayDismissed();
625
+ }
626
+ }
627
+
628
+ private void cleanup() {
629
+ restoreHiddenActiveSourceView();
630
+ removeCallbacks(openTransitionReadyWatcher);
631
+ if (pagerAdapter != null) {
632
+ pagerAdapter.releaseAll();
633
+ }
634
+ releaseVelocityTracker();
635
+ }
636
+ }