[feat] Better UI 2

This commit is contained in:
acite
2025-10-01 02:04:37 +08:00
parent c5a5826321
commit 24dda0eb2c
26 changed files with 512 additions and 537 deletions

View File

@@ -3,8 +3,6 @@ package com.acitelight.aether
import android.app.Activity
import android.content.Intent
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
@@ -16,36 +14,26 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.automirrored.filled.CompareArrows
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.Card
import androidx.compose.material3.CardColors
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SegmentedButtonDefaults.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
@@ -60,22 +48,18 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.acitelight.aether.view.ComicGridView
import com.acitelight.aether.view.ComicPageView
import com.acitelight.aether.view.ComicScreen
import com.acitelight.aether.view.HomeScreen
import com.acitelight.aether.view.MeScreen
import com.acitelight.aether.view.TransmissionScreen
import com.acitelight.aether.view.VideoPlayer
import com.acitelight.aether.view.VideoScreen
import com.acitelight.aether.view.pages.ComicGridView
import com.acitelight.aether.view.pages.ComicPageView
import com.acitelight.aether.view.pages.ComicScreen
import com.acitelight.aether.view.pages.HomeScreen
import com.acitelight.aether.view.pages.MeScreen
import com.acitelight.aether.view.pages.TransmissionScreen
import com.acitelight.aether.view.pages.VideoPlayer
import com.acitelight.aether.view.pages.VideoScreen
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
@AndroidEntryPoint
class MainActivity : ComponentActivity() {

View File

@@ -1,171 +0,0 @@
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 android.view.View
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
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.filled.Pause
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import androidx.navigation.NavHostController
import com.acitelight.aether.viewModel.VideoPlayerViewModel
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
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.VolumeUp
import androidx.compose.material.icons.filled.Brightness4
import androidx.compose.material.icons.filled.FastForward
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.LockOpen
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.material3.Card
import androidx.compose.material3.CardColors
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
import androidx.media3.common.text.Cue
import androidx.media3.common.util.UnstableApi
import coil3.ImageLoader
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.Global
import com.acitelight.aether.ToggleFullScreen
import com.acitelight.aether.model.KeyImage
import com.acitelight.aether.model.Video
import kotlinx.coroutines.launch
import kotlin.math.abs
import kotlin.math.exp
import kotlin.math.ln
import kotlin.math.pow
fun formatTime(ms: Long): String {
if (ms <= 0) return "00:00:00"
val totalSeconds = ms / 1000
val hours = totalSeconds / 3600
val minutes = (totalSeconds % 3600) / 60
val seconds = totalSeconds % 60
return String.format("%02d:%02d:%02d", hours, minutes, seconds)
}
fun moveBrit(db: Float, activity: Activity, videoPlayerViewModel: VideoPlayerViewModel) {
val attr = activity.window.attributes
val britUi = (videoPlayerViewModel.brit - db * 0.002f).coerceIn(0f, 1f)
videoPlayerViewModel.brit = britUi
val gamma = 2.2f
val britSystem = britUi.pow(gamma).coerceIn(0.001f, 1f)
attr.screenBrightness = britSystem
activity.window.attributes = attr
}
@Composable
fun VideoPlayer(
videoPlayerViewModel: VideoPlayerViewModel = hiltViewModel<VideoPlayerViewModel>(),
videoId: String,
navController: NavHostController
) {
val context = LocalContext.current
val activity = (context as? Activity)!!
DisposableEffect(Unit) {
onDispose {
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
videoPlayerViewModel.init(videoId)
activity.requestedOrientation =
if(videoPlayerViewModel.isLandscape)
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
else
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
if (videoPlayerViewModel.startPlaying) {
if (videoPlayerViewModel.isLandscape) {
VideoPlayerLandscape(videoPlayerViewModel)
} else {
VideoPlayerPortal(videoPlayerViewModel, navController)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth

View File

@@ -0,0 +1,129 @@
package com.acitelight.aether.view.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.model.Comic
import com.acitelight.aether.view.pages.toHex
import com.acitelight.aether.viewModel.ComicScreenViewModel
@Composable
fun ComicCard(
comic: Comic,
navController: NavHostController,
comicScreenViewModel: ComicScreenViewModel
) {
Card(
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface.copy(0.65f)),
shape = RoundedCornerShape(8.dp),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
onClick = {
val route = "comic_grid_route/${comic.id.toHex()}"
navController.navigate(route)
}
) {
Column(
modifier = Modifier
.fillMaxWidth()
) {
Box(modifier = Modifier.fillMaxSize()) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(comic.getPage(0, comicScreenViewModel.apiClient))
.memoryCacheKey("${comic.id}/${0}")
.diskCacheKey("${comic.id}/${0}")
.build(),
contentDescription = null,
imageLoader = comicScreenViewModel.imageLoader!!,
modifier = Modifier
.fillMaxSize()
.clip(RoundedCornerShape(8.dp)),
contentScale = ContentScale.Crop,
)
Box(
Modifier
.fillMaxWidth()
.height(24.dp)
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.45f)
)
)
)
.align(Alignment.BottomCenter)
)
{
Text(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(2.dp),
fontSize = 12.sp,
text = "${comic.comic.list.size} Pages",
fontWeight = FontWeight.Bold,
color = Color.White,
maxLines = 1
)
}
}
Text(
text = comic.comic.comic_name,
fontSize = 14.sp,
lineHeight = 17.sp,
fontWeight = FontWeight.Bold,
maxLines = 2,
modifier = Modifier.padding(4.dp)
)
Box(Modifier.padding(4.dp).fillMaxWidth()){
Text(
text = "Id: ${comic.id}",
fontSize = 12.sp,
lineHeight = 14.sp,
maxLines = 1,
modifier = Modifier.align(Alignment.CenterStart)
)
Text(
text = comic.comic.author,
fontSize = 12.sp,
lineHeight = 14.sp,
maxLines = 1,
modifier = Modifier.align(Alignment.CenterEnd)
)
}
}
}
}

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues

