From 0adb493b5571e92f4c67a27958f72e82e2ce7741 Mon Sep 17 00:00:00 2001 From: dracarys18 Date: Tue, 16 Nov 2021 23:14:07 +0530 Subject: [PATCH] Implemented ProgressView and first alpha release Signed-off-by: dracarys18 --- app/build.gradle | 2 +- .../karthihegde/readlist/database/BookDao.kt | 7 +- .../karthihegde/readlist/database/BookData.kt | 5 +- .../readlist/navigation/Navigation.kt | 18 +- .../navigation/screens/BookNavScreens.kt | 1 + .../readlist/navigation/screens/Screens.kt | 4 +- .../karthihegde/readlist/ui/BookDetailView.kt | 16 +- .../karthihegde/readlist/ui/CollectionView.kt | 5 +- .../readlist/ui/EditBookProgress.kt | 139 ++++++++++++++++ .../karthihegde/readlist/ui/ProgressScreen.kt | 157 +++++++++++++++++- app/src/main/res/values/strings.xml | 4 +- 11 files changed, 337 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/com/karthihegde/readlist/ui/EditBookProgress.kt diff --git a/app/build.gradle b/app/build.gradle index e36b4cd..8ce5e68 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,7 +13,7 @@ android { minSdk 21 targetSdk 31 versionCode 1 - versionName "1.0" + versionName "0.1alpha" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/com/karthihegde/readlist/database/BookDao.kt b/app/src/main/java/com/karthihegde/readlist/database/BookDao.kt index 7f80f1f..5e636b1 100644 --- a/app/src/main/java/com/karthihegde/readlist/database/BookDao.kt +++ b/app/src/main/java/com/karthihegde/readlist/database/BookDao.kt @@ -23,6 +23,9 @@ interface BookDao { @Query("SELECT EXISTS (SELECT 1 FROM book_data WHERE id = :id)") fun checkIfBookExists(id: String): LiveData - @Query("UPDATE book_data SET pages_read=:pages") - fun updatePages(pages: String) + @Query("SELECT pages_read FROM book_data WHERE id = :id") + fun getPagesRead(id: String): LiveData + + @Query("UPDATE book_data SET pages_read=:pages where id = :id") + fun updatePages(pages: Int, id: String) } diff --git a/app/src/main/java/com/karthihegde/readlist/database/BookData.kt b/app/src/main/java/com/karthihegde/readlist/database/BookData.kt index 8c5582c..8b35078 100644 --- a/app/src/main/java/com/karthihegde/readlist/database/BookData.kt +++ b/app/src/main/java/com/karthihegde/readlist/database/BookData.kt @@ -8,7 +8,10 @@ import androidx.room.PrimaryKey data class BookData( @PrimaryKey val id: String, @ColumnInfo(name = "book_name") val bookName: String, + @ColumnInfo(name = "author") val author: String, @ColumnInfo(name = "image_url") val imageUrl: String, - @ColumnInfo(name = "pages_read") val pagesRead: Int = 0 + @ColumnInfo(name = "total_pages") val totalPages: Int, + @ColumnInfo(name = "pages_read") val pagesRead: Int = 0, + @ColumnInfo(name = "insert_date") val insertDate: String, ) diff --git a/app/src/main/java/com/karthihegde/readlist/navigation/Navigation.kt b/app/src/main/java/com/karthihegde/readlist/navigation/Navigation.kt index e3d20ba..4272d34 100644 --- a/app/src/main/java/com/karthihegde/readlist/navigation/Navigation.kt +++ b/app/src/main/java/com/karthihegde/readlist/navigation/Navigation.kt @@ -1,20 +1,14 @@ package com.karthihegde.readlist.navigation -import android.app.Application import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument -import com.karthihegde.readlist.database.BookViewModel import com.karthihegde.readlist.navigation.screens.BookNavScreens import com.karthihegde.readlist.navigation.screens.Screens -import com.karthihegde.readlist.ui.BookDetailView -import com.karthihegde.readlist.ui.CollectionScreen -import com.karthihegde.readlist.ui.DiscoverScreen -import com.karthihegde.readlist.ui.ProgressView +import com.karthihegde.readlist.ui.* import com.karthihegde.readlist.utils.clickBook import com.karthihegde.readlist.utils.getBookFromId import kotlinx.coroutines.CoroutineScope @@ -42,6 +36,16 @@ fun Navigation() { BookDetailView(navHostController = navHostController) } } + composable( + route = BookNavScreens.EditView.route + "/{id}", + arguments = listOf(navArgument("id") { + type = NavType.StringType + }) + ) { ids -> + ids.arguments?.getString("id")?.let { id -> + EditBookProgress(navController = navHostController, id = id) + } + } composable(route = Screens.Collection.route) { CollectionScreen(navHostController) } diff --git a/app/src/main/java/com/karthihegde/readlist/navigation/screens/BookNavScreens.kt b/app/src/main/java/com/karthihegde/readlist/navigation/screens/BookNavScreens.kt index 219a62a..a5677c9 100644 --- a/app/src/main/java/com/karthihegde/readlist/navigation/screens/BookNavScreens.kt +++ b/app/src/main/java/com/karthihegde/readlist/navigation/screens/BookNavScreens.kt @@ -2,6 +2,7 @@ package com.karthihegde.readlist.navigation.screens sealed class BookNavScreens(val route: String) { object DetailView : BookNavScreens("detail_view") + object EditView : BookNavScreens("edit_view") fun withArgs(vararg args: String): String { return buildString { diff --git a/app/src/main/java/com/karthihegde/readlist/navigation/screens/Screens.kt b/app/src/main/java/com/karthihegde/readlist/navigation/screens/Screens.kt index a29c3bb..bae61ec 100644 --- a/app/src/main/java/com/karthihegde/readlist/navigation/screens/Screens.kt +++ b/app/src/main/java/com/karthihegde/readlist/navigation/screens/Screens.kt @@ -1,7 +1,9 @@ package com.karthihegde.readlist.navigation.screens import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* +import androidx.compose.material.icons.filled.CollectionsBookmark +import androidx.compose.material.icons.filled.Pageview +import androidx.compose.material.icons.filled.Sync import androidx.compose.ui.graphics.vector.ImageVector sealed class Screens(val route: String, val label: String, val icon: ImageVector) { diff --git a/app/src/main/java/com/karthihegde/readlist/ui/BookDetailView.kt b/app/src/main/java/com/karthihegde/readlist/ui/BookDetailView.kt index 1ce561e..f69d486 100644 --- a/app/src/main/java/com/karthihegde/readlist/ui/BookDetailView.kt +++ b/app/src/main/java/com/karthihegde/readlist/ui/BookDetailView.kt @@ -35,6 +35,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import java.text.SimpleDateFormat +import java.util.* @Composable fun BookDetailView(navHostController: NavController) { @@ -218,7 +220,19 @@ fun BackAndCollButton(item: Item, navHostController: NavController) { IconButton( onClick = { val imageLink = item.volumeInfo.imageLinks?.thumbnail ?: PLACEHOLDER_IMAGE - val data = BookData(item.id, item.volumeInfo.title, imageLink) + val author = item.volumeInfo.authors?.joinToString(",") ?: "Unknown" + val calender = Calendar.getInstance() + val dateFormat = SimpleDateFormat("MMMM dd,yyyy", Locale.getDefault()) + val date = dateFormat.format(calender.time) + val data = + BookData( + id = item.id, + bookName = item.volumeInfo.title, + imageUrl = imageLink, + author = author, + totalPages = item.volumeInfo.pageCount, + insertDate = date, + ) val dao = BookDatabase.getInstance(context).bookDatabaseDo val scope = CoroutineScope(Job() + Dispatchers.IO) scope.launch { diff --git a/app/src/main/java/com/karthihegde/readlist/ui/CollectionView.kt b/app/src/main/java/com/karthihegde/readlist/ui/CollectionView.kt index ac3def2..2c1d993 100644 --- a/app/src/main/java/com/karthihegde/readlist/ui/CollectionView.kt +++ b/app/src/main/java/com/karthihegde/readlist/ui/CollectionView.kt @@ -6,7 +6,10 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.* +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Surface +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState diff --git a/app/src/main/java/com/karthihegde/readlist/ui/EditBookProgress.kt b/app/src/main/java/com/karthihegde/readlist/ui/EditBookProgress.kt new file mode 100644 index 0000000..700289f --- /dev/null +++ b/app/src/main/java/com/karthihegde/readlist/ui/EditBookProgress.kt @@ -0,0 +1,139 @@ +package com.karthihegde.readlist.ui + +import android.app.Application +import android.widget.Toast +import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBackIosNew +import androidx.compose.material.icons.filled.Check +import androidx.compose.runtime.* +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import com.karthihegde.readlist.database.BookViewModel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlin.math.abs + +@Composable +fun EditBookProgress(navController: NavController, id: String) { + val context = LocalContext.current + var newPage = 0 + val viewModel = BookViewModel(context.applicationContext as Application) + val bookData by viewModel.dao.getBookFromId(id).observeAsState() + val pagesRead = bookData?.pagesRead?.toString() ?: "" + var isError by remember { + mutableStateOf(false) + } + var text by remember { + mutableStateOf("") + } + val borderColor = if (isSystemInDarkTheme()) Color.DarkGray else Color.LightGray + val totalPages = bookData?.totalPages ?: Int.MAX_VALUE + fun onDoneAction() { + if (!isError && text.isNotEmpty()) { + val scope = CoroutineScope(Job() + Dispatchers.IO) + scope.launch { + viewModel.dao.updatePages(pages = newPage, id = id) + } + navController.popBackStack() + } else + Toast.makeText( + context, + "Enter a Proper Page Number", + Toast.LENGTH_SHORT + ).show() + } + Scaffold(topBar = { + Box( + modifier = Modifier + .padding(top = 8.dp) + .fillMaxWidth() + ) { + IconButton( + onClick = { navController.popBackStack() }, + modifier = Modifier.align(Alignment.TopStart) + ) { + Icon( + Icons.Filled.ArrowBackIosNew, + contentDescription = "", + tint = MaterialTheme.colors.onBackground, + modifier = Modifier.shadow(elevation = 8.dp, clip = true) + ) + } + } + }) { + Column(modifier = Modifier.fillMaxSize()) { + Row( + modifier = Modifier.padding(8.dp) + ) { + Text( + text = "Pages Read:", + fontSize = 20.sp, + color = MaterialTheme.colors.onBackground, + modifier = Modifier.padding(20.dp) + ) + Row { + OutlinedTextField( + value = text, + onValueChange = { value -> + text = value + isError = try { + newPage = abs(value.toInt()) + newPage > totalPages + } catch (e: NumberFormatException) { + true + } + }, + placeholder = { Text(pagesRead, textAlign = TextAlign.Center) }, + isError = isError, + singleLine = true, + keyboardActions = KeyboardActions(onDone = { onDoneAction() }), + modifier = Modifier + .wrapContentHeight() + .fillMaxWidth(0.6f) + .padding(top = 10.dp) + .border(1.dp, color = borderColor, shape = RoundedCornerShape(12.dp)), + colors = TextFieldDefaults.textFieldColors( + backgroundColor = MaterialTheme.colors.background, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent + ) + ) + Text( + text = "/$totalPages", + fontSize = 20.sp, + color = MaterialTheme.colors.onBackground, + modifier = Modifier.padding(20.dp) + ) + } + } + Row { + Spacer(modifier = Modifier.fillMaxWidth(0.8f)) + OutlinedButton( + onClick = { + onDoneAction() + }, + shape = RoundedCornerShape(50), + colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.secondary) + ) { + Icon(Icons.Default.Check, contentDescription = "") + } + } + } + } +} diff --git a/app/src/main/java/com/karthihegde/readlist/ui/ProgressScreen.kt b/app/src/main/java/com/karthihegde/readlist/ui/ProgressScreen.kt index 1917b18..a06f7ba 100644 --- a/app/src/main/java/com/karthihegde/readlist/ui/ProgressScreen.kt +++ b/app/src/main/java/com/karthihegde/readlist/ui/ProgressScreen.kt @@ -1,15 +1,162 @@ package com.karthihegde.readlist.ui -import androidx.compose.material.Scaffold -import androidx.compose.material.Text +import android.app.Application +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DoneAll import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +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.sp import androidx.navigation.NavController +import com.karthihegde.readlist.database.BookData +import com.karthihegde.readlist.database.BookDatabase +import com.karthihegde.readlist.database.BookViewModel +import com.karthihegde.readlist.navigation.screens.BookNavScreens +import com.karthihegde.readlist.retrofit.data.ImageLinks +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch @Composable fun ProgressView(navController: NavController) { - Scaffold(bottomBar = { + Scaffold(topBar = { + TopProgressBar() + }, bottomBar = { BottomBar(navHostController = navController) - }) { - Text(text = "This is Progress Screen") + }) { paddingValues -> + val viewModel = BookViewModel(LocalContext.current.applicationContext as Application) + val books by viewModel.getAllData.observeAsState() + if (!books.isNullOrEmpty()) { + LazyColumn( + verticalArrangement = Arrangement.spacedBy(10.dp), + modifier = Modifier.padding(paddingValues) + ) { + items(books!!) { + BookProgress(navController = navController, data = it) + } + } + } else { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + text = "Nothing here so far", + fontSize = 25.sp, + style = MaterialTheme.typography.overline + ) + } + } + } +} + +@Composable +fun TopProgressBar() { + Surface(modifier = Modifier.fillMaxWidth()) { + Column(horizontalAlignment = Alignment.Start, modifier = Modifier.padding(15.dp)) { + Text( + text = "Progress", + style = MaterialTheme.typography.h3, + textAlign = TextAlign.Start, + fontWeight = FontWeight.Bold + ) + } + } +} + +@Composable +fun BookProgress(navController: NavController, data: BookData) { + val context = LocalContext.current + Surface( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = { + navController.navigate(route = BookNavScreens.DetailView.withArgs(data.id)) + }) + ) { + Text( + text = data.insertDate, + style = MaterialTheme.typography.overline, + color = MaterialTheme.colors.onBackground, + maxLines = 2, + modifier = Modifier.padding(end = 5.dp), + textAlign = TextAlign.Right + ) + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(5.dp) + ) { + Row { + BookImage( + imageLink = ImageLinks("", data.imageUrl), + ActualImageModifier = Modifier.size(100.dp), + PlaceHolderModifier = Modifier.size(100.dp) + ) + Column(modifier = Modifier.fillMaxWidth(0.7f)) { + Text( + text = data.bookName, + color = MaterialTheme.colors.onBackground, + style = MaterialTheme.typography.h6, + overflow = TextOverflow.Ellipsis + ) + Text( + text = data.author, + color = MaterialTheme.colors.secondary, + style = MaterialTheme.typography.caption + ) + Text( + text = "${data.pagesRead}/${data.totalPages}", + color = MaterialTheme.colors.onBackground, + style = MaterialTheme.typography.overline + ) + val progress = (data.pagesRead.toFloat() / data.totalPages.toFloat()) + Text( + text = "${(progress * 100).toInt()}%", + color = MaterialTheme.colors.onBackground, + style = MaterialTheme.typography.overline + ) + LinearProgressIndicator( + progress, + color = MaterialTheme.colors.primaryVariant, + backgroundColor = MaterialTheme.colors.onBackground + ) + } + } + + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.SpaceBetween + ) { + TextButton(onClick = { + navController.navigate(BookNavScreens.EditView.withArgs(data.id)) + }) { + Text(text = "Edit") + } + Spacer(modifier = Modifier.weight(1f, true)) + IconButton(onClick = { + val dao = BookDatabase.getInstance(context) + val scope = CoroutineScope(Job() + Dispatchers.IO) + scope.launch { + dao.bookDatabaseDo.updatePages(pages = data.totalPages, id = data.id) + } + }) { + Icon(Icons.Default.DoneAll, contentDescription = "") + } + } + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bef3975..7bae6d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - readlist - \ No newline at end of file + Readlist +