Skip to content

Commit

Permalink
PDF search.
Browse files Browse the repository at this point in the history
Upping compose compile version to 1.5.7
Upping kotlin gradle plugin.
  • Loading branch information
Dima-Android committed Oct 4, 2024
1 parent 417836d commit 30d60d5
Show file tree
Hide file tree
Showing 16 changed files with 528 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.zotero.android.pdf.annotation.data.PdfAnnotationArgs
import org.zotero.android.pdf.annotationmore.data.PdfAnnotationMoreArgs
import org.zotero.android.pdf.annotationmore.editpage.data.PdfAnnotationEditPageArgs
import org.zotero.android.pdf.colorpicker.data.PdfReaderColorPickerArgs
import org.zotero.android.pdf.reader.pdfsearch.data.PdfReaderSearchArgs
import org.zotero.android.pdf.settings.data.PdfSettingsArgs
import org.zotero.android.pdffilter.data.PdfFilterArgs
import org.zotero.android.screens.addnote.data.AddOrEditNoteArgs
Expand All @@ -19,7 +20,6 @@ import org.zotero.android.screens.mediaviewer.video.VideoPlayerArgs
import org.zotero.android.screens.share.sharecollectionpicker.data.ShareCollectionPickerArgs
import org.zotero.android.screens.sortpicker.data.SortPickerArgs
import org.zotero.android.screens.tagpicker.data.TagPickerArgs
import org.zotero.android.uicomponents.addbyidentifier.data.AddByIdentifierPickerArgs
import org.zotero.android.uicomponents.singlepicker.SinglePickerArgs

object ScreenArguments {
Expand All @@ -43,5 +43,5 @@ object ScreenArguments {
lateinit var pdfAnnotationEditPageArgs: PdfAnnotationEditPageArgs
lateinit var pdfReaderColorPickerArgs: PdfReaderColorPickerArgs
lateinit var shareCollectionPickerArgs: ShareCollectionPickerArgs
lateinit var addByIdentifierPickerArgs: AddByIdentifierPickerArgs
lateinit var pdfReaderSearchArgs: PdfReaderSearchArgs
}
30 changes: 30 additions & 0 deletions app/src/main/java/org/zotero/android/pdf/reader/PdfReaderModes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import androidx.compose.animation.ContentTransform
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.with
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
Expand All @@ -23,6 +25,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import org.zotero.android.architecture.ui.CustomLayoutSize
import org.zotero.android.pdf.reader.pdfsearch.PdfReaderSearchScreen
import org.zotero.android.pdf.reader.sidebar.PdfReaderSidebar
import org.zotero.android.pdf.reader.sidebar.SidebarDivider
import org.zotero.android.uicomponents.theme.CustomTheme
Expand Down Expand Up @@ -113,6 +116,21 @@ internal fun PdfReaderPhoneMode(
}
}
}
AnimatedContent(targetState = viewState.showPdfSearch, transitionSpec = {
createPdfSearchTransitionSpec()
}, label = "") { showScreen ->
if (showScreen) {
Column(
modifier = Modifier
.fillMaxSize()
.background(CustomTheme.colors.pdfAnnotationsFormBackground)
) {
PdfReaderSearchScreen(
onBack = vMInterface::hidePdfSearch
)
}
}
}
}
}

Expand All @@ -127,3 +145,15 @@ private fun AnimatedContentTransitionScope<Boolean>.createSidebarTransitionSpec(
sizeAnimationSpec = { _, _ -> tween() }
))
}