View File

@@ -1,7 +1,5 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import android.R
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -20,10 +18,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PaintingStyle.Companion.Stroke
import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.layout.ContentScale
@@ -36,6 +32,7 @@ import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.model.Video
import com.acitelight.aether.service.ApiClient
import com.acitelight.aether.view.pages.formatTime
@Composable

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -29,6 +29,7 @@ import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.model.Video
import com.acitelight.aether.service.ApiClient
import com.acitelight.aether.view.pages.formatTime
@Composable

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box

View File

@@ -1,9 +1,11 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import android.app.Activity
import android.content.Context
import android.media.AudioManager
import android.view.View
import androidx.annotation.OptIn
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
@@ -51,11 +53,13 @@ import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import com.acitelight.aether.view.pages.formatTime
import com.acitelight.aether.view.pages.moveBrit
import com.acitelight.aether.viewModel.VideoPlayerViewModel
import kotlin.math.abs
@androidx.annotation.OptIn(UnstableApi::class)
@OptIn(UnstableApi::class)
@Composable
fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel, cover: Float) {
val exoPlayer: ExoPlayer = videoPlayerViewModel.player!!
@@ -173,7 +177,7 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
}
)
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.isLongPressing,
enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }),
exit = slideOutVertically(targetOffsetY = { fullHeight -> -fullHeight }),
@@ -212,7 +216,7 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
}
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 0,
enter = fadeIn(
initialAlpha = 0f,
@@ -235,7 +239,7 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
)
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 2,
enter = fadeIn(
initialAlpha = 0f,
@@ -270,7 +274,7 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
}
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 1,
enter = fadeIn(
initialAlpha = 0f,
@@ -310,7 +314,7 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
.background(MaterialTheme.colorScheme.primary.copy(cover))
.fillMaxSize())
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = (!videoPlayerViewModel.planeVisibility) || videoPlayerViewModel.locked,
enter = fadeIn(
initialAlpha = 0f,
@@ -331,7 +335,7 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
)
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.planeVisibility && (!videoPlayerViewModel.locked),
enter = fadeIn(
initialAlpha = 0f,

View File

@@ -1,5 +1,6 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import android.text.Layout
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
@@ -42,9 +43,9 @@ fun SubtitleOverlay(
if (raw.isEmpty()) return
val textAlign = when (cues.firstOrNull()?.textAlignment) {
android.text.Layout.Alignment.ALIGN_CENTER -> TextAlign.Center
android.text.Layout.Alignment.ALIGN_OPPOSITE -> TextAlign.End
android.text.Layout.Alignment.ALIGN_NORMAL -> TextAlign.Start
Layout.Alignment.ALIGN_CENTER -> TextAlign.Center
Layout.Alignment.ALIGN_OPPOSITE -> TextAlign.End
Layout.Alignment.ALIGN_NORMAL -> TextAlign.Start
else -> TextAlign.Center
}

View File

@@ -0,0 +1,186 @@
package com.acitelight.aether.view.components
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.Global.updateRelate
import com.acitelight.aether.model.Video
import com.acitelight.aether.view.pages.formatTime
import com.acitelight.aether.view.pages.toHex
import com.acitelight.aether.viewModel.VideoScreenViewModel
import kotlinx.coroutines.launch
@Composable
fun VideoCard(
videos: List<Video>,
navController: NavHostController,
videoScreenViewModel: VideoScreenViewModel
) {
val tabIndex by videoScreenViewModel.tabIndex;
val video = videos.first()
Card(
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface.copy(0.65f)),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.combinedClickable(
onClick = {
updateRelate(
videoScreenViewModel.videoLibrary.classesMap[videoScreenViewModel.videoLibrary.classes[tabIndex]]
?: mutableStateListOf(), video
)
val vg = videos.joinToString(",") { "${it.klass}/${it.id}" }.toHex()
val route = "video_player_route/$vg"
navController.navigate(route)
},
onLongClick = {
videoScreenViewModel.viewModelScope.launch {
for(i in videos)
{
videoScreenViewModel.download(i)
}
Toast.makeText(
videoScreenViewModel.context,
"Start downloading ${video.video.group}",
Toast.LENGTH_SHORT
).show()
}
}
),
shape = RoundedCornerShape(6.dp),
) {
Column(
modifier = Modifier
.fillMaxWidth(),
) {
Box(modifier = Modifier.fillMaxSize()) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(video.getCover(videoScreenViewModel.apiClient))
.memoryCacheKey("${video.klass}/${video.id}/cover")
.diskCacheKey("${video.klass}/${video.id}/cover")
.build(),
contentDescription = null,
modifier = Modifier
.fillMaxSize()
.clip(RoundedCornerShape(8.dp)),
contentScale = ContentScale.Fit,
imageLoader = videoScreenViewModel.imageLoader!!
)
Box(
Modifier
.fillMaxWidth()
.height(24.dp)
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.6f)
)
)
)
.align(Alignment.BottomCenter)
)
Text(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(horizontal = 2.dp),
text = "${videos.size} Videos",
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
lineHeight = 13.sp,
color = Color.White
)
Text(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(horizontal = 2.dp),
text = formatTime(video.video.duration),
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
lineHeight = 13.sp,
color = Color.White
)
if (videos.all{ it.isLocal })
Card(
Modifier
.align(Alignment.TopStart)
.padding(5.dp)
.widthIn(max = 46.dp)
) {
Box(Modifier.fillMaxWidth())
{
Text(
modifier = Modifier.align(Alignment.Center),
text = "Local",
fontSize = 14.sp,
fontWeight = FontWeight.Bold
)
}
}
}
Text(
text = video.video.group ?: video.video.name,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
maxLines = 2,
modifier = Modifier
.padding(4.dp)
.background(Color.Transparent)
.heightIn(min = 24.dp),
lineHeight = 14.sp
)
Spacer(modifier = Modifier.weight(1f))
Box(
modifier = Modifier.padding(horizontal = 4.dp).fillMaxWidth()
) {
Text(modifier = Modifier.align(Alignment.CenterStart), text = "Class: ${video.klass}", fontSize = 10.sp, maxLines = 1)
Text(modifier = Modifier.align(Alignment.CenterEnd), text = "Id: ${
videos.take(5).joinToString(
","
) { it.id }
}", fontSize = 10.sp, maxLines = 1)
}
}
}
}

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -39,6 +39,7 @@ import coil3.request.ImageRequest
import com.acitelight.aether.Global.updateRelate
import com.acitelight.aether.model.Video
import com.acitelight.aether.model.VideoDownloadItemState
import com.acitelight.aether.view.pages.toHex
import com.acitelight.aether.viewModel.TransmissionScreenViewModel
import com.tonyodev.fetch2.Status
import kotlinx.coroutines.Dispatchers

