2 Commits

Author SHA1 Message Date
acite
b5940aecc3 [feat] Beautify the interface, title bar in full screen mode 2025-08-27 03:56:26 +08:00
acite
76054da910 [feat] Gestures for volume and brightness control 2025-08-27 03:43:52 +08:00
5 changed files with 354 additions and 64 deletions

View File

@@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
import android.graphics.drawable.Icon
import android.net.http.SslCertificate.saveState
import android.os.Bundle
import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@@ -56,6 +57,9 @@ import com.acitelight.aether.view.VideoScreen
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.attributes = window.attributes.apply {
screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
}
enableEdgeToEdge()
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {

View File

@@ -1,8 +1,10 @@
package com.acitelight.aether.view
import android.app.Activity
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.media.AudioManager
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
@@ -12,7 +14,6 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Pause
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.Icon
@@ -50,7 +51,10 @@ import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.VolumeUp
import androidx.compose.material.icons.filled.Brightness4
import androidx.compose.material.icons.filled.FastForward
import androidx.compose.material.icons.filled.Fullscreen
import androidx.compose.material.icons.filled.Info
@@ -58,6 +62,7 @@ import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.filled.ThumbDown
import androidx.compose.material.icons.filled.ThumbUp
import androidx.compose.material.icons.filled.VolumeUp
import androidx.compose.material3.Card
import androidx.compose.material3.CardColors
import androidx.compose.material3.DividerDefaults
@@ -68,6 +73,8 @@ import androidx.compose.material3.VerticalDivider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
@@ -95,6 +102,7 @@ import com.acitelight.aether.Global
import com.acitelight.aether.ToggleFullScreen
import com.acitelight.aether.model.KeyImage
import com.acitelight.aether.model.Video
import kotlin.math.abs
fun formatTime(ms: Long): String {
if (ms <= 0) return "00:00:00"
@@ -223,6 +231,18 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
val context = LocalContext.current
val activity = context as? Activity
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
var volFactor by remember { mutableFloatStateOf(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()) }
fun setVolume(value: Int) {
audioManager.setStreamVolume(
AudioManager.STREAM_MUSIC,
value.coerceIn(0, maxVolume),
AudioManager.FLAG_PLAY_SOUND
)
}
Box(modifier)
{
AndroidView(
@@ -239,19 +259,53 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
.fillMaxWidth()
.pointerInput(Unit) {
detectDragGestures(
onDragStart = {
videoPlayerViewModel.dragging = true
videoPlayerViewModel.planeVisibility = true
exoPlayer.pause()
onDragStart = { offset ->
if(offset.x < size.width / 2)
{
videoPlayerViewModel.draggingPurpose = -1;
}else{
videoPlayerViewModel.draggingPurpose = -2;
}
},
onDragEnd = {
videoPlayerViewModel.dragging = false
if (videoPlayerViewModel.isPlaying)
if (videoPlayerViewModel.isPlaying && videoPlayerViewModel.draggingPurpose == 0)
exoPlayer.play()
videoPlayerViewModel.draggingPurpose = -1;
},
onDrag = { change, dragAmount ->
if(abs(dragAmount.x) > abs(dragAmount.y) &&
(videoPlayerViewModel.draggingPurpose == -1 || videoPlayerViewModel.draggingPurpose == -2))
{
videoPlayerViewModel.draggingPurpose = 0
videoPlayerViewModel.planeVisibility = true
exoPlayer.pause()
}
else if(videoPlayerViewModel.draggingPurpose == -1) videoPlayerViewModel.draggingPurpose = 1
else if(videoPlayerViewModel.draggingPurpose == -2) videoPlayerViewModel.draggingPurpose = 2
if(videoPlayerViewModel.draggingPurpose == 0)
{
exoPlayer.seekTo((exoPlayer.currentPosition + dragAmount.x * 200.0f).toLong())
videoPlayerViewModel.playProcess = exoPlayer.currentPosition.toFloat() / exoPlayer.duration.toFloat()
}else if(videoPlayerViewModel.draggingPurpose == 2)
{
val cu = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
volFactor = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()
if(dragAmount.y < 0)
setVolume( cu + 1);
else if(dragAmount.y > 0)
setVolume( cu - 1);
}else if(videoPlayerViewModel.draggingPurpose == 1)
{
videoPlayerViewModel.brit = (videoPlayerViewModel.brit - dragAmount.y * 0.002f).coerceIn(0f, 1f);
activity?.window?.attributes = activity.window.attributes.apply {
screenBrightness = videoPlayerViewModel.brit.coerceIn(0f, 1f)
}
activity?.window?.setAttributes(activity.window.attributes)
}
}
)
}
@@ -312,7 +366,7 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
}
androidx.compose.animation.AnimatedVisibility(
visible = videoPlayerViewModel.dragging,
visible = videoPlayerViewModel.draggingPurpose == 0,
enter = fadeIn(
initialAlpha = 0f,
),
@@ -320,7 +374,8 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
targetAlpha = 0f
),
modifier = Modifier.align(Alignment.Center)
) {
)
{
Text(
text = "${formatTime((exoPlayer.duration * videoPlayerViewModel.playProcess).toLong())}/${
formatTime(
@@ -328,12 +383,74 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
)
}",
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(bottom = 12.dp),
modifier = Modifier.padding(bottom = 12.dp),
fontSize = 18.sp
)
}
androidx.compose.animation.AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 2,
enter = fadeIn(
initialAlpha = 0f,
),
exit = fadeOut(
targetAlpha = 0f
),
modifier = Modifier.align(Alignment.Center)
)
{
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
{
Icon(
imageVector = Icons.AutoMirrored.Filled.VolumeUp,
contentDescription = "Vol",
tint = Color.White,
modifier = Modifier.size(48.dp).padding(8.dp)
.align(Alignment.CenterVertically)
)
BiliMiniSlider(
value = volFactor,
onValueChange = {},
modifier = Modifier
.height(4.dp)
.padding(horizontal = 8.dp)
.align(Alignment.CenterVertically)
)
}
}
androidx.compose.animation.AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 1,
enter = fadeIn(
initialAlpha = 0f,
),
exit = fadeOut(
targetAlpha = 0f
),
modifier = Modifier.align(Alignment.Center)
)
{
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
{
Icon(
imageVector = Icons.Default.Brightness4,
contentDescription = "Brightness",
tint = Color.White,
modifier = Modifier.size(48.dp).padding(8.dp)
.align(Alignment.CenterVertically)
)
BiliMiniSlider(
value = videoPlayerViewModel.brit,
onValueChange = {},
modifier = Modifier
.height(4.dp)
.padding(horizontal = 8.dp)
.align(Alignment.CenterVertically)
)
}
}
if(cover > 0.0f)
Spacer(Modifier.background(Color(0x00FF6699 - 0x00222222 + ((0x000000FF * cover).toLong() shl 24) )).fillMaxSize())
@@ -371,7 +488,13 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 2.dp)
.align(Alignment.BottomCenter),
.align(Alignment.BottomCenter).background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.4f),
)
)),
horizontalArrangement = Arrangement.SpaceBetween,
) {
IconButton(
@@ -713,6 +836,18 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
val activity = context as? Activity
val exoPlayer: ExoPlayer = videoPlayerViewModel._player!!;
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
var volFactor by remember { mutableFloatStateOf(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()) }
fun setVolume(value: Int) {
audioManager.setStreamVolume(
AudioManager.STREAM_MUSIC,
value.coerceIn(0, maxVolume),
AudioManager.FLAG_PLAY_SOUND
)
}
BackHandler {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
@@ -738,19 +873,53 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
.fillMaxWidth()
.pointerInput(Unit) {
detectDragGestures(
onDragStart = {
videoPlayerViewModel.planeVisibility = true
videoPlayerViewModel.dragging = true;
exoPlayer.pause()
onDragStart = { offset ->
if(offset.x < size.width / 2)
{
videoPlayerViewModel.draggingPurpose = -1;
}else{
videoPlayerViewModel.draggingPurpose = -2;
}
},
onDragEnd = {
videoPlayerViewModel.dragging = false;
if (videoPlayerViewModel.isPlaying)
if (videoPlayerViewModel.isPlaying && videoPlayerViewModel.draggingPurpose == 0)
exoPlayer.play()
videoPlayerViewModel.draggingPurpose = -1;
},
onDrag = { change, dragAmount ->
if(abs(dragAmount.x) > abs(dragAmount.y) &&
(videoPlayerViewModel.draggingPurpose == -1 || videoPlayerViewModel.draggingPurpose == -2))
{
videoPlayerViewModel.draggingPurpose = 0
videoPlayerViewModel.planeVisibility = true
exoPlayer.pause()
}
else if(videoPlayerViewModel.draggingPurpose == -1) videoPlayerViewModel.draggingPurpose = 1
else if(videoPlayerViewModel.draggingPurpose == -2) videoPlayerViewModel.draggingPurpose = 2
if(videoPlayerViewModel.draggingPurpose == 0)
{
exoPlayer.seekTo((exoPlayer.currentPosition + dragAmount.x * 200.0f).toLong())
videoPlayerViewModel.playProcess = exoPlayer.currentPosition.toFloat() / exoPlayer.duration.toFloat()
}else if(videoPlayerViewModel.draggingPurpose == 2)
{
val cu = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
volFactor = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / maxVolume.toFloat()
if(dragAmount.y < 0)
setVolume( cu + 1);
else if(dragAmount.y > 0)
setVolume( cu - 1);
}else if(videoPlayerViewModel.draggingPurpose == 1)
{
videoPlayerViewModel.brit = (videoPlayerViewModel.brit - dragAmount.y * 0.002f).coerceIn(0f, 1f);
activity?.window?.attributes = activity.window.attributes.apply {
screenBrightness = videoPlayerViewModel.brit.coerceIn(0f, 1f)
}
activity?.window?.setAttributes(activity.window.attributes)
}
}
)
}
@@ -782,7 +951,7 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
)
androidx.compose.animation.AnimatedVisibility(
visible = videoPlayerViewModel.dragging,
visible = videoPlayerViewModel.draggingPurpose == 0,
enter = fadeIn(
initialAlpha = 0f,
),
@@ -790,7 +959,8 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
targetAlpha = 0f
),
modifier = Modifier.align(Alignment.Center)
) {
)
{
Text(
text = "${formatTime((exoPlayer.duration * videoPlayerViewModel.playProcess).toLong())}/${
formatTime(
@@ -803,6 +973,68 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
)
}
androidx.compose.animation.AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 2,
enter = fadeIn(
initialAlpha = 0f,
),
exit = fadeOut(
targetAlpha = 0f
),
modifier = Modifier.align(Alignment.Center)
)
{
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
{
Icon(
imageVector = Icons.AutoMirrored.Filled.VolumeUp,
contentDescription = "Vol",
tint = Color.White,
modifier = Modifier.size(48.dp).padding(8.dp)
.align(Alignment.CenterVertically)
)
BiliMiniSlider(
value = volFactor,
onValueChange = {},
modifier = Modifier
.height(4.dp)
.padding(horizontal = 8.dp)
.align(Alignment.CenterVertically)
)
}
}
androidx.compose.animation.AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 1,
enter = fadeIn(
initialAlpha = 0f,
),
exit = fadeOut(
targetAlpha = 0f
),
modifier = Modifier.align(Alignment.Center)
)
{
Row(Modifier.background(Color(0x88000000), RoundedCornerShape(18)).width(200.dp))
{
Icon(
imageVector = Icons.Default.Brightness4,
contentDescription = "Brightness",
tint = Color.White,
modifier = Modifier.size(48.dp).padding(8.dp)
.align(Alignment.CenterVertically)
)
BiliMiniSlider(
value = videoPlayerViewModel.brit,
onValueChange = {},
modifier = Modifier
.height(4.dp)
.padding(horizontal = 8.dp)
.align(Alignment.CenterVertically)
)
}
}
AnimatedVisibility(
visible = videoPlayerViewModel.isLongPressing,
enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }),
@@ -832,21 +1064,50 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel)
}
}
AnimatedVisibility(
visible = videoPlayerViewModel.planeVisibility,
enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }),
exit = slideOutVertically(targetOffsetY = { fullHeight -> -fullHeight }),
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxWidth()
)
{
Row(Modifier
.align(Alignment.TopStart)
.padding(horizontal = 32.dp).background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Black.copy(alpha = 0.4f),
Color.Transparent,
)
)))
{
IconButton(
onClick = {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
},
modifier = Modifier
.align(Alignment.TopStart)
.padding(8.dp)
modifier = Modifier.size(36.dp).align(Alignment.CenterVertically)
) {
Icon(
modifier = Modifier.size(36.dp),
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = Color.White
)
}
Text(
text = "${videoPlayerViewModel.video?.video?.name}",
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(horizontal = 12.dp).align(Alignment.CenterVertically),
fontSize = 18.sp
)
}
}
AnimatedVisibility(
visible = videoPlayerViewModel.planeVisibility,
enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight }),

