v1.0.47 (#279)
* Add performance and stylus debugging logs * Refactor and decouple UI models from `MainViewModel` * Refactor library state management and projection logic * Implement desktop shell using Compose Multiplatform * Implement desktop shell using Compose Multiplatform * Implement desktop shell using Compose Multiplatform * Introduce ReaderEngine and enhance EPUB reader features in windows app * Move core paginated reader logic to a Kotlin Multiplatform `shared` module and introduce experimental desktop support. * Implement PDF rendering and text extraction for desktop using Pdfium * Add `NonReaderScreens.kt` and UI dependencies * Refactor and centralize library state management and models to improve cross-platform consistency * Implement JSON persistence for desktop library and enhance library management features including shelf CRUD, tagging, and metadata editing * Implement PDF annotation system and enhanced zoom controls for the desktop viewer * Implement WebView-based EPUB rendering for desktop using CEF and embedded resources * Optimize UI state projection, navigation state handling, and main screen pager performance * Implement Bring Your Own Key (BYOK) support for AI features in OSS version * Support Gemini-based Cloud TTS with BYOK support for OSS builds * Refactor table cell image sizing in `PaginatedReader` and improve `MobiParser` native library loading and error handling. * crash fixes * Enhance navigation stability with lifecycle-aware safety checks and update `navigation-compose` to 2.9.6 * Implement dynamic bottom padding for the page info bar to account for device rounded corners * Implement bidirectional jump history navigation and replace the jump-back pill with a dedicated `PdfJumpHistoryBar` * Optimize PDF tiling performance and refine pan-and-fling gesture handling * Implement customizable toolbars with drag-and-drop reordering and placement for PDF and EPUB readers * Updated UI for customize toolbar * Refine drag-and-drop reordering and section assignment for PDF and EPUB reader controls * restructure PDF viewer UI component hierarchy to fix verifier crash * Implement separate text dimming factors for light and dark themes * Synchronize Pdfium access and improve resource lifecycle safety across Kotlin and native layers * Enhance image alignment in paginated and EPUB readers through anchor detection and style-based positioning * Centralize file type resolution logic and implement HTML sanitization during import * Introduce vertical margin customization and configurable progress bar positioning * texture support in epub reader * Enhance TTS session management, progress tracking, and diagnostic logging * Optimize library state projection and folder synchronization performance by refactoring collection lookups and refining metadata extraction logic. * Refine TTS page mapping for PDF and overhaul TTS control UI * Implement natural session completion logic in `TtsPlaybackManager` for cloud tts * Replace Snackbar with `CustomTopBanner` for notifications in `PdfViewerScreen` * Refine TTS playback continuity across PDF pages and improve state management for session transitions * Implement global texture transparency and enhance textured theme support across PDF and EPUB readers. * Update reader themes and improve texture rendering in page animations, EPUB UI, and immersive mode * Add Support Project screen * Optimize library performance via projection caching, batch database updates, and scoped folder synchronization. * Enhance folder synchronization with fallback query mechanisms and refactor annotation sidecar importing logic * Bump version to 1.0.47 (51)
This commit is contained in:
parent
f42de6b462
commit
d7a9cae9e1
126 changed files with 15287 additions and 3154 deletions
220
app/src/main/java/com/aryan/reader/SharedModelMappers.kt
Normal file
220
app/src/main/java/com/aryan/reader/SharedModelMappers.kt
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
package com.aryan.reader
|
||||
|
||||
import com.aryan.reader.data.BookShelfCrossRef
|
||||
import com.aryan.reader.data.BookTagCrossRef
|
||||
import com.aryan.reader.data.RecentFileItem
|
||||
import com.aryan.reader.data.ShelfEntity
|
||||
import com.aryan.reader.data.TagEntity
|
||||
import com.aryan.reader.shared.AddBooksSource as SharedAddBooksSource
|
||||
import com.aryan.reader.shared.AppContrastOption as SharedAppContrastOption
|
||||
import com.aryan.reader.shared.AppThemeMode as SharedAppThemeMode
|
||||
import com.aryan.reader.shared.BannerMessage as SharedBannerMessage
|
||||
import com.aryan.reader.shared.BookItem as SharedBookItem
|
||||
import com.aryan.reader.shared.BookShelfRef as SharedBookShelfRef
|
||||
import com.aryan.reader.shared.CustomAppTheme as SharedCustomAppTheme
|
||||
import com.aryan.reader.shared.FileType as SharedFileType
|
||||
import com.aryan.reader.shared.LibraryFilters as SharedLibraryFilters
|
||||
import com.aryan.reader.shared.ReadStatusFilter as SharedReadStatusFilter
|
||||
import com.aryan.reader.shared.RenderMode as SharedRenderMode
|
||||
import com.aryan.reader.shared.SharedLibraryProjectionInput
|
||||
import com.aryan.reader.shared.SharedReaderScreenState
|
||||
import com.aryan.reader.shared.ShelfRecord
|
||||
import com.aryan.reader.shared.SortOrder as SharedSortOrder
|
||||
import com.aryan.reader.shared.SyncedFolder as SharedSyncedFolder
|
||||
import com.aryan.reader.shared.Tag as SharedTag
|
||||
|
||||
fun RecentFileItem.toSharedBookItem(): SharedBookItem {
|
||||
return SharedBookItem(
|
||||
id = bookId,
|
||||
path = uriString,
|
||||
type = type.toSharedFileType(),
|
||||
displayName = customName ?: displayName,
|
||||
timestamp = timestamp,
|
||||
title = title,
|
||||
author = author,
|
||||
progressPercentage = progressPercentage,
|
||||
isRecent = isRecent,
|
||||
fileSize = fileSize,
|
||||
sourceFolder = sourceFolderUri,
|
||||
seriesName = seriesName,
|
||||
seriesIndex = seriesIndex,
|
||||
tags = tags.map { it.toSharedTag() }
|
||||
)
|
||||
}
|
||||
|
||||
fun TagEntity.toSharedTag(): SharedTag {
|
||||
return SharedTag(
|
||||
id = id,
|
||||
name = name,
|
||||
color = color
|
||||
)
|
||||
}
|
||||
|
||||
fun ShelfEntity.toSharedShelfRecord(): ShelfRecord {
|
||||
return ShelfRecord(
|
||||
id = id,
|
||||
name = name,
|
||||
isSmart = isSmart,
|
||||
smartRulesJson = smartRulesJson
|
||||
)
|
||||
}
|
||||
|
||||
fun BookShelfCrossRef.toSharedBookShelfRef(): SharedBookShelfRef {
|
||||
return SharedBookShelfRef(
|
||||
bookId = bookId,
|
||||
shelfId = shelfId,
|
||||
addedAt = addedAt
|
||||
)
|
||||
}
|
||||
|
||||
fun ReaderScreenState.toSharedReaderScreenState(
|
||||
rawBooks: List<RecentFileItem> = rawLibraryFiles,
|
||||
dbTags: List<TagEntity> = allTags
|
||||
): SharedReaderScreenState {
|
||||
return SharedReaderScreenState(
|
||||
selectedBookId = selectedBookId,
|
||||
selectedUriString = selectedPdfUri?.toString() ?: selectedEpubUri?.toString(),
|
||||
selectedFileType = selectedFileType?.toSharedFileType(),
|
||||
isLoading = isLoading,
|
||||
errorMessage = errorMessage,
|
||||
renderMode = renderMode.toSharedRenderMode(),
|
||||
sortOrder = sortOrder.toSharedSortOrder(),
|
||||
viewingShelfId = viewingShelfId,
|
||||
isAddingBooksToShelf = isAddingBooksToShelf,
|
||||
showCreateShelfDialog = showCreateShelfDialog,
|
||||
mainScreenStartPage = mainScreenStartPage,
|
||||
libraryScreenStartPage = libraryScreenStartPage,
|
||||
showRenameShelfDialogFor = showRenameShelfDialogFor,
|
||||
showDeleteShelfDialogFor = showDeleteShelfDialogFor,
|
||||
addBooksSource = addBooksSource.toSharedAddBooksSource(),
|
||||
booksSelectedForAdding = booksSelectedForAdding,
|
||||
selectedBookIds = contextualActionItems.mapTo(mutableSetOf()) { it.bookId },
|
||||
selectedShelfIds = contextualActionShelfIds,
|
||||
isProUser = isProUser,
|
||||
credits = credits,
|
||||
isSyncEnabled = isSyncEnabled,
|
||||
isFolderSyncEnabled = isFolderSyncEnabled,
|
||||
bannerMessage = bannerMessage?.toSharedBannerMessage(),
|
||||
downloadingBookIds = downloadingBookIds,
|
||||
uploadingBookIds = uploadingBookIds,
|
||||
syncedFolders = syncedFolders.map { it.toSharedSyncedFolder() },
|
||||
lastFolderScanTime = lastFolderScanTime,
|
||||
hasUnreadFeedback = hasUnreadFeedback,
|
||||
searchQuery = searchQuery,
|
||||
isSearchActive = isSearchActive,
|
||||
isRefreshing = isRefreshing,
|
||||
reflowProgress = reflowProgress,
|
||||
recentBooks = recentFiles.map { it.toSharedBookItem() },
|
||||
libraryBooks = allRecentFiles.map { it.toSharedBookItem() },
|
||||
rawLibraryBooks = rawBooks.map { it.toSharedBookItem() },
|
||||
pinnedHomeBookIds = pinnedHomeBookIds,
|
||||
pinnedLibraryBookIds = pinnedLibraryBookIds,
|
||||
libraryFilters = libraryFilters.toSharedLibraryFilters(),
|
||||
recentFilesLimit = recentFilesLimit,
|
||||
isTabsEnabled = isTabsEnabled,
|
||||
openTabIds = openTabIds,
|
||||
openTabs = openTabs.map { it.toSharedBookItem() },
|
||||
activeTabBookId = activeTabBookId,
|
||||
showExternalFileSavePromptFor = showExternalFileSavePromptFor,
|
||||
externalFileBehavior = externalFileBehavior,
|
||||
useStrictFileFilter = useStrictFileFilter,
|
||||
appThemeMode = appThemeMode.toSharedAppThemeMode(),
|
||||
appContrastOption = appContrastOption.toSharedAppContrastOption(),
|
||||
appTextDimFactorLight = appTextDimFactorLight,
|
||||
appTextDimFactorDark = appTextDimFactorDark,
|
||||
appSeedColor = appSeedColor,
|
||||
customAppThemes = customAppThemes.map { it.toSharedCustomAppTheme() },
|
||||
allTags = dbTags.map { it.toSharedTag() },
|
||||
showTagSelectionDialogFor = showTagSelectionDialogFor
|
||||
)
|
||||
}
|
||||
|
||||
fun ReaderScreenState.toSharedLibraryProjectionInput(
|
||||
recentFilesFromDb: List<RecentFileItem>,
|
||||
dbShelves: List<ShelfEntity>,
|
||||
shelfRefs: List<BookShelfCrossRef>,
|
||||
dbTags: List<TagEntity>,
|
||||
tagRefs: List<BookTagCrossRef>
|
||||
): SharedLibraryProjectionInput {
|
||||
val tagsById = dbTags.associateBy { it.id }
|
||||
val bookTagsMap = tagRefs.groupBy { it.bookId }.mapValues { entry ->
|
||||
entry.value.mapNotNull { tagsById[it.tagId] }
|
||||
}
|
||||
val taggedBooks = recentFilesFromDb.map { item ->
|
||||
item.copy(tags = bookTagsMap[item.bookId].orEmpty())
|
||||
}
|
||||
return SharedLibraryProjectionInput(
|
||||
state = toSharedReaderScreenState(
|
||||
rawBooks = taggedBooks,
|
||||
dbTags = dbTags
|
||||
),
|
||||
booksFromStore = taggedBooks
|
||||
.filterNot { it.bookId.endsWith("_reflow") }
|
||||
.map { it.toSharedBookItem() },
|
||||
shelfRecords = dbShelves.map { it.toSharedShelfRecord() },
|
||||
shelfRefs = shelfRefs.map { it.toSharedBookShelfRef() },
|
||||
tags = dbTags.map { it.toSharedTag() }
|
||||
)
|
||||
}
|
||||
|
||||
fun FileType.toSharedFileType(): SharedFileType {
|
||||
return runCatching { SharedFileType.valueOf(name) }.getOrDefault(SharedFileType.UNKNOWN)
|
||||
}
|
||||
|
||||
private fun RenderMode.toSharedRenderMode(): SharedRenderMode {
|
||||
return SharedRenderMode.valueOf(name)
|
||||
}
|
||||
|
||||
private fun AddBooksSource.toSharedAddBooksSource(): SharedAddBooksSource {
|
||||
return SharedAddBooksSource.valueOf(name)
|
||||
}
|
||||
|
||||
private fun SortOrder.toSharedSortOrder(): SharedSortOrder {
|
||||
return SharedSortOrder.valueOf(name)
|
||||
}
|
||||
|
||||
private fun ReadStatusFilter.toSharedReadStatusFilter(): SharedReadStatusFilter {
|
||||
return SharedReadStatusFilter.valueOf(name)
|
||||
}
|
||||
|
||||
private fun LibraryFilters.toSharedLibraryFilters(): SharedLibraryFilters {
|
||||
return SharedLibraryFilters(
|
||||
fileTypes = fileTypes.mapTo(mutableSetOf()) { it.toSharedFileType() },
|
||||
sourceFolders = sourceFolders,
|
||||
readStatus = readStatus.toSharedReadStatusFilter(),
|
||||
tagIds = tagIds
|
||||
)
|
||||
}
|
||||
|
||||
private fun SyncedFolder.toSharedSyncedFolder(): SharedSyncedFolder {
|
||||
return SharedSyncedFolder(
|
||||
uriString = uriString,
|
||||
name = name,
|
||||
lastScanTime = lastScanTime,
|
||||
allowedFileTypes = allowedFileTypes.mapTo(mutableSetOf()) { it.toSharedFileType() }
|
||||
)
|
||||
}
|
||||
|
||||
private fun BannerMessage.toSharedBannerMessage(): SharedBannerMessage {
|
||||
return SharedBannerMessage(
|
||||
message = message,
|
||||
isError = isError,
|
||||
isPersistent = isPersistent
|
||||
)
|
||||
}
|
||||
|
||||
private fun AppThemeMode.toSharedAppThemeMode(): SharedAppThemeMode {
|
||||
return SharedAppThemeMode.valueOf(name)
|
||||
}
|
||||
|
||||
private fun AppContrastOption.toSharedAppContrastOption(): SharedAppContrastOption {
|
||||
return SharedAppContrastOption.valueOf(name)
|
||||
}
|
||||
|
||||
private fun CustomAppTheme.toSharedCustomAppTheme(): SharedCustomAppTheme {
|
||||
return SharedCustomAppTheme(
|
||||
id = id,
|
||||
name = name,
|
||||
seedColor = seedColor
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue