this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

lint kt

Hailey df167182 29cf10db

+428 -409
+53 -52
android/src/main/java/expo/modules/blueskyvideo/BlueskyVideoModule.kt
··· 10 10 11 11 @UnstableApi 12 12 class BlueskyVideoModule : Module() { 13 - private var wasPlayingPlayer: Player? = null 13 + private var wasPlayingPlayer: Player? = null 14 14 15 - override fun definition() = ModuleDefinition { 16 - Name("BlueskyVideo") 15 + override fun definition() = 16 + ModuleDefinition { 17 + Name("BlueskyVideo") 17 18 18 - OnActivityEntersForeground { 19 - val view = ViewManager.getActiveView() ?: return@OnActivityEntersForeground 20 - val player = view.player ?: return@OnActivityEntersForeground 19 + OnActivityEntersForeground { 20 + val view = ViewManager.getActiveView() ?: return@OnActivityEntersForeground 21 + val player = view.player ?: return@OnActivityEntersForeground 21 22 22 - if (player.isPlaying) { 23 - wasPlayingPlayer = player 24 - player.pause() 25 - } 26 - } 23 + if (player.isPlaying) { 24 + wasPlayingPlayer = player 25 + player.pause() 26 + } 27 + } 27 28 28 - OnActivityEntersBackground { 29 - val player = wasPlayingPlayer ?: return@OnActivityEntersBackground 30 - player.play() 31 - wasPlayingPlayer = null 32 - } 29 + OnActivityEntersBackground { 30 + val player = wasPlayingPlayer ?: return@OnActivityEntersBackground 31 + player.play() 32 + wasPlayingPlayer = null 33 + } 33 34 34 - AsyncFunction("updateActiveVideoViewAsync") { 35 - val handler = Handler(Looper.getMainLooper()) 36 - handler.post { 37 - ViewManager.updateActiveView() 38 - } 39 - } 35 + AsyncFunction("updateActiveVideoViewAsync") { 36 + val handler = Handler(Looper.getMainLooper()) 37 + handler.post { 38 + ViewManager.updateActiveView() 39 + } 40 + } 40 41 41 - View(BlueskyVideoView::class) { 42 - Events( 43 - "onActiveChange", 44 - "onLoadingChange", 45 - "onMutedChange", 46 - "onPlayerPress", 47 - "onStatusChange", 48 - "onTimeRemainingChange", 49 - "onError", 50 - ) 42 + View(BlueskyVideoView::class) { 43 + Events( 44 + "onActiveChange", 45 + "onLoadingChange", 46 + "onMutedChange", 47 + "onPlayerPress", 48 + "onStatusChange", 49 + "onTimeRemainingChange", 50 + "onError", 51 + ) 51 52 52 - Prop("url") { view: BlueskyVideoView, prop: Uri -> 53 - view.url = prop 54 - } 53 + Prop("url") { view: BlueskyVideoView, prop: Uri -> 54 + view.url = prop 55 + } 55 56 56 - Prop("autoplay") { view: BlueskyVideoView, prop: Boolean -> 57 - view.autoplay = prop 58 - } 57 + Prop("autoplay") { view: BlueskyVideoView, prop: Boolean -> 58 + view.autoplay = prop 59 + } 59 60 60 - Prop("beginMuted") { view: BlueskyVideoView, prop: Boolean -> 61 - view.beginMuted = prop 62 - } 61 + Prop("beginMuted") { view: BlueskyVideoView, prop: Boolean -> 62 + view.beginMuted = prop 63 + } 63 64 64 - AsyncFunction("togglePlayback") { view: BlueskyVideoView -> 65 - view.togglePlayback() 66 - } 65 + AsyncFunction("togglePlayback") { view: BlueskyVideoView -> 66 + view.togglePlayback() 67 + } 67 68 68 - AsyncFunction("toggleMuted") { view: BlueskyVideoView -> 69 - view.toggleMuted() 70 - } 69 + AsyncFunction("toggleMuted") { view: BlueskyVideoView -> 70 + view.toggleMuted() 71 + } 71 72 72 - AsyncFunction("enterFullscreen") { view: BlueskyVideoView -> 73 - view.enterFullscreen() 74 - } 75 - } 76 - } 73 + AsyncFunction("enterFullscreen") { view: BlueskyVideoView -> 74 + view.enterFullscreen() 75 + } 76 + } 77 + } 77 78 }
+252 -236
android/src/main/java/expo/modules/blueskyvideo/BlueskyVideoView.kt
··· 16 16 import expo.modules.kotlin.viewevent.EventDispatcher 17 17 import expo.modules.kotlin.views.ExpoView 18 18 import expo.modules.video.ProgressTracker 19 - import kotlinx.coroutines.Dispatchers 20 - import kotlinx.coroutines.withContext 21 19 import kotlinx.coroutines.CoroutineScope 20 + import kotlinx.coroutines.Dispatchers 22 21 import kotlinx.coroutines.Job 23 22 import kotlinx.coroutines.launch 23 + import kotlinx.coroutines.withContext 24 24 import java.lang.ref.WeakReference 25 25 26 26 @UnstableApi 27 - class BlueskyVideoView(context: Context, appContext: AppContext) : ExpoView(context, appContext) { 28 - private val playerScope = CoroutineScope(Job() + Dispatchers.Main) 27 + class BlueskyVideoView( 28 + context: Context, 29 + appContext: AppContext, 30 + ) : ExpoView(context, appContext) { 31 + private val playerScope = CoroutineScope(Job() + Dispatchers.Main) 29 32 30 - private val playerView: PlayerView 31 - var player: ExoPlayer? = null 33 + private val playerView: PlayerView 34 + var player: ExoPlayer? = null 32 35 33 - private var progressTracker: ProgressTracker? = null 36 + private var progressTracker: ProgressTracker? = null 34 37 35 - var url: Uri? = null 36 - var autoplay = false 37 - var beginMuted = true 38 + var url: Uri? = null 39 + var autoplay = false 40 + var beginMuted = true 38 41 39 - private var isFullscreen: Boolean = false 40 - set(value) { 41 - field = value 42 - if (value) { 43 - this.playerView.useController = true 44 - this.playerView.player?.play() 45 - } else { 46 - this.playerView.useController = false 47 - } 48 - } 42 + private var isFullscreen: Boolean = false 43 + set(value) { 44 + field = value 45 + if (value) { 46 + this.playerView.useController = true 47 + this.playerView.player?.play() 48 + } else { 49 + this.playerView.useController = false 50 + } 51 + } 49 52 50 - private var isPlaying: Boolean = false 51 - set(value) { 52 - field = value 53 - onStatusChange(mapOf( 54 - "status" to if (value) "playing" else "paused" 55 - )) 56 - } 53 + private var isPlaying: Boolean = false 54 + set(value) { 55 + field = value 56 + onStatusChange( 57 + mapOf( 58 + "status" to if (value) "playing" else "paused", 59 + ), 60 + ) 61 + } 57 62 58 - private var isMuted: Boolean = false 59 - set(value) { 60 - field = value 61 - onMutedChange(mapOf( 62 - "isMuted" to value 63 - )) 64 - } 63 + private var isMuted: Boolean = false 64 + set(value) { 65 + field = value 66 + onMutedChange( 67 + mapOf( 68 + "isMuted" to value, 69 + ), 70 + ) 71 + } 65 72 66 - private var isLoading: Boolean = false 67 - set(value) { 68 - field = value 69 - onLoadingChange(mapOf( 70 - "isLoading" to value 71 - )) 72 - } 73 + private var isLoading: Boolean = false 74 + set(value) { 75 + field = value 76 + onLoadingChange( 77 + mapOf( 78 + "isLoading" to value, 79 + ), 80 + ) 81 + } 73 82 74 - private var isViewActive: Boolean = false 75 - set(value) { 76 - field = value 77 - onActiveChange(mapOf( 78 - "isActive" to value 79 - )) 80 - } 83 + private var isViewActive: Boolean = false 84 + set(value) { 85 + field = value 86 + onActiveChange( 87 + mapOf( 88 + "isActive" to value, 89 + ), 90 + ) 91 + } 81 92 82 - private val onActiveChange by EventDispatcher() 83 - private val onLoadingChange by EventDispatcher() 84 - private val onMutedChange by EventDispatcher() 85 - private val onPlayerPress by EventDispatcher() 86 - private val onStatusChange by EventDispatcher() 87 - private val onTimeRemainingChange by EventDispatcher() 88 - private val onError by EventDispatcher() 93 + private val onActiveChange by EventDispatcher() 94 + private val onLoadingChange by EventDispatcher() 95 + private val onMutedChange by EventDispatcher() 96 + private val onPlayerPress by EventDispatcher() 97 + private val onStatusChange by EventDispatcher() 98 + private val onTimeRemainingChange by EventDispatcher() 99 + private val onError by EventDispatcher() 89 100 90 - private var enteredFullscreenMuteState = true 101 + private var enteredFullscreenMuteState = true 91 102 92 - init { 93 - val playerView = PlayerView(context).apply { 94 - setBackgroundColor(Color.BLACK) 95 - resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM 96 - useController = false 97 - setOnClickListener { _ -> 98 - onPlayerPress(mapOf()) 99 - } 103 + init { 104 + val playerView = 105 + PlayerView(context).apply { 106 + setBackgroundColor(Color.BLACK) 107 + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM 108 + useController = false 109 + setOnClickListener { _ -> 110 + onPlayerPress(mapOf()) 111 + } 112 + } 113 + this.addView( 114 + playerView, 115 + ViewGroup.LayoutParams( 116 + ViewGroup.LayoutParams.MATCH_PARENT, 117 + ViewGroup.LayoutParams.MATCH_PARENT, 118 + ), 119 + ) 120 + this.playerView = playerView 100 121 } 101 - this.addView( 102 - playerView, 103 - ViewGroup.LayoutParams( 104 - ViewGroup.LayoutParams.MATCH_PARENT, 105 - ViewGroup.LayoutParams.MATCH_PARENT 106 - ) 107 - ) 108 - this.playerView = playerView 109 - } 110 122 111 - // Lifecycle 123 + // Lifecycle 112 124 113 - private fun setup() { 114 - // We shouldn't encounter this scenario, but would rather be safe than sorry here and just 115 - // skip setup if we do. 116 - if (this.player != null) { 117 - return 118 - } 125 + private fun setup() { 126 + // We shouldn't encounter this scenario, but would rather be safe than sorry here and just 127 + // skip setup if we do. 128 + if (this.player != null) { 129 + return 130 + } 119 131 120 - val player = this.createExoPlayer() 121 - this.player = player 122 - this.playerView.player = player 132 + val player = this.createExoPlayer() 133 + this.player = player 134 + this.playerView.player = player 123 135 124 - playerScope.launch { 125 - val mediaItem = createMediaItem() 126 - player.setMediaItem(mediaItem) 127 - player.prepare() 136 + playerScope.launch { 137 + val mediaItem = createMediaItem() 138 + player.setMediaItem(mediaItem) 139 + player.prepare() 140 + } 128 141 } 129 - } 130 142 131 - private fun destroy() { 132 - val player = this.player ?: return 143 + private fun destroy() { 144 + val player = this.player ?: return 133 145 134 - this.mute() 135 - this.pause() 136 - this.isLoading = true 146 + this.mute() 147 + this.pause() 148 + this.isLoading = true 137 149 138 - player.release() 139 - this.player = null 140 - this.playerView.player = null 141 - this.isLoading = false 142 - } 150 + player.release() 151 + this.player = null 152 + this.playerView.player = null 153 + this.isLoading = false 154 + } 143 155 144 - override fun onAttachedToWindow() { 145 - super.onAttachedToWindow() 146 - ViewManager.addView(this) 147 - } 156 + override fun onAttachedToWindow() { 157 + super.onAttachedToWindow() 158 + ViewManager.addView(this) 159 + } 148 160 149 - override fun onDetachedFromWindow() { 150 - super.onDetachedFromWindow() 151 - ViewManager.removeView(this) 152 - } 161 + override fun onDetachedFromWindow() { 162 + super.onDetachedFromWindow() 163 + ViewManager.removeView(this) 164 + } 153 165 154 - // Controls 155 - 156 - private fun play() { 157 - this.addProgressTracker() 158 - this.player?.play() 159 - this.isPlaying = true 160 - } 166 + // Controls 161 167 162 - private fun pause() { 163 - this.removeProgressTracker() 164 - this.player?.pause() 165 - this.isPlaying = false 166 - } 168 + private fun play() { 169 + this.addProgressTracker() 170 + this.player?.play() 171 + this.isPlaying = true 172 + } 167 173 168 - fun togglePlayback() { 169 - if (this.isPlaying) { 170 - pause() 171 - } else { 172 - play() 174 + private fun pause() { 175 + this.removeProgressTracker() 176 + this.player?.pause() 177 + this.isPlaying = false 173 178 } 174 - } 175 179 176 - private fun mute() { 177 - this.player?.volume = 0f 178 - this.isMuted = true 179 - } 180 - private fun unmute() { 181 - this.player?.volume = 1f 182 - this.isMuted = false 183 - } 184 - fun toggleMuted() { 185 - if (this.isMuted) { 186 - unmute() 187 - } else { 188 - mute() 180 + fun togglePlayback() { 181 + if (this.isPlaying) { 182 + pause() 183 + } else { 184 + play() 185 + } 189 186 } 190 - } 191 187 192 - fun enterFullscreen() { 193 - val currentActivity = this.appContext.currentActivity ?: return 188 + private fun mute() { 189 + this.player?.volume = 0f 190 + this.isMuted = true 191 + } 194 192 195 - this.enteredFullscreenMuteState = this.isMuted 193 + private fun unmute() { 194 + this.player?.volume = 1f 195 + this.isMuted = false 196 + } 196 197 197 - // We always want to start with unmuted state and playing. Fire those from here so the 198 - // event dispatcher gets called 199 - this.unmute() 200 - if (!this.isPlaying) { 201 - this.play() 198 + fun toggleMuted() { 199 + if (this.isMuted) { 200 + unmute() 201 + } else { 202 + mute() 203 + } 202 204 } 203 205 204 - // Remove the player from this view, but don't null the player! 205 - this.playerView.player = null 206 + fun enterFullscreen() { 207 + val currentActivity = this.appContext.currentActivity ?: return 206 208 207 - // create the intent and give it a view 208 - val intent = Intent(context, FullscreenActivity::class.java) 209 - FullscreenActivity.asscVideoView = WeakReference(this) 209 + this.enteredFullscreenMuteState = this.isMuted 210 210 211 - // fire the fullscreen event and launch the intent 212 - this.isFullscreen = true 213 - currentActivity.startActivity(intent) 214 - } 211 + // We always want to start with unmuted state and playing. Fire those from here so the 212 + // event dispatcher gets called 213 + this.unmute() 214 + if (!this.isPlaying) { 215 + this.play() 216 + } 215 217 216 - fun onExitFullscreen() { 217 - this.isFullscreen = false 218 - if (this.enteredFullscreenMuteState) { 219 - this.mute() 220 - } 221 - if(autoplay) { 222 - this.play() 223 - } else { 224 - this.pause() 225 - } 226 - this.playerView.player = this.player 227 - } 218 + // Remove the player from this view, but don't null the player! 219 + this.playerView.player = null 228 220 229 - // Visibility 221 + // create the intent and give it a view 222 + val intent = Intent(context, FullscreenActivity::class.java) 223 + FullscreenActivity.asscVideoView = WeakReference(this) 230 224 231 - fun setIsCurrentlyActive(isActive: Boolean): Boolean { 232 - if (this.isFullscreen) { 233 - return false 225 + // fire the fullscreen event and launch the intent 226 + this.isFullscreen = true 227 + currentActivity.startActivity(intent) 234 228 } 235 229 236 - this.isViewActive = isActive 237 - if (isActive) { 238 - this.setup() 239 - } else { 240 - this.destroy() 230 + fun onExitFullscreen() { 231 + this.isFullscreen = false 232 + if (this.enteredFullscreenMuteState) { 233 + this.mute() 234 + } 235 + if (autoplay) { 236 + this.play() 237 + } else { 238 + this.pause() 239 + } 240 + this.playerView.player = this.player 241 241 } 242 - return true 243 - } 244 242 245 - fun getPositionOnScreen(): Rect? { 246 - if (!this.isShown) { 247 - return null 248 - } 243 + // Visibility 249 244 250 - val screenPosition = intArrayOf(0, 0) 251 - this.getLocationInWindow(screenPosition) 252 - return Rect( 253 - screenPosition[0], 254 - screenPosition[1], 255 - screenPosition[0] + this.width, 256 - screenPosition[1] + this.height, 257 - ) 258 - } 245 + fun setIsCurrentlyActive(isActive: Boolean): Boolean { 246 + if (this.isFullscreen) { 247 + return false 248 + } 259 249 260 - fun isViewableEnough(): Boolean { 261 - val positionOnScreen = this.getPositionOnScreen() ?: return false 262 - val visibleArea = positionOnScreen.width() * positionOnScreen.height() 263 - val totalArea = this.width * this.height 264 - return visibleArea >= 0.5 * totalArea 265 - } 250 + this.isViewActive = isActive 251 + if (isActive) { 252 + this.setup() 253 + } else { 254 + this.destroy() 255 + } 256 + return true 257 + } 258 + 259 + fun getPositionOnScreen(): Rect? { 260 + if (!this.isShown) { 261 + return null 262 + } 266 263 267 - // Setup helpers 264 + val screenPosition = intArrayOf(0, 0) 265 + this.getLocationInWindow(screenPosition) 266 + return Rect( 267 + screenPosition[0], 268 + screenPosition[1], 269 + screenPosition[0] + this.width, 270 + screenPosition[1] + this.height, 271 + ) 272 + } 268 273 269 - private suspend fun createMediaItem(): MediaItem { 270 - return withContext(Dispatchers.IO) { 271 - MediaItem.Builder() 272 - .setUri(url.toString()) 273 - .build() 274 + fun isViewableEnough(): Boolean { 275 + val positionOnScreen = this.getPositionOnScreen() ?: return false 276 + val visibleArea = positionOnScreen.width() * positionOnScreen.height() 277 + val totalArea = this.width * this.height 278 + return visibleArea >= 0.5 * totalArea 274 279 } 275 - } 276 280 277 - private fun createExoPlayer(): ExoPlayer { 278 - return ExoPlayer.Builder(context) 279 - .apply { 280 - setLooper(context.mainLooper) 281 - setSeekForwardIncrementMs(5000) 282 - setSeekBackIncrementMs(5000) 283 - } 284 - .build().apply { 285 - repeatMode = ExoPlayer.REPEAT_MODE_ALL 286 - if (beginMuted) { 287 - volume = 0f 281 + // Setup helpers 282 + 283 + private suspend fun createMediaItem(): MediaItem = 284 + withContext(Dispatchers.IO) { 285 + MediaItem 286 + .Builder() 287 + .setUri(url.toString()) 288 + .build() 288 289 } 289 - addListener(object : Player.Listener { 290 - override fun onPlaybackStateChanged(playbackState: Int) { 291 - when (playbackState) { 292 - ExoPlayer.STATE_READY -> { 293 - val view = this@BlueskyVideoView 294 - if (view.autoplay) { 295 - view.isLoading = false 296 - view.play() 290 + 291 + private fun createExoPlayer(): ExoPlayer = 292 + ExoPlayer 293 + .Builder(context) 294 + .apply { 295 + setLooper(context.mainLooper) 296 + setSeekForwardIncrementMs(5000) 297 + setSeekBackIncrementMs(5000) 298 + }.build() 299 + .apply { 300 + repeatMode = ExoPlayer.REPEAT_MODE_ALL 301 + if (beginMuted) { 302 + volume = 0f 297 303 } 298 - } 304 + addListener( 305 + object : Player.Listener { 306 + override fun onPlaybackStateChanged(playbackState: Int) { 307 + when (playbackState) { 308 + ExoPlayer.STATE_READY -> { 309 + val view = this@BlueskyVideoView 310 + if (view.autoplay) { 311 + view.isLoading = false 312 + view.play() 313 + } 314 + } 315 + } 316 + } 317 + }, 318 + ) 299 319 } 300 - } 301 - }) 302 - } 303 - } 304 320 305 - private fun addProgressTracker() { 306 - val player = this.playerView.player ?: return 307 - this.progressTracker = ProgressTracker(player, onTimeRemainingChange) 308 - } 321 + private fun addProgressTracker() { 322 + val player = this.playerView.player ?: return 323 + this.progressTracker = ProgressTracker(player, onTimeRemainingChange) 324 + } 309 325 310 - private fun removeProgressTracker() { 311 - this.progressTracker?.remove() 312 - this.progressTracker = null 313 - } 326 + private fun removeProgressTracker() { 327 + this.progressTracker?.remove() 328 + this.progressTracker = null 329 + } 314 330 }
+37 -35
android/src/main/java/expo/modules/blueskyvideo/FullscreenActivity.kt
··· 10 10 import java.lang.ref.WeakReference 11 11 12 12 @UnstableApi 13 - class FullscreenActivity: AppCompatActivity() { 14 - companion object { 15 - var asscVideoView: WeakReference<BlueskyVideoView>? = null 16 - } 13 + class FullscreenActivity : AppCompatActivity() { 14 + companion object { 15 + var asscVideoView: WeakReference<BlueskyVideoView>? = null 16 + } 17 17 18 - override fun onCreate(savedInstanceState: Bundle?) { 19 - val player = asscVideoView?.get()?.player ?: return 18 + override fun onCreate(savedInstanceState: Bundle?) { 19 + val player = asscVideoView?.get()?.player ?: return 20 20 21 - super.onCreate(savedInstanceState) 21 + super.onCreate(savedInstanceState) 22 22 23 - this.window.setFlags( 24 - WindowManager.LayoutParams.FLAG_FULLSCREEN, 25 - WindowManager.LayoutParams.FLAG_FULLSCREEN 26 - ) 23 + this.window.setFlags( 24 + WindowManager.LayoutParams.FLAG_FULLSCREEN, 25 + WindowManager.LayoutParams.FLAG_FULLSCREEN, 26 + ) 27 27 28 - // Update the player viewz 29 - val playerView = PlayerView(this).apply { 30 - setBackgroundColor(Color.BLACK) 31 - setShowSubtitleButton(true) 32 - setShowNextButton(false) 33 - setShowPreviousButton(false) 34 - setFullscreenButtonClickListener { 35 - finish() 36 - } 28 + // Update the player viewz 29 + val playerView = 30 + PlayerView(this).apply { 31 + setBackgroundColor(Color.BLACK) 32 + setShowSubtitleButton(true) 33 + setShowNextButton(false) 34 + setShowPreviousButton(false) 35 + setFullscreenButtonClickListener { 36 + finish() 37 + } 37 38 38 - layoutParams = ViewGroup.LayoutParams( 39 - ViewGroup.LayoutParams.MATCH_PARENT, 40 - ViewGroup.LayoutParams.MATCH_PARENT 41 - ) 42 - useController = true 43 - controllerAutoShow = false 44 - controllerHideOnTouch = true 45 - } 46 - playerView.player = player 39 + layoutParams = 40 + ViewGroup.LayoutParams( 41 + ViewGroup.LayoutParams.MATCH_PARENT, 42 + ViewGroup.LayoutParams.MATCH_PARENT, 43 + ) 44 + useController = true 45 + controllerAutoShow = false 46 + controllerHideOnTouch = true 47 + } 48 + playerView.player = player 47 49 48 - setContentView(playerView) 49 - } 50 + setContentView(playerView) 51 + } 50 52 51 - override fun onDestroy() { 52 - asscVideoView?.get()?.onExitFullscreen() 53 - super.onDestroy() 54 - } 53 + override fun onDestroy() { 54 + asscVideoView?.get()?.onExitFullscreen() 55 + super.onDestroy() 56 + } 55 57 }
+22 -20
android/src/main/java/expo/modules/blueskyvideo/ProgressTracker.kt
··· 4 4 import android.os.Looper 5 5 import androidx.media3.common.Player 6 6 import androidx.media3.common.util.UnstableApi 7 - import kotlin.math.floor 8 7 import expo.modules.kotlin.viewevent.ViewEventCallback 8 + import kotlin.math.floor 9 9 10 10 @androidx.annotation.OptIn(UnstableApi::class) 11 11 class ProgressTracker( 12 - private val player: Player, 13 - private val onTimeRemainingChange: ViewEventCallback<Map<String, Any>> 12 + private val player: Player, 13 + private val onTimeRemainingChange: ViewEventCallback<Map<String, Any>>, 14 14 ) : Runnable { 15 - private val handler: Handler = Handler(Looper.getMainLooper()) 15 + private val handler: Handler = Handler(Looper.getMainLooper()) 16 16 17 - init { 18 - handler.post(this) 19 - } 17 + init { 18 + handler.post(this) 19 + } 20 20 21 - override fun run() { 22 - val currentPosition = player.currentPosition 23 - val duration = player.duration 24 - val timeRemaining = floor(((duration - currentPosition) / 1000).toDouble()) 25 - onTimeRemainingChange(mapOf( 26 - "timeRemaining" to timeRemaining 27 - )) 28 - handler.postDelayed(this, 1000) 29 - } 21 + override fun run() { 22 + val currentPosition = player.currentPosition 23 + val duration = player.duration 24 + val timeRemaining = floor(((duration - currentPosition) / 1000).toDouble()) 25 + onTimeRemainingChange( 26 + mapOf( 27 + "timeRemaining" to timeRemaining, 28 + ), 29 + ) 30 + handler.postDelayed(this, 1000) 31 + } 30 32 31 - fun remove() { 32 - handler.removeCallbacks(this) 33 - } 34 - } 33 + fun remove() { 34 + handler.removeCallbacks(this) 35 + } 36 + }
+64 -66
android/src/main/java/expo/modules/blueskyvideo/ViewManager.kt
··· 5 5 6 6 @UnstableApi 7 7 class ViewManager { 8 - companion object { 9 - private val views = mutableSetOf<BlueskyVideoView>() 10 - private var currentlyActiveView: BlueskyVideoView? = null 11 - private var prevCount = 0 8 + companion object { 9 + private val views = mutableSetOf<BlueskyVideoView>() 10 + private var currentlyActiveView: BlueskyVideoView? = null 11 + private var prevCount = 0 12 12 13 - fun addView(view: BlueskyVideoView) { 14 - views.add(view) 15 - if (prevCount == 0) { 16 - this.updateActiveView() 17 - } 18 - prevCount = views.count() 19 - } 13 + fun addView(view: BlueskyVideoView) { 14 + views.add(view) 15 + if (prevCount == 0) { 16 + this.updateActiveView() 17 + } 18 + prevCount = views.count() 19 + } 20 20 21 - fun removeView(view: BlueskyVideoView) { 22 - views.remove(view) 23 - prevCount = views.count() 24 - } 21 + fun removeView(view: BlueskyVideoView) { 22 + views.remove(view) 23 + prevCount = views.count() 24 + } 25 25 26 - fun updateActiveView() { 27 - var activeView: BlueskyVideoView? = null 28 - val count = views.count() 26 + fun updateActiveView() { 27 + var activeView: BlueskyVideoView? = null 28 + val count = views.count() 29 29 30 - if (count == 1) { 31 - val view = views.first() 32 - if (view.isViewableEnough()) { 33 - activeView = view 34 - } 35 - } else if (count > 1) { 36 - var mostVisibleView: BlueskyVideoView? = null 37 - var mostVisiblePosition: Rect? = null 30 + if (count == 1) { 31 + val view = views.first() 32 + if (view.isViewableEnough()) { 33 + activeView = view 34 + } 35 + } else if (count > 1) { 36 + var mostVisibleView: BlueskyVideoView? = null 37 + var mostVisiblePosition: Rect? = null 38 38 39 - views.forEach { view -> 40 - if (!view.isViewableEnough()) { 41 - return 42 - } 39 + views.forEach { view -> 40 + if (!view.isViewableEnough()) { 41 + return 42 + } 43 43 44 - val position = view.getPositionOnScreen() ?: return@forEach 45 - val topY = position.centerY() - (position.height() / 2) 44 + val position = view.getPositionOnScreen() ?: return@forEach 45 + val topY = position.centerY() - (position.height() / 2) 46 46 47 - if (topY >= 150) { 48 - if (mostVisiblePosition == null) { 49 - mostVisiblePosition = position 47 + if (topY >= 150) { 48 + if (mostVisiblePosition == null) { 49 + mostVisiblePosition = position 50 + } 51 + 52 + if (position.centerY() <= mostVisiblePosition!!.centerY()) { 53 + mostVisibleView = view 54 + mostVisiblePosition = position 55 + } 56 + } 57 + } 58 + 59 + activeView = mostVisibleView 60 + } 61 + 62 + if (activeView == currentlyActiveView) { 63 + return 50 64 } 51 65 52 - if (position.centerY() <= mostVisiblePosition!!.centerY()) { 53 - mostVisibleView = view 54 - mostVisiblePosition = position 66 + this.clearActiveView() 67 + if (activeView != null) { 68 + this.setActiveView(activeView) 55 69 } 56 - } 57 70 } 58 71 59 - activeView = mostVisibleView 60 - } 72 + private fun clearActiveView() { 73 + currentlyActiveView?.setIsCurrentlyActive(false) 74 + currentlyActiveView = null 75 + } 61 76 62 - if (activeView == currentlyActiveView) { 63 - return 64 - } 65 - 66 - this.clearActiveView() 67 - if (activeView != null) { 68 - this.setActiveView(activeView) 69 - } 70 - } 71 - 72 - private fun clearActiveView() { 73 - currentlyActiveView?.setIsCurrentlyActive(false) 74 - currentlyActiveView = null 75 - } 76 - 77 - private fun setActiveView(view: BlueskyVideoView) { 78 - val didSet = view.setIsCurrentlyActive(true) 79 - if (didSet) { 80 - currentlyActiveView = view 81 - } 82 - } 77 + private fun setActiveView(view: BlueskyVideoView) { 78 + val didSet = view.setIsCurrentlyActive(true) 79 + if (didSet) { 80 + currentlyActiveView = view 81 + } 82 + } 83 83 84 - fun getActiveView(): BlueskyVideoView? { 85 - return currentlyActiveView 84 + fun getActiveView(): BlueskyVideoView? = currentlyActiveView 86 85 } 87 - } 88 - } 86 + }