Skip to content

Commit 5bb42e6

Browse files
Migrate pdfkit to nutrient (#1539)
1 parent 69b409b commit 5bb42e6

64 files changed

Lines changed: 1364 additions & 1601 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ dependencies {
160160
implementation(projects.features.languages)
161161
implementation(projects.features.media)
162162
implementation(projects.features.navigationSuite)
163-
implementation(projects.features.pdf)
164163
implementation(projects.features.resource)
165164
implementation(projects.features.settings)
166165
implementation(projects.features.share)
@@ -172,6 +171,7 @@ dependencies {
172171
implementation(projects.services.lessons.impl)
173172
implementation(projects.services.media.impl)
174173
implementation(projects.services.media.ui)
174+
implementation(projects.services.pdf.impl)
175175
implementation(projects.services.prefs.impl)
176176
implementation(projects.services.resources.impl)
177177
implementation(projects.services.storage.impl)

app/src/main/java/com/cryart/sabbathschool/ui/home/HomeActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
package com.cryart.sabbathschool.ui.home
2424

2525
import android.os.Bundle
26-
import androidx.activity.ComponentActivity
2726
import androidx.activity.compose.setContent
2827
import androidx.activity.enableEdgeToEdge
28+
import androidx.appcompat.app.AppCompatActivity
2929
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
3030
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
3131
import androidx.compose.runtime.remember
@@ -47,7 +47,7 @@ import ss.services.circuit.impl.interceptor.AndroidSupportingInterceptor
4747
import javax.inject.Inject
4848

4949
@AndroidEntryPoint
50-
class HomeActivity : ComponentActivity() {
50+
class HomeActivity : AppCompatActivity() {
5151

5252
@Inject
5353
lateinit var circuit: Circuit

common/design/src/main/res/values/colors.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<color name="white">#FFFFFF</color>
3939
<color name="black">#000000</color>
4040
<color name="black_40">#66000000</color>
41+
<color name="sepia">#FDF4E6</color>
4142

4243
<color name="list_divider">#80D7D7D7</color>
4344
<color name="ss_gray_1">#EFEFEF</color>

common/translations/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,5 @@
151151
<string name="ss_action_share">Share</string>
152152
<string name="ss_downloading">Downloading…</string>
153153
<string name="ss_off">Off</string>
154+
<string name="ss_annotations">Annotations</string>
154155
</resources>

features/document/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@ ksp {
4545
}
4646

4747
dependencies {
48+
implementation(libs.androidx.activity.compose)
4849
implementation(libs.coil.compose)
4950
implementation(libs.google.hilt.android)
5051
implementation(libs.joda.time)
5152
implementation(libs.kotlinx.collectionsImmutable)
53+
implementation(libs.nutrient)
5254
implementation(libs.timber)
55+
implementation(projects.common.design)
5356
implementation(projects.common.designCompose)
5457
implementation(projects.common.misc)
5558
implementation(projects.common.translations)

features/document/src/main/kotlin/ss/document/DocumentPresenter.kt

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,11 @@
2323
package ss.document
2424

2525
import androidx.compose.runtime.Composable
26-
import androidx.compose.runtime.LaunchedEffect
2726
import androidx.compose.runtime.getValue
2827
import androidx.compose.runtime.mutableStateOf
2928
import androidx.compose.runtime.rememberCoroutineScope
3029
import androidx.compose.runtime.setValue
31-
import androidx.compose.runtime.snapshots.Snapshot
3230
import androidx.core.net.toUri
33-
import app.ss.models.PDFAux
3431
import app.ss.models.media.AudioFile
3532
import app.ss.models.media.SSVideo
3633
import com.slack.circuit.codegen.annotations.CircuitInject
@@ -66,7 +63,6 @@ import ss.document.producer.UserInputStateProducer
6663
import ss.document.segment.producer.SegmentOverlayStateProducer
6764
import ss.libraries.circuit.navigation.DocumentScreen
6865
import ss.libraries.circuit.navigation.ExpandedAudioPlayerScreen
69-
import ss.libraries.circuit.navigation.PdfScreen
7066
import ss.libraries.circuit.navigation.ResourceScreen
7167
import ss.libraries.media.api.MediaNavigation
7268
import ss.libraries.media.api.SSMediaPlayer
@@ -75,7 +71,6 @@ import ss.libraries.media.model.SSMediaItem
7571
import ss.libraries.media.model.extensions.NONE_PLAYING
7672
import ss.libraries.media.service.MusicService
7773
import ss.libraries.media.service.VideoService
78-
import ss.libraries.pdf.api.PdfReader
7974
import ss.misc.DateHelper
8075
import ss.resources.api.ResourcesRepository
8176
import ss.services.media.ui.PlaybackConnection
@@ -93,7 +88,6 @@ class DocumentPresenter @AssistedInject constructor(
9388
private val readerStyleStateProducer: ReaderStyleStateProducer,
9489
private val segmentOverlayStateProducer: SegmentOverlayStateProducer,
9590
private val userInputStateProducer: UserInputStateProducer,
96-
private val pdfReader: PdfReader,
9791
private val playbackConnection: PlaybackConnection,
9892
private val mediaNavigation: MediaNavigation,
9993
private val mediaPlayer: SSMediaPlayer,
@@ -111,8 +105,6 @@ class DocumentPresenter @AssistedInject constructor(
111105

112106
val resourceDocument = response
113107

114-
LaunchedEffect(resourceDocument) { checkPdfOnlySegment(resourceDocument) }
115-
116108
val actionsState = resourceDocument?.let {
117109
actionsProducer(
118110
navigator = navigator,
@@ -292,37 +284,6 @@ class DocumentPresenter @AssistedInject constructor(
292284
} ?: firstOrNull()
293285
}
294286

295-
private fun checkPdfOnlySegment(resourceDocument: ResourceDocument?) {
296-
val document = resourceDocument ?: return
297-
val segments = document.segments ?: return
298-
val blocks = segments.flatMap { it.blocks.orEmpty() }
299-
val pdfs = segments.flatMap { it.pdf.orEmpty() }
300-
301-
if (blocks.isEmpty() && pdfs.isNotEmpty()) {
302-
val pdfs = segments.flatMap { it.pdf.orEmpty() }
303-
val screen = PdfScreen(
304-
documentId = document.id,
305-
resourceId = document.resourceId,
306-
resourceIndex = document.resourceIndex,
307-
documentIndex = document.index,
308-
segmentId = null,
309-
pdfs = pdfs.map {
310-
PDFAux(
311-
id = it.id,
312-
src = it.src,
313-
title = it.title,
314-
target = it.target,
315-
targetIndex = it.targetIndex,
316-
)
317-
},
318-
)
319-
Snapshot.withMutableSnapshot {
320-
navigator.pop()
321-
navigator.goTo(IntentScreen(pdfReader.launchIntent(screen)))
322-
}
323-
}
324-
}
325-
326287
private fun BlockItem.Video.toSSVideo(
327288
resource: Resource?,
328289
document: ResourceDocument?,

features/document/src/main/kotlin/ss/document/DocumentScreenUi.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,10 @@ private fun State.showTopBar(collapsed: Boolean): Boolean = when (this) {
291291
is State.Success -> when (selectedSegment?.type) {
292292
SegmentType.VIDEO -> false
293293
SegmentType.STORY -> collapsed
294-
SegmentType.PDF,
295294
SegmentType.UNKNOWN,
296295
SegmentType.BLOCK,
297-
298296
null -> true
297+
SegmentType.PDF -> false
299298
}
300299
}
301300

features/document/src/main/kotlin/ss/document/components/DocumentTopAppBar.kt

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import androidx.compose.foundation.layout.sizeIn
4242
import androidx.compose.foundation.layout.wrapContentSize
4343
import androidx.compose.foundation.shape.CircleShape
4444
import androidx.compose.foundation.shape.RoundedCornerShape
45-
import androidx.compose.material.icons.rounded.MoreVert
4645
import androidx.compose.material3.DropdownMenu
4746
import androidx.compose.material3.DropdownMenuItem
4847
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -52,6 +51,7 @@ import androidx.compose.material3.ListItem
5251
import androidx.compose.material3.MaterialTheme
5352
import androidx.compose.material3.Text
5453
import androidx.compose.material3.TopAppBar
54+
import androidx.compose.material3.TopAppBarColors
5555
import androidx.compose.material3.TopAppBarDefaults
5656
import androidx.compose.material3.TopAppBarScrollBehavior
5757
import androidx.compose.runtime.Composable
@@ -73,14 +73,13 @@ import app.ss.design.compose.extensions.haptics.LocalSsHapticFeedback
7373
import app.ss.design.compose.theme.SsTheme
7474
import app.ss.design.compose.widget.icon.IconBox
7575
import app.ss.design.compose.widget.icon.IconButtonResSlot
76-
import app.ss.design.compose.widget.icon.IconButtonSlot
7776
import app.ss.design.compose.widget.icon.Icons
7877
import io.adventech.blockkit.model.resource.Segment
7978
import kotlinx.collections.immutable.ImmutableList
8079
import kotlinx.collections.immutable.persistentListOf
8180
import ss.misc.DateHelper
82-
import androidx.compose.material.icons.Icons as MaterialIcons
8381
import app.ss.translations.R as L10nR
82+
import com.pspdfkit.R as PspdfR
8483
import ss.document.R as DocumentR
8584
import ss.libraries.media.resources.R as MediaR
8685

@@ -113,6 +112,21 @@ enum class DocumentTopAppBarAction(
113112
iconRes = DocumentR.drawable.ic_text_format,
114113
title = L10nR.string.ss_settings_display_options,
115114
primary = false,
115+
),
116+
Annotations(
117+
iconRes = DocumentR.drawable.ic_pdf_annotations,
118+
title = L10nR.string.ss_annotations,
119+
primary = true,
120+
),
121+
Outline(
122+
iconRes = DocumentR.drawable.ic_pdf_bookmark,
123+
title = PspdfR.string.pspdf__activity_menu_outline,
124+
primary = true,
125+
),
126+
Settings(
127+
iconRes = DocumentR.drawable.ic_pdf_settings,
128+
title = PspdfR.string.pspdf__activity_menu_settings,
129+
primary = true,
116130
)
117131
}
118132

@@ -126,11 +140,21 @@ internal fun DocumentTopAppBar(
126140
contentColor: Color = SsTheme.colors.primaryForeground,
127141
scrollBehavior: TopAppBarScrollBehavior? = null,
128142
actions: ImmutableList<DocumentTopAppBarAction> = persistentListOf(),
143+
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(
144+
containerColor = Color.Transparent,
145+
scrolledContainerColor = Color.Transparent,
146+
),
129147
onNavBack: () -> Unit = {},
130148
onActionClick: (DocumentTopAppBarAction) -> Unit = {},
131149
) {
132150
val hapticFeedback = LocalSsHapticFeedback.current
133151
var expanded by remember { mutableStateOf(false) }
152+
153+
val primaryActions = remember(actions) { actions.filter { it.primary } }
154+
val nonPrimaryActions = remember(actions) { actions.filter { !it.primary } }
155+
val visibleActions = remember(primaryActions) { primaryActions.take(2) }
156+
val overflowActions = remember(primaryActions, nonPrimaryActions) { primaryActions.drop(2) + nonPrimaryActions }
157+
134158
Box(
135159
modifier = Modifier
136160
.fillMaxWidth()
@@ -144,7 +168,7 @@ internal fun DocumentTopAppBar(
144168
shape = RoundedCornerShape(16.dp),
145169
containerColor = SsTheme.colors.primaryBackground,
146170
) {
147-
actions.filter { !it.primary }.forEach { action ->
171+
overflowActions.forEach { action ->
148172
DropdownMenuItem(
149173
text = {
150174
Text(
@@ -219,7 +243,8 @@ internal fun DocumentTopAppBar(
219243
},
220244
actions = {
221245
buildList {
222-
actions.filter { it.primary }.forEach { action ->
246+
// Add the visible primary actions (up to 2)
247+
visibleActions.forEach { action ->
223248
add(
224249
IconButtonResSlot(
225250
iconRes = action.iconRes,
@@ -228,10 +253,12 @@ internal fun DocumentTopAppBar(
228253
)
229254
)
230255
}
231-
if (actions.any { !it.primary }) {
256+
257+
// Add the "More" icon if there are any secondary or overflowed primary actions
258+
if (overflowActions.isNotEmpty()) {
232259
add(
233-
IconButtonSlot(
234-
imageVector = MaterialIcons.Rounded.MoreVert,
260+
IconButtonResSlot(
261+
iconRes = DocumentR.drawable.ic_more_vert,
235262
contentDescription = stringResource(L10nR.string.ss_more),
236263
onClick = {
237264
expanded = true
@@ -242,12 +269,7 @@ internal fun DocumentTopAppBar(
242269
}
243270
}.forEach { icon ->
244271
val iconColor by topAppBarContentColor(collapsible, collapsed, contentColor)
245-
val onClick = (icon as? IconButtonSlot)?.onClick ?: (icon as? IconButtonResSlot)?.onClick
246-
IconButton(
247-
onClick = {
248-
onClick?.invoke()
249-
},
250-
) {
272+
IconButton(onClick = { icon.onClick() }) {
251273
IconBox(
252274
icon = icon,
253275
contentColor = iconColor,
@@ -256,10 +278,7 @@ internal fun DocumentTopAppBar(
256278
}
257279
},
258280
scrollBehavior = scrollBehavior,
259-
colors = TopAppBarDefaults.topAppBarColors(
260-
containerColor = Color.Transparent,
261-
scrolledContainerColor = Color.Transparent,
262-
)
281+
colors = colors
263282
)
264283
}
265284

features/document/src/main/kotlin/ss/document/di/BindingsModule.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import ss.document.producer.TopAppbarActionsProducer
3434
import ss.document.producer.TopAppbarActionsProducerImpl
3535
import ss.document.producer.UserInputStateProducer
3636
import ss.document.producer.UserInputStateProducerImpl
37+
import ss.document.segment.components.pdf.PdfTopAppBarStateProducer
38+
import ss.document.segment.components.pdf.PdfTopAppBarStateProducerImpl
3739
import ss.document.segment.producer.OverlayStateProducerImpl
3840
import ss.document.segment.producer.SegmentOverlayStateProducer
3941

@@ -54,4 +56,7 @@ internal abstract class BindingsModule {
5456

5557
@Binds
5658
internal abstract fun bindUserInputStateProducer(impl: UserInputStateProducerImpl): UserInputStateProducer
59+
60+
@Binds
61+
internal abstract fun bindPdfTopAppBarStateProducer(impl: PdfTopAppBarStateProducerImpl): PdfTopAppBarStateProducer
5762
}

features/document/src/main/kotlin/ss/document/producer/TopAppbarActionsProducer.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,12 @@ import androidx.compose.runtime.Composable
2727
import androidx.compose.runtime.Stable
2828
import androidx.compose.runtime.getValue
2929
import androidx.compose.runtime.mutableStateOf
30-
import androidx.compose.runtime.remember
3130
import androidx.compose.runtime.setValue
3231
import app.ss.models.PDFAux
3332
import com.slack.circuit.retained.produceRetainedState
3433
import com.slack.circuit.retained.rememberRetained
3534
import com.slack.circuit.runtime.CircuitUiState
3635
import com.slack.circuit.runtime.Navigator
37-
import com.slack.circuitx.android.IntentScreen
3836
import dagger.Lazy
3937
import io.adventech.blockkit.model.resource.Segment
4038
import io.adventech.blockkit.model.resource.SegmentType
@@ -52,7 +50,6 @@ import ss.libraries.circuit.navigation.AudioPlayerScreen
5250
import ss.libraries.circuit.navigation.PdfScreen
5351
import ss.libraries.circuit.navigation.ShareOptionsScreen
5452
import ss.libraries.circuit.navigation.VideosScreen
55-
import ss.libraries.pdf.api.PdfReader
5653
import ss.resources.api.ResourcesRepository
5754
import javax.inject.Inject
5855

@@ -92,7 +89,6 @@ interface TopAppbarActionsProducer {
9289

9390
internal class TopAppbarActionsProducerImpl @Inject constructor(
9491
private val repository: ResourcesRepository,
95-
private val pdfReader: PdfReader,
9692
private val shareIntentHelper: Lazy<ShareIntentHelper>,
9793
) : TopAppbarActionsProducer {
9894

@@ -118,7 +114,7 @@ internal class TopAppbarActionsProducerImpl @Inject constructor(
118114
if (segment?.type == SegmentType.PDF) return@produceRetainedState
119115
value = repository.pdf(resourceIndex, documentIndex).getOrNull().orEmpty()
120116
}
121-
val actions = remember(audio, video, pdfs, segment, shareOptions) {
117+
val actions = rememberRetained(audio, video, pdfs, segment, shareOptions) {
122118
buildList {
123119
if (audio.isNotEmpty()) {
124120
add(DocumentTopAppBarAction.Audio)
@@ -184,7 +180,7 @@ internal class TopAppbarActionsProducerImpl @Inject constructor(
184180
)
185181
},
186182
)
187-
navigator.goTo(IntentScreen(pdfReader.launchIntent(screen)))
183+
navigator.goTo(screen)
188184
}
189185
DocumentTopAppBarAction.DisplayOptions -> {
190186
bottomSheetState = BottomSheet(
@@ -217,6 +213,7 @@ internal class TopAppbarActionsProducerImpl @Inject constructor(
217213
}
218214
}
219215
}
216+
else -> Unit
220217
}
221218
}
222219
}

0 commit comments

Comments
 (0)