View File

@@ -1,5 +1,6 @@
package com.acitelight.aether.view
import android.R.id.tabs
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -19,7 +20,12 @@ import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryScrollableTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.TabRowDefaults
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -33,16 +39,19 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil3.compose.AsyncImage
import com.acitelight.aether.model.Video
import com.acitelight.aether.service.MediaManager
import com.acitelight.aether.viewModel.VideoScreenViewModel
import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.ScrollableTabRow
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.navigation.NavHostController
import coil3.request.ImageRequest
import com.acitelight.aether.Global
import kotlinx.coroutines.flow.first
import java.nio.charset.Charset
fun String.toHex(): String {
@@ -63,7 +72,6 @@ fun String.hexToString(charset: Charset = Charsets.UTF_8): String {
@Composable
fun VideoScreen(videoScreenViewModel: VideoScreenViewModel = viewModel(), navController: NavHostController)
{
val tabIndex by videoScreenViewModel.tabIndex;
videoScreenViewModel.SetupClient()
Column(
@@ -78,14 +86,11 @@ fun VideoScreen(videoScreenViewModel: VideoScreenViewModel = viewModel(), navCon
horizontalArrangement = Arrangement.spacedBy(8.dp)
)
{
if(videoScreenViewModel.classes.isNotEmpty())
{
items(videoScreenViewModel.classesMap[videoScreenViewModel.classes[tabIndex]] ?: mutableStateListOf()) { video ->
items(videoScreenViewModel.videos) { video ->
VideoCard(video, navController, videoScreenViewModel)
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -93,11 +98,12 @@ fun VideoScreen(videoScreenViewModel: VideoScreenViewModel = viewModel(), navCon
fun TopRow(videoScreenViewModel: VideoScreenViewModel)
{
val tabIndex by videoScreenViewModel.tabIndex;
val klasses by videoScreenViewModel.klasses.collectAsState();
if(videoScreenViewModel.classes.isEmpty()) return
if(klasses.isEmpty()) return
ScrollableTabRow (selectedTabIndex = tabIndex) {
videoScreenViewModel.classes.forEachIndexed { index, title ->
klasses.forEachIndexed { index, title ->
Tab(
selected = tabIndex == index,
onClick = { videoScreenViewModel.setTabIndex(index) },
@@ -109,14 +115,13 @@ fun TopRow(videoScreenViewModel: VideoScreenViewModel)
@Composable
fun VideoCard(video: Video, navController: NavHostController, videoScreenViewModel: VideoScreenViewModel) {
val tabIndex by videoScreenViewModel.tabIndex;
Card(
shape = RoundedCornerShape(6.dp),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
onClick = {
Global.sameClassVideos = videoScreenViewModel.classesMap[videoScreenViewModel.classes[tabIndex]] ?: mutableStateListOf()
Global.sameClassVideos = videoScreenViewModel.videos
val route = "video_player_route/${ "${video.klass}/${video.id}".toHex() }"
navController.navigate(route)
}

View File

@@ -1,5 +1,6 @@
package com.acitelight.aether.viewModel
import android.app.Activity
import androidx.annotation.OptIn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
@@ -40,7 +41,12 @@ class VideoPlayerViewModel() : ViewModel()
var playProcess by mutableFloatStateOf(0.0f)
var planeVisibility by mutableStateOf(true)
var isLongPressing by mutableStateOf(false)
var dragging by mutableStateOf(false)
// -1 : Not dragging
// 0 : Seek
// 1 : Volume
// 2 : Brightness
var draggingPurpose by mutableIntStateOf(-1)
var thumbUp by mutableIntStateOf(0)
var thumbDown by mutableIntStateOf(0)
@@ -53,6 +59,7 @@ class VideoPlayerViewModel() : ViewModel()
val dataSourceFactory = OkHttpDataSource.Factory(createOkHttp())
var imageLoader: ImageLoader? = null;
var brit by mutableFloatStateOf(0.5f)
@OptIn(UnstableApi::class)
@Composable

View File

@@ -3,35 +3,51 @@ package com.acitelight.aether.viewModel
import android.app.Application
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.platform.LocalContext
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import coil3.ImageLoader
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import com.acitelight.aether.Global
import com.acitelight.aether.dataStore
import com.acitelight.aether.model.Video
import com.acitelight.aether.service.ApiClient
import com.acitelight.aether.service.ApiClient.createOkHttp
import com.acitelight.aether.service.AuthManager
import com.acitelight.aether.service.MediaManager
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
class VideoScreenViewModel(application: Application) : AndroidViewModel(application)
{
private val dataStore = application.dataStore
private val USER_NAME_KEY = stringPreferencesKey("user_name")
private val PRIVATE_KEY = stringPreferencesKey("private_key")
val userNameFlow: Flow<String> = dataStore.data.map { preferences ->
preferences[USER_NAME_KEY] ?: ""
}
val privateKeyFlow: Flow<String> = dataStore.data.map { preferences ->
preferences[PRIVATE_KEY] ?: ""
}
private val _tabIndex = mutableIntStateOf(0)
val tabIndex: State<Int> = _tabIndex
// val videos = mutableStateListOf<Video>()
// private val _klasses = MutableStateFlow<List<String>>(emptyList())
var classes = mutableStateListOf<String>()
val classesMap = mutableStateMapOf<String, SnapshotStateList<Video>>()
val videos = mutableStateListOf<Video>()
private val _klasses = MutableStateFlow<List<String>>(emptyList())
val klasses: StateFlow<List<String>> = _klasses;
var imageLoader: ImageLoader? = null;
@Composable
@@ -46,14 +62,10 @@ class VideoScreenViewModel(application: Application) : AndroidViewModel(applicat
}
suspend fun init() {
classes.addAll(MediaManager.listVideoKlasses())
for(it in classes)
{
classesMap[it] = mutableStateListOf<Video>()
}
_klasses.value = MediaManager.listVideoKlasses()
MediaManager.listVideos(classes[0]){
v -> classesMap[classes[0]]?.add(v)
MediaManager.listVideos(_klasses.value.first()){
v -> if(0 == tabIndex.value && !videos.contains(v)) videos.add(videos.size, v)
}
}
@@ -63,9 +75,10 @@ class VideoScreenViewModel(application: Application) : AndroidViewModel(applicat
{
_tabIndex.intValue = index;
MediaManager.listVideos(classes[index])
videos.clear()
MediaManager.listVideos(_klasses.value[index])
{
v -> classesMap[classes[index]]?.add(v)
v -> if(index == tabIndex.value) videos.add(videos.size, v)
}
}
}