View File

@@ -1,8 +1,7 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -18,17 +17,11 @@ import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Pause
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Stop
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -37,7 +30,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -46,15 +38,11 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.Global.updateRelate
import com.acitelight.aether.model.Video
import com.acitelight.aether.model.VideoDownloadItemState
import com.acitelight.aether.viewModel.TransmissionScreenViewModel
import com.tonyodev.fetch2.Status
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.io.File
import kotlin.math.abs
@@ -90,8 +78,8 @@ fun VideoDownloadCardMini(
.build()
Card(
colors = CardDefaults.cardColors(containerColor = Color.Transparent),
shape = RoundedCornerShape(8.dp),
elevation = CardDefaults.cardElevation(4.dp),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 4.dp)
@@ -108,20 +96,23 @@ fun VideoDownloadCardMini(
else -> {}
}
})
.height(85.dp)
.height(100.dp)
) {
Row(
modifier = Modifier.fillMaxSize()
)
{
Box(Modifier
.fillMaxHeight()
.widthIn(max = 152.dp))
.fillMaxHeight())
{
AsyncImage(
model = imageModel,
contentDescription = null,
modifier = Modifier.fillMaxSize(),
modifier = Modifier
.height(100.dp)
.clip(RoundedCornerShape(8.dp))
.widthIn(max = 150.dp)
.background(Color.Black),
contentScale = ContentScale.Crop
)

View File

@@ -1,10 +1,11 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import android.app.Activity
import android.content.Context
import android.media.AudioManager
import android.view.View
import androidx.activity.compose.BackHandler
import androidx.annotation.OptIn
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@@ -68,12 +69,14 @@ import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import com.acitelight.aether.ToggleFullScreen
import com.acitelight.aether.view.pages.formatTime
import com.acitelight.aether.view.pages.moveBrit
import com.acitelight.aether.viewModel.VideoPlayerViewModel
import kotlinx.coroutines.launch
import kotlin.math.abs
@androidx.annotation.OptIn(UnstableApi::class)
@OptIn(UnstableApi::class)
@Composable
fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
val colorScheme = MaterialTheme.colorScheme
@@ -221,7 +224,7 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 0,
enter = fadeIn(
initialAlpha = 0f,
@@ -242,7 +245,7 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
)
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 2,
enter = fadeIn(
initialAlpha = 0f,
@@ -279,7 +282,7 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
}
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = videoPlayerViewModel.draggingPurpose == 1,
enter = fadeIn(
initialAlpha = 0f,

View File

@@ -1,5 +1,6 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
@@ -47,8 +48,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import com.acitelight.aether.Global
import com.acitelight.aether.Global.updateRelate
import com.acitelight.aether.ToggleFullScreen
import com.acitelight.aether.view.pages.formatTime
import com.acitelight.aether.view.pages.toHex
import com.acitelight.aether.viewModel.VideoPlayerViewModel

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.pages
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable

View File

@@ -1,5 +1,6 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.pages
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
@@ -46,6 +47,7 @@ import androidx.navigation.NavHostController
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.model.BookMark
import com.acitelight.aether.view.components.BookmarkPop
import com.acitelight.aether.viewModel.ComicPageViewModel
import kotlinx.coroutines.launch
@@ -102,7 +104,7 @@ fun ComicPageView(
)
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = showPlane,
enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }),
exit = slideOutVertically(targetOffsetY = { fullHeight -> -fullHeight }),
@@ -216,7 +218,7 @@ fun ComicPageView(
}
}
androidx.compose.animation.AnimatedVisibility(
AnimatedVisibility(
visible = showPlane,
enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight }),
exit = slideOutVertically(targetOffsetY = { fullHeight -> fullHeight }),

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.pages
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@@ -21,28 +20,22 @@ import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridS
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavHostController
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.model.Comic
import com.acitelight.aether.view.components.ComicCard
import com.acitelight.aether.viewModel.ComicScreenViewModel
@Composable
@@ -127,11 +120,18 @@ fun ComicScreen(
val colorScheme = MaterialTheme.colorScheme
Column {
Text(
text = "Comic& Images",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier
.padding(8.dp)
.align(Alignment.Start)
)
HorizontalDivider(Modifier.padding(1.dp), thickness = 1.5.dp)
VariableGrid(
modifier = Modifier
.heightIn(max = 120.dp)
.padding(8.dp),
.heightIn(max = 88.dp)
.padding(4.dp),
rowHeight = 32.dp
)
{
@@ -164,13 +164,13 @@ fun ComicScreen(
}
}
HorizontalDivider(thickness = 1.5.dp)
HorizontalDivider(Modifier.padding(1.dp), thickness = 1.5.dp)
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Adaptive(136.dp),
contentPadding = PaddingValues(8.dp),
verticalItemSpacing = 8.dp,
horizontalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
state = state,
modifier = Modifier.fillMaxSize()
) {
@@ -190,86 +190,3 @@ fun ComicScreen(
}
}
}
@Composable
fun ComicCard(
comic: Comic,
navController: NavHostController,
comicScreenViewModel: ComicScreenViewModel
) {
Card(
shape = RoundedCornerShape(6.dp),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
onClick = {
val route = "comic_grid_route/${comic.id.toHex()}"
navController.navigate(route)
}
) {
Column(
modifier = Modifier
.fillMaxWidth()
) {
Box(modifier = Modifier.fillMaxSize()) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(comic.getPage(0, comicScreenViewModel.apiClient))
.memoryCacheKey("${comic.id}/${0}")
.diskCacheKey("${comic.id}/${0}")
.build(),
contentDescription = null,
imageLoader = comicScreenViewModel.imageLoader!!,
modifier = Modifier
.fillMaxSize(),
contentScale = ContentScale.Crop,
)
Box(
Modifier
.fillMaxWidth()
.height(24.dp)
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.45f)
)
)
)
.align(Alignment.BottomCenter)
)
{
Text(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(2.dp),
fontSize = 12.sp,
text = "${comic.comic.list.size} Pages",
fontWeight = FontWeight.Bold,
color = Color.White
)
}
}
Text(
text = comic.comic.comic_name,
fontSize = 14.sp,
fontWeight = FontWeight.Bold,
maxLines = 2,
modifier = Modifier
.padding(4.dp)
.background(Color.Transparent)
.heightIn(max = 48.dp)
)
Spacer(Modifier.height(4.dp))
Text(
text = "Id: ${comic.id}",
fontSize = 12.sp,
maxLines = 2,
modifier = Modifier
.padding(bottom = 4.dp).padding(horizontal = 4.dp)
.background(Color.Transparent)
)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.pages
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -36,16 +36,18 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavHostController
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.Global.updateRelate
import com.acitelight.aether.model.Comic
import com.acitelight.aether.view.components.MiniVideoCard
import com.acitelight.aether.viewModel.HomeScreenViewModel
@Composable
fun HomeScreen(
homeScreenViewModel: HomeScreenViewModel = androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel<HomeScreenViewModel>(),
homeScreenViewModel: HomeScreenViewModel = hiltViewModel<HomeScreenViewModel>(),
navController: NavHostController
) {
val pagerState = rememberPagerState(initialPage = 0, pageCount = { 2 })
@@ -54,7 +56,6 @@ fun HomeScreen(
state = pagerState,
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
) { p ->
if (p == 0) {
Column(Modifier.fillMaxHeight()) {

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.pages
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -32,10 +32,11 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.acitelight.aether.viewModel.MeScreenViewModel
@Composable
fun MeScreen(meScreenViewModel: MeScreenViewModel = androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel<MeScreenViewModel>()) {
fun MeScreen(meScreenViewModel: MeScreenViewModel = hiltViewModel<MeScreenViewModel>()) {
var username by meScreenViewModel.username
var privateKey by meScreenViewModel.privateKey
var url by meScreenViewModel.url

View File

@@ -1,58 +1,28 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.pages
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Pause
import androidx.compose.material.icons.filled.Stop
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import com.acitelight.aether.Global.updateRelate
import com.acitelight.aether.model.VideoDownloadItemState
import com.acitelight.aether.model.Video
import com.acitelight.aether.view.components.BiliMiniSlider
import com.acitelight.aether.view.components.VideoDownloadCardMini
import com.acitelight.aether.viewModel.TransmissionScreenViewModel
import com.tonyodev.fetch2.Status
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.io.File
import kotlin.collections.sortedWith
import kotlin.math.abs
@Composable
fun TransmissionScreen(
@@ -65,12 +35,16 @@ fun TransmissionScreen(
Text(
text = "Video Tasks",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(8.dp).align(Alignment.Start)
modifier = Modifier
.padding(8.dp)
.align(Alignment.Start)
)
Text(
text = "All: ${downloads.count { it.type == "main" }}",
modifier = Modifier.padding(horizontal = 8.dp).align(Alignment.Start),
modifier = Modifier
.padding(horizontal = 8.dp)
.align(Alignment.Start),
fontSize = 12.sp,
lineHeight = 13.sp,
maxLines = 1
@@ -78,7 +52,9 @@ fun TransmissionScreen(
Text(
text = "Completed: ${downloads.count { it.type == "main" && it.status == Status.COMPLETED }}",
modifier = Modifier.padding(horizontal = 8.dp).align(Alignment.Start),
modifier = Modifier
.padding(horizontal = 8.dp)
.align(Alignment.Start),
fontSize = 12.sp,
lineHeight = 13.sp,
maxLines = 1
@@ -86,7 +62,8 @@ fun TransmissionScreen(
val downloading = downloads.filter { it.status == Status.DOWNLOADING }
BiliMiniSlider(
value = if (downloading.sumOf { it.totalBytes } == 0L) 1f else downloading.sumOf { it.downloadedBytes } / downloading.sumOf { it.totalBytes }.toFloat(),
value = if (downloading.sumOf { it.totalBytes } == 0L) 1f else downloading.sumOf { it.downloadedBytes } / downloading.sumOf { it.totalBytes }
.toFloat(),
modifier = Modifier
.height(6.dp)
.align(Alignment.End)
@@ -99,11 +76,15 @@ fun TransmissionScreen(
HorizontalDivider(Modifier.padding(8.dp), 2.dp, DividerDefaults.color)
LazyColumn(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(12.dp)
modifier = Modifier.fillMaxWidth()
)
{
items(downloads.filter { it.type == "main" }.sortedBy { it.status == Status.COMPLETED }, key = { it.id }) { item ->
items(
downloads
.filter { it.type == "main" }
.sortedWith(compareBy(naturalOrder()) { it.fileName })
.sortedBy { it.status == Status.COMPLETED }, key = { it.id })
{ item ->
VideoDownloadCardMini(
navigator = navigator,
viewModel = transmissionScreenViewModel,
@@ -139,6 +120,11 @@ fun TransmissionScreen(
)) transmissionScreenViewModel.retry(i.id)
}
)
HorizontalDivider(
Modifier.padding(horizontal = 16.dp, vertical = 6.dp),
2.dp,
DividerDefaults.color
)
}
}
}

View File

@@ -0,0 +1,68 @@
package com.acitelight.aether.view.pages
import android.app.Activity
import android.content.pm.ActivityInfo
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavHostController
import com.acitelight.aether.viewModel.VideoPlayerViewModel
import androidx.compose.runtime.DisposableEffect
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.acitelight.aether.view.components.VideoPlayerLandscape
import com.acitelight.aether.view.components.VideoPlayerPortal
import kotlin.math.pow
fun formatTime(ms: Long): String {
if (ms <= 0) return "00:00:00"
val totalSeconds = ms / 1000
val hours = totalSeconds / 3600
val minutes = (totalSeconds % 3600) / 60
val seconds = totalSeconds % 60
return String.format("%02d:%02d:%02d", hours, minutes, seconds)
}
fun moveBrit(db: Float, activity: Activity, videoPlayerViewModel: VideoPlayerViewModel) {
val attr = activity.window.attributes
val britUi = (videoPlayerViewModel.brit - db * 0.002f).coerceIn(0f, 1f)
videoPlayerViewModel.brit = britUi
val gamma = 2.2f
val britSystem = britUi.pow(gamma).coerceIn(0.001f, 1f)
attr.screenBrightness = britSystem
activity.window.attributes = attr
}
@Composable
fun VideoPlayer(
videoPlayerViewModel: VideoPlayerViewModel = hiltViewModel<VideoPlayerViewModel>(),
videoId: String,
navController: NavHostController
) {
val context = LocalContext.current
val activity = (context as? Activity)!!
DisposableEffect(Unit) {
onDispose {
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
videoPlayerViewModel.init(videoId)
activity.requestedOrientation =
if(videoPlayerViewModel.isLandscape)
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
else
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
if (videoPlayerViewModel.startPlaying) {
if (videoPlayerViewModel.isLandscape) {
VideoPlayerLandscape(videoPlayerViewModel)
} else {
VideoPlayerPortal(videoPlayerViewModel, navController)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.acitelight.aether.view
package com.acitelight.aether.view.pages
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
@@ -65,6 +65,7 @@ import androidx.navigation.NavHostController
import coil3.request.ImageRequest
import com.acitelight.aether.CardPage
import com.acitelight.aether.Global.updateRelate
import com.acitelight.aether.view.components.VideoCard
import kotlinx.coroutines.launch
import java.nio.charset.Charset
import kotlin.collections.sortedWith
@@ -116,15 +117,23 @@ fun VideoScreen(
Column(
modifier = Modifier.fillMaxSize()
) {
Text(
text = "Videos",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier
.padding(horizontal = 8.dp)
.align(Alignment.Start)
)
// TopRow(videoScreenViewModel);
Row(Modifier.padding(bottom = 4.dp))
Row(Modifier.padding(bottom = 4.dp).padding(start = 8.dp))
{
Card(
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(horizontal = 2.dp)
.padding(horizontal = 1.dp)
.size(36.dp),
onClick = {
menuVisibility = !menuVisibility
@@ -147,7 +156,7 @@ fun VideoScreen(
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(horizontal = 2.dp)
.padding(horizontal = 1.dp)
.height(36.dp),
onClick = {
menuVisibility = !menuVisibility
@@ -199,15 +208,15 @@ fun VideoScreen(
}
}
HorizontalDivider(
Modifier.padding(bottom = 8.dp),
1.5.dp,
Modifier.padding(4.dp),
2.dp,
DividerDefaults.color
)
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Adaptive(160.dp),
contentPadding = PaddingValues(8.dp),
verticalItemSpacing = 8.dp,
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(
horizontalArrangement = Arrangement.spacedBy(
8.dp
),
state = state,
@@ -217,7 +226,7 @@ fun VideoScreen(
items = vb,
key = { "${it.first}/${it.second}" }
) { video ->
androidx.compose.foundation.layout.Box(
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
@@ -295,140 +304,3 @@ fun CatalogueItemRow(
)
}
}
@Composable
fun VideoCard(
videos: List<Video>,
navController: NavHostController,
videoScreenViewModel: VideoScreenViewModel
) {
val tabIndex by videoScreenViewModel.tabIndex;
val video = videos.first()
Card(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.combinedClickable(
onClick = {
updateRelate(
videoScreenViewModel.videoLibrary.classesMap[videoScreenViewModel.videoLibrary.classes[tabIndex]]
?: mutableStateListOf(), video
)
val vg = videos.joinToString(",") { "${it.klass}/${it.id}" }.toHex()
val route = "video_player_route/$vg"
navController.navigate(route)
},
onLongClick = {
videoScreenViewModel.viewModelScope.launch {
for(i in videos)
{
videoScreenViewModel.download(i)
}
Toast.makeText(
videoScreenViewModel.context,
"Start downloading ${video.video.group}",
Toast.LENGTH_SHORT
).show()
}
}
),
shape = RoundedCornerShape(6.dp),
) {
Column(
modifier = Modifier
.fillMaxWidth(),
) {
Box(modifier = Modifier.fillMaxSize()) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(video.getCover(videoScreenViewModel.apiClient))
.memoryCacheKey("${video.klass}/${video.id}/cover")
.diskCacheKey("${video.klass}/${video.id}/cover")
.build(),
contentDescription = null,
modifier = Modifier
.fillMaxSize(),
contentScale = ContentScale.Fit,
imageLoader = videoScreenViewModel.imageLoader!!
)
Box(
Modifier
.fillMaxWidth()
.height(24.dp)
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.6f)
)
)
)
.align(Alignment.BottomCenter)
)
Text(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(horizontal = 2.dp),
text = "${videos.size} Videos",
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
lineHeight = 13.sp,
color = Color.White
)
Text(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(horizontal = 2.dp),
text = formatTime(video.video.duration),
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
lineHeight = 13.sp,
color = Color.White
)
if (videos.all{ it.isLocal })
Card(
Modifier
.align(Alignment.TopStart)
.padding(5.dp)
.widthIn(max = 46.dp)
) {
Box(Modifier.fillMaxWidth())
{
Text(
modifier = Modifier.align(Alignment.Center),
text = "Local",
fontSize = 14.sp,
fontWeight = FontWeight.Bold
)
}
}
}
Text(
text = video.video.group ?: video.video.name,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
maxLines = 4,
modifier = Modifier
.padding(8.dp)
.background(Color.Transparent)
.heightIn(min = 24.dp),
lineHeight = 14.sp
)
Spacer(modifier = Modifier.weight(1f))
Row(
modifier = Modifier.padding(horizontal = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text("Class: ", fontSize = 10.sp, maxLines = 1)
Text(video.klass, fontSize = 10.sp, maxLines = 1)
}
}
}
}

View File

@@ -15,7 +15,7 @@ import com.acitelight.aether.service.ApiClient
import com.acitelight.aether.service.FetchManager
import com.acitelight.aether.service.MediaManager
import com.acitelight.aether.service.VideoLibrary
import com.acitelight.aether.view.toHex
import com.acitelight.aether.view.pages.toHex
import com.tonyodev.fetch2.Download
import com.tonyodev.fetch2.FetchListener
import com.tonyodev.fetch2.Status

View File

@@ -36,8 +36,8 @@ import com.acitelight.aether.service.ApiClient
import com.acitelight.aether.service.MediaManager
import com.acitelight.aether.service.RecentManager
import com.acitelight.aether.service.VideoLibrary
import com.acitelight.aether.view.formatTime
import com.acitelight.aether.view.hexToString
import com.acitelight.aether.view.pages.formatTime
import com.acitelight.aether.view.pages.hexToString
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope