0.8.0 - History Screen and Project Name change

This commit is contained in:
acclorite 2024-03-04 19:12:00 +02:00
parent 0b3a31a183
commit 5a966e9d9d
171 changed files with 3027 additions and 1877 deletions

2
.idea/.name generated
View file

@ -1 +1 @@
Book's History Resurrection
Book's Story

View file

@ -4,19 +4,18 @@
<value>
<entry key="app">
<State>
<runningDeviceTargetSelectedWithDropDown>
<targetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Phone_13_.avd" />
<value value="C:\Users\Administrator\.android\avd\Phone_33_.avd" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-02-22T17:49:53.931710327Z" />
<multipleDevicesSelectedInDropDown value="true" />
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-02-29T15:05:04.852701900Z" />
<targetsSelectedWithDialog>
<Target>
<type value="QUICK_BOOT_TARGET" />

2
.idea/gradle.xml generated
View file

@ -5,7 +5,7 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="gradleJvm" value="jbr-17 (2)" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

2
.idea/vcs.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="" vcs="Git" />
</component>
</project>

View file

@ -10,15 +10,15 @@ plugins {
}
android {
namespace = "com.acclorite.books_history"
namespace = "ua.acclorite.book_story"
compileSdk = 34
defaultConfig {
applicationId = "com.acclorite.books_history"
applicationId = "ua.acclorite.book_story"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "0.6.0"
versionName = "0.8.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@ -140,4 +140,7 @@ dependencies {
}
implementation("org.slf4j:slf4j-android:latest.release")
implementation("org.jsoup:jsoup:latest.release")
implementation("androidx.appcompat:appcompat:latest.release")
implementation("androidx.appcompat:appcompat-resources:latest.release")
}

View file

@ -1,22 +0,0 @@
package com.acclorite.books_history
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.acclorite.books_history", appContext.packageName)
}
}

View file

@ -17,9 +17,10 @@
android:theme="@style/Theme.Start.Splash"
android:enableOnBackInvokedCallback="true"
tools:targetApi="tiramisu">
<activity
android:name=".MainActivity"
android:configChanges="screenSize|screenLayout|smallestScreenSize|locale|density"
android:configChanges="screenSize|screenLayout|smallestScreenSize|locale|density|uiMode"
android:windowSoftInputMode="adjustResize"
android:exported="true"
android:theme="@style/Theme.Start.Splash">
@ -28,6 +29,16 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

View file

@ -1,35 +0,0 @@
package com.acclorite.books_history.data.di
import com.acclorite.books_history.data.local.data_store.DataStore
import com.acclorite.books_history.data.local.data_store.DataStoreImpl
import com.acclorite.books_history.data.mapper.BookMapper
import com.acclorite.books_history.data.mapper.BookMapperImpl
import com.acclorite.books_history.data.repository.BookRepositoryImpl
import com.acclorite.books_history.domain.repository.BookRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindDataStore(
dataStoreImpl: DataStoreImpl
): DataStore
@Binds
@Singleton
abstract fun bindBookRepository(
bookRepositoryImpl: BookRepositoryImpl
): BookRepository
@Binds
@Singleton
abstract fun bindBookMapper(
bookMapperImpl: BookMapperImpl
): BookMapper
}

View file

@ -1,14 +0,0 @@
package com.acclorite.books_history.data.local.room
import androidx.room.Database
import androidx.room.RoomDatabase
import com.acclorite.books_history.data.local.dto.BookEntity
@Database(
entities = [BookEntity::class],
version = 1,
exportSchema = false
)
abstract class BookDatabase : RoomDatabase() {
abstract val dao: BookDao
}

View file

@ -1,10 +0,0 @@
package com.acclorite.books_history.data.mapper
import com.acclorite.books_history.data.local.dto.BookEntity
import com.acclorite.books_history.domain.model.Book
interface BookMapper {
suspend fun toBookEntity(book: Book): BookEntity
suspend fun toBook(bookEntity: BookEntity): Book
}

View file

@ -1,9 +0,0 @@
package com.acclorite.books_history.data.parser
import com.acclorite.books_history.domain.model.Book
import java.io.File
interface FileParser {
suspend fun parse(file: File): Book?
}

View file

@ -1,8 +0,0 @@
package com.acclorite.books_history.data.parser
import com.acclorite.books_history.domain.model.StringWithId
import java.io.File
interface TextParser {
suspend fun parse(file: File): List<StringWithId>
}

View file

@ -1,12 +0,0 @@
package com.acclorite.books_history.domain.use_case
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.repository.BookRepository
import javax.inject.Inject
class DeleteBooks @Inject constructor(private val repository: BookRepository) {
suspend fun execute(books: List<Book>) {
repository.deleteBooks(books)
}
}

View file

@ -1,128 +0,0 @@
package com.acclorite.books_history.presentation.components
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.statusBars
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.ui.DefaultTransition
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AnimatedTopAppBar(
containerColor: Color = MaterialTheme.colorScheme.surface,
scrolledContainerColor: Color?,
scrollBehavior: TopAppBarScrollBehavior?,
isTopBarScrolled: Boolean?,
content1Visibility: Boolean,
content1NavigationIcon: @Composable () -> Unit,
content1Title: @Composable () -> Unit,
content1Actions: @Composable RowScope.() -> Unit,
content2Visibility: Boolean,
content2NavigationIcon: @Composable () -> Unit,
content2Title: @Composable () -> Unit,
content2Actions: @Composable RowScope.() -> Unit,
content3Visibility: Boolean,
content3NavigationIcon: @Composable () -> Unit,
content3Title: @Composable () -> Unit,
content3Actions: @Composable RowScope.() -> Unit
) {
val color =
if (isTopBarScrolled == true && scrolledContainerColor != null) scrolledContainerColor
else containerColor
val animatedColor by animateColorAsState(
targetValue = color,
animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
label = "TopAppBar color animation"
)
if (scrollBehavior != null && scrolledContainerColor != null) {
val isScrolled = scrollBehavior.state.overlappedFraction > 0.01f
val statusBarPadding = with(LocalDensity.current) {
WindowInsets.statusBars.getTop(LocalDensity.current).toDp()
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(64.dp + statusBarPadding)
.background(
if (isScrolled) scrolledContainerColor
else containerColor
)
)
}
Box(modifier = Modifier.fillMaxWidth()) {
DefaultTransition(visible = content1Visibility) {
TopAppBar(
navigationIcon = content1NavigationIcon,
title = content1Title,
actions = content1Actions,
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedColor,
scrolledContainerColor = scrolledContainerColor ?: Color.Transparent
)
)
}
DefaultTransition(visible = content2Visibility) {
TopAppBar(
navigationIcon = content2NavigationIcon,
title = content2Title,
actions = content2Actions,
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedColor,
scrolledContainerColor = scrolledContainerColor ?: Color.Transparent
)
)
}
DefaultTransition(visible = content3Visibility) {
TopAppBar(
navigationIcon = content3NavigationIcon,
title = content3Title,
actions = content3Actions,
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = animatedColor,
scrolledContainerColor = scrolledContainerColor ?: Color.Transparent
)
)
}
}
}

