From eb32f0412b6d3baae7fc47e9deb9c561097834ba Mon Sep 17 00:00:00 2001 From: minjoojeon Date: Wed, 6 Dec 2023 22:36:46 +0900 Subject: [PATCH 01/15] fix: apply paddings changed in viewer settings, switch positions of plus and minus buttons in viewer settings; feat: set min/max value for viewer settings, change condition for ai from pages to number of characters; --- frontend/app/src/main/assets/sample_text.txt | 5 +- .../ui/screens/settings/ViewerView.kt | 75 ++++++++++++------- .../ui/screens/viewer/ViewerView.kt | 6 +- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/frontend/app/src/main/assets/sample_text.txt b/frontend/app/src/main/assets/sample_text.txt index bdea18d..4fa9a83 100644 --- a/frontend/app/src/main/assets/sample_text.txt +++ b/frontend/app/src/main/assets/sample_text.txt @@ -1,4 +1,5 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut et rutrum velit. Nunc quis rutrum sem. Fusce nunc nisl, vulputate ac enim id, semper consequat magna. Vivamus maximus magna nunc, eu mattis velit fringilla tempor. Praesent egestas consequat varius. Aenean vulputate non justo vitae faucibus. Sed pellentesque elementum velit sit amet dapibus. Quisque tristique faucibus dolor, at sagittis ante sollicitudin suscipit. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut et rutrum velit. + Nunc quis rutrum sem. Fusce nunc nisl, vulputate ac enim id, semper consequat magna. Vivamus maximus magna nunc, eu mattis velit fringilla tempor. Praesent egestas consequat varius. Aenean vulputate non justo vitae faucibus. Sed pellentesque elementum velit sit amet dapibus. Quisque tristique faucibus dolor, at sagittis ante sollicitudin suscipit. Quisque sapien mi, auctor sed accumsan in, venenatis vitae metus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed vel porttitor libero. Phasellus vitae odio elit. Sed eu viverra turpis. Sed efficitur vestibulum interdum. Mauris dapibus magna in tellus viverra malesuada. Etiam ligula leo, condimentum sit amet mi in, iaculis luctus arcu. Suspendisse interdum mollis sollicitudin. Ut vel nisl eros. Cras nec ex bibendum, tempus ante a, pellentesque leo. Vestibulum egestas ante non eleifend pellentesque. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. @@ -6,4 +7,4 @@ Aliquam vitae nunc enim. Praesent semper est at justo fermentum elementum. Cras Proin scelerisque ultrices feugiat. Nunc in mauris neque. Nam metus mi, malesuada quis justo eu, egestas dictum elit. In aliquam, est vel ullamcorper congue, ligula nisi euismod nulla, non condimentum lorem neque in quam. Nunc cursus purus diam, et ornare dolor eleifend quis. Duis condimentum eget magna sit amet venenatis. Donec aliquet placerat ante nec sagittis. Maecenas sed metus et tortor tincidunt convallis. Maecenas non mauris semper, luctus odio eget, commodo dolor. Suspendisse aliquam blandit nunc at euismod. Proin euismod orci et nisl tristique cursus. Aenean pharetra elit at magna rhoncus, non semper lorem tincidunt. -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tincidunt venenatis urna, sit amet sodales lorem hendrerit vehicula. Nulla facilisi. Proin rutrum mauris nec nunc varius finibus. Proin consequat venenatis lacus, nec imperdiet sem mattis sed. Aliquam in nibh a purus vehicula venenatis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis congue risus quam, at tincidunt nunc aliquet nec. Quisque et dictum velit, tempor condimentum felis. Nunc sed enim mi. Aenean in libero eget elit tincidunt venenatis eget vel libero. \ No newline at end of file +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tincidunt venenatis urna, sit amet sodales lorem hendrerit vehicula. Nulla facilisi. Proin rutrum mauris nec nunc varius finibus. Proin consequat venenatis lacus, nec imperdiet sem mattis sed. Aliquam in nibh a purus vehicula venenatis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis congue risus quam, at tincidunt nunc aliquet nec. Quisque et dictum velit, tempor condimentum felis. Nunc sed enim mi. Aenean in libero eget elit tincidunt venenatis eget vel libero. diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt index 9ce78df..1fc7337 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt @@ -96,8 +96,7 @@ fun ViewerView( ) { val width = Resources.getSystem().displayMetrics.widthPixels val padding = with(LocalDensity.current) { 16.dp.toPx() } - val pageHorizontalPadding = - with(LocalDensity.current) { viewerStyle.horizontalPadding.dp.toPx() } + val pageHorizontalPadding = with(LocalDensity.current) { viewerStyle.horizontalPadding.dp.toPx() } val pagerState = rememberPagerState(initialPage = 0) { 2 @@ -107,8 +106,7 @@ fun ViewerView( val density = LocalDensity.current Scaffold( - modifier = Modifier - .safeDrawingPadding(), + modifier = Modifier.safeDrawingPadding(), topBar = { TopAppBar(title = { Text(text = "Viewer Settings") }, navigationIcon = { IconButton(onClick = { onBack() }) { @@ -276,15 +274,16 @@ fun TextOptions( title = "Text Size", value = viewerStyle.textSize.roundToInt().toString(), onPlus = { - onViewerStyleChanged(viewerStyle.copy(textSize = viewerStyle.textSize + 1)) + onViewerStyleChanged( + viewerStyle.copy( + textSize = minOf(50f, viewerStyle.textSize + 1) + ) + ) }, onMinus = { onViewerStyleChanged( viewerStyle.copy( - textSize = maxOf( - 1f, - viewerStyle.textSize - 1, - ), + textSize = maxOf(10f,viewerStyle.textSize - 1,), ), ) }, @@ -293,30 +292,54 @@ fun TextOptions( title = "Line Height", value = "${(viewerStyle.lineHeight * 100).roundToInt()}%", onPlus = { - onViewerStyleChanged(viewerStyle.copy(lineHeight = viewerStyle.lineHeight + 0.05f)) + onViewerStyleChanged( + viewerStyle.copy( + lineHeight = minOf(6f, viewerStyle.lineHeight + 0.05f) + ) + ) }, onMinus = { - onViewerStyleChanged(viewerStyle.copy(lineHeight = viewerStyle.lineHeight - 0.05f)) + onViewerStyleChanged( + viewerStyle.copy( + lineHeight = maxOf(0.6f, viewerStyle.lineHeight - 0.05f) + ) + ) }, ) OptionWithPlusMinus( title = "Letter Spacing", value = ((viewerStyle.letterSpacing * 100).roundToInt() / 100f).toString(), onPlus = { - onViewerStyleChanged(viewerStyle.copy(letterSpacing = viewerStyle.letterSpacing + 0.01f)) + onViewerStyleChanged( + viewerStyle.copy( + letterSpacing = minOf(0.4f, viewerStyle.letterSpacing + 0.01f) + ) + ) }, onMinus = { - onViewerStyleChanged(viewerStyle.copy(letterSpacing = viewerStyle.letterSpacing - 0.01f)) + onViewerStyleChanged( + viewerStyle.copy( + letterSpacing = maxOf(0f, viewerStyle.letterSpacing - 0.01f) + ) + ) }, ) OptionWithPlusMinus( title = "Paragraph Spacing", value = "${(viewerStyle.paragraphSpacing * 100).roundToInt()}%", onPlus = { - onViewerStyleChanged(viewerStyle.copy(paragraphSpacing = viewerStyle.paragraphSpacing + 0.05f)) + onViewerStyleChanged( + viewerStyle.copy( + paragraphSpacing = minOf(3f, viewerStyle.paragraphSpacing + 0.05f) + ) + ) }, onMinus = { - onViewerStyleChanged(viewerStyle.copy(paragraphSpacing = viewerStyle.paragraphSpacing - 0.05f)) + onViewerStyleChanged( + viewerStyle.copy( + paragraphSpacing = maxOf(1f, viewerStyle.paragraphSpacing - 0.05f) + ) + ) }, ) } @@ -340,10 +363,7 @@ fun ViewerOptions( onMinus = { onViewerStyleChanged( viewerStyle.copy( - horizontalPadding = maxOf( - 0f, - viewerStyle.horizontalPadding - 1, - ), + horizontalPadding = maxOf(0f, viewerStyle.horizontalPadding - 1,), ), ) }, @@ -357,10 +377,7 @@ fun ViewerOptions( onMinus = { onViewerStyleChanged( viewerStyle.copy( - verticalPadding = maxOf( - 0f, - viewerStyle.verticalPadding - 1, - ), + verticalPadding = maxOf(0f, viewerStyle.verticalPadding - 1,), ), ) }, @@ -376,10 +393,10 @@ fun OptionWithPlusMinus(title: String, value: String, onPlus: () -> Unit, onMinu ) { Text(text = title, style = MaterialTheme.typography.bodyLarge) Spacer(modifier = Modifier.weight(1f)) - IconButton(onClick = { onPlus() }) { + IconButton(onClick = { onMinus() }) { Icon( - painter = painterResource(id = R.drawable.plus), - contentDescription = "Plus", + painter = painterResource(id = R.drawable.minus), + contentDescription = "Minus", ) } Text( @@ -388,10 +405,10 @@ fun OptionWithPlusMinus(title: String, value: String, onPlus: () -> Unit, onMinu style = MaterialTheme.typography.bodyLarge, textAlign = TextAlign.Center, ) - IconButton(onClick = { onMinus() }) { + IconButton(onClick = { onPlus() }) { Icon( - painter = painterResource(id = R.drawable.minus), - contentDescription = "Minus", + painter = painterResource(id = R.drawable.plus), + contentDescription = "Plus", ) } } diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt index 01f89f7..d25515c 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt @@ -686,6 +686,7 @@ fun ViewerOverlay( onNavigateSummary = onNavigateSummary, onNavigateQuiz = onNavigateQuiz, onUpdateSummaryProgress = onUpdateSummaryProgress, + pageSplitData = pageSplitData, ) Slider( modifier = Modifier.padding(horizontal = 16.dp), @@ -753,6 +754,7 @@ fun SummaryActions( onNavigateSummary: () -> Unit = {}, onNavigateQuiz: () -> Unit = {}, onUpdateSummaryProgress: suspend () -> Result = { Result.success(Unit) }, + pageSplitData: PageSplitData? ) { // update summary progress on every 2 seconds, if the progress is not 1 val summaryUpdateScope = rememberCoroutineScope() @@ -860,7 +862,7 @@ fun SummaryActions( } } } - } else if (pageIndex < 4) { + } else if (pageSplitData?.pageSplits?.get(pageIndex)!! < 15000) { Box( modifier = modifier .background( @@ -872,7 +874,7 @@ fun SummaryActions( contentAlignment = Alignment.Center, ) { Text( - "4 pages required for Summary and Quiz", + "Not enough pages for Summary and Quiz", style = MaterialTheme.typography.labelLarge.copy( color = MaterialTheme.colorScheme.onSurfaceVariant, ), From 32b42ce5ef8c5361a0377fec5de75c5b43b9e390 Mon Sep 17 00:00:00 2001 From: Hyungoo Kwon Date: Wed, 6 Dec 2023 22:42:55 +0900 Subject: [PATCH 02/15] fix: apply paddings changed in viewer settings --- .../ui/screens/viewer/ViewerView.kt | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt index d25515c..7bd4ac3 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt @@ -90,6 +90,7 @@ import coil.compose.AsyncImage import com.example.readability.R import com.example.readability.data.book.Book import com.example.readability.data.viewer.PageSplitData +import com.example.readability.data.viewer.ViewerStyle import com.example.readability.data.viewer.getPageIndex import com.example.readability.data.viewer.getPageProgress import com.example.readability.ui.animation.DURATION_EMPHASIZED @@ -160,7 +161,7 @@ fun ViewerView( val pageSize = pageSplitData?.pageSplits?.size ?: 0 val pageIndex = pageSplitData?.getPageIndex(bookData?.progress ?: 0.0) ?: 0 - var pageChangedByAnimation by remember { mutableStateOf(true) } + var pageChangedByAnimation by remember(pageSplitData) { mutableStateOf(true) } Box( modifier = Modifier @@ -173,6 +174,7 @@ fun ViewerView( onPageSizeChanged = { width, height -> onPageSizeChanged(width, height) }, + viewerStyle = pageSplitData?.viewerStyle ) AnimatedContent( modifier = Modifier @@ -508,10 +510,11 @@ fun BookPage( pageIndex: Int, onPageDraw: (canvas: NativeCanvas, pageIndex: Int) -> Unit = { _, _ -> }, ) { - val padding = with(LocalDensity.current) { 16.dp.toPx() } + val horizontalPadding = with(LocalDensity.current) { (pageSplitData?.viewerStyle?.horizontalPadding ?: 16f).dp.toPx() } + val verticalPadding = with(LocalDensity.current) { (pageSplitData?.viewerStyle?.verticalPadding ?: 16f).dp.toPx() } val aspectRatio = - ((pageSplitData?.width ?: 0) + padding * 2) / ((pageSplitData?.height ?: 0) + padding * 2) + ((pageSplitData?.width ?: 0) + horizontalPadding * 2) / ((pageSplitData?.height ?: 0) + verticalPadding * 2) var drawCache by remember(pageIndex, pageSplitData?.width, pageSplitData?.height, pageSplitData?.viewerStyle) { mutableStateOf(null) @@ -547,12 +550,12 @@ fun BookPage( val tempCanvas = NativeCanvas(drawCache!!) onPageDraw(tempCanvas, pageIndex) } - val sizeRatio = size.width / (pageSplitData.width + 32.dp.toPx()) + val sizeRatio = size.width / (pageSplitData.width + horizontalPadding * 2) scale( scale = sizeRatio, pivot = Offset(0f, 0f), ) { - translate(left = 16.dp.toPx(), top = 16.dp.toPx()) { + translate(left = horizontalPadding, top = verticalPadding) { canvas.nativeCanvas.drawBitmap(drawCache!!, 0f, 0f, null) } } @@ -577,7 +580,14 @@ fun BookPage( } @Composable -fun ViewerSizeMeasurer(modifier: Modifier = Modifier, onPageSizeChanged: (Int, Int) -> Unit = { _, _ -> }) { +fun ViewerSizeMeasurer( + modifier: Modifier = Modifier, + viewerStyle: ViewerStyle?, + onPageSizeChanged: (Int, Int) -> Unit = { _, _ -> } +) { + val horizontalPadding = (viewerStyle?.horizontalPadding ?: 16f).dp + val verticalPadding = (viewerStyle?.verticalPadding ?: 16f).dp + Column( modifier = modifier, ) { @@ -585,7 +595,10 @@ fun ViewerSizeMeasurer(modifier: Modifier = Modifier, onPageSizeChanged: (Int, I modifier = Modifier .weight(1f) .fillMaxWidth() - .padding(16.dp) + .padding( + horizontal = horizontalPadding, + vertical = verticalPadding + ) .onGloballyPositioned { onPageSizeChanged( it.size.width, From 17ae44eb3774469a947fcdb06ca3419cc03622e9 Mon Sep 17 00:00:00 2001 From: minjoojeon Date: Wed, 6 Dec 2023 23:20:47 +0900 Subject: [PATCH 03/15] refactor: apply Builder Pattern for ViewerStyle --- .../readability/data/viewer/FontDataSource.kt | 12 ++- .../data/viewer/SettingDatabase.kt | 16 ++++ .../data/viewer/SettingRepository.kt | 6 +- .../ui/screens/settings/ViewerView.kt | 83 +++++++++++-------- 4 files changed, 75 insertions(+), 42 deletions(-) diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt b/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt index 5fde890..bacacb8 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt +++ b/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt @@ -45,7 +45,7 @@ class FontDataSource @Inject constructor( init { customTypefaceName = "garamond" customTypeface.value = ResourcesCompat.getFont(context, R.font.garamond) - calculateReferenceCharWidth(ViewerStyle()) + calculateReferenceCharWidth(ViewerStyleBuilder().build()) updateReferenceLineHeight() } @@ -53,7 +53,12 @@ class FontDataSource @Inject constructor( * Update reference line height with current typeface */ private fun updateReferenceLineHeight() { - val fontMetrics = buildTextPaint(ViewerStyle(textSize = 16f, letterSpacing = 0f)).fontMetrics + val fontMetrics = buildTextPaint( + ViewerStyleBuilder() + .textSize(16f) + .letterSpacing(0f) + .build() + ).fontMetrics referenceLineHeight.value = fontMetrics.bottom - fontMetrics.top + fontMetrics.leading } @@ -129,8 +134,7 @@ class FontDataSource @Inject constructor( val textSizeRatio = viewerStyle.textSize / 16f val letterSpacing = viewerStyle.letterSpacing * viewerStyle.textSize * density for (i in 0 until 65536) { - charWidthArray[i] = - charWidthReferenceArray[i] * textSizeRatio + letterSpacing + charWidthArray[i] = charWidthReferenceArray[i] * textSizeRatio + letterSpacing } } } diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt b/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt index 47e73e9..56e30d4 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt +++ b/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt @@ -40,6 +40,22 @@ data class ViewerStyle( @ColumnInfo("dark_text_color") val darkTextColor: Int = md_theme_dark_onBackground.toArgb(), ) +class ViewerStyleBuilder(private var viewerStyle: ViewerStyle = ViewerStyle()) { + fun id(id: Int) = apply { viewerStyle = viewerStyle.copy(id = id) } + fun textSize(textSize: Float) = apply { viewerStyle = viewerStyle.copy(textSize = textSize) } + fun lineHeight(lineHeight: Float) = apply { viewerStyle = viewerStyle.copy(lineHeight = lineHeight) } + fun letterSpacing(letterSpacing: Float) = apply { viewerStyle = viewerStyle.copy(letterSpacing = letterSpacing) } + fun paragraphSpacing(paragraphSpacing: Float) = apply { viewerStyle = viewerStyle.copy(paragraphSpacing = paragraphSpacing) } + fun fontFamily(fontFamily: String) = apply { viewerStyle = viewerStyle.copy(fontFamily = fontFamily) } + fun verticalPadding(verticalPadding: Float) = apply { viewerStyle = viewerStyle.copy(verticalPadding = verticalPadding) } + fun horizontalPadding(horizontalPadding: Float) = apply { viewerStyle = viewerStyle.copy(horizontalPadding = horizontalPadding) } + fun brightBackgroundColor(brightBackgroundColor: Int) = apply { viewerStyle = viewerStyle.copy(brightBackgroundColor = brightBackgroundColor) } + fun darkBackgroundColor(darkBackgroundColor: Int) = apply { viewerStyle = viewerStyle.copy(darkBackgroundColor = darkBackgroundColor) } + fun brightTextColor(brightTextColor: Int) = apply { viewerStyle = viewerStyle.copy(brightTextColor = brightTextColor) } + fun darkTextColor(darkTextColor: Int) = apply { viewerStyle = viewerStyle.copy(darkTextColor = darkTextColor) } + fun build() = viewerStyle +} + @Dao interface SettingDao { @Query("SELECT * FROM ViewerStyle") diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingRepository.kt b/frontend/app/src/main/java/com/example/readability/data/viewer/SettingRepository.kt index 9ce3384..d69d8d7 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingRepository.kt +++ b/frontend/app/src/main/java/com/example/readability/data/viewer/SettingRepository.kt @@ -21,8 +21,8 @@ class SettingRepository @Inject constructor( val sampleText = MutableStateFlow("") val viewerStyle = settingDao.get().map { println("SettingRepository: viewerStyle: $it") - it ?: ViewerStyle() - }.stateIn(CoroutineScope(Dispatchers.Main), SharingStarted.Eagerly, ViewerStyle()) + it ?: ViewerStyleBuilder().build() + }.stateIn(CoroutineScope(Dispatchers.Main), SharingStarted.Eagerly, ViewerStyleBuilder().build()) init { CoroutineScope(Dispatchers.IO).launch { @@ -43,7 +43,7 @@ class SettingRepository @Inject constructor( fun resetViewerStyle() { settingDao.delete() - settingDao.insert(ViewerStyle()) + settingDao.insert(ViewerStyleBuilder().build()) } fun updateViewerStyle(viewerStyle: ViewerStyle) { diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt index 1fc7337..811c343 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt @@ -58,6 +58,7 @@ import androidx.compose.ui.unit.dp import com.example.readability.R import com.example.readability.data.viewer.FontDataSource import com.example.readability.data.viewer.ViewerStyle +import com.example.readability.data.viewer.ViewerStyleBuilder import com.example.readability.ui.theme.Gabarito import com.example.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.launch @@ -68,7 +69,7 @@ import kotlin.math.roundToInt fun ViewerPreview() { ReadabilityTheme { ViewerView( - viewerStyle = ViewerStyle(), + viewerStyle = ViewerStyleBuilder().build(), ) } } @@ -80,7 +81,7 @@ fun ViewerOptionsPreview() { Surface( modifier = Modifier.background(MaterialTheme.colorScheme.background), ) { - ViewerOptions(viewerStyle = ViewerStyle(), onViewerStyleChanged = {}) + ViewerOptions(viewerStyle = ViewerStyleBuilder().build(), onViewerStyleChanged = {}) } } } @@ -258,7 +259,11 @@ fun TextOptions( }) { fontMap.forEach { selectionOption -> DropdownMenuItem(onClick = { - onViewerStyleChanged(viewerStyle.copy(fontFamily = selectionOption.key)) + onViewerStyleChanged( + ViewerStyleBuilder(viewerStyle) + .fontFamily(selectionOption.key) + .build() + ) fontFamilyExpanded = false }, text = { Text( @@ -275,16 +280,16 @@ fun TextOptions( value = viewerStyle.textSize.roundToInt().toString(), onPlus = { onViewerStyleChanged( - viewerStyle.copy( - textSize = minOf(50f, viewerStyle.textSize + 1) - ) + ViewerStyleBuilder(viewerStyle) + .textSize(minOf(50f, viewerStyle.textSize + 1f)) + .build() ) }, onMinus = { onViewerStyleChanged( - viewerStyle.copy( - textSize = maxOf(10f,viewerStyle.textSize - 1,), - ), + ViewerStyleBuilder(viewerStyle) + .textSize(maxOf(10f, viewerStyle.textSize - 1f)) + .build() ) }, ) @@ -293,16 +298,16 @@ fun TextOptions( value = "${(viewerStyle.lineHeight * 100).roundToInt()}%", onPlus = { onViewerStyleChanged( - viewerStyle.copy( - lineHeight = minOf(6f, viewerStyle.lineHeight + 0.05f) - ) + ViewerStyleBuilder(viewerStyle) + .lineHeight(minOf(6f, viewerStyle.lineHeight + 0.05f)) + .build() ) }, onMinus = { onViewerStyleChanged( - viewerStyle.copy( - lineHeight = maxOf(0.6f, viewerStyle.lineHeight - 0.05f) - ) + ViewerStyleBuilder(viewerStyle) + .lineHeight(maxOf(0.6f, viewerStyle.lineHeight - 0.05f)) + .build() ) }, ) @@ -311,16 +316,16 @@ fun TextOptions( value = ((viewerStyle.letterSpacing * 100).roundToInt() / 100f).toString(), onPlus = { onViewerStyleChanged( - viewerStyle.copy( - letterSpacing = minOf(0.4f, viewerStyle.letterSpacing + 0.01f) - ) + ViewerStyleBuilder(viewerStyle) + .letterSpacing(minOf(0.4f, viewerStyle.letterSpacing + 0.01f)) + .build() ) }, onMinus = { onViewerStyleChanged( - viewerStyle.copy( - letterSpacing = maxOf(0f, viewerStyle.letterSpacing - 0.01f) - ) + ViewerStyleBuilder(viewerStyle) + .letterSpacing(maxOf(0f, viewerStyle.letterSpacing - 0.01f)) + .build() ) }, ) @@ -329,16 +334,16 @@ fun TextOptions( value = "${(viewerStyle.paragraphSpacing * 100).roundToInt()}%", onPlus = { onViewerStyleChanged( - viewerStyle.copy( - paragraphSpacing = minOf(3f, viewerStyle.paragraphSpacing + 0.05f) - ) + ViewerStyleBuilder(viewerStyle) + .paragraphSpacing(minOf(3f, viewerStyle.paragraphSpacing + 0.05f)) + .build() ) }, onMinus = { onViewerStyleChanged( - viewerStyle.copy( - paragraphSpacing = maxOf(1f, viewerStyle.paragraphSpacing - 0.05f) - ) + ViewerStyleBuilder(viewerStyle) + .paragraphSpacing(maxOf(1f, viewerStyle.paragraphSpacing - 0.05f)) + .build() ) }, ) @@ -358,13 +363,17 @@ fun ViewerOptions( title = "Horizontal Padding", value = viewerStyle.horizontalPadding.roundToInt().toString(), onPlus = { - onViewerStyleChanged(viewerStyle.copy(horizontalPadding = viewerStyle.horizontalPadding + 1)) + onViewerStyleChanged( + ViewerStyleBuilder(viewerStyle) + .horizontalPadding(minOf(70f, viewerStyle.horizontalPadding + 1)) + .build() + ) }, onMinus = { onViewerStyleChanged( - viewerStyle.copy( - horizontalPadding = maxOf(0f, viewerStyle.horizontalPadding - 1,), - ), + ViewerStyleBuilder(viewerStyle) + .horizontalPadding(maxOf(0f, viewerStyle.horizontalPadding - 1)) + .build() ) }, ) @@ -372,13 +381,17 @@ fun ViewerOptions( title = "Vertical Padding", value = viewerStyle.verticalPadding.roundToInt().toString(), onPlus = { - onViewerStyleChanged(viewerStyle.copy(verticalPadding = viewerStyle.verticalPadding + 1)) + onViewerStyleChanged( + ViewerStyleBuilder(viewerStyle) + .verticalPadding(minOf(110f, viewerStyle.verticalPadding + 1)) + .build() + ) }, onMinus = { onViewerStyleChanged( - viewerStyle.copy( - verticalPadding = maxOf(0f, viewerStyle.verticalPadding - 1,), - ), + ViewerStyleBuilder(viewerStyle) + .verticalPadding(maxOf(0f, viewerStyle.verticalPadding - 1)) + .build() ) }, ) From 4cdf13eafbe5d9a8bbfb30959dc2cbc8df443637 Mon Sep 17 00:00:00 2001 From: Ikjun Choi <1350adwx@snu.ac.kr> Date: Thu, 7 Dec 2023 22:13:03 +0900 Subject: [PATCH 04/15] fix: fix delete account crash, match token life to backend, fix page movement when move to another page --- .../com/example/readability/data/user/UserRepository.kt | 6 +++--- .../readability/ui/screens/settings/SettingsScreen.kt | 1 + .../example/readability/ui/screens/viewer/ViewerScreen.kt | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt index 56357f3..8bcedb7 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt +++ b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt @@ -24,9 +24,9 @@ class UserRepository @Inject constructor( userName = null, userEmail = email, refreshToken = it.refresh_token, - refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(12), + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(730), accessToken = it.access_token, - accessTokenLife = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(30), + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(365), createdAt = null, verified = null, ), @@ -73,7 +73,7 @@ class UserRepository @Inject constructor( userRemoteDataSource.refreshAccessToken(refreshToken).fold(onSuccess = { userDao.updateAccessToken( it, - System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(30), + System.currentTimeMillis() + TimeUnit.DAYS.toMillis(365), ) return Result.success(Unit) }, onFailure = { diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt index 203b292..fce0b9f 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt @@ -61,6 +61,7 @@ fun SettingsScreen( onDeleteAccount = { withContext(Dispatchers.IO) { // TODO: delete account using userViewModel + userViewModel.signOut() delay(1000L) Result.success(Unit) } diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerScreen.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerScreen.kt index d405158..531ec57 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerScreen.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerScreen.kt @@ -91,7 +91,7 @@ fun ViewerScreen( val quizViewModel: QuizViewModel = hiltViewModel() val summaryViewModel: SummaryViewModel = hiltViewModel() val bookData by viewerViewModel.getBookData(id).collectAsState(initial = null) - val pageSplitData by viewerViewModel.pageSplitData.collectAsState(initial = null) + val pageSplitData by viewerViewModel.pageSplitData.collectAsState() val isDarkTheme = isSystemInDarkTheme() val isNetworkConnected by networkStatusViewModel.connectedState.collectAsState() ViewerView( From 894822425bd44819f391f89ca3691a278b042dab Mon Sep 17 00:00:00 2001 From: h9kwon Date: Thu, 7 Dec 2023 22:27:40 +0900 Subject: [PATCH 05/15] feat: delete account --- .../readability/data/user/UserRemoteDataSource.kt | 13 +++++++++++++ .../example/readability/data/user/UserRepository.kt | 8 ++++++++ .../ui/screens/settings/SettingsScreen.kt | 9 +++++---- .../readability/ui/viewmodels/UserViewModel.kt | 2 ++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserRemoteDataSource.kt b/frontend/app/src/main/java/com/example/readability/data/user/UserRemoteDataSource.kt index b8d05b3..47d69ca 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserRemoteDataSource.kt +++ b/frontend/app/src/main/java/com/example/readability/data/user/UserRemoteDataSource.kt @@ -9,6 +9,7 @@ import retrofit2.Call import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.Body +import retrofit2.http.DELETE import retrofit2.http.Field import retrofit2.http.FormUrlEncoded import retrofit2.http.GET @@ -84,6 +85,9 @@ interface UserAPI { @POST("/user/change_password") fun changePassword(@Query("access_token") accessToken: String, @Query("password") newPassword: String): Call + + @DELETE("/user/delete_user") + fun deleteAccount(@Query("access_token") accessToken: String): Call } @InstallIn(SingletonComponent::class) @@ -180,4 +184,13 @@ class UserRemoteDataSource @Inject constructor( return Result.failure(Throwable(parseErrorBody(result.errorBody()))) } } + + suspend fun deleteAccount(accessToken: String): Result { + val result = userApi.deleteAccount(accessToken).execute() + if (result.isSuccessful) { + return Result.success(Unit) + } else { + return Result.failure(Throwable(parseErrorBody(result.errorBody()))) + } + } } diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt index 8bcedb7..6264f85 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt +++ b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt @@ -110,4 +110,12 @@ class UserRepository @Inject constructor( fun signOut() { userDao.deleteAll() } + + suspend fun deleteAccount(): Result { + val accessToken = getAccessToken() ?: return Result.failure(UserNotSignedInException()) + if (!networkStatusRepository.isConnected) { + return Result.failure(Exception("Network not connected")) + } + return userRemoteDataSource.deleteAccount(accessToken) + } } diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt index fce0b9f..d960482 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt @@ -12,7 +12,6 @@ import com.example.readability.ui.animation.composableSharedAxis import com.example.readability.ui.viewmodels.SettingViewModel import com.example.readability.ui.viewmodels.UserViewModel import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay import kotlinx.coroutines.withContext sealed class SettingsScreens(val route: String) { @@ -61,9 +60,11 @@ fun SettingsScreen( onDeleteAccount = { withContext(Dispatchers.IO) { // TODO: delete account using userViewModel - userViewModel.signOut() - delay(1000L) - Result.success(Unit) + val result = userViewModel.deleteAccount() + if (result.isSuccess) { + userViewModel.signOut() + } + result } }, onNavigateIntro = { diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/UserViewModel.kt b/frontend/app/src/main/java/com/example/readability/ui/viewmodels/UserViewModel.kt index 109b8d9..71cc866 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/UserViewModel.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/viewmodels/UserViewModel.kt @@ -54,4 +54,6 @@ class UserViewModel @Inject constructor( suspend fun getUserInfo() = userRepository.getUserInfo() suspend fun changePassword(newPassword: String) = userRepository.changePassword(newPassword) + + suspend fun deleteAccount() = userRepository.deleteAccount() } From 07d1aa149879a1802d871d757a45cb5476885c04 Mon Sep 17 00:00:00 2001 From: minjoojeon Date: Sat, 9 Dec 2023 17:32:24 +0900 Subject: [PATCH 06/15] feat: change max char size of book title --- .../java/com/example/readability/ui/screens/book/AddBookView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/book/AddBookView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/book/AddBookView.kt index 3491dd7..d784062 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/book/AddBookView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/book/AddBookView.kt @@ -103,7 +103,7 @@ fun AddBookView( var loading by remember { mutableStateOf(false) } val scope = rememberCoroutineScope() - val maxChar = 80 + val maxChar = 60 var defaultImageString = "" val defaultUri = Uri.parse( From c7907f2f239de264d3885a7fbe48571c50334202 Mon Sep 17 00:00:00 2001 From: h9kwon Date: Sat, 9 Dec 2023 21:28:09 +0900 Subject: [PATCH 07/15] fix: changed message for AI buttons --- .../com/example/readability/ui/screens/viewer/ViewerView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt index 7bd4ac3..84d84be 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt @@ -903,13 +903,13 @@ fun SummaryActions( modifier = Modifier.weight(1f), onClick = { onNavigateSummary() }, ) { - Text("Generate Summary") + Text("Summarize") } RoundedRectFilledTonalButton( modifier = Modifier.weight(1f), onClick = { onNavigateQuiz() }, ) { - Text("Generate Quiz") + Text("Solve Quiz") } } } From cf822a98fd6fc51c9d692fe93fb6a80358b53c76 Mon Sep 17 00:00:00 2001 From: Ikjun Choi <1350adwx@snu.ac.kr> Date: Sun, 10 Dec 2023 16:24:11 +0900 Subject: [PATCH 08/15] test: add unit tests for all possible data layer classes --- frontend/app/build.gradle.kts | 8 +- .../data/NetworkStatusDataSource.kt | 21 +- .../data/ai/QuizRemoteDataSource.kt | 8 + .../data/book/BookFileDataSource.kt | 76 ++-- .../readability/data/user/UserRepository.kt | 5 +- .../ui/models/UserRepositoryTest.kt | 89 ----- .../ui/models/ai/QuizRemoteDataSourceTest.kt | 247 ++++++++++++ .../ui/models/ai/QuizRepositoryTest.kt | 103 +++++ .../models/ai/SummaryRemoteDataSourceTest.kt | 155 ++++++++ .../ui/models/ai/SummaryRepositoryTest.kt | 88 ++++ .../ui/models/book/BookFileDataSourceTest.kt | 149 +++++++ .../models/book/BookRemoteDataSourceTest.kt | 245 ++++++++++++ .../models/{ => book}/BookRepositoryTest.kt | 60 ++- .../network/NetworkStatusDataSourceTest.kt | 81 ++++ .../network/NetworkStatusRepositoryTest.kt | 39 ++ .../models/user/UserRemoteDataSourceTest.kt | 228 +++++++++++ .../ui/models/user/UserRepositoryTest.kt | 375 ++++++++++++++++++ .../ui/models/viewer/FontDataSourceTest.kt | 83 ++++ .../models/viewer/PageSplitRepositoryTest.kt | 128 ++++++ .../ui/models/viewer/SettingRepositoryTest.kt | 85 ++++ 20 files changed, 2122 insertions(+), 151 deletions(-) delete mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/UserRepositoryTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt rename frontend/app/src/test/java/com/example/readability/ui/models/{ => book}/BookRepositoryTest.kt (91%) create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt create mode 100644 frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt diff --git a/frontend/app/build.gradle.kts b/frontend/app/build.gradle.kts index 3fc61eb..b6670dd 100644 --- a/frontend/app/build.gradle.kts +++ b/frontend/app/build.gradle.kts @@ -132,6 +132,7 @@ dependencies { androidTestImplementation("androidx.navigation:navigation-testing:2.7.5") androidTestImplementation("com.google.dagger:hilt-android-testing:$hiltVersion") androidTestImplementation("org.awaitility:awaitility:4.2.0") + androidTestImplementation("org.awaitility:awaitility-kotlin:4.2.0") val mocckVersion = "1.13.8" testImplementation("io.mockk:mockk:$mocckVersion") @@ -141,10 +142,3 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-test-manifest") } - -configurations.all { - resolutionStrategy.dependencySubstitution { - substitute(module("org.hamcrest:hamcrest-core:1.3")).using(module("junit:junit:4.13.2")) - substitute(module("org.hamcrest:hamcrest-library:1.3")).using(module("junit:junit:4.13.2")) - } -} diff --git a/frontend/app/src/main/java/com/example/readability/data/NetworkStatusDataSource.kt b/frontend/app/src/main/java/com/example/readability/data/NetworkStatusDataSource.kt index e85a435..1a8e322 100644 --- a/frontend/app/src/main/java/com/example/readability/data/NetworkStatusDataSource.kt +++ b/frontend/app/src/main/java/com/example/readability/data/NetworkStatusDataSource.kt @@ -4,6 +4,7 @@ import android.content.Context import android.net.ConnectivityManager import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import javax.inject.Inject import javax.inject.Singleton @@ -16,26 +17,36 @@ class NetworkStatusDataSource @Inject constructor( // a MutableStateFlow which represents the current network status // It is automatically updated when the network becomes available. // However, it is not automatically updated when the network becomes unavailable. - val connectedState = MutableStateFlow(false) + private val _connectedState = MutableStateFlow(false) + val connectedState = _connectedState.asStateFlow() val isConnected: Boolean get() { val result = connectivityManager.activeNetworkInfo?.isConnected ?: false - connectedState.value = result + _connectedState.value = result return result } init { - connectedState.value = isConnected + _connectedState.value = isConnected connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: android.net.Network) { - connectedState.value = true + super.onAvailable(network) + this@NetworkStatusDataSource.onAvailable() } // This is not actually called? override fun onUnavailable() { super.onUnavailable() - connectedState.value = false + this@NetworkStatusDataSource.onUnavailable() } }) } + + fun onAvailable() { + _connectedState.value = true + } + + fun onUnavailable() { + _connectedState.value = false + } } diff --git a/frontend/app/src/main/java/com/example/readability/data/ai/QuizRemoteDataSource.kt b/frontend/app/src/main/java/com/example/readability/data/ai/QuizRemoteDataSource.kt index 7edd43a..8f370e3 100644 --- a/frontend/app/src/main/java/com/example/readability/data/ai/QuizRemoteDataSource.kt +++ b/frontend/app/src/main/java/com/example/readability/data/ai/QuizRemoteDataSource.kt @@ -85,6 +85,9 @@ class QuizRemoteDataSource @Inject constructor( if (token.contains(":")) { updateContent(token.substring(0, token.indexOf(":"))) if (quizCount == 0) { + if (!"Number of Questions".startsWith(content.trim())) { + throw Throwable("Failed to parse quiz") + } receivingQuizCount = true } else { receivingQuiz = content.contains("Q") @@ -114,6 +117,11 @@ class QuizRemoteDataSource @Inject constructor( } else if (receivingAnswer) { emit(QuizResponse(QuizResponseType.STRING, content, 0)) content = "" + } else if (!receivingQuizCount && quizCount == 0) { + println(content) + if (!"Number of Questions".startsWith(content.trim())) { + throw Throwable("Failed to parse quiz") + } } } } diff --git a/frontend/app/src/main/java/com/example/readability/data/book/BookFileDataSource.kt b/frontend/app/src/main/java/com/example/readability/data/book/BookFileDataSource.kt index 060d406..72e0f6c 100644 --- a/frontend/app/src/main/java/com/example/readability/data/book/BookFileDataSource.kt +++ b/frontend/app/src/main/java/com/example/readability/data/book/BookFileDataSource.kt @@ -10,35 +10,63 @@ import dagger.hilt.android.qualifiers.ApplicationContext import java.io.File import java.io.FileInputStream import java.io.FileOutputStream +import java.io.InputStream +import java.io.OutputStream import javax.inject.Inject import javax.inject.Singleton +class FileHelper @Inject constructor( + @ApplicationContext private val context: Context, +) { + fun openFileInputStream(fileName: String): InputStream { + return FileInputStream(context.filesDir.path + fileName) + } + + fun openFileOutputStream(fileName: String): OutputStream { + return FileOutputStream(context.filesDir.path + fileName) + } + + fun deleteFile(fileName: String) { + File(context.filesDir.path + fileName).delete() + } + + fun exists(fileName: String): Boolean { + return File(context.filesDir.path + fileName).exists() + } + + fun mkdirsIfNotExists(fileName: String) { + if (!File(context.filesDir.path + fileName).exists()) { + File(context.filesDir.path + fileName).mkdirs() + } + } + + fun resetDirectory(fileName: String) { + File(context.filesDir.path + fileName).deleteRecursively() + File(context.filesDir.path + fileName).mkdir() + } +} + @Singleton class BookFileDataSource @Inject constructor( - @ApplicationContext private val context: Context, + private val fileHelper: FileHelper, ) { init { - if (!File(context.filesDir.path + "/book_cover").exists()) { - File(context.filesDir.path + "/book_cover").mkdir() - } - if (!File(context.filesDir.path + "/book_content").exists()) { - File(context.filesDir.path + "/book_content").mkdir() - } + fileHelper.mkdirsIfNotExists("/book_cover") + fileHelper.mkdirsIfNotExists("/book_content") } + fun contentExists(bookId: Int): Boolean { - val bookContentPath = context.filesDir.path + "/book_content/$bookId.txt" return try { - File(bookContentPath).exists() + fileHelper.exists("/book_content/$bookId.txt") } catch (e: Exception) { println("BookFileDataSource: contentExists failed: ${e.message}") false } } fun readContentFile(bookId: Int): String? { - val bookContentPath = context.filesDir.path + "/book_content/$bookId.txt" return if (contentExists(bookId)) { try { - FileInputStream(bookContentPath).bufferedReader().use { + fileHelper.openFileInputStream("/book_content/$bookId.txt").bufferedReader().use { it.readText() } } catch (e: Exception) { @@ -51,9 +79,8 @@ class BookFileDataSource @Inject constructor( } fun writeContentFile(bookId: Int, content: String) { - val bookContentPath = context.filesDir.path + "/book_content/$bookId.txt" try { - FileOutputStream(bookContentPath).bufferedWriter().use { + fileHelper.openFileOutputStream("/book_content/$bookId.txt").bufferedWriter().use { it.write(content) } } catch (e: Exception) { @@ -62,19 +89,16 @@ class BookFileDataSource @Inject constructor( } fun deleteContentFile(bookId: Int) { - val bookContentPath = context.filesDir.path + "/book_content/$bookId.txt" try { - File(bookContentPath).delete() + fileHelper.deleteFile("/book_content/$bookId.txt") } catch (e: Exception) { println("BookFileDataSource: deleteContentFile failed: ${e.message}") } } fun coverImageExists(bookId: Int): Boolean { - val coverImagePath = context.filesDir.path + "/book_cover/$bookId.png" - println("BookFileDataSource: check for exist: $coverImagePath") return try { - File(coverImagePath).exists() + fileHelper.exists("/book_cover/$bookId.png") } catch (e: Exception) { println("BookFileDataSource: coverImageExists failed: ${e.message}") false @@ -82,10 +106,9 @@ class BookFileDataSource @Inject constructor( } fun readCoverImageFile(bookId: Int): ImageBitmap? { - val coverImagePath = context.filesDir.path + "/book_cover/$bookId.png" return if (coverImageExists(bookId)) { try { - FileInputStream(coverImagePath).use { + fileHelper.openFileInputStream("/book_cover/$bookId.png").use { val byteArray = it.readBytes() BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size).asImageBitmap() } @@ -99,10 +122,8 @@ class BookFileDataSource @Inject constructor( } fun writeCoverImageFile(bookId: Int, coverImage: ImageBitmap) { - val coverImagePath = context.filesDir.path + "/book_cover/$bookId.png" - println("BookFileDataSource: write cover image: $coverImagePath") try { - FileOutputStream(coverImagePath).use { + fileHelper.openFileOutputStream("/book_cover/$bookId.png").use { coverImage.asAndroidBitmap().compress(Bitmap.CompressFormat.JPEG, 100, it) } } catch (e: Exception) { @@ -111,9 +132,8 @@ class BookFileDataSource @Inject constructor( } fun deleteCoverImageFile(bookId: Int) { - val coverImagePath = context.filesDir.path + "/book_cover/$bookId.png" try { - File(coverImagePath).delete() + fileHelper.deleteFile("/book_cover/$bookId.png") } catch (e: Exception) { println("BookFileDataSource: deleteCoverImageFile failed: ${e.message}") } @@ -121,10 +141,8 @@ class BookFileDataSource @Inject constructor( fun deleteAll() { try { - File(context.filesDir.path + "/book_cover").deleteRecursively() - File(context.filesDir.path + "/book_cover").mkdir() - File(context.filesDir.path + "/book_content").deleteRecursively() - File(context.filesDir.path + "/book_content").mkdir() + fileHelper.resetDirectory("/book_cover") + fileHelper.resetDirectory("/book_content") } catch (e: Exception) { println("BookFileDataSource: clearAll failed: ${e.message}") } diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt index 6264f85..81dc9cc 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt +++ b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt @@ -2,6 +2,7 @@ package com.example.readability.data.user import com.example.readability.data.NetworkStatusRepository import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton @@ -49,7 +50,7 @@ class UserRepository @Inject constructor( } suspend fun getRefreshToken(): String? { - val user = userDao.get().first() ?: return null + val user = userDao.get().firstOrNull() ?: return null if (user.refreshTokenLife!! < System.currentTimeMillis()) { signOut() return null @@ -58,7 +59,7 @@ class UserRepository @Inject constructor( } suspend fun getAccessToken(): String? { - val user = userDao.get().first() ?: return null + val user = userDao.get().firstOrNull() ?: return null if (user.accessTokenLife!! < System.currentTimeMillis()) { refreshAccessToken() } diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/UserRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/UserRepositoryTest.kt deleted file mode 100644 index 1dbabba..0000000 --- a/frontend/app/src/test/java/com/example/readability/ui/models/UserRepositoryTest.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.example.readability.ui.models -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.user.TokenResponse -import com.example.readability.data.user.UserDao -import com.example.readability.data.user.UserRemoteDataSource -import com.example.readability.data.user.UserRepository -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.resetMain -import kotlinx.coroutines.test.runTest -import kotlinx.coroutines.test.setMain -import org.junit.After -import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import org.mockito.ArgumentMatchers.anyString -import org.mockito.Mockito.mock -import org.mockito.Mockito.`when` - -@ExperimentalCoroutinesApi -class UserRepositoryTest { - - // classes to be mocked - private lateinit var userRemoteDataSource: UserRemoteDataSource - private lateinit var userDao: UserDao - private lateinit var networkStatusRepository: NetworkStatusRepository - - // class under test - private lateinit var userRepository: UserRepository - - @Before - fun setUp() { - Dispatchers.setMain(Dispatchers.Unconfined) - userRemoteDataSource = mock(UserRemoteDataSource::class.java) - userDao = mock(UserDao::class.java) - networkStatusRepository = mock(NetworkStatusRepository::class.java) - `when`(networkStatusRepository.isConnected).thenReturn(true) - userRepository = UserRepository( - userRemoteDataSource = userRemoteDataSource, - userDao = userDao, - networkStatusRepository = networkStatusRepository, - ) - } - - @Test - fun `signIn success returns success`() = runTest { - // Arrange - val email = "fdsa@fdsa.com" - val password = "fdsa" - val fakeResponse = TokenResponse("access_token", "refresh_token", "bearer") - - `when`( - userRemoteDataSource.signIn(anyString(), anyString()), - ).thenReturn(Result.success(fakeResponse)) - - // Act - val result = userRepository.signIn(email, password) - println(result) - - // Assert - assertTrue(result.isSuccess) - } - - @Test - fun `signIn failure returns failure`() = runTest { - // Arrange - val email = "fdsa@fdsa.com" - val password = "fdsa" -// val fakeResponse = Response.error(401, "Unauthorized".toResponseBody(null)) - -// val callMock = mock(Call::class.java) as Call -// `when`(callMock.execute()).thenReturn(fakeResponse) - `when`( - userRemoteDataSource.signIn(anyString(), anyString()), - ).thenReturn(Result.failure(Throwable("Any custom error message should be handled"))) - - // Act - val result = userRepository.signIn(email, password) - // Assert - assertTrue(result.isFailure) - assertEquals("Any custom error message should be handled", result.exceptionOrNull()?.message) - } - - @After - fun tearDown() { - Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher - } -} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt new file mode 100644 index 0000000..a3217f1 --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt @@ -0,0 +1,247 @@ +package com.example.readability.ui.models.ai + +import com.example.readability.data.ai.QuizAPI +import com.example.readability.data.ai.QuizRemoteDataSource +import com.example.readability.data.ai.QuizResponseType +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.test.runTest +import okhttp3.ResponseBody +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.doThrow +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import retrofit2.Response +import java.io.ByteArrayInputStream +import java.io.IOException + +val quizResponseExample = """ +event: quiz +data: Number of Questions + +event: quiz +data: : + +event: quiz +data: 3 + +event: quiz +data: + +event: quiz +data: Q1 + +event: quiz +data: : + +event: quiz +data: Why this unit test is meaningful? + +event: quiz +data: + +event: quiz +data: A1: + +event: quiz +data: Because it checks the correctness of the code. + +event: quiz +data: + +event: quiz +data: Q + +event: quiz +data: 2: + +event: quiz +data: What is the best programming language? + +event: quiz +data: + +event: quiz +data: A2: + +event: quiz +data: Kotlin! + +event: quiz +data: + +event: quiz +data: Q3: + +event: quiz +data: Is the parsing works + +event: quiz +data: + +event: quiz +data: A3: + +event: quiz +data: Yes! + +event: quiz +data: +""".trimIndent() + +class QuizRemoteDataSourceTest { + + @get:Rule + val mockitoRule: MockitoRule = MockitoJUnit.rule() + + @Mock + lateinit var quizAPI: QuizAPI + + lateinit var quizRemoteDataSource: QuizRemoteDataSource + + @Before + fun setUp() { + quizRemoteDataSource = QuizRemoteDataSource(quizAPI) + } + + @Test + fun `getQuiz success`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + val responseBody = mock(ResponseBody::class.java) + doReturn(ByteArrayInputStream(quizResponseExample.toByteArray())).`when`(responseBody).byteStream() + val response = Response.success(responseBody) + + val call = mock(retrofit2.Call::class.java) + doReturn(response).`when`(call).execute() + doReturn(call).`when`(quizAPI).getQuiz(bookId, progress, accessToken) + + // Act + val result = quizRemoteDataSource.getQuiz(bookId, progress, accessToken) + + // Assert + val number_of_quiz = 3 + val data = mutableListOf( + "Why this unit test is meaningful?" to "Because it checks the correctness of the code.", + "What is the best programming language?" to "Kotlin!", + "Is the parsing works" to "Yes!", + ) + var isQuestion = true + var index = 0 + result.toList().forEach { + println(it) + if (it.type == QuizResponseType.COUNT) { + assert(it.intData == number_of_quiz) + } else if (it.type == QuizResponseType.QUESTION_END) { + isQuestion = false + } else if (it.type == QuizResponseType.ANSWER_END) { + isQuestion = true + index++ + } else if (it.type == QuizResponseType.STRING) { + if (isQuestion) { + assert(data[index].first.startsWith(it.data)) + data[index] = data[index].copy( + first = data[index].first.substring(it.data.length) + ) + } else { + assert(data[index].second.startsWith(it.data)) + data[index] = data[index].copy( + second = data[index].second.substring(it.data.length) + ) + } + } + } + + println(data) + + for (d in data) { + assert(d.first.isEmpty()) + assert(d.second.isEmpty()) + } + + // Verify + verify(quizAPI).getQuiz(bookId, progress, accessToken) + } + + @Test(expected = Throwable::class) + fun `getQuiz network error`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + + doThrow(IOException("Network error")).`when`(quizAPI).getQuiz(bookId, progress, accessToken).execute() + + // Act + val result = quizRemoteDataSource.getQuiz(bookId, progress, accessToken) + + // Assert + result.collect { + // This block should not be reached + } + + // Verify + verify(quizAPI).getQuiz(bookId, progress, accessToken) + } + + @Test(expected = Throwable::class) + fun `getQuiz server error`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + val errorBody = mock(ResponseBody::class.java) + doReturn("{\"detail\":\"Server error\"}").`when`(errorBody).string() + val response = Response.error(400, errorBody) + +// `when`(quizAPI.getQuiz(bookId, progress, accessToken)).thenReturn(mock { +// on { execute() } doReturn response +// }) + doReturn(response).`when`(quizAPI).getQuiz(bookId, progress, accessToken) + + // Act + val result = quizRemoteDataSource.getQuiz(bookId, progress, accessToken) + + // Assert + result.collect { + // This block should not be reached + } + + // Verify + verify(quizAPI).getQuiz(bookId, progress, accessToken) + } + + @Test(expected = Throwable::class) + fun `getQuiz parsing error`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + val responseBody = mock(ResponseBody::class.java) + doReturn(ByteArrayInputStream("data: Sorry, but we cannot generate quiz.".toByteArray())).`when`(responseBody).byteStream() + val response = Response.success(responseBody) + + val call = mock(retrofit2.Call::class.java) + doReturn(response).`when`(call).execute() + doReturn(call).`when`(quizAPI).getQuiz(bookId, progress, accessToken) + + // Act + val result = quizRemoteDataSource.getQuiz(bookId, progress, accessToken) + + // Assert + result.collect { + // This block should not be reached + } + + // Verify + verify(quizAPI).getQuiz(bookId, progress, accessToken) + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt new file mode 100644 index 0000000..1055708 --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt @@ -0,0 +1,103 @@ +package com.example.readability.ui.models.ai + +import com.example.readability.data.ai.QuizRemoteDataSource +import com.example.readability.data.ai.QuizRepository + +import com.example.readability.data.NetworkStatusRepository +import com.example.readability.data.ai.QuizLoadState +import com.example.readability.data.ai.QuizResponse +import com.example.readability.data.ai.QuizResponseType +import com.example.readability.data.user.UserNotSignedInException +import com.example.readability.data.user.UserRepository +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +@ExperimentalCoroutinesApi +class QuizRepositoryTest { + + private lateinit var quizRepository: QuizRepository + private lateinit var quizRemoteDataSource: QuizRemoteDataSource + private lateinit var userRepository: UserRepository + private lateinit var networkStatusRepository: NetworkStatusRepository + + @Before + fun setup() { + quizRemoteDataSource = mockk() + userRepository = mockk() + networkStatusRepository = mockk() + quizRepository = QuizRepository(quizRemoteDataSource, userRepository, networkStatusRepository) + } + + @Test + fun `getQuiz when not connected to network should return failure`() = runTest { + // Arrange + coEvery { networkStatusRepository.isConnected } returns false + + // Act + val result = quizRepository.getQuiz(1, 0.5) + + // Assert + assert(result.isFailure) + assert(result.exceptionOrNull() is Exception) + } + + @Test + fun `getQuiz when user not signed in should return failure`() = runTest { + // Arrange + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRepository.getAccessToken() } returns null + + // Act + val result = quizRepository.getQuiz(1, 0.5) + + // Assert + assert(result.isFailure) + assert(result.exceptionOrNull() is UserNotSignedInException) + } + + @Test + fun `getQuiz success should update quizList and quizCount`() = runTest { + // Arrange + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRepository.getAccessToken() } returns "testAccessToken" + coEvery { quizRemoteDataSource.getQuiz(any(), any(), any()) } returns flowOf( + QuizResponse(QuizResponseType.COUNT, "", 3), + QuizResponse(QuizResponseType.STRING, "Question 1", 0), + QuizResponse(QuizResponseType.QUESTION_END, "", 0), + QuizResponse(QuizResponseType.STRING, "Answer 1", 0), + QuizResponse(QuizResponseType.ANSWER_END, "", 0), + QuizResponse(QuizResponseType.STRING, "Question 2", 0), + QuizResponse(QuizResponseType.QUESTION_END, "", 0), + QuizResponse(QuizResponseType.STRING, "Answer 2", 0), + QuizResponse(QuizResponseType.ANSWER_END, "", 0), + QuizResponse(QuizResponseType.STRING, "Question 3", 0), + QuizResponse(QuizResponseType.QUESTION_END, "", 0), + QuizResponse(QuizResponseType.STRING, "Answer 3", 0), + QuizResponse(QuizResponseType.ANSWER_END, "", 0) + ) + + // Act + val result = quizRepository.getQuiz(1, 0.5) + + // Assert + assertEquals(Result.success(Unit), result) + assertEquals(3, quizRepository.quizCount.first()) + assertEquals(3, quizRepository.quizList.first().size) + assertEquals("Question 1", quizRepository.quizList.first()[0].question) + assertEquals("Question 2", quizRepository.quizList.first()[1].question) + assertEquals("Question 3", quizRepository.quizList.first()[2].question) + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt new file mode 100644 index 0000000..9cb023b --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt @@ -0,0 +1,155 @@ +package com.example.readability.ui.models.ai + +import com.example.readability.data.ai.SummaryAPI +import com.example.readability.data.ai.SummaryRemoteDataSource +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.test.runTest +import okhttp3.ResponseBody +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.doThrow +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import retrofit2.Call +import retrofit2.Response +import java.io.ByteArrayInputStream +import java.io.IOException + +val exampleSummary = """ + event: summary + data: + + event: summary + data: This is + + event: summary + data: a test + + event: summary + data: summary. + + event: summary + data: +""".trimIndent() + +class SummaryRemoteDataSourceTest { + + @get:Rule + val mockitoRule: MockitoRule = MockitoJUnit.rule() + + @Mock + lateinit var summaryAPI: SummaryAPI + + @InjectMocks + lateinit var summaryRemoteDataSource: SummaryRemoteDataSource + + @Before + fun setUp() { + summaryRemoteDataSource = SummaryRemoteDataSource(summaryAPI) + } + + @Test + fun `getSummary success`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + val responseBody = mock(ResponseBody::class.java) + doReturn(ByteArrayInputStream(exampleSummary.toByteArray())).`when`(responseBody).byteStream() + val response = Response.success(responseBody) + + val call = mock(Call::class.java) + doReturn(response).`when`(call).execute() + doReturn(call).`when`(summaryAPI).getSummary(bookId, progress, accessToken) + + // Act + val result = summaryRemoteDataSource.getSummary(bookId, progress, accessToken) + + // Assert + result.toList().reduce { + acc, s -> acc + s + }.let { + assert(it == "This is a test summary.\n") + } + + // Verify + verify(summaryAPI).getSummary(bookId, progress, accessToken) + } + + @Test(expected = Throwable::class) + fun `getSummary network error`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + + doThrow(IOException("Network error")).`when`(summaryAPI).getSummary(bookId, progress, accessToken).execute() + + // Act + val result = summaryRemoteDataSource.getSummary(bookId, progress, accessToken) + + // Assert + result.collect { + // This block should not be reached + } + + // Verify + verify(summaryAPI).getSummary(bookId, progress, accessToken) + } + + @Test(expected = Throwable::class) + fun `getSummary server error`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + val errorBody = mock(ResponseBody::class.java) + doReturn("{\"detail\":\"Server error\"}").`when`(errorBody).string() + val response = Response.error(400, errorBody) + + doReturn(response).`when`(summaryAPI).getSummary(bookId, progress, accessToken) + + // Act + val result = summaryRemoteDataSource.getSummary(bookId, progress, accessToken) + + // Assert + result.collect { + // This block should not be reached + } + + // Verify + verify(summaryAPI).getSummary(bookId, progress, accessToken) + } + + @Test(expected = Throwable::class) + fun `getSummary parsing error`() = runTest { + // Arrange + val bookId = 1 + val progress = 0.5 + val accessToken = "testAccessToken" + val responseBody = mock(ResponseBody::class.java) + doReturn(ByteArrayInputStream("data:".toByteArray())).`when`(responseBody).byteStream() + val response = Response.success(responseBody) + + val call = mock(Call::class.java) + doReturn(response).`when`(call).execute() + doReturn(call).`when`(summaryAPI).getSummary(bookId, progress, accessToken) + + // Act + val result = summaryRemoteDataSource.getSummary(bookId, progress, accessToken) + + // Assert + result.collect { + // This block should not be reached + } + + // Verify + verify(summaryAPI).getSummary(bookId, progress, accessToken) + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt new file mode 100644 index 0000000..25f0f17 --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt @@ -0,0 +1,88 @@ +package com.example.readability.ui.models.ai + +import com.example.readability.data.NetworkStatusRepository +import com.example.readability.data.ai.SummaryRemoteDataSource +import com.example.readability.data.ai.SummaryRepository +import com.example.readability.data.user.UserNotSignedInException +import com.example.readability.data.user.UserRepository +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +@ExperimentalCoroutinesApi +class SummaryRepositoryTest { + + private lateinit var summaryRepository: SummaryRepository + private lateinit var summaryRemoteDataSource: SummaryRemoteDataSource + private lateinit var userRepository: UserRepository + private lateinit var networkStatusRepository: NetworkStatusRepository + + @Before + fun setup() { + summaryRemoteDataSource = mockk() + userRepository = mockk() + networkStatusRepository = mockk() + summaryRepository = SummaryRepository( + summaryRemoteDataSource, + userRepository, + networkStatusRepository + ) + } + + @Test + fun `getSummary when not connected to network should return failure`() = runTest { + // Arrange + coEvery { networkStatusRepository.isConnected } returns false + + // Act + val result = summaryRepository.getSummary(1, 0.5) + + // Assert + assert(result.isFailure) + assert(result.exceptionOrNull() is Exception) + } + + @Test + fun `getSummary when user not signed in should return failure`() = runTest { + // Arrange + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRepository.getAccessToken() } returns null + + // Act + val result = summaryRepository.getSummary(1, 0.5) + + // Assert + assert(result.isFailure) + assert(result.exceptionOrNull() is UserNotSignedInException) + } + + @Test + fun `getSummary success should update summary`() = runTest { + // Arrange + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRepository.getAccessToken() } returns "testAccessToken" + coEvery { summaryRemoteDataSource.getSummary(any(), any(), any()) } returns flowOf("Summary 1", "Summary 2", "Summary 3") + + // Act + val result = summaryRepository.getSummary(1, 0.5) + + // Assert + assertEquals(Result.success(Unit), result) + assertEquals("Summary 1Summary 2Summary 3", summaryRepository.summary.first()) + } + + @Test + fun `clearSummary should reset summary`() = runTest { + // Arrange + summaryRepository.clearSummary() + + // Assert + assertEquals("", summaryRepository.summary.first()) + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt new file mode 100644 index 0000000..a6002be --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt @@ -0,0 +1,149 @@ +package com.example.readability.ui.models.book + +import android.graphics.Bitmap +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asAndroidBitmap +import androidx.compose.ui.graphics.asImageBitmap +import com.example.readability.data.book.BookFileDataSource +import com.example.readability.data.book.FileHelper +import io.mockk.* +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream + +@ExperimentalCoroutinesApi +@RunWith(RobolectricTestRunner::class) +class BookFileDataSourceTest { + + private lateinit var fileHelper: FileHelper + private lateinit var bookFileDataSource: BookFileDataSource + + @Before + fun setup() { + fileHelper = mockk(relaxed = true) + bookFileDataSource = BookFileDataSource(fileHelper) + } + + @Test + fun `contentExists should call FileHelper exists`() = runTest { + // Arrange + coEvery { fileHelper.exists(any()) } returns true + + // Act + val result = bookFileDataSource.contentExists(1) + + // Assert + assert(result) + coVerify { fileHelper.exists("/book_content/1.txt") } + } + + @Test + fun `readContentFile should call FileHelper openFileInputStream and bufferedReader`() = runTest { + // Arrange + coEvery { fileHelper.exists(any()) } returns true + coEvery { fileHelper.openFileInputStream(any()) } returns mockk() + coEvery { fileHelper.openFileInputStream(any()).bufferedReader() } returns mockk() + + // Act + bookFileDataSource.readContentFile(1) + + // Assert + coVerify { fileHelper.openFileInputStream("/book_content/1.txt") } + coVerify { fileHelper.openFileInputStream("/book_content/1.txt").bufferedReader() } + } + + @Test + fun `writeContentFile should call FileHelper openFileOutputStream and bufferedWriter`() = runTest { + // Arrange + coEvery { fileHelper.openFileOutputStream(any()) } returns mockk() + coEvery { fileHelper.openFileOutputStream(any()).bufferedWriter() } returns mockk() + + // Act + bookFileDataSource.writeContentFile(1, "content") + + // Assert + coVerify { fileHelper.openFileOutputStream("/book_content/1.txt") } + coVerify { fileHelper.openFileOutputStream("/book_content/1.txt").bufferedWriter() } + } + + @Test + fun `deleteContentFile should call FileHelper deleteFile`() = runTest { + // Act + bookFileDataSource.deleteContentFile(1) + + // Assert + coVerify { fileHelper.deleteFile("/book_content/1.txt") } + } + + @Test + fun `coverImageExists should call FileHelper exists`() = runTest { + // Arrange + coEvery { fileHelper.exists(any()) } returns true + + // Act + val result = bookFileDataSource.coverImageExists(1) + + // Assert + assert(result) + coVerify { fileHelper.exists("/book_cover/1.png") } + } + + @Test + fun `readCoverImageFile should call FileHelper openFileInputStream and use BitmapFactory`() = runTest { + // Arrange + val byteArray = ByteArrayOutputStream().use { + // Create a sample image + Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) + .compress(Bitmap.CompressFormat.PNG, 100, it) + it.toByteArray() + } + coEvery { fileHelper.exists(any()) } returns true + coEvery { fileHelper.openFileInputStream(any()) } returns ByteArrayInputStream(byteArray) + + // Act + bookFileDataSource.readCoverImageFile(1) + + // Assert + coVerify { fileHelper.openFileInputStream("/book_cover/1.png") } + } + + @Test + fun `writeCoverImageFile should call FileHelper openFileOutputStream and compress`() = runTest { + // Arrange + val imageBitmap: ImageBitmap = spyk( + Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888).asImageBitmap(), + ) + every { imageBitmap.asAndroidBitmap() } returns mockk() + coEvery { fileHelper.openFileOutputStream(any()) } returns mockk() + + // Act + bookFileDataSource.writeCoverImageFile(1, imageBitmap) + + // Assert + coVerify { fileHelper.openFileOutputStream("/book_cover/1.png") } + } + + @Test + fun `deleteCoverImageFile should call FileHelper deleteFile`() = runTest { + // Act + bookFileDataSource.deleteCoverImageFile(1) + + // Assert + coVerify { fileHelper.deleteFile("/book_cover/1.png") } + } + + @Test + fun `deleteAll should call FileHelper resetDirectory`() = runTest { + // Act + bookFileDataSource.deleteAll() + + // Assert + coVerify { fileHelper.resetDirectory("/book_cover") } + coVerify { fileHelper.resetDirectory("/book_content") } + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt new file mode 100644 index 0000000..ff59eac --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt @@ -0,0 +1,245 @@ +package com.example.readability.ui.models.book + +import android.graphics.Bitmap +import com.example.readability.data.book.AddBookRequest +import com.example.readability.data.book.BookAPI +import com.example.readability.data.book.BookRemoteDataSource +import com.example.readability.data.book.BookResponse +import com.example.readability.data.book.BooksResponse +import com.example.readability.data.book.SummaryProgressResponse +import io.mockk.* +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.ResponseBody.Companion.toResponseBody +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import retrofit2.Response +import java.io.ByteArrayOutputStream + +@ExperimentalCoroutinesApi +@RunWith(RobolectricTestRunner::class) +class BookRemoteDataSourceTest { + + private lateinit var bookAPI: BookAPI + private lateinit var bookRemoteDataSource: BookRemoteDataSource + + @Before + fun setup() { + bookAPI = mockk(relaxed = true) + bookRemoteDataSource = BookRemoteDataSource(bookAPI) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `getBookList success should return a list of books`() = runTest { + // Arrange + coEvery { bookAPI.getBooks(any()).execute() } returns Response.success( + BooksResponse(listOf( + BookResponse(1, "Title1", "Author1", "Content1", "Cover1", 0.5), + BookResponse(2, "Title2", "Author2", "Content2", "Cover2", 0.8) + )) + ) + + // Act + val result = bookRemoteDataSource.getBookList("accessToken") + + // Assert + assert(result.isSuccess) + assert(result.getOrNull() != null) + assert(result.getOrNull()?.size == 2) + assert(result.getOrNull()?.get(0)?.bookId == 1) + assert(result.getOrNull()?.get(1)?.bookId == 2) + coVerify { bookAPI.getBooks("accessToken") } + } + + @Test + fun `getBookList failure should return a failure result`() = runTest { + // Arrange + coEvery { bookAPI.getBooks(any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.getBookList("accessToken") + + // Assert + assert(result.isFailure) + coVerify { bookAPI.getBooks("accessToken") } + } + + @Test + fun `getCoverImageData success should return an ImageBitmap`() = runTest { + // Arrange + val bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) + val byteArrayOutputStream = ByteArrayOutputStream() + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream) + coEvery { bookAPI.getBookCoverImage(any(), any()).execute() } returns Response.success( + byteArrayOutputStream.toByteArray().toResponseBody("image/jpeg".toMediaTypeOrNull()) + ) + + // Act + val result = bookRemoteDataSource.getCoverImageData("accessToken", "coverImage") + + // Assert + assert(result.isSuccess) + assert(result.getOrNull() != null) + coVerify { bookAPI.getBookCoverImage("coverImage", "accessToken") } + + bitmap.recycle() + byteArrayOutputStream.close() + } + + @Test + fun `getCoverImageData failure should return a failure result`() = runTest { + // Arrange + coEvery { bookAPI.getBookCoverImage(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.getCoverImageData("accessToken", "coverImage") + + // Assert + assert(result.isFailure) + coVerify { bookAPI.getBookCoverImage("coverImage", "accessToken") } + } + + @Test + fun `getContentData success should return content string`() = runTest { + // Arrange + coEvery { bookAPI.getBookContent(any(), any()).execute() } returns Response.success("Content".toResponseBody("text/plain".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.getContentData("accessToken", "content") + + // Assert + assert(result.isSuccess) + assert(result.getOrNull() == "Content") + coVerify { bookAPI.getBookContent("content", "accessToken") } + } + + @Test + fun `getContentData failure should return a failure result`() = runTest { + // Arrange + coEvery { bookAPI.getBookContent(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.getContentData("accessToken", "content") + + // Assert + assert(result.isFailure) + coVerify { bookAPI.getBookContent("content", "accessToken") } + } + + @Test + fun `getSummaryProgress success should return summary progress string`() = runTest { + // Arrange + coEvery { bookAPI.getSummaryProgress(any(), any()).execute() } returns Response.success(SummaryProgressResponse("0.7")) + + // Act + val result = bookRemoteDataSource.getSummaryProgress("accessToken", 1) + + // Assert + assert(result.isSuccess) + assert(result.getOrNull() == "0.7") + coVerify { bookAPI.getSummaryProgress(1, "accessToken") } + } + + @Test + fun `getSummaryProgress failure should return a failure result`() = runTest { + // Arrange + coEvery { bookAPI.getSummaryProgress(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.getSummaryProgress("accessToken", 1) + + // Assert + assert(result.isFailure) + coVerify { bookAPI.getSummaryProgress(1, "accessToken") } + } + + @Test + fun `addBook success should return Unit`() = runTest { + // Arrange + coEvery { bookAPI.addBook(any(), any()).execute() } returns Response.success(Unit) + + // Act + val result = bookRemoteDataSource.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) + + // Assert + assert(result.isSuccess) + assert(result.getOrNull() == Unit) + coVerify { bookAPI.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) } + } + + @Test + fun `addBook failure should return a failure result`() = runTest { + // Arrange + coEvery { bookAPI.addBook(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) + + // Assert + assert(result.isFailure) + coVerify { bookAPI.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) } + } + + @Test + fun `deleteBook success should return success message`() = runTest { + // Arrange + coEvery { bookAPI.deleteBook(any(), any()).execute() } returns Response.success("Success".toResponseBody("text/plain".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.deleteBook(1, "accessToken") + + // Assert + assert(result.isSuccess) + assert(result.getOrNull() == "Success") + coVerify { bookAPI.deleteBook(1, "accessToken") } + } + + @Test + fun `deleteBook failure should return a failure result`() = runTest { + // Arrange + coEvery { bookAPI.deleteBook(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.deleteBook(1, "accessToken") + + // Assert + assert(result.isFailure) + coVerify { bookAPI.deleteBook(1, "accessToken") } + } + + @Test + fun `updateProgress success should return success message`() = runTest { + // Arrange + coEvery { bookAPI.updateProgress(any(), any(), any()).execute() } returns Response.success("Success".toResponseBody("text/plain".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.updateProgress(1, 0.5, "accessToken") + + // Assert + assert(result.isSuccess) + assert(result.getOrNull() == "Success") + coVerify { bookAPI.updateProgress(1, 0.5, "accessToken") } + } + + @Test + fun `updateProgress failure should return a failure result`() = runTest { + // Arrange + coEvery { bookAPI.updateProgress(any(), any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = bookRemoteDataSource.updateProgress(1, 0.5, "accessToken") + + // Assert + assert(result.isFailure) + coVerify { bookAPI.updateProgress(1, 0.5, "accessToken") } + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/BookRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt similarity index 91% rename from frontend/app/src/test/java/com/example/readability/ui/models/BookRepositoryTest.kt rename to frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt index de01bf3..23d3ded 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/BookRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.models +package com.example.readability.ui.models.book import com.example.readability.data.NetworkStatusRepository import com.example.readability.data.book.AddBookRequest @@ -9,9 +9,12 @@ import com.example.readability.data.book.BookFileDataSource import com.example.readability.data.book.BookRemoteDataSource import com.example.readability.data.book.BookRepository import com.example.readability.data.user.UserRepository +import io.mockk.coEvery +import io.mockk.unmockkAll import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test @@ -115,8 +118,13 @@ class BookRepositoryTest { ) } + @After + fun tearDown() { + unmockkAll() + } + @Test - fun setProgress_succeed() = runTest { + fun `setProgress success`() = runTest { // Arrange val bookId = 1 val progress = 0.5 @@ -133,7 +141,7 @@ class BookRepositoryTest { } @Test - fun updateSummaryProgress_succeed() = runTest { + fun `updateProgressSummary success`() = runTest { // Arrange val bookId = 1 val summaryProgress = 0.5 @@ -154,7 +162,7 @@ class BookRepositoryTest { } @Test - fun updateSummaryProgress_remote_fail() = runTest { + fun `updateSummaryProgress when server error should return failure`() = runTest { // Arrange val bookId = 1 `when`(bookRemoteDataSource.getSummaryProgress("test", bookId)).thenReturn(Result.failure(Throwable("test"))) @@ -167,7 +175,7 @@ class BookRepositoryTest { } @Test - fun getBook_succeed() = runTest { + fun `getBook success`() = runTest { // Arrange val bookId = 1 `when`(bookDao.getBook(bookId)).thenReturn( @@ -191,7 +199,7 @@ class BookRepositoryTest { } @Test - fun getBook_fail() = runTest { + fun `getBook fail`() = runTest { // Arrange val bookId = 10 `when`(bookDao.getBook(bookId)).thenReturn(null) @@ -205,7 +213,7 @@ class BookRepositoryTest { } @Test - fun refreshBookList_succeed() = runTest { + fun `refreshBookList success should update book list`() = runTest { // Arrange val deletedBookId = 1 val updatedProgressBookId = 2 @@ -309,7 +317,7 @@ class BookRepositoryTest { } @Test - fun refreshBookList_network_fail() = runTest { + fun `refreshBookList when no network should return failure`() = runTest { // Arrange `when`(networkStatusRepository.isConnected).thenReturn(false) @@ -321,7 +329,7 @@ class BookRepositoryTest { } @Test - fun refreshBookList_remote_fail() = runTest { + fun `refreshBookList when server error should return failure`() = runTest { // Arrange `when`(bookRemoteDataSource.getBookList("test")).thenReturn(Result.failure(Throwable("test"))) @@ -333,7 +341,7 @@ class BookRepositoryTest { } @Test - fun getCoverImageData_succeed() = runTest { + fun `getCoverImageData success`() = runTest { // Arrange val bookId = 2 val imageBitmap = null @@ -349,7 +357,7 @@ class BookRepositoryTest { } @Test - fun getCoverImageData_fail() = runTest { + fun `getCoverImageData fails when server error`() = runTest { // Arrange val bookId = 2 val coverImage = "test" @@ -365,7 +373,7 @@ class BookRepositoryTest { } @Test - fun getCoverImageDataIsNull_fail() = runTest { + fun `getCoverImageData fails`() = runTest { // Arrange val bookId = 1 `when`(bookFileDataSource.coverImageExists(bookId)).thenReturn(false) @@ -378,7 +386,7 @@ class BookRepositoryTest { } @Test - fun getContentData_succeed() = runTest { + fun `getContentData success when local data exists`() = runTest { // Arrange val bookId = 1 val contentString = "test_string" @@ -394,7 +402,7 @@ class BookRepositoryTest { } @Test - fun getContentData_fail() = runTest { + fun `getContentData fail`() = runTest { // Arrange val bookId = 1 val content = "test" @@ -410,7 +418,7 @@ class BookRepositoryTest { } @Test - fun getContentData_remote_succeed() = runTest { + fun `getContenData success`() = runTest { // Arrange val bookId = 1 val content = "test" @@ -428,7 +436,7 @@ class BookRepositoryTest { } @Test - fun addBook_succeed() = runTest { + fun `addBook success should add book data`() = runTest { // Arrange val addBookRequest = AddBookRequest( title = "test", @@ -517,7 +525,7 @@ class BookRepositoryTest { } @Test - fun addBook_remote_fail() = runTest { + fun `addBook when server error should return failure`() = runTest { // Arrange val addBookRequest = AddBookRequest( title = "test", @@ -536,7 +544,7 @@ class BookRepositoryTest { } @Test - fun deleteBook_succeed() = runTest { + fun `deleteBook success should remove book data`() = runTest { // Arrange val bookId = 3 @@ -582,7 +590,7 @@ class BookRepositoryTest { } @Test - fun deleteBook_remote_fail() = runTest { + fun `deleteBook when server error should return failure`() = runTest { // Arrange val bookId = 3 @@ -594,4 +602,18 @@ class BookRepositoryTest { // Assert assert(result.isFailure) } + + @Test + fun `clearBooks success should clear books`() = runTest { + // Arrange + doNothing().`when`(bookFileDataSource).deleteAll() + doNothing().`when`(bookDao).deleteAll() + + // Act + bookRepository.clearBooks() + + // Assert + verify(bookFileDataSource, times(1)).deleteAll() + verify(bookDao, times(1)).deleteAll() + } } diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt new file mode 100644 index 0000000..5964145 --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt @@ -0,0 +1,81 @@ +package com.example.readability.ui.models.network + +import android.content.Context +import android.net.ConnectivityManager +import com.example.readability.data.NetworkStatusDataSource +import io.mockk.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +@OptIn(ExperimentalCoroutinesApi::class) +class NetworkStatusDataSourceTest { + + private lateinit var networkStatusDataSource: NetworkStatusDataSource + private lateinit var mockContext: Context + private lateinit var mockConnectivityManager: ConnectivityManager + + @Before + fun setup() { + Dispatchers.setMain(Dispatchers.Unconfined) + mockContext = mockk(relaxed = true) + mockConnectivityManager = mockk(relaxed = true) + every { mockContext.getSystemService(Context.CONNECTIVITY_SERVICE) } returns mockConnectivityManager + networkStatusDataSource = NetworkStatusDataSource(mockContext) + } + + @After + fun tearDown() { + Dispatchers.resetMain() + } + + @Test + fun `isConnected returns correct value based on ConnectivityManager`() { + // Arrange + every { mockConnectivityManager.activeNetworkInfo?.isConnected } returns true + + // Act + val result = networkStatusDataSource.isConnected + + // Assert + assertEquals(true, result) + assertEquals(true, networkStatusDataSource.connectedState.value) + } + + @Test + fun `onAvailable callback updates connectedState to true`() = runTest { + // Arrange + coEvery { mockConnectivityManager.activeNetworkInfo?.isConnected } returns false + + // Act + networkStatusDataSource.isConnected // call to trigger initialization + coEvery { mockConnectivityManager.activeNetworkInfo?.isConnected } returns true + networkStatusDataSource.onAvailable() + + // Assert + assertEquals(true, networkStatusDataSource.connectedState.value) + } + + @Test + fun `onUnavailable callback updates connectedState to false`() = runTest { + // Arrange + coEvery { mockConnectivityManager.activeNetworkInfo?.isConnected } returns true + + // Act + networkStatusDataSource.isConnected // call to trigger initialization + coEvery { mockConnectivityManager.activeNetworkInfo?.isConnected } returns false + networkStatusDataSource.onUnavailable() + + // Assert + assertEquals(false, networkStatusDataSource.connectedState.value) + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt new file mode 100644 index 0000000..8d8fc64 --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt @@ -0,0 +1,39 @@ +package com.example.readability.ui.models.network + +import com.example.readability.data.NetworkStatusDataSource +import com.example.readability.data.NetworkStatusRepository +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +class NetworkStatusRepositoryTest { + + private lateinit var networkStatusRepository: NetworkStatusRepository + private lateinit var mockNetworkStatusDataSource: NetworkStatusDataSource + + @Before + fun setup() { + MockKAnnotations.init(this) + mockNetworkStatusDataSource = mockk(relaxed = true) + networkStatusRepository = NetworkStatusRepository(mockNetworkStatusDataSource) + } + + @Test + fun `isConnected returns correct value based on NetworkStatusDataSource`() { + // Arrange + coEvery { mockNetworkStatusDataSource.isConnected } returns true + + // Act + val result = networkStatusRepository.isConnected + + // Assert + assertEquals(true, result) + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt new file mode 100644 index 0000000..63ef1c4 --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt @@ -0,0 +1,228 @@ +package com.example.readability.ui.models.user + +import com.example.readability.data.user.RefreshTokenResponse +import com.example.readability.data.user.SignUpResponse +import com.example.readability.data.user.TokenResponse +import com.example.readability.data.user.UserAPI +import com.example.readability.data.user.UserInfoResponse +import com.example.readability.data.user.UserRemoteDataSource +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.ResponseBody.Companion.toResponseBody +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import retrofit2.Response + +@ExperimentalCoroutinesApi +class UserRemoteDataSourceTest { + + private lateinit var userAPI: UserAPI + private lateinit var userRemoteDataSource: UserRemoteDataSource + + @Before + fun setup() { + userAPI = mockk(relaxed = true) + userRemoteDataSource = UserRemoteDataSource(userAPI) + } + + @Test + fun `signIn success should return token response`() = runTest { + // Arrange + coEvery { + userAPI.signIn( + grantType = any(), + scope = any(), + clientId = any(), + clientSecret = any(), + username = any(), + password = any() + ).execute() + } returns Response.success(TokenResponse("access_token", "refresh_token", "token_type")) + + // Act + val result = userRemoteDataSource.signIn("email", "password") + + // Assert + Assert.assertTrue(result.isSuccess) + Assert.assertNotNull(result.getOrNull()) + Assert.assertEquals("access_token", result.getOrNull()?.access_token) + } + + @Test + fun `signIn failure should return a failure result`() = runTest { + // Arrange + coEvery { + userAPI.signIn( + grantType = any(), + scope = any(), + clientId = any(), + clientSecret = any(), + username = any(), + password = any() + ).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + + // Act + val result = userRemoteDataSource.signIn("email", "password") + + // Assert + Assert.assertTrue(result.isFailure) + } + + @Test + fun `signUp success should return Unit`() = runTest { + // Arrange + coEvery { userAPI.signUp(any()).execute() } returns Response.success(SignUpResponse(true)) + + // Act + val result = userRemoteDataSource.signUp("email", "username", "password") + + // Assert + Assert.assertTrue(result.isSuccess) + Assert.assertTrue(result.getOrNull() is Unit) + } + + @Test + fun `signUp failure should return a failure result`() = runTest { + // Arrange + coEvery { userAPI.signUp(any()).execute() } returns Response.error( + 400, + "".toResponseBody("application/json".toMediaTypeOrNull()) + ) + + // Act + val result = userRemoteDataSource.signUp("email", "username", "password") + + // Assert + Assert.assertTrue(result.isFailure) + } + + @Test + fun `refreshAccessToken success should return access token`() = runTest { + // Arrange + coEvery { userAPI.refreshAccessToken(any()).execute() } returns Response.success( + RefreshTokenResponse( + "new_access_token", + "token_type" + ) + ) + + // Act + val result = userRemoteDataSource.refreshAccessToken("refresh_token") + + // Assert + Assert.assertTrue(result.isSuccess) + Assert.assertEquals("new_access_token", result.getOrNull()) + } + + @Test + fun `refreshAccessToken failure should return a failure result`() = runTest { + // Arrange + coEvery { userAPI.refreshAccessToken(any()).execute() } returns Response.error( + 400, + "".toResponseBody("application/json".toMediaTypeOrNull()) + ) + + // Act + val result = userRemoteDataSource.refreshAccessToken("refresh_token") + + // Assert + Assert.assertTrue(result.isFailure) + } + + @Test + fun `getUserInfo success should return user info response`() = runTest { + // Arrange + coEvery { userAPI.getUserInfo(any()).execute() } returns Response.success( + UserInfoResponse( + "username", + "email", + "created_at", + 1 + ) + ) + + // Act + val result = userRemoteDataSource.getUserInfo("access_token") + + // Assert + Assert.assertTrue(result.isSuccess) + Assert.assertNotNull(result.getOrNull()) + Assert.assertEquals("username", result.getOrNull()?.username) + } + + @Test + fun `getUserInfo failure should return a failure result`() = runTest { + // Arrange + coEvery { userAPI.getUserInfo(any()).execute() } returns Response.error( + 400, + "".toResponseBody("application/json".toMediaTypeOrNull()) + ) + + // Act + val result = userRemoteDataSource.getUserInfo("access_token") + + // Assert + Assert.assertTrue(result.isFailure) + } + + @Test + fun `changePassword success should return Unit`() = runTest { + // Arrange + coEvery { userAPI.changePassword(any(), any()).execute() } returns Response.success(Unit) + + // Act + val result = userRemoteDataSource.changePassword("access_token", "new_password") + + // Assert + Assert.assertTrue(result.isSuccess) + Assert.assertTrue(result.getOrNull() is Unit) + } + + @Test + fun `changePassword failure should return a failure result`() = runTest { + // Arrange + coEvery { userAPI.changePassword(any(), any()).execute() } returns Response.error( + 400, + "".toResponseBody("application/json".toMediaTypeOrNull()) + ) + + // Act + val result = userRemoteDataSource.changePassword("access_token", "new_password") + + // Assert + Assert.assertTrue(result.isFailure) + } + + @Test + fun `deleteAccount success should return Unit`() = runTest { + // Arrange + coEvery { userAPI.deleteAccount(any()).execute() } returns Response.success(Unit) + + // Act + val result = userRemoteDataSource.deleteAccount("access_token") + + // Assert + Assert.assertTrue(result.isSuccess) + Assert.assertTrue(result.getOrNull() is Unit) + } + + @Test + fun `deleteAccount failure should return a failure result`() = runTest { + // Arrange + coEvery { userAPI.deleteAccount(any()).execute() } returns Response.error( + 400, + "".toResponseBody("application/json".toMediaTypeOrNull()) + ) + + // Act + val result = userRemoteDataSource.deleteAccount("access_token") + + // Assert + Assert.assertTrue(result.isFailure) + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt new file mode 100644 index 0000000..e29595a --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt @@ -0,0 +1,375 @@ +package com.example.readability.ui.models.user + +import com.example.readability.data.NetworkStatusRepository +import com.example.readability.data.user.TokenResponse +import com.example.readability.data.user.User +import com.example.readability.data.user.UserDao +import com.example.readability.data.user.UserInfoResponse +import com.example.readability.data.user.UserRemoteDataSource +import com.example.readability.data.user.UserRepository +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import java.util.concurrent.TimeUnit + +@ExperimentalCoroutinesApi +class UserRepositoryTest { + + // classes to be mocked + private lateinit var userRemoteDataSource: UserRemoteDataSource + private lateinit var userDao: UserDao + private lateinit var networkStatusRepository: NetworkStatusRepository + + // class under test + private lateinit var userRepository: UserRepository + + @Before + fun setUp() { + Dispatchers.setMain(Dispatchers.Unconfined) + userRemoteDataSource = mockk() + userDao = mockk(relaxed = true) + networkStatusRepository = mockk() + every { networkStatusRepository.isConnected } returns true + userRepository = UserRepository( + userRemoteDataSource = userRemoteDataSource, + userDao = userDao, + networkStatusRepository = networkStatusRepository, + ) + } + + @Test + fun `signIn success returns success`() = runTest { + // Arrange + val email = "fdsa@fdsa.com" + val password = "fdsa" + val fakeResponse = TokenResponse("access_token", "refresh_token", "bearer") + + coEvery { userRemoteDataSource.signIn(any(), any()) } returns Result.success(fakeResponse) + + // Act + val result = userRepository.signIn(email, password) + println(result) + + // Assert + assertTrue(result.isSuccess) + } + + @Test + fun `signIn failure returns failure`() = runTest { + // Arrange + val email = "fdsa@fdsa.com" + val password = "fdsa" +// val fakeResponse = Response.error(401, "Unauthorized".toResponseBody(null)) + +// val callMock = mock(Call::class.java) as Call +// `when`(callMock.execute()).thenReturn(fakeResponse) + coEvery { + userRemoteDataSource.signIn( + any(), + any() + ) + } returns Result.failure(Throwable("Any custom error message should be handled")) + + // Act + val result = userRepository.signIn(email, password) + // Assert + assertTrue(result.isFailure) + assertEquals("Any custom error message should be handled", result.exceptionOrNull()?.message) + } + + @Test + fun `signUp success returns success`() = runTest { + // Arrange + val email = "test@example.com" + val username = "testuser" + val password = "password" + + coEvery { userRemoteDataSource.signUp(any(), any(), any()) } returns Result.success(Unit) + coEvery { userRemoteDataSource.signIn(any(), any()) } returns Result.success( + TokenResponse( + "fake_access_token", + "fake_refresh_token", + "bearer" + ) + ) + + // Act + val result = userRepository.signUp(email, username, password) + + // Assert + assertTrue(result.isSuccess) + } + + @Test + fun `signUp failure returns failure`() = runTest { + // Arrange + val email = "test@example.com" + val username = "testuser" + val password = "password" + + coEvery { + userRemoteDataSource.signUp( + any(), + any(), + any() + ) + } returns Result.failure(Throwable("Any custom error message should be handled")) + + // Act + val result = userRepository.signUp(email, username, password) + + // Assert + assertTrue(result.isFailure) + assertEquals("Any custom error message should be handled", result.exceptionOrNull()?.message) + } + + @Test + fun `getRefreshToken returns valid token`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "fake_access_token", + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email", + userName = "fake_name", + createdAt = "fake_created_at", + verified = 0, + ) + + coEvery { userDao.get() } returns flowOf(fakeUser) + + // Act + val result = userRepository.getRefreshToken() + + // Assert + assertEquals("fake_refresh_token", result) + } + + @Test + fun `getAccessToken updates token when token is expired`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "expired_token", + accessTokenLife = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email2", + userName = "fake_name2", + createdAt = "fake_created_at2", + verified = 0, + ) + val fakeRefreshToken = "fake_refresh_token" + + coEvery { userDao.get() } returns flowOf(fakeUser) + coEvery { userDao.updateAccessToken(any(), any()) } returns Unit + coEvery { userRemoteDataSource.refreshAccessToken(fakeRefreshToken) } returns Result.success("fake_new_access_token") + + // Act + val result = userRepository.getAccessToken() + + // Assert + verify { userDao.updateAccessToken("fake_new_access_token", any()) } + } + + @Test + fun `getUserInfo success returns user info`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "fake_access_token", + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email", + userName = "fake_name", + createdAt = "fake_created_at", + verified = 0, + ) + val fakeUserInfoResponse = UserInfoResponse( + username = "testuser", + email = "test@example.com", + created_at = "2023-01-01", + verified = 1 + ) + + coEvery { userDao.get() } returns flowOf(fakeUser) + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRemoteDataSource.getUserInfo(fakeUser.accessToken!!) } returns Result.success(fakeUserInfoResponse) + + // Act + val result = userRepository.getUserInfo() + + // Assert + assertTrue(result.isSuccess) + assertEquals(fakeUserInfoResponse, result.getOrNull()) + } + + @Test + fun `getUserInfo failure returns failure`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "fake_access_token", + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email", + userName = "fake_name", + createdAt = "fake_created_at", + verified = 0, + ) + + coEvery { userDao.get() } returns flowOf(fakeUser) + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRemoteDataSource.getUserInfo(fakeUser.accessToken!!) } returns Result.failure(Throwable("Any custom error message")) + + // Act + val result = userRepository.getUserInfo() + + // Assert + assertTrue(result.isFailure) + assertEquals("Any custom error message", result.exceptionOrNull()?.message) + } + + @Test + fun `changePassword success returns success`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "fake_access_token", + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email", + userName = "fake_name", + createdAt = "fake_created_at", + verified = 0, + ) + val newPassword = "new_password" + + coEvery { userDao.get() } returns flowOf(fakeUser) + coEvery { networkStatusRepository.isConnected } returns true + coEvery { + userRemoteDataSource.changePassword( + fakeUser.accessToken!!, + newPassword + ) + } returns Result.success(Unit) + + // Act + val result = userRepository.changePassword(newPassword) + + // Assert + assertTrue(result.isSuccess) + } + + @Test + fun `changePassword failure returns failure`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "fake_access_token", + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email", + userName = "fake_name", + createdAt = "fake_created_at", + verified = 0, + ) + val newPassword = "new_password" + + coEvery { userDao.get() } returns flowOf(fakeUser) + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRemoteDataSource.changePassword(fakeUser.accessToken!!, newPassword) } returns Result.failure( + Throwable("Any custom error message") + ) + + // Act + val result = userRepository.changePassword(newPassword) + + // Assert + assertTrue(result.isFailure) + assertEquals("Any custom error message", result.exceptionOrNull()?.message) + } + + @Test + fun `signOut clears user data`() = runTest { + // Arrange + coEvery { userDao.deleteAll() } returns Unit + + // Act + userRepository.signOut() + + // Assert + coVerify(exactly = 1) { userDao.deleteAll() } + } + + @Test + fun `deleteAccount success returns success`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "fake_access_token", + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email", + userName = "fake_name", + createdAt = "fake_created_at", + verified = 0, + ) + + coEvery { userDao.get() } returns flowOf(fakeUser) + coEvery { networkStatusRepository.isConnected } returns true + coEvery { userRemoteDataSource.deleteAccount(fakeUser.accessToken!!) } returns Result.success(Unit) + + // Act + val result = userRepository.deleteAccount() + + // Assert + assertTrue(result.isSuccess) + } + + @Test + fun `deleteAccount failure returns failure`() = runTest { + // Arrange + val fakeUser = User( + refreshToken = "fake_refresh_token", + refreshTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + accessToken = "fake_access_token", + accessTokenLife = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1), + userEmail = "fake_email", + userName = "fake_name", + createdAt = "fake_created_at", + verified = 0, + ) + + coEvery { userDao.get() } returns flowOf(fakeUser) + coEvery { networkStatusRepository.isConnected } returns true + coEvery { + userRemoteDataSource.deleteAccount(fakeUser.accessToken!!) + } returns Result.failure(Throwable("Any custom error message")) + + // Act + val result = userRepository.deleteAccount() + + // Assert + assertTrue(result.isFailure) + assertEquals("Any custom error message", result.exceptionOrNull()?.message) + } + + @After + fun tearDown() { + Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt new file mode 100644 index 0000000..56f4d3d --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt @@ -0,0 +1,83 @@ +package com.example.readability.ui.models.viewer + + +import android.content.Context +import androidx.core.content.res.ResourcesCompat +import com.example.readability.data.viewer.FontDataSource +import com.example.readability.data.viewer.ViewerStyleBuilder +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import org.junit.After +import org.junit.Assert.assertNotNull +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class FontDataSourceTest { + + private lateinit var fontDataSource: FontDataSource + private lateinit var mockContext: Context + + @Before + fun setup() { + mockkStatic(ResourcesCompat::class) + mockContext = mockk(relaxed = true) + every { ResourcesCompat.getFont(mockContext, any()) } returns mockk(relaxed = true) + fontDataSource = FontDataSource(mockContext) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `getCharWidthArray returns char width array`() { + // Arrange + val viewerStyle = ViewerStyleBuilder().build() + + // Act + val result = fontDataSource.getCharWidthArray(viewerStyle) + + // Assert + assertNotNull(result) + } + + @Test + fun `buildTextPaint returns text paint`() { + // Arrange + val viewerStyle = ViewerStyleBuilder().build() + + // Act + val result = fontDataSource.buildTextPaint(viewerStyle) + + // Assert + assertNotNull(result) + } + + @Test + fun `calculateReferenceCharWidth updates char width array`() { + // Arrange + val viewerStyle = ViewerStyleBuilder().build() + + // Act + fontDataSource.calculateReferenceCharWidth(viewerStyle) + + // It works without exception + } + + @Test + fun `calculateCharWidth updates char width array`() { + // Arrange + val viewerStyle = ViewerStyleBuilder().build() + + // Act + fontDataSource.calculateCharWidth(viewerStyle) + + // It works without exception + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt new file mode 100644 index 0000000..dfe248d --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt @@ -0,0 +1,128 @@ +package com.example.readability.ui.models.viewer + +import androidx.compose.ui.graphics.NativeCanvas +import com.example.readability.data.book.Book +import com.example.readability.data.book.BookRepository +import com.example.readability.data.viewer.FontDataSource +import com.example.readability.data.viewer.PageSplitDataSource +import com.example.readability.data.viewer.PageSplitRepository +import com.example.readability.data.viewer.SettingRepository +import com.example.readability.data.viewer.ViewerStyle +import com.example.readability.data.viewer.ViewerStyleBuilder +import io.mockk.coEvery +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Before +import org.junit.Test + +@ExperimentalCoroutinesApi +class PageSplitRepositoryTest { + + private lateinit var pageSplitRepository: PageSplitRepository + private lateinit var pageSplitDataSource: PageSplitDataSource + private lateinit var fontDataSource: FontDataSource + private lateinit var settingRepository: SettingRepository + private lateinit var bookRepository: BookRepository + + @Before + fun setup() { + Dispatchers.setMain(Dispatchers.Unconfined) + pageSplitDataSource = mockk(relaxed = true) + fontDataSource = mockk(relaxed = true) + settingRepository = mockk(relaxed = true) + bookRepository = mockk(relaxed = true) + + coEvery { settingRepository.viewerStyle } returns MutableStateFlow(ViewerStyle()) + coEvery { bookRepository.getBook(any()) } returns MutableStateFlow( + Book( + bookId = 1, + title = "title", + author = "author", + content = "content", + contentData = "content", + coverImage = null, + progress = 0.7, + ) + ) + pageSplitRepository = PageSplitRepository( + pageSplitDataSource, + fontDataSource, + settingRepository, + bookRepository + ) + coEvery { pageSplitDataSource.splitPage(any(), any(), any(), any(), any(), any()) } returns listOf( + 0, + 3, + 5 + ).toIntArray() + } + + @After + fun tearDown() { + Dispatchers.resetMain() + } + + @Test + fun `getSplitData returns PageSplitData`() = runTest { + // Arrange + val bookId = 1 + val width = 500 + val height = 800 + val viewerStyle = ViewerStyle() + val charWidths = FloatArray(65536) { 16f } + + // Act + val result = pageSplitRepository.getSplitData(bookId, width, height) + + // Assert + assertNotNull(result) + assertEquals(width, result!!.width) + assertEquals(height, result.height) + assertEquals(viewerStyle, result.viewerStyle) + } + + @Test + fun `drawPage calls drawPage on PageSplitDataSource`() = runTest { + // Arrange + val canvas = mockk(relaxed = true) + val bookId = 1 + val page = 0 + val isDarkMode = false + val width = 500 + val height = 800 + val viewerStyle = ViewerStyle() + val charWidths = FloatArray(65536) { 16f } + + // Act + pageSplitRepository.getSplitData(bookId, width, height) + pageSplitRepository.drawPage(canvas, bookId, page, isDarkMode) + + // Assert + verify(exactly = 1) { pageSplitDataSource.drawPage(any(), any(), any(), any(), any(), any()) } + } + + @Test + fun `drawPageRaw calls drawPage on PageSplitDataSource`() { + // Arrange + val canvas = mockk(relaxed = true) + val pageContent = "Lorem ipsum dolor sit amet." + val viewerStyle = ViewerStyleBuilder().build() + val width = 500 + val isDarkMode = false + + // Act + pageSplitRepository.drawPageRaw(canvas, pageContent, viewerStyle, width, isDarkMode) + + // Assert + verify(exactly = 1) { pageSplitDataSource.drawPage(any(), any(), any(), any(), any(), any()) } + } +} diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt new file mode 100644 index 0000000..9bd077d --- /dev/null +++ b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt @@ -0,0 +1,85 @@ +package com.example.readability.ui.models.viewer + +import android.content.Context +import com.example.readability.data.viewer.SettingDao +import com.example.readability.data.viewer.SettingRepository +import com.example.readability.data.viewer.ViewerStyleBuilder +import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +@ExperimentalCoroutinesApi +class SettingRepositoryTest { + + private lateinit var settingRepository: SettingRepository + private lateinit var mockSettingDao: SettingDao + private lateinit var mockContext: Context + + @Before + fun setup() { + Dispatchers.setMain(Dispatchers.Unconfined) + mockSettingDao = mockk(relaxed = true) + mockContext = mockk(relaxed = true) + every { mockContext.assets } returns mockk(relaxed = true) + every { mockContext.assets.open(any()) } returns "".byteInputStream() + settingRepository = SettingRepository(mockSettingDao, mockContext) + } + + @After + fun tearDown() { + Dispatchers.resetMain() + } + + @Test + fun `resetViewerStyle deletes and inserts a new ViewerStyle`() = runTest { + // Arrange + coEvery { mockSettingDao.delete() } just Runs + coEvery { mockSettingDao.insert(any()) } just Runs + + // Act + settingRepository.resetViewerStyle() + + // Assert + coVerify { mockSettingDao.delete() } + coVerify { mockSettingDao.insert(any()) } + } + + @Test + fun `updateViewerStyle updates the ViewerStyle in SettingDao`() = runTest { + // Arrange + val viewerStyle = ViewerStyleBuilder().textSize(18f).build() + coEvery { mockSettingDao.update(any()) } just Runs + + // Act + settingRepository.updateViewerStyle(viewerStyle) + + // Assert + coVerify(exactly = 1) { mockSettingDao.update(viewerStyle) } + } + + @Test + fun `viewerStyle returns default ViewerStyle if SettingDao returns null`() = runTest { + // Arrange + coEvery { mockSettingDao.get() } returns flowOf(null) + + // Act + val result = settingRepository.viewerStyle.value + + // Assert + assertEquals(ViewerStyleBuilder().build(), result) + } +} + From 9eff7439efd10bc0d23925dcd1a7f251f4a8167b Mon Sep 17 00:00:00 2001 From: Scripter36 <1350adwx@gmail.com> Date: Sun, 10 Dec 2023 16:27:10 +0900 Subject: [PATCH 09/15] fix: run ktlintFormat --- .../readability/data/user/UserRepository.kt | 1 - .../readability/data/viewer/FontDataSource.kt | 2 +- .../data/viewer/SettingDatabase.kt | 18 ++-- .../ui/screens/settings/ViewerView.kt | 26 ++--- .../ui/screens/viewer/ViewerView.kt | 11 +- .../ui/models/ai/QuizRemoteDataSourceTest.kt | 13 +-- .../ui/models/ai/QuizRepositoryTest.kt | 12 +-- .../models/ai/SummaryRemoteDataSourceTest.kt | 3 +- .../ui/models/ai/SummaryRepositoryTest.kt | 6 +- .../ui/models/book/BookFileDataSourceTest.kt | 7 +- .../models/book/BookRemoteDataSourceTest.kt | 101 ++++++++++++++---- .../ui/models/book/BookRepositoryTest.kt | 1 - .../network/NetworkStatusRepositoryTest.kt | 4 - .../models/user/UserRemoteDataSourceTest.kt | 22 ++-- .../ui/models/user/UserRepositoryTest.kt | 26 +++-- .../ui/models/viewer/FontDataSourceTest.kt | 1 - .../models/viewer/PageSplitRepositoryTest.kt | 6 +- .../ui/models/viewer/SettingRepositoryTest.kt | 1 - 18 files changed, 162 insertions(+), 99 deletions(-) diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt index 81dc9cc..981a0b0 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt +++ b/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt @@ -1,7 +1,6 @@ package com.example.readability.data.user import com.example.readability.data.NetworkStatusRepository -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.firstOrNull import java.util.concurrent.TimeUnit import javax.inject.Inject diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt b/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt index bacacb8..ecc0b70 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt +++ b/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt @@ -57,7 +57,7 @@ class FontDataSource @Inject constructor( ViewerStyleBuilder() .textSize(16f) .letterSpacing(0f) - .build() + .build(), ).fontMetrics referenceLineHeight.value = fontMetrics.bottom - fontMetrics.top + fontMetrics.leading } diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt b/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt index 56e30d4..8cb2acb 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt +++ b/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt @@ -45,13 +45,19 @@ class ViewerStyleBuilder(private var viewerStyle: ViewerStyle = ViewerStyle()) { fun textSize(textSize: Float) = apply { viewerStyle = viewerStyle.copy(textSize = textSize) } fun lineHeight(lineHeight: Float) = apply { viewerStyle = viewerStyle.copy(lineHeight = lineHeight) } fun letterSpacing(letterSpacing: Float) = apply { viewerStyle = viewerStyle.copy(letterSpacing = letterSpacing) } - fun paragraphSpacing(paragraphSpacing: Float) = apply { viewerStyle = viewerStyle.copy(paragraphSpacing = paragraphSpacing) } + fun paragraphSpacing(paragraphSpacing: Float) = + apply { viewerStyle = viewerStyle.copy(paragraphSpacing = paragraphSpacing) } fun fontFamily(fontFamily: String) = apply { viewerStyle = viewerStyle.copy(fontFamily = fontFamily) } - fun verticalPadding(verticalPadding: Float) = apply { viewerStyle = viewerStyle.copy(verticalPadding = verticalPadding) } - fun horizontalPadding(horizontalPadding: Float) = apply { viewerStyle = viewerStyle.copy(horizontalPadding = horizontalPadding) } - fun brightBackgroundColor(brightBackgroundColor: Int) = apply { viewerStyle = viewerStyle.copy(brightBackgroundColor = brightBackgroundColor) } - fun darkBackgroundColor(darkBackgroundColor: Int) = apply { viewerStyle = viewerStyle.copy(darkBackgroundColor = darkBackgroundColor) } - fun brightTextColor(brightTextColor: Int) = apply { viewerStyle = viewerStyle.copy(brightTextColor = brightTextColor) } + fun verticalPadding(verticalPadding: Float) = + apply { viewerStyle = viewerStyle.copy(verticalPadding = verticalPadding) } + fun horizontalPadding(horizontalPadding: Float) = + apply { viewerStyle = viewerStyle.copy(horizontalPadding = horizontalPadding) } + fun brightBackgroundColor(brightBackgroundColor: Int) = + apply { viewerStyle = viewerStyle.copy(brightBackgroundColor = brightBackgroundColor) } + fun darkBackgroundColor(darkBackgroundColor: Int) = + apply { viewerStyle = viewerStyle.copy(darkBackgroundColor = darkBackgroundColor) } + fun brightTextColor(brightTextColor: Int) = + apply { viewerStyle = viewerStyle.copy(brightTextColor = brightTextColor) } fun darkTextColor(darkTextColor: Int) = apply { viewerStyle = viewerStyle.copy(darkTextColor = darkTextColor) } fun build() = viewerStyle } diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt index 811c343..a583ade 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt @@ -262,7 +262,7 @@ fun TextOptions( onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .fontFamily(selectionOption.key) - .build() + .build(), ) fontFamilyExpanded = false }, text = { @@ -282,14 +282,14 @@ fun TextOptions( onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .textSize(minOf(50f, viewerStyle.textSize + 1f)) - .build() + .build(), ) }, onMinus = { onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .textSize(maxOf(10f, viewerStyle.textSize - 1f)) - .build() + .build(), ) }, ) @@ -300,14 +300,14 @@ fun TextOptions( onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .lineHeight(minOf(6f, viewerStyle.lineHeight + 0.05f)) - .build() + .build(), ) }, onMinus = { onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .lineHeight(maxOf(0.6f, viewerStyle.lineHeight - 0.05f)) - .build() + .build(), ) }, ) @@ -318,14 +318,14 @@ fun TextOptions( onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .letterSpacing(minOf(0.4f, viewerStyle.letterSpacing + 0.01f)) - .build() + .build(), ) }, onMinus = { onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .letterSpacing(maxOf(0f, viewerStyle.letterSpacing - 0.01f)) - .build() + .build(), ) }, ) @@ -336,14 +336,14 @@ fun TextOptions( onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .paragraphSpacing(minOf(3f, viewerStyle.paragraphSpacing + 0.05f)) - .build() + .build(), ) }, onMinus = { onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .paragraphSpacing(maxOf(1f, viewerStyle.paragraphSpacing - 0.05f)) - .build() + .build(), ) }, ) @@ -366,14 +366,14 @@ fun ViewerOptions( onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .horizontalPadding(minOf(70f, viewerStyle.horizontalPadding + 1)) - .build() + .build(), ) }, onMinus = { onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .horizontalPadding(maxOf(0f, viewerStyle.horizontalPadding - 1)) - .build() + .build(), ) }, ) @@ -384,14 +384,14 @@ fun ViewerOptions( onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .verticalPadding(minOf(110f, viewerStyle.verticalPadding + 1)) - .build() + .build(), ) }, onMinus = { onViewerStyleChanged( ViewerStyleBuilder(viewerStyle) .verticalPadding(maxOf(0f, viewerStyle.verticalPadding - 1)) - .build() + .build(), ) }, ) diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt index 84d84be..0a493c0 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt +++ b/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt @@ -174,7 +174,7 @@ fun ViewerView( onPageSizeChanged = { width, height -> onPageSizeChanged(width, height) }, - viewerStyle = pageSplitData?.viewerStyle + viewerStyle = pageSplitData?.viewerStyle, ) AnimatedContent( modifier = Modifier @@ -510,7 +510,8 @@ fun BookPage( pageIndex: Int, onPageDraw: (canvas: NativeCanvas, pageIndex: Int) -> Unit = { _, _ -> }, ) { - val horizontalPadding = with(LocalDensity.current) { (pageSplitData?.viewerStyle?.horizontalPadding ?: 16f).dp.toPx() } + val horizontalPadding = + with(LocalDensity.current) { (pageSplitData?.viewerStyle?.horizontalPadding ?: 16f).dp.toPx() } val verticalPadding = with(LocalDensity.current) { (pageSplitData?.viewerStyle?.verticalPadding ?: 16f).dp.toPx() } val aspectRatio = @@ -583,7 +584,7 @@ fun BookPage( fun ViewerSizeMeasurer( modifier: Modifier = Modifier, viewerStyle: ViewerStyle?, - onPageSizeChanged: (Int, Int) -> Unit = { _, _ -> } + onPageSizeChanged: (Int, Int) -> Unit = { _, _ -> }, ) { val horizontalPadding = (viewerStyle?.horizontalPadding ?: 16f).dp val verticalPadding = (viewerStyle?.verticalPadding ?: 16f).dp @@ -597,7 +598,7 @@ fun ViewerSizeMeasurer( .fillMaxWidth() .padding( horizontal = horizontalPadding, - vertical = verticalPadding + vertical = verticalPadding, ) .onGloballyPositioned { onPageSizeChanged( @@ -767,7 +768,7 @@ fun SummaryActions( onNavigateSummary: () -> Unit = {}, onNavigateQuiz: () -> Unit = {}, onUpdateSummaryProgress: suspend () -> Result = { Result.success(Unit) }, - pageSplitData: PageSplitData? + pageSplitData: PageSplitData?, ) { // update summary progress on every 2 seconds, if the progress is not 1 val summaryUpdateScope = rememberCoroutineScope() diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt index a3217f1..20badaf 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt @@ -3,7 +3,6 @@ package com.example.readability.ui.models.ai import com.example.readability.data.ai.QuizAPI import com.example.readability.data.ai.QuizRemoteDataSource import com.example.readability.data.ai.QuizResponseType -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.runTest import okhttp3.ResponseBody @@ -128,7 +127,7 @@ class QuizRemoteDataSourceTest { val result = quizRemoteDataSource.getQuiz(bookId, progress, accessToken) // Assert - val number_of_quiz = 3 + val numberOfQuiz = 3 val data = mutableListOf( "Why this unit test is meaningful?" to "Because it checks the correctness of the code.", "What is the best programming language?" to "Kotlin!", @@ -139,7 +138,7 @@ class QuizRemoteDataSourceTest { result.toList().forEach { println(it) if (it.type == QuizResponseType.COUNT) { - assert(it.intData == number_of_quiz) + assert(it.intData == numberOfQuiz) } else if (it.type == QuizResponseType.QUESTION_END) { isQuestion = false } else if (it.type == QuizResponseType.ANSWER_END) { @@ -149,12 +148,12 @@ class QuizRemoteDataSourceTest { if (isQuestion) { assert(data[index].first.startsWith(it.data)) data[index] = data[index].copy( - first = data[index].first.substring(it.data.length) + first = data[index].first.substring(it.data.length), ) } else { assert(data[index].second.startsWith(it.data)) data[index] = data[index].copy( - second = data[index].second.substring(it.data.length) + second = data[index].second.substring(it.data.length), ) } } @@ -226,7 +225,9 @@ class QuizRemoteDataSourceTest { val progress = 0.5 val accessToken = "testAccessToken" val responseBody = mock(ResponseBody::class.java) - doReturn(ByteArrayInputStream("data: Sorry, but we cannot generate quiz.".toByteArray())).`when`(responseBody).byteStream() + doReturn( + ByteArrayInputStream("data: Sorry, but we cannot generate quiz.".toByteArray()), + ).`when`(responseBody).byteStream() val response = Response.success(responseBody) val call = mock(retrofit2.Call::class.java) diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt index 1055708..a44151f 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt @@ -1,25 +1,17 @@ package com.example.readability.ui.models.ai +import com.example.readability.data.NetworkStatusRepository import com.example.readability.data.ai.QuizRemoteDataSource import com.example.readability.data.ai.QuizRepository - -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.ai.QuizLoadState import com.example.readability.data.ai.QuizResponse import com.example.readability.data.ai.QuizResponseType import com.example.readability.data.user.UserNotSignedInException import com.example.readability.data.user.UserRepository import io.mockk.coEvery -import io.mockk.coVerify import io.mockk.mockk -import io.mockk.verify -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.launch -import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Before @@ -86,7 +78,7 @@ class QuizRepositoryTest { QuizResponse(QuizResponseType.STRING, "Question 3", 0), QuizResponse(QuizResponseType.QUESTION_END, "", 0), QuizResponse(QuizResponseType.STRING, "Answer 3", 0), - QuizResponse(QuizResponseType.ANSWER_END, "", 0) + QuizResponse(QuizResponseType.ANSWER_END, "", 0), ) // Act diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt index 9cb023b..5d6b93f 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt @@ -73,7 +73,8 @@ class SummaryRemoteDataSourceTest { // Assert result.toList().reduce { - acc, s -> acc + s + acc, s -> + acc + s }.let { assert(it == "This is a test summary.\n") } diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt index 25f0f17..69225f0 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt @@ -31,7 +31,7 @@ class SummaryRepositoryTest { summaryRepository = SummaryRepository( summaryRemoteDataSource, userRepository, - networkStatusRepository + networkStatusRepository, ) } @@ -67,7 +67,9 @@ class SummaryRepositoryTest { // Arrange coEvery { networkStatusRepository.isConnected } returns true coEvery { userRepository.getAccessToken() } returns "testAccessToken" - coEvery { summaryRemoteDataSource.getSummary(any(), any(), any()) } returns flowOf("Summary 1", "Summary 2", "Summary 3") + coEvery { + summaryRemoteDataSource.getSummary(any(), any(), any()) + } returns flowOf("Summary 1", "Summary 2", "Summary 3") // Act val result = summaryRepository.getSummary(1, 0.5) diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt index a6002be..d477fab 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt @@ -6,7 +6,10 @@ import androidx.compose.ui.graphics.asAndroidBitmap import androidx.compose.ui.graphics.asImageBitmap import com.example.readability.data.book.BookFileDataSource import com.example.readability.data.book.FileHelper -import io.mockk.* +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import io.mockk.spyk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Before @@ -118,7 +121,7 @@ class BookFileDataSourceTest { val imageBitmap: ImageBitmap = spyk( Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888).asImageBitmap(), ) - every { imageBitmap.asAndroidBitmap() } returns mockk() + coEvery { imageBitmap.asAndroidBitmap() } returns mockk() coEvery { fileHelper.openFileOutputStream(any()) } returns mockk() // Act diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt index ff59eac..99b7845 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt @@ -7,7 +7,10 @@ import com.example.readability.data.book.BookRemoteDataSource import com.example.readability.data.book.BookResponse import com.example.readability.data.book.BooksResponse import com.example.readability.data.book.SummaryProgressResponse -import io.mockk.* +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import io.mockk.unmockkAll import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -42,10 +45,26 @@ class BookRemoteDataSourceTest { fun `getBookList success should return a list of books`() = runTest { // Arrange coEvery { bookAPI.getBooks(any()).execute() } returns Response.success( - BooksResponse(listOf( - BookResponse(1, "Title1", "Author1", "Content1", "Cover1", 0.5), - BookResponse(2, "Title2", "Author2", "Content2", "Cover2", 0.8) - )) + BooksResponse( + listOf( + BookResponse( + 1, + "Title1", + "Author1", + "Content1", + "Cover1", + 0.5, + ), + BookResponse( + 2, + "Title2", + "Author2", + "Content2", + "Cover2", + 0.8, + ), + ), + ), ) // Act @@ -63,7 +82,9 @@ class BookRemoteDataSourceTest { @Test fun `getBookList failure should return a failure result`() = runTest { // Arrange - coEvery { bookAPI.getBooks(any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + coEvery { + bookAPI.getBooks(any()).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.getBookList("accessToken") @@ -80,7 +101,7 @@ class BookRemoteDataSourceTest { val byteArrayOutputStream = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream) coEvery { bookAPI.getBookCoverImage(any(), any()).execute() } returns Response.success( - byteArrayOutputStream.toByteArray().toResponseBody("image/jpeg".toMediaTypeOrNull()) + byteArrayOutputStream.toByteArray().toResponseBody("image/jpeg".toMediaTypeOrNull()), ) // Act @@ -98,7 +119,9 @@ class BookRemoteDataSourceTest { @Test fun `getCoverImageData failure should return a failure result`() = runTest { // Arrange - coEvery { bookAPI.getBookCoverImage(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + coEvery { + bookAPI.getBookCoverImage(any(), any()).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.getCoverImageData("accessToken", "coverImage") @@ -111,7 +134,9 @@ class BookRemoteDataSourceTest { @Test fun `getContentData success should return content string`() = runTest { // Arrange - coEvery { bookAPI.getBookContent(any(), any()).execute() } returns Response.success("Content".toResponseBody("text/plain".toMediaTypeOrNull())) + coEvery { + bookAPI.getBookContent(any(), any()).execute() + } returns Response.success("Content".toResponseBody("text/plain".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.getContentData("accessToken", "content") @@ -125,7 +150,9 @@ class BookRemoteDataSourceTest { @Test fun `getContentData failure should return a failure result`() = runTest { // Arrange - coEvery { bookAPI.getBookContent(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + coEvery { + bookAPI.getBookContent(any(), any()).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.getContentData("accessToken", "content") @@ -138,7 +165,11 @@ class BookRemoteDataSourceTest { @Test fun `getSummaryProgress success should return summary progress string`() = runTest { // Arrange - coEvery { bookAPI.getSummaryProgress(any(), any()).execute() } returns Response.success(SummaryProgressResponse("0.7")) + coEvery { bookAPI.getSummaryProgress(any(), any()).execute() } returns Response.success( + SummaryProgressResponse( + "0.7", + ), + ) // Act val result = bookRemoteDataSource.getSummaryProgress("accessToken", 1) @@ -152,7 +183,9 @@ class BookRemoteDataSourceTest { @Test fun `getSummaryProgress failure should return a failure result`() = runTest { // Arrange - coEvery { bookAPI.getSummaryProgress(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + coEvery { + bookAPI.getSummaryProgress(any(), any()).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.getSummaryProgress("accessToken", 1) @@ -168,31 +201,51 @@ class BookRemoteDataSourceTest { coEvery { bookAPI.addBook(any(), any()).execute() } returns Response.success(Unit) // Act - val result = bookRemoteDataSource.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) + val result = bookRemoteDataSource.addBook( + "accessToken", + AddBookRequest("Title", "Content", "Author", "Cover"), + ) // Assert assert(result.isSuccess) assert(result.getOrNull() == Unit) - coVerify { bookAPI.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) } + coVerify { + bookAPI.addBook( + "accessToken", + AddBookRequest("Title", "Content", "Author", "Cover"), + ) + } } @Test fun `addBook failure should return a failure result`() = runTest { // Arrange - coEvery { bookAPI.addBook(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + coEvery { + bookAPI.addBook(any(), any()).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) // Act - val result = bookRemoteDataSource.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) + val result = bookRemoteDataSource.addBook( + "accessToken", + AddBookRequest("Title", "Content", "Author", "Cover"), + ) // Assert assert(result.isFailure) - coVerify { bookAPI.addBook("accessToken", AddBookRequest("Title", "Content", "Author", "Cover")) } + coVerify { + bookAPI.addBook( + "accessToken", + AddBookRequest("Title", "Content", "Author", "Cover"), + ) + } } @Test fun `deleteBook success should return success message`() = runTest { // Arrange - coEvery { bookAPI.deleteBook(any(), any()).execute() } returns Response.success("Success".toResponseBody("text/plain".toMediaTypeOrNull())) + coEvery { + bookAPI.deleteBook(any(), any()).execute() + } returns Response.success("Success".toResponseBody("text/plain".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.deleteBook(1, "accessToken") @@ -206,7 +259,9 @@ class BookRemoteDataSourceTest { @Test fun `deleteBook failure should return a failure result`() = runTest { // Arrange - coEvery { bookAPI.deleteBook(any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + coEvery { + bookAPI.deleteBook(any(), any()).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.deleteBook(1, "accessToken") @@ -219,7 +274,9 @@ class BookRemoteDataSourceTest { @Test fun `updateProgress success should return success message`() = runTest { // Arrange - coEvery { bookAPI.updateProgress(any(), any(), any()).execute() } returns Response.success("Success".toResponseBody("text/plain".toMediaTypeOrNull())) + coEvery { + bookAPI.updateProgress(any(), any(), any()).execute() + } returns Response.success("Success".toResponseBody("text/plain".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.updateProgress(1, 0.5, "accessToken") @@ -233,7 +290,9 @@ class BookRemoteDataSourceTest { @Test fun `updateProgress failure should return a failure result`() = runTest { // Arrange - coEvery { bookAPI.updateProgress(any(), any(), any()).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) + coEvery { + bookAPI.updateProgress(any(), any(), any()).execute() + } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) // Act val result = bookRemoteDataSource.updateProgress(1, 0.5, "accessToken") diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt index 23d3ded..6ca63ae 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt @@ -9,7 +9,6 @@ import com.example.readability.data.book.BookFileDataSource import com.example.readability.data.book.BookRemoteDataSource import com.example.readability.data.book.BookRepository import com.example.readability.data.user.UserRepository -import io.mockk.coEvery import io.mockk.unmockkAll import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.runBlocking diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt index 8d8fc64..b372156 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt @@ -5,10 +5,6 @@ import com.example.readability.data.NetworkStatusRepository import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.mockk -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt index 63ef1c4..919b177 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt @@ -39,7 +39,7 @@ class UserRemoteDataSourceTest { clientId = any(), clientSecret = any(), username = any(), - password = any() + password = any(), ).execute() } returns Response.success(TokenResponse("access_token", "refresh_token", "token_type")) @@ -62,7 +62,7 @@ class UserRemoteDataSourceTest { clientId = any(), clientSecret = any(), username = any(), - password = any() + password = any(), ).execute() } returns Response.error(400, "".toResponseBody("application/json".toMediaTypeOrNull())) @@ -91,7 +91,7 @@ class UserRemoteDataSourceTest { // Arrange coEvery { userAPI.signUp(any()).execute() } returns Response.error( 400, - "".toResponseBody("application/json".toMediaTypeOrNull()) + "".toResponseBody("application/json".toMediaTypeOrNull()), ) // Act @@ -107,8 +107,8 @@ class UserRemoteDataSourceTest { coEvery { userAPI.refreshAccessToken(any()).execute() } returns Response.success( RefreshTokenResponse( "new_access_token", - "token_type" - ) + "token_type", + ), ) // Act @@ -124,7 +124,7 @@ class UserRemoteDataSourceTest { // Arrange coEvery { userAPI.refreshAccessToken(any()).execute() } returns Response.error( 400, - "".toResponseBody("application/json".toMediaTypeOrNull()) + "".toResponseBody("application/json".toMediaTypeOrNull()), ) // Act @@ -142,8 +142,8 @@ class UserRemoteDataSourceTest { "username", "email", "created_at", - 1 - ) + 1, + ), ) // Act @@ -160,7 +160,7 @@ class UserRemoteDataSourceTest { // Arrange coEvery { userAPI.getUserInfo(any()).execute() } returns Response.error( 400, - "".toResponseBody("application/json".toMediaTypeOrNull()) + "".toResponseBody("application/json".toMediaTypeOrNull()), ) // Act @@ -188,7 +188,7 @@ class UserRemoteDataSourceTest { // Arrange coEvery { userAPI.changePassword(any(), any()).execute() } returns Response.error( 400, - "".toResponseBody("application/json".toMediaTypeOrNull()) + "".toResponseBody("application/json".toMediaTypeOrNull()), ) // Act @@ -216,7 +216,7 @@ class UserRemoteDataSourceTest { // Arrange coEvery { userAPI.deleteAccount(any()).execute() } returns Response.error( 400, - "".toResponseBody("application/json".toMediaTypeOrNull()) + "".toResponseBody("application/json".toMediaTypeOrNull()), ) // Act diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt index e29595a..03bd21c 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt @@ -79,7 +79,7 @@ class UserRepositoryTest { coEvery { userRemoteDataSource.signIn( any(), - any() + any(), ) } returns Result.failure(Throwable("Any custom error message should be handled")) @@ -102,8 +102,8 @@ class UserRepositoryTest { TokenResponse( "fake_access_token", "fake_refresh_token", - "bearer" - ) + "bearer", + ), ) // Act @@ -124,7 +124,7 @@ class UserRepositoryTest { userRemoteDataSource.signUp( any(), any(), - any() + any(), ) } returns Result.failure(Throwable("Any custom error message should be handled")) @@ -176,7 +176,9 @@ class UserRepositoryTest { coEvery { userDao.get() } returns flowOf(fakeUser) coEvery { userDao.updateAccessToken(any(), any()) } returns Unit - coEvery { userRemoteDataSource.refreshAccessToken(fakeRefreshToken) } returns Result.success("fake_new_access_token") + coEvery { + userRemoteDataSource.refreshAccessToken(fakeRefreshToken) + } returns Result.success("fake_new_access_token") // Act val result = userRepository.getAccessToken() @@ -202,12 +204,14 @@ class UserRepositoryTest { username = "testuser", email = "test@example.com", created_at = "2023-01-01", - verified = 1 + verified = 1, ) coEvery { userDao.get() } returns flowOf(fakeUser) coEvery { networkStatusRepository.isConnected } returns true - coEvery { userRemoteDataSource.getUserInfo(fakeUser.accessToken!!) } returns Result.success(fakeUserInfoResponse) + coEvery { + userRemoteDataSource.getUserInfo(fakeUser.accessToken!!) + } returns Result.success(fakeUserInfoResponse) // Act val result = userRepository.getUserInfo() @@ -233,7 +237,9 @@ class UserRepositoryTest { coEvery { userDao.get() } returns flowOf(fakeUser) coEvery { networkStatusRepository.isConnected } returns true - coEvery { userRemoteDataSource.getUserInfo(fakeUser.accessToken!!) } returns Result.failure(Throwable("Any custom error message")) + coEvery { + userRemoteDataSource.getUserInfo(fakeUser.accessToken!!) + } returns Result.failure(Throwable("Any custom error message")) // Act val result = userRepository.getUserInfo() @@ -263,7 +269,7 @@ class UserRepositoryTest { coEvery { userRemoteDataSource.changePassword( fakeUser.accessToken!!, - newPassword + newPassword, ) } returns Result.success(Unit) @@ -292,7 +298,7 @@ class UserRepositoryTest { coEvery { userDao.get() } returns flowOf(fakeUser) coEvery { networkStatusRepository.isConnected } returns true coEvery { userRemoteDataSource.changePassword(fakeUser.accessToken!!, newPassword) } returns Result.failure( - Throwable("Any custom error message") + Throwable("Any custom error message"), ) // Act diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt index 56f4d3d..9dffddd 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt @@ -1,6 +1,5 @@ package com.example.readability.ui.models.viewer - import android.content.Context import androidx.core.content.res.ResourcesCompat import com.example.readability.data.viewer.FontDataSource diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt index dfe248d..3facf65 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt @@ -51,18 +51,18 @@ class PageSplitRepositoryTest { contentData = "content", coverImage = null, progress = 0.7, - ) + ), ) pageSplitRepository = PageSplitRepository( pageSplitDataSource, fontDataSource, settingRepository, - bookRepository + bookRepository, ) coEvery { pageSplitDataSource.splitPage(any(), any(), any(), any(), any(), any()) } returns listOf( 0, 3, - 5 + 5, ).toIntArray() } diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt index 9bd077d..143f14b 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt @@ -82,4 +82,3 @@ class SettingRepositoryTest { assertEquals(ViewerStyleBuilder().build(), result) } } - From e30f2a1d5dd7b62ff168b21b68f10214915e6f38 Mon Sep 17 00:00:00 2001 From: Scripter36 <1350adwx@gmail.com> Date: Sun, 10 Dec 2023 16:38:04 +0900 Subject: [PATCH 10/15] fix: make instrumented test run again --- frontend/app/build.gradle.kts | 2 -- .../java/com/example/readability/BookDBTest.kt | 16 +++++++++++----- .../readability/screens/BookScreenTest.kt | 2 ++ .../readability/data/user/UserDatabase.kt | 5 +++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/frontend/app/build.gradle.kts b/frontend/app/build.gradle.kts index b6670dd..9f19a7c 100644 --- a/frontend/app/build.gradle.kts +++ b/frontend/app/build.gradle.kts @@ -131,8 +131,6 @@ dependencies { androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.5.4") androidTestImplementation("androidx.navigation:navigation-testing:2.7.5") androidTestImplementation("com.google.dagger:hilt-android-testing:$hiltVersion") - androidTestImplementation("org.awaitility:awaitility:4.2.0") - androidTestImplementation("org.awaitility:awaitility-kotlin:4.2.0") val mocckVersion = "1.13.8" testImplementation("io.mockk:mockk:$mocckVersion") diff --git a/frontend/app/src/androidTest/java/com/example/readability/BookDBTest.kt b/frontend/app/src/androidTest/java/com/example/readability/BookDBTest.kt index 7de66f6..a7e4290 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/BookDBTest.kt +++ b/frontend/app/src/androidTest/java/com/example/readability/BookDBTest.kt @@ -13,10 +13,10 @@ import junit.framework.TestCase.assertTrue import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.test.runTest import kotlinx.coroutines.withContext -import org.awaitility.Awaitility.await import org.junit.Before import org.junit.Rule import org.junit.Test @@ -60,6 +60,14 @@ class BookDBTest { return (diff / (bitmap1.width * bitmap1.height)) < 5 } + suspend fun assertUntil(time: Long, block: () -> Boolean) { + val startTime = System.currentTimeMillis() + while (startTime + time > System.currentTimeMillis() && !block()) { + delay(100L) + } + assert(block()) + } + @OptIn(ExperimentalStdlibApi::class) @Test fun addBook_success() = runTest(timeout = Duration.parse("60s")) { @@ -98,9 +106,7 @@ class BookDBTest { val bookRefreshResult = withContext(Dispatchers.IO) { bookRepository.refreshBookList() } assertTrue("Book refresh should succeed", bookRefreshResult.isSuccess) - await().timeout(java.time.Duration.ofMillis(5000L)).until { - bookList.value.isNotEmpty() && bookList.value.any { it.title == bookTitle } - } + assertUntil(5000L) { bookList.value.isNotEmpty() && bookList.value.any { it.title == bookTitle } } // get content and image var book = bookList.value.first { it.title == bookTitle } @@ -109,7 +115,7 @@ class BookDBTest { assertTrue("Get content should succeed", contentResult.isSuccess) assertTrue("Get image should succeed", imageResult.isSuccess) - await().timeout(java.time.Duration.ofMillis(5000L)).until { + assertUntil(5000L) { book = bookList.value.first { it.title == bookTitle } book.contentData != null && book.coverImageData != null } diff --git a/frontend/app/src/androidTest/java/com/example/readability/screens/BookScreenTest.kt b/frontend/app/src/androidTest/java/com/example/readability/screens/BookScreenTest.kt index a602196..d04bd50 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/screens/BookScreenTest.kt +++ b/frontend/app/src/androidTest/java/com/example/readability/screens/BookScreenTest.kt @@ -147,6 +147,7 @@ class BookScreenTest { content = "asdf", progress = 0.1, coverImage = "asd", + summaryProgress = 1.0, ), ), ) @@ -179,6 +180,7 @@ class BookScreenTest { content = "asdf", progress = 0.1, coverImage = "asd", + summaryProgress = 1.0, ), ), ) diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserDatabase.kt b/frontend/app/src/main/java/com/example/readability/data/user/UserDatabase.kt index d4b427e..46983b1 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserDatabase.kt +++ b/frontend/app/src/main/java/com/example/readability/data/user/UserDatabase.kt @@ -6,6 +6,7 @@ import androidx.room.Dao import androidx.room.Database import androidx.room.Entity import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.PrimaryKey import androidx.room.Query import androidx.room.Room @@ -33,10 +34,10 @@ data class User( @Dao interface UserDao { - @Query("SELECT * FROM User") + @Query("SELECT * FROM User LIMIT 1") fun get(): Flow - @Insert + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(user: User) @Query("DELETE FROM User") From a5ff9426cb1d60b404a123ad956a9ee33cbadfb9 Mon Sep 17 00:00:00 2001 From: Scripter36 <1350adwx@gmail.com> Date: Sun, 10 Dec 2023 16:45:42 +0900 Subject: [PATCH 11/15] fix: remove wildcard import --- .../ui/models/network/NetworkStatusDataSourceTest.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt index 5964145..bdf3253 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt +++ b/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt @@ -3,7 +3,9 @@ package com.example.readability.ui.models.network import android.content.Context import android.net.ConnectivityManager import com.example.readability.data.NetworkStatusDataSource -import io.mockk.* +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.resetMain From b36042e3881093ed13335723438a4d88f3404618 Mon Sep 17 00:00:00 2001 From: Min Su Yoon Date: Sun, 10 Dec 2023 17:10:41 +0900 Subject: [PATCH 12/15] test: add unit test for proxy pattern; misc: add requirements file for backend venv --- backend/requirements.txt | 103 ++++++++++++++++++++++++++++++++++ backend/tests/test_summary.py | 9 ++- 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 backend/requirements.txt diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..99837d8 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,103 @@ +accelerate==0.23.0 +aiohttp==3.8.6 +aiosignal==1.3.1 +annotated-types==0.6.0 +anyio==3.7.1 +async-timeout==4.0.3 +attrs==23.1.0 +auto-gptq==0.4.2+cu118 +autopep8==2.0.4 +bcrypt==4.0.1 +certifi==2023.7.22 +cffi==1.16.0 +charset-normalizer==3.3.0 +click==8.1.7 +coloredlogs==15.0.1 +coverage==7.3.2 +cryptography==41.0.5 +datasets==2.14.5 +dill==0.3.7 +exceptiongroup==1.1.3 +fastapi==0.103.2 +filelock==3.12.4 +frozenlist==1.4.0 +fsspec==2023.6.0 +gunicorn==21.2.0 +h11==0.14.0 +httpcore==1.0.1 +httptools==0.6.0 +httpx==0.25.1 +huggingface-hub==0.18.0 +humanfriendly==10.0 +idna==3.4 +iniconfig==2.0.0 +Jinja2==3.1.2 +MarkupSafe==2.1.3 +mpmath==1.3.0 +multidict==6.0.4 +multiprocess==0.70.15 +mysql-connector-python==8.2.0 +networkx==3.1 +numpy==1.24.4 +nvidia-cublas-cu12==12.1.3.1 +nvidia-cuda-cupti-cu12==12.1.105 +nvidia-cuda-nvrtc-cu12==12.1.105 +nvidia-cuda-runtime-cu12==12.1.105 +nvidia-cudnn-cu12==8.9.2.26 +nvidia-cufft-cu12==11.0.2.54 +nvidia-curand-cu12==10.3.2.106 +nvidia-cusolver-cu12==11.4.5.107 +nvidia-cusparse-cu12==12.1.0.106 +nvidia-nccl-cu12==2.18.1 +nvidia-nvjitlink-cu12==12.2.140 +nvidia-nvtx-cu12==12.1.105 +openai==0.28.1 +optimum==1.13.2 +packaging==23.2 +pandas==2.0.3 +passlib==1.7.4 +peft==0.5.0 +Pillow==10.1.0 +pluggy==1.3.0 +protobuf==4.21.12 +psutil==5.9.5 +pyarrow==13.0.0 +pycodestyle==2.11.1 +pycparser==2.21 +pydantic==2.4.2 +pydantic-core==2.10.1 +PyJWT==2.8.0 +pytest==7.4.2 +pytest-cov==4.1.0 +python-dateutil==2.8.2 +python-dotenv==1.0.0 +python-multipart==0.0.6 +pytz==2023.3.post1 +PyYAML==6.0.1 +regex==2023.10.3 +requests==2.31.0 +rouge==1.0.1 +safetensors==0.4.0 +sentencepiece==0.1.99 +six==1.16.0 +sniffio==1.3.0 +sse-starlette==1.6.5 +starlette==0.27.0 +sympy==1.12 +tenacity==8.2.3 +tiktoken==0.5.1 +tokenizers==0.14.1 +tomli==2.0.1 +torch==2.1.0 +tqdm==4.66.1 +transformers==4.34.0 +triton==2.1.0 +typing-extensions==4.8.0 +tzdata==2023.3 +urllib3==2.0.6 +uvicorn==0.23.2 +uvloop==0.17.0 +watchfiles==0.20.0 +websockets==11.0.3 +xxhash==3.4.1 +yarl==1.9.2 diff --git a/backend/tests/test_summary.py b/backend/tests/test_summary.py index dbfd640..5c582ce 100644 --- a/backend/tests/test_summary.py +++ b/backend/tests/test_summary.py @@ -6,7 +6,7 @@ reduce_multiple_summaries_to_one, reduce_summaries_list, generate_summary_tree, update_summary_path_url, get_number_of_inferences ) -from llama.custom_type import Summary +from llama.custom_type import Summary, ProxyAIBackend, GPT4Backend, GPT3Backend import random import string import tiktoken @@ -161,3 +161,10 @@ def test_get_number_of_inferences(): expected4 = 1 assert get_number_of_inferences(len(list4)) == expected4, "Failed on list smaller than split size" print("fourth case passed") + +def test_proxy_pattern(): + ai_backend = ProxyAIBackend(GPT4Backend()) + assert type(ai_backend.summary_generator) == GPT4Backend + ai_backend.summary_generator = GPT3Backend() + assert type(ai_backend.summary_generator) == GPT3Backend + From 94731c802857f143a30f93e4fc1137c45182ebae Mon Sep 17 00:00:00 2001 From: Ikjun Choi <1350adwx@snu.ac.kr> Date: Sun, 10 Dec 2023 19:53:13 +0900 Subject: [PATCH 13/15] feat: add some privacy documents --- backend/main.py | 3 + backend/static/privacy_policy.html | 110 ++++++++++++++++++++++ backend/static/terms_and_conditions.html | 114 +++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 backend/static/privacy_policy.html create mode 100644 backend/static/terms_and_conditions.html diff --git a/backend/main.py b/backend/main.py index b5a58ab..c43422d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,4 +1,6 @@ from typing import Union + +from fastapi.staticfiles import StaticFiles from routers.ai import ai from routers.book import book from routers.user import user @@ -9,6 +11,7 @@ app.include_router(ai) app.include_router(book) app.include_router(user) +app.mount("/static", StaticFiles(directory="static"), name="static") if __name__ == "__main__": import uvicorn diff --git a/backend/static/privacy_policy.html b/backend/static/privacy_policy.html new file mode 100644 index 0000000..65faac0 --- /dev/null +++ b/backend/static/privacy_policy.html @@ -0,0 +1,110 @@ + + + + + + Privacy Policy + + + + Privacy Policy

+ Turkey built the Readability app as + a Free app. This SERVICE is provided by + Turkey at no cost and is intended for use as + is. +

+ This page is used to inform visitors regarding our + policies with the collection, use, and disclosure of Personal + Information if anyone decided to use our Service. +

+ If you choose to use our Service, then you agree to + the collection and use of information in relation to this + policy. The Personal Information that we collect is + used for providing and improving the Service. We will not use or share your information with + anyone except as described in this Privacy Policy. +

+ The terms used in this Privacy Policy have the same meanings + as in our Terms and Conditions, which are accessible at + Readability unless otherwise defined in this Privacy Policy. +

Information Collection and Use

+ For a better experience, while using our Service, we + may require you to provide us with certain personally + identifiable information, including but not limited to email, username. The information that + we request will be retained by us and used as described in this privacy policy. +

+ The app does use third-party services that may collect + information used to identify you. +

+ Link to the privacy policy of third-party service providers used + by the app +

Log Data

+ We want to inform you that whenever you + use our Service, in a case of an error in the app + we collect data and information (through third-party + products) on your phone called Log Data. This Log Data may + include information such as your device Internet Protocol + (“IP”) address, device name, operating system version, the + configuration of the app when utilizing our Service, + the time and date of your use of the Service, and other + statistics. +

Cookies

+ Cookies are files with a small amount of data that are + commonly used as anonymous unique identifiers. These are sent + to your browser from the websites that you visit and are + stored on your device's internal memory. +

+ This Service does not use these “cookies” explicitly. However, + the app may use third-party code and libraries that use + “cookies” to collect information and improve their services. + You have the option to either accept or refuse these cookies + and know when a cookie is being sent to your device. If you + choose to refuse our cookies, you may not be able to use some + portions of this Service. +

Service Providers

+ We may employ third-party companies and + individuals due to the following reasons: +

  • To facilitate our Service;
  • To provide the Service on our behalf;
  • To perform Service-related services; or
  • To assist us in analyzing how our Service is used.

+ We want to inform users of this Service + that these third parties have access to their Personal + Information. The reason is to perform the tasks assigned to + them on our behalf. However, they are obligated not to + disclose or use the information for any other purpose. +

Security

+ We value your trust in providing us your + Personal Information, thus we are striving to use commercially + acceptable means of protecting it. But remember that no method + of transmission over the internet, or method of electronic + storage is 100% secure and reliable, and we cannot + guarantee its absolute security. +

Links to Other Sites

+ This Service may contain links to other sites. If you click on + a third-party link, you will be directed to that site. Note + that these external sites are not operated by us. + Therefore, we strongly advise you to review the + Privacy Policy of these websites. We have + no control over and assume no responsibility for the content, + privacy policies, or practices of any third-party sites or + services. +

Children’s Privacy

+ These Services do not address anyone under the age of 13. + We do not knowingly collect personally + identifiable information from children under 13 years of age. In the case + we discover that a child under 13 has provided + us with personal information, we immediately + delete this from our servers. If you are a parent or guardian + and you are aware that your child has provided us with + personal information, please contact us so that + we will be able to do the necessary actions. +

Changes to This Privacy Policy

+ We may update our Privacy Policy from + time to time. Thus, you are advised to review this page + periodically for any changes. We will + notify you of any changes by posting the new Privacy Policy on + this page. +

This policy is effective as of 2023-12-10

Contact Us

+ If you have any questions or suggestions about our + Privacy Policy, do not hesitate to contact us at 1350adwx@gmail.com. +

This privacy policy page was created at privacypolicytemplate.net and modified/generated by App Privacy Policy Generator

+ + + \ No newline at end of file diff --git a/backend/static/terms_and_conditions.html b/backend/static/terms_and_conditions.html new file mode 100644 index 0000000..4ad33dc --- /dev/null +++ b/backend/static/terms_and_conditions.html @@ -0,0 +1,114 @@ + + + + + + Terms & Conditions + + + + Terms & Conditions

+ By downloading or using the app, these terms will + automatically apply to you – you should make sure therefore + that you read them carefully before using the app. You’re not + allowed to copy or modify the app, any part of the app, or + our trademarks in any way. You’re not allowed to attempt to + extract the source code of the app, and you also shouldn’t try + to translate the app into other languages or make derivative + versions. The app itself, and all the trademarks, copyright, + database rights, and other intellectual property rights related + to it, still belong to Turkey. +

+ Turkey is committed to ensuring that the app is + as useful and efficient as possible. For that reason, we + reserve the right to make changes to the app or to charge for + its services, at any time and for any reason. We will never + charge you for the app or its services without making it very + clear to you exactly what you’re paying for. +

+ The Readability app stores and processes personal data that + you have provided to us, to provide our + Service. It’s your responsibility to keep your phone and + access to the app secure. We therefore recommend that you do + not jailbreak or root your phone, which is the process of + removing software restrictions and limitations imposed by the + official operating system of your device. It could make your + phone vulnerable to malware/viruses/malicious programs, + compromise your phone’s security features and it could mean + that the Readability app won’t work properly or at all. +

+ The app does use third-party services that declare their + Terms and Conditions. +

+ Link to Terms and Conditions of third-party service + providers used by the app +

+ You should be aware that there are certain things that + Turkey will not take responsibility for. Certain + functions of the app will require the app to have an active + internet connection. The connection can be Wi-Fi or provided + by your mobile network provider, but Turkey + cannot take responsibility for the app not working at full + functionality if you don’t have access to Wi-Fi, and you don’t + have any of your data allowance left. +

+ If you’re using the app outside of an area with Wi-Fi, you + should remember that the terms of the agreement with your + mobile network provider will still apply. As a result, you may + be charged by your mobile provider for the cost of data for + the duration of the connection while accessing the app, or + other third-party charges. In using the app, you’re accepting + responsibility for any such charges, including roaming data + charges if you use the app outside of your home territory + (i.e. region or country) without turning off data roaming. If + you are not the bill payer for the device on which you’re + using the app, please be aware that we assume that you have + received permission from the bill payer for using the app. +

+ Along the same lines, Turkey cannot always take + responsibility for the way you use the app i.e. You need to + make sure that your device stays charged – if it runs out of + battery and you can’t turn it on to avail the Service, + Turkey cannot accept responsibility. +

+ With respect to Turkey’s responsibility for your + use of the app, when you’re using the app, it’s important to + bear in mind that although we endeavor to ensure that it is + updated and correct at all times, we do rely on third parties + to provide information to us so that we can make it available + to you. Turkey accepts no liability for any + loss, direct or indirect, you experience as a result of + relying wholly on this functionality of the app. +

+ At some point, we may wish to update the app. The app is + currently available on Android – the requirements for the + system(and for any additional systems we + decide to extend the availability of the app to) may change, + and you’ll need to download the updates if you want to keep + using the app. Turkey does not promise that it + will always update the app so that it is relevant to you + and/or works with the Android version that you have + installed on your device. However, you promise to always + accept updates to the application when offered to you, We may + also wish to stop providing the app, and may terminate use of + it at any time without giving notice of termination to you. + Unless we tell you otherwise, upon any termination, (a) the + rights and licenses granted to you in these terms will end; + (b) you must stop using the app, and (if needed) delete it + from your device. +

Changes to This Terms and Conditions

+ We may update our Terms and Conditions + from time to time. Thus, you are advised to review this page + periodically for any changes. We will + notify you of any changes by posting the new Terms and + Conditions on this page. +

+ These terms and conditions are effective as of 2023-12-10 +

Contact Us

+ If you have any questions or suggestions about our + Terms and Conditions, do not hesitate to contact us + at 1350adwx@gmail.com. +

This Terms and Conditions page was generated by App Privacy Policy Generator

+ + + \ No newline at end of file From b19f83d5671d36fb962710d737782a876dbe2815 Mon Sep 17 00:00:00 2001 From: Ikjun Choi <1350adwx@snu.ac.kr> Date: Sun, 10 Dec 2023 20:28:14 +0900 Subject: [PATCH 14/15] Update README.md --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c2fe005..cae9529 100644 --- a/README.md +++ b/README.md @@ -5,22 +5,25 @@ Readability is an eBook reader application that provide reading assistant services. - ## Features - Feature 1: Summary for previous contents - Feature 2: Quiz generation -- Ebook Viewer with overlay +- E-Book Viewer with overlay - Upload own book with txt file ## Getting Started ### Prerequisites -- Android Studio [version, e.g., 4.2.1] -- Minimum Android SDK Version [e.g., 21] +#### Frontend + +- Android Studio Giraffe (2022.3) or above +- Minimum Android SDK Version: 24 +- Target Android SDK Version: 34 -### Installation +#### Backend -[Installation link here] +- OpenAI key for GPT-4 +- A MySQL server From 0acbca0031a92b5ba46b563cff5b04e171d07c84 Mon Sep 17 00:00:00 2001 From: Ikjun Choi <1350adwx@snu.ac.kr> Date: Sun, 10 Dec 2023 20:30:41 +0900 Subject: [PATCH 15/15] refacor: change package name for play store deployment --- frontend/app/build.gradle.kts | 6 ++--- frontend/app/release/output-metadata.json | 20 ++++++++++++++ .../readability/AuthDBTest.kt | 4 +-- .../readability/BookDBTest.kt | 8 +++--- .../readability/HiltTestRunner.kt | 2 +- .../readability/screens/AuthScreenTest.kt | 16 ++++++------ .../readability/screens/BookScreenTest.kt | 14 +++++----- .../readability/screens/SettingScreenTest.kt | 12 ++++----- .../readability/screens/ViewerScreenTest.kt | 22 ++++++++-------- frontend/app/src/main/cpp/readability.cpp | 6 ++--- .../readability/MainActivity.kt | 10 +++---- .../readability/ReadabilityApplication.kt | 2 +- .../data/NetworkStatusDataSource.kt | 2 +- .../data/NetworkStatusRepository.kt | 2 +- .../readability/data/Utils.kt | 2 +- .../data/ai/QuizRemoteDataSource.kt | 4 +-- .../readability/data/ai/QuizRepository.kt | 8 +++--- .../data/ai/SummaryRemoteDataSource.kt | 4 +-- .../readability/data/ai/SummaryRepository.kt | 8 +++--- .../readability/data/book/BookDatabase.kt | 2 +- .../data/book/BookFileDataSource.kt | 2 +- .../data/book/BookRemoteDataSource.kt | 4 +-- .../readability/data/book/BookRepository.kt | 8 +++--- .../readability/data/user/UserDatabase.kt | 2 +- .../readability/data/user/UserException.kt | 2 +- .../data/user/UserRemoteDataSource.kt | 4 +-- .../readability/data/user/UserRepository.kt | 4 +-- .../readability/data/viewer/FontDataSource.kt | 4 +-- .../data/viewer/PageSplitDataSource.kt | 2 +- .../data/viewer/PageSplitRepository.kt | 4 +-- .../data/viewer/SettingDatabase.kt | 10 +++---- .../data/viewer/SettingRepository.kt | 2 +- .../readability/ui/animation/AnimateImeDp.kt | 2 +- .../ui/animation/FadeThroughTransition.kt | 2 +- .../ui/animation/SharedAxisTransition.kt | 2 +- .../readability/ui/animation/Values.kt | 2 +- .../ui/components/BottomSheetView.kt | 6 ++--- .../ui/components/PasswordTextField.kt | 4 +-- .../ui/components/RoundedRectButton.kt | 2 +- .../readability/ui/components/SettingTitle.kt | 6 ++--- .../readability/ui/screens/Screen.kt | 16 ++++++------ .../readability/ui/screens/auth/AuthScreen.kt | 8 +++--- .../readability/ui/screens/auth/EmailView.kt | 10 +++---- .../ui/screens/auth/ForgotPasswordView.kt | 10 +++---- .../readability/ui/screens/auth/IntroView.kt | 12 ++++----- .../ui/screens/auth/ResetPasswordView.kt | 10 +++---- .../readability/ui/screens/auth/SignInView.kt | 12 ++++----- .../readability/ui/screens/auth/SignUpView.kt | 12 ++++----- .../ui/screens/auth/VerifyEmailView.kt | 12 ++++----- .../ui/screens/book/AddBookView.kt | 10 +++---- .../ui/screens/book/BookListView.kt | 10 +++---- .../readability/ui/screens/book/BookScreen.kt | 10 +++---- .../ui/screens/settings/AboutView.kt | 2 +- .../ui/screens/settings/AccountView.kt | 8 +++--- .../ui/screens/settings/ChangePasswordView.kt | 12 ++++----- .../ui/screens/settings/SettingsScreen.kt | 10 +++---- .../ui/screens/settings/SettingsView.kt | 8 +++--- .../ui/screens/settings/ViewerView.kt | 14 +++++----- .../ui/screens/viewer/QuizReportView.kt | 8 +++--- .../readability/ui/screens/viewer/QuizView.kt | 24 ++++++++--------- .../ui/screens/viewer/SummaryView.kt | 4 +-- .../ui/screens/viewer/ViewerScreen.kt | 14 +++++----- .../ui/screens/viewer/ViewerView.kt | 26 +++++++++---------- .../readability/ui/theme/Color.kt | 2 +- .../readability/ui/theme/Theme.kt | 2 +- .../readability/ui/theme/Type.kt | 4 +-- .../ui/viewmodels/AddBookViewModel.kt | 6 ++--- .../ui/viewmodels/BookListViewModel.kt | 8 +++--- .../ui/viewmodels/NetworkStatusViewModel.kt | 4 +-- .../ui/viewmodels/QuizViewModel.kt | 6 ++--- .../ui/viewmodels/SettingViewModel.kt | 8 +++--- .../ui/viewmodels/SummaryViewModel.kt | 10 +++---- .../ui/viewmodels/UserViewModel.kt | 8 +++--- .../ui/viewmodels/ViewerViewModel.kt | 10 +++---- .../ui/models/ai/QuizRemoteDataSourceTest.kt | 8 +++--- .../ui/models/ai/QuizRepositoryTest.kt | 16 ++++++------ .../models/ai/SummaryRemoteDataSourceTest.kt | 6 ++--- .../ui/models/ai/SummaryRepositoryTest.kt | 12 ++++----- .../ui/models/book/BookFileDataSourceTest.kt | 6 ++--- .../models/book/BookRemoteDataSourceTest.kt | 14 +++++----- .../ui/models/book/BookRepositoryTest.kt | 22 ++++++++-------- .../network/NetworkStatusDataSourceTest.kt | 4 +-- .../network/NetworkStatusRepositoryTest.kt | 6 ++--- .../models/user/UserRemoteDataSourceTest.kt | 16 ++++++------ .../ui/models/user/UserRepositoryTest.kt | 18 ++++++------- .../ui/models/viewer/FontDataSourceTest.kt | 6 ++--- .../models/viewer/PageSplitRepositoryTest.kt | 18 ++++++------- .../ui/models/viewer/SettingRepositoryTest.kt | 8 +++--- 88 files changed, 369 insertions(+), 349 deletions(-) create mode 100644 frontend/app/release/output-metadata.json rename frontend/app/src/androidTest/java/com/{example => snu}/readability/AuthDBTest.kt (96%) rename frontend/app/src/androidTest/java/com/{example => snu}/readability/BookDBTest.kt (96%) rename frontend/app/src/androidTest/java/com/{example => snu}/readability/HiltTestRunner.kt (93%) rename frontend/app/src/androidTest/java/com/{example => snu}/readability/screens/AuthScreenTest.kt (97%) rename frontend/app/src/androidTest/java/com/{example => snu}/readability/screens/BookScreenTest.kt (94%) rename frontend/app/src/androidTest/java/com/{example => snu}/readability/screens/SettingScreenTest.kt (96%) rename frontend/app/src/androidTest/java/com/{example => snu}/readability/screens/ViewerScreenTest.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/MainActivity.kt (91%) rename frontend/app/src/main/java/com/{example => snu}/readability/ReadabilityApplication.kt (80%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/NetworkStatusDataSource.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/NetworkStatusRepository.kt (90%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/Utils.kt (89%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/ai/QuizRemoteDataSource.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/ai/QuizRepository.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/ai/SummaryRemoteDataSource.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/ai/SummaryRepository.kt (90%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/book/BookDatabase.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/book/BookFileDataSource.kt (99%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/book/BookRemoteDataSource.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/book/BookRepository.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/user/UserDatabase.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/user/UserException.kt (87%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/user/UserRemoteDataSource.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/user/UserRepository.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/viewer/FontDataSource.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/viewer/PageSplitDataSource.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/viewer/PageSplitRepository.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/viewer/SettingDatabase.kt (92%) rename frontend/app/src/main/java/com/{example => snu}/readability/data/viewer/SettingRepository.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/animation/AnimateImeDp.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/animation/FadeThroughTransition.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/animation/SharedAxisTransition.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/animation/Values.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/components/BottomSheetView.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/components/PasswordTextField.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/components/RoundedRectButton.kt (99%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/components/SettingTitle.kt (90%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/Screen.kt (90%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/AuthScreen.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/EmailView.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/ForgotPasswordView.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/IntroView.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/ResetPasswordView.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/SignInView.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/SignUpView.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/auth/VerifyEmailView.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/book/AddBookView.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/book/BookListView.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/book/BookScreen.kt (89%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/settings/AboutView.kt (79%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/settings/AccountView.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/settings/ChangePasswordView.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/settings/SettingsScreen.kt (93%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/settings/SettingsView.kt (95%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/settings/ViewerView.kt (97%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/viewer/QuizReportView.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/viewer/QuizView.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/viewer/SummaryView.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/viewer/ViewerScreen.kt (94%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/screens/viewer/ViewerView.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/theme/Color.kt (98%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/theme/Theme.kt (99%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/theme/Type.kt (96%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/AddBookViewModel.kt (66%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/BookListViewModel.kt (91%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/NetworkStatusViewModel.kt (79%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/QuizViewModel.kt (80%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/SettingViewModel.kt (84%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/SummaryViewModel.kt (74%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/UserViewModel.kt (90%) rename frontend/app/src/main/java/com/{example => snu}/readability/ui/viewmodels/ViewerViewModel.kt (86%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/ai/QuizRemoteDataSourceTest.kt (96%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/ai/QuizRepositoryTest.kt (88%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt (96%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/ai/SummaryRepositoryTest.kt (88%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/book/BookFileDataSourceTest.kt (96%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/book/BookRemoteDataSourceTest.kt (96%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/book/BookRepositoryTest.kt (97%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/network/NetworkStatusDataSourceTest.kt (96%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/network/NetworkStatusRepositoryTest.kt (83%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/user/UserRemoteDataSourceTest.kt (94%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/user/UserRepositoryTest.kt (96%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/viewer/FontDataSourceTest.kt (92%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/viewer/PageSplitRepositoryTest.kt (88%) rename frontend/app/src/test/java/com/{example => snu}/readability/ui/models/viewer/SettingRepositoryTest.kt (91%) diff --git a/frontend/app/build.gradle.kts b/frontend/app/build.gradle.kts index 9f19a7c..df621bf 100644 --- a/frontend/app/build.gradle.kts +++ b/frontend/app/build.gradle.kts @@ -6,17 +6,17 @@ plugins { } android { - namespace = "com.example.readability" + namespace = "com.snu.readability" compileSdk = 34 defaultConfig { - applicationId = "com.example.readability" + applicationId = "com.snu.readability" minSdk = 24 targetSdk = 34 versionCode = 1 versionName = "1.0" - testInstrumentationRunner = "com.example.readability.HiltTestRunner" + testInstrumentationRunner = "com.snu.readability.HiltTestRunner" vectorDrawables { useSupportLibrary = true } diff --git a/frontend/app/release/output-metadata.json b/frontend/app/release/output-metadata.json new file mode 100644 index 0000000..dc90a1c --- /dev/null +++ b/frontend/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.snu.readability", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0", + "outputFile": "app-release.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/frontend/app/src/androidTest/java/com/example/readability/AuthDBTest.kt b/frontend/app/src/androidTest/java/com/snu/readability/AuthDBTest.kt similarity index 96% rename from frontend/app/src/androidTest/java/com/example/readability/AuthDBTest.kt rename to frontend/app/src/androidTest/java/com/snu/readability/AuthDBTest.kt index 663f592..b6df6d6 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/AuthDBTest.kt +++ b/frontend/app/src/androidTest/java/com/snu/readability/AuthDBTest.kt @@ -1,6 +1,6 @@ -package com.example.readability +package com.snu.readability import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.user.UserRepository import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import junit.framework.TestCase.assertEquals diff --git a/frontend/app/src/androidTest/java/com/example/readability/BookDBTest.kt b/frontend/app/src/androidTest/java/com/snu/readability/BookDBTest.kt similarity index 96% rename from frontend/app/src/androidTest/java/com/example/readability/BookDBTest.kt rename to frontend/app/src/androidTest/java/com/snu/readability/BookDBTest.kt index a7e4290..c06cfe8 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/BookDBTest.kt +++ b/frontend/app/src/androidTest/java/com/snu/readability/BookDBTest.kt @@ -1,12 +1,12 @@ -package com.example.readability +package com.snu.readability import android.graphics.Bitmap import android.graphics.BitmapFactory import androidx.compose.ui.graphics.asAndroidBitmap import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.example.readability.data.book.AddBookRequest -import com.example.readability.data.book.BookRepository -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.book.AddBookRequest +import com.snu.readability.data.book.BookRepository +import com.snu.readability.data.user.UserRepository import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import junit.framework.TestCase.assertTrue diff --git a/frontend/app/src/androidTest/java/com/example/readability/HiltTestRunner.kt b/frontend/app/src/androidTest/java/com/snu/readability/HiltTestRunner.kt similarity index 93% rename from frontend/app/src/androidTest/java/com/example/readability/HiltTestRunner.kt rename to frontend/app/src/androidTest/java/com/snu/readability/HiltTestRunner.kt index b76413a..b12e46e 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/HiltTestRunner.kt +++ b/frontend/app/src/androidTest/java/com/snu/readability/HiltTestRunner.kt @@ -1,4 +1,4 @@ -package com.example.readability +package com.snu.readability import android.app.Application import android.content.Context diff --git a/frontend/app/src/androidTest/java/com/example/readability/screens/AuthScreenTest.kt b/frontend/app/src/androidTest/java/com/snu/readability/screens/AuthScreenTest.kt similarity index 97% rename from frontend/app/src/androidTest/java/com/example/readability/screens/AuthScreenTest.kt rename to frontend/app/src/androidTest/java/com/snu/readability/screens/AuthScreenTest.kt index 3f45d32..ba45f92 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/screens/AuthScreenTest.kt +++ b/frontend/app/src/androidTest/java/com/snu/readability/screens/AuthScreenTest.kt @@ -1,4 +1,4 @@ -package com.example.readability.screens +package com.snu.readability.screens import androidx.activity.compose.setContent import androidx.compose.ui.platform.LocalContext @@ -19,13 +19,13 @@ import androidx.compose.ui.test.performTextInput import androidx.navigation.compose.ComposeNavigator import androidx.navigation.testing.TestNavHostController import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.example.readability.MainActivity -import com.example.readability.ui.screens.auth.AuthScreen -import com.example.readability.ui.screens.auth.EmailView -import com.example.readability.ui.screens.auth.IntroView -import com.example.readability.ui.screens.auth.SignInView -import com.example.readability.ui.screens.auth.SignUpView -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.MainActivity +import com.snu.readability.ui.screens.auth.AuthScreen +import com.snu.readability.ui.screens.auth.EmailView +import com.snu.readability.ui.screens.auth.IntroView +import com.snu.readability.ui.screens.auth.SignInView +import com.snu.readability.ui.screens.auth.SignUpView +import com.snu.readability.ui.theme.ReadabilityTheme import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Before diff --git a/frontend/app/src/androidTest/java/com/example/readability/screens/BookScreenTest.kt b/frontend/app/src/androidTest/java/com/snu/readability/screens/BookScreenTest.kt similarity index 94% rename from frontend/app/src/androidTest/java/com/example/readability/screens/BookScreenTest.kt rename to frontend/app/src/androidTest/java/com/snu/readability/screens/BookScreenTest.kt index d04bd50..9cfd2b0 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/screens/BookScreenTest.kt +++ b/frontend/app/src/androidTest/java/com/snu/readability/screens/BookScreenTest.kt @@ -1,16 +1,16 @@ -package com.example.readability.screens +package com.snu.readability.screens import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.example.readability.data.book.BookCardData -import com.example.readability.ui.screens.book.BookListView -import com.example.readability.ui.screens.book.BookScreen -import com.example.readability.ui.theme.ReadabilityTheme -import com.example.readability.ui.viewmodels.AddBookViewModel -import com.example.readability.ui.viewmodels.BookListViewModel +import com.snu.readability.data.book.BookCardData +import com.snu.readability.ui.screens.book.BookListView +import com.snu.readability.ui.screens.book.BookScreen +import com.snu.readability.ui.theme.ReadabilityTheme +import com.snu.readability.ui.viewmodels.AddBookViewModel +import com.snu.readability.ui.viewmodels.BookListViewModel import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every diff --git a/frontend/app/src/androidTest/java/com/example/readability/screens/SettingScreenTest.kt b/frontend/app/src/androidTest/java/com/snu/readability/screens/SettingScreenTest.kt similarity index 96% rename from frontend/app/src/androidTest/java/com/example/readability/screens/SettingScreenTest.kt rename to frontend/app/src/androidTest/java/com/snu/readability/screens/SettingScreenTest.kt index a25ef06..0d5887d 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/screens/SettingScreenTest.kt +++ b/frontend/app/src/androidTest/java/com/snu/readability/screens/SettingScreenTest.kt @@ -1,4 +1,4 @@ -package com.example.readability.screens +package com.snu.readability.screens import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createComposeRule @@ -8,11 +8,11 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTextInput import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.example.readability.data.viewer.ViewerStyle -import com.example.readability.ui.screens.settings.AccountView -import com.example.readability.ui.screens.settings.ChangePasswordView -import com.example.readability.ui.screens.settings.SettingsView -import com.example.readability.ui.screens.settings.ViewerView +import com.snu.readability.data.viewer.ViewerStyle +import com.snu.readability.ui.screens.settings.AccountView +import com.snu.readability.ui.screens.settings.ChangePasswordView +import com.snu.readability.ui.screens.settings.SettingsView +import com.snu.readability.ui.screens.settings.ViewerView import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith diff --git a/frontend/app/src/androidTest/java/com/example/readability/screens/ViewerScreenTest.kt b/frontend/app/src/androidTest/java/com/snu/readability/screens/ViewerScreenTest.kt similarity index 96% rename from frontend/app/src/androidTest/java/com/example/readability/screens/ViewerScreenTest.kt rename to frontend/app/src/androidTest/java/com/snu/readability/screens/ViewerScreenTest.kt index 5dea747..1a2afca 100644 --- a/frontend/app/src/androidTest/java/com/example/readability/screens/ViewerScreenTest.kt +++ b/frontend/app/src/androidTest/java/com/snu/readability/screens/ViewerScreenTest.kt @@ -1,4 +1,4 @@ -package com.example.readability.screens +package com.snu.readability.screens import android.graphics.Typeface import androidx.compose.ui.geometry.Offset @@ -17,16 +17,16 @@ import androidx.compose.ui.test.swipeLeft import androidx.compose.ui.test.swipeRight import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.example.readability.data.ai.Quiz -import com.example.readability.data.ai.QuizLoadState -import com.example.readability.data.book.Book -import com.example.readability.data.viewer.PageSplitData -import com.example.readability.data.viewer.ViewerStyle -import com.example.readability.data.viewer.getPageIndex -import com.example.readability.ui.screens.viewer.QuizReportView -import com.example.readability.ui.screens.viewer.QuizView -import com.example.readability.ui.screens.viewer.SummaryView -import com.example.readability.ui.screens.viewer.ViewerView +import com.snu.readability.data.ai.Quiz +import com.snu.readability.data.ai.QuizLoadState +import com.snu.readability.data.book.Book +import com.snu.readability.data.viewer.PageSplitData +import com.snu.readability.data.viewer.ViewerStyle +import com.snu.readability.data.viewer.getPageIndex +import com.snu.readability.ui.screens.viewer.QuizReportView +import com.snu.readability.ui.screens.viewer.QuizView +import com.snu.readability.ui.screens.viewer.SummaryView +import com.snu.readability.ui.screens.viewer.ViewerView import org.junit.BeforeClass import org.junit.Rule import org.junit.Test diff --git a/frontend/app/src/main/cpp/readability.cpp b/frontend/app/src/main/cpp/readability.cpp index 4214172..4abc7fb 100644 --- a/frontend/app/src/main/cpp/readability.cpp +++ b/frontend/app/src/main/cpp/readability.cpp @@ -2,7 +2,7 @@ #include #include -extern "C" JNIEXPORT jintArray JNICALL Java_com_example_readability_data_viewer_PageSplitDataSource_splitPageNative( +extern "C" JNIEXPORT jintArray JNICALL Java_com_snu_readability_data_viewer_PageSplitDataSource_splitPageNative( JNIEnv *env, jobject thiz, jstring content, jfloatArray charWidths, jfloat lineHeight, jfloat width, jfloat height, jfloat paragraphSpacing) { @@ -128,7 +128,7 @@ extern "C" JNIEXPORT jintArray JNICALL Java_com_example_readability_data_viewer_ return result; } -extern "C" JNIEXPORT void JNICALL Java_com_example_readability_data_viewer_PageSplitDataSource_drawPageNative( +extern "C" JNIEXPORT void JNICALL Java_com_snu_readability_data_viewer_PageSplitDataSource_drawPageNative( JNIEnv *env, jobject thiz, jstring content, jfloatArray charWidths, jfloat lineHeight, jfloat offset, jfloat width, jfloat paragraphSpacing, jobject textDrawer) { // retrive drawText method in TextDrawer @@ -237,4 +237,4 @@ extern "C" JNIEXPORT void JNICALL Java_com_example_readability_data_viewer_PageS // cleanup env->ReleaseStringChars(content, contentChars); env->ReleaseFloatArrayElements(charWidths, charWidthsPointer, 0); -} \ No newline at end of file +} diff --git a/frontend/app/src/main/java/com/example/readability/MainActivity.kt b/frontend/app/src/main/java/com/snu/readability/MainActivity.kt similarity index 91% rename from frontend/app/src/main/java/com/example/readability/MainActivity.kt rename to frontend/app/src/main/java/com/snu/readability/MainActivity.kt index 4af7450..dabbf33 100644 --- a/frontend/app/src/main/java/com/example/readability/MainActivity.kt +++ b/frontend/app/src/main/java/com/snu/readability/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.readability +package com.snu.readability import android.annotation.SuppressLint import android.os.Bundle @@ -15,10 +15,10 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.staticCompositionLocalOf import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat -import com.example.readability.data.viewer.FontDataSource -import com.example.readability.ui.screens.Screen -import com.example.readability.ui.theme.ReadabilityTheme -import com.example.readability.ui.viewmodels.UserViewModel +import com.snu.readability.data.viewer.FontDataSource +import com.snu.readability.ui.screens.Screen +import com.snu.readability.ui.theme.ReadabilityTheme +import com.snu.readability.ui.viewmodels.UserViewModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/frontend/app/src/main/java/com/example/readability/ReadabilityApplication.kt b/frontend/app/src/main/java/com/snu/readability/ReadabilityApplication.kt similarity index 80% rename from frontend/app/src/main/java/com/example/readability/ReadabilityApplication.kt rename to frontend/app/src/main/java/com/snu/readability/ReadabilityApplication.kt index 4bb4ca6..ee7c6a2 100644 --- a/frontend/app/src/main/java/com/example/readability/ReadabilityApplication.kt +++ b/frontend/app/src/main/java/com/snu/readability/ReadabilityApplication.kt @@ -1,4 +1,4 @@ -package com.example.readability +package com.snu.readability import android.app.Application import dagger.hilt.android.HiltAndroidApp diff --git a/frontend/app/src/main/java/com/example/readability/data/NetworkStatusDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/NetworkStatusDataSource.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/data/NetworkStatusDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/NetworkStatusDataSource.kt index 1a8e322..8d83439 100644 --- a/frontend/app/src/main/java/com/example/readability/data/NetworkStatusDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/NetworkStatusDataSource.kt @@ -1,4 +1,4 @@ -package com.example.readability.data +package com.snu.readability.data import android.content.Context import android.net.ConnectivityManager diff --git a/frontend/app/src/main/java/com/example/readability/data/NetworkStatusRepository.kt b/frontend/app/src/main/java/com/snu/readability/data/NetworkStatusRepository.kt similarity index 90% rename from frontend/app/src/main/java/com/example/readability/data/NetworkStatusRepository.kt rename to frontend/app/src/main/java/com/snu/readability/data/NetworkStatusRepository.kt index 98123f1..b8ad68a 100644 --- a/frontend/app/src/main/java/com/example/readability/data/NetworkStatusRepository.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/NetworkStatusRepository.kt @@ -1,4 +1,4 @@ -package com.example.readability.data +package com.snu.readability.data import javax.inject.Inject import javax.inject.Singleton diff --git a/frontend/app/src/main/java/com/example/readability/data/Utils.kt b/frontend/app/src/main/java/com/snu/readability/data/Utils.kt similarity index 89% rename from frontend/app/src/main/java/com/example/readability/data/Utils.kt rename to frontend/app/src/main/java/com/snu/readability/data/Utils.kt index 47ee54b..fb9d588 100644 --- a/frontend/app/src/main/java/com/example/readability/data/Utils.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/Utils.kt @@ -1,4 +1,4 @@ -package com.example.readability.data +package com.snu.readability.data import okhttp3.ResponseBody import org.json.JSONObject diff --git a/frontend/app/src/main/java/com/example/readability/data/ai/QuizRemoteDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/ai/QuizRemoteDataSource.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/data/ai/QuizRemoteDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/ai/QuizRemoteDataSource.kt index 8f370e3..914600e 100644 --- a/frontend/app/src/main/java/com/example/readability/data/ai/QuizRemoteDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/ai/QuizRemoteDataSource.kt @@ -1,6 +1,6 @@ -package com.example.readability.data.ai +package com.snu.readability.data.ai -import com.example.readability.data.parseErrorBody +import com.snu.readability.data.parseErrorBody import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/frontend/app/src/main/java/com/example/readability/data/ai/QuizRepository.kt b/frontend/app/src/main/java/com/snu/readability/data/ai/QuizRepository.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/data/ai/QuizRepository.kt rename to frontend/app/src/main/java/com/snu/readability/data/ai/QuizRepository.kt index 527c651..ed452db 100644 --- a/frontend/app/src/main/java/com/example/readability/data/ai/QuizRepository.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/ai/QuizRepository.kt @@ -1,8 +1,8 @@ -package com.example.readability.data.ai +package com.snu.readability.data.ai -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.user.UserNotSignedInException -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.NetworkStatusRepository +import com.snu.readability.data.user.UserNotSignedInException +import com.snu.readability.data.user.UserRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/frontend/app/src/main/java/com/example/readability/data/ai/SummaryRemoteDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/ai/SummaryRemoteDataSource.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/data/ai/SummaryRemoteDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/ai/SummaryRemoteDataSource.kt index 5eb4aa5..73a50c4 100644 --- a/frontend/app/src/main/java/com/example/readability/data/ai/SummaryRemoteDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/ai/SummaryRemoteDataSource.kt @@ -1,6 +1,6 @@ -package com.example.readability.data.ai +package com.snu.readability.data.ai -import com.example.readability.data.parseErrorBody +import com.snu.readability.data.parseErrorBody import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/frontend/app/src/main/java/com/example/readability/data/ai/SummaryRepository.kt b/frontend/app/src/main/java/com/snu/readability/data/ai/SummaryRepository.kt similarity index 90% rename from frontend/app/src/main/java/com/example/readability/data/ai/SummaryRepository.kt rename to frontend/app/src/main/java/com/snu/readability/data/ai/SummaryRepository.kt index c204873..67c4ae7 100644 --- a/frontend/app/src/main/java/com/example/readability/data/ai/SummaryRepository.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/ai/SummaryRepository.kt @@ -1,8 +1,8 @@ -package com.example.readability.data.ai +package com.snu.readability.data.ai -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.user.UserNotSignedInException -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.NetworkStatusRepository +import com.snu.readability.data.user.UserNotSignedInException +import com.snu.readability.data.user.UserRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/frontend/app/src/main/java/com/example/readability/data/book/BookDatabase.kt b/frontend/app/src/main/java/com/snu/readability/data/book/BookDatabase.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/data/book/BookDatabase.kt rename to frontend/app/src/main/java/com/snu/readability/data/book/BookDatabase.kt index eb57a2b..54559c5 100644 --- a/frontend/app/src/main/java/com/example/readability/data/book/BookDatabase.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/book/BookDatabase.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.book +package com.snu.readability.data.book import android.content.Context import androidx.room.ColumnInfo diff --git a/frontend/app/src/main/java/com/example/readability/data/book/BookFileDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/book/BookFileDataSource.kt similarity index 99% rename from frontend/app/src/main/java/com/example/readability/data/book/BookFileDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/book/BookFileDataSource.kt index 72e0f6c..d9637a3 100644 --- a/frontend/app/src/main/java/com/example/readability/data/book/BookFileDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/book/BookFileDataSource.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.book +package com.snu.readability.data.book import android.content.Context import android.graphics.Bitmap diff --git a/frontend/app/src/main/java/com/example/readability/data/book/BookRemoteDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/book/BookRemoteDataSource.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/data/book/BookRemoteDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/book/BookRemoteDataSource.kt index 6315b72..ebdbe6a 100644 --- a/frontend/app/src/main/java/com/example/readability/data/book/BookRemoteDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/book/BookRemoteDataSource.kt @@ -1,9 +1,9 @@ -package com.example.readability.data.book +package com.snu.readability.data.book import android.graphics.BitmapFactory import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap -import com.example.readability.data.parseErrorBody +import com.snu.readability.data.parseErrorBody import com.google.gson.annotations.SerializedName import dagger.Module import dagger.Provides diff --git a/frontend/app/src/main/java/com/example/readability/data/book/BookRepository.kt b/frontend/app/src/main/java/com/snu/readability/data/book/BookRepository.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/data/book/BookRepository.kt rename to frontend/app/src/main/java/com/snu/readability/data/book/BookRepository.kt index 9704931..7689545 100644 --- a/frontend/app/src/main/java/com/example/readability/data/book/BookRepository.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/book/BookRepository.kt @@ -1,9 +1,9 @@ -package com.example.readability.data.book +package com.snu.readability.data.book import androidx.compose.ui.graphics.ImageBitmap -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.user.UserNotSignedInException -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.NetworkStatusRepository +import com.snu.readability.data.user.UserNotSignedInException +import com.snu.readability.data.user.UserRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserDatabase.kt b/frontend/app/src/main/java/com/snu/readability/data/user/UserDatabase.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/data/user/UserDatabase.kt rename to frontend/app/src/main/java/com/snu/readability/data/user/UserDatabase.kt index 46983b1..1094150 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserDatabase.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/user/UserDatabase.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.user +package com.snu.readability.data.user import android.content.Context import androidx.room.ColumnInfo diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserException.kt b/frontend/app/src/main/java/com/snu/readability/data/user/UserException.kt similarity index 87% rename from frontend/app/src/main/java/com/example/readability/data/user/UserException.kt rename to frontend/app/src/main/java/com/snu/readability/data/user/UserException.kt index d076deb..1cf89a1 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserException.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/user/UserException.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.user +package com.snu.readability.data.user // top class for all user exceptions open class UserException( diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserRemoteDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/user/UserRemoteDataSource.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/data/user/UserRemoteDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/user/UserRemoteDataSource.kt index 47d69ca..42b47b2 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserRemoteDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/user/UserRemoteDataSource.kt @@ -1,6 +1,6 @@ -package com.example.readability.data.user +package com.snu.readability.data.user -import com.example.readability.data.parseErrorBody +import com.snu.readability.data.parseErrorBody import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt b/frontend/app/src/main/java/com/snu/readability/data/user/UserRepository.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt rename to frontend/app/src/main/java/com/snu/readability/data/user/UserRepository.kt index 981a0b0..5c6090e 100644 --- a/frontend/app/src/main/java/com/example/readability/data/user/UserRepository.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/user/UserRepository.kt @@ -1,6 +1,6 @@ -package com.example.readability.data.user +package com.snu.readability.data.user -import com.example.readability.data.NetworkStatusRepository +import com.snu.readability.data.NetworkStatusRepository import kotlinx.coroutines.flow.firstOrNull import java.util.concurrent.TimeUnit import javax.inject.Inject diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/viewer/FontDataSource.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/viewer/FontDataSource.kt index ecc0b70..751f273 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/FontDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/viewer/FontDataSource.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.viewer +package com.snu.readability.data.viewer import android.content.Context import android.content.res.Resources @@ -6,7 +6,7 @@ import android.graphics.Typeface import android.text.TextPaint import android.util.Log import androidx.core.content.res.ResourcesCompat -import com.example.readability.R +import com.snu.readability.R import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import javax.inject.Inject diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/PageSplitDataSource.kt b/frontend/app/src/main/java/com/snu/readability/data/viewer/PageSplitDataSource.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/data/viewer/PageSplitDataSource.kt rename to frontend/app/src/main/java/com/snu/readability/data/viewer/PageSplitDataSource.kt index d61d461..a64fdc0 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/PageSplitDataSource.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/viewer/PageSplitDataSource.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.viewer +package com.snu.readability.data.viewer import android.graphics.Canvas import android.graphics.Paint diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/PageSplitRepository.kt b/frontend/app/src/main/java/com/snu/readability/data/viewer/PageSplitRepository.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/data/viewer/PageSplitRepository.kt rename to frontend/app/src/main/java/com/snu/readability/data/viewer/PageSplitRepository.kt index e7f8c8b..b9cb350 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/PageSplitRepository.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/viewer/PageSplitRepository.kt @@ -1,7 +1,7 @@ -package com.example.readability.data.viewer +package com.snu.readability.data.viewer import androidx.compose.ui.graphics.NativeCanvas -import com.example.readability.data.book.BookRepository +import com.snu.readability.data.book.BookRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.runBlocking diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt b/frontend/app/src/main/java/com/snu/readability/data/viewer/SettingDatabase.kt similarity index 92% rename from frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt rename to frontend/app/src/main/java/com/snu/readability/data/viewer/SettingDatabase.kt index 8cb2acb..686e567 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingDatabase.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/viewer/SettingDatabase.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.viewer +package com.snu.readability.data.viewer import android.content.Context import androidx.compose.ui.graphics.toArgb @@ -12,10 +12,10 @@ import androidx.room.Query import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.Update -import com.example.readability.ui.theme.md_theme_dark_background -import com.example.readability.ui.theme.md_theme_dark_onBackground -import com.example.readability.ui.theme.md_theme_light_background -import com.example.readability.ui.theme.md_theme_light_onBackground +import com.snu.readability.ui.theme.md_theme_dark_background +import com.snu.readability.ui.theme.md_theme_dark_onBackground +import com.snu.readability.ui.theme.md_theme_light_background +import com.snu.readability.ui.theme.md_theme_light_onBackground import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingRepository.kt b/frontend/app/src/main/java/com/snu/readability/data/viewer/SettingRepository.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/data/viewer/SettingRepository.kt rename to frontend/app/src/main/java/com/snu/readability/data/viewer/SettingRepository.kt index d69d8d7..3b96cac 100644 --- a/frontend/app/src/main/java/com/example/readability/data/viewer/SettingRepository.kt +++ b/frontend/app/src/main/java/com/snu/readability/data/viewer/SettingRepository.kt @@ -1,4 +1,4 @@ -package com.example.readability.data.viewer +package com.snu.readability.data.viewer import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/animation/AnimateImeDp.kt b/frontend/app/src/main/java/com/snu/readability/ui/animation/AnimateImeDp.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/ui/animation/AnimateImeDp.kt rename to frontend/app/src/main/java/com/snu/readability/ui/animation/AnimateImeDp.kt index 757a924..ab50bb0 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/animation/AnimateImeDp.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/animation/AnimateImeDp.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.animation +package com.snu.readability.ui.animation import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.layout.ExperimentalLayoutApi diff --git a/frontend/app/src/main/java/com/example/readability/ui/animation/FadeThroughTransition.kt b/frontend/app/src/main/java/com/snu/readability/ui/animation/FadeThroughTransition.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/animation/FadeThroughTransition.kt rename to frontend/app/src/main/java/com/snu/readability/ui/animation/FadeThroughTransition.kt index 64c434a..a440c49 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/animation/FadeThroughTransition.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/animation/FadeThroughTransition.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.animation +package com.snu.readability.ui.animation import androidx.compose.animation.AnimatedContentScope import androidx.compose.animation.core.tween diff --git a/frontend/app/src/main/java/com/example/readability/ui/animation/SharedAxisTransition.kt b/frontend/app/src/main/java/com/snu/readability/ui/animation/SharedAxisTransition.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/animation/SharedAxisTransition.kt rename to frontend/app/src/main/java/com/snu/readability/ui/animation/SharedAxisTransition.kt index 4d4f023..b42bbd4 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/animation/SharedAxisTransition.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/animation/SharedAxisTransition.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.animation +package com.snu.readability.ui.animation import android.content.res.Resources import androidx.compose.animation.AnimatedContentScope diff --git a/frontend/app/src/main/java/com/example/readability/ui/animation/Values.kt b/frontend/app/src/main/java/com/snu/readability/ui/animation/Values.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/ui/animation/Values.kt rename to frontend/app/src/main/java/com/snu/readability/ui/animation/Values.kt index 9c8bc34..113e7bf 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/animation/Values.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/animation/Values.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.animation +package com.snu.readability.ui.animation import android.graphics.Path import android.view.animation.PathInterpolator diff --git a/frontend/app/src/main/java/com/example/readability/ui/components/BottomSheetView.kt b/frontend/app/src/main/java/com/snu/readability/ui/components/BottomSheetView.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/components/BottomSheetView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/components/BottomSheetView.kt index 0b8a648..963df37 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/components/BottomSheetView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/components/BottomSheetView.kt @@ -41,9 +41,9 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.data.book.BookCardData -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.data.book.BookCardData +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.launch import kotlin.math.roundToInt diff --git a/frontend/app/src/main/java/com/example/readability/ui/components/PasswordTextField.kt b/frontend/app/src/main/java/com/snu/readability/ui/components/PasswordTextField.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/ui/components/PasswordTextField.kt rename to frontend/app/src/main/java/com/snu/readability/ui/components/PasswordTextField.kt index 9fa35f8..2402d70 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/components/PasswordTextField.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/components/PasswordTextField.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.components +package com.snu.readability.ui.components import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -16,7 +16,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation -import com.example.readability.R +import com.snu.readability.R @Composable fun PasswordTextField( diff --git a/frontend/app/src/main/java/com/example/readability/ui/components/RoundedRectButton.kt b/frontend/app/src/main/java/com/snu/readability/ui/components/RoundedRectButton.kt similarity index 99% rename from frontend/app/src/main/java/com/example/readability/ui/components/RoundedRectButton.kt rename to frontend/app/src/main/java/com/snu/readability/ui/components/RoundedRectButton.kt index 0d7df3d..9dfa21a 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/components/RoundedRectButton.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/components/RoundedRectButton.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.components +package com.snu.readability.ui.components import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.BorderStroke diff --git a/frontend/app/src/main/java/com/example/readability/ui/components/SettingTitle.kt b/frontend/app/src/main/java/com/snu/readability/ui/components/SettingTitle.kt similarity index 90% rename from frontend/app/src/main/java/com/example/readability/ui/components/SettingTitle.kt rename to frontend/app/src/main/java/com/snu/readability/ui/components/SettingTitle.kt index 70d8dcb..9315bb6 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/components/SettingTitle.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/components/SettingTitle.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.components +package com.snu.readability.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column @@ -13,8 +13,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.ui.theme.GabaritoMedium -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.ui.theme.GabaritoMedium +import com.snu.readability.ui.theme.ReadabilityTheme @Composable @Preview diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/Screen.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/Screen.kt similarity index 90% rename from frontend/app/src/main/java/com/example/readability/ui/screens/Screen.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/Screen.kt index 993a0d2..a27075c 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/Screen.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/Screen.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens +package com.snu.readability.ui.screens import android.os.Build import android.view.View @@ -14,13 +14,13 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument -import com.example.readability.ui.animation.composableFadeThrough -import com.example.readability.ui.screens.auth.AuthScreen -import com.example.readability.ui.screens.book.BookScreen -import com.example.readability.ui.screens.settings.SettingsScreen -import com.example.readability.ui.screens.settings.SettingsScreens -import com.example.readability.ui.screens.viewer.ViewerScreen -import com.example.readability.ui.screens.viewer.findActivity +import com.snu.readability.ui.animation.composableFadeThrough +import com.snu.readability.ui.screens.auth.AuthScreen +import com.snu.readability.ui.screens.book.BookScreen +import com.snu.readability.ui.screens.settings.SettingsScreen +import com.snu.readability.ui.screens.settings.SettingsScreens +import com.snu.readability.ui.screens.viewer.ViewerScreen +import com.snu.readability.ui.screens.viewer.findActivity sealed class Screens(val route: String) { object Auth : Screens("auth") diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/AuthScreen.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/AuthScreen.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/AuthScreen.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/AuthScreen.kt index 266dab2..c306e31 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/AuthScreen.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/AuthScreen.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -10,9 +10,9 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument -import com.example.readability.ui.animation.SharedAxis -import com.example.readability.ui.animation.composableSharedAxis -import com.example.readability.ui.viewmodels.UserViewModel +import com.snu.readability.ui.animation.SharedAxis +import com.snu.readability.ui.animation.composableSharedAxis +import com.snu.readability.ui.viewmodels.UserViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/EmailView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/EmailView.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/EmailView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/EmailView.kt index 7ab5ca5..5c16e7f 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/EmailView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/EmailView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -35,10 +35,10 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.ui.animation.animateImeDp -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.ui.animation.animateImeDp +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme @Composable @Preview(device = "id:pixel_5") diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/ForgotPasswordView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/ForgotPasswordView.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/ForgotPasswordView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/ForgotPasswordView.kt index 5dc9631..8313aea 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/ForgotPasswordView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/ForgotPasswordView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -38,10 +38,10 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.ui.animation.animateImeDp -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.ui.animation.animateImeDp +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/IntroView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/IntroView.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/IntroView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/IntroView.kt index 3e3581a..195e053 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/IntroView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/IntroView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween @@ -44,11 +44,11 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.readability.R -import com.example.readability.ui.animation.DURATION_EMPHASIZED -import com.example.readability.ui.animation.EASING_EMPHASIZED -import com.example.readability.ui.theme.Gabarito -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.ui.animation.DURATION_EMPHASIZED +import com.snu.readability.ui.animation.EASING_EMPHASIZED +import com.snu.readability.ui.theme.Gabarito +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.delay @Composable diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/ResetPasswordView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/ResetPasswordView.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/ResetPasswordView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/ResetPasswordView.kt index f548818..71951d3 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/ResetPasswordView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/ResetPasswordView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -34,10 +34,10 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.ui.animation.animateImeDp -import com.example.readability.ui.components.PasswordTextField -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.ui.animation.animateImeDp +import com.snu.readability.ui.components.PasswordTextField +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/SignInView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/SignInView.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/SignInView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/SignInView.kt index c924204..9928e54 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/SignInView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/SignInView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import android.widget.Toast import androidx.compose.foundation.layout.Column @@ -40,11 +40,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.ui.animation.animateImeDp -import com.example.readability.ui.components.PasswordTextField -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.ui.animation.animateImeDp +import com.snu.readability.ui.components.PasswordTextField +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/SignUpView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/SignUpView.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/SignUpView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/SignUpView.kt index 5e3a3c2..6e3bd73 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/SignUpView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/SignUpView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import android.widget.Toast import androidx.compose.foundation.layout.Arrangement @@ -41,11 +41,11 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.ui.animation.animateImeDp -import com.example.readability.ui.components.PasswordTextField -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.ui.animation.animateImeDp +import com.snu.readability.ui.components.PasswordTextField +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/VerifyEmailView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/VerifyEmailView.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/auth/VerifyEmailView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/auth/VerifyEmailView.kt index 5b2e29d..3053d6f 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/auth/VerifyEmailView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/auth/VerifyEmailView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.auth +package com.snu.readability.ui.screens.auth import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -39,11 +39,11 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.LocalSnackbarHost -import com.example.readability.R -import com.example.readability.ui.animation.animateImeDp -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.LocalSnackbarHost +import com.snu.readability.R +import com.snu.readability.ui.animation.animateImeDp +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/book/AddBookView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/book/AddBookView.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/screens/book/AddBookView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/book/AddBookView.kt index d784062..c0827f0 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/book/AddBookView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/book/AddBookView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.book +package com.snu.readability.ui.screens.book import android.content.ContentResolver import android.graphics.Bitmap @@ -49,10 +49,10 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.data.book.AddBookRequest -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.data.book.AddBookRequest +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.launch import java.io.ByteArrayOutputStream diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/book/BookListView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/book/BookListView.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/screens/book/BookListView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/book/BookListView.kt index a5d51dc..ce582b6 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/book/BookListView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/book/BookListView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.book +package com.snu.readability.ui.screens.book import BottomSheet import android.widget.Toast @@ -59,10 +59,10 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.readability.R -import com.example.readability.data.book.BookCardData -import com.example.readability.ui.theme.Gabarito -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.data.book.BookCardData +import com.snu.readability.ui.theme.Gabarito +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.math.roundToInt diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/book/BookScreen.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/book/BookScreen.kt similarity index 89% rename from frontend/app/src/main/java/com/example/readability/ui/screens/book/BookScreen.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/book/BookScreen.kt index c7de9ac..54498ff 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/book/BookScreen.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/book/BookScreen.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.book +package com.snu.readability.ui.screens.book import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -6,10 +6,10 @@ import androidx.compose.runtime.getValue import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController -import com.example.readability.ui.animation.SharedAxis -import com.example.readability.ui.animation.composableSharedAxis -import com.example.readability.ui.viewmodels.AddBookViewModel -import com.example.readability.ui.viewmodels.BookListViewModel +import com.snu.readability.ui.animation.SharedAxis +import com.snu.readability.ui.animation.composableSharedAxis +import com.snu.readability.ui.viewmodels.AddBookViewModel +import com.snu.readability.ui.viewmodels.BookListViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/AboutView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/AboutView.kt similarity index 79% rename from frontend/app/src/main/java/com/example/readability/ui/screens/settings/AboutView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/settings/AboutView.kt index be3bb10..1cc0b26 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/AboutView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/AboutView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.settings +package com.snu.readability.ui.screens.settings import androidx.compose.runtime.Composable diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/AccountView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/AccountView.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/screens/settings/AccountView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/settings/AccountView.kt index 04aa1d0..c96cde3 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/AccountView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/AccountView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.settings +package com.snu.readability.ui.screens.settings import android.widget.Toast import androidx.compose.foundation.clickable @@ -42,9 +42,9 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.ui.components.SettingTitle -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.ui.components.SettingTitle +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.launch @Composable diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ChangePasswordView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/ChangePasswordView.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/settings/ChangePasswordView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/settings/ChangePasswordView.kt index 54bc5a0..e61bb1b 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ChangePasswordView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/ChangePasswordView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.settings +package com.snu.readability.ui.screens.settings import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -35,11 +35,11 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.LocalSnackbarHost -import com.example.readability.ui.animation.animateImeDp -import com.example.readability.ui.components.PasswordTextField -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.LocalSnackbarHost +import com.snu.readability.ui.animation.animateImeDp +import com.snu.readability.ui.components.PasswordTextField +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/SettingsScreen.kt similarity index 93% rename from frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/settings/SettingsScreen.kt index d960482..7bbc962 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsScreen.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/SettingsScreen.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.settings +package com.snu.readability.ui.screens.settings import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable @@ -7,10 +7,10 @@ import androidx.compose.runtime.getValue import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController -import com.example.readability.ui.animation.SharedAxis -import com.example.readability.ui.animation.composableSharedAxis -import com.example.readability.ui.viewmodels.SettingViewModel -import com.example.readability.ui.viewmodels.UserViewModel +import com.snu.readability.ui.animation.SharedAxis +import com.snu.readability.ui.animation.composableSharedAxis +import com.snu.readability.ui.viewmodels.SettingViewModel +import com.snu.readability.ui.viewmodels.UserViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/SettingsView.kt similarity index 95% rename from frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/settings/SettingsView.kt index 6e941b3..9642702 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/SettingsView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/SettingsView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.settings +package com.snu.readability.ui.screens.settings import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -24,9 +24,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.ui.components.SettingTitle -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.ui.components.SettingTitle +import com.snu.readability.ui.theme.ReadabilityTheme @Composable @Preview(showBackground = true, device = "id:pixel_5") diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/ViewerView.kt similarity index 97% rename from frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/settings/ViewerView.kt index a583ade..b935686 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/settings/ViewerView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/settings/ViewerView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.settings +package com.snu.readability.ui.screens.settings import android.content.res.Resources import androidx.compose.foundation.Canvas @@ -55,12 +55,12 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.data.viewer.FontDataSource -import com.example.readability.data.viewer.ViewerStyle -import com.example.readability.data.viewer.ViewerStyleBuilder -import com.example.readability.ui.theme.Gabarito -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.data.viewer.FontDataSource +import com.snu.readability.data.viewer.ViewerStyle +import com.snu.readability.data.viewer.ViewerStyleBuilder +import com.snu.readability.ui.theme.Gabarito +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.launch import kotlin.math.roundToInt diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/QuizReportView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/QuizReportView.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/ui/screens/viewer/QuizReportView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/QuizReportView.kt index 5de5dac..52ffcb0 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/QuizReportView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/QuizReportView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.viewer +package com.snu.readability.ui.screens.viewer import android.widget.Toast import androidx.compose.foundation.border @@ -35,9 +35,9 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.ui.components.CircularProgressIndicatorInButton -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.ui.components.CircularProgressIndicatorInButton +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.launch private val REPORT_REASONS = listOf( diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/QuizView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/QuizView.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/ui/screens/viewer/QuizView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/QuizView.kt index bd38ad2..d56c75d 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/QuizView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/QuizView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.viewer +package com.snu.readability.ui.screens.viewer import android.widget.Toast import androidx.compose.animation.core.animateFloat @@ -57,17 +57,17 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.example.readability.R -import com.example.readability.data.ai.Quiz -import com.example.readability.data.ai.QuizLoadState -import com.example.readability.ui.animation.DURATION_EMPHASIZED_DECELERATE -import com.example.readability.ui.animation.DURATION_STANDARD -import com.example.readability.ui.animation.EASING_EMPHASIZED_DECELERATE -import com.example.readability.ui.animation.EASING_STANDARD -import com.example.readability.ui.components.RoundedRectButton -import com.example.readability.ui.components.RoundedRectFilledTonalButton -import com.example.readability.ui.theme.Gabarito -import com.example.readability.ui.theme.ReadabilityTheme +import com.snu.readability.R +import com.snu.readability.data.ai.Quiz +import com.snu.readability.data.ai.QuizLoadState +import com.snu.readability.ui.animation.DURATION_EMPHASIZED_DECELERATE +import com.snu.readability.ui.animation.DURATION_STANDARD +import com.snu.readability.ui.animation.EASING_EMPHASIZED_DECELERATE +import com.snu.readability.ui.animation.EASING_STANDARD +import com.snu.readability.ui.components.RoundedRectButton +import com.snu.readability.ui.components.RoundedRectFilledTonalButton +import com.snu.readability.ui.theme.Gabarito +import com.snu.readability.ui.theme.ReadabilityTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/SummaryView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/SummaryView.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/ui/screens/viewer/SummaryView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/SummaryView.kt index 4cb5c7a..0bcb7e1 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/SummaryView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/SummaryView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.viewer +package com.snu.readability.ui.screens.viewer import android.graphics.Typeface import android.widget.Toast @@ -24,7 +24,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em -import com.example.readability.data.viewer.ViewerStyle +import com.snu.readability.data.viewer.ViewerStyle import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerScreen.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/ViewerScreen.kt similarity index 94% rename from frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerScreen.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/ViewerScreen.kt index 531ec57..8cfbee6 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerScreen.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/ViewerScreen.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.viewer +package com.snu.readability.ui.screens.viewer import android.os.Build import android.view.View @@ -18,12 +18,12 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController -import com.example.readability.ui.animation.SharedAxis -import com.example.readability.ui.animation.composableSharedAxis -import com.example.readability.ui.viewmodels.NetworkStatusViewModel -import com.example.readability.ui.viewmodels.QuizViewModel -import com.example.readability.ui.viewmodels.SummaryViewModel -import com.example.readability.ui.viewmodels.ViewerViewModel +import com.snu.readability.ui.animation.SharedAxis +import com.snu.readability.ui.animation.composableSharedAxis +import com.snu.readability.ui.viewmodels.NetworkStatusViewModel +import com.snu.readability.ui.viewmodels.QuizViewModel +import com.snu.readability.ui.viewmodels.SummaryViewModel +import com.snu.readability.ui.viewmodels.ViewerViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext diff --git a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/ViewerView.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt rename to frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/ViewerView.kt index 0a493c0..9631da5 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/screens/viewer/ViewerView.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/screens/viewer/ViewerView.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.screens.viewer +package com.snu.readability.ui.screens.viewer import android.app.Activity import android.content.Context @@ -87,18 +87,18 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastAll import coil.compose.AsyncImage -import com.example.readability.R -import com.example.readability.data.book.Book -import com.example.readability.data.viewer.PageSplitData -import com.example.readability.data.viewer.ViewerStyle -import com.example.readability.data.viewer.getPageIndex -import com.example.readability.data.viewer.getPageProgress -import com.example.readability.ui.animation.DURATION_EMPHASIZED -import com.example.readability.ui.animation.DURATION_STANDARD -import com.example.readability.ui.animation.EASING_EMPHASIZED -import com.example.readability.ui.animation.EASING_LEGACY -import com.example.readability.ui.animation.EASING_STANDARD -import com.example.readability.ui.components.RoundedRectFilledTonalButton +import com.snu.readability.R +import com.snu.readability.data.book.Book +import com.snu.readability.data.viewer.PageSplitData +import com.snu.readability.data.viewer.ViewerStyle +import com.snu.readability.data.viewer.getPageIndex +import com.snu.readability.data.viewer.getPageProgress +import com.snu.readability.ui.animation.DURATION_EMPHASIZED +import com.snu.readability.ui.animation.DURATION_STANDARD +import com.snu.readability.ui.animation.EASING_EMPHASIZED +import com.snu.readability.ui.animation.EASING_LEGACY +import com.snu.readability.ui.animation.EASING_STANDARD +import com.snu.readability.ui.components.RoundedRectFilledTonalButton import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay diff --git a/frontend/app/src/main/java/com/example/readability/ui/theme/Color.kt b/frontend/app/src/main/java/com/snu/readability/ui/theme/Color.kt similarity index 98% rename from frontend/app/src/main/java/com/example/readability/ui/theme/Color.kt rename to frontend/app/src/main/java/com/snu/readability/ui/theme/Color.kt index 9b23cab..1f72c55 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/theme/Color.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/theme/Color.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.theme +package com.snu.readability.ui.theme import androidx.compose.ui.graphics.Color diff --git a/frontend/app/src/main/java/com/example/readability/ui/theme/Theme.kt b/frontend/app/src/main/java/com/snu/readability/ui/theme/Theme.kt similarity index 99% rename from frontend/app/src/main/java/com/example/readability/ui/theme/Theme.kt rename to frontend/app/src/main/java/com/snu/readability/ui/theme/Theme.kt index aad080e..af3ac90 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/theme/Theme.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/theme/Theme.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.theme +package com.snu.readability.ui.theme import android.app.Activity import androidx.compose.foundation.isSystemInDarkTheme diff --git a/frontend/app/src/main/java/com/example/readability/ui/theme/Type.kt b/frontend/app/src/main/java/com/snu/readability/ui/theme/Type.kt similarity index 96% rename from frontend/app/src/main/java/com/example/readability/ui/theme/Type.kt rename to frontend/app/src/main/java/com/snu/readability/ui/theme/Type.kt index be926f4..e8c0aa5 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/theme/Type.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/theme/Type.kt @@ -1,4 +1,4 @@ -package com.example.readability.ui.theme +package com.snu.readability.ui.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.ExperimentalTextApi @@ -6,7 +6,7 @@ import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontVariation import androidx.compose.ui.text.font.FontWeight -import com.example.readability.R +import com.snu.readability.R @OptIn(ExperimentalTextApi::class) val Gabarito = FontFamily( diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/AddBookViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/AddBookViewModel.kt similarity index 66% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/AddBookViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/AddBookViewModel.kt index 3ede92a..d93be4b 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/AddBookViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/AddBookViewModel.kt @@ -1,8 +1,8 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.lifecycle.ViewModel -import com.example.readability.data.book.AddBookRequest -import com.example.readability.data.book.BookRepository +import com.snu.readability.data.book.AddBookRequest +import com.snu.readability.data.book.BookRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/BookListViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/BookListViewModel.kt similarity index 91% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/BookListViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/BookListViewModel.kt index 5322f50..b388e9f 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/BookListViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/BookListViewModel.kt @@ -1,10 +1,10 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.readability.data.book.Book -import com.example.readability.data.book.BookCardData -import com.example.readability.data.book.BookRepository +import com.snu.readability.data.book.Book +import com.snu.readability.data.book.BookCardData +import com.snu.readability.data.book.BookRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/NetworkStatusViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/NetworkStatusViewModel.kt similarity index 79% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/NetworkStatusViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/NetworkStatusViewModel.kt index f0499b3..0b6f680 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/NetworkStatusViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/NetworkStatusViewModel.kt @@ -1,7 +1,7 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.lifecycle.ViewModel -import com.example.readability.data.NetworkStatusRepository +import com.snu.readability.data.NetworkStatusRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/QuizViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/QuizViewModel.kt similarity index 80% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/QuizViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/QuizViewModel.kt index f44f833..12a7ba1 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/QuizViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/QuizViewModel.kt @@ -1,8 +1,8 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.lifecycle.ViewModel -import com.example.readability.data.ai.QuizRepository -import com.example.readability.data.book.BookRepository +import com.snu.readability.data.ai.QuizRepository +import com.snu.readability.data.book.BookRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.first import javax.inject.Inject diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/SettingViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/SettingViewModel.kt similarity index 84% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/SettingViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/SettingViewModel.kt index c456b96..cd5a361 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/SettingViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/SettingViewModel.kt @@ -1,11 +1,11 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.compose.ui.graphics.NativeCanvas import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.readability.data.viewer.PageSplitRepository -import com.example.readability.data.viewer.SettingRepository -import com.example.readability.data.viewer.ViewerStyle +import com.snu.readability.data.viewer.PageSplitRepository +import com.snu.readability.data.viewer.SettingRepository +import com.snu.readability.data.viewer.ViewerStyle import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.asStateFlow diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/SummaryViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/SummaryViewModel.kt similarity index 74% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/SummaryViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/SummaryViewModel.kt index 39650eb..18dc4d0 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/SummaryViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/SummaryViewModel.kt @@ -1,10 +1,10 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.lifecycle.ViewModel -import com.example.readability.data.ai.SummaryRepository -import com.example.readability.data.book.BookRepository -import com.example.readability.data.viewer.FontDataSource -import com.example.readability.data.viewer.SettingRepository +import com.snu.readability.data.ai.SummaryRepository +import com.snu.readability.data.book.BookRepository +import com.snu.readability.data.viewer.FontDataSource +import com.snu.readability.data.viewer.SettingRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.first import javax.inject.Inject diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/UserViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/UserViewModel.kt similarity index 90% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/UserViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/UserViewModel.kt index 71cc866..e800913 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/UserViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/UserViewModel.kt @@ -1,10 +1,10 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.readability.data.user.User -import com.example.readability.data.user.UserData -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.user.User +import com.snu.readability.data.user.UserData +import com.snu.readability.data.user.UserRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted diff --git a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/ViewerViewModel.kt b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/ViewerViewModel.kt similarity index 86% rename from frontend/app/src/main/java/com/example/readability/ui/viewmodels/ViewerViewModel.kt rename to frontend/app/src/main/java/com/snu/readability/ui/viewmodels/ViewerViewModel.kt index 817d77e..6e40e08 100644 --- a/frontend/app/src/main/java/com/example/readability/ui/viewmodels/ViewerViewModel.kt +++ b/frontend/app/src/main/java/com/snu/readability/ui/viewmodels/ViewerViewModel.kt @@ -1,12 +1,12 @@ -package com.example.readability.ui.viewmodels +package com.snu.readability.ui.viewmodels import androidx.compose.ui.graphics.NativeCanvas import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.example.readability.data.book.BookRepository -import com.example.readability.data.viewer.PageSplitData -import com.example.readability.data.viewer.PageSplitRepository -import com.example.readability.data.viewer.SettingRepository +import com.snu.readability.data.book.BookRepository +import com.snu.readability.data.viewer.PageSplitData +import com.snu.readability.data.viewer.PageSplitRepository +import com.snu.readability.data.viewer.SettingRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/QuizRemoteDataSourceTest.kt similarity index 96% rename from frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/ai/QuizRemoteDataSourceTest.kt index 20badaf..7adf4d4 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/QuizRemoteDataSourceTest.kt @@ -1,8 +1,8 @@ -package com.example.readability.ui.models.ai +package com.snu.readability.ui.models.ai -import com.example.readability.data.ai.QuizAPI -import com.example.readability.data.ai.QuizRemoteDataSource -import com.example.readability.data.ai.QuizResponseType +import com.snu.readability.data.ai.QuizAPI +import com.snu.readability.data.ai.QuizRemoteDataSource +import com.snu.readability.data.ai.QuizResponseType import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.runTest import okhttp3.ResponseBody diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/QuizRepositoryTest.kt similarity index 88% rename from frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/ai/QuizRepositoryTest.kt index a44151f..9633d76 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/QuizRepositoryTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/QuizRepositoryTest.kt @@ -1,12 +1,12 @@ -package com.example.readability.ui.models.ai +package com.snu.readability.ui.models.ai -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.ai.QuizRemoteDataSource -import com.example.readability.data.ai.QuizRepository -import com.example.readability.data.ai.QuizResponse -import com.example.readability.data.ai.QuizResponseType -import com.example.readability.data.user.UserNotSignedInException -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.NetworkStatusRepository +import com.snu.readability.data.ai.QuizRemoteDataSource +import com.snu.readability.data.ai.QuizRepository +import com.snu.readability.data.ai.QuizResponse +import com.snu.readability.data.ai.QuizResponseType +import com.snu.readability.data.user.UserNotSignedInException +import com.snu.readability.data.user.UserRepository import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt similarity index 96% rename from frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt index 5d6b93f..a7a6008 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/SummaryRemoteDataSourceTest.kt @@ -1,7 +1,7 @@ -package com.example.readability.ui.models.ai +package com.snu.readability.ui.models.ai -import com.example.readability.data.ai.SummaryAPI -import com.example.readability.data.ai.SummaryRemoteDataSource +import com.snu.readability.data.ai.SummaryAPI +import com.snu.readability.data.ai.SummaryRemoteDataSource import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.runTest import okhttp3.ResponseBody diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/SummaryRepositoryTest.kt similarity index 88% rename from frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/ai/SummaryRepositoryTest.kt index 69225f0..6005259 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/ai/SummaryRepositoryTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/ai/SummaryRepositoryTest.kt @@ -1,10 +1,10 @@ -package com.example.readability.ui.models.ai +package com.snu.readability.ui.models.ai -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.ai.SummaryRemoteDataSource -import com.example.readability.data.ai.SummaryRepository -import com.example.readability.data.user.UserNotSignedInException -import com.example.readability.data.user.UserRepository +import com.snu.readability.data.NetworkStatusRepository +import com.snu.readability.data.ai.SummaryRemoteDataSource +import com.snu.readability.data.ai.SummaryRepository +import com.snu.readability.data.user.UserNotSignedInException +import com.snu.readability.data.user.UserRepository import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/book/BookFileDataSourceTest.kt similarity index 96% rename from frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/book/BookFileDataSourceTest.kt index d477fab..66312c2 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookFileDataSourceTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/book/BookFileDataSourceTest.kt @@ -1,11 +1,11 @@ -package com.example.readability.ui.models.book +package com.snu.readability.ui.models.book import android.graphics.Bitmap import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asAndroidBitmap import androidx.compose.ui.graphics.asImageBitmap -import com.example.readability.data.book.BookFileDataSource -import com.example.readability.data.book.FileHelper +import com.snu.readability.data.book.BookFileDataSource +import com.snu.readability.data.book.FileHelper import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/book/BookRemoteDataSourceTest.kt similarity index 96% rename from frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/book/BookRemoteDataSourceTest.kt index 99b7845..df8a04f 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/book/BookRemoteDataSourceTest.kt @@ -1,12 +1,12 @@ -package com.example.readability.ui.models.book +package com.snu.readability.ui.models.book import android.graphics.Bitmap -import com.example.readability.data.book.AddBookRequest -import com.example.readability.data.book.BookAPI -import com.example.readability.data.book.BookRemoteDataSource -import com.example.readability.data.book.BookResponse -import com.example.readability.data.book.BooksResponse -import com.example.readability.data.book.SummaryProgressResponse +import com.snu.readability.data.book.AddBookRequest +import com.snu.readability.data.book.BookAPI +import com.snu.readability.data.book.BookRemoteDataSource +import com.snu.readability.data.book.BookResponse +import com.snu.readability.data.book.BooksResponse +import com.snu.readability.data.book.SummaryProgressResponse import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/book/BookRepositoryTest.kt similarity index 97% rename from frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/book/BookRepositoryTest.kt index 6ca63ae..6718a8d 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/book/BookRepositoryTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/book/BookRepositoryTest.kt @@ -1,14 +1,14 @@ -package com.example.readability.ui.models.book - -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.book.AddBookRequest -import com.example.readability.data.book.Book -import com.example.readability.data.book.BookDao -import com.example.readability.data.book.BookEntity -import com.example.readability.data.book.BookFileDataSource -import com.example.readability.data.book.BookRemoteDataSource -import com.example.readability.data.book.BookRepository -import com.example.readability.data.user.UserRepository +package com.snu.readability.ui.models.book + +import com.snu.readability.data.NetworkStatusRepository +import com.snu.readability.data.book.AddBookRequest +import com.snu.readability.data.book.Book +import com.snu.readability.data.book.BookDao +import com.snu.readability.data.book.BookEntity +import com.snu.readability.data.book.BookFileDataSource +import com.snu.readability.data.book.BookRemoteDataSource +import com.snu.readability.data.book.BookRepository +import com.snu.readability.data.user.UserRepository import io.mockk.unmockkAll import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.runBlocking diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/network/NetworkStatusDataSourceTest.kt similarity index 96% rename from frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/network/NetworkStatusDataSourceTest.kt index bdf3253..d48fdba 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusDataSourceTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/network/NetworkStatusDataSourceTest.kt @@ -1,8 +1,8 @@ -package com.example.readability.ui.models.network +package com.snu.readability.ui.models.network import android.content.Context import android.net.ConnectivityManager -import com.example.readability.data.NetworkStatusDataSource +import com.snu.readability.data.NetworkStatusDataSource import io.mockk.coEvery import io.mockk.every import io.mockk.mockk diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/network/NetworkStatusRepositoryTest.kt similarity index 83% rename from frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/network/NetworkStatusRepositoryTest.kt index b372156..ff4a57f 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/network/NetworkStatusRepositoryTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/network/NetworkStatusRepositoryTest.kt @@ -1,7 +1,7 @@ -package com.example.readability.ui.models.network +package com.snu.readability.ui.models.network -import com.example.readability.data.NetworkStatusDataSource -import com.example.readability.data.NetworkStatusRepository +import com.snu.readability.data.NetworkStatusDataSource +import com.snu.readability.data.NetworkStatusRepository import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.mockk diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/user/UserRemoteDataSourceTest.kt similarity index 94% rename from frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/user/UserRemoteDataSourceTest.kt index 919b177..5a5f3a3 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRemoteDataSourceTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/user/UserRemoteDataSourceTest.kt @@ -1,11 +1,11 @@ -package com.example.readability.ui.models.user - -import com.example.readability.data.user.RefreshTokenResponse -import com.example.readability.data.user.SignUpResponse -import com.example.readability.data.user.TokenResponse -import com.example.readability.data.user.UserAPI -import com.example.readability.data.user.UserInfoResponse -import com.example.readability.data.user.UserRemoteDataSource +package com.snu.readability.ui.models.user + +import com.snu.readability.data.user.RefreshTokenResponse +import com.snu.readability.data.user.SignUpResponse +import com.snu.readability.data.user.TokenResponse +import com.snu.readability.data.user.UserAPI +import com.snu.readability.data.user.UserInfoResponse +import com.snu.readability.data.user.UserRemoteDataSource import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/user/UserRepositoryTest.kt similarity index 96% rename from frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/user/UserRepositoryTest.kt index 03bd21c..4ec2b7c 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/user/UserRepositoryTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/user/UserRepositoryTest.kt @@ -1,12 +1,12 @@ -package com.example.readability.ui.models.user - -import com.example.readability.data.NetworkStatusRepository -import com.example.readability.data.user.TokenResponse -import com.example.readability.data.user.User -import com.example.readability.data.user.UserDao -import com.example.readability.data.user.UserInfoResponse -import com.example.readability.data.user.UserRemoteDataSource -import com.example.readability.data.user.UserRepository +package com.snu.readability.ui.models.user + +import com.snu.readability.data.NetworkStatusRepository +import com.snu.readability.data.user.TokenResponse +import com.snu.readability.data.user.User +import com.snu.readability.data.user.UserDao +import com.snu.readability.data.user.UserInfoResponse +import com.snu.readability.data.user.UserRemoteDataSource +import com.snu.readability.data.user.UserRepository import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/viewer/FontDataSourceTest.kt similarity index 92% rename from frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/viewer/FontDataSourceTest.kt index 9dffddd..a70c126 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/FontDataSourceTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/viewer/FontDataSourceTest.kt @@ -1,9 +1,9 @@ -package com.example.readability.ui.models.viewer +package com.snu.readability.ui.models.viewer import android.content.Context import androidx.core.content.res.ResourcesCompat -import com.example.readability.data.viewer.FontDataSource -import com.example.readability.data.viewer.ViewerStyleBuilder +import com.snu.readability.data.viewer.FontDataSource +import com.snu.readability.data.viewer.ViewerStyleBuilder import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/viewer/PageSplitRepositoryTest.kt similarity index 88% rename from frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/viewer/PageSplitRepositoryTest.kt index 3facf65..0ebaa90 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/PageSplitRepositoryTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/viewer/PageSplitRepositoryTest.kt @@ -1,14 +1,14 @@ -package com.example.readability.ui.models.viewer +package com.snu.readability.ui.models.viewer import androidx.compose.ui.graphics.NativeCanvas -import com.example.readability.data.book.Book -import com.example.readability.data.book.BookRepository -import com.example.readability.data.viewer.FontDataSource -import com.example.readability.data.viewer.PageSplitDataSource -import com.example.readability.data.viewer.PageSplitRepository -import com.example.readability.data.viewer.SettingRepository -import com.example.readability.data.viewer.ViewerStyle -import com.example.readability.data.viewer.ViewerStyleBuilder +import com.snu.readability.data.book.Book +import com.snu.readability.data.book.BookRepository +import com.snu.readability.data.viewer.FontDataSource +import com.snu.readability.data.viewer.PageSplitDataSource +import com.snu.readability.data.viewer.PageSplitRepository +import com.snu.readability.data.viewer.SettingRepository +import com.snu.readability.data.viewer.ViewerStyle +import com.snu.readability.data.viewer.ViewerStyleBuilder import io.mockk.coEvery import io.mockk.mockk import io.mockk.verify diff --git a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt b/frontend/app/src/test/java/com/snu/readability/ui/models/viewer/SettingRepositoryTest.kt similarity index 91% rename from frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt rename to frontend/app/src/test/java/com/snu/readability/ui/models/viewer/SettingRepositoryTest.kt index 143f14b..6bd92c4 100644 --- a/frontend/app/src/test/java/com/example/readability/ui/models/viewer/SettingRepositoryTest.kt +++ b/frontend/app/src/test/java/com/snu/readability/ui/models/viewer/SettingRepositoryTest.kt @@ -1,9 +1,9 @@ -package com.example.readability.ui.models.viewer +package com.snu.readability.ui.models.viewer import android.content.Context -import com.example.readability.data.viewer.SettingDao -import com.example.readability.data.viewer.SettingRepository -import com.example.readability.data.viewer.ViewerStyleBuilder +import com.snu.readability.data.viewer.SettingDao +import com.snu.readability.data.viewer.SettingRepository +import com.snu.readability.data.viewer.ViewerStyleBuilder import io.mockk.Runs import io.mockk.coEvery import io.mockk.coVerify