This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
restartable scheme("[androidx.compose.ui.UiComposable]") fun UserDetails( | |
unstable user: User | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data class User(val id: Long, val name: String, var isSelected: Boolean) | |
@Composable | |
fun UnstableClassUsageScreen(viewModel: TypicalViewModel = hiltViewModel()) { | |
val user by viewModel.user.collectAsStateWithLifecycle() | |
Box { | |
UserDetails(user) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object ImageCompressor { | |
/** | |
* @param context the application environment | |
* @param imageUri the input image uri. usually "content://..." | |
* @param imageFile file where the image was saved. For "photo from camera" scenarios. If it's | |
* null - we're creating the File inside the createFileAndCompress() | |
* @param compressFormat the output image file format | |
* @param maxWidth the output image max width | |
* @param maxHeight the output image max height |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
for i in `seq 1 100` | |
do | |
adb shell am force-stop com.smth.smth | |
sleep 1 | |
adb shell am start-activity -W -n com.smth.smth/.application.MainActivity | grep "TotalTime" | cut -d ' ' -f 2 | |
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
LaunchedEffect(isCurrentItemVisible.value) { | |
if (!isCurrentItemVisible.value && playingItemIndex != null) { | |
viewModel.onPlayVideoClick(exoPlayer.currentPosition, playingItemIndex!!) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private fun LazyListState.visibleAreaContainsItem( | |
currentlyPlayedIndex: Int?, | |
videos: List<VideoItem> | |
): Boolean { | |
return when { | |
currentlyPlayedIndex == null -> false | |
videos.isEmpty() -> false | |
else -> { | |
layoutInfo.visibleItemsInfo.map { videos[it.index] }.contains(videos[currentlyPlayedIndex]) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun VideosScreen(viewModel: VideosViewModel = hiltViewModel()) { | |
val listState = rememberLazyListState() | |
val playingItemIndex by viewModel.currentlyPlayingIndex.observeAsState() | |
var isCurrentItemVisible by remember { mutableStateOf(false) } | |
LaunchedEffect(Unit) { | |
snapshotFlow { | |
listState.visibleAreaContainsItem(playingItemIndex, videos) | |
}.collect { isItemVisible -> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DisposableEffect(exoPlayer) { | |
val lifecycleObserver = LifecycleEventObserver { _, event -> | |
if (playingItemIndex == null) return@LifecycleEventObserver | |
when (event) { | |
Lifecycle.Event.ON_START -> exoPlayer.play() | |
Lifecycle.Event.ON_STOP -> exoPlayer.pause() | |
} | |
} | |
lifecycleOwner.lifecycle.addObserver(lifecycleObserver) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
LaunchedEffect(playingItemIndex) { | |
if (playingItemIndex == null) { | |
exoPlayer.pause() | |
} else { | |
val video = videos[playingItemIndex] | |
exoPlayer.setMediaItem(MediaItem.fromUri(video.mediaUrl), video.lastPlayedPosition) | |
exoPlayer.prepare() | |
exoPlayer.playWhenReady = true | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun VideoPlayer( | |
exoPlayer: ExoPlayer, | |
onControllerVisibilityChanged: (uiVisible: Boolean) -> Unit | |
) { | |
val context = LocalContext.current | |
val playerView = remember { | |
val layout = LayoutInflater.from(context).inflate(R.layout.video_player, null, false) | |
val playerView = layout.findViewById(R.id.playerView) as PlayerView | |
playerView.apply { |