Skip to content

Commit

Permalink
Merge pull request #31 from azrael8576/feat/video-pip
Browse files Browse the repository at this point in the history
Implement Picture-in-Picture Mode in Video Module
  • Loading branch information
azrael8576 authored Dec 14, 2023
2 parents 1abb72e + 32cb4ab commit 9b82f03
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 103 deletions.
5 changes: 5 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,9 @@ dependencies {

// Timber
implementation(libs.timber)

// ExoPlayer
implementation(libs.media3.exoplayer)
implementation(libs.media3.exoplayer.dash)
implementation(libs.media3.ui)
}
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
100 changes: 61 additions & 39 deletions app/src/main/java/com/wei/picquest/ui/PqApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -119,24 +119,30 @@ fun PqApp(
SnackbarHost(
hostState = snackbarHostState,
snackbar = { snackbarData ->
if (!appState.isFullScreenCurrentDestination) {
val isError = snackbarData.visuals.message.startsWith(ErrorTextPrefix)
PqAppSnackbar(snackbarData, isError)
}
ConditionalContent(
condition = !appState.isInPictureInPicture && !appState.isFullScreenCurrentDestination,
content = {
val isError = snackbarData.visuals.message.startsWith(ErrorTextPrefix)
PqAppSnackbar(snackbarData, isError)
},
)
},
)
},
bottomBar = {
if (!appState.isFullScreenCurrentDestination &&
appState.navigationType == PqNavigationType.BOTTOM_NAVIGATION
) {
PqBottomBar(
destinations = appState.topLevelDestinations,
onNavigateToDestination = appState::navigateToTopLevelDestination,
currentDestination = appState.currentDestination,
modifier = Modifier.testTag(pqBottomBar),
)
}
ConditionalContent(
condition = !appState.isInPictureInPicture &&
!appState.isFullScreenCurrentDestination &&
appState.navigationType == PqNavigationType.BOTTOM_NAVIGATION,
content = {
PqBottomBar(
destinations = appState.topLevelDestinations,
onNavigateToDestination = appState::navigateToTopLevelDestination,
currentDestination = appState.currentDestination,
modifier = Modifier.testTag(pqBottomBar),
)
},
)
},
) { padding ->
Row(
Expand All @@ -150,32 +156,38 @@ fun PqApp(
),
),
) {
if (!appState.isFullScreenCurrentDestination &&
appState.navigationType == PqNavigationType.PERMANENT_NAVIGATION_DRAWER
) {
PqNavDrawer(
destinations = appState.topLevelDestinations,
onNavigateToDestination = appState::navigateToTopLevelDestination,
currentDestination = appState.currentDestination,
modifier = Modifier
.testTag(pqNavDrawer)
.padding(SPACING_LARGE.dp)
.safeDrawingPadding(),
)
}
ConditionalContent(
condition = !appState.isInPictureInPicture &&
!appState.isFullScreenCurrentDestination &&
appState.navigationType == PqNavigationType.PERMANENT_NAVIGATION_DRAWER,
content = {
PqNavDrawer(
destinations = appState.topLevelDestinations,
onNavigateToDestination = appState::navigateToTopLevelDestination,
currentDestination = appState.currentDestination,
modifier = Modifier
.testTag(pqNavDrawer)
.padding(SPACING_LARGE.dp)
.safeDrawingPadding(),
)
},
)

if (!appState.isFullScreenCurrentDestination &&
appState.navigationType == PqNavigationType.NAVIGATION_RAIL
) {
PqNavRail(
destinations = appState.topLevelDestinations,
onNavigateToDestination = appState::navigateToTopLevelDestination,
currentDestination = appState.currentDestination,
modifier = Modifier
.testTag(pqNavRail)
.safeDrawingPadding(),
)
}
ConditionalContent(
condition = !appState.isInPictureInPicture &&
!appState.isFullScreenCurrentDestination &&
appState.navigationType == PqNavigationType.NAVIGATION_RAIL,
content = {
PqNavRail(
destinations = appState.topLevelDestinations,
onNavigateToDestination = appState::navigateToTopLevelDestination,
currentDestination = appState.currentDestination,
modifier = Modifier
.testTag(pqNavRail)
.safeDrawingPadding(),
)
},
)

Column(
modifier = Modifier
Expand Down Expand Up @@ -258,6 +270,16 @@ private fun PqNavRail(
}
}

@Composable
fun ConditionalContent(
condition: Boolean,
content: @Composable () -> Unit,
) {
if (condition) {
content()
}
}

@Composable
private fun PqBottomBar(
destinations: List<TopLevelDestination>,
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/com/wei/picquest/ui/PqAppState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavDestination
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
Expand All @@ -25,6 +26,7 @@ import com.wei.picquest.core.designsystem.ui.PqNavigationType
import com.wei.picquest.core.designsystem.ui.currentDeviceOrientation
import com.wei.picquest.core.designsystem.ui.isBookPosture
import com.wei.picquest.core.designsystem.ui.isSeparating
import com.wei.picquest.core.pip.isInPictureInPictureMode
import com.wei.picquest.feature.contactme.contactme.navigation.contactMeRoute
import com.wei.picquest.feature.contactme.contactme.navigation.navigateToContactMe
import com.wei.picquest.feature.home.home.navigation.homeRoute
Expand Down Expand Up @@ -152,6 +154,9 @@ class PqAppState(
else -> false
}

val isInPictureInPicture: Boolean
@Composable get() = LocalContext.current.isInPictureInPictureMode

val currentTopLevelDestination: TopLevelDestination?
@Composable get() = when (currentDestination?.route) {
homeRoute -> TopLevelDestination.HOME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal fun Project.configureKotlinAndroid(
compileSdk = 34

defaultConfig {
minSdk = 21
minSdk = 26
}

compileOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.wei.picquest.core.pip

import android.app.Activity
import android.app.PictureInPictureParams
import android.content.Context
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.graphics.Rect
import android.os.Build
import android.util.Rational

fun updatedPipParams(
context: Context,
rect: Rect,
) {
if (!context.isPictureInPictureSupported) return

val aspect = Rational(rect.width(), rect.height())
val paramsBuilder = PictureInPictureParams.Builder()

if (aspect.toFloat() in 0.418410..2.390000) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
paramsBuilder.setAspectRatio(aspect)
paramsBuilder.setSourceRectHint(rect)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
paramsBuilder.setSeamlessResizeEnabled(true)
}
context.findActivity().setPictureInPictureParams(paramsBuilder.build())
}

@Suppress("DEPRECATION")
fun enterPictureInPicture(
context: Context,
) {
context.findActivity().enterPictureInPictureMode()
}

val Context.isPictureInPictureSupported: Boolean
get() {
return packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
}

val Context.isInPictureInPictureMode: Boolean
get() {
val currentActivity = findActivity()
return currentActivity.isInPictureInPictureMode
}

internal fun Context.findActivity(): Activity {
var context = this
while (context is ContextWrapper) {
if (context is Activity) return context
context = context.baseContext
}
throw IllegalStateException("Activity not found. Unknown error.")
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material.icons.rounded.Person
import androidx.compose.material.icons.rounded.Phone
import androidx.compose.material.icons.rounded.PhotoLibrary
import androidx.compose.material.icons.rounded.PictureInPicture
import androidx.compose.material.icons.rounded.Search
import androidx.compose.material.icons.rounded.Settings
import androidx.compose.material.icons.rounded.Star
Expand Down Expand Up @@ -59,4 +60,5 @@ object PqIcons {
val Add = Icons.Rounded.Add
val ListView = Icons.Rounded.List
val GridView = Icons.Rounded.GridView
val PictureInPicture = Icons.Rounded.PictureInPicture
}
3 changes: 2 additions & 1 deletion feature/video/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ android {
}

dependencies {
// Navigation

// ExoPlayer
implementation(libs.media3.exoplayer)
implementation(libs.media3.exoplayer.dash)
implementation(libs.media3.ui)
Expand Down
Loading

0 comments on commit 9b82f03

Please sign in to comment.