diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
index 5fad538e7..793204587 100644
--- a/.idea/deploymentTargetDropDown.xml
+++ b/.idea/deploymentTargetDropDown.xml
@@ -1,6 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -12,6 +23,6 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/java/org/ireader/infinity/presentation/MainActivity.kt b/app/src/main/java/org/ireader/infinity/presentation/MainActivity.kt
index e16461a97..494439211 100644
--- a/app/src/main/java/org/ireader/infinity/presentation/MainActivity.kt
+++ b/app/src/main/java/org/ireader/infinity/presentation/MainActivity.kt
@@ -5,6 +5,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
+import androidx.core.app.NotificationManagerCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import dagger.hilt.android.AndroidEntryPoint
@@ -32,5 +33,10 @@ class MainActivity : ComponentActivity() {
}
+ override fun onDestroy() {
+ NotificationManagerCompat.from(this).cancelAll()
+ super.onDestroy()
+ }
+
}
diff --git a/core-ui/src/main/java/org/ireader/core_ui/theme/AppPreferences.kt b/core-ui/src/main/java/org/ireader/core_ui/theme/AppPreferences.kt
index abed6eba7..eb27feb2f 100644
--- a/core-ui/src/main/java/org/ireader/core_ui/theme/AppPreferences.kt
+++ b/core-ui/src/main/java/org/ireader/core_ui/theme/AppPreferences.kt
@@ -31,12 +31,14 @@ class AppPreferences @Inject constructor(
const val AUTO_SCROLL_MODE_OFFSET = "auto_scroll_mode_offset"
const val SCROLL_INDICATOR_PADDING = "scroll_indicator_padding"
const val SCROLL_INDICATOR_WIDTH = "scroll_indicator_width"
+ const val SELECTABLE_TEXT = "selectable_text"
const val TEXT_READER_SPEECH_RATE = "text_reader_speech_rate"
const val TEXT_READER_SPEECH_PITCH = "text_reader_speech_pitch"
const val TEXT_READER_SPEECH_LANGUAGE = "text_reader_speech_language"
const val TEXT_READER_SPEECH_VOICE = "text_reader_speech_voice"
+ const val TEXT_READER_AUTO_NEXT = "text_reader_auto_next"
/** Services **/
const val Last_UPDATE_CHECK = "last_update_check"
@@ -108,6 +110,10 @@ class AppPreferences @Inject constructor(
return preferenceStore.getBoolean(SCROLL_MODE, true)
}
+ fun selectableText(): Preference {
+ return preferenceStore.getBoolean(SELECTABLE_TEXT, true)
+ }
+
fun autoScrollInterval(): Preference {
return preferenceStore.getLong(AUTO_SCROLL_MODE_INTERVAL, 5000L)
}
@@ -136,6 +142,10 @@ class AppPreferences @Inject constructor(
return preferenceStore.getFloat(TEXT_READER_SPEECH_RATE, .8f)
}
+ fun readerAutoNext(): Preference {
+ return preferenceStore.getBoolean(TEXT_READER_AUTO_NEXT, false)
+ }
+
fun speechPitch(): Preference {
return preferenceStore.getFloat(TEXT_READER_SPEECH_PITCH, .8f)
}
diff --git a/domain/src/main/java/org/ireader/domain/feature_services/notification/DefaultNotificationHelper.kt b/domain/src/main/java/org/ireader/domain/feature_services/notification/DefaultNotificationHelper.kt
index 0d95ecf3a..377fb1f20 100644
--- a/domain/src/main/java/org/ireader/domain/feature_services/notification/DefaultNotificationHelper.kt
+++ b/domain/src/main/java/org/ireader/domain/feature_services/notification/DefaultNotificationHelper.kt
@@ -5,10 +5,10 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.media.MediaMetadata
-import android.media.session.PlaybackState
import android.os.Build
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
+import android.support.v4.media.session.PlaybackStateCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri
@@ -176,9 +176,10 @@ class DefaultNotificationHelper @Inject constructor(
setMetadata(MediaMetadataCompat.Builder().apply {
putText(MediaMetadata.METADATA_KEY_TITLE, chapter.title)
}.build())
- val actions =
- PlaybackState.ACTION_PLAY_PAUSE or PlaybackState.ACTION_STOP or PlaybackState.ACTION_SKIP_TO_NEXT or PlaybackState.ACTION_SKIP_TO_PREVIOUS
+ setPlaybackState(PlaybackStateCompat.Builder().apply {
+ setActions(PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_STOP or PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)
+ }.build())
}
return NotificationCompat.Builder(applicationContext,
Notifications.CHANNEL_TEXT_READER_PROGRESS).apply {
@@ -186,9 +187,8 @@ class DefaultNotificationHelper @Inject constructor(
setContentText("${progress}/${chapter.content.size}")
setSmallIcon(org.ireader.core.R.drawable.ic_infinity)
setOnlyAlertOnce(true)
- // setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
setLargeIcon(applicationContext, book.cover)
- //setShowWhen(false)
priority = NotificationCompat.PRIORITY_LOW
addAction(R.drawable.ic_baseline_skip_previous,
@@ -213,7 +213,6 @@ class DefaultNotificationHelper @Inject constructor(
.setShowActionsInCompactView(1, 2, 3)
)
setSubText(book.title)
- color = applicationContext.resources.getColor(R.color.blue_200)
//setColorized(true)
//setAutoCancel(true)
diff --git a/domain/src/main/java/org/ireader/domain/feature_services/notification/Notifications.kt b/domain/src/main/java/org/ireader/domain/feature_services/notification/Notifications.kt
index e3fa48c3e..fcad908ba 100644
--- a/domain/src/main/java/org/ireader/domain/feature_services/notification/Notifications.kt
+++ b/domain/src/main/java/org/ireader/domain/feature_services/notification/Notifications.kt
@@ -9,7 +9,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.toBitmap
import coil.ImageLoader
import coil.request.ImageRequest
-import coil.transform.CircleCropTransformation
data class Channel(
val name: String,
@@ -41,10 +40,9 @@ fun createChannel(context: Context, channel: Channel) {
if (data != null) {
val request = ImageRequest.Builder(context)
.data(data)
- .transformations(CircleCropTransformation())
.allowHardware(true)
.target { setLargeIcon(it.toBitmap()) }
- .size(200)
+ .size(512)
.build()
ImageLoader(context).execute(request)
}
diff --git a/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/OrientationUseCase.kt b/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/OrientationUseCase.kt
index cf0618b4e..f414535ba 100644
--- a/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/OrientationUseCase.kt
+++ b/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/OrientationUseCase.kt
@@ -123,4 +123,12 @@ class TextReaderPrefUseCase @Inject constructor(
return appPreferences.speechVoice().get()
}
+ fun saveAutoNext(value: Boolean) {
+ appPreferences.readerAutoNext().set(value)
+ }
+
+ fun readAutoNext(): Boolean {
+ return appPreferences.readerAutoNext().get()
+ }
+
}
\ No newline at end of file
diff --git a/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/SelectedFontStateUseCase.kt b/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/SelectedFontStateUseCase.kt
index e0d013ea2..4668623ee 100644
--- a/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/SelectedFontStateUseCase.kt
+++ b/domain/src/main/java/org/ireader/domain/use_cases/preferences/reader_preferences/SelectedFontStateUseCase.kt
@@ -8,16 +8,25 @@ import javax.inject.Inject
class SelectedFontStateUseCase @Inject constructor(
private val appPreferences: AppPreferences,
) {
- fun save(fontIndex: Int) {
+ fun saveFont(fontIndex: Int) {
appPreferences.font().set(fontIndex)
}
/**
* fontIndex is the index of font which is in fonts list inside the Type package
*/
- fun read(): FontType {
+ fun readFont(): FontType {
val fontType = appPreferences.font().get()
return fonts[fontType]
}
+ fun saveSelectableText(value: Boolean) {
+ appPreferences.selectableText().set(value)
+ }
+
+ fun readSelectableText(): Boolean {
+ return appPreferences.selectableText().get()
+ }
+
+
}
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreen.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreen.kt
index 033f59f57..312c6c852 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreen.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreen.kt
@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.*
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
@@ -63,13 +62,13 @@ fun ReadingScreen(
val context = LocalContext.current
- DisposableEffect(key1 = true) {
- onDispose {
- vm.uiFunc.apply {
- vm.restoreSetting(context, scrollState)
- }
- }
- }
+// DisposableEffect(key1 = true) {
+// onDispose {
+// vm.uiFunc.apply {
+// vm.restoreSetting(context, scrollState)
+// }
+// }
+// }
LaunchedEffect(key1 = scaffoldState.drawerState.targetValue) {
if (chapter != null && scaffoldState.drawerState.targetValue == DrawerValue.Open && vm.stateChapters.isNotEmpty()) {
vm.uiFunc.apply {
@@ -195,6 +194,15 @@ fun ReadingScreen(
vm.showSnackBar(UiText.ExceptionString(e))
}
}
+ },
+ vm = vm,
+ state = vm,
+ scrollState = scrollState,
+ onBookMark = {
+ vm.uiFunc.apply {
+ vm.bookmarkChapter()
+
+ }
}
)
},
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreenTopBar.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreenTopBar.kt
index e06bde909..c91b3f492 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreenTopBar.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderScreenTopBar.kt
@@ -5,23 +5,28 @@ import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.systemBarsPadding
+import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Autorenew
-import androidx.compose.material.icons.filled.Public
+import androidx.compose.material.icons.filled.*
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
+import kotlinx.coroutines.launch
import org.ireader.domain.models.entities.Chapter
+import org.ireader.presentation.feature_reader.presentation.reader.viewmodel.ReaderScreenPreferencesState
+import org.ireader.presentation.feature_reader.presentation.reader.viewmodel.ReaderScreenState
import org.ireader.presentation.presentation.Toolbar
import org.ireader.presentation.presentation.reusable_composable.AppIconButton
+import org.ireader.presentation.presentation.reusable_composable.AppTextField
import org.ireader.presentation.presentation.reusable_composable.TopAppBarBackButton
import tachiyomi.source.Source
@@ -30,15 +35,18 @@ import tachiyomi.source.Source
fun ReaderScreenTopBar(
isReaderModeEnable: Boolean,
isLoaded: Boolean,
+ vm: ReaderScreenPreferencesState,
+ state: ReaderScreenState,
modalBottomSheetValue: ModalBottomSheetValue,
chapter: Chapter?,
navController: NavController,
onRefresh: () -> Unit,
source: Source,
onWebView: () -> Unit,
-
-
- ) {
+ onBookMark: () -> Unit,
+ scrollState: LazyListState,
+) {
+ val scope = rememberCoroutineScope()
if (!isReaderModeEnable && isLoaded) {
AnimatedVisibility(
visible = !isReaderModeEnable && isLoaded,
@@ -48,34 +56,153 @@ fun ReaderScreenTopBar(
Toolbar(
modifier = Modifier.systemBarsPadding(),
title = {
- Text(
- text = chapter?.title ?: "",
- color = MaterialTheme.colors.onBackground,
- style = MaterialTheme.typography.subtitle1,
- fontWeight = FontWeight.Bold,
- overflow = TextOverflow.Ellipsis,
- maxLines = 1
- )
+ if (!vm.searchMode) {
+ Text(
+ text = chapter?.title ?: "",
+ color = MaterialTheme.colors.onBackground,
+ style = MaterialTheme.typography.subtitle1,
+ fontWeight = FontWeight.Bold,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1
+ )
+ } else {
+ AppTextField(
+ query = vm.searchQuery,
+ onValueChange = { query ->
+ vm.searchQuery = query
+ vm.queriedTextIndex.clear()
+ state.stateChapter?.let { chapter ->
+ chapter.content.filter { cont ->
+ cont.contains(query,
+ ignoreCase = true)
+ }.forEach { str ->
+ val index = chapter.content.indexOf(str)
+ if (index != -1) {
+ vm.queriedTextIndex.add(index)
+ }
+
+ }
+ }
+
+ },
+ onConfirm = {
+
+ },
+ )
+ }
+
},
backgroundColor = MaterialTheme.colors.background,
contentColor = MaterialTheme.colors.onBackground,
elevation = 0.dp,
navigationIcon = {
- TopAppBarBackButton(navController = navController)
- },
- actions = {
- if (chapter != null) {
- AppIconButton(imageVector = Icons.Default.Autorenew,
- title = "Refresh",
+ if (!vm.searchMode) {
+ TopAppBarBackButton(navController = navController)
+ } else {
+ AppIconButton(imageVector = Icons.Default.ArrowBack,
+ title = "Exit search mode",
onClick = {
- onRefresh()
+ vm.searchQuery = ""
+ vm.searchMode = false
+ vm.queriedTextIndex.clear()
})
}
- AppIconButton(imageVector = Icons.Default.Public,
- title = "WebView",
- onClick = {
- onWebView()
- })
+ },
+ actions = {
+ when (vm.searchMode) {
+ true -> {
+ AppIconButton(
+ imageVector = Icons.Default.Close,
+ title = "Close",
+ onClick = {
+ vm.searchQuery = ""
+ vm.searchMode = false
+ vm.queriedTextIndex.clear()
+ },
+ )
+ AppIconButton(
+ imageVector = Icons.Default.ExpandMore,
+ title = "previous result",
+ onClick = {
+ vm.currentViewingSearchResultIndex.let { index ->
+ chapter?.let {
+ if (index < chapter.content.lastIndex) {
+ scope.launch {
+ try {
+ vm.currentViewingSearchResultIndex += 1
+ scrollState.scrollToItem(vm.queriedTextIndex[index])
+ } catch (e: Exception) {
+ vm.currentViewingSearchResultIndex = 0
+ }
+ }
+
+ }
+
+ }
+ }
+
+
+ },
+ )
+ AppIconButton(
+ imageVector = Icons.Default.ExpandLess,
+ title = "next result",
+ onClick = {
+ vm.currentViewingSearchResultIndex.let { index ->
+ if (index > 0) {
+
+ scope.launch {
+ try {
+ vm.currentViewingSearchResultIndex -= 1
+ scrollState.scrollToItem(vm.queriedTextIndex[index])
+ } catch (e: Exception) {
+ vm.currentViewingSearchResultIndex = 0
+ }
+ }
+ }
+
+
+ }
+ },
+ )
+ }
+ else -> {
+ if (chapter != null) {
+ AppIconButton(imageVector = if (vm.expandTopMenu) Icons.Default.ChevronRight else Icons.Default.ChevronLeft,
+ title = "Expand Menu",
+ onClick = {
+ vm.expandTopMenu = !vm.expandTopMenu
+ })
+ if (vm.expandTopMenu) {
+ AppIconButton(imageVector = if (chapter.bookmark) Icons.Filled.Bookmark else Icons.Default.Bookmark,
+ title = "Bookmark",
+ tint = if (chapter.bookmark) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground,
+ onClick = {
+ onBookMark()
+ })
+ AppIconButton(imageVector = Icons.Default.Search,
+ title = "Search",
+ onClick = {
+ vm.searchMode = true
+ })
+ AppIconButton(imageVector = Icons.Default.Public,
+ title = "WebView",
+ onClick = {
+ onWebView()
+ })
+ }
+ AppIconButton(imageVector = Icons.Default.Autorenew,
+ title = "Refresh",
+ onClick = {
+ onRefresh()
+ })
+
+ }
+ }
+
+ }
+
+
}
)
}
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderText.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderText.kt
index 69604cd9a..f58f5f004 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderText.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/ReaderText.kt
@@ -7,6 +7,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ModalBottomSheetState
@@ -19,6 +20,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -100,21 +102,42 @@ fun ReaderText(
state = scrollState,
modifier = Modifier
) {
- item {
- Text(
- modifier = modifier
- .fillMaxSize()
- .padding(horizontal = vm.paragraphsIndent.dp,
- vertical = 4.dp),
- text = "\n\n" + chapter.content.map { it.trimStart() }
- .joinToString("\n".repeat(vm.distanceBetweenParagraphs)),
- fontSize = vm.fontSize.sp,
- fontFamily = vm.font.fontFamily,
- textAlign = TextAlign.Start,
- color = vm.textColor,
- lineHeight = vm.lineHeight.sp,
- )
+ items(count = chapter.content.size) { index ->
+ TextSelectionContainer(selectable = vm.selectableMode) {
+ Text(
+ modifier = modifier
+ .padding(horizontal = vm.paragraphsIndent.dp, vertical = 4.dp)
+ .background(if (index in vm.queriedTextIndex) vm.textColor.copy(
+ .1f) else Color.Transparent),
+ text = if (index == 0) "\n\n" + chapter.content[index].plus("\n".repeat(
+ vm.distanceBetweenParagraphs)) else chapter.content[index].plus(
+ "\n".repeat(vm.distanceBetweenParagraphs)),
+ fontSize = vm.fontSize.sp,
+ fontFamily = vm.font.fontFamily,
+ textAlign = TextAlign.Start,
+ color = vm.textColor,
+ lineHeight = vm.lineHeight.sp,
+ )
+ }
}
+// item {
+// TextSelectionContainer(selectable = vm.selectableMode) {
+// Text(
+// modifier = modifier
+// .fillMaxSize()
+// .padding(horizontal = vm.paragraphsIndent.dp,
+// vertical = 4.dp),
+// text = "\n\n" + chapter.content.map { it.trimStart() }
+// .joinToString("\n".repeat(vm.distanceBetweenParagraphs)),
+// fontSize = vm.fontSize.sp,
+// fontFamily = vm.font.fontFamily,
+// textAlign = TextAlign.Start,
+// color = vm.textColor,
+// lineHeight = vm.lineHeight.sp,
+// )
+// }
+//
+// }
}
@@ -196,4 +219,20 @@ fun ReaderText(
fun LazyListState.isScrolledToTheEnd(): Boolean {
val lastItem = layoutInfo.visibleItemsInfo.lastOrNull()
return lastItem == null || lastItem.size + lastItem.offset <= layoutInfo.viewportEndOffset
+}
+
+@Composable
+fun TextSelectionContainer(
+ modifier: Modifier = Modifier,
+ selectable: Boolean,
+ content: @Composable () -> Unit,
+) {
+ when (selectable) {
+ true -> SelectionContainer {
+ content()
+ }
+ else -> {
+ content()
+ }
+ }
}
\ No newline at end of file
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/components/ReaderSettingComposable.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/components/ReaderSettingComposable.kt
index 2bad43210..2c7131a13 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/components/ReaderSettingComposable.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/components/ReaderSettingComposable.kt
@@ -70,6 +70,13 @@ fun ReaderSettingComposable(modifier: Modifier = Modifier, viewModel: ReaderScre
viewModel.toggleImmersiveMode(context)
}
})
+ SettingItemToggleComposable(text = "Selectable mode",
+ value = viewModel.selectableMode,
+ onToggle = {
+ func.apply {
+ viewModel.toggleSelectableMode()
+ }
+ })
SettingItemComposable(text = "Font Size",
value = viewModel.fontSize.toString(),
onAdd = {
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderMainFunc.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderMainFunc.kt
index 0c933442f..4aa410f93 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderMainFunc.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderMainFunc.kt
@@ -19,6 +19,7 @@ interface ReaderMainFunctions {
suspend fun ReaderScreenViewModel.getChapter(
chapterId: Long,
source: Source,
+ onSuccess: () -> Unit = {},
)
suspend fun ReaderScreenViewModel.getLocalBookById(
@@ -30,13 +31,22 @@ interface ReaderMainFunctions {
suspend fun ReaderScreenViewModel.insertChapter(chapter: Chapter)
suspend fun ReaderScreenViewModel.insertBook(book: Book)
- fun ReaderScreenViewModel.getReadingContentRemotely(chapter: Chapter, source: Source)
+ fun ReaderScreenViewModel.getReadingContentRemotely(
+ chapter: Chapter,
+ source: Source,
+ onSuccess: () -> Unit = {},
+ )
+
fun ReaderScreenViewModel.updateLastReadTime(chapter: Chapter)
fun ReaderScreenViewModel.getLocalChaptersByPaging(bookId: Long)
}
class ReaderMainFunctionsImpl @Inject constructor() : ReaderMainFunctions {
- override suspend fun ReaderScreenViewModel.getChapter(chapterId: Long, source: Source) {
+ override suspend fun ReaderScreenViewModel.getChapter(
+ chapterId: Long,
+ source: Source,
+ onSuccess: () -> Unit,
+ ) {
toggleLoading(true)
toggleLocalLoaded(false)
viewModelScope.launch {
@@ -61,13 +71,16 @@ class ReaderMainFunctionsImpl @Inject constructor() : ReaderMainFunctions {
!state.isRemoteLoading &&
!state.isLoading
) {
- getReadingContentRemotely(chapter = chapter, source = source)
+ getReadingContentRemotely(chapter = chapter, source = source) {
+
+ }
}
updateLastReadTime(resultChapter)
updateChapterSliderIndex(getCurrentIndexOfChapter(resultChapter))
if (!initialized) {
initialized = true
}
+ onSuccess()
} else {
toggleLoading(false)
toggleLocalLoaded(false)
@@ -121,7 +134,11 @@ class ReaderMainFunctionsImpl @Inject constructor() : ReaderMainFunctions {
insertUseCases.insertBook(book)
}
- override fun ReaderScreenViewModel.getReadingContentRemotely(chapter: Chapter, source: Source) {
+ override fun ReaderScreenViewModel.getReadingContentRemotely(
+ chapter: Chapter,
+ source: Source,
+ onSuccess: () -> Unit,
+ ) {
clearError()
toggleLocalLoaded(false)
toggleRemoteLoading(true)
@@ -144,7 +161,7 @@ class ReaderMainFunctionsImpl @Inject constructor() : ReaderMainFunctions {
toggleRemoteLoaded(true)
clearError()
getChapter(chapter.id, source = source)
-
+ onSuccess()
} else {
showSnackBar(UiText.StringResource(R.string.something_is_wrong_with_this_chapter))
}
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderPrefCodes.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderPrefCodes.kt
index 3ac818d45..9c42d42cd 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderPrefCodes.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderPrefCodes.kt
@@ -27,6 +27,7 @@ interface ReaderPrefFunctions {
fun ReaderScreenViewModel.saveOrientation(context: Context)
fun ReaderScreenViewModel.readImmersiveMode(context: Context)
fun ReaderScreenViewModel.toggleImmersiveMode(context: Context)
+ fun ReaderScreenViewModel.toggleSelectableMode()
fun ReaderScreenViewModel.toggleAutoScrollMode()
fun ReaderScreenViewModel.toggleScrollMode()
fun ReaderScreenViewModel.saveParagraphDistance(isIncreased: Boolean)
@@ -49,8 +50,8 @@ interface ReaderPrefFunctions {
class ReaderPrefFunctionsImpl @Inject constructor() : ReaderPrefFunctions {
override fun ReaderScreenViewModel.readPreferences() {
- font = readerUseCases.selectedFontStateUseCase.read()
- readerUseCases.selectedFontStateUseCase.save(0)
+ font = readerUseCases.selectedFontStateUseCase.readFont()
+ readerUseCases.selectedFontStateUseCase.saveFont(0)
this.fontSize = readerUseCases.fontSizeStateUseCase.read()
@@ -71,6 +72,8 @@ class ReaderPrefFunctionsImpl @Inject constructor() : ReaderPrefFunctions {
pitch = speechPrefUseCases.readPitch()
currentVoice = speechPrefUseCases.readVoice()
currentLanguage = speechPrefUseCases.readLanguage()
+ selectableMode = readerUseCases.selectedFontStateUseCase.readSelectableText()
+ autoNextChapter = speechPrefUseCases.readAutoNext()
}
override fun ReaderScreenViewModel.toggleReaderMode(enable: Boolean?) {
@@ -93,7 +96,7 @@ class ReaderPrefFunctionsImpl @Inject constructor() : ReaderPrefFunctions {
override fun ReaderScreenViewModel.saveFont(index: Int) {
this.font = fonts[index]
- readerUseCases.selectedFontStateUseCase.save(index)
+ readerUseCases.selectedFontStateUseCase.saveFont(index)
}
@@ -194,6 +197,11 @@ class ReaderPrefFunctionsImpl @Inject constructor() : ReaderPrefFunctions {
}
}
+ override fun ReaderScreenViewModel.toggleSelectableMode() {
+ selectableMode = !selectableMode
+ readerUseCases.selectedFontStateUseCase.saveSelectableText(selectableMode)
+ }
+
override fun ReaderScreenViewModel.toggleAutoScrollMode() {
autoScrollMode = !autoScrollMode
}
@@ -210,7 +218,7 @@ class ReaderPrefFunctionsImpl @Inject constructor() : ReaderPrefFunctions {
readerUseCases.paragraphDistanceUseCase.save(currentDistance + 1)
distanceBetweenParagraphs = currentDistance + 1
- } else if (currentDistance > 1 && !isIncreased) {
+ } else if (currentDistance > 0 && !isIncreased) {
readerUseCases.paragraphDistanceUseCase.save(currentDistance - 1)
distanceBetweenParagraphs = currentDistance - 1
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenState.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenState.kt
index 1917ef204..d806afb81 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenState.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenState.kt
@@ -4,8 +4,10 @@ package org.ireader.presentation.feature_reader.presentation.reader.viewmodel
import android.speech.tts.TextToSpeech
import android.speech.tts.Voice
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.graphics.Color
import org.ireader.core.utils.UiText
import org.ireader.core_ui.theme.BackgroundColor
@@ -134,7 +136,13 @@ open class ReaderScreenPreferencesStateImpl @Inject constructor() : ReaderScreen
override var autoScrollMode by mutableStateOf(false)
override var autoBrightnessMode by mutableStateOf(false)
override var immersiveMode by mutableStateOf(false)
+ override var selectableMode by mutableStateOf(false)
override var initialized by mutableStateOf(false)
+ override var searchMode by mutableStateOf(false)
+ override var expandTopMenu by mutableStateOf(false)
+ override var searchQuery by mutableStateOf("")
+ override var queriedTextIndex: SnapshotStateList = mutableStateListOf()
+ override var currentViewingSearchResultIndex by mutableStateOf(0)
}
@@ -161,7 +169,13 @@ interface ReaderScreenPreferencesState {
var autoScrollMode: Boolean
var autoBrightnessMode: Boolean
var immersiveMode: Boolean
+ var selectableMode: Boolean
var initialized: Boolean
+ var searchMode: Boolean
+ var expandTopMenu: Boolean
+ var searchQuery: String
+ var queriedTextIndex: SnapshotStateList
+ var currentViewingSearchResultIndex: Int
}
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenViewModel.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenViewModel.kt
index 985dfdd60..7466af140 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenViewModel.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderScreenViewModel.kt
@@ -3,16 +3,19 @@ package org.ireader.presentation.feature_reader.presentation.reader.viewmodel
import android.content.Context
import android.support.v4.media.session.MediaSessionCompat
+import androidx.compose.foundation.lazy.LazyListState
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
+import org.ireader.core.R
import org.ireader.core.utils.UiText
import org.ireader.core_ui.viewmodel.BaseViewModel
import org.ireader.domain.catalog.service.CatalogStore
import org.ireader.domain.feature_services.notification.DefaultNotificationHelper
import org.ireader.domain.feature_services.notification.NotificationStates
+import org.ireader.domain.models.entities.Chapter
import org.ireader.domain.ui.NavigationArgs
import org.ireader.domain.use_cases.history.HistoryUseCase
import org.ireader.domain.use_cases.local.LocalGetChapterUseCase
@@ -20,6 +23,7 @@ import org.ireader.domain.use_cases.local.LocalInsertUseCases
import org.ireader.domain.use_cases.preferences.reader_preferences.ReaderPrefUseCases
import org.ireader.domain.use_cases.preferences.reader_preferences.TextReaderPrefUseCase
import org.ireader.domain.use_cases.remote.RemoteUseCases
+import tachiyomi.source.Source
import javax.inject.Inject
@@ -70,6 +74,7 @@ class ReaderScreenViewModel @Inject constructor(
}
+
} else {
viewModelScope.launch {
showSnackBar(UiText.StringResource(org.ireader.core.R.string.the_source_is_not_found))
@@ -125,5 +130,33 @@ class ReaderScreenViewModel @Inject constructor(
currentReadingParagraph = 0
}
+ fun onNext(
+ scrollState: LazyListState,
+ chapters: List,
+ source: Source,
+ currentIndex: Int,
+ ) {
+ if (currentIndex < chapters.lastIndex) {
+ uiFunc.apply {
+ updateChapterSliderIndex(currentIndex + 1)
+ }
+ mainFunc.apply {
+ uiFunc.apply {
+ scope.launch {
+ getChapter(getCurrentChapterByIndex().id,
+ source = source)
+ scrollState.animateScrollToItem(0, 0)
+ }
+ }
+ }
+
+ } else {
+ scope.launch {
+ showSnackBar(UiText.StringResource(R.string.this_is_last_chapter))
+
+ }
+ }
+ }
+
}
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderUiFunc.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderUiFunc.kt
index 61dd75b59..206d7dab9 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderUiFunc.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/ReaderUiFunc.kt
@@ -5,6 +5,8 @@ import android.content.pm.ActivityInfo
import android.view.WindowManager
import androidx.compose.foundation.lazy.LazyListState
import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.ireader.core.utils.UiText
import org.ireader.core.utils.findComponentActivity
@@ -29,6 +31,8 @@ interface ReaderUiFunctions {
fun ReaderScreenViewModel.getCurrentIndex(): Int
fun ReaderScreenViewModel.getCurrentChapterByIndex(): Chapter
fun ReaderScreenViewModel.reverseChapters()
+ fun ReaderScreenViewModel.bookmarkChapter()
+
}
@@ -130,4 +134,15 @@ class ReaderUiFunctionsImpl @Inject constructor() : ReaderUiFunctions {
override fun ReaderScreenViewModel.reverseChapters() {
toggleIsAsc(!prefState.isAsc)
}
+
+ override fun ReaderScreenViewModel.bookmarkChapter() {
+ stateChapter?.let { chapter ->
+ viewModelScope.launch(Dispatchers.IO) {
+ stateChapter = chapter.copy(bookmark = !chapter.bookmark)
+ insertUseCases.insertChapter(chapter.copy(bookmark = !chapter.bookmark))
+
+ }
+
+ }
+ }
}
\ No newline at end of file
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/TextReaderManager.kt b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/TextReaderManager.kt
index c56b4e271..55a49627f 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/TextReaderManager.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_reader/presentation/reader/viewmodel/TextReaderManager.kt
@@ -69,7 +69,7 @@ class TextReaderManager @Inject constructor(
defaultNotificationHelper.basicPlayingTextReaderNotification(
chapter,
book,
- true,
+ isPlaying,
currentReadingParagraph,
mediaSessionCompat)
@@ -105,16 +105,20 @@ class TextReaderManager @Inject constructor(
// notify(Notifications.ID_TEXT_READER_PROGRESS, builder.build())
readText(context, mediaSessionCompat)
}
- if (currentReadingParagraph == chapter.content.size) {
+ if (currentReadingParagraph == chapter.content.size && speaker != null && !isLoading && !isRemoteLoading) {
isPlaying = false
+ speaker?.stop()
if (autoNextChapter) {
source?.let {
updateChapterSliderIndex(currentChapterIndex + 1)
viewModelScope.launch {
getChapter(getCurrentChapterByIndex().id,
- source = it)
- readText(context = context, mediaSessionCompat)
- isPlaying = true
+ source = it) {
+ if (chapter.content.isNotEmpty() && !isLoading && !isRemoteLoading) {
+ readText(context = context,
+ mediaSessionCompat)
+ }
+ }
}
}
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/setting/SettingViewModel.kt b/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/setting/SettingViewModel.kt
index 5a0aeed3e..fcbf27a2b 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/setting/SettingViewModel.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/setting/SettingViewModel.kt
@@ -56,7 +56,7 @@ class SettingViewModel @Inject constructor(
fun deleteDefaultSettings() {
viewModelScope.launchIO {
- prefUseCases.selectedFontStateUseCase.save(0)
+ prefUseCases.selectedFontStateUseCase.saveFont(0)
prefUseCases.fontHeightUseCase.save(25)
prefUseCases.fontSizeStateUseCase.save(18)
prefUseCases.paragraphDistanceUseCase.save(2)
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/webview/WebPageTopBar.kt b/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/webview/WebPageTopBar.kt
index 52ff920b3..1589428fb 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/webview/WebPageTopBar.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_settings/presentation/webview/WebPageTopBar.kt
@@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
+import org.ireader.core.ChapterParse
import org.ireader.core.ChaptersParse
import org.ireader.core.DetailParse
import org.ireader.domain.FetchType
@@ -103,7 +104,8 @@ fun WebPageTopBar(
}) {
MidSizeTextComposable(text = stringResource(R.string.go_forward))
}
- if (source is HttpSource && source.getListings().contains(DetailParse())) {
+ if (source is HttpSource && source.getListings().map { it.name }
+ .contains(DetailParse().name)) {
DropdownMenuItem(onClick = {
isMenuExpanded = false
fetchBook()
@@ -111,7 +113,17 @@ fun WebPageTopBar(
MidSizeTextComposable(text = "Fetch Book")
}
}
- if (source is HttpSource && source.getListings().contains(ChaptersParse())) {
+ if (source is HttpSource && source.getListings().map { it.name }
+ .contains(ChaptersParse().name)) {
+ DropdownMenuItem(onClick = {
+ isMenuExpanded = false
+ fetchChapter()
+ }) {
+ MidSizeTextComposable(text = "Fetch Chapter")
+ }
+ }
+ if (source is HttpSource && source.getListings().map { it.name }
+ .contains(ChapterParse().name)) {
DropdownMenuItem(onClick = {
isMenuExpanded = false
fetchChapter()
diff --git a/presentation/src/main/java/org/ireader/presentation/feature_ttl/TTSScreen.kt b/presentation/src/main/java/org/ireader/presentation/feature_ttl/TTSScreen.kt
index 16208709e..c425ee7a9 100644
--- a/presentation/src/main/java/org/ireader/presentation/feature_ttl/TTSScreen.kt
+++ b/presentation/src/main/java/org/ireader/presentation/feature_ttl/TTSScreen.kt
@@ -1,12 +1,15 @@
package org.ireader.presentation.feature_ttl
+import android.speech.tts.TextToSpeech
import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.TweenSpec
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
@@ -20,6 +23,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.app.NotificationManagerCompat
@@ -27,6 +31,7 @@ import androidx.navigation.NavController
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.ireader.core.R
+import org.ireader.core.utils.toast
import org.ireader.domain.feature_services.io.BookCover
import org.ireader.domain.feature_services.notification.Notifications
import org.ireader.domain.models.entities.Chapter
@@ -59,6 +64,8 @@ fun TTSScreen(
onNext: () -> Unit,
source: Source,
onChapter: (Chapter) -> Unit,
+ onValueChange: (Float) -> Unit,
+ onValueChangeFinished: () -> Unit,
) {
@@ -83,6 +90,38 @@ fun TTSScreen(
}
}
}
+ LaunchedEffect(key1 = true) {
+ vm.apply {
+ if (speaker == null) {
+ speaker = TextToSpeech(context) { status ->
+ isLoading = true
+ if (status == TextToSpeech.ERROR) {
+ context.toast("Text-to-Speech Not Available")
+ isLoading = false
+ return@TextToSpeech
+ }
+ isLoading = false
+ }
+ }
+ }
+ }
+ LaunchedEffect(key1 = vm.stateChapter, vm.isPlaying, vm.currentReadingParagraph) {
+ vm.state.stateChapter?.let { chapter ->
+ vm.state.book?.let { book ->
+ val notification = vm.defaultNotificationHelper.basicPlayingTextReaderNotification(
+ chapter,
+ book,
+ vm.isPlaying,
+ vm.currentReadingParagraph,
+ vm.mediaSessionCompat(context))
+ NotificationManagerCompat.from(context)
+ .notify(Notifications.ID_TEXT_READER_PROGRESS, notification.build())
+ }
+
+ }
+ }
+
+
LaunchedEffect(key1 = true) {
vm.notificationStates.mediaPlayerNotification.collectLatest {
Timber.e(it.toString())
@@ -97,28 +136,17 @@ fun TTSScreen(
onPlay()
chapter?.let {
vm.book?.let { book ->
- val notification = when {
- vm.isPlaying -> {
- vm.defaultNotificationHelper.basicPlayingTextReaderNotification(
- chapter,
- book,
- false,
- vm.currentReadingParagraph,
- vm.mediaSessionCompat(context))
- }
- else -> {
- vm.defaultNotificationHelper.basicPlayingTextReaderNotification(
- chapter,
- book,
- true,
- vm.currentReadingParagraph,
- vm.mediaSessionCompat(context))
-
- }
- }
- NotificationManagerCompat.from(context).apply {
- notify(Notifications.ID_TEXT_READER_PROGRESS, notification.build())
- }
+// val notification = vm.defaultNotificationHelper.basicPlayingTextReaderNotification(
+// chapter,
+// book,
+// !vm.isPlaying,
+// vm.currentReadingParagraph,
+// vm.mediaSessionCompat(context))
+//
+//
+// NotificationManagerCompat.from(context).apply {
+// notify(Notifications.ID_TEXT_READER_PROGRESS, notification.build())
+// }
}
}
@@ -150,7 +178,10 @@ fun TTSScreen(
LanguageChip(viewModel = vm, modifier = Modifier.height(32.dp))
SettingItemToggleComposable(text = "Auto Next Chapter",
value = vm.autoNextChapter,
- onToggle = { vm.autoNextChapter = !vm.autoNextChapter })
+ onToggle = {
+ vm.autoNextChapter = !vm.autoNextChapter
+ vm.speechPrefUseCases.saveAutoNext(vm.autoNextChapter)
+ })
SettingItemComposable(text = "Speech Rate",
value = vm.speechSpeed.toString(),
onAdd = {
@@ -249,7 +280,7 @@ fun TTSScreen(
image = BookCover.from(book),
modifier = Modifier
.padding(8.dp)
- .height(150.dp)
+ .height(180.dp)
.width(120.dp)
.clip(MaterialTheme.shapes.medium)
.border(2.dp,
@@ -257,8 +288,14 @@ fun TTSScreen(
contentScale = ContentScale.Crop,
)
- BigSizeTextComposable(text = chapter.title, align = TextAlign.Center)
- MidSizeTextComposable(text = book.title, align = TextAlign.Center)
+ BigSizeTextComposable(text = chapter.title,
+ align = TextAlign.Center,
+ maxLine = 1,
+ overflow = TextOverflow.Ellipsis)
+ MidSizeTextComposable(text = book.title,
+ align = TextAlign.Center,
+ maxLine = 1,
+ overflow = TextOverflow.Ellipsis)
vm.stateChapter?.let { chapter ->
SuperSmallTextComposable(text = "${vm.currentReadingParagraph}/${chapter.content.size}")
@@ -266,11 +303,11 @@ fun TTSScreen(
}
Text(
modifier = modifier
-
+ .padding(horizontal = vm.paragraphsIndent.dp, vertical = 4.dp)
.fillMaxWidth()
- .align(Alignment.CenterHorizontally)
- .padding(horizontal = vm.paragraphsIndent.dp,
- vertical = 4.dp),
+ .height(160.dp)
+ .verticalScroll(rememberScrollState())
+ .align(Alignment.CenterHorizontally),
text = if (chapter.content.isNotEmpty() && vm.currentReadingParagraph != chapter.content.size) chapter.content[vm.currentReadingParagraph] else "",
fontSize = vm.fontSize.sp,
fontFamily = vm.font.fontFamily,
@@ -297,13 +334,15 @@ fun TTSScreen(
}
)
TTLScreenPlay(
- modifier = Modifier.padding(bottom = 46.dp, top = 32.dp),
onPlay = onPlay,
onNext = onNext,
onPrev = onPrev,
vm = vm,
onNextPar = onNextPar,
- onPrevPar = onPrevPar
+ onPrevPar = onPrevPar,
+ chapter = chapter,
+ onValueChange = onValueChange,
+ onValueChangeFinished = onValueChangeFinished
)
}
@@ -326,8 +365,8 @@ private fun TTLScreenSetting(
onContent: () -> Unit,
) {
Row(modifier = Modifier
+ .padding(horizontal = 8.dp)
.fillMaxWidth()
- // .padding(16.dp)
.height(80.dp)
.border(width = 1.dp, color = MaterialTheme.colors.onBackground.copy(.1f)),
horizontalArrangement = Arrangement.SpaceAround,
@@ -364,69 +403,99 @@ private fun TTLScreenSetting(
private fun TTLScreenPlay(
modifier: Modifier = Modifier,
vm: ReaderScreenViewModel,
+ chapter: Chapter?,
onPrev: () -> Unit,
onPlay: () -> Unit,
onNext: () -> Unit,
onNextPar: () -> Unit,
onPrevPar: () -> Unit,
+ onValueChange: (Float) -> Unit,
+ onValueChangeFinished: () -> Unit,
) {
- Row(modifier = modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.SpaceAround,
- verticalAlignment = Alignment.CenterVertically) {
- Row(modifier = Modifier
- .fillMaxWidth()
- .padding(horizontal = 32.dp),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.SpaceAround) {
- AppIconButton(modifier = Modifier.size(50.dp),
- imageVector = Icons.Filled.SkipPrevious,
- title = "Previous Paragraph",
- onClick = onPrev,
- tint = MaterialTheme.colors.onBackground)
- AppIconButton(modifier = Modifier.size(50.dp),
- imageVector = Icons.Filled.FastRewind,
- title = "Previous",
- onClick = onPrevPar,
- tint = MaterialTheme.colors.onBackground)
- Box(modifier = Modifier
- .size(100.dp)
- .border(1.dp, MaterialTheme.colors.onBackground.copy(.4f), CircleShape),
- contentAlignment = Alignment.Center) {
- when {
- vm.isLoading || vm.isRemoteLoading -> {
- showLoading()
- }
- vm.isPlaying -> {
- AppIconButton(modifier = Modifier.size(80.dp),
- imageVector = Icons.Filled.Pause,
- title = "Play",
- onClick = onPlay,
- tint = MaterialTheme.colors.onBackground)
- }
- else -> {
- AppIconButton(modifier = Modifier.size(80.dp),
- imageVector = Icons.Filled.PlayArrow,
- title = "Play",
- onClick = onPlay,
- tint = MaterialTheme.colors.onBackground)
+ Column(modifier = Modifier.fillMaxWidth()) {
+ chapter?.let { chapter ->
+ Slider(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 8.dp),
+ value = if (chapter.content.isEmpty()) 0F else vm.currentReadingParagraph.toFloat(),
+ onValueChange = {
+ onValueChange(it)
+ },
+ onValueChangeFinished = {
+ onValueChangeFinished()
+ },
+ valueRange = 0f..(if (chapter.content.isNotEmpty()) chapter.content.size - 1 else 0).toFloat(),
+ colors = SliderDefaults.colors(
+ thumbColor = MaterialTheme.colors.primary,
+ activeTrackColor = MaterialTheme.colors.primary.copy(alpha = .6f),
+ inactiveTickColor = MaterialTheme.colors.onBackground.copy(alpha = .6f),
+ inactiveTrackColor = MaterialTheme.colors.onBackground.copy(alpha = .6f),
+ activeTickColor = MaterialTheme.colors.primary.copy(alpha = .6f)
+ )
+ )
+ }
+
+ Row(modifier = modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceAround,
+ verticalAlignment = Alignment.CenterVertically) {
+ Row(modifier = Modifier
+ .padding(bottom = 16.dp, top = 4.dp)
+ .fillMaxWidth()
+ .height(80.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceAround) {
+ AppIconButton(modifier = Modifier.size(50.dp),
+ imageVector = Icons.Filled.SkipPrevious,
+ title = "Previous Paragraph",
+ onClick = onPrev,
+ tint = MaterialTheme.colors.onBackground)
+ AppIconButton(modifier = Modifier.size(50.dp),
+ imageVector = Icons.Filled.FastRewind,
+ title = "Previous",
+ onClick = onPrevPar,
+ tint = MaterialTheme.colors.onBackground)
+ Box(modifier = Modifier
+ .size(80.dp)
+ .border(1.dp, MaterialTheme.colors.onBackground.copy(.4f), CircleShape),
+ contentAlignment = Alignment.Center) {
+ when {
+ vm.isLoading || vm.isRemoteLoading -> {
+ showLoading()
+ }
+ vm.isPlaying -> {
+ AppIconButton(modifier = Modifier.size(80.dp),
+ imageVector = Icons.Filled.Pause,
+ title = "Play",
+ onClick = onPlay,
+ tint = MaterialTheme.colors.onBackground)
+ }
+ else -> {
+ AppIconButton(modifier = Modifier.size(80.dp),
+ imageVector = Icons.Filled.PlayArrow,
+ title = "Play",
+ onClick = onPlay,
+ tint = MaterialTheme.colors.onBackground)
+ }
}
- }
- }
+ }
- AppIconButton(modifier = Modifier.size(50.dp),
- imageVector = Icons.Filled.FastForward,
- title = "Next Paragraph",
- onClick = onNextPar,
- tint = MaterialTheme.colors.onBackground)
- AppIconButton(modifier = Modifier.size(50.dp),
- imageVector = Icons.Filled.SkipNext,
- title = "Next",
- onClick = onNext,
- tint = MaterialTheme.colors.onBackground)
+ AppIconButton(modifier = Modifier.size(50.dp),
+ imageVector = Icons.Filled.FastForward,
+ title = "Next Paragraph",
+ onClick = onNextPar,
+ tint = MaterialTheme.colors.onBackground)
+ AppIconButton(modifier = Modifier.size(50.dp),
+ imageVector = Icons.Filled.SkipNext,
+ title = "Next",
+ onClick = onNext,
+ tint = MaterialTheme.colors.onBackground)
+ }
}
}
+
}
diff --git a/presentation/src/main/java/org/ireader/presentation/presentation/reusable_composable/TopAppBarReusableComposables.kt b/presentation/src/main/java/org/ireader/presentation/presentation/reusable_composable/TopAppBarReusableComposables.kt
index 7df927e5c..d6fe9105a 100644
--- a/presentation/src/main/java/org/ireader/presentation/presentation/reusable_composable/TopAppBarReusableComposables.kt
+++ b/presentation/src/main/java/org/ireader/presentation/presentation/reusable_composable/TopAppBarReusableComposables.kt
@@ -35,6 +35,7 @@ fun BigSizeTextComposable(
fontWeight: FontWeight? = null,
overflow: TextOverflow? = null,
align: TextAlign? = null,
+ maxLine: Int = Int.MAX_VALUE,
) {
Text(
modifier = modifier,
@@ -44,6 +45,7 @@ fun BigSizeTextComposable(
fontWeight = fontWeight ?: FontWeight.Bold,
overflow = overflow ?: TextOverflow.Ellipsis,
textAlign = align ?: TextAlign.Start,
+ maxLines = maxLine
)
}
diff --git a/presentation/src/main/java/org/ireader/presentation/ui/ReaderScreenSpec.kt b/presentation/src/main/java/org/ireader/presentation/ui/ReaderScreenSpec.kt
index cdc0b9bbd..808ce1d70 100644
--- a/presentation/src/main/java/org/ireader/presentation/ui/ReaderScreenSpec.kt
+++ b/presentation/src/main/java/org/ireader/presentation/ui/ReaderScreenSpec.kt
@@ -55,6 +55,7 @@ object ReaderScreenSpec : ScreenSpec {
val currentIndex = vm.currentChapterIndex
val source = vm.source
val chapters = vm.stateChapters
+ val chapter = vm.stateChapter
val scope = rememberCoroutineScope()
val scrollState = rememberLazyListState()
val drawerScrollState = rememberLazyListState()
@@ -67,8 +68,13 @@ object ReaderScreenSpec : ScreenSpec {
vm.mediaSessionCompat(context).release()
NotificationManagerCompat.from(context)
.cancel(Notifications.ID_TEXT_READER_PROGRESS)
+ vm.uiFunc.apply {
+ vm.restoreSetting(context, scrollState)
+ }
}
}
+
+
if (source != null) {
when {
vm.voiceMode -> {
@@ -76,22 +82,15 @@ object ReaderScreenSpec : ScreenSpec {
TTSScreen(
vm = vm,
onPrev = {
- if (currentIndex > 0) {
- vm.uiFunc.apply {
- vm.updateChapterSliderIndex(currentIndex - 1)
-
- }
- vm.mainFunc.apply {
- vm.uiFunc.apply {
- scope.launch {
- vm.getChapter(vm.getCurrentChapterByIndex().id,
- source = source)
- scrollState.animateScrollToItem(0, 0)
- }
+ if (vm.currentChapterIndex > 0) {
+ vm.apply {
+ currentChapterIndex -= 1
+ scope.launch {
+ vm.getChapter(vm.getCurrentChapterByIndex().id,
+ source = source)
+ scrollState.animateScrollToItem(0, 0)
}
}
-
-
} else {
scope.launch {
vm.showSnackBar(UiText.StringResource(org.ireader.core.R.string.this_is_first_chapter))
@@ -109,22 +108,33 @@ object ReaderScreenSpec : ScreenSpec {
}
}
}
-
+ scope.launch {
+ vm.state.stateChapter?.let { chapter ->
+ vm.state.book?.let { book ->
+ val notification =
+ vm.defaultNotificationHelper.basicPlayingTextReaderNotification(
+ chapter,
+ book,
+ vm.isPlaying,
+ vm.currentReadingParagraph,
+ vm.mediaSessionCompat(context))
+ NotificationManagerCompat.from(context)
+ .notify(Notifications.ID_TEXT_READER_PROGRESS,
+ notification.build())
+ }
+ }
+ }
},
onNext = {
if (currentIndex < chapters.lastIndex) {
- vm.uiFunc.apply {
-
- vm.updateChapterSliderIndex(currentIndex + 1)
- }
- vm.mainFunc.apply {
- vm.uiFunc.apply {
- scope.launch {
- vm.getChapter(vm.getCurrentChapterByIndex().id,
- source = source)
- scrollState.animateScrollToItem(0, 0)
- }
+ vm.apply {
+ currentChapterIndex += 1
+ scope.launch {
+ vm.getChapter(vm.getCurrentChapterByIndex().id,
+ source = source)
+ scrollState.animateScrollToItem(0, 0)
}
+
}
} else {
@@ -177,6 +187,18 @@ object ReaderScreenSpec : ScreenSpec {
}
}
}
+ },
+ onValueChange = {
+ vm.speaker?.stop()
+ vm.currentReadingParagraph = it.toInt()
+ },
+ onValueChangeFinished = {
+ if (vm.isPlaying) {
+ vm.textReaderManager.apply {
+ vm.readText(context, vm.mediaSessionCompat(context))
+ }
+ }
+
}
)
}