Skip to content

Commit

Permalink
Fix artwork video orientation bug (#21)
Browse files Browse the repository at this point in the history
* Parcelize Artwork

* Add seek position on exoplayer restore
  • Loading branch information
jocmp committed Oct 26, 2023
1 parent 203f904 commit 5961826
Show file tree
Hide file tree
Showing 24 changed files with 111 additions and 52 deletions.
5 changes: 1 addition & 4 deletions app/build.gradle
Expand Up @@ -4,7 +4,6 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.firebase.crashlytics'


Properties properties = new Properties()
if (rootProject.file("project.properties").exists()) {
properties.load(rootProject.file("project.properties").newDataInputStream())
Expand Down Expand Up @@ -85,7 +84,6 @@ dependencies {
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-video:${camerax_version}"

implementation "androidx.camera:camera-view:${camerax_version}"
implementation "androidx.camera:camera-extensions:${camerax_version}"
implementation 'androidx.camera:camera-view:1.0.0-alpha23'
Expand All @@ -100,10 +98,9 @@ dependencies {
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "androidx.compose.ui:ui-util:$compose_version"
implementation "androidx.datastore:datastore-preferences:$datastore_version"
implementation "androidx.navigation:navigation-compose:2.4.0-rc01"
implementation "androidx.navigation:navigation-compose:2.7.4"
implementation 'com.google.mlkit:barcode-scanning:17.0.2'
implementation "com.github.Tlaster:Swiper:0.7.1"
implementation "com.google.accompanist:accompanist-navigation-animation:$accompanist_version"
implementation "com.google.accompanist:accompanist-pager-indicators:$accompanist_version"
implementation "com.google.accompanist:accompanist-pager:$accompanist_version"
implementation "com.google.accompanist:accompanist-permissions:$accompanist_version"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/edu/gvsu/art/gallery/MainActivity.kt
Expand Up @@ -22,6 +22,7 @@ import androidx.navigation.compose.rememberNavController
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import edu.gvsu.art.gallery.ui.*
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen
import edu.gvsu.art.gallery.ui.theme.ArtAtGVSUTheme

@ExperimentalPagerApi
Expand Down
Expand Up @@ -14,9 +14,9 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import edu.gvsu.art.client.Artist
import edu.gvsu.art.gallery.TitleText
import edu.gvsu.art.gallery.lib.Async
import edu.gvsu.art.gallery.navigateToArtworkDetail
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen
import edu.gvsu.art.gallery.ui.theme.ArtAtGVSUTheme

@Composable
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/edu/gvsu/art/gallery/ui/ArtistEffects.kt
Expand Up @@ -20,6 +20,6 @@ fun useArtist(id: String): Async<Artist> {
)
}
}
Log.d("artist", "returned state")

return state.value
}
10 changes: 2 additions & 8 deletions app/src/main/java/edu/gvsu/art/gallery/ui/ArtworkDetailScreen.kt
Expand Up @@ -29,10 +29,10 @@ import edu.gvsu.art.client.Artwork
import edu.gvsu.art.gallery.DetailDivider
import edu.gvsu.art.gallery.R
import edu.gvsu.art.gallery.extensions.openGoogleMaps
import edu.gvsu.art.gallery.lib.Async
import edu.gvsu.art.gallery.lib.MediaTypes
import edu.gvsu.art.gallery.navigateToArtistDetail
import edu.gvsu.art.gallery.navigateToArtworkDetail
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen
import edu.gvsu.art.gallery.ui.foundation.rememberRemoteImage
import edu.gvsu.art.gallery.ui.theme.ArtAtGVSUTheme
import java.net.URL
Expand All @@ -45,13 +45,7 @@ import java.net.URL
fun ArtworkDetailScreen(navController: NavController, artworkID: String?) {
artworkID ?: return Column {}
val (isFavorite, toggleFavorite) = useFavorite(artworkID = artworkID)
val (data) = useArtwork(id = artworkID)

val (artwork, loading) = when (data) {
is Async.Success -> Pair(data(), false)
is Async.Loading -> Pair(Artwork(), true)
else -> Pair(Artwork(), false)
}
val (artwork, loading) = useArtwork(id = artworkID)

ArtworkView(
navController = navController,
Expand Down
Expand Up @@ -14,7 +14,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import edu.gvsu.art.client.Artwork
import edu.gvsu.art.gallery.TitleText
import edu.gvsu.art.gallery.extensions.shareArtwork
import edu.gvsu.art.gallery.ui.theme.ArtAtGVSUTheme
import edu.gvsu.art.gallery.ui.theme.Red
Expand Down
27 changes: 23 additions & 4 deletions app/src/main/java/edu/gvsu/art/gallery/ui/ArtworkEffects.kt
@@ -1,6 +1,7 @@
package edu.gvsu.art.gallery.ui

import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import edu.gvsu.art.client.Artwork
import edu.gvsu.art.client.repository.ArtworkRepository
import edu.gvsu.art.client.repository.ArtworkSearchRepository
Expand All @@ -9,10 +10,6 @@ import edu.gvsu.art.gallery.lib.Async
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

@Composable
fun useArtwork(id: String) = useKeyedRepositoryResource(fetch = {
get<ArtworkRepository>().find(id)
})

@Composable
fun useFavorite(artworkID: String): Pair<Boolean, () -> Unit> {
Expand All @@ -28,6 +25,28 @@ fun useFavorite(artworkID: String): Pair<Boolean, () -> Unit> {
return Pair(isFavorite, { setFavorite(repository.toggle(artworkID)) })
}

@Composable
fun useArtwork(id: String): Pair<Artwork, Boolean> {
val artwork = rememberSaveable(id) { mutableStateOf<Artwork?>(null) }

artwork.value?.let {
return Pair(it, false)
}

val (result) = useKeyedRepositoryResource(fetch = {
get<ArtworkRepository>().find(id)
})

LaunchedEffect(result) {
when (result) {
is Async.Success -> artwork.value = result()
else -> {}
}
}

return Pair(Artwork(), true)
}

@Composable
fun useFeaturedArtworks(): Async<List<Artwork>> {
val state = produceState<Async<List<Artwork>>>(initialValue = Async.Uninitialized) {
Expand Down
Expand Up @@ -22,8 +22,10 @@ fun ArtworkMediaDialog(
selectedPage: Int,
onDismiss: () -> Unit = {},
) {
Dialog(onDismissRequest = { onDismiss() },
properties = DialogProperties(usePlatformDefaultWidth = false)) {
Dialog(
onDismissRequest = { onDismiss() },
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
Scaffold(backgroundColor = Color.Transparent) {
MediaScreen(
urls = artwork.mediaRepresentations,
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/edu/gvsu/art/gallery/ui/BrowseScreen.kt
Expand Up @@ -31,6 +31,7 @@ import edu.gvsu.art.gallery.R
import edu.gvsu.art.gallery.Route
import edu.gvsu.art.gallery.lib.Async
import edu.gvsu.art.gallery.navigateToArtworkDetail
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen
import edu.gvsu.art.gallery.ui.foundation.rememberRemoteImage
import edu.gvsu.art.gallery.ui.theme.OffWhite
import edu.gvsu.art.gallery.ui.theme.OffWhiteSecondary
Expand Down
Expand Up @@ -21,6 +21,7 @@ import edu.gvsu.art.gallery.R
import edu.gvsu.art.gallery.Route
import edu.gvsu.art.gallery.lib.Async
import edu.gvsu.art.gallery.navigateToArtworkDetail
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen

@Composable
fun FeaturedArtIndexScreen(navController: NavController) {
Expand Down
Expand Up @@ -23,6 +23,7 @@ import edu.gvsu.art.gallery.R
import edu.gvsu.art.gallery.lib.Async
import edu.gvsu.art.gallery.navigateToArtworkDetail
import edu.gvsu.art.gallery.navigateToLocation
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen
import edu.gvsu.art.gallery.ui.theme.ArtAtGVSUTheme

@Composable
Expand Down
58 changes: 38 additions & 20 deletions app/src/main/java/edu/gvsu/art/gallery/ui/MediaView.kt
Expand Up @@ -7,6 +7,10 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
Expand All @@ -20,6 +24,7 @@ import com.google.accompanist.pager.PagerState
import com.mxalbert.zoomable.Zoomable
import edu.gvsu.art.gallery.lib.MediaTypes
import edu.gvsu.art.gallery.ui.foundation.VideoPlayer
import edu.gvsu.art.gallery.ui.foundation.VideoPlayerState
import edu.gvsu.art.gallery.ui.foundation.rememberRemoteImage
import edu.gvsu.art.gallery.ui.foundation.rememberVideoPlayerState
import moe.tlaster.swiper.Swiper
Expand All @@ -37,12 +42,27 @@ fun MediaView(
videoControlVisibility: Boolean,
onClick: () -> Unit,
) {
val (videoUrl, setVideoUrl) = remember { mutableStateOf<URL?>(null)}
val videoState = rememberVideoPlayerState(
url = videoUrl?.toString()
)

LaunchedEffect(pagerState.currentPage) {
val url = urls[pagerState.currentPage]

if (MediaTypes.isVideo(url)) {
setVideoUrl(url)
} else {
setVideoUrl(null)
}
}

Swiper(state = swiperState) {
HorizontalPager(
itemSpacing = 8.dp,
count = urls.size,
state = pagerState,
key = { urls[it] }
key = { urls[it] },
) { page ->
val url = urls[page]
if (MediaTypes.isVideo(url)) {
Expand All @@ -51,25 +71,22 @@ fun MediaView(
onTap = { onClick() }
)
}) {
val videoState = rememberVideoPlayerState(
url = url.toString(),
volume = volume,
isMute = false
)
VideoPlayer(
playEnable = currentPage == page,
videoState = videoState,
zOrderMediaOverlay = true,
keepScreenOn = true,
backgroundColor = Color.Blue,
)
AnimatedVisibility(
visible = videoControlVisibility,
enter = fadeIn() + expandVertically(),
exit = shrinkVertically() + fadeOut(),
modifier = Modifier.align(Alignment.BottomStart)
) {
VideoControl(state = videoState)
videoState?.let {
VideoPlayer(
playEnable = true,
videoState = it,
zOrderMediaOverlay = true,
keepScreenOn = true,
backgroundColor = Color.Blue,
)
AnimatedVisibility(
visible = videoControlVisibility,
enter = fadeIn() + expandVertically(),
exit = shrinkVertically() + fadeOut(),
modifier = Modifier.align(Alignment.BottomStart)
) {
VideoControl(state = it)
}
}
}
} else {
Expand All @@ -80,6 +97,7 @@ fun MediaView(
}
}
}

@Composable
private fun RemoteImage(url: URL) {
val modifier = Modifier.fillMaxSize()
Expand Down
1 change: 0 additions & 1 deletion app/src/main/java/edu/gvsu/art/gallery/ui/QRScanner.kt
Expand Up @@ -25,7 +25,6 @@ class QRScanner(val callback: QRCodeFoundCallback) : ImageAnalysis.Analyzer {
barcodeScanner.process(inputImage)
.addOnSuccessListener { barcodes ->
barcodes.firstOrNull()?.let { qrCode ->
Log.d("URL scanned", qrCode.url?.url.toString())
qrCode.url?.url?.let { callback(it) }
}
}.addOnCompleteListener {
Expand Down
Expand Up @@ -39,6 +39,7 @@ import edu.gvsu.art.gallery.R
import edu.gvsu.art.gallery.lib.Links
import edu.gvsu.art.gallery.navigateToArtistDetail
import edu.gvsu.art.gallery.navigateToArtworkDetail
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen

@ExperimentalPermissionsApi
@ExperimentalComposeUiApi
Expand Down
@@ -1,4 +1,4 @@
package edu.gvsu.art.gallery
package edu.gvsu.art.gallery.ui

import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
Expand Down
Expand Up @@ -34,6 +34,7 @@ import edu.gvsu.art.client.TourStop
import edu.gvsu.art.gallery.R
import edu.gvsu.art.gallery.lib.Async
import edu.gvsu.art.gallery.navigateToArtworkDetail
import edu.gvsu.art.gallery.ui.foundation.LocalTabScreen
import edu.gvsu.art.gallery.ui.foundation.rememberRemoteImage
import edu.gvsu.art.gallery.ui.theme.LightBlue
import edu.gvsu.art.gallery.ui.theme.Shapes
Expand Down
@@ -1,4 +1,4 @@
package edu.gvsu.art.gallery.ui
package edu.gvsu.art.gallery.ui.foundation

import androidx.compose.runtime.compositionLocalOf
import edu.gvsu.art.gallery.TabScreen
Expand Down
Expand Up @@ -81,7 +81,8 @@ class PlayerView constructor(
}
}

fun play() {
fun play(seekPosition: Long? = null) {
seekPosition?.let { seekTo(it) }
androidPlayer.player?.playWhenReady = true
androidPlayer.onResume()
}
Expand Down
Expand Up @@ -9,13 +9,17 @@ import androidx.compose.runtime.saveable.rememberSaveable

@Composable
fun rememberVideoPlayerState(
url: String,
url: String?,
isPlaying: Boolean = false,
volume: Float = 1f,
isReady: Boolean = false,
currentPosition: Long = 0L,
isMute: Boolean = false,
): VideoPlayerState {
): VideoPlayerState? {
if (url.isNullOrEmpty()) {
return null
}

return rememberSaveable(
saver = VideoPlayerState.Saver(url),
key = url
Expand Down Expand Up @@ -155,7 +159,7 @@ class VideoPlayerState(
internal fun onResume() {
player.registerProgressCallback(progressCallBack)
player.registerPlayerCallback(playerCallBack)
if (isPlaying) player.play()
if (isPlaying) player.play(seekPosition = currentPosition)
}

internal fun onPause() {
Expand Down
10 changes: 8 additions & 2 deletions artgalleryclient/build.gradle.kts
@@ -1,7 +1,13 @@
plugins {
id("java-library")
id("kotlin")
id("com.android.library")
id("kotlin-android")
id("com.squareup.sqldelight")
id("org.jetbrains.kotlin.plugin.parcelize")
}

android {
namespace = "edu.gvsu.art.client"
compileSdkVersion = "android-34"
}

sqldelight {
Expand Down
3 changes: 3 additions & 0 deletions artgalleryclient/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
@@ -1,7 +1,10 @@
package edu.gvsu.art.client

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.net.URL

@Parcelize
data class Artwork(
val id: String = "",
val isPublic: Boolean = true,
Expand All @@ -22,7 +25,7 @@ data class Artwork(
val mediaMedium: URL? = null,
val mediaLarge: URL? = null,
val thumbnail: URL? = null
) {
) : Parcelable {
val formattedArtistName: String
get() {
return if (artistName.isNotBlank()) {
Expand Down
@@ -1,6 +1,10 @@
package edu.gvsu.art.client

data class LatLng(val latitude: Double, val longitude: Double) {
import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class LatLng(val latitude: Double, val longitude: Double): Parcelable {
companion object {
fun fromCoordinates(latitude: Double?, longitude: Double?): LatLng? {
if (latitude == null || longitude == null) {
Expand Down

0 comments on commit 5961826

Please sign in to comment.