Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6397bac
Migrate pdfkit to nutrient
TinasheMzondiwa Feb 25, 2026
151a796
Add new key
TinasheMzondiwa Mar 29, 2026
3a9b9f0
Implement pdf ui
TinasheMzondiwa Mar 29, 2026
3325300
Show custom toolbar
TinasheMzondiwa Mar 29, 2026
4a79f66
Go to Pdf screen
TinasheMzondiwa Mar 29, 2026
281f31a
Show document title
TinasheMzondiwa Mar 29, 2026
c38baf0
Attempt to override colors
TinasheMzondiwa Apr 1, 2026
b729d04
Merge branch 'develop' into tm/pdfkit-to-nutrient
TinasheMzondiwa Apr 5, 2026
8cd09b4
Configure PDF topbar menu
TinasheMzondiwa Apr 6, 2026
a62fd48
Clean up
TinasheMzondiwa Apr 6, 2026
7508e26
Show media icon buttons
TinasheMzondiwa Apr 6, 2026
1fd58a6
Add loading state
TinasheMzondiwa Apr 6, 2026
6e56223
Save PdfConfiguration to prefs
TinasheMzondiwa Apr 7, 2026
6099cbb
Save annotations
TinasheMzondiwa Apr 7, 2026
1cd605c
Save annotations
TinasheMzondiwa Apr 7, 2026
f97fb01
Refactor topAppBar to re-use existing composable
TinasheMzondiwa Apr 11, 2026
9628d59
rename
TinasheMzondiwa Apr 11, 2026
7072401
Fix config state
TinasheMzondiwa Apr 11, 2026
8c25850
Remove unused pdf code
TinasheMzondiwa Apr 11, 2026
7567e70
Remove legacy video fragment
TinasheMzondiwa Apr 11, 2026
3269380
Clean up unused code
TinasheMzondiwa Apr 11, 2026
5d68a4b
Merge branch 'develop' into tm/pdfkit-to-nutrient
TinasheMzondiwa Apr 12, 2026
e00ce86
Clean-up DocumentPresenter
TinasheMzondiwa Apr 12, 2026
52573bc
Update PdfReaderPrefsImpl.kt
TinasheMzondiwa Apr 12, 2026
aa3b4c3
Move to services module
TinasheMzondiwa Apr 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ dependencies {
implementation(projects.features.languages)
implementation(projects.features.media)
implementation(projects.features.navigationSuite)
implementation(projects.features.pdf)
implementation(projects.features.resource)
implementation(projects.features.settings)
implementation(projects.features.share)
Expand All @@ -172,6 +171,7 @@ dependencies {
implementation(projects.services.lessons.impl)
implementation(projects.services.media.impl)
implementation(projects.services.media.ui)
implementation(projects.services.pdf.impl)
implementation(projects.services.prefs.impl)
implementation(projects.services.resources.impl)
implementation(projects.services.storage.impl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
package com.cryart.sabbathschool.ui.home

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.remember
Expand All @@ -47,7 +47,7 @@ import ss.services.circuit.impl.interceptor.AndroidSupportingInterceptor
import javax.inject.Inject

@AndroidEntryPoint
class HomeActivity : ComponentActivity() {
class HomeActivity : AppCompatActivity() {

@Inject
lateinit var circuit: Circuit
Expand Down
1 change: 1 addition & 0 deletions common/design/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
<color name="black_40">#66000000</color>
<color name="sepia">#FDF4E6</color>

<color name="list_divider">#80D7D7D7</color>
<color name="ss_gray_1">#EFEFEF</color>
Expand Down
1 change: 1 addition & 0 deletions common/translations/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,5 @@
<string name="ss_action_share">Share</string>
<string name="ss_downloading">Downloading…</string>
<string name="ss_off">Off</string>
<string name="ss_annotations">Annotations</string>
</resources>
3 changes: 3 additions & 0 deletions features/document/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@ ksp {
}

dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.coil.compose)
implementation(libs.google.hilt.android)
implementation(libs.joda.time)
implementation(libs.kotlinx.collectionsImmutable)
implementation(libs.nutrient)
implementation(libs.timber)
implementation(projects.common.design)
implementation(projects.common.designCompose)
implementation(projects.common.misc)
implementation(projects.common.translations)
Expand Down
39 changes: 0 additions & 39 deletions features/document/src/main/kotlin/ss/document/DocumentPresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,11 @@
package ss.document

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.Snapshot
import androidx.core.net.toUri
import app.ss.models.PDFAux
import app.ss.models.media.AudioFile
import app.ss.models.media.SSVideo
import com.slack.circuit.codegen.annotations.CircuitInject
Expand Down Expand Up @@ -66,7 +63,6 @@ import ss.document.producer.UserInputStateProducer
import ss.document.segment.producer.SegmentOverlayStateProducer
import ss.libraries.circuit.navigation.DocumentScreen
import ss.libraries.circuit.navigation.ExpandedAudioPlayerScreen
import ss.libraries.circuit.navigation.PdfScreen
import ss.libraries.circuit.navigation.ResourceScreen
import ss.libraries.media.api.MediaNavigation
import ss.libraries.media.api.SSMediaPlayer
Expand All @@ -75,7 +71,6 @@ import ss.libraries.media.model.SSMediaItem
import ss.libraries.media.model.extensions.NONE_PLAYING
import ss.libraries.media.service.MusicService
import ss.libraries.media.service.VideoService
import ss.libraries.pdf.api.PdfReader
import ss.misc.DateHelper
import ss.resources.api.ResourcesRepository
import ss.services.media.ui.PlaybackConnection
Expand All @@ -93,7 +88,6 @@ class DocumentPresenter @AssistedInject constructor(
private val readerStyleStateProducer: ReaderStyleStateProducer,
private val segmentOverlayStateProducer: SegmentOverlayStateProducer,
private val userInputStateProducer: UserInputStateProducer,
private val pdfReader: PdfReader,
private val playbackConnection: PlaybackConnection,
private val mediaNavigation: MediaNavigation,
private val mediaPlayer: SSMediaPlayer,
Expand All @@ -111,8 +105,6 @@ class DocumentPresenter @AssistedInject constructor(

val resourceDocument = response

LaunchedEffect(resourceDocument) { checkPdfOnlySegment(resourceDocument) }

val actionsState = resourceDocument?.let {
actionsProducer(
navigator = navigator,
Expand Down Expand Up @@ -292,37 +284,6 @@ class DocumentPresenter @AssistedInject constructor(
} ?: firstOrNull()
}

private fun checkPdfOnlySegment(resourceDocument: ResourceDocument?) {
val document = resourceDocument ?: return
val segments = document.segments ?: return
val blocks = segments.flatMap { it.blocks.orEmpty() }
val pdfs = segments.flatMap { it.pdf.orEmpty() }

if (blocks.isEmpty() && pdfs.isNotEmpty()) {
val pdfs = segments.flatMap { it.pdf.orEmpty() }
val screen = PdfScreen(
documentId = document.id,
resourceId = document.resourceId,
resourceIndex = document.resourceIndex,
documentIndex = document.index,
segmentId = null,
pdfs = pdfs.map {
PDFAux(
id = it.id,
src = it.src,
title = it.title,
target = it.target,
targetIndex = it.targetIndex,
)
},
)
Snapshot.withMutableSnapshot {
navigator.pop()
navigator.goTo(IntentScreen(pdfReader.launchIntent(screen)))
}
}
}

private fun BlockItem.Video.toSSVideo(
resource: Resource?,
document: ResourceDocument?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,11 +291,10 @@ private fun State.showTopBar(collapsed: Boolean): Boolean = when (this) {
is State.Success -> when (selectedSegment?.type) {
SegmentType.VIDEO -> false
SegmentType.STORY -> collapsed
SegmentType.PDF,
SegmentType.UNKNOWN,
SegmentType.BLOCK,

null -> true
SegmentType.PDF -> false
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
Expand All @@ -52,6 +51,7 @@ import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarColors
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
Expand All @@ -73,14 +73,13 @@ import app.ss.design.compose.extensions.haptics.LocalSsHapticFeedback
import app.ss.design.compose.theme.SsTheme
import app.ss.design.compose.widget.icon.IconBox
import app.ss.design.compose.widget.icon.IconButtonResSlot
import app.ss.design.compose.widget.icon.IconButtonSlot
import app.ss.design.compose.widget.icon.Icons
import io.adventech.blockkit.model.resource.Segment
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import ss.misc.DateHelper
import androidx.compose.material.icons.Icons as MaterialIcons
import app.ss.translations.R as L10nR
import com.pspdfkit.R as PspdfR
import ss.document.R as DocumentR
import ss.libraries.media.resources.R as MediaR

Expand Down Expand Up @@ -113,6 +112,21 @@ enum class DocumentTopAppBarAction(
iconRes = DocumentR.drawable.ic_text_format,
title = L10nR.string.ss_settings_display_options,
primary = false,
),
Annotations(
iconRes = DocumentR.drawable.ic_pdf_annotations,
title = L10nR.string.ss_annotations,
primary = true,
),
Outline(
iconRes = DocumentR.drawable.ic_pdf_bookmark,
title = PspdfR.string.pspdf__activity_menu_outline,
primary = true,
),
Settings(
iconRes = DocumentR.drawable.ic_pdf_settings,
title = PspdfR.string.pspdf__activity_menu_settings,
primary = true,
)
}

Expand All @@ -126,11 +140,21 @@ internal fun DocumentTopAppBar(
contentColor: Color = SsTheme.colors.primaryForeground,
scrollBehavior: TopAppBarScrollBehavior? = null,
actions: ImmutableList<DocumentTopAppBarAction> = persistentListOf(),
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent,
),
onNavBack: () -> Unit = {},
onActionClick: (DocumentTopAppBarAction) -> Unit = {},
) {
val hapticFeedback = LocalSsHapticFeedback.current
var expanded by remember { mutableStateOf(false) }

val primaryActions = remember(actions) { actions.filter { it.primary } }
val nonPrimaryActions = remember(actions) { actions.filter { !it.primary } }
val visibleActions = remember(primaryActions) { primaryActions.take(2) }
val overflowActions = remember(primaryActions, nonPrimaryActions) { primaryActions.drop(2) + nonPrimaryActions }

Box(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -144,7 +168,7 @@ internal fun DocumentTopAppBar(
shape = RoundedCornerShape(16.dp),
containerColor = SsTheme.colors.primaryBackground,
) {
actions.filter { !it.primary }.forEach { action ->
overflowActions.forEach { action ->
DropdownMenuItem(
text = {
Text(
Expand Down Expand Up @@ -219,7 +243,8 @@ internal fun DocumentTopAppBar(
},
actions = {
buildList {
actions.filter { it.primary }.forEach { action ->
// Add the visible primary actions (up to 2)
visibleActions.forEach { action ->
add(
IconButtonResSlot(
iconRes = action.iconRes,
Expand All @@ -228,10 +253,12 @@ internal fun DocumentTopAppBar(
)
)
}
if (actions.any { !it.primary }) {

// Add the "More" icon if there are any secondary or overflowed primary actions
if (overflowActions.isNotEmpty()) {
add(
IconButtonSlot(
imageVector = MaterialIcons.Rounded.MoreVert,
IconButtonResSlot(
iconRes = DocumentR.drawable.ic_more_vert,
contentDescription = stringResource(L10nR.string.ss_more),
onClick = {
expanded = true
Expand All @@ -242,12 +269,7 @@ internal fun DocumentTopAppBar(
}
}.forEach { icon ->
val iconColor by topAppBarContentColor(collapsible, collapsed, contentColor)
val onClick = (icon as? IconButtonSlot)?.onClick ?: (icon as? IconButtonResSlot)?.onClick
IconButton(
onClick = {
onClick?.invoke()
},
) {
IconButton(onClick = { icon.onClick() }) {
IconBox(
icon = icon,
contentColor = iconColor,
Expand All @@ -256,10 +278,7 @@ internal fun DocumentTopAppBar(
}
},
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent,
)
colors = colors
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import ss.document.producer.TopAppbarActionsProducer
import ss.document.producer.TopAppbarActionsProducerImpl
import ss.document.producer.UserInputStateProducer
import ss.document.producer.UserInputStateProducerImpl
import ss.document.segment.components.pdf.PdfTopAppBarStateProducer
import ss.document.segment.components.pdf.PdfTopAppBarStateProducerImpl
import ss.document.segment.producer.OverlayStateProducerImpl
import ss.document.segment.producer.SegmentOverlayStateProducer

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

@Binds
internal abstract fun bindUserInputStateProducer(impl: UserInputStateProducerImpl): UserInputStateProducer

@Binds
internal abstract fun bindPdfTopAppBarStateProducer(impl: PdfTopAppBarStateProducerImpl): PdfTopAppBarStateProducer
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import app.ss.models.PDFAux
import com.slack.circuit.retained.produceRetainedState
import com.slack.circuit.retained.rememberRetained
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuitx.android.IntentScreen
import dagger.Lazy
import io.adventech.blockkit.model.resource.Segment
import io.adventech.blockkit.model.resource.SegmentType
Expand All @@ -52,7 +50,6 @@ import ss.libraries.circuit.navigation.AudioPlayerScreen
import ss.libraries.circuit.navigation.PdfScreen
import ss.libraries.circuit.navigation.ShareOptionsScreen
import ss.libraries.circuit.navigation.VideosScreen
import ss.libraries.pdf.api.PdfReader
import ss.resources.api.ResourcesRepository
import javax.inject.Inject

Expand Down Expand Up @@ -92,7 +89,6 @@ interface TopAppbarActionsProducer {

internal class TopAppbarActionsProducerImpl @Inject constructor(
private val repository: ResourcesRepository,
private val pdfReader: PdfReader,
private val shareIntentHelper: Lazy<ShareIntentHelper>,
) : TopAppbarActionsProducer {

Expand All @@ -118,7 +114,7 @@ internal class TopAppbarActionsProducerImpl @Inject constructor(
if (segment?.type == SegmentType.PDF) return@produceRetainedState
value = repository.pdf(resourceIndex, documentIndex).getOrNull().orEmpty()
}
val actions = remember(audio, video, pdfs, segment, shareOptions) {
val actions = rememberRetained(audio, video, pdfs, segment, shareOptions) {
buildList {
if (audio.isNotEmpty()) {
add(DocumentTopAppBarAction.Audio)
Expand Down Expand Up @@ -184,7 +180,7 @@ internal class TopAppbarActionsProducerImpl @Inject constructor(
)
},
)
navigator.goTo(IntentScreen(pdfReader.launchIntent(screen)))
navigator.goTo(screen)
}
DocumentTopAppBarAction.DisplayOptions -> {
bottomSheetState = BottomSheet(
Expand Down Expand Up @@ -217,6 +213,7 @@ internal class TopAppbarActionsProducerImpl @Inject constructor(
}
}
}
else -> Unit
}
}
}
Expand Down
Loading