View file

@ -1,16 +0,0 @@
package com.acclorite.books_history.presentation.screens.history
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.hilt.navigation.compose.hiltViewModel
import com.acclorite.books_history.presentation.Navigator
import com.acclorite.books_history.presentation.screens.history.data.HistoryViewModel
@Composable
fun HistoryScreen(
viewModel: HistoryViewModel = hiltViewModel(),
navigator: Navigator
) {
val state by viewModel.state.collectAsState()
}

View file

@ -1,3 +0,0 @@
package com.acclorite.books_history.presentation.screens.history.data
sealed class HistoryEvent

View file

@ -1,5 +0,0 @@
package com.acclorite.books_history.presentation.screens.history.data
data class HistoryState(
val foo: Int = 0
)

View file

@ -1,36 +0,0 @@
package com.acclorite.books_history.presentation.screens.history.data
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
@HiltViewModel
class HistoryViewModel @Inject constructor(
) : ViewModel() {
private val _state = MutableStateFlow(HistoryState())
val state = _state.asStateFlow()
fun onEvent(event: HistoryEvent) {
//
}
}

View file

@ -1,50 +0,0 @@
package com.acclorite.books_history.presentation.screens.reader.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun ReaderSettingsBottomSheetItem(
modifier: Modifier = Modifier,
title: String,
description: String,
verticalPadding: Dp = 8.dp,
onClick: () -> Unit
) {
Column(
modifier
.fillMaxWidth()
.clickable {
onClick()
}
.padding(horizontal = 18.dp, vertical = verticalPadding),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start
) {
Text(
title,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
fontSize = 18.sp
)
Spacer(modifier = Modifier.height(2.dp))
Text(
description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}

View file

@ -1,50 +0,0 @@
package com.acclorite.books_history.presentation.screens.settings.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun SettingsOptionItem(
modifier: Modifier = Modifier,
title: String,
description: String,
verticalPadding: Dp = 8.dp,
onClick: () -> Unit
) {
Column(
modifier
.fillMaxWidth()
.clickable {
onClick()
}
.padding(horizontal = 16.dp, vertical = verticalPadding),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start
) {
Text(
title,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
fontSize = 18.sp
)
Spacer(modifier = Modifier.height(2.dp))
Text(
description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}

View file

@ -1,11 +1,15 @@
package com.acclorite.books_history
package ua.acclorite.book_story
import android.content.res.Configuration
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.slideInHorizontally
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@ -15,33 +19,29 @@ import androidx.compose.material3.Scaffold
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.presentation.NavigationHost
import com.acclorite.books_history.presentation.Screen
import com.acclorite.books_history.presentation.components.BottomNavigationBar
import com.acclorite.books_history.presentation.data.MainEvent
import com.acclorite.books_history.presentation.data.MainViewModel
import com.acclorite.books_history.presentation.screens.book_info.BookInfoScreen
import com.acclorite.books_history.presentation.screens.browse.BrowseScreen
import com.acclorite.books_history.presentation.screens.history.HistoryScreen
import com.acclorite.books_history.presentation.screens.library.LibraryScreen
import com.acclorite.books_history.presentation.screens.reader.ReaderScreen
import com.acclorite.books_history.presentation.screens.settings.SettingsScreen
import com.acclorite.books_history.presentation.screens.settings.nested.appearance.AppearanceSettings
import com.acclorite.books_history.presentation.screens.settings.nested.general.GeneralSettings
import com.acclorite.books_history.ui.BooksHistoryResurrectionTheme
import com.acclorite.books_history.ui.DefaultTransition
import com.acclorite.books_history.ui.Transitions
import com.acclorite.books_history.ui.isDark
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import dagger.hilt.android.AndroidEntryPoint
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.presentation.NavigationHost
import ua.acclorite.book_story.presentation.Screen
import ua.acclorite.book_story.presentation.components.BottomNavigationBar
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainViewModel
import ua.acclorite.book_story.presentation.screens.book_info.BookInfoScreen
import ua.acclorite.book_story.presentation.screens.browse.BrowseScreen
import ua.acclorite.book_story.presentation.screens.history.HistoryScreen
import ua.acclorite.book_story.presentation.screens.library.LibraryScreen
import ua.acclorite.book_story.presentation.screens.reader.ReaderScreen
import ua.acclorite.book_story.presentation.screens.settings.SettingsScreen
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.AppearanceSettings
import ua.acclorite.book_story.presentation.screens.settings.nested.general.GeneralSettings
import ua.acclorite.book_story.ui.BooksHistoryResurrectionTheme
import ua.acclorite.book_story.ui.Transitions
import ua.acclorite.book_story.ui.isDark
@OptIn(ExperimentalPermissionsApi::class)
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
class MainActivity : AppCompatActivity() {
private val mainViewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
@ -70,14 +70,17 @@ class MainActivity : ComponentActivity() {
if (!updating) {
NavigationHost(startScreen = Screen.LIBRARY) {
val currentScreen by this.getCurrentScreen().collectAsState()
DefaultTransition(
AnimatedVisibility(
visible = currentScreen == Screen.LIBRARY ||
currentScreen == Screen.HISTORY ||
currentScreen == Screen.BROWSE
currentScreen == Screen.BROWSE,
enter = fadeIn(tween(200)) +
slideInHorizontally(tween(200)) { it / 15 },
exit = Transitions.SlidingTransitionOut
) {
Scaffold(
bottomBar = {
BottomNavigationBar(navigator = this)
BottomNavigationBar(navigator = this@NavigationHost)
},
containerColor = MaterialTheme.colorScheme.surface
) {
@ -122,8 +125,7 @@ class MainActivity : ComponentActivity() {
exitAnim = Transitions.SlidingTransitionOut
) {
ReaderScreen(
navigator = this@NavigationHost,
mainViewModel = mainViewModel
navigator = this@NavigationHost
)
}
@ -145,7 +147,6 @@ class MainActivity : ComponentActivity() {
exitAnim = Transitions.SlidingTransitionOut
) {
GeneralSettings(
mainViewModel = mainViewModel,
navigator = this@NavigationHost
)
}
@ -155,7 +156,6 @@ class MainActivity : ComponentActivity() {
exitAnim = Transitions.SlidingTransitionOut
) {
AppearanceSettings(
mainViewModel = mainViewModel,
navigator = this@NavigationHost
)
}
@ -165,8 +165,7 @@ class MainActivity : ComponentActivity() {
modifier = Modifier
.fillMaxSize()
.background(
if (darkTheme.isDark()) Color.Black
else Color.White
MaterialTheme.colorScheme.surface
)
)
}

View file

@ -1,13 +1,13 @@
package com.acclorite.books_history.data.di
package ua.acclorite.book_story.data.di
import android.app.Application
import androidx.room.Room
import com.acclorite.books_history.data.local.room.BookDao
import com.acclorite.books_history.data.local.room.BookDatabase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import ua.acclorite.book_story.data.local.room.BookDao
import ua.acclorite.book_story.data.local.room.BookDatabase
import javax.inject.Singleton
@Module

View file

@ -0,0 +1,43 @@
package ua.acclorite.book_story.data.di
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import ua.acclorite.book_story.data.local.data_store.DataStore
import ua.acclorite.book_story.data.local.data_store.DataStoreImpl
import ua.acclorite.book_story.data.mapper.BookMapper
import ua.acclorite.book_story.data.mapper.BookMapperImpl
import ua.acclorite.book_story.data.mapper.HistoryMapper
import ua.acclorite.book_story.data.mapper.HistoryMapperImpl
import ua.acclorite.book_story.data.repository.BookRepositoryImpl
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindDataStore(
dataStoreImpl: DataStoreImpl
): DataStore
@Binds
@Singleton
abstract fun bindBookRepository(
bookRepositoryImpl: BookRepositoryImpl
): BookRepository
@Binds
@Singleton
abstract fun bindBookMapper(
bookMapperImpl: BookMapperImpl
): BookMapper
@Binds
@Singleton
abstract fun bindHistoryMapper(
historyMapperImpl: HistoryMapperImpl
): HistoryMapper
}

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.data.local.data_store
package ua.acclorite.book_story.data.local.data_store
import androidx.datastore.preferences.core.Preferences
import kotlinx.coroutines.flow.Flow

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.data.local.data_store
package ua.acclorite.book_story.data.local.data_store
import android.app.Application
import android.content.Context

View file

@ -1,8 +1,8 @@
package com.acclorite.books_history.data.local.dto
package ua.acclorite.book_story.data.local.dto
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.acclorite.books_history.domain.model.Category
import ua.acclorite.book_story.domain.model.Category
@Entity
data class BookEntity(

View file

@ -0,0 +1,12 @@
package ua.acclorite.book_story.data.local.dto
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class HistoryEntity(
@PrimaryKey(true)
val id: Int? = null,
val bookId: Int,
val time: Long
)

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.data.local.room
package ua.acclorite.book_story.data.local.room
import androidx.room.Dao
import androidx.room.Delete
@ -6,7 +6,8 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.acclorite.books_history.data.local.dto.BookEntity
import ua.acclorite.book_story.data.local.dto.BookEntity
import ua.acclorite.book_story.data.local.dto.HistoryEntity
@Dao
interface BookDao {
@ -35,4 +36,22 @@ interface BookDao {
@Update
suspend fun updateBooks(books: List<BookEntity>)
@Query("SELECT * FROM historyentity")
suspend fun getHistory(): List<HistoryEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertHistory(
history: List<HistoryEntity>
)
@Query("DELETE FROM historyentity")
suspend fun deleteWholeHistory()
@Query("DELETE FROM historyentity WHERE bookId = :bookId")
suspend fun deleteBookHistory(bookId: Int)
@Delete
suspend fun deleteHistory(history: List<HistoryEntity>)
}

View file

@ -0,0 +1,18 @@
package ua.acclorite.book_story.data.local.room
import androidx.room.Database
import androidx.room.RoomDatabase
import ua.acclorite.book_story.data.local.dto.BookEntity
import ua.acclorite.book_story.data.local.dto.HistoryEntity
@Database(
entities = [
BookEntity::class,
HistoryEntity::class
],
version = 1,
exportSchema = false
)
abstract class BookDatabase : RoomDatabase() {
abstract val dao: BookDao
}

View file

@ -0,0 +1,10 @@
package ua.acclorite.book_story.data.mapper
import ua.acclorite.book_story.data.local.dto.BookEntity
import ua.acclorite.book_story.domain.model.Book
interface BookMapper {
suspend fun toBookEntity(book: Book): BookEntity
suspend fun toBook(bookEntity: BookEntity): Book
}

View file

@ -1,14 +1,14 @@
package com.acclorite.books_history.data.mapper
package ua.acclorite.book_story.data.mapper
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import com.acclorite.books_history.R
import com.acclorite.books_history.data.local.dto.BookEntity
import com.acclorite.books_history.data.parser.EpubFileParser
import com.acclorite.books_history.data.parser.PdfFileParser
import com.acclorite.books_history.data.parser.TxtFileParser
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.util.UIText
import ua.acclorite.book_story.R
import ua.acclorite.book_story.data.local.dto.BookEntity
import ua.acclorite.book_story.data.parser.EpubFileParser
import ua.acclorite.book_story.data.parser.PdfFileParser
import ua.acclorite.book_story.data.parser.TxtFileParser
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.util.UIText
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File

View file

@ -0,0 +1,11 @@
package ua.acclorite.book_story.data.mapper
import ua.acclorite.book_story.data.local.dto.HistoryEntity
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.History
interface HistoryMapper {
suspend fun toHistoryEntity(history: History): HistoryEntity
suspend fun toHistory(historyEntity: HistoryEntity, book: Book): History
}

View file

@ -0,0 +1,24 @@
package ua.acclorite.book_story.data.mapper
import ua.acclorite.book_story.data.local.dto.HistoryEntity
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.History
import javax.inject.Inject
class HistoryMapperImpl @Inject constructor() : HistoryMapper {
override suspend fun toHistoryEntity(history: History): HistoryEntity {
return HistoryEntity(
id = history.id,
bookId = history.book.id ?: 0,
time = history.time
)
}
override suspend fun toHistory(historyEntity: HistoryEntity, book: Book): History {
return History(
historyEntity.id,
book = book,
time = historyEntity.time
)
}
}

View file

@ -1,10 +1,12 @@
package com.acclorite.books_history.data.parser
package ua.acclorite.book_story.data.parser
import android.graphics.BitmapFactory
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.model.Category
import com.acclorite.books_history.util.UIText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import nl.siegmann.epublib.epub.EpubReader
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.Category
import ua.acclorite.book_story.util.UIText
import java.io.File
import java.io.FileInputStream
import javax.inject.Inject
@ -18,7 +20,9 @@ class EpubFileParser @Inject constructor() : FileParser {
try {
val epubReader = EpubReader()
val book = epubReader.readEpub(FileInputStream(file))
val book = withContext(Dispatchers.IO) {
epubReader.readEpub(FileInputStream(file))
}
val metadata = book.metadata
val author = UIText.StringValue(metadata.authors.joinToString(", "))

View file

@ -1,8 +1,10 @@
package com.acclorite.books_history.data.parser
package ua.acclorite.book_story.data.parser
import com.acclorite.books_history.domain.model.StringWithId
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import nl.siegmann.epublib.epub.EpubReader
import org.jsoup.Jsoup
import ua.acclorite.book_story.domain.model.StringWithId
import java.io.BufferedReader
import java.io.File
import java.io.FileInputStream
@ -18,7 +20,9 @@ class EpubTextParser @Inject constructor() : TextParser {
}
try {
val book = EpubReader().readEpub(FileInputStream(file))
val book = withContext(Dispatchers.IO) {
EpubReader().readEpub(FileInputStream(file))
}
val unformattedText = StringBuilder()
for (spineReference in book.spine.spineReferences) {
@ -28,7 +32,9 @@ class EpubTextParser @Inject constructor() : TextParser {
BufferedReader(InputStreamReader(inputStream, Charset.forName("UTF-8")))
var line: String?
while (reader.readLine().also { line = it } != null) {
while (withContext(Dispatchers.IO) {
reader.readLine()
}.also { line = it } != null) {
unformattedText.append(line).append("\n")
}
}

View file

@ -0,0 +1,9 @@
package ua.acclorite.book_story.data.parser
import ua.acclorite.book_story.domain.model.Book
import java.io.File
interface FileParser {
suspend fun parse(file: File): Book?
}

View file

@ -1,13 +1,13 @@
package com.acclorite.books_history.data.parser
package ua.acclorite.book_story.data.parser
import android.app.Application
import com.acclorite.books_history.R
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.model.Category
import com.acclorite.books_history.domain.model.StringWithId
import com.acclorite.books_history.util.UIText
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
import com.tom_roush.pdfbox.pdmodel.PDDocument
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.Category
import ua.acclorite.book_story.domain.model.StringWithId
import ua.acclorite.book_story.util.UIText
import java.io.File
import javax.inject.Inject

View file

@ -1,10 +1,10 @@
package com.acclorite.books_history.data.parser
package ua.acclorite.book_story.data.parser
import android.app.Application
import com.acclorite.books_history.domain.model.StringWithId
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
import com.tom_roush.pdfbox.pdmodel.PDDocument
import com.tom_roush.pdfbox.text.PDFTextStripper
import ua.acclorite.book_story.domain.model.StringWithId
import java.io.File
import javax.inject.Inject

View file

@ -0,0 +1,8 @@
package ua.acclorite.book_story.data.parser
import ua.acclorite.book_story.domain.model.StringWithId
import java.io.File
interface TextParser {
suspend fun parse(file: File): List<StringWithId>
}

View file

@ -1,10 +1,10 @@
package com.acclorite.books_history.data.parser
package ua.acclorite.book_story.data.parser
import com.acclorite.books_history.R
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.model.Category
import com.acclorite.books_history.domain.model.StringWithId
import com.acclorite.books_history.util.UIText
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.Category
import ua.acclorite.book_story.domain.model.StringWithId
import ua.acclorite.book_story.util.UIText
import java.io.File
import javax.inject.Inject

View file

@ -1,6 +1,8 @@
package com.acclorite.books_history.data.parser
package ua.acclorite.book_story.data.parser
import com.acclorite.books_history.domain.model.StringWithId
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import ua.acclorite.book_story.domain.model.StringWithId
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
@ -16,10 +18,12 @@ class TxtTextParser @Inject constructor() : TextParser {
return try {
val formattedLines = mutableListOf<StringWithId>()
BufferedReader(FileReader(file)).forEachLine { line ->
formattedLines.add(
StringWithId(line)
)
withContext(Dispatchers.IO) {
BufferedReader(FileReader(file)).forEachLine { line ->
formattedLines.add(
StringWithId(line)
)
}
}
formattedLines

View file

@ -1,25 +1,27 @@
package com.acclorite.books_history.data.repository
package ua.acclorite.book_story.data.repository
import android.os.Environment
import androidx.datastore.preferences.core.Preferences
import com.acclorite.books_history.data.local.data_store.DataStore
import com.acclorite.books_history.data.local.dto.BookEntity
import com.acclorite.books_history.data.local.room.BookDao
import com.acclorite.books_history.data.mapper.BookMapper
import com.acclorite.books_history.data.parser.EpubFileParser
import com.acclorite.books_history.data.parser.EpubTextParser
import com.acclorite.books_history.data.parser.PdfFileParser
import com.acclorite.books_history.data.parser.PdfTextParser
import com.acclorite.books_history.data.parser.TxtFileParser
import com.acclorite.books_history.data.parser.TxtTextParser
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.model.NullableBook
import com.acclorite.books_history.domain.model.StringWithId
import com.acclorite.books_history.domain.repository.BookRepository
import com.acclorite.books_history.util.Constants
import com.acclorite.books_history.util.Resource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import ua.acclorite.book_story.data.local.data_store.DataStore
import ua.acclorite.book_story.data.local.dto.BookEntity
import ua.acclorite.book_story.data.local.room.BookDao
import ua.acclorite.book_story.data.mapper.BookMapper
import ua.acclorite.book_story.data.mapper.HistoryMapper
import ua.acclorite.book_story.data.parser.EpubFileParser
import ua.acclorite.book_story.data.parser.EpubTextParser
import ua.acclorite.book_story.data.parser.PdfFileParser
import ua.acclorite.book_story.data.parser.PdfTextParser
import ua.acclorite.book_story.data.parser.TxtFileParser
import ua.acclorite.book_story.data.parser.TxtTextParser
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.History
import ua.acclorite.book_story.domain.model.NullableBook
import ua.acclorite.book_story.domain.model.StringWithId
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.util.Constants
import ua.acclorite.book_story.util.Resource
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton
@ -30,6 +32,7 @@ class BookRepositoryImpl @Inject constructor(
private val dataStore: DataStore,
private val bookMapper: BookMapper,
private val historyMapper: HistoryMapper,
private val txtFileParser: TxtFileParser,
private val pdfFileParser: PdfFileParser,
@ -233,6 +236,38 @@ class BookRepositoryImpl @Inject constructor(
emit(Resource.Success(books))
}
}
override suspend fun insertHistory(history: List<History>) {
database.insertHistory(history.map { historyMapper.toHistoryEntity(it) })
}
override suspend fun getHistory(): Flow<Resource<List<History>>> {
return flow {
emit(Resource.Loading(true))
val history = database.getHistory()
emit(
Resource.Success(
data = history.map {
val book = database.findBookById(it.bookId)
historyMapper.toHistory(it, bookMapper.toBook(book))
}
)
)
}
}
override suspend fun deleteWholeHistory() {
database.deleteWholeHistory()
}
override suspend fun deleteBookHistory(bookId: Int) {
database.deleteBookHistory(bookId)
}
override suspend fun deleteHistory(history: List<History>) {
database.deleteHistory(history.map { historyMapper.toHistoryEntity(it) })
}
}
@ -248,3 +283,4 @@ class BookRepositoryImpl @Inject constructor(

View file

@ -1,21 +1,21 @@
package com.acclorite.books_history.domain.model
import android.graphics.Bitmap
import androidx.compose.runtime.Immutable
import com.acclorite.books_history.util.UIText
import java.io.File
@Immutable
data class Book(
val id: Int?,
val title: String,
val author: UIText,
val description: String?,
val text: List<StringWithId> = emptyList(),
val progress: Float,
val file: File?,
val filePath: String,
val lastOpened: Long?,
val category: Category,
val coverImage: Bitmap?
)
package ua.acclorite.book_story.domain.model
import android.graphics.Bitmap
import androidx.compose.runtime.Immutable
import ua.acclorite.book_story.util.UIText
import java.io.File
@Immutable
data class Book(
val id: Int?,
val title: String,
val author: UIText,
val description: String?,
val text: List<StringWithId> = emptyList(),
val progress: Float,
val file: File?,
val filePath: String,
val lastOpened: Long?,
val category: Category,
val coverImage: Bitmap?
)

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.domain.model
package ua.acclorite.book_story.domain.model
enum class Category {
READING, ALREADY_READ, PLANNING, DROPPED

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.domain.model
package ua.acclorite.book_story.domain.model
import androidx.compose.runtime.Immutable
import androidx.compose.ui.text.TextStyle

View file

@ -1,8 +1,8 @@
package com.acclorite.books_history.domain.model
package ua.acclorite.book_story.domain.model
import androidx.compose.runtime.Immutable
import androidx.compose.ui.text.font.FontFamily
import com.acclorite.books_history.util.UIText
import ua.acclorite.book_story.util.UIText
@Immutable
data class FontWithName(

View file

@ -0,0 +1,9 @@
package ua.acclorite.book_story.domain.model
import androidx.compose.runtime.Immutable
@Immutable
data class GroupedHistory(
val title: String,
val history: List<History>
)

View file

@ -0,0 +1,10 @@
package ua.acclorite.book_story.domain.model
import androidx.compose.runtime.Immutable
@Immutable
data class History(
val id: Int?,
val book: Book,
val time: Long
)

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.domain.model
package ua.acclorite.book_story.domain.model
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.painter.Painter

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.domain.model
package ua.acclorite.book_story.domain.model
sealed class NullableBook(val book: Pair<Book, Boolean>?, val fileName: String?) {
class NotNull(book: Pair<Book, Boolean>) : NullableBook(book, null)

View file

@ -1,13 +1,13 @@
package com.acclorite.books_history.domain.model
import android.os.Parcelable
import androidx.compose.runtime.Immutable
import kotlinx.parcelize.Parcelize
import java.util.UUID
@Parcelize
@Immutable
data class StringWithId(
val line: String,
val id: String = UUID.randomUUID().toString()
) : Parcelable
package ua.acclorite.book_story.domain.model
import android.os.Parcelable
import androidx.compose.runtime.Immutable
import kotlinx.parcelize.Parcelize
import java.util.UUID
@Parcelize
@Immutable
data class StringWithId(
val line: String,
val id: String = UUID.randomUUID().toString()
) : Parcelable

View file

@ -1,12 +1,13 @@
package com.acclorite.books_history.domain.repository
package ua.acclorite.book_story.domain.repository
import androidx.datastore.preferences.core.Preferences
import com.acclorite.books_history.data.local.dto.BookEntity
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.model.NullableBook
import com.acclorite.books_history.domain.model.StringWithId
import com.acclorite.books_history.util.Resource
import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.data.local.dto.BookEntity
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.History
import ua.acclorite.book_story.domain.model.NullableBook
import ua.acclorite.book_story.domain.model.StringWithId
import ua.acclorite.book_story.util.Resource
import java.io.File
interface BookRepository {
@ -50,4 +51,17 @@ interface BookRepository {
suspend fun getBookTextFromFile(file: File): Flow<Resource<List<StringWithId>>>
suspend fun getBooksFromFiles(files: List<File>): Flow<Resource<List<NullableBook>>>
suspend fun insertHistory(history: List<History>)
suspend fun getHistory(): Flow<Resource<List<History>>>
suspend fun deleteWholeHistory()
suspend fun deleteBookHistory(bookId: Int)
suspend fun deleteHistory(
history: List<History>
)
}

View file

@ -1,12 +1,14 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import android.annotation.SuppressLint
import androidx.activity.ComponentActivity
import com.acclorite.books_history.domain.repository.BookRepository
import com.acclorite.books_history.util.DataStoreConstants
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.util.DataStoreConstants
import java.util.Locale
import javax.inject.Inject
class ChangeLanguage @Inject constructor(private val repository: BookRepository) {
@SuppressLint("AppBundleLocaleChanges")
suspend fun execute(language: String, activity: ComponentActivity) {
val config = activity.resources.configuration
val resources = activity.resources

View file

@ -0,0 +1,17 @@
package ua.acclorite.book_story.domain.use_case
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class DeleteBooks @Inject constructor(private val repository: BookRepository) {
suspend fun execute(books: List<Book>) {
repository.deleteBooks(books)
books.forEach {
if (it.id != null) {
repository.deleteBookHistory(it.id)
}
}
}
}

View file

@ -0,0 +1,12 @@
package ua.acclorite.book_story.domain.use_case
import ua.acclorite.book_story.domain.model.History
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class DeleteHistory @Inject constructor(private val repository: BookRepository) {
suspend fun execute(history: List<History>) {
repository.deleteHistory(history)
}
}

View file

@ -0,0 +1,11 @@
package ua.acclorite.book_story.domain.use_case
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class DeleteWholeHistory @Inject constructor(private val repository: BookRepository) {
suspend fun execute() {
repository.deleteWholeHistory()
}
}

View file

@ -1,7 +1,7 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.repository.BookRepository
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class FastGetBooks @Inject constructor(private val repository: BookRepository) {

View file

@ -1,9 +1,9 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.repository.BookRepository
import com.acclorite.books_history.util.Resource
import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.util.Resource
import javax.inject.Inject
class GetBooks @Inject constructor(private val repository: BookRepository) {

View file

@ -1,9 +1,9 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import com.acclorite.books_history.domain.model.NullableBook
import com.acclorite.books_history.domain.repository.BookRepository
import com.acclorite.books_history.util.Resource
import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.domain.model.NullableBook
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.util.Resource
import java.io.File
import javax.inject.Inject

View file

@ -1,8 +1,8 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import androidx.datastore.preferences.core.Preferences
import com.acclorite.books_history.domain.repository.BookRepository
import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class GetDatastore @Inject constructor(private val repository: BookRepository) {

View file

@ -1,8 +1,8 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import com.acclorite.books_history.domain.repository.BookRepository
import com.acclorite.books_history.util.Resource
import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.util.Resource
import java.io.File
import javax.inject.Inject

View file

@ -0,0 +1,14 @@
package ua.acclorite.book_story.domain.use_case
import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.domain.model.History
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.util.Resource
import javax.inject.Inject
class GetHistory @Inject constructor(private val repository: BookRepository) {
suspend fun execute(): Flow<Resource<List<History>>> {
return repository.getHistory()
}
}

View file

@ -1,9 +1,9 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import com.acclorite.books_history.domain.model.StringWithId
import com.acclorite.books_history.domain.repository.BookRepository
import com.acclorite.books_history.util.Resource
import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.domain.model.StringWithId
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.util.Resource
import java.io.File
import javax.inject.Inject

View file

@ -1,7 +1,7 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.repository.BookRepository
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class InsertBooks @Inject constructor(private val repository: BookRepository) {

View file

@ -0,0 +1,11 @@
package ua.acclorite.book_story.domain.use_case
import ua.acclorite.book_story.domain.model.History
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class InsertHistory @Inject constructor(private val repository: BookRepository) {
suspend fun execute(history: List<History>) {
repository.insertHistory(history)
}
}

View file

@ -1,7 +1,7 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import androidx.datastore.preferences.core.Preferences
import com.acclorite.books_history.domain.repository.BookRepository
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class SetDatastore @Inject constructor(private val repository: BookRepository) {

View file

@ -1,7 +1,7 @@
package com.acclorite.books_history.domain.use_case
package ua.acclorite.book_story.domain.use_case
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.domain.repository.BookRepository
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.repository.BookRepository
import javax.inject.Inject
class UpdateBooks @Inject constructor(private val repository: BookRepository) {

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation
package ua.acclorite.book_story.presentation
import android.annotation.SuppressLint
import androidx.activity.ComponentActivity
@ -20,7 +20,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.acclorite.books_history.ui.Transitions
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -29,6 +28,7 @@ import dagger.hilt.android.lifecycle.withCreationCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import ua.acclorite.book_story.ui.Transitions
private const val CURRENT_SCREEN = "current_screen"
@ -155,8 +155,8 @@ class Navigator @AssistedInject constructor(
@Composable
fun composable(
screen: Screen,
enterAnim: EnterTransition = Transitions.DefaultTransitionIn,
exitAnim: ExitTransition = Transitions.DefaultTransitionOut,
enterAnim: EnterTransition = Transitions.FadeTransitionIn,
exitAnim: ExitTransition = Transitions.FadeTransitionOut,
content: @Composable () -> Unit
) {
AnimatedVisibility(

View file

@ -0,0 +1,141 @@
package ua.acclorite.book_story.presentation.components
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.statusBars
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.ui.DefaultTransition
import ua.acclorite.book_story.ui.elevation
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AnimatedTopAppBar(
containerColor: Color = MaterialTheme.colorScheme.surface,
scrolledContainerColor: Color? = MaterialTheme.elevation(),
scrollBehavior: TopAppBarScrollBehavior?,
isTopBarScrolled: Boolean?,
content1Visibility: Boolean? = null,
content1NavigationIcon: @Composable () -> Unit,
content1Title: @Composable () -> Unit,
content1Actions: @Composable RowScope.() -> Unit,
content2Visibility: Boolean? = null,
content2NavigationIcon: @Composable () -> Unit = {},
content2Title: @Composable () -> Unit = {},
content2Actions: @Composable RowScope.() -> Unit = {},
content3Visibility: Boolean? = null,
content3NavigationIcon: @Composable () -> Unit = {},
content3Title: @Composable () -> Unit = {},
content3Actions: @Composable RowScope.() -> Unit = {}
) {
Box(modifier = Modifier.fillMaxWidth()) {
if ((scrollBehavior != null || isTopBarScrolled != null) && scrolledContainerColor != null) {
val fraction by remember {
derivedStateOf {
scrollBehavior?.state?.overlappedFraction ?: 0f
}
}
val isScrolled = if (scrollBehavior != null) {
fraction > 0.01f
} else isTopBarScrolled ?: false
val color = if (isScrolled) scrolledContainerColor else containerColor
val animatedColor by animateColorAsState(
targetValue = color,
animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
label = "TopAppBar color animation"
)
val statusBarPadding = with(LocalDensity.current) {
WindowInsets.statusBars.getTop(LocalDensity.current).toDp()
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(64.dp + statusBarPadding)
.background(
animatedColor
)
)
}
DefaultTransition(visible = content1Visibility ?: true) {
TopAppBar(
navigationIcon = content1NavigationIcon,
title = content1Title,
actions = content1Actions,
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent
)
)
}
if (content2Visibility != null) {
DefaultTransition(visible = content2Visibility) {
TopAppBar(
navigationIcon = content2NavigationIcon,
title = content2Title,
actions = content2Actions,
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent
)
)
}
}
if (content3Visibility != null) {
DefaultTransition(visible = content3Visibility) {
TopAppBar(
navigationIcon = content3NavigationIcon,
title = content3Title,
actions = content3Actions,
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent
)
)
}
}
}
}

View file

@ -1,17 +1,20 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.acclorite.books_history.R
import com.acclorite.books_history.domain.model.NavigationBarItem
import com.acclorite.books_history.presentation.Navigator
import com.acclorite.books_history.presentation.Screen
import com.acclorite.books_history.ui.elevation
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.NavigationBarItem
import ua.acclorite.book_story.presentation.Navigator
import ua.acclorite.book_story.presentation.Screen
import ua.acclorite.book_story.ui.elevation
/**
* Bottom navigation bar, uses default [NavigationBar].
@ -20,7 +23,15 @@ import com.acclorite.books_history.ui.elevation
fun BottomNavigationBar(
navigator: Navigator
) {
val currentScreen by navigator.getCurrentScreen().collectAsState()
var currentScreen: Screen? by remember { mutableStateOf(null) }
LaunchedEffect(Unit) {
navigator.getCurrentScreen().collect {
if (it == Screen.LIBRARY || it == Screen.HISTORY || it == Screen.BROWSE) {
currentScreen = it
}
}
}
NavigationBar(
containerColor = MaterialTheme.elevation()

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.size
@ -11,7 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.domain.model.NavigationBarItem
import ua.acclorite.book_story.domain.model.NavigationBarItem
/**
* Bottom Navigation Bar Item, uses default [NavigationBarItem].

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.ui.elevation
import ua.acclorite.book_story.ui.elevation
@Composable
fun CustomCheckbox(selected: Boolean) {

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
@ -31,9 +31,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.DialogWindowProvider
import com.acclorite.books_history.R
import com.acclorite.books_history.ui.ElevationDefaults
import com.acclorite.books_history.ui.elevation
import ua.acclorite.book_story.R
import ua.acclorite.book_story.ui.ElevationDefaults
import ua.acclorite.book_story.ui.elevation
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -100,6 +100,8 @@ fun CustomDialogWithContent(
else Alignment.Start
)
.padding(horizontal = 24.dp),
textAlign = if (drawableIcon != null || imageVectorIcon != null) TextAlign.Center
else TextAlign.Start,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface
)

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
@ -32,9 +32,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.DialogWindowProvider
import com.acclorite.books_history.R
import com.acclorite.books_history.ui.ElevationDefaults
import com.acclorite.books_history.ui.elevation
import ua.acclorite.book_story.R
import ua.acclorite.book_story.ui.ElevationDefaults
import ua.acclorite.book_story.ui.elevation
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -101,6 +101,8 @@ fun CustomDialogWithLazyColumn(
else Alignment.Start
)
.padding(horizontal = 24.dp),
textAlign = if (drawableIcon != null || imageVectorIcon != null) TextAlign.Center
else TextAlign.Start,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface
)

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.size

View file

@ -0,0 +1,49 @@
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.DismissValue
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.SwipeToDismiss
import androidx.compose.material.rememberDismissState
import androidx.compose.material3.Snackbar
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun CustomSnackbar(snackbarState: SnackbarHostState) {
val dismissState = rememberDismissState { value ->
if (value != DismissValue.Default) {
snackbarState.currentSnackbarData?.dismiss()
true
} else false
}
LaunchedEffect(dismissState.currentValue) {
if (dismissState.currentValue != DismissValue.Default) {
dismissState.reset()
}
}
SwipeToDismiss(
modifier = Modifier
.padding(vertical = 4.dp)
.fillMaxWidth(),
state = dismissState,
background = {}
) {
SnackbarHost(
hostState = snackbarState,
snackbar = { data ->
Snackbar(
data
)
}
)
}
}

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
@ -20,9 +20,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.R
import com.acclorite.books_history.presentation.Navigator
import com.acclorite.books_history.presentation.Screen
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.Navigator
import ua.acclorite.book_story.presentation.Screen
@Composable
fun MoreDropDown(navigator: Navigator) {

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.components
package ua.acclorite.book_story.presentation.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.data
package ua.acclorite.book_story.presentation.data
fun String.removeTrailingZero(): String {
if (!this.contains('.'))

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.data
package ua.acclorite.book_story.presentation.data
import androidx.activity.ComponentActivity

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.data
package ua.acclorite.book_story.presentation.data
import android.os.Build
import androidx.activity.ComponentActivity
@ -6,15 +6,6 @@ import androidx.compose.ui.graphics.Color
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.acclorite.books_history.domain.use_case.ChangeLanguage
import com.acclorite.books_history.domain.use_case.GetDatastore
import com.acclorite.books_history.domain.use_case.SetDatastore
import com.acclorite.books_history.ui.DarkTheme
import com.acclorite.books_history.ui.Theme
import com.acclorite.books_history.ui.toDarkTheme
import com.acclorite.books_history.ui.toTheme
import com.acclorite.books_history.util.Constants
import com.acclorite.books_history.util.DataStoreConstants
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
@ -25,6 +16,15 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import ua.acclorite.book_story.domain.use_case.ChangeLanguage
import ua.acclorite.book_story.domain.use_case.GetDatastore
import ua.acclorite.book_story.domain.use_case.SetDatastore
import ua.acclorite.book_story.ui.DarkTheme
import ua.acclorite.book_story.ui.Theme
import ua.acclorite.book_story.ui.toDarkTheme
import ua.acclorite.book_story.ui.toTheme
import ua.acclorite.book_story.util.Constants
import ua.acclorite.book_story.util.DataStoreConstants
import java.util.Locale
import javax.inject.Inject

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info
package ua.acclorite.book_story.presentation.screens.book_info
import android.widget.Toast
import androidx.activity.ComponentActivity
@ -33,7 +33,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -51,34 +50,39 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.acclorite.books_history.R
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.presentation.Argument
import com.acclorite.books_history.presentation.Navigator
import com.acclorite.books_history.presentation.Screen
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoBackground
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoChangeCoverBottomSheet
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoDeleteDialog
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoDescriptionSection
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoDetailsBottomSheet
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoInfoSection
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoMoreDropDown
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoMoveDialog
import com.acclorite.books_history.presentation.screens.book_info.components.BookInfoStatisticSection
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoEvent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoViewModel
import com.acclorite.books_history.presentation.screens.library.data.LibraryEvent
import com.acclorite.books_history.presentation.screens.library.data.LibraryViewModel
import com.acclorite.books_history.ui.DefaultTransition
import com.acclorite.books_history.ui.Transitions
import com.acclorite.books_history.ui.elevation
import com.acclorite.books_history.util.Constants
import dagger.hilt.android.lifecycle.withCreationCallback
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.presentation.Argument
import ua.acclorite.book_story.presentation.Navigator
import ua.acclorite.book_story.presentation.Screen
import ua.acclorite.book_story.presentation.components.AnimatedTopAppBar
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoBackground
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoChangeCoverBottomSheet
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoDeleteDialog
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoDescriptionSection
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoDetailsBottomSheet
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoInfoSection
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoMoreDropDown
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoMoveDialog
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoStatisticSection
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
import ua.acclorite.book_story.ui.DefaultTransition
import ua.acclorite.book_story.ui.Transitions
import ua.acclorite.book_story.ui.elevation
import ua.acclorite.book_story.util.Constants
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BookInfoScreen(
libraryViewModel: LibraryViewModel = hiltViewModel(),
browseViewModel: BrowseViewModel = hiltViewModel(),
historyViewModel: HistoryViewModel = hiltViewModel(),
navigator: Navigator
) {
val context = LocalContext.current
@ -120,7 +124,11 @@ fun BookInfoScreen(
}
if (state.showChangeCoverBottomSheet) {
BookInfoChangeCoverBottomSheet(libraryViewModel = libraryViewModel, viewModel = viewModel)
BookInfoChangeCoverBottomSheet(
libraryViewModel = libraryViewModel,
historyViewModel = historyViewModel,
viewModel = viewModel
)
}
if (state.showDetailsBottomSheet) {
BookInfoDetailsBottomSheet(viewModel = viewModel)
@ -128,6 +136,8 @@ fun BookInfoScreen(
if (state.showDeleteDialog) {
BookInfoDeleteDialog(
libraryViewModel = libraryViewModel,
browseViewModel = browseViewModel,
historyViewModel = historyViewModel,
viewModel = viewModel,
navigator = navigator
)
@ -147,9 +157,13 @@ fun BookInfoScreen(
.windowInsetsPadding(WindowInsets.navigationBars),
containerColor = MaterialTheme.colorScheme.surface,
topBar = {
TopAppBar(
AnimatedTopAppBar(
containerColor = Color.Transparent,
scrolledContainerColor = MaterialTheme.elevation(),
scrollBehavior = scrollBehavior,
navigationIcon = {
isTopBarScrolled = null,
content1NavigationIcon = {
IconButton(onClick = {
navigator.navigateBack()
}) {
@ -160,7 +174,7 @@ fun BookInfoScreen(
)
}
},
title = {
content1Title = {
DefaultTransition(visible = firstVisibleItemIndex > 0) {
Text(
state.book.title,
@ -171,7 +185,7 @@ fun BookInfoScreen(
)
}
},
actions = {
content1Actions = {
Box {
DefaultTransition(
visible = !state.editTitle
@ -214,11 +228,7 @@ fun BookInfoScreen(
}
}
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = MaterialTheme.elevation()
)
}
)
}
) { paddingValues ->

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.fillMaxWidth

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
@ -22,18 +22,21 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.R
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoEvent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoViewModel
import com.acclorite.books_history.presentation.screens.library.data.LibraryEvent
import com.acclorite.books_history.presentation.screens.library.data.LibraryViewModel
import com.acclorite.books_history.ui.ElevationDefaults
import com.acclorite.books_history.ui.elevation
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
import ua.acclorite.book_story.ui.ElevationDefaults
import ua.acclorite.book_story.ui.elevation
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BookInfoChangeCoverBottomSheet(
libraryViewModel: LibraryViewModel,
historyViewModel: HistoryViewModel,
viewModel: BookInfoViewModel
) {
val state by viewModel.state.collectAsState()
@ -50,6 +53,7 @@ fun BookInfoChangeCoverBottomSheet(
context,
refreshList = {
libraryViewModel.onEvent(LibraryEvent.OnLoadList)
historyViewModel.onEvent(HistoryEvent.OnLoadList)
}
)
)
@ -91,6 +95,7 @@ fun BookInfoChangeCoverBottomSheet(
viewModel.onEvent(BookInfoEvent.OnDeleteCover(
refreshList = {
libraryViewModel.onEvent(LibraryEvent.OnLoadList)
historyViewModel.onEvent(HistoryEvent.OnLoadList)
}
))
Toast.makeText(

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import android.widget.Toast
import androidx.compose.material.icons.Icons
@ -6,17 +6,23 @@ import androidx.compose.material.icons.outlined.DeleteOutline
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.acclorite.books_history.R
import com.acclorite.books_history.presentation.Navigator
import com.acclorite.books_history.presentation.components.CustomDialogWithContent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoEvent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoViewModel
import com.acclorite.books_history.presentation.screens.library.data.LibraryEvent
import com.acclorite.books_history.presentation.screens.library.data.LibraryViewModel
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.Navigator
import ua.acclorite.book_story.presentation.components.CustomDialogWithContent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
@Composable
fun BookInfoDeleteDialog(
libraryViewModel: LibraryViewModel,
browseViewModel: BrowseViewModel,
historyViewModel: HistoryViewModel,
viewModel: BookInfoViewModel,
navigator: Navigator
) {
@ -37,9 +43,9 @@ fun BookInfoDeleteDialog(
BookInfoEvent.OnDeleteBook(
navigator = navigator,
refreshList = {
libraryViewModel.onEvent(
LibraryEvent.OnLoadList
)
libraryViewModel.onEvent(LibraryEvent.OnLoadList)
browseViewModel.onEvent(BrowseEvent.OnLoadList)
historyViewModel.onEvent(HistoryEvent.OnLoadList)
}
)
)

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
@ -11,8 +11,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.R
import com.acclorite.books_history.domain.model.Book
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Book
@Composable
fun BookInfoDescriptionSection(book: Book) {

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import android.widget.Toast
import androidx.compose.foundation.layout.Spacer
@ -16,11 +16,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.R
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoEvent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoViewModel
import com.acclorite.books_history.ui.ElevationDefaults
import com.acclorite.books_history.ui.elevation
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
import ua.acclorite.book_story.ui.ElevationDefaults
import ua.acclorite.book_story.ui.elevation
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
@ -41,10 +41,10 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoEvent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoViewModel
import com.acclorite.books_history.ui.elevation
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
import ua.acclorite.book_story.ui.elevation
@OptIn(ExperimentalFoundationApi::class)
@Composable
@ -117,8 +117,8 @@ fun BookInfoInfoSection(viewModel: BookInfoViewModel, book: Book) {
)
} else {
BasicTextField(
maxLines = 4,
value = state.titleValue,
singleLine = true,
textStyle = TextStyle(
color = MaterialTheme.colorScheme.onSurface,
fontSize = MaterialTheme.typography.headlineSmall.fontSize,

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
@ -18,10 +18,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.R
import com.acclorite.books_history.presentation.components.CustomDropDownMenuItem
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoEvent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoViewModel
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.components.CustomDropDownMenuItem
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
@Composable
fun BookInfoMoreDropDown(viewModel: BookInfoViewModel) {

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import android.widget.Toast
import androidx.compose.foundation.lazy.items
@ -11,15 +11,15 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.acclorite.books_history.R
import com.acclorite.books_history.domain.model.Category
import com.acclorite.books_history.presentation.Navigator
import com.acclorite.books_history.presentation.components.CustomDialogWithLazyColumn
import com.acclorite.books_history.presentation.components.SelectableDialogItem
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoEvent
import com.acclorite.books_history.presentation.screens.book_info.data.BookInfoViewModel
import com.acclorite.books_history.presentation.screens.library.data.LibraryEvent
import com.acclorite.books_history.presentation.screens.library.data.LibraryViewModel
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Category
import ua.acclorite.book_story.presentation.Navigator
import ua.acclorite.book_story.presentation.components.CustomDialogWithLazyColumn
import ua.acclorite.book_story.presentation.components.SelectableDialogItem
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
@Composable
fun BookInfoMoveDialog(

View file

@ -1,4 +1,4 @@
package com.acclorite.books_history.presentation.screens.book_info.components
package ua.acclorite.book_story.presentation.screens.book_info.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@ -14,10 +14,10 @@ import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.acclorite.books_history.R
import com.acclorite.books_history.domain.model.Book
import com.acclorite.books_history.presentation.data.removeDigits
import com.acclorite.books_history.presentation.data.removeTrailingZero
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.presentation.data.removeDigits
import ua.acclorite.book_story.presentation.data.removeTrailingZero
@Composable
fun BookInfoStatisticSection(book: Book) {

Some files were not shown because too many files have changed in this diff Show more