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.
- package/README.md +56 -0
- package/android/build.gradle +100 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GaleriaModule.kt +43 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GaleriaView.kt +305 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryLayoutSupport.java +450 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryMediaItem.java +36 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryPagerAdapter.java +140 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySharedElementGeometry.java +25 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySharedElementNames.java +39 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySharedElementState.java +25 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GallerySourceViewRegistry.java +115 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryTransitionSnapshotView.java +60 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryVideoPlayerView.java +338 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryViewerOverlayView.java +636 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryViewerPageView.java +357 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/GalleryViewerTransitionController.java +223 -0
- package/android/src/main/res/layout/galeria_player_view.xml +9 -0
- package/dist/all.d.ts +2 -0
- package/dist/all.d.ts.map +1 -1
- package/dist/all.js +24 -22
- package/dist/ui/NativeImagePreview/NativeImagePreview.d.ts +3 -0
- package/dist/ui/NativeImagePreview/NativeImagePreview.d.ts.map +1 -0
- package/dist/ui/NativeImagePreview/NativeImagePreview.js +99 -0
- package/dist/ui/NativeImagePreview/NativeImagePreview.web.d.ts +3 -0
- package/dist/ui/NativeImagePreview/NativeImagePreview.web.d.ts.map +1 -0
- package/dist/ui/NativeImagePreview/NativeImagePreview.web.js +56 -0
- package/dist/ui/NativeImagePreview/context.d.ts +14 -0
- package/dist/ui/NativeImagePreview/context.d.ts.map +1 -0
- package/dist/ui/NativeImagePreview/context.js +38 -0
- package/dist/ui/NativeImagePreview/index.d.ts +3 -0
- package/dist/ui/NativeImagePreview/index.d.ts.map +1 -0
- package/dist/ui/NativeImagePreview/index.js +5 -0
- package/dist/ui/NativeImagePreview/types.d.ts +66 -0
- package/dist/ui/NativeImagePreview/types.d.ts.map +1 -0
- package/dist/ui/NativeImagePreview/types.js +2 -0
- package/dist/ui/NativeImagePreview/utils.d.ts +8 -0
- package/dist/ui/NativeImagePreview/utils.d.ts.map +1 -0
- package/dist/ui/NativeImagePreview/utils.js +82 -0
- package/expo-module.config.json +11 -0
- package/ios/GaleriaModule.swift +46 -0
- package/ios/GaleriaView.swift +253 -0
- package/ios/GalleryViewer/GaleriaImageLoader.swift +73 -0
- package/ios/GalleryViewer/GaleriaImageViewInteraction.swift +245 -0
- package/ios/GalleryViewer/GaleriaLayoutSupport.swift +143 -0
- package/ios/GalleryViewer/GaleriaMedia.swift +28 -0
- package/ios/GalleryViewer/GaleriaSourceViewRegistry.swift +80 -0
- package/ios/GalleryViewer/GaleriaVideoPlayerView.swift +437 -0
- package/ios/GalleryViewer/GaleriaViewerConfiguration.swift +51 -0
- package/ios/GalleryViewer/GaleriaViewerController.swift +745 -0
- package/ios/GalleryViewer/GaleriaViewerPageView.swift +623 -0
- package/ios/GalleryViewer/GaleriaViewerTransitionCoordinator.swift +312 -0
- package/package.json +21 -13
- package/src/all.ts +18 -0
- package/src/services/ImagePreviewService/README.md +19 -0
- package/src/ui/NativeImagePreview/NativeImagePreview.tsx +146 -0
- package/src/ui/NativeImagePreview/NativeImagePreview.web.tsx +37 -0
- package/src/ui/NativeImagePreview/README.md +111 -0
- package/src/ui/NativeImagePreview/context.tsx +22 -0
- package/src/ui/NativeImagePreview/index.tsx +18 -0
- package/src/ui/NativeImagePreview/types.ts +92 -0
- package/src/ui/NativeImagePreview/utils.ts +107 -0
- 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
|
+
}
|