private fun AnimatedContentTransitionScope<Boolean>.createPdfSearchTransitionSpec(): ContentTransform {
val intOffsetSpec = tween<IntOffset>()
return (slideInVertically(intOffsetSpec) { it } with
slideOutVertically(intOffsetSpec) { it }).using(
// Disable clipping since the faded slide-in/out should
// be displayed out of bounds.
SizeTransform(
clip = false,
sizeAnimationSpec = { _, _ -> tween() }
))
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,13 @@ internal fun PdfReaderScreen(
onBack = onBack,
onShowHideSideBar = viewModel::toggleSideBar,
toPdfSettings = viewModel::navigateToPdfSettings,
showPdfSearch = viewState.showPdfSearch,
toggleToolbarButton = viewModel::toggleToolbarButton,
isToolbarButtonSelected = viewState.showCreationToolbar,
showSideBar = viewState.showSideBar,
onShowHidePdfSearch = viewModel::togglePdfSearch,
viewModel = viewModel,
viewState = viewState
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.zotero.android.pdf.reader

import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import org.zotero.android.architecture.ui.CustomLayoutSize
import org.zotero.android.pdf.reader.pdfsearch.PdfReaderSearchPopup
import org.zotero.android.uicomponents.Drawables
import org.zotero.android.uicomponents.Strings
import org.zotero.android.uicomponents.icon.IconWithPadding
Expand All @@ -15,10 +18,15 @@ internal fun PdfReaderTopBar(
onBack: () -> Unit,
onShowHideSideBar: () -> Unit,
toPdfSettings: () -> Unit,
onShowHidePdfSearch: () -> Unit,
toggleToolbarButton:() -> Unit,
isToolbarButtonSelected: Boolean,
showSideBar: Boolean,
showPdfSearch: Boolean,
viewState: PdfReaderViewState,
viewModel: PdfReaderVMInterface
) {
val isTablet = CustomLayoutSize.calculateLayoutType().isTablet()
NewCustomTopBar(
backgroundColor = CustomTheme.colors.surface,
leftContainerContent = listOf(
Expand Down Expand Up @@ -46,9 +54,33 @@ internal fun PdfReaderTopBar(
isSelected = isToolbarButtonSelected
)
},
{
if (isTablet) {
Box {
IconWithPadding(
drawableRes = Drawables.search_24px,
onClick = onShowHidePdfSearch
)
if (viewState.showPdfSearch) {
PdfReaderSearchPopup(
viewState = viewState,
viewModel = viewModel,
)
}
}
} else {
ToggleIconWithPadding(
drawableRes = Drawables.search_24px,
onToggle = {
onShowHidePdfSearch()
},
isSelected = showPdfSearch
)
}
},
{
IconWithPadding(drawableRes = Drawables.settings_24px, onClick = toPdfSettings)
}
},
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ interface PdfReaderVMInterface {
fun onOutlineItemChevronTapped(outline: Outline)
fun selectThumbnail(row: PdfReaderThumbnailRow)
fun loadThumbnailPreviews(pageIndex: Int)
fun hidePdfSearch()
fun togglePdfSearch()
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import com.pspdfkit.preferences.PSPDFKitPreferences
import com.pspdfkit.ui.PdfFragment
import com.pspdfkit.ui.PdfUiFragment
import com.pspdfkit.ui.PdfUiFragmentBuilder
import com.pspdfkit.ui.search.SearchResultHighlighter
import com.pspdfkit.ui.special_mode.controller.AnnotationCreationController
import com.pspdfkit.ui.special_mode.controller.AnnotationSelectionController
import com.pspdfkit.ui.special_mode.controller.AnnotationTool
Expand Down Expand Up @@ -135,6 +136,8 @@ import org.zotero.android.pdf.data.PdfAnnotationChanges
import org.zotero.android.pdf.data.PdfReaderArgs
import org.zotero.android.pdf.data.PdfReaderCurrentThemeEventStream
import org.zotero.android.pdf.data.PdfReaderThemeDecider
import org.zotero.android.pdf.reader.pdfsearch.data.PdfReaderSearchArgs
import org.zotero.android.pdf.reader.pdfsearch.data.PdfReaderSearchResultSelected
import org.zotero.android.pdf.reader.sidebar.data.Outline
import org.zotero.android.pdf.reader.sidebar.data.PdfReaderOutlineOptionsWithChildren
import org.zotero.android.pdf.reader.sidebar.data.PdfReaderSliderOptions
Expand Down Expand Up @@ -221,6 +224,8 @@ class PdfReaderViewModel @Inject constructor(

private var toolHistory = mutableListOf<AnnotationTool>()

private lateinit var searchResultHighlighter: SearchResultHighlighter

val screenArgs: PdfReaderArgs by lazy {
val argsEncoded = stateHandle.get<String>(ARG_PDF_SCREEN).require()
navigationParamsMarshaller.decodeObjectFromBase64(argsEncoded)
Expand Down Expand Up @@ -330,8 +335,13 @@ class PdfReaderViewModel @Inject constructor(
)
}
}
}


@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(result: PdfReaderSearchResultSelected) {
searchResultHighlighter.setSearchResults(listOf(result.searchResult))
searchResultHighlighter.setSelectedSearchResult(result.searchResult)
this.pdfUiFragment.pageIndex = result.searchResult.pageIndex
}

private fun update(pdfSettings: PDFSettings) {
Expand Down Expand Up @@ -386,6 +396,8 @@ class PdfReaderViewModel @Inject constructor(
this.containerId = containerId
this.annotationMaxSideSize = annotationMaxSideSize

searchResultHighlighter = SearchResultHighlighter(context)

if (this::pdfUiFragment.isInitialized) {
replaceFragment()
return
Expand Down Expand Up @@ -413,6 +425,7 @@ class PdfReaderViewModel @Inject constructor(
this@PdfReaderViewModel.pdfUiFragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
this@PdfReaderViewModel.pdfFragment = pdfUiFragment.pdfFragment!!
this@PdfReaderViewModel.pdfFragment.addDrawableProvider(searchResultHighlighter)
addDocumentListenerOnInit()
addOnAnnotationCreationModeChangeListener()
setOnPreparePopupToolbarListener()
Expand Down Expand Up @@ -2226,6 +2239,7 @@ class PdfReaderViewModel @Inject constructor(
this@PdfReaderViewModel.pdfUiFragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
this@PdfReaderViewModel.pdfFragment = pdfUiFragment.pdfFragment!!
this@PdfReaderViewModel.pdfFragment.addDrawableProvider(searchResultHighlighter)
addDocumentListener2()
addOnAnnotationCreationModeChangeListener()
setOnPreparePopupToolbarListener()
Expand Down Expand Up @@ -3190,6 +3204,25 @@ class PdfReaderViewModel @Inject constructor(
}

}

override fun togglePdfSearch() {
ScreenArguments.pdfReaderSearchArgs = PdfReaderSearchArgs(
pdfDocument = this.document,
configuration = pdfFragment.configuration
)
updateState {
copy(showPdfSearch = !showPdfSearch)
}

}

override fun hidePdfSearch() {
updateState {
copy(
showPdfSearch = false
)
}
}
}

data class PdfReaderViewState(
Expand Down Expand Up @@ -3229,7 +3262,8 @@ data class PdfReaderViewState(
val outlineSearchTerm: String = "",
val isOutlineEmpty: Boolean = false,
val thumbnailRows: ImmutableList<PdfReaderThumbnailRow> = persistentListOf(),
val selectedThumbnail: PdfReaderThumbnailRow? = null
val selectedThumbnail: PdfReaderThumbnailRow? = null,
val showPdfSearch: Boolean = false,
) : ViewState {

fun isAnnotationSelected(annotationKey: String): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.zotero.android.pdf.reader.pdfsearch

import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.compose.ui.window.PopupProperties
import org.zotero.android.pdf.reader.PdfReaderVMInterface
import org.zotero.android.pdf.reader.PdfReaderViewState
import org.zotero.android.uicomponents.CustomScaffold
import org.zotero.android.uicomponents.theme.CustomTheme

@Composable
internal fun PdfReaderSearchPopup(
viewState: PdfReaderViewState,
viewModel: PdfReaderVMInterface,
) {
val backgroundColor = CustomTheme.colors.cardBackground
Popup(
properties = PopupProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true,
focusable = true
),
onDismissRequest = viewModel::hidePdfSearch,
popupPositionProvider = createPdfReaderSearchPopupPositionProvider(),

) {
CustomScaffold(
modifier = Modifier
.width(350.dp)
.height(530.dp)
.shadow(
elevation = 4.dp,
shape = RoundedCornerShape(16.dp),
),
backgroundColor = backgroundColor,
) {
PdfReaderSearchScreen(onBack = viewModel::hidePdfSearch)
}
}
}

@Composable
private fun createPdfReaderSearchPopupPositionProvider() = object : PopupPositionProvider {
val localDensity = LocalDensity.current
override fun calculatePosition(
anchorBounds: IntRect,
windowSize: IntSize,
layoutDirection: LayoutDirection,
popupContentSize: IntSize
): IntOffset {
val extraXOffset = with(localDensity) {
12.dp.toPx()
}.toInt()
val extraYOffset = with(localDensity) {
8.dp.toPx()
}.toInt()

val xOffset = windowSize.width - popupContentSize.width - extraXOffset
val yOffset = anchorBounds.bottom + extraYOffset

return IntOffset(
x = xOffset,
y = yOffset
)
}
}
Loading

0 comments on commit 30d60d5

Please sign in to comment.