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,25 @@
1
+ package cn.fontree.zkit.ui.preview;
2
+
3
+ import android.graphics.drawable.Drawable;
4
+
5
+ import androidx.annotation.NonNull;
6
+
7
+ public final class GallerySharedElementState {
8
+ private final Drawable drawable;
9
+ private final GallerySharedElementGeometry geometry;
10
+
11
+ public GallerySharedElementState(@NonNull Drawable drawable, @NonNull GallerySharedElementGeometry geometry) {
12
+ this.drawable = drawable;
13
+ this.geometry = geometry;
14
+ }
15
+
16
+ @NonNull
17
+ public Drawable getDrawable() {
18
+ return drawable;
19
+ }
20
+
21
+ @NonNull
22
+ public GallerySharedElementGeometry getGeometry() {
23
+ return geometry;
24
+ }
25
+ }
@@ -0,0 +1,115 @@
1
+ package cn.fontree.zkit.ui.preview;
2
+
3
+ import android.view.View;
4
+ import android.widget.ImageView;
5
+
6
+ import androidx.annotation.NonNull;
7
+ import androidx.annotation.Nullable;
8
+ import androidx.core.view.ViewCompat;
9
+
10
+ import java.lang.ref.WeakReference;
11
+ import java.util.HashMap;
12
+ import java.util.Iterator;
13
+ import java.util.Map;
14
+
15
+ public final class GallerySourceViewRegistry {
16
+ private static final Map<String, WeakReference<ImageView>> SOURCE_VIEWS = new HashMap<>();
17
+
18
+ private GallerySourceViewRegistry() {
19
+ }
20
+
21
+ public static synchronized void register(@NonNull String key, @NonNull ImageView imageView) {
22
+ cleanupLocked();
23
+ if (!hasUsableGeometry(imageView)) {
24
+ ImageView existingImageView = resolveMappedViewLocked(key);
25
+ boolean keepExisting = existingImageView != null
26
+ && existingImageView != imageView
27
+ && hasUsableGeometry(existingImageView);
28
+ clearMappingsForViewLocked(imageView);
29
+ if (keepExisting) {
30
+ SOURCE_VIEWS.put(key, new WeakReference<>(existingImageView));
31
+ return;
32
+ }
33
+ SOURCE_VIEWS.remove(key);
34
+ return;
35
+ }
36
+
37
+ ImageView previousImageView = resolveMappedViewLocked(key);
38
+ if (!isPreferredSourceView(imageView)
39
+ && previousImageView != null
40
+ && previousImageView != imageView
41
+ && isPreferredSourceView(previousImageView)) {
42
+ clearMappingsForViewLocked(imageView);
43
+ SOURCE_VIEWS.put(key, new WeakReference<>(previousImageView));
44
+ return;
45
+ }
46
+
47
+ clearMappingsForViewLocked(imageView);
48
+ SOURCE_VIEWS.put(key, new WeakReference<>(imageView));
49
+ ViewCompat.setTransitionName(imageView, key);
50
+ }
51
+
52
+ public static synchronized void unregisterView(@NonNull ImageView imageView) {
53
+ clearMappingsForViewLocked(imageView);
54
+ }
55
+
56
+ @Nullable
57
+ public static synchronized ImageView find(@NonNull String key) {
58
+ cleanupLocked();
59
+ WeakReference<ImageView> reference = SOURCE_VIEWS.get(key);
60
+ if (reference == null) {
61
+ return null;
62
+ }
63
+ ImageView imageView = reference.get();
64
+ if (imageView == null || !imageView.isAttachedToWindow()) {
65
+ SOURCE_VIEWS.remove(key);
66
+ return null;
67
+ }
68
+ if (!hasUsableGeometry(imageView)) {
69
+ SOURCE_VIEWS.remove(key);
70
+ return null;
71
+ }
72
+ return imageView;
73
+ }
74
+
75
+ @Nullable
76
+ private static ImageView resolveMappedViewLocked(@NonNull String key) {
77
+ WeakReference<ImageView> reference = SOURCE_VIEWS.get(key);
78
+ return reference != null ? reference.get() : null;
79
+ }
80
+
81
+ private static boolean hasUsableGeometry(@Nullable ImageView imageView) {
82
+ return imageView != null
83
+ && imageView.isAttachedToWindow()
84
+ && imageView.getWidth() > 0
85
+ && imageView.getHeight() > 0;
86
+ }
87
+
88
+ private static boolean isPreferredSourceView(@Nullable ImageView imageView) {
89
+ return hasUsableGeometry(imageView)
90
+ && imageView.getVisibility() == View.VISIBLE
91
+ && imageView.isShown();
92
+ }
93
+
94
+ private static void clearMappingsForViewLocked(@NonNull ImageView imageView) {
95
+ Iterator<Map.Entry<String, WeakReference<ImageView>>> iterator = SOURCE_VIEWS.entrySet().iterator();
96
+ while (iterator.hasNext()) {
97
+ Map.Entry<String, WeakReference<ImageView>> entry = iterator.next();
98
+ ImageView mappedView = entry.getValue().get();
99
+ if (mappedView == null || mappedView == imageView) {
100
+ iterator.remove();
101
+ }
102
+ }
103
+ }
104
+
105
+ private static void cleanupLocked() {
106
+ Iterator<Map.Entry<String, WeakReference<ImageView>>> iterator = SOURCE_VIEWS.entrySet().iterator();
107
+ while (iterator.hasNext()) {
108
+ Map.Entry<String, WeakReference<ImageView>> entry = iterator.next();
109
+ ImageView mappedView = entry.getValue().get();
110
+ if (mappedView == null) {
111
+ iterator.remove();
112
+ }
113
+ }
114
+ }
115
+ }
@@ -0,0 +1,60 @@
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.Gravity;
7
+ import android.widget.FrameLayout;
8
+ import android.widget.ImageView;
9
+
10
+ import androidx.annotation.NonNull;
11
+
12
+ public final class GalleryTransitionSnapshotView extends FrameLayout {
13
+ private final ImageView imageView;
14
+
15
+ public GalleryTransitionSnapshotView(@NonNull Context context, @NonNull Drawable drawable) {
16
+ super(context);
17
+ setClipChildren(true);
18
+ setClipToPadding(true);
19
+ imageView = new ImageView(context);
20
+ imageView.setScaleType(ImageView.ScaleType.FIT_XY);
21
+ imageView.setImageDrawable(drawable);
22
+ addView(imageView);
23
+ }
24
+
25
+ public void applyGeometry(@NonNull GallerySharedElementGeometry geometry) {
26
+ RectF visibleFrame = geometry.getVisibleFrameInWindow();
27
+ FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
28
+ if (layoutParams == null) {
29
+ layoutParams = new FrameLayout.LayoutParams(
30
+ Math.max(1, Math.round(visibleFrame.width())),
31
+ Math.max(1, Math.round(visibleFrame.height()))
32
+ );
33
+ }
34
+ layoutParams.width = Math.max(1, Math.round(visibleFrame.width()));
35
+ layoutParams.height = Math.max(1, Math.round(visibleFrame.height()));
36
+ layoutParams.leftMargin = 0;
37
+ layoutParams.topMargin = 0;
38
+ layoutParams.gravity = Gravity.TOP | Gravity.START;
39
+ setLayoutParams(layoutParams);
40
+ setX(visibleFrame.left);
41
+ setY(visibleFrame.top);
42
+
43
+ RectF contentFrame = geometry.getContentFrameInVisibleBounds();
44
+ FrameLayout.LayoutParams imageLayoutParams = (FrameLayout.LayoutParams) imageView.getLayoutParams();
45
+ if (imageLayoutParams == null) {
46
+ imageLayoutParams = new FrameLayout.LayoutParams(
47
+ Math.max(1, Math.round(contentFrame.width())),
48
+ Math.max(1, Math.round(contentFrame.height()))
49
+ );
50
+ }
51
+ imageLayoutParams.width = Math.max(1, Math.round(contentFrame.width()));
52
+ imageLayoutParams.height = Math.max(1, Math.round(contentFrame.height()));
53
+ imageLayoutParams.leftMargin = 0;
54
+ imageLayoutParams.topMargin = 0;
55
+ imageLayoutParams.gravity = Gravity.TOP | Gravity.START;
56
+ imageView.setLayoutParams(imageLayoutParams);
57
+ imageView.setX(contentFrame.left);
58
+ imageView.setY(contentFrame.top);
59
+ }
60
+ }
@@ -0,0 +1,338 @@
1
+ package cn.fontree.zkit.ui.preview;
2
+
3
+ import android.content.Context;
4
+ import android.content.res.ColorStateList;
5
+ import android.graphics.Color;
6
+ import android.graphics.Rect;
7
+ import android.graphics.drawable.Drawable;
8
+ import android.net.Uri;
9
+ import android.util.TypedValue;
10
+ import android.view.Gravity;
11
+ import android.view.LayoutInflater;
12
+ import android.view.View;
13
+ import android.view.ViewGroup;
14
+ import android.widget.FrameLayout;
15
+ import android.widget.ImageView;
16
+
17
+ import androidx.annotation.NonNull;
18
+ import androidx.annotation.Nullable;
19
+ import androidx.appcompat.content.res.AppCompatResources;
20
+ import androidx.appcompat.widget.AppCompatImageButton;
21
+ import androidx.media3.common.MediaItem;
22
+ import androidx.media3.common.Player;
23
+ import androidx.media3.exoplayer.ExoPlayer;
24
+ import androidx.media3.ui.PlayerControlView;
25
+ import androidx.media3.ui.PlayerView;
26
+
27
+ import com.bumptech.glide.Glide;
28
+ import com.bumptech.glide.load.engine.GlideException;
29
+ import com.bumptech.glide.request.RequestListener;
30
+ import com.bumptech.glide.request.target.Target;
31
+
32
+ public final class GalleryVideoPlayerView extends FrameLayout {
33
+ public interface Listener {
34
+ void onCloseRequested();
35
+ }
36
+
37
+ private final ImageView posterImageView;
38
+ private final PlayerView playerView;
39
+ private final AppCompatImageButton closeButton;
40
+ @Nullable
41
+ private Runnable contentReadyListener;
42
+ @Nullable
43
+ private GalleryMediaItem item;
44
+ @Nullable
45
+ private ExoPlayer player;
46
+ @Nullable
47
+ private String preparedSourceUrl;
48
+ @Nullable
49
+ private Listener listener;
50
+ private boolean firstFrameReady;
51
+ private boolean active;
52
+
53
+ private final Player.Listener playerListener = new Player.Listener() {
54
+ @Override
55
+ public void onRenderedFirstFrame() {
56
+ firstFrameReady = true;
57
+ if (active) {
58
+ revealPlayer();
59
+ }
60
+ }
61
+ };
62
+
63
+ public GalleryVideoPlayerView(@NonNull Context context) {
64
+ super(context);
65
+ setLayoutParams(new LayoutParams(
66
+ ViewGroup.LayoutParams.MATCH_PARENT,
67
+ ViewGroup.LayoutParams.MATCH_PARENT
68
+ ));
69
+ setBackgroundColor(Color.TRANSPARENT);
70
+
71
+ posterImageView = new ImageView(context);
72
+ posterImageView.setLayoutParams(new LayoutParams(
73
+ ViewGroup.LayoutParams.MATCH_PARENT,
74
+ ViewGroup.LayoutParams.MATCH_PARENT
75
+ ));
76
+ posterImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
77
+ posterImageView.setBackgroundColor(Color.TRANSPARENT);
78
+ addView(posterImageView);
79
+
80
+ playerView = (PlayerView) LayoutInflater.from(context)
81
+ .inflate(R.layout.galeria_player_view, this, false);
82
+ playerView.setUseController(true);
83
+ playerView.setControllerAutoShow(true);
84
+ playerView.setControllerHideOnTouch(true);
85
+ playerView.setShutterBackgroundColor(Color.TRANSPARENT);
86
+ playerView.setBackgroundColor(Color.TRANSPARENT);
87
+ playerView.setShowPreviousButton(false);
88
+ playerView.setShowNextButton(false);
89
+ playerView.setShowRewindButton(false);
90
+ playerView.setShowFastForwardButton(false);
91
+ playerView.setShowSubtitleButton(false);
92
+ playerView.setShowVrButton(false);
93
+ playerView.setShowShuffleButton(false);
94
+ playerView.setAlpha(0f);
95
+ playerView.setVisibility(VISIBLE);
96
+ addView(playerView);
97
+ hideControllerView(androidx.media3.ui.R.id.exo_settings);
98
+ hideControllerView(androidx.media3.ui.R.id.exo_overflow_show);
99
+ hideControllerView(androidx.media3.ui.R.id.exo_overflow_hide);
100
+
101
+ closeButton = new AppCompatImageButton(context);
102
+ LayoutParams closeLayoutParams = new LayoutParams(dp(48), dp(48));
103
+ closeLayoutParams.gravity = Gravity.TOP | Gravity.START;
104
+ closeLayoutParams.topMargin = dp(14);
105
+ closeLayoutParams.leftMargin = dp(10);
106
+ closeButton.setLayoutParams(closeLayoutParams);
107
+ closeButton.setImageDrawable(
108
+ AppCompatResources.getDrawable(context, androidx.appcompat.R.drawable.abc_ic_clear_material)
109
+ );
110
+ closeButton.setBackgroundResource(resolveSelectableItemBackgroundBorderless());
111
+ closeButton.setImageTintList(ColorStateList.valueOf(Color.WHITE));
112
+ closeButton.setPadding(dp(12), dp(12), dp(12), dp(12));
113
+ closeButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
114
+ closeButton.setVisibility(GONE);
115
+ closeButton.setOnClickListener(v -> {
116
+ if (listener != null) {
117
+ listener.onCloseRequested();
118
+ }
119
+ });
120
+ addView(closeButton);
121
+
122
+ playerView.setControllerVisibilityListener((PlayerControlView.VisibilityListener) visibility -> {
123
+ if (firstFrameReady) {
124
+ closeButton.setVisibility(visibility == View.VISIBLE ? View.VISIBLE : View.GONE);
125
+ }
126
+ });
127
+ }
128
+
129
+ public void setListener(@Nullable Listener listener) {
130
+ this.listener = listener;
131
+ }
132
+
133
+ public void setOnContentReadyListener(@Nullable Runnable contentReadyListener) {
134
+ this.contentReadyListener = contentReadyListener;
135
+ }
136
+
137
+ public void bind(@NonNull GalleryMediaItem item) {
138
+ this.item = item;
139
+ firstFrameReady = false;
140
+ playerView.animate().cancel();
141
+ playerView.setAlpha(0f);
142
+ playerView.setVisibility(VISIBLE);
143
+ closeButton.setVisibility(GONE);
144
+ posterImageView.animate().cancel();
145
+ posterImageView.setAlpha(1f);
146
+ posterImageView.setVisibility(VISIBLE);
147
+ Glide.with(posterImageView).clear(posterImageView);
148
+ posterImageView.setImageDrawable(null);
149
+ Glide.with(posterImageView)
150
+ .load(item.getThumbnailUrl())
151
+ .dontAnimate()
152
+ .listener(new RequestListener<Drawable>() {
153
+ @Override
154
+ public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
155
+ notifyContentReady();
156
+ return false;
157
+ }
158
+
159
+ @Override
160
+ public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, com.bumptech.glide.load.DataSource dataSource, boolean isFirstResource) {
161
+ notifyContentReady();
162
+ return false;
163
+ }
164
+ })
165
+ .into(posterImageView);
166
+ if (active) {
167
+ ensurePlayerPrepared(item.getSourceUrl());
168
+ }
169
+ }
170
+
171
+ public void setActive(boolean active) {
172
+ this.active = active;
173
+ if (item == null) {
174
+ return;
175
+ }
176
+ if (active) {
177
+ ensurePlayerPrepared(item.getSourceUrl());
178
+ if (player != null) {
179
+ player.play();
180
+ }
181
+ if (firstFrameReady) {
182
+ revealPlayer();
183
+ }
184
+ } else {
185
+ if (player != null) {
186
+ player.pause();
187
+ }
188
+ closeButton.setVisibility(GONE);
189
+ }
190
+ }
191
+
192
+ public void setMediaHidden(boolean hidden) {
193
+ setAlpha(hidden ? 0f : 1f);
194
+ }
195
+
196
+ @Nullable
197
+ public GallerySharedElementState sharedElementState() {
198
+ return GalleryLayoutSupport.captureImageViewState(posterImageView);
199
+ }
200
+
201
+ @Nullable
202
+ public Drawable getPosterDrawable() {
203
+ return posterImageView.getDrawable();
204
+ }
205
+
206
+ public void prepareForReturnTransition() {
207
+ playerView.animate().cancel();
208
+ posterImageView.animate().cancel();
209
+ posterImageView.setAlpha(1f);
210
+ posterImageView.setVisibility(VISIBLE);
211
+ playerView.setAlpha(0f);
212
+ playerView.setVisibility(VISIBLE);
213
+ closeButton.setVisibility(GONE);
214
+ }
215
+
216
+ public void restoreAfterDismissCancelled() {
217
+ if (!firstFrameReady) {
218
+ prepareForReturnTransition();
219
+ return;
220
+ }
221
+ playerView.setVisibility(VISIBLE);
222
+ playerView.setAlpha(1f);
223
+ posterImageView.setVisibility(VISIBLE);
224
+ posterImageView.setAlpha(0f);
225
+ }
226
+
227
+ public boolean isTouchOnInteractiveControls(float rawX, float rawY) {
228
+ return isTouchInsideView(playerView.findViewById(androidx.media3.ui.R.id.exo_progress), rawX, rawY, dp(24))
229
+ || isTouchInsideView(closeButton, rawX, rawY, dp(12));
230
+ }
231
+
232
+ public void release() {
233
+ Glide.with(posterImageView.getContext().getApplicationContext()).clear(posterImageView);
234
+ posterImageView.setImageDrawable(null);
235
+ posterImageView.animate().cancel();
236
+ posterImageView.setAlpha(1f);
237
+ posterImageView.setVisibility(VISIBLE);
238
+ closeButton.setVisibility(GONE);
239
+ if (player != null) {
240
+ player.removeListener(playerListener);
241
+ player.release();
242
+ player = null;
243
+ playerView.setPlayer(null);
244
+ }
245
+ playerView.animate().cancel();
246
+ playerView.setAlpha(0f);
247
+ playerView.setVisibility(VISIBLE);
248
+ preparedSourceUrl = null;
249
+ firstFrameReady = false;
250
+ }
251
+
252
+ private void ensurePlayerPrepared(@NonNull String sourceUrl) {
253
+ if (player == null) {
254
+ player = new ExoPlayer.Builder(getContext()).build();
255
+ player.addListener(playerListener);
256
+ playerView.setPlayer(player);
257
+ }
258
+ if (sourceUrl.equals(preparedSourceUrl)) {
259
+ return;
260
+ }
261
+ firstFrameReady = false;
262
+ playerView.animate().cancel();
263
+ playerView.setAlpha(0f);
264
+ playerView.setVisibility(VISIBLE);
265
+ closeButton.setVisibility(GONE);
266
+ player.setMediaItem(MediaItem.fromUri(Uri.parse(sourceUrl)));
267
+ player.prepare();
268
+ preparedSourceUrl = sourceUrl;
269
+ }
270
+
271
+ private void revealPlayer() {
272
+ playerView.setVisibility(VISIBLE);
273
+ playerView.animate().cancel();
274
+ playerView.setAlpha(0f);
275
+ posterImageView.animate().cancel();
276
+ posterImageView.setVisibility(VISIBLE);
277
+ posterImageView.setAlpha(1f);
278
+ playerView.animate()
279
+ .alpha(1f)
280
+ .setDuration(180L)
281
+ .start();
282
+ posterImageView.animate()
283
+ .alpha(0f)
284
+ .setDuration(220L)
285
+ .withEndAction(() -> {
286
+ if (playerView.isControllerFullyVisible()) {
287
+ closeButton.setVisibility(VISIBLE);
288
+ }
289
+ })
290
+ .start();
291
+ }
292
+
293
+ private void notifyContentReady() {
294
+ if (contentReadyListener != null) {
295
+ contentReadyListener.run();
296
+ }
297
+ }
298
+
299
+ private void hideControllerView(int viewId) {
300
+ View target = playerView.findViewById(viewId);
301
+ if (target != null) {
302
+ target.setVisibility(GONE);
303
+ }
304
+ }
305
+
306
+ private boolean isTouchInsideView(@Nullable View target, float rawX, float rawY, int extraPaddingPx) {
307
+ if (target == null || !target.isShown() || target.getWidth() <= 0 || target.getHeight() <= 0) {
308
+ return false;
309
+ }
310
+ int[] location = new int[2];
311
+ target.getLocationOnScreen(location);
312
+ Rect hitRect = new Rect(
313
+ location[0] - extraPaddingPx,
314
+ location[1] - extraPaddingPx,
315
+ location[0] + target.getWidth() + extraPaddingPx,
316
+ location[1] + target.getHeight() + extraPaddingPx
317
+ );
318
+ return hitRect.contains(Math.round(rawX), Math.round(rawY));
319
+ }
320
+
321
+ private int resolveSelectableItemBackgroundBorderless() {
322
+ TypedValue outValue = new TypedValue();
323
+ boolean resolved = getContext().getTheme().resolveAttribute(
324
+ android.R.attr.selectableItemBackgroundBorderless,
325
+ outValue,
326
+ true
327
+ );
328
+ return resolved ? outValue.resourceId : 0;
329
+ }
330
+
331
+ private int dp(int value) {
332
+ return (int) TypedValue.applyDimension(
333
+ TypedValue.COMPLEX_UNIT_DIP,
334
+ value,
335
+ getResources().getDisplayMetrics()
336
+ );
337
+ }
338
+ }