Skip to content

Commit 7629a9e

Browse files
authored
Merge pull request #82 from fmasa/pdf-import
Winds of Magic + Up in Arms PDF import
2 parents 06c119d + cd4b4eb commit 7629a9e

File tree

72 files changed

+2234
-1757
lines changed

Some content is hidden

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

72 files changed

+2234
-1757
lines changed

common/build.gradle.kts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ kotlin {
4747
api("cafe.adriel.voyager:voyager-koin:$voyagerVersion")
4848
api("cafe.adriel.voyager:voyager-transitions:$voyagerVersion")
4949

50-
implementation("com.github.librepdf:openpdf:1.3.25")
51-
5250
api(project(":common:firebase"))
5351

5452
api("io.ktor:ktor-client-core:$ktorVersion")
@@ -129,6 +127,8 @@ kotlin {
129127
// Firebase functions
130128
api("com.google.firebase:firebase-functions-ktx:20.0.1")
131129

130+
implementation("com.tom-roush:pdfbox-android:2.0.27.0")
131+
132132
// Coil - image library
133133
implementation("io.coil-kt:coil-compose:2.0.0")
134134

@@ -146,9 +146,6 @@ kotlin {
146146
// Network availability check
147147
implementation("com.github.pwittchen:reactivenetwork-rx2:3.0.8")
148148
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-rx2:1.4.2")
149-
150-
// Rulebook parsing
151-
implementation("com.github.andob:android-awt:1.0.0")
152149
}
153150
}
154151

@@ -158,6 +155,7 @@ kotlin {
158155
implementation(compose.desktop.currentOs)
159156

160157
implementation("com.soywiz.korlibs.korau:korau:2.2.0")
158+
implementation("org.apache.pdfbox:pdfbox:2.0.27")
161159
}
162160
}
163161

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package cz.frantisekmasa.wfrp_master.common.compendium.domain.importer.parsers
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.ui.platform.LocalContext
5+
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
6+
import com.tom_roush.pdfbox.io.MemoryUsageSetting
7+
import com.tom_roush.pdfbox.pdmodel.PDDocument
8+
import com.tom_roush.pdfbox.pdmodel.font.PDFont
9+
import com.tom_roush.pdfbox.text.PDFTextStripper
10+
import java.io.InputStream
11+
12+
actual typealias TextPosition = com.tom_roush.pdfbox.text.TextPosition
13+
actual typealias Document = PDDocument
14+
actual typealias Font = PDFont
15+
16+
actual abstract class PdfTextStripper : PDFTextStripper() {
17+
protected actual val textCharactersByArticle: List<List<TextPosition>> get() = charactersByArticle
18+
19+
protected actual abstract fun onPageEnter()
20+
21+
protected actual abstract fun onTextLine(text: String, textPositions: List<TextPosition>)
22+
23+
override fun writePage() {
24+
onPageEnter()
25+
super.writePage()
26+
}
27+
28+
protected actual abstract fun onFinish()
29+
30+
override fun writeString(text: String, textPositions: List<TextPosition>) {
31+
onTextLine(text, textPositions)
32+
}
33+
34+
override fun endDocument(document: PDDocument) {
35+
onFinish()
36+
}
37+
}
38+
39+
actual fun loadDocument(inputStream: InputStream): Document {
40+
return PDDocument.load(
41+
inputStream,
42+
MemoryUsageSetting.setupTempFileOnly(),
43+
)
44+
}
45+
46+
@Composable
47+
actual fun pdfBoxInitializer(): () -> Unit {
48+
val context = LocalContext.current
49+
50+
return {
51+
if (!PDFBoxResourceLoader.isReady()) {
52+
PDFBoxResourceLoader.init(context)
53+
}
54+
}
55+
}

common/src/androidMain/kotlin/cz/frantisekmasa/wfrp_master/common/core/shared/FileChooser.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ actual fun rememberFileChooser(
2929

3030
val inputStream = context.contentResolver.openInputStream(uri)
3131

32-
onFileChoose(
33-
if (inputStream == null)
34-
Result.failure(Exception("Could not open input stream"))
35-
else Result.success(ReadableFile(inputStream))
36-
)
32+
inputStream.use {
33+
onFileChoose(
34+
if (inputStream == null)
35+
Result.failure(Exception("Could not open input stream"))
36+
else Result.success(ReadableFile(inputStream))
37+
)
38+
}
3739
}
3840
}
3941

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package cz.frantisekmasa.wfrp_master.common.compendium
2+
3+
import cz.frantisekmasa.wfrp_master.common.compendium.domain.CompendiumItem
4+
import cz.frantisekmasa.wfrp_master.common.core.domain.character.CharacterCompendiumItemRepository
5+
import cz.frantisekmasa.wfrp_master.common.core.domain.character.CharacterItem
6+
import cz.frantisekmasa.wfrp_master.common.core.domain.compendium.Compendium
7+
import cz.frantisekmasa.wfrp_master.common.core.domain.identifiers.CharacterId
8+
import cz.frantisekmasa.wfrp_master.common.core.domain.party.PartyId
9+
import cz.frantisekmasa.wfrp_master.common.firebase.firestore.Firestore
10+
import cz.frantisekmasa.wfrp_master.common.firebase.firestore.Transaction
11+
12+
abstract class CharacterItemCompendiumItemScreenModel<A : CompendiumItem<A>, B : CharacterItem<B, A>>(
13+
private val partyId: PartyId,
14+
private val firestore: Firestore,
15+
compendium: Compendium<A>,
16+
protected val characterItems: CharacterCompendiumItemRepository<B>
17+
) : CompendiumItemScreenModel<A>(partyId, compendium) {
18+
19+
override suspend fun createNew(compendiumItem: A) {
20+
firestore.runTransaction { transaction ->
21+
compendium.save(transaction, partyId, compendiumItem)
22+
}
23+
}
24+
25+
override suspend fun update(compendiumItem: A) {
26+
val characterItems = characterItems.findByCompendiumId(partyId, compendiumItem.id)
27+
28+
firestore.runTransaction { transaction ->
29+
compendium.save(transaction, partyId, compendiumItem)
30+
characterItems.forEach { (characterId, item) ->
31+
saveCharacterItem(
32+
transaction,
33+
characterId,
34+
item,
35+
item.updateFromCompendium(compendiumItem),
36+
)
37+
}
38+
}
39+
}
40+
41+
override suspend fun remove(compendiumItem: A) {
42+
val characterItems = characterItems.findByCompendiumId(partyId, compendiumItem.id)
43+
44+
firestore.runTransaction { transaction ->
45+
compendium.remove(transaction, partyId, compendiumItem)
46+
characterItems.forEach { (characterId, item) ->
47+
saveCharacterItem(
48+
transaction,
49+
characterId,
50+
item,
51+
item.unlinkFromCompendium(),
52+
)
53+
}
54+
}
55+
}
56+
57+
protected abstract suspend fun saveCharacterItem(
58+
transaction: Transaction,
59+
characterId: CharacterId,
60+
existing: B,
61+
new: B
62+
)
63+
}

common/src/commonMain/kotlin/cz/frantisekmasa/wfrp_master/common/compendium/CompendiumItemDetailScreen.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import cafe.adriel.voyager.navigator.LocalNavigator
2121
import cafe.adriel.voyager.navigator.currentOrThrow
2222
import com.benasher44.uuid.Uuid
2323
import cz.frantisekmasa.wfrp_master.common.compendium.domain.CompendiumItem
24-
import cz.frantisekmasa.wfrp_master.common.core.domain.character.CharacterItem
2524
import cz.frantisekmasa.wfrp_master.common.core.ui.buttons.BackButton
2625
import cz.frantisekmasa.wfrp_master.common.core.ui.flow.collectWithLifecycle
2726
import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.FullScreenProgress
@@ -30,9 +29,9 @@ import cz.frantisekmasa.wfrp_master.common.core.ui.scaffolding.LocalPersistentSn
3029
import cz.frantisekmasa.wfrp_master.common.localization.LocalStrings
3130

3231
@Composable
33-
fun <A : CompendiumItem<A>, B : CharacterItem<B, A>> Screen.CompendiumItemDetailScreen(
32+
fun <A : CompendiumItem<A>> Screen.CompendiumItemDetailScreen(
3433
id: Uuid,
35-
screenModel: CompendiumItemScreenModel<A, B>,
34+
screenModel: CompendiumItemScreenModel<A>,
3635
detail: @Composable (A) -> Unit,
3736
editDialog: @Composable (item: A, onDismissRequest: () -> Unit) -> Unit,
3837
) {

common/src/commonMain/kotlin/cz/frantisekmasa/wfrp_master/common/compendium/CompendiumItemScreenModel.kt

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,20 @@ import cafe.adriel.voyager.core.model.ScreenModel
55
import com.benasher44.uuid.Uuid
66
import cz.frantisekmasa.wfrp_master.common.compendium.domain.CompendiumItem
77
import cz.frantisekmasa.wfrp_master.common.compendium.domain.exceptions.CompendiumItemNotFound
8-
import cz.frantisekmasa.wfrp_master.common.core.domain.character.CharacterItem
9-
import cz.frantisekmasa.wfrp_master.common.core.domain.character.CharacterItemRepository
108
import cz.frantisekmasa.wfrp_master.common.core.domain.compendium.Compendium
11-
import cz.frantisekmasa.wfrp_master.common.core.domain.identifiers.CharacterId
129
import cz.frantisekmasa.wfrp_master.common.core.domain.party.PartyId
13-
import cz.frantisekmasa.wfrp_master.common.firebase.firestore.Firestore
14-
import cz.frantisekmasa.wfrp_master.common.firebase.firestore.Transaction
1510
import kotlinx.coroutines.flow.Flow
1611

17-
abstract class CompendiumItemScreenModel<A : CompendiumItem<A>, B : CharacterItem<B, A>>(
12+
abstract class CompendiumItemScreenModel<A : CompendiumItem<A>>(
1813
private val partyId: PartyId,
19-
private val firestore: Firestore,
2014
protected val compendium: Compendium<A>,
21-
protected val characterItems: CharacterItemRepository<B>
2215
) : ScreenModel {
2316

2417
val items: Flow<List<A>> = compendium.liveForParty(partyId)
2518

26-
suspend fun createNew(compendiumItem: A) {
27-
firestore.runTransaction { transaction ->
28-
compendium.save(transaction, partyId, compendiumItem)
29-
}
30-
}
31-
32-
suspend fun update(compendiumItem: A) {
33-
val characterItems = characterItems.findByCompendiumId(partyId, compendiumItem.id)
19+
abstract suspend fun createNew(compendiumItem: A)
3420

35-
firestore.runTransaction { transaction ->
36-
compendium.save(transaction, partyId, compendiumItem)
37-
characterItems.forEach { (characterId, item) ->
38-
saveCharacterItem(
39-
transaction,
40-
characterId,
41-
item,
42-
item.updateFromCompendium(compendiumItem),
43-
)
44-
}
45-
}
46-
}
21+
abstract suspend fun update(compendiumItem: A)
4722

4823
suspend fun import(actions: Sequence<ImportAction<A>>) {
4924
actions.forEach { action ->
@@ -59,25 +34,9 @@ abstract class CompendiumItemScreenModel<A : CompendiumItem<A>, B : CharacterIte
5934
class Update<T : CompendiumItem<T>>(item: T) : ImportAction<T>(item)
6035
}
6136

62-
suspend fun remove(compendiumItem: A) {
63-
val characterItems = characterItems.findByCompendiumId(partyId, compendiumItem.id)
64-
65-
firestore.runTransaction { transaction ->
66-
compendium.remove(transaction, partyId, compendiumItem)
67-
characterItems.forEach { (characterId, item) ->
68-
saveCharacterItem(transaction, characterId, item, item.unlinkFromCompendium())
69-
}
70-
}
71-
}
37+
abstract suspend fun remove(compendiumItem: A)
7238

7339
fun get(id: Uuid): Flow<Either<CompendiumItemNotFound, A>> {
7440
return compendium.getLive(partyId, id)
7541
}
76-
77-
protected abstract suspend fun saveCharacterItem(
78-
transaction: Transaction,
79-
characterId: CharacterId,
80-
existing: B,
81-
new: B
82-
)
8342
}

0 commit comments

Comments
 (0)