This commit is contained in:
Marek
2026-04-05 19:58:14 +02:00
parent 6e96c5ee99
commit 6a6df85139
8 changed files with 131 additions and 78 deletions

View File

@@ -3,7 +3,11 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.software.leanback" android:required="false" />
<application
android:banner="@drawable/tv_banner"
android:allowBackup="true"
android:label="YouTube App"
android:usesCleartextTraffic="true"
@@ -15,6 +19,7 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
</application>

View File

@@ -1,5 +1,7 @@
package com.youtubeapp.ui.components
import androidx.compose.foundation.border
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
@@ -8,7 +10,13 @@ import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -17,9 +25,18 @@ import com.youtubeapp.data.Video
@Composable
fun VideoCard(video: Video, onClick: () -> Unit) {
var isFocused by remember { mutableStateOf(false) }
Card(
onClick = onClick,
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.onFocusChanged { isFocused = it.isFocused }
.then(
if (isFocused) Modifier.border(3.dp, Color.White, MaterialTheme.shapes.medium)
else Modifier
)
.focusable()
) {
Column {
AsyncImage(

View File

@@ -47,7 +47,7 @@ fun AllVideosScreen(viewModel: VideoViewModel, onVideoClick: (Int) -> Unit) {
}
else -> {
LazyVerticalGrid(
columns = GridCells.Fixed(2),
columns = GridCells.Adaptive(minSize = 250.dp),
contentPadding = PaddingValues(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),

View File

@@ -52,7 +52,7 @@ fun DownloadedScreen(viewModel: VideoViewModel, onVideoClick: (Int) -> Unit) {
}
else -> {
LazyVerticalGrid(
columns = GridCells.Fixed(2),
columns = GridCells.Adaptive(minSize = 250.dp),
contentPadding = PaddingValues(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),

View File

@@ -1,6 +1,7 @@
package com.youtubeapp.ui.screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -73,19 +74,38 @@ fun VideoDetailScreen(
if (video == null) {
Text("Video nicht gefunden", modifier = Modifier.padding(innerPadding).padding(16.dp))
} else {
Column(
BoxWithConstraints(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
val isWide = maxWidth > 600.dp
Column(modifier = Modifier.fillMaxSize()) {
AsyncImage(
model = video.thumbnail_url,
contentDescription = video.title,
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxWidth()
.fillMaxWidth(if (isWide) 0.5f else 1f)
.aspectRatio(16f / 9f)
)
VideoInfo(video, isLocal, state.isDownloading, viewModel, videoId, onPlayClick)
}
}
}
}
}
@Composable
private fun VideoInfo(
video: com.youtubeapp.data.Video,
isLocal: Boolean,
isDownloading: Boolean,
viewModel: VideoViewModel,
videoId: Int,
onPlayClick: () -> Unit
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = video.title,
@@ -119,7 +139,7 @@ fun VideoDetailScreen(
Icon(Icons.Default.PlayArrow, contentDescription = null)
Text(" Abspielen")
}
if (state.isDownloading) {
if (isDownloading) {
OutlinedButton(
onClick = {},
enabled = false,
@@ -150,7 +170,4 @@ fun VideoDetailScreen(
}
}
}
}
}
}
}

View File

@@ -1,6 +1,7 @@
package com.youtubeapp.ui.screens
import android.app.Activity
import android.view.LayoutInflater
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -14,6 +15,7 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import com.youtubeapp.R
import com.youtubeapp.ui.viewmodel.VideoViewModel
@Composable
@@ -49,10 +51,12 @@ fun VideoPlayerScreen(videoId: Int, viewModel: VideoViewModel) {
AndroidView(
factory = { ctx ->
PlayerView(ctx).apply {
player = exoPlayer
useController = true
}
val view = LayoutInflater.from(ctx).inflate(R.layout.player_view, null) as PlayerView
view.player = exoPlayer
view
},
update = { view ->
view.player = exoPlayer
},
modifier = Modifier.fillMaxSize()
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.media3.ui.PlayerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:surface_type="texture_view"
app:show_buffering="when_playing"
app:use_controller="true" />