Compare commits

...

3 Commits

Author SHA1 Message Date
Stefan Schüller 595ad702f8 feat: Miniplayer work 2022-05-01 14:08:07 +02:00
Stefan Schüller 9c45c76ec0 feat: Updated exoplayer 2022-04-30 14:47:44 +02:00
Stefan Schüller 528132c47d feat: Updated libraries 2022-04-30 13:20:58 +02:00
11 changed files with 201 additions and 249 deletions

View File

@ -28,7 +28,7 @@ x CI pipeline (gradle?)
- add themes and selection
- Add NSFW filter
- Translate all strings
- Swipe player down and up
- Swipe miniplayer down and up
- implement preferences using data stores
Issues:
@ -40,4 +40,5 @@ x Refreshing video list causes odd loading order of video items
- playback rotate on click doesn't re-hide buttons
- Explore list is memory intensive, leak??
- Access Token refresh circular injection problem
- app crashes when clicking items in background list while player is visible (minimode)
x app crashes when clicking items in background list while player is visible (minimode)
- Opening more in player stops player in background

View File

@ -55,6 +55,12 @@ android {
vectorDrawables {
useSupportLibrary true
}
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
signingConfigs {
release {
@ -111,12 +117,12 @@ dependencies {
implementation 'com.google.android.material:material:1.5.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.material3:material3:1.0.0-alpha04"
implementation "androidx.compose.material3:material3:1.0.0-alpha10"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation 'androidx.activity:activity-compose:1.4.0'
testImplementation 'junit:junit:4.+'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
@ -129,14 +135,17 @@ dependencies {
implementation 'org.ocpsoft.prettytime:prettytime:4.0.4.Final'
// Vide playback
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-core:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-hls:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.16.1'
implementation "com.google.android.exoplayer:exoplayer:$exo_player_version"
implementation "com.google.android.exoplayer:exoplayer-core:$exo_player_version"
implementation "com.google.android.exoplayer:exoplayer-hls:$exo_player_version"
implementation "com.google.android.exoplayer:exoplayer-dash:$exo_player_version"
implementation "com.google.android.exoplayer:exoplayer-rtsp:$exo_player_version"
implementation "com.google.android.exoplayer:exoplayer-transformer:$exo_player_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exo_player_version"
// Compose dependencies
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4"
implementation "androidx.navigation:navigation-compose:2.5.0-alpha01"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1"
implementation "androidx.navigation:navigation-compose:2.5.0-beta01"
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0"
implementation "com.google.accompanist:accompanist-flowlayout:0.17.0"
@ -158,12 +167,12 @@ dependencies {
implementation 'com.google.accompanist:accompanist-swiperefresh:0.22.0-rc'
// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
// Coroutine Lifecycle Scopes
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.40.5"
@ -176,10 +185,10 @@ dependencies {
// Retrofit
// http client / REST
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.3'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.2"
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.3"
implementation "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2"
}

View File

@ -108,10 +108,11 @@ fun VideoListScreen(
bottomBar = {
BottomBarComponent(navController)
}
) {
// Pull to refresh
) { contentPadding ->
// Pull to refresh
// TODO: fix appbar blank issue
SwipeRefresh(
modifier = Modifier.padding(contentPadding),
state = rememberSwipeRefreshState(
isRefreshing = (lazyVideoItems.loadState.refresh is LoadState.Loading) || (lazyVideoExploreItems.loadState.refresh is LoadState.Loading)
),

View File

@ -221,6 +221,12 @@ class VideoPlayViewModel @Inject constructor(
_eventFlow.emit(UiEvent.ShowMore)
}
}
is VideoPlayEvent.MiniPlayerButton -> {
Log.v("VPVM", "Video Miniplayer Pressed")
viewModelScope.launch {
_eventFlow.emit(UiEvent.ShowMiniPlayer)
}
}
is VideoPlayEvent.PlayVideo -> {
// Load new video
getVideo(event.video.uuid)
@ -259,5 +265,7 @@ class VideoPlayViewModel @Inject constructor(
object HideDescription : UiEvent()
object ShowMore : UiEvent()
object HideMore : UiEvent()
object ShowMiniPlayer : UiEvent()
object HideMiniPlayer : UiEvent()
}
}

View File

@ -27,7 +27,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.*
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemsIndexed
@ -53,10 +52,11 @@ fun VideoPlayScreen(
val state = videoPlayViewModel.state.value
val context = LocalContext.current
var miniPlayerVisible by remember { mutableStateOf(false) }
var descriptionVisible by remember { mutableStateOf(false) }
var moreVisible by remember { mutableStateOf(false) }
// Show toasts
LaunchedEffect(key1 = true) {
videoPlayViewModel.eventFlow.collectLatest { event ->
when(event) {
@ -79,6 +79,12 @@ fun VideoPlayScreen(
is VideoPlayViewModel.UiEvent.HideMore -> {
moreVisible = false
}
is VideoPlayViewModel.UiEvent.ShowMiniPlayer -> {
miniPlayerVisible = true
}
is VideoPlayViewModel.UiEvent.HideMiniPlayer -> {
miniPlayerVisible = false
}
}
}
}
@ -95,9 +101,9 @@ fun VideoPlayScreen(
val configuration = LocalConfiguration.current
var animateToEnd by remember { mutableStateOf(false) }
val progress by animateFloatAsState(
targetValue = if (animateToEnd) 1f else 0f,
targetValue = if (miniPlayerVisible) 1f else 0f,
animationSpec = tween(250)
)
@ -239,8 +245,10 @@ fun VideoPlayScreen(
Box(
modifier = Modifier
.layoutId("background", "box")
.background(Color.Blue)
.clickable(onClick = { animateToEnd = !animateToEnd })
.background(Color.White)
.clickable(onClick = {
miniPlayerVisible = false
})
)
VideoScreen(exoPlayerHolder, video,
@ -252,7 +260,9 @@ fun VideoPlayScreen(
Text(
text = "MotionLayout in Compose",
modifier = Modifier.layoutId("title")
.clickable(onClick = { animateToEnd = !animateToEnd }),
.clickable(onClick = {
miniPlayerVisible = false
}),
color = MaterialTheme.colors.onBackground,
fontSize = motionProperties("title").value.fontSize("textSize")
)
@ -379,7 +389,12 @@ fun VideoPlayScreen(
}
BackHandler(enabled = true) {
Log.v("back", "back pressed")
videoPlayViewModel.playerVisible.value = false
if (!miniPlayerVisible) {
miniPlayerVisible = true;
} else {
videoPlayViewModel.playerVisible.value = false
}
}
}

View File

@ -16,6 +16,7 @@ import android.widget.FrameLayout
import android.widget.ImageButton
import androidx.compose.ui.platform.LocalConfiguration
import androidx.hilt.navigation.compose.hiltViewModel
import com.google.android.exoplayer2.ui.StyledPlayerView
import net.schueller.peertube.R
import net.schueller.peertube.feature_video.presentation.video.events.VideoPlayEvent
import net.schueller.peertube.feature_video.presentation.video.VideoPlayViewModel
@ -58,7 +59,7 @@ fun VideoScreen(
Log.v("VideoScreen", "playerView assign")
PlayerView.switchTargetView(
StyledPlayerView.switchTargetView(
player,
PlayerViewPool.currentPlayerView,
playerView
@ -78,13 +79,19 @@ fun VideoScreen(
// Video More Button
val videoMoreButton = playerView.findViewById<FrameLayout>(R.id.exo_more_button)
val videoMoreButton = playerView.findViewById<ImageButton>(R.id.exo_more)
videoMoreButton.setOnClickListener {
viewModel.onEvent(VideoPlayEvent.MoreButton)
}
Log.v("VideoScreen", "videoMoreButton")
// Video MiniPlayer Button
val videoMiniplayerButton = playerView.findViewById<ImageButton>(R.id.exo_miniplayer)
videoMiniplayerButton.setOnClickListener {
viewModel.onEvent(VideoPlayEvent.MiniPlayerButton)
}
// TODO: does not update on orientation gesture
val enterFullscreenIcon = playerView.findViewById<ImageButton>(R.id.exo_fullscreen_enable)

View File

@ -13,6 +13,7 @@ sealed class VideoPlayEvent {
data class OpenDescription(val video: Video): VideoPlayEvent()
object CloseDescription: VideoPlayEvent()
object MoreButton: VideoPlayEvent()
object MiniPlayerButton: VideoPlayEvent()
data class PlayVideo(val video: Video): VideoPlayEvent()
object CloseVideo: VideoPlayEvent()
}

View File

@ -4,22 +4,23 @@ import android.content.Context
import android.view.LayoutInflater
import androidx.core.util.Pools
import com.google.android.exoplayer2.ui.PlayerView
import com.google.android.exoplayer2.ui.StyledPlayerView
import net.schueller.peertube.R
object PlayerViewPool {
var currentPlayerView: PlayerView? = null
var currentPlayerView: StyledPlayerView? = null
private val playerViewPool = Pools.SimplePool<PlayerView>(2)
private val playerViewPool = Pools.SimplePool<StyledPlayerView>(2)
fun get(context: Context): PlayerView {
fun get(context: Context): StyledPlayerView {
return playerViewPool.acquire() ?: createPlayerView(context)
}
fun release(player: PlayerView) {
fun release(player: StyledPlayerView) {
playerViewPool.release(player)
}
private fun createPlayerView(context: Context): PlayerView {
return (LayoutInflater.from(context).inflate(R.layout.exoplayer_texture_view, null, false) as PlayerView)
private fun createPlayerView(context: Context): StyledPlayerView {
return (LayoutInflater.from(context).inflate(R.layout.exoplayer_texture_view, null, false) as StyledPlayerView)
}
}

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.exoplayer2.ui.PlayerView xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.exoplayer2.ui.StyledPlayerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -11,6 +13,7 @@
app:show_buffering="when_playing"
app:shutter_background_color="@android:color/black"
app:surface_type="surface_view"
app:show_subtitle_button="true"
app:use_controller="true"
android:animateLayoutChanges="true"
app:controller_layout_id="@layout/video_playback_controls"

View File

@ -1,230 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#CC000000"
android:layoutDirection="ltr"
android:orientation="vertical"
tools:targetApi="32">
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:id="@+id/exo_more_button"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="end">
<View android:id="@id/exo_controls_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@color/exo_black_opacity_60"/>
<ImageButton
android:clickable="false"
android:id="@+id/exo_more"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="@android:color/transparent"
android:contentDescription="More"
android:src="@drawable/ic_more_vertical"
/>
<FrameLayout android:id="@id/exo_bottom_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/exo_styled_bottom_bar_height"
android:layout_marginTop="@dimen/exo_styled_bottom_bar_margin_top"
android:layout_gravity="bottom"
android:background="@color/exo_bottom_bar_background"
android:layoutDirection="ltr">
<LinearLayout android:id="@id/exo_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingEnd="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingLeft="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingRight="@dimen/exo_styled_bottom_bar_time_padding"
android:layout_gravity="center_vertical|start"
android:layoutDirection="ltr">
<TextView android:id="@id/exo_position"
style="@style/ExoStyledControls.TimeText.Position"/>
<TextView
style="@style/ExoStyledControls.TimeText.Separator"/>
<TextView android:id="@id/exo_duration"
style="@style/ExoStyledControls.TimeText.Duration"/>
</LinearLayout>
<LinearLayout android:id="@id/exo_basic_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:layoutDirection="ltr">
<ImageButton android:id="@+id/exo_more"
style="@style/ExoStyledControls.Button.Bottom.Settings"/>
<ImageButton android:id="@+id/exo_miniplayer"
style="@style/ExoStyledControls.Button.Bottom.OverflowHide"/>
<FrameLayout
android:id="@+id/exo_fullscreen_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end">
<ImageButton
android:clickable="false"
android:id="@+id/exo_fullscreen_enable"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="@android:color/transparent"
android:contentDescription="Fullscreen"
android:src="@drawable/ic_maximize"
android:visibility="gone"
/>
<ImageButton
android:clickable="false"
android:id="@+id/exo_fullscreen_disable"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="@android:color/transparent"
android:contentDescription="Exit Fullscreen"
android:src="@drawable/ic_maximize"
android:visibility="gone"
/>
</FrameLayout>
</LinearLayout>
</FrameLayout>
<Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
/>
<LinearLayout
<View android:id="@id/exo_progress_placeholder"
android:layout_width="match_parent"
android:layout_height="@dimen/exo_styled_progress_layout_height"
android:layout_gravity="bottom"
android:layout_marginBottom="@dimen/exo_styled_progress_margin_bottom"/>
<LinearLayout android:id="@id/exo_minimal_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/exo_styled_minimal_controls_margin_bottom"
android:orientation="horizontal"
android:paddingTop="8dp">
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageButton
android:id="@id/exo_rew"
android:layout_width="72sp"
android:layout_height="52sp"
android:layout_gravity="start"
android:background="@android:color/transparent"
android:contentDescription="@string/exo_controls_rewind_description"
android:scaleType="center"
android:src="@drawable/ic_rewind" />
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageButton
android:id="@id/exo_repeat_toggle"
style="@style/ExoMediaButton" />
android:gravity="center_vertical"
android:layoutDirection="ltr">
<ImageButton
android:id="@id/exo_play"
android:contentDescription="@string/exo_controls_play_description"
android:src="@drawable/ic_play"
android:layout_height="52sp"
android:layout_width="72sp"
android:scaleType="center"
android:background="@android:color/transparent"
/>
<ImageButton android:id="@id/exo_minimal_fullscreen"
style="@style/ExoStyledControls.Button.Bottom.FullScreen"/>
<ImageButton
android:id="@id/exo_pause"
android:contentDescription="@string/exo_controls_pause_description"
android:src="@drawable/ic_pause"
android:layout_height="52sp"
android:layout_width="72sp"
android:scaleType="center"
android:background="@android:color/transparent"
/>
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageButton
android:id="@id/exo_ffwd"
android:layout_width="72sp"
android:layout_height="52sp"
android:layout_gravity="end"
android:background="@android:color/transparent"
android:contentDescription="@string/exo_controls_fastforward_description"
android:scaleType="center"
android:src="@drawable/ic_fast_forward" />
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<Space
<LinearLayout
android:id="@id/exo_center_controls"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:gravity="bottom"
android:orientation="horizontal">
android:layout_gravity="center"
android:background="@android:color/transparent"
android:gravity="center"
android:padding="@dimen/exo_styled_controls_padding">
<TextView
android:id="@id/exo_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:layout_gravity="center"
android:paddingStart="12dp"
android:paddingEnd="2dp"
android:textColor="#FFFFFF"
android:textSize="14sp" />
<ImageButton android:id="@id/exo_rew"
style="@style/ExoStyledControls.Button.Center.RewWithAmount"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#BABABA"
android:textSize="14sp"
android:includeFontPadding="false"
android:text="@string/player_time_seperator" />
<ImageButton android:id="@id/exo_play_pause"
style="@style/ExoStyledControls.Button.Center.PlayPause"/>
<TextView
android:id="@id/exo_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:includeFontPadding="false"
android:paddingStart="2dp"
android:paddingEnd="6dp"
android:textColor="#BABABA"
android:textSize="14sp" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
android:id="@+id/exo_fullscreen_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end">
<ImageButton
android:clickable="false"
android:id="@+id/exo_fullscreen_enable"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="@android:color/transparent"
android:contentDescription="Fullscreen"
android:src="@drawable/ic_maximize"
android:visibility="gone"
/>
<ImageButton
android:clickable="false"
android:id="@+id/exo_fullscreen_disable"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="@android:color/transparent"
android:contentDescription="Exit Fullscreen"
android:src="@drawable/ic_maximize"
android:visibility="gone"
/>
</FrameLayout>
<ImageButton android:id="@id/exo_ffwd"
style="@style/ExoStyledControls.Button.Center.FfwdWithAmount"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-12dp"
android:gravity="bottom"
android:orientation="horizontal">
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@id/exo_progress"
android:layout_width="0dp"
android:layout_height="26dp"
android:layout_weight="1"
app:played_color="?attr/colorPrimary" />
</LinearLayout>
<!-- <LinearLayout-->
<!-- android:visibility="gone"-->
<!-- android:id="@+id/exo_torrent_status"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content">-->
<!-- <ProgressBar-->
<!-- android:id="@+id/torrent_progress"-->
<!-- style="?android:attr/progressBarStyleHorizontal"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:indeterminate="false"-->
<!-- android:max="100" />-->
<!-- </LinearLayout>-->
</LinearLayout>
</merge>

View File

@ -1,16 +1,17 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
compose_version = '1.2.0-alpha02'
koltin_version = '1.6.10'
room_version = "2.4.1"
compose_version = '1.2.0-alpha08'
exo_player_version = '2.17.1'
koltin_version = '1.6.20'
room_version = '2.4.2'
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath 'com.android.tools.build:gradle:7.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$koltin_version"
classpath "com.google.dagger:hilt-android-gradle-plugin:2.38.1"