diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6d1409a..f3474b0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) kotlin("plugin.serialization") version "1.9.0" + id("kotlin-kapt") } android { @@ -42,6 +43,9 @@ android { } dependencies { + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.ktx) + kapt("androidx.room:room-compiler:2.7.2") implementation(libs.androidx.datastore.preferences) implementation(libs.bcprov.jdk15on) implementation(libs.converter.gson) diff --git a/app/src/main/java/com/acitelight/aether/model/Comic.kt b/app/src/main/java/com/acitelight/aether/model/Comic.kt index ef9035b..51dc9d9 100644 --- a/app/src/main/java/com/acitelight/aether/model/Comic.kt +++ b/app/src/main/java/com/acitelight/aether/model/Comic.kt @@ -47,4 +47,22 @@ class Comic( return -1 } + + fun getPageChapterIndex(page: Int): Pair? + { + var p = page + while(p >= 0 && !comic.bookmarks.any{ x -> x.page == comic.list[p] }) + { + p-- + } + for(i in comic.bookmarks) + { + if(i.page == comic.list[p]) + { + return Pair(i, page - comic.list.indexOf(i.page) + 1) + } + } + + return null + } } \ No newline at end of file diff --git a/app/src/main/java/com/acitelight/aether/model/ComicRecord.kt b/app/src/main/java/com/acitelight/aether/model/ComicRecord.kt new file mode 100644 index 0000000..4598d97 --- /dev/null +++ b/app/src/main/java/com/acitelight/aether/model/ComicRecord.kt @@ -0,0 +1,13 @@ +package com.acitelight.aether.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + + +@Entity +data class ComicRecord( + @PrimaryKey(autoGenerate = false) val id: Int = 0, + @ColumnInfo(name = "name") val name: String, + @ColumnInfo(name = "position") val position: Int +) diff --git a/app/src/main/java/com/acitelight/aether/model/ComicRecordDao.kt b/app/src/main/java/com/acitelight/aether/model/ComicRecordDao.kt new file mode 100644 index 0000000..3390597 --- /dev/null +++ b/app/src/main/java/com/acitelight/aether/model/ComicRecordDao.kt @@ -0,0 +1,27 @@ +package com.acitelight.aether.model + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update +import kotlinx.coroutines.flow.Flow + +@Dao +interface ComicRecordDao { + @Query("SELECT * FROM comicrecord") + fun getAll(): Flow> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(rec: ComicRecord) + + @Update + suspend fun update(rec: ComicRecord) + + @Delete + suspend fun delete(rec: ComicRecord) + + @Query("SELECT * FROM comicrecord WHERE id = :id") + suspend fun getById(id: Int): ComicRecord? +} \ No newline at end of file diff --git a/app/src/main/java/com/acitelight/aether/model/ComicRecordDatabase.kt b/app/src/main/java/com/acitelight/aether/model/ComicRecordDatabase.kt new file mode 100644 index 0000000..6573fd6 --- /dev/null +++ b/app/src/main/java/com/acitelight/aether/model/ComicRecordDatabase.kt @@ -0,0 +1,29 @@ +package com.acitelight.aether.model + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + + +@Database(entities = [ComicRecord::class], version = 1) +abstract class ComicRecordDatabase : RoomDatabase() { + abstract fun userDao(): ComicRecordDao + + companion object { + @Volatile + private var INSTANCE: ComicRecordDatabase? = null + + fun getDatabase(context: Context): ComicRecordDatabase { + return INSTANCE ?: synchronized(this) { + val instance = Room.databaseBuilder( + context.applicationContext, + ComicRecordDatabase::class.java, + "comicrecord_database" + ).build() + INSTANCE = instance + instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/acitelight/aether/view/ComicGridView.kt b/app/src/main/java/com/acitelight/aether/view/ComicGridView.kt index c61abc7..427e722 100644 --- a/app/src/main/java/com/acitelight/aether/view/ComicGridView.kt +++ b/app/src/main/java/com/acitelight/aether/view/ComicGridView.kt @@ -1,6 +1,7 @@ package com.acitelight.aether.view 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 @@ -20,7 +21,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -37,28 +40,113 @@ import androidx.navigation.NavHostController import coil3.compose.AsyncImage import coil3.request.ImageRequest import com.acitelight.aether.Global +import com.acitelight.aether.ToggleFullScreen import com.acitelight.aether.model.BookMark import com.acitelight.aether.model.Comic +import com.acitelight.aether.model.ComicRecordDatabase import com.acitelight.aether.viewModel.ComicGridViewModel import java.util.EnumSet.range import java.util.stream.IntStream.range @Composable -fun ComicGridView(comicId: String, navController: NavHostController, comicGridViewModel: ComicGridViewModel = viewModel()) -{ +fun ComicGridView(comicId: String, navController: NavHostController, comicGridViewModel: ComicGridViewModel = viewModel()) { comicGridViewModel.SetupClient() comicGridViewModel.Resolve(comicId.hexToString()) - LazyColumn(modifier = Modifier.fillMaxWidth()) - { - items(comicGridViewModel.chapterList) - { - c -> - ChapterCard(comicGridViewModel.comic!!, navController, c, comicGridViewModel) + comicGridViewModel.updateProcess(comicId.hexToString()){} + ToggleFullScreen(false) + + val context = LocalContext.current + val comic by comicGridViewModel.comic + val record by comicGridViewModel.record + + if (comic != null) { + Column { + Box( + Modifier + .padding(horizontal = 16.dp).padding(top = 36.dp) + .background(Color.White.copy(alpha = 0.65f), shape = RoundedCornerShape(12.dp)) + ) + { + Column { + Text( + text = comic!!.comic.comic_name, + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + maxLines = 1, + modifier = Modifier.padding(4.dp) + ) + + Text( + text = comic!!.comic.author, + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + maxLines = 1, + modifier = Modifier.padding(4.dp).fillMaxWidth() + ) + } + } + + LazyColumn(modifier = Modifier.fillMaxWidth().weight(1f).padding(top = 6.dp).clip(RoundedCornerShape(6.dp))) + { + items(comicGridViewModel.chapterList) + { c -> + ChapterCard(comic!!, navController, c, comicGridViewModel) + } + } + + Box( + Modifier + .padding(horizontal = 16.dp).padding(top = 6.dp).padding(bottom = 20.dp).heightIn(min = 42.dp) + .background(Color.White.copy(alpha = 0.65f), shape = RoundedCornerShape(12.dp)) + .clickable{ + comicGridViewModel.updateProcess(comicId.hexToString()) + { + if(record != null) { + val k = comic!!.getPageChapterIndex(record!!.position)!! + val route = "comic_page_route/${"${comic!!.id}".toHex()}/${ + comic!!.getPageIndex(k.first.page) + }" + navController.navigate(route) + }else + { + val route = "comic_page_route/${"${comic!!.id}".toHex()}/${0}" + navController.navigate(route) + } + } + } + ) + { + Row(Modifier.fillMaxWidth().align(Alignment.Center).padding(horizontal = 8.dp)) { + if(record != null) + { + val k = comic!!.getPageChapterIndex(record!!.position)!! + + Text( + text = "Last Read Position: ${k.first.name} ${k.second}/${comic!!.getChapterLength(k.first.page)}", + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + maxLines = 1, + modifier = Modifier.padding(4.dp).weight(1f) + ) + }else{ + Text( + text = "Read from scratch", + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + maxLines = 1, + modifier = Modifier.padding(4.dp).weight(1f) + ) + } + } + } } } } - @Composable fun ChapterCard(comic: Comic, navController: NavHostController, chapter: BookMark, comicGridViewModel: ComicGridViewModel = viewModel()) { @@ -70,7 +158,7 @@ fun ChapterCard(comic: Comic, navController: NavHostController, chapter: BookMar modifier = Modifier .fillMaxWidth() .wrapContentHeight() - .padding(16.dp), + .padding(horizontal = 16.dp).padding(vertical = 6.dp), onClick = { val route = "comic_page_route/${"${comic.id}".toHex()}/${comic.getPageIndex(chapter.page)}" navController.navigate(route) @@ -78,10 +166,10 @@ fun ChapterCard(comic: Comic, navController: NavHostController, chapter: BookMar ) { Column(Modifier.fillMaxWidth()) { - Row(Modifier.padding(12.dp)) + Row(Modifier.padding(6.dp)) { Box(Modifier - .height(260.dp) + .height(170.dp) .clip(RoundedCornerShape(8.dp)) .background(Color(0x44FFFFFF))) { @@ -117,7 +205,7 @@ fun ChapterCard(comic: Comic, navController: NavHostController, chapter: BookMar } val r = comic.comic.list.subList(iv, iv + comic.getChapterLength(c.page)) - LazyRow(modifier = Modifier.fillMaxWidth().padding(8.dp)) { + LazyRow(modifier = Modifier.fillMaxWidth().padding(6.dp)) { items(r) { r -> @@ -126,7 +214,7 @@ fun ChapterCard(comic: Comic, navController: NavHostController, chapter: BookMar modifier = Modifier .fillMaxWidth() .wrapContentHeight() - .height(200.dp) + .height(140.dp) .padding(horizontal = 6.dp), onClick = { val route = "comic_page_route/${"${comic.id}".toHex()}/${comic.getPageIndex(r)}" diff --git a/app/src/main/java/com/acitelight/aether/view/ComicPageView.kt b/app/src/main/java/com/acitelight/aether/view/ComicPageView.kt index 1b07642..47e3b3d 100644 --- a/app/src/main/java/com/acitelight/aether/view/ComicPageView.kt +++ b/app/src/main/java/com/acitelight/aether/view/ComicPageView.kt @@ -6,6 +6,7 @@ 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.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -25,6 +26,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue @@ -44,6 +46,7 @@ import androidx.navigation.NavHostController import coil3.compose.AsyncImage import coil3.request.ImageRequest import com.acitelight.aether.ToggleFullScreen +import com.acitelight.aether.model.ComicRecord import com.acitelight.aether.viewModel.ComicPageViewModel import kotlinx.coroutines.launch @@ -57,122 +60,188 @@ fun ComicPageView(comicId: String, page: String, navController: NavHostControll val pagerState = rememberPagerState(initialPage = page.toInt(), pageCount = { comicPageViewModel.pageList.size }) var showPlane by comicPageViewModel.showPlane - Box() - { - HorizontalPager( - state = pagerState, - modifier = Modifier.fillMaxSize().align(Alignment.Center).background(Color.Black).clickable(){ - showPlane = !showPlane + comicPageViewModel.UpdateProcess(pagerState.currentPage) + + val comic by comicPageViewModel.comic + comic?.let { + Box() + { + HorizontalPager( + state = pagerState, + modifier = Modifier.fillMaxSize().align(Alignment.Center).background(Color.Black).clickable{ + showPlane = !showPlane + if(showPlane) + { + comicPageViewModel.coroutineScope?.launch { + comicPageViewModel.listState?.scrollToItem(index = pagerState.currentPage) + } + } + } + ) { + page -> + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(it.getPage(page)) + .memoryCacheKey("${it.id}/${page}") + .diskCacheKey("${it.id}/${page}") + .build(), + contentDescription = null, + imageLoader = comicPageViewModel.imageLoader!!, + modifier = Modifier.padding(8.dp).fillMaxSize(), + contentScale = ContentScale.Fit, + ) } - ) { - page -> - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(comicPageViewModel.comic!!.getPage(page)) - .memoryCacheKey("${comicPageViewModel.comic!!.id}/${page}") - .diskCacheKey("${comicPageViewModel.comic!!.id}/${page}") - .build(), - contentDescription = null, - imageLoader = comicPageViewModel.imageLoader!!, - modifier = Modifier.padding(8.dp).fillMaxSize(), - contentScale = ContentScale.Fit, - ) - } - androidx.compose.animation.AnimatedVisibility( - visible = showPlane, - enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }), - exit = slideOutVertically(targetOffsetY = { fullHeight -> -fullHeight }), - modifier = Modifier - .align(Alignment.TopCenter) - ){ - Box() - { - Box(modifier = Modifier.height(180.dp).align(Alignment.TopCenter).fillMaxWidth().background( - brush = Brush.verticalGradient( - colors = listOf( - Color.Black.copy(alpha = 0.75f), - Color.Transparent, - )))) - - - Row(modifier = Modifier - .fillMaxWidth() - .padding(top = 18.dp).padding(horizontal = 12.dp) - .height(60.dp) + androidx.compose.animation.AnimatedVisibility( + visible = showPlane, + enter = slideInVertically(initialOffsetY = { fullHeight -> -fullHeight }), + exit = slideOutVertically(targetOffsetY = { fullHeight -> -fullHeight }), + modifier = Modifier .align(Alignment.TopCenter) - .background(Color(0x90FFFFFF), shape = RoundedCornerShape(12.dp))) + ){ + Box() { - Text( - text = title, - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - color = Color.Black, - maxLines = 1, - modifier = Modifier.padding(8.dp).padding(horizontal = 10.dp).weight(1f).align(Alignment.CenterVertically) - ) + Box(modifier = Modifier.height(240.dp).align(Alignment.TopCenter).fillMaxWidth().background( + brush = Brush.verticalGradient( + colors = listOf( + Color.Black.copy(alpha = 0.75f), + Color.Transparent, + )))) - Text( - text = "${pagerState.currentPage + 1}/${pagerState.pageCount}", - fontSize = 24.sp, - fontWeight = FontWeight.Bold, - color = Color.Black, - maxLines = 1, - modifier = Modifier.padding(8.dp).widthIn(120.dp).align(Alignment.CenterVertically) - ) + Column(Modifier.align(Alignment.TopCenter).fillMaxWidth()) + { + Row(modifier = Modifier + .fillMaxWidth() + .padding(top = 18.dp).padding(horizontal = 12.dp) + .height(42.dp) + .background(Color(0x90FFFFFF), shape = RoundedCornerShape(12.dp))) + { + Text( + text = title, + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + maxLines = 1, + modifier = Modifier.padding(8.dp).padding(horizontal = 10.dp).weight(1f).align(Alignment.CenterVertically) + ) + + Text( + text = "${pagerState.currentPage + 1}/${pagerState.pageCount}", + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + maxLines = 1, + modifier = Modifier.padding(8.dp).widthIn(min = 60.dp).align(Alignment.CenterVertically) + ) + } + Row(modifier = Modifier + .padding(top = 6.dp).padding(horizontal = 12.dp) + .height(42.dp) + .background(Color(0x90FFFFFF), shape = RoundedCornerShape(12.dp))) + { + val k = it.getPageChapterIndex(pagerState.currentPage)!! + Text( + text = k.first.name, + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + maxLines = 1, + 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, + color = Color.Black, + maxLines = 1, + modifier = Modifier.padding(8.dp).widthIn(min = 60.dp).align(Alignment.CenterVertically) + ) + } + } } } - } - androidx.compose.animation.AnimatedVisibility( - visible = showPlane, - enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight }), - exit = slideOutVertically(targetOffsetY = { fullHeight -> fullHeight }), - modifier = Modifier - .align(Alignment.BottomCenter) - ) - { - Box{ - Box(modifier = Modifier.height(360.dp).align(Alignment.BottomCenter).fillMaxWidth().background( - brush = Brush.verticalGradient( - colors = listOf( - Color.Transparent, - Color.Black.copy(alpha = 0.90f), - )))) - - LazyRow (state = comicPageViewModel.listState!!, modifier = Modifier - .fillMaxWidth() - .padding(bottom = 18.dp).padding(horizontal = 12.dp) - .height(240.dp) + androidx.compose.animation.AnimatedVisibility( + visible = showPlane, + enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight }), + exit = slideOutVertically(targetOffsetY = { fullHeight -> fullHeight }), + modifier = Modifier .align(Alignment.BottomCenter) - .background(Color(0x90999999), shape = RoundedCornerShape(12.dp))) - { - items(comicPageViewModel.pageList.size) + ) + { + Box{ + Box(modifier = Modifier.height(360.dp).align(Alignment.BottomCenter).fillMaxWidth().background( + brush = Brush.verticalGradient( + colors = listOf( + Color.Transparent, + Color.Black.copy(alpha = 0.90f), + )))) + + LazyRow (state = comicPageViewModel.listState!!, modifier = Modifier + .fillMaxWidth() + .padding(bottom = 18.dp).padding(horizontal = 12.dp) + .height(240.dp) + .align(Alignment.BottomCenter) + .background(Color(0x90999999), shape = RoundedCornerShape(12.dp))) { - r -> - Card( - shape = RoundedCornerShape(12.dp), - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(horizontal = 6.dp).padding(vertical = 6.dp), - onClick = { - pagerState.requestScrollToPage(page = r) - } - ){ - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(comicPageViewModel.comic!!.getPage(r)) - .memoryCacheKey("${comicPageViewModel.comic!!.id}/${r}") - .diskCacheKey("${comicPageViewModel.comic!!.id}/${r}") - .build(), - contentDescription = null, - imageLoader = comicPageViewModel.imageLoader!!, + items(comicPageViewModel.pageList.size) + { + r -> + Card( + shape = RoundedCornerShape(12.dp), modifier = Modifier - .fillMaxSize() - .clip(RoundedCornerShape(12.dp)), - contentScale = ContentScale.Fit, - ) + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 6.dp).padding(vertical = 6.dp), + onClick = { + pagerState.requestScrollToPage(page = r) + } + ){ + Box(Modifier.fillMaxSize()) + { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(it.getPage(r)) + .memoryCacheKey("${it.id}/${r}") + .diskCacheKey("${it.id}/${r}") + .build(), + contentDescription = null, + imageLoader = comicPageViewModel.imageLoader!!, + modifier = Modifier + .fillMaxSize() + .clip(RoundedCornerShape(12.dp)) + .align(Alignment.Center), + contentScale = ContentScale.Fit, + ) + val k = it.getPageChapterIndex(r)!! + Box(Modifier + .align(Alignment.TopEnd) + .padding(6.dp) + .background(Color.Black.copy(alpha = 0.65f), shape = RoundedCornerShape(12.dp))) + { + Row{ + Text( + text = k.first.name, + fontSize = 14.sp, + fontWeight = FontWeight.Bold, + color = Color.White, + maxLines = 1, + modifier = Modifier.padding(4.dp).align(Alignment.CenterVertically) + ) + + Text( + text = "${k.second}/${it.getChapterLength(k.first.page)}", + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color.White, + maxLines = 1, + modifier = Modifier.padding(4.dp).fillMaxWidth().align(Alignment.CenterVertically) + ) + } + } + } + } } } } diff --git a/app/src/main/java/com/acitelight/aether/view/VideoScreen.kt b/app/src/main/java/com/acitelight/aether/view/VideoScreen.kt index c5b9512..4342f0c 100644 --- a/app/src/main/java/com/acitelight/aether/view/VideoScreen.kt +++ b/app/src/main/java/com/acitelight/aether/view/VideoScreen.kt @@ -72,7 +72,7 @@ fun VideoScreen(videoScreenViewModel: VideoScreenViewModel = viewModel(), navCon TopRow(videoScreenViewModel); LazyVerticalGrid( - columns = GridCells.Adaptive(200.dp), + columns = GridCells.Adaptive(160.dp), contentPadding = PaddingValues(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) diff --git a/app/src/main/java/com/acitelight/aether/viewModel/ComicGridViewModel.kt b/app/src/main/java/com/acitelight/aether/viewModel/ComicGridViewModel.kt index 8ae2f2f..7b4a68e 100644 --- a/app/src/main/java/com/acitelight/aether/viewModel/ComicGridViewModel.kt +++ b/app/src/main/java/com/acitelight/aether/viewModel/ComicGridViewModel.kt @@ -2,6 +2,8 @@ package com.acitelight.aether.viewModel import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -9,15 +11,20 @@ import coil3.ImageLoader import coil3.network.okhttp.OkHttpNetworkFetcherFactory import com.acitelight.aether.model.BookMark import com.acitelight.aether.model.Comic +import com.acitelight.aether.model.ComicRecord +import com.acitelight.aether.model.ComicRecordDatabase import com.acitelight.aether.service.ApiClient.createOkHttp import com.acitelight.aether.service.MediaManager +import com.acitelight.aether.view.hexToString import kotlinx.coroutines.launch class ComicGridViewModel : ViewModel() { var imageLoader: ImageLoader? = null - var comic: Comic? = null + var comic = mutableStateOf(null) val chapterList = mutableStateListOf() + var db: ComicRecordDatabase? = null + var record = mutableStateOf(null) @Composable fun SetupClient() @@ -28,18 +35,33 @@ class ComicGridViewModel : ViewModel() add(OkHttpNetworkFetcherFactory(createOkHttp())) } .build() + db = remember { + try{ + ComicRecordDatabase.getDatabase(context) + }catch (e: Exception) { + print(e.message) + } as ComicRecordDatabase? + } } fun Resolve(id: String) { - if(comic != null) return + if(comic.value != null) return viewModelScope.launch { - comic = MediaManager.queryComicInfo(id) - val c = comic!! + comic.value = MediaManager.queryComicInfo(id) + val c = comic.value!! for(i in c.comic.bookmarks) { chapterList.add(i) } } } + + fun updateProcess(id: String, callback: () -> Unit) + { + viewModelScope.launch { + record.value = db?.userDao()?.getById(id.toInt()) + callback() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/acitelight/aether/viewModel/ComicPageViewModel.kt b/app/src/main/java/com/acitelight/aether/viewModel/ComicPageViewModel.kt index 912b7d7..1cbbab7 100644 --- a/app/src/main/java/com/acitelight/aether/viewModel/ComicPageViewModel.kt +++ b/app/src/main/java/com/acitelight/aether/viewModel/ComicPageViewModel.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModel @@ -16,20 +17,24 @@ import androidx.lifecycle.viewModelScope import coil3.ImageLoader import coil3.network.okhttp.OkHttpNetworkFetcherFactory import com.acitelight.aether.model.Comic +import com.acitelight.aether.model.ComicRecord +import com.acitelight.aether.model.ComicRecordDatabase import com.acitelight.aether.service.ApiClient.createOkHttp import com.acitelight.aether.service.MediaManager +import com.acitelight.aether.view.hexToString import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class ComicPageViewModel : ViewModel() { var imageLoader: ImageLoader? = null - var comic: Comic? = null + var comic = mutableStateOf(null) var pageList = mutableStateListOf() var title = mutableStateOf("") var listState: LazyListState? = null var coroutineScope: CoroutineScope? = null - var showPlane = mutableStateOf(false) + var showPlane = mutableStateOf(true) + var db: ComicRecordDatabase? = null @Composable fun SetupClient() @@ -42,21 +47,38 @@ class ComicPageViewModel : ViewModel() .build() listState = rememberLazyListState() coroutineScope = rememberCoroutineScope() + + db = remember { + try{ + ComicRecordDatabase.getDatabase(context) + }catch (e: Exception) { + print(e.message) + } as ComicRecordDatabase? + } } @Composable fun Resolve(id: String, page: Int) { - if(comic != null) return + if(comic.value != null) return LaunchedEffect(id, page) { coroutineScope?.launch { - comic = MediaManager.queryComicInfo(id) - comic?.let { + comic.value = MediaManager.queryComicInfo(id) + comic.value?.let { pageList.addAll(it.comic.list) title.value = it.comic.comic_name listState?.scrollToItem(index = page) + UpdateProcess(page) } } } } + + fun UpdateProcess(page: Int) + { + if(comic.value == null) return + coroutineScope?.launch { + db?.userDao()?.insert(ComicRecord(id = comic.value!!.id.toInt(), name = comic.value!!.comic.comic_name, position = page)) + } + } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a49e2ee..734ef90 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,9 @@ okhttp = "5.1.0" retrofit = "3.0.0" retrofit2KotlinxSerializationConverter = "1.0.0" media3DatasourceOkhttp = "1.8.0" +roomCompiler = "2.7.2" +roomKtx = "2.7.2" +roomRuntime = "2.7.2" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -34,6 +37,9 @@ androidx-media3-common = { module = "androidx.media3:media3-common", version.ref androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" } androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Ui" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomCompiler" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomKtx" } +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomRuntime" } bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk15on", version.ref = "bcprovJdk15on" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coilNetworkOkhttp" }