Compare commits
7 Commits
2c4d5d2366
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9efbcdfe8a | ||
|
|
c3e0a23ed1 | ||
|
|
7be18dd517 | ||
|
|
a13ddbdd87 | ||
|
|
390094b8b0 | ||
|
|
b360724dca | ||
|
|
db8d5ef4d5 |
@@ -56,6 +56,7 @@ 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.LiveScreen
|
||||
import com.acitelight.aether.view.pages.MeScreen
|
||||
import com.acitelight.aether.view.pages.TransmissionScreen
|
||||
import com.acitelight.aether.view.pages.VideoPlayer
|
||||
@@ -179,12 +180,21 @@ fun AppNavigation() {
|
||||
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,
|
||||
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)) }) {
|
||||
MeScreen();
|
||||
MeScreen()
|
||||
}
|
||||
|
||||
composable(
|
||||
@@ -246,6 +256,7 @@ fun BottomNavigationBar(navController: NavController) {
|
||||
Screen.Video,
|
||||
Screen.Comic,
|
||||
Screen.Transmission,
|
||||
Screen.Live,
|
||||
Screen.Me
|
||||
) else listOf(
|
||||
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 Transmission : Screen("transmission_route",
|
||||
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 VideoPlayer : Screen("video_player_route/{videoId}", Icons.Filled.PlayArrow, "VideoPlayer")
|
||||
data object ComicGrid : Screen("comic_grid_route/{comicId}", Icons.Filled.PlayArrow, "ComicGrid")
|
||||
|
||||
@@ -46,6 +46,9 @@ class ApiClient @Inject constructor(
|
||||
fun getBase(): String{
|
||||
return replaceAbyssProtocol(base)
|
||||
}
|
||||
|
||||
fun getDomain(): String = domain
|
||||
|
||||
private var base: String = ""
|
||||
private var domain: String = ""
|
||||
private var cert: String = ""
|
||||
@@ -236,7 +239,7 @@ class ApiClient @Inject constructor(
|
||||
throw Exception("No reachable URL found")
|
||||
}
|
||||
|
||||
domain = selectedUrl.toHttpUrlOrNull()?.host ?: ""
|
||||
domain = replaceAbyssProtocol(selectedUrl).toHttpUrlOrNull()?.host ?: ""
|
||||
cert = crt
|
||||
base = selectedUrl
|
||||
withContext(Dispatchers.IO)
|
||||
|
||||
@@ -156,7 +156,7 @@ class MediaManager @Inject constructor(
|
||||
{
|
||||
try{
|
||||
val j = apiClient.api!!.getComics()
|
||||
return j
|
||||
return j.sorted()
|
||||
}catch (_: Exception)
|
||||
{
|
||||
return listOf()
|
||||
|
||||
@@ -64,11 +64,11 @@ fun ComicCard(
|
||||
.diskCacheKey("${comic.id}/cover")
|
||||
.build(),
|
||||
contentDescription = null,
|
||||
imageLoader = comicScreenViewModel.imageLoader!!,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(8.dp)),
|
||||
contentScale = ContentScale.Crop,
|
||||
contentScale = ContentScale.Fit,
|
||||
imageLoader = comicScreenViewModel.imageLoader!!,
|
||||
)
|
||||
|
||||
Box(
|
||||
@@ -100,22 +100,21 @@ fun ComicCard(
|
||||
}
|
||||
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)
|
||||
fontWeight = FontWeight.Bold,
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
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
|
||||
@@ -52,6 +53,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -87,6 +89,18 @@ fun VideoPlayerLandscape(videoPlayerViewModel: VideoPlayerViewModel) {
|
||||
val activity = (context as? Activity)!!
|
||||
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 maxVolume = remember { audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) }
|
||||
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) {
|
||||
audioManager.setStreamVolume(
|
||||
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))
|
||||
)
|
||||
{
|
||||
LazyColumn(contentPadding = PaddingValues(vertical = 4.dp)) {
|
||||
LazyColumn(state = listState, contentPadding = PaddingValues(vertical = 4.dp)) {
|
||||
items(videoPlayerViewModel.videos) { item ->
|
||||
MiniPlaylistCard(Modifier.padding(4.dp), video = item, imageLoader = videoPlayerViewModel.imageLoader!!,
|
||||
selected = id == item.id, apiClient = videoPlayerViewModel.apiClient)
|
||||
|
||||
@@ -260,7 +260,7 @@ fun VideoPlayerPortal(
|
||||
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)
|
||||
}
|
||||
HorizontalDivider(
|
||||
|
||||
@@ -95,8 +95,9 @@ fun ComicGridView(
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
comicGridViewModel.coverHeight = screenHeight * 0.4f
|
||||
LaunchedEffect(comicGridViewModel) {
|
||||
comicGridViewModel.coverHeight = screenHeight * 0.3f
|
||||
if(comicGridViewModel.maxHeight == 0.dp)
|
||||
comicGridViewModel.maxHeight = screenHeight * 0.8f
|
||||
}
|
||||
|
||||
@@ -251,7 +252,7 @@ fun ComicGridView(
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 15.sp,
|
||||
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 = {
|
||||
@@ -378,10 +379,10 @@ fun ChapterCard(
|
||||
{
|
||||
Text(
|
||||
text = chapter.name,
|
||||
fontSize = 14.sp,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 2,
|
||||
lineHeight = 16.sp,
|
||||
lineHeight = 18.sp,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp).padding(vertical = 4.dp)
|
||||
.background(Color.Transparent)
|
||||
@@ -390,7 +391,6 @@ fun ChapterCard(
|
||||
text = "${comic.getChapterLength(chapter.page)} Pages",
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
|
||||
@@ -5,15 +5,18 @@ import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
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.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
@@ -36,7 +39,9 @@ import androidx.compose.runtime.setValue
|
||||
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.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
@@ -50,6 +55,7 @@ import coil3.compose.AsyncImage
|
||||
import coil3.request.ImageRequest
|
||||
import com.acitelight.aether.model.BookMark
|
||||
import com.acitelight.aether.setFullScreen
|
||||
import com.acitelight.aether.view.components.BiliMiniSlider
|
||||
import com.acitelight.aether.view.components.BookmarkPop
|
||||
import com.acitelight.aether.viewModel.ComicPageViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -92,7 +98,9 @@ fun ComicPageView(
|
||||
.fillMaxSize()
|
||||
.align(Alignment.Center)
|
||||
.background(Color.Black)
|
||||
.clickable {
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onTap = {
|
||||
showPlane = !showPlane
|
||||
if (showPlane) {
|
||||
comicPageViewModel.viewModelScope.launch {
|
||||
@@ -100,6 +108,8 @@ fun ComicPageView(
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { page ->
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
@@ -123,29 +133,29 @@ fun ComicPageView(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
) {
|
||||
Box()
|
||||
{
|
||||
Column(Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.fillMaxWidth())
|
||||
{
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 18.dp)
|
||||
.padding(horizontal = 12.dp)
|
||||
.height(42.dp)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Black.copy(alpha = 0.9f),
|
||||
Color.Transparent,
|
||||
)
|
||||
)
|
||||
))
|
||||
{
|
||||
Row(modifier = Modifier.fillMaxSize())
|
||||
Row(modifier = Modifier
|
||||
.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)
|
||||
@@ -155,27 +165,19 @@ fun ComicPageView(
|
||||
|
||||
Text(
|
||||
text = "${pagerState.currentPage + 1}/${pagerState.pageCount}",
|
||||
fontSize = 18.sp,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 19.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)
|
||||
)
|
||||
Box(Modifier.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp))
|
||||
{
|
||||
Row {
|
||||
val k = it.getPageChapterIndex(pagerState.currentPage)
|
||||
@@ -184,6 +186,7 @@ fun ComicPageView(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
color = Color.White,
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.padding(horizontal = 10.dp)
|
||||
@@ -195,13 +198,13 @@ fun ComicPageView(
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
color = Color.White,
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.widthIn(min = 60.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Card(
|
||||
@@ -210,7 +213,7 @@ fun ComicPageView(
|
||||
.padding(top = 6.dp)
|
||||
.padding(horizontal = 12.dp)
|
||||
.height(42.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = colorScheme.primary),
|
||||
colors = CardDefaults.cardColors(containerColor = colorScheme.surface),
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
)
|
||||
{
|
||||
@@ -226,7 +229,7 @@ fun ComicPageView(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(64.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,15 +241,24 @@ fun ComicPageView(
|
||||
.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(
|
||||
horizontalArrangement = Arrangement.spacedBy(5.dp),
|
||||
state = comicPageViewModel.listState!!, modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 18.dp)
|
||||
.padding(bottom = 1.dp)
|
||||
.padding(horizontal = 12.dp)
|
||||
.height(180.dp)
|
||||
.align(Alignment.BottomCenter)
|
||||
)
|
||||
{
|
||||
items(comicPageViewModel.pageList.size)
|
||||
@@ -262,7 +274,7 @@ fun ComicPageView(
|
||||
pagerState.requestScrollToPage(page = r)
|
||||
}
|
||||
) {
|
||||
Box(Modifier.padding(1.dp))
|
||||
Box(Modifier.padding(0.dp))
|
||||
{
|
||||
AsyncImage(
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.acitelight.aether.view.pages
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -27,13 +33,21 @@ import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -122,6 +136,7 @@ fun VariableGrid(
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ComicScreen(
|
||||
navController: NavHostController,
|
||||
@@ -131,11 +146,18 @@ fun ComicScreen(
|
||||
val state = rememberLazyStaggeredGridState()
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
var searchFilter by comicScreenViewModel.searchFilter
|
||||
var isTagsVisible by remember { mutableStateOf(false) }
|
||||
var sortType by remember { mutableIntStateOf(0) }
|
||||
|
||||
Column {
|
||||
Row(Modifier
|
||||
Column(
|
||||
modifier = Modifier.animateContentSize()
|
||||
) {
|
||||
Row(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterHorizontally)) {
|
||||
.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
{
|
||||
Text(
|
||||
text = "Comics",
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
@@ -149,7 +171,7 @@ fun ComicScreen(
|
||||
.align(Alignment.CenterVertically)
|
||||
.height(36.dp)
|
||||
.widthIn(max = 240.dp)
|
||||
.background(colorScheme.primary, RoundedCornerShape(8.dp))
|
||||
.background(colorScheme.surface, RoundedCornerShape(8.dp))
|
||||
.padding(horizontal = 6.dp)
|
||||
) {
|
||||
Icon(
|
||||
@@ -174,11 +196,76 @@ fun ComicScreen(
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Text(
|
||||
text = "Sorted by: ",
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier.padding(horizontal = 6.dp).align(Alignment.CenterVertically)
|
||||
)
|
||||
|
||||
RadioButton(
|
||||
selected = (sortType == 0),
|
||||
onClick = { sortType = 0 },
|
||||
modifier = Modifier.align(Alignment.CenterVertically).size(24.dp)
|
||||
)
|
||||
Text(
|
||||
text = "Id",
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier.align(Alignment.CenterVertically).padding(3.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
RadioButton(
|
||||
selected = (sortType == 1),
|
||||
onClick = { sortType = 1 },
|
||||
modifier = Modifier.align(Alignment.CenterVertically).size(24.dp)
|
||||
)
|
||||
Text(
|
||||
text = "Name",
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier.align(Alignment.CenterVertically).padding(3.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
Card(
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = colorScheme.surface),
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(horizontal = 4.dp)
|
||||
.padding(vertical = 4.dp)
|
||||
.height(32.dp)
|
||||
.width(64.dp),
|
||||
onClick = {
|
||||
isTagsVisible = !isTagsVisible
|
||||
})
|
||||
{
|
||||
Row(Modifier.fillMaxSize())
|
||||
{
|
||||
Text(text = "Tags", fontWeight = FontWeight.Bold, fontSize = 16.sp, modifier = Modifier.align(Alignment.CenterVertically).padding(start = 5.dp))
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = isTagsVisible, modifier = Modifier.align(Alignment.CenterVertically).padding(end = 5.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(Modifier.padding(1.dp), thickness = 1.5.dp)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = isTagsVisible,
|
||||
enter = expandVertically(expandFrom = Alignment.Top) + fadeIn(),
|
||||
exit = shrinkVertically(shrinkTowards = Alignment.Top) + fadeOut()
|
||||
) {
|
||||
Column {
|
||||
VariableGrid(
|
||||
modifier = Modifier
|
||||
.heightIn(max = 88.dp)
|
||||
.heightIn(max = 80.dp)
|
||||
.padding(4.dp),
|
||||
rowHeight = 32.dp
|
||||
rowHeight = 30.dp
|
||||
)
|
||||
{
|
||||
for (i in comicScreenViewModel.tags) {
|
||||
@@ -189,7 +276,8 @@ fun ComicScreen(
|
||||
if (included.contains(i)) Color.Green.copy(alpha = 0.65f) else colorScheme.surface,
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
.height(32.dp).widthIn(max = 72.dp)
|
||||
.height(32.dp)
|
||||
.widthIn(max = 72.dp)
|
||||
.clickable {
|
||||
if (included.contains(i))
|
||||
included.remove(i)
|
||||
@@ -211,6 +299,8 @@ fun ComicScreen(
|
||||
}
|
||||
|
||||
HorizontalDivider(Modifier.padding(1.dp), thickness = 1.5.dp)
|
||||
}
|
||||
}
|
||||
|
||||
LazyVerticalStaggeredGrid(
|
||||
columns = StaggeredGridCells.Adaptive(120.dp),
|
||||
@@ -221,12 +311,23 @@ fun ComicScreen(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
items(
|
||||
items = comicScreenViewModel.comics.filter { searchFilter.isEmpty() || searchFilter in it.comic.comic_name }.filter { x ->
|
||||
items = comicScreenViewModel.comics
|
||||
.filter { searchFilter.isEmpty() || searchFilter in it.comic.comic_name }
|
||||
.filter { x ->
|
||||
included.all { y -> y in x.comic.tags } || included.isEmpty()
|
||||
}
|
||||
.sortedByDescending {
|
||||
when(sortType)
|
||||
{
|
||||
0 -> it.id.toInt().toString().padStart(10, '0')
|
||||
1 -> it.comic.comic_name
|
||||
else -> it.id
|
||||
}
|
||||
},
|
||||
key = { it.id }
|
||||
) { comic ->
|
||||
Box(modifier = Modifier
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
) {
|
||||
|
||||
@@ -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>()
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Key
|
||||
import androidx.compose.material.icons.filled.Link
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material.icons.filled.Textsms
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Checkbox
|
||||
@@ -41,6 +42,7 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = hiltViewModel<MeScreenViewMo
|
||||
var privateKey by meScreenViewModel.privateKey
|
||||
var url by meScreenViewModel.url
|
||||
var cert by meScreenViewModel.cert
|
||||
var pak by meScreenViewModel.pak
|
||||
|
||||
val uss by meScreenViewModel.uss.collectAsState(initial = false)
|
||||
|
||||
@@ -50,7 +52,8 @@ fun MeScreen(meScreenViewModel: MeScreenViewModel = hiltViewModel<MeScreenViewMo
|
||||
.padding(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Top
|
||||
) {
|
||||
)
|
||||
{
|
||||
// Card component for a clean, contained UI block
|
||||
item{
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class ComicGridViewModel @Inject constructor(
|
||||
) : ViewModel()
|
||||
{
|
||||
var coverHeight by mutableStateOf(220.dp)
|
||||
var maxHeight = 220.dp
|
||||
var maxHeight = 0.dp
|
||||
|
||||
var imageLoader: ImageLoader? = null
|
||||
var comic = mutableStateOf<Comic?>(null)
|
||||
|
||||
@@ -61,7 +61,7 @@ class ComicScreenViewModel @Inject constructor(
|
||||
val m = mediaManager.queryComicInfoBulk(l)
|
||||
|
||||
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()
|
||||
.entries.sortedByDescending { it.value }
|
||||
.map { it.key })
|
||||
|
||||
@@ -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(){
|
||||
|
||||
}
|
||||
@@ -18,6 +18,9 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.net.DatagramPacket
|
||||
import java.net.DatagramSocket
|
||||
import java.net.InetAddress
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -33,6 +36,7 @@ class MeScreenViewModel @Inject constructor(
|
||||
val privateKey = mutableStateOf("")
|
||||
val url = mutableStateOf("")
|
||||
val cert = mutableStateOf("")
|
||||
val pak = mutableStateOf("")
|
||||
|
||||
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 {
|
||||
settingsDataStoreManager.saveUserName(u)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user