6 Commits

Author SHA1 Message Date
rootacite
c3e0a23ed1 [update] Comic sort policy 2025-10-29 20:14:07 +08:00
acite
7be18dd517 [feat] Playlist remember 2025-10-09 11:33:34 +08:00
acite
a13ddbdd87 [feat] Live framework. 2025-10-06 22:54:08 +08:00
acite
390094b8b0 [fix&optimize] Fix the issue of element teleportation in ComicScreen pages 2025-10-02 12:24:26 +08:00
acite
b360724dca [fix] Chapter progress 2025-10-02 01:34:09 +08:00
acite
db8d5ef4d5 [fix] Cover height meansure 2025-10-02 01:20:13 +08:00
15 changed files with 313 additions and 152 deletions

View File

@@ -56,6 +56,7 @@ import com.acitelight.aether.view.pages.ComicGridView
import com.acitelight.aether.view.pages.ComicPageView import com.acitelight.aether.view.pages.ComicPageView
import com.acitelight.aether.view.pages.ComicScreen import com.acitelight.aether.view.pages.ComicScreen
import com.acitelight.aether.view.pages.HomeScreen import com.acitelight.aether.view.pages.HomeScreen
import com.acitelight.aether.view.pages.LiveScreen
import com.acitelight.aether.view.pages.MeScreen import com.acitelight.aether.view.pages.MeScreen
import com.acitelight.aether.view.pages.TransmissionScreen import com.acitelight.aether.view.pages.TransmissionScreen
import com.acitelight.aether.view.pages.VideoPlayer import com.acitelight.aether.view.pages.VideoPlayer
@@ -179,12 +180,21 @@ fun AppNavigation() {
TransmissionScreen(navigator = navController) TransmissionScreen(navigator = navController)
} }
} }
composable(Screen.Live.route,
enterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Start, animationSpec = tween(200)) },
exitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Start, animationSpec = tween(200)) },
popEnterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.End, animationSpec = tween(200)) },
popExitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.End, animationSpec = tween(200)) }) {
LiveScreen()
}
composable(Screen.Me.route, composable(Screen.Me.route,
enterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Start, animationSpec = tween(200)) }, enterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Start, animationSpec = tween(200)) },
exitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Start, animationSpec = tween(200)) }, exitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Start, animationSpec = tween(200)) },
popEnterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.End, animationSpec = tween(200)) }, popEnterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.End, animationSpec = tween(200)) },
popExitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.End, animationSpec = tween(200)) }) { popExitTransition = { slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.End, animationSpec = tween(200)) }) {
MeScreen(); MeScreen()
} }
composable( composable(
@@ -246,6 +256,7 @@ fun BottomNavigationBar(navController: NavController) {
Screen.Video, Screen.Video,
Screen.Comic, Screen.Comic,
Screen.Transmission, Screen.Transmission,
Screen.Live,
Screen.Me Screen.Me
) else listOf( ) else listOf(
Screen.Video, Screen.Video,
@@ -310,6 +321,8 @@ sealed class Screen(val route: String, val icon: ImageVector, val title: String)
data object Comic : Screen("comic_route", Icons.Filled.Image, "Comic") data object Comic : Screen("comic_route", Icons.Filled.Image, "Comic")
data object Transmission : Screen("transmission_route", data object Transmission : Screen("transmission_route",
Icons.AutoMirrored.Filled.CompareArrows, "Transmission") Icons.AutoMirrored.Filled.CompareArrows, "Transmission")
data object Live : Screen("live_route",
Icons.Filled.LiveTv, "Live")
data object Me : Screen("me_route", Icons.Filled.AccountCircle, "me") data object Me : Screen("me_route", Icons.Filled.AccountCircle, "me")
data object VideoPlayer : Screen("video_player_route/{videoId}", Icons.Filled.PlayArrow, "VideoPlayer") data object VideoPlayer : Screen("video_player_route/{videoId}", Icons.Filled.PlayArrow, "VideoPlayer")
data object ComicGrid : Screen("comic_grid_route/{comicId}", Icons.Filled.PlayArrow, "ComicGrid") data object ComicGrid : Screen("comic_grid_route/{comicId}", Icons.Filled.PlayArrow, "ComicGrid")

View File

@@ -46,6 +46,9 @@ class ApiClient @Inject constructor(
fun getBase(): String{ fun getBase(): String{
return replaceAbyssProtocol(base) return replaceAbyssProtocol(base)
} }
fun getDomain(): String = domain
private var base: String = "" private var base: String = ""
private var domain: String = "" private var domain: String = ""
private var cert: String = "" private var cert: String = ""
@@ -236,7 +239,7 @@ class ApiClient @Inject constructor(
throw Exception("No reachable URL found") throw Exception("No reachable URL found")
} }
domain = selectedUrl.toHttpUrlOrNull()?.host ?: "" domain = replaceAbyssProtocol(selectedUrl).toHttpUrlOrNull()?.host ?: ""
cert = crt cert = crt
base = selectedUrl base = selectedUrl
withContext(Dispatchers.IO) withContext(Dispatchers.IO)

View File

@@ -156,7 +156,7 @@ class MediaManager @Inject constructor(
{ {
try{ try{
val j = apiClient.api!!.getComics() val j = apiClient.api!!.getComics()
return j return j.sorted()
}catch (_: Exception) }catch (_: Exception)
{ {
return listOf() return listOf()

View File

@@ -64,11 +64,11 @@ fun ComicCard(
.diskCacheKey("${comic.id}/cover") .diskCacheKey("${comic.id}/cover")
.build(), .build(),
contentDescription = null, contentDescription = null,
imageLoader = comicScreenViewModel.imageLoader!!,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.clip(RoundedCornerShape(8.dp)), .clip(RoundedCornerShape(8.dp)),
contentScale = ContentScale.Crop, contentScale = ContentScale.Fit,
imageLoader = comicScreenViewModel.imageLoader!!,
) )
Box( Box(
@@ -100,22 +100,21 @@ fun ComicCard(
} }
Text( Text(
text = comic.comic.comic_name, text = comic.comic.comic_name,
fontSize = 14.sp, fontSize = 12.sp,
lineHeight = 17.sp, lineHeight = 14.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
maxLines = 2, maxLines = 2,
modifier = Modifier
.padding(4.dp)
.heightIn(min = 14.dp)
)
Text(
text = "Id: ${comic.id}",
fontSize = 10.sp,
lineHeight = 12.sp,
maxLines = 1,
modifier = Modifier.padding(4.dp) 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)
)
}
} }
} }
} }

View File

@@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
@@ -52,6 +53,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@@ -87,6 +89,18 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
val activity = (context as? Activity)!! val activity = (context as? Activity)!!
val exoPlayer: ExoPlayer = videoPlayerViewModel.player!! val exoPlayer: ExoPlayer = videoPlayerViewModel.player!!
val name by videoPlayerViewModel.currentName
val id by videoPlayerViewModel.currentId
val listState = rememberLazyListState()
val videos = videoPlayerViewModel.videos
LaunchedEffect(id, videos) {
val targetIndex = videos.indexOfFirst { it.id == id }
if (targetIndex >= 0) {
listState.scrollToItem(targetIndex)
}
}
val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager } val audioManager = remember { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager }
val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) } val maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
var volFactor by remember { var volFactor by remember {
@@ -95,9 +109,6 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
) )
} }
val name by videoPlayerViewModel.currentName
val id by videoPlayerViewModel.currentId
fun setVolume(value: Int) { fun setVolume(value: Int) {
audioManager.setStreamVolume( audioManager.setStreamVolume(
AudioManager.STREAM_MUSIC, AudioManager.STREAM_MUSIC,
@@ -229,7 +240,9 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
} }
} }
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier
.align(Alignment.Center)
.fillMaxWidth()
) )
} }
@@ -588,7 +601,7 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
colors = CardDefaults.cardColors(containerColor = colorScheme.surface.copy(0.75f)) colors = CardDefaults.cardColors(containerColor = colorScheme.surface.copy(0.75f))
) )
{ {
LazyColumn(contentPadding = PaddingValues(vertical = 4.dp)) { LazyColumn(state = listState, contentPadding = PaddingValues(vertical = 4.dp)) {
items(videoPlayerViewModel.videos) { item -> items(videoPlayerViewModel.videos) { item ->
MiniPlaylistCard(Modifier.padding(4.dp), video = item, imageLoader = videoPlayerViewModel.imageLoader!!, MiniPlaylistCard(Modifier.padding(4.dp), video = item, imageLoader = videoPlayerViewModel.imageLoader!!,
selected = id == item.id, apiClient = videoPlayerViewModel.apiClient) selected = id == item.id, apiClient = videoPlayerViewModel.apiClient)

View File

@@ -260,7 +260,7 @@ fun VideoPlayerPortal(
playList.add("${i.klass}/${i.id}") playList.add("${i.klass}/${i.id}")
} }
val route = "video_player_route/${playList.joinToString(",").toHex()}" val route = "video_player_route/${(playList.joinToString(",") + "|${i.id}").toHex()}"
navController.navigate(route) navController.navigate(route)
} }
HorizontalDivider( HorizontalDivider(

View File

@@ -95,9 +95,10 @@ fun ComicGridView(
} }
} }
LaunchedEffect(Unit) { LaunchedEffect(comicGridViewModel) {
comicGridViewModel.coverHeight = screenHeight * 0.4f comicGridViewModel.coverHeight = screenHeight * 0.3f
comicGridViewModel.maxHeight = screenHeight * 0.8f if(comicGridViewModel.maxHeight == 0.dp)
comicGridViewModel.maxHeight = screenHeight * 0.8f
} }
val dens = LocalDensity.current val dens = LocalDensity.current
@@ -251,7 +252,7 @@ fun ComicGridView(
fontSize = 11.sp, fontSize = 11.sp,
lineHeight = 15.sp, lineHeight = 15.sp,
maxLines = 3, maxLines = 3,
modifier = Modifier.padding(horizontal = 16.dp).padding(bottom = 4.dp) modifier = Modifier.padding(horizontal = 16.dp).padding(bottom = 4.dp).align(Alignment.CenterStart)
) )
Button(onClick = { Button(onClick = {
@@ -378,10 +379,10 @@ fun ChapterCard(
{ {
Text( Text(
text = chapter.name, text = chapter.name,
fontSize = 14.sp, fontSize = 16.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
maxLines = 2, maxLines = 2,
lineHeight = 16.sp, lineHeight = 18.sp,
modifier = Modifier modifier = Modifier
.padding(horizontal = 8.dp).padding(vertical = 4.dp) .padding(horizontal = 8.dp).padding(vertical = 4.dp)
.background(Color.Transparent) .background(Color.Transparent)
@@ -390,7 +391,6 @@ fun ChapterCard(
text = "${comic.getChapterLength(chapter.page)} Pages", text = "${comic.getChapterLength(chapter.page)} Pages",
fontSize = 14.sp, fontSize = 14.sp,
lineHeight = 16.sp, lineHeight = 16.sp,
fontWeight = FontWeight.Bold,
maxLines = 1, maxLines = 1,
modifier = Modifier modifier = Modifier
.padding(horizontal = 8.dp) .padding(horizontal = 8.dp)

View File

@@ -5,15 +5,18 @@ import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
@@ -36,7 +39,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
@@ -50,6 +55,7 @@ import coil3.compose.AsyncImage
import coil3.request.ImageRequest import coil3.request.ImageRequest
import com.acitelight.aether.model.BookMark import com.acitelight.aether.model.BookMark
import com.acitelight.aether.setFullScreen import com.acitelight.aether.setFullScreen
import com.acitelight.aether.view.components.BiliMiniSlider
import com.acitelight.aether.view.components.BookmarkPop import com.acitelight.aether.view.components.BookmarkPop
import com.acitelight.aether.viewModel.ComicPageViewModel import com.acitelight.aether.viewModel.ComicPageViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -92,13 +98,17 @@ fun ComicPageView(
.fillMaxSize() .fillMaxSize()
.align(Alignment.Center) .align(Alignment.Center)
.background(Color.Black) .background(Color.Black)
.clickable { .pointerInput(Unit) {
showPlane = !showPlane detectTapGestures(
if (showPlane) { onTap = {
comicPageViewModel.viewModelScope.launch { showPlane = !showPlane
comicPageViewModel.listState?.scrollToItem(index = pagerState.currentPage) if (showPlane) {
comicPageViewModel.viewModelScope.launch {
comicPageViewModel.listState?.scrollToItem(index = pagerState.currentPage)
}
}
} }
} )
} }
) { page -> ) { page ->
AsyncImage( AsyncImage(
@@ -123,110 +133,103 @@ fun ComicPageView(
modifier = Modifier modifier = Modifier
.align(Alignment.TopCenter) .align(Alignment.TopCenter)
) { ) {
Box() Column(Modifier
{ .align(Alignment.TopCenter)
Column(Modifier .fillMaxWidth()
.align(Alignment.TopCenter) .background(
.fillMaxWidth()) brush = Brush.verticalGradient(
{ colors = listOf(
Card( Color.Black.copy(alpha = 0.9f),
colors = CardDefaults.cardColors(containerColor = colorScheme.primary), Color.Transparent,
shape = RoundedCornerShape(12.dp), )
modifier = Modifier )
.fillMaxWidth() ))
.padding(top = 18.dp) {
.padding(horizontal = 12.dp) Row(modifier = Modifier
.height(42.dp) .fillMaxWidth()
.padding(horizontal = 16.dp).padding(top = 16.dp))
{
Text(
text = title,
fontSize = 16.sp,
lineHeight = 19.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
color = Color.White,
modifier = Modifier
.padding(8.dp)
.padding(horizontal = 10.dp)
.weight(1f)
.align(Alignment.CenterVertically)
) )
{
Row(modifier = Modifier.fillMaxSize())
{
Text(
text = title,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
modifier = Modifier
.padding(8.dp)
.padding(horizontal = 10.dp)
.weight(1f)
.align(Alignment.CenterVertically)
)
Text( Text(
text = "${pagerState.currentPage + 1}/${pagerState.pageCount}", text = "${pagerState.currentPage + 1}/${pagerState.pageCount}",
fontSize = 18.sp, fontSize = 16.sp,
fontWeight = FontWeight.Bold, lineHeight = 19.sp,
maxLines = 1, fontWeight = FontWeight.Bold,
modifier = Modifier maxLines = 1,
.padding(8.dp) color = Color.White,
.widthIn(min = 60.dp) modifier = Modifier
.align(Alignment.CenterVertically) .padding(8.dp)
) .widthIn(min = 60.dp)
} .align(Alignment.CenterVertically)
)
}
Box(Modifier.fillMaxWidth()
.padding(horizontal = 16.dp))
{
Row {
val k = it.getPageChapterIndex(pagerState.currentPage)
Text(
text = k.first.name,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
color = Color.White,
modifier = Modifier
.padding(8.dp)
.padding(horizontal = 10.dp)
.align(Alignment.CenterVertically)
)
Text(
text = "${k.second}/${it.getChapterLength(k.first.page)}",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
color = Color.White,
modifier = Modifier
.padding(8.dp)
.widthIn(min = 60.dp)
.align(Alignment.CenterVertically)
)
} }
Box(Modifier.fillMaxWidth()) {
Card(
modifier = Modifier
.align(Alignment.CenterStart)
.padding(top = 6.dp)
.padding(horizontal = 12.dp)
.height(42.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
shape = RoundedCornerShape(12.dp)
)
{
Row {
val k = it.getPageChapterIndex(pagerState.currentPage)
Text(
text = k.first.name,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
modifier = Modifier
.padding(8.dp)
.padding(horizontal = 10.dp)
.align(Alignment.CenterVertically)
)
Text( Card(
text = "${k.second}/${it.getChapterLength(k.first.page)}", modifier = Modifier
fontSize = 18.sp, .align(Alignment.CenterEnd)
fontWeight = FontWeight.Bold, .padding(top = 6.dp)
maxLines = 1, .padding(horizontal = 12.dp)
modifier = Modifier .height(42.dp),
.padding(8.dp) colors = CardDefaults.cardColors(containerColor = colorScheme.surface),
.widthIn(min = 60.dp) shape = RoundedCornerShape(12.dp)
.align(Alignment.CenterVertically) )
) {
} Box(Modifier.clickable {
} showBookMarkPop = true
}) {
Icon(
Card( Icons.Filled.Bookmarks,
modifier = Modifier modifier = Modifier
.align(Alignment.CenterEnd) .padding(8.dp),
.padding(top = 6.dp) contentDescription = "Bookmark"
.padding(horizontal = 12.dp) )
.height(42.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
shape = RoundedCornerShape(12.dp)
)
{
Box(Modifier.clickable {
showBookMarkPop = true
}) {
Icon(
Icons.Filled.Bookmarks,
modifier = Modifier
.padding(8.dp),
contentDescription = "Bookmark"
)
}
} }
} }
} }
Spacer(Modifier.height(64.dp))
} }
} }
@@ -238,15 +241,24 @@ fun ComicPageView(
.align(Alignment.BottomCenter) .align(Alignment.BottomCenter)
) )
{ {
Box { val k = it.getPageChapterIndex(pagerState.currentPage)
Column(Modifier
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.9f),
)
)
)) {
Spacer(Modifier.height(42.dp))
LazyRow( LazyRow(
horizontalArrangement = Arrangement.spacedBy(5.dp), horizontalArrangement = Arrangement.spacedBy(5.dp),
state = comicPageViewModel.listState!!, modifier = Modifier state = comicPageViewModel.listState!!, modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 18.dp) .padding(bottom = 1.dp)
.padding(horizontal = 12.dp) .padding(horizontal = 12.dp)
.height(180.dp) .height(180.dp)
.align(Alignment.BottomCenter)
) )
{ {
items(comicPageViewModel.pageList.size) items(comicPageViewModel.pageList.size)
@@ -262,7 +274,7 @@ fun ComicPageView(
pagerState.requestScrollToPage(page = r) pagerState.requestScrollToPage(page = r)
} }
) { ) {
Box(Modifier.padding(1.dp)) Box(Modifier.padding(0.dp))
{ {
AsyncImage( AsyncImage(
model = ImageRequest.Builder(LocalContext.current) model = ImageRequest.Builder(LocalContext.current)
@@ -306,6 +318,20 @@ fun ComicPageView(
} }
} }
} }
BiliMiniSlider(
value = (k.second.toInt()) / it.getChapterLength(k.first.page).toFloat(),
modifier = Modifier
.height(6.dp)
.fillMaxWidth().padding(horizontal = 24.dp)
.fillMaxWidth(),
onValueChange = {
}
)
Spacer(Modifier.height(24.dp))
} }
} }
} }

View File

@@ -133,9 +133,11 @@ fun ComicScreen(
var searchFilter by comicScreenViewModel.searchFilter var searchFilter by comicScreenViewModel.searchFilter
Column { Column {
Row(Modifier Row(
.padding(4.dp) Modifier
.align(Alignment.CenterHorizontally)) { .padding(4.dp)
.align(Alignment.CenterHorizontally)
) {
Text( Text(
text = "Comics", text = "Comics",
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineMedium,
@@ -176,9 +178,9 @@ fun ComicScreen(
VariableGrid( VariableGrid(
modifier = Modifier modifier = Modifier
.heightIn(max = 88.dp) .heightIn(max = 72.dp)
.padding(4.dp), .padding(4.dp),
rowHeight = 32.dp rowHeight = 30.dp
) )
{ {
for (i in comicScreenViewModel.tags) { for (i in comicScreenViewModel.tags) {
@@ -189,7 +191,8 @@ fun ComicScreen(
if (included.contains(i)) Color.Green.copy(alpha = 0.65f) else colorScheme.surface, if (included.contains(i)) Color.Green.copy(alpha = 0.65f) else colorScheme.surface,
shape = RoundedCornerShape(4.dp) shape = RoundedCornerShape(4.dp)
) )
.height(32.dp).widthIn(max = 72.dp) .height(32.dp)
.widthIn(max = 72.dp)
.clickable { .clickable {
if (included.contains(i)) if (included.contains(i))
included.remove(i) included.remove(i)
@@ -221,14 +224,17 @@ fun ComicScreen(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
items( items(
items = comicScreenViewModel.comics.filter { searchFilter.isEmpty() || searchFilter in it.comic.comic_name }.filter { x -> items = comicScreenViewModel.comics
included.all { y -> y in x.comic.tags } || included.isEmpty() .filter { searchFilter.isEmpty() || searchFilter in it.comic.comic_name }
}, .filter { x ->
included.all { y -> y in x.comic.tags } || included.isEmpty()
},
key = { it.id } key = { it.id }
) { comic -> ) { comic ->
Box(modifier = Modifier Box(
.fillMaxWidth() modifier = Modifier
.wrapContentHeight() .fillMaxWidth()
.wrapContentHeight()
) { ) {
ComicCard(comic, navController, comicScreenViewModel) ComicCard(comic, navController, comicScreenViewModel)
} }

View File

@@ -0,0 +1,13 @@
package com.acitelight.aether.view.pages
import androidx.compose.runtime.Composable
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.acitelight.aether.viewModel.LiveScreenViewModel
@Composable
fun LiveScreen(
liveScreenViewModel: LiveScreenViewModel = hiltViewModel<LiveScreenViewModel>()
)
{
}

View File

@@ -15,6 +15,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Key import androidx.compose.material.icons.filled.Key
import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.Link
import androidx.compose.material.icons.filled.Person import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Textsms
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.Checkbox import androidx.compose.material3.Checkbox
@@ -41,6 +42,7 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = hiltViewModel<MeScreenViewMo
var privateKey by meScreenViewModel.privateKey var privateKey by meScreenViewModel.privateKey
var url by meScreenViewModel.url var url by meScreenViewModel.url
var cert by meScreenViewModel.cert var cert by meScreenViewModel.cert
var pak by meScreenViewModel.pak
val uss by meScreenViewModel.uss.collectAsState(initial = false) val uss by meScreenViewModel.uss.collectAsState(initial = false)
@@ -50,7 +52,8 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = hiltViewModel<MeScreenViewMo
.padding(8.dp), .padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top verticalArrangement = Arrangement.Top
) { )
{
// Card component for a clean, contained UI block // Card component for a clean, contained UI block
item{ item{
Card( Card(
@@ -196,6 +199,54 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = hiltViewModel<MeScreenViewMo
} }
} }
} }
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
)
{
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Toolbox",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier
.padding(bottom = 16.dp)
.align(Alignment.Start)
)
Spacer(modifier = Modifier.width(8.dp))
OutlinedTextField(
value = pak,
onValueChange = { pak = it },
label = { Text("Packet") },
leadingIcon = {
Icon(Icons.Default.Textsms, contentDescription = "Packet")
},
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(8.dp))
Row{
Button(
onClick = {
meScreenViewModel.sendPacket(pak)
},
modifier = Modifier.weight(0.5f).padding(8.dp)
) {
Text("Send")
}
}
}
}
} }
} }
} }

View File

@@ -32,7 +32,7 @@ class ComicGridViewModel @Inject constructor(
) : ViewModel() ) : ViewModel()
{ {
var coverHeight by mutableStateOf(220.dp) var coverHeight by mutableStateOf(220.dp)
var maxHeight = 220.dp var maxHeight = 0.dp
var imageLoader: ImageLoader? = null var imageLoader: ImageLoader? = null
var comic = mutableStateOf<Comic?>(null) var comic = mutableStateOf<Comic?>(null)

View File

@@ -61,7 +61,7 @@ class ComicScreenViewModel @Inject constructor(
val m = mediaManager.queryComicInfoBulk(l) val m = mediaManager.queryComicInfoBulk(l)
if(m != null) { if(m != null) {
comics.addAll(m.sortedWith(compareBy(naturalOrder()) { it.comic.comic_name })) comics.addAll(m.sortedBy { it.id.toInt() }.reversed())
tags.addAll(m.flatMap { it.comic.tags }.groupingBy { it }.eachCount() tags.addAll(m.flatMap { it.comic.tags }.groupingBy { it }.eachCount()
.entries.sortedByDescending { it.value } .entries.sortedByDescending { it.value }
.map { it.key }) .map { it.key })

View File

@@ -0,0 +1,14 @@
package com.acitelight.aether.viewModel
import androidx.lifecycle.ViewModel
import com.acitelight.aether.service.ApiClient
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class LiveScreenViewModel @Inject constructor(
val apiClient: ApiClient
) : ViewModel(){
}

View File

@@ -18,6 +18,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@@ -33,6 +36,7 @@ class MeScreenViewModel @Inject constructor(
val privateKey = mutableStateOf("") val privateKey = mutableStateOf("")
val url = mutableStateOf("") val url = mutableStateOf("")
val cert = mutableStateOf("") val cert = mutableStateOf("")
val pak = mutableStateOf("")
val uss = settingsDataStoreManager.useSelfSignedFlow val uss = settingsDataStoreManager.useSelfSignedFlow
@@ -108,7 +112,8 @@ class MeScreenViewModel @Inject constructor(
} }
} }
fun updateAccount(u: String, p: String) { fun updateAccount(u: String, p: String)
{
viewModelScope.launch { viewModelScope.launch {
settingsDataStoreManager.saveUserName(u) settingsDataStoreManager.saveUserName(u)
settingsDataStoreManager.savePrivateKey(p) settingsDataStoreManager.savePrivateKey(p)
@@ -142,4 +147,22 @@ class MeScreenViewModel @Inject constructor(
} }
} }
} }
fun sendPacket(p: String)
{
val b = (p + "\r\n").toByteArray(Charsets.UTF_8)
viewModelScope.launch {
withContext(Dispatchers.IO) {
val addr = InetAddress.getByName(apiClient.getDomain())
val socket = DatagramSocket()
val packet = DatagramPacket(
b, b.size, addr, 4096
)
socket.send(packet)
}
}
}
} }