Refactor the Adventure Book/Story/Line model. Avoid clearing of already downloaded stories.
This commit is contained in:
parent
8cfa0ac272
commit
250d9cbb7c
13 changed files with 342 additions and 229 deletions
|
|
@ -36,56 +36,67 @@ interface AdventureDao {
|
||||||
@Query("SELECT * from ${AdventureLineDbo.TABLE} where documentId = :documentId AND title = :storyTitle")
|
@Query("SELECT * from ${AdventureLineDbo.TABLE} where documentId = :documentId AND title = :storyTitle")
|
||||||
fun fetchAdventureLine(documentId: String, storyTitle: String): List<AdventureLineDbo>
|
fun fetchAdventureLine(documentId: String, storyTitle: String): List<AdventureLineDbo>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
fun insertBook(book: AdventureBookDbo)
|
fun insertBook(book: AdventureBookDbo): Long
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
fun updateBook(book: AdventureBookDbo)
|
fun updateBook(book: AdventureBookDbo)
|
||||||
|
|
||||||
|
fun insertOrUpdateBook(book: AdventureBookDbo) {
|
||||||
|
if (insertBook(book = book) == 1L) {
|
||||||
|
updateBook(book = book)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Delete(entity = AdventureBookDbo::class)
|
@Delete(entity = AdventureBookDbo::class)
|
||||||
fun deleteBook(id: AdventureBookDbo.BookId)
|
fun deleteBook(id: AdventureBookDbo.BookId)
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
fun insertStory(story: AdventureStoryDbo)
|
fun insertStory(story: AdventureStoryDbo): Long
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
fun updateStory(story: AdventureStoryDbo)
|
fun updateStory(story: AdventureStoryDbo)
|
||||||
|
|
||||||
|
fun insertOrUpdateStory(story: AdventureStoryDbo) {
|
||||||
|
if (insertStory(story = story) == 1L) {
|
||||||
|
updateStory(story = story)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Delete(entity = AdventureStoryDbo::class)
|
@Delete(entity = AdventureStoryDbo::class)
|
||||||
fun deleteStory(id: AdventureStoryDbo.StoryId)
|
fun deleteStory(id: AdventureStoryDbo.StoryId)
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
fun insertLine(line: AdventureLineDbo)
|
fun insertLine(line: AdventureLineDbo): Long
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
fun updateLine(line: AdventureLineDbo)
|
fun updateLine(line: AdventureLineDbo)
|
||||||
|
|
||||||
|
fun insertOrUpdateLine(line: AdventureLineDbo) {
|
||||||
|
if (insertLine(line = line) == 1L) {
|
||||||
|
updateLine(line = line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Delete(entity = AdventureLineDbo::class)
|
@Delete(entity = AdventureLineDbo::class)
|
||||||
fun deleteLines(id: AdventureLineDbo.LineId)
|
fun deleteLines(id: AdventureLineDbo.LineId)
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
fun update(
|
fun update(
|
||||||
booksToInsert: List<AdventureBookDbo>,
|
booksToInsertOrUpdate: List<AdventureBookDbo> = emptyList(),
|
||||||
booksToUpdate: List<AdventureBookDbo>,
|
booksToRemove: List<AdventureBookDbo.BookId> = emptyList(),
|
||||||
booksToRemove: List<AdventureBookDbo.BookId>,
|
storiesToInsertOrUpdate: List<AdventureStoryDbo> = emptyList(),
|
||||||
storiesToInsert: List<AdventureStoryDbo>,
|
storiesToRemove: List<AdventureStoryDbo.StoryId> = emptyList(),
|
||||||
storiesToUpdate: List<AdventureStoryDbo>,
|
linesToInsertOrUpdate: List<AdventureLineDbo> = emptyList(),
|
||||||
storiesToRemove: List<AdventureStoryDbo.StoryId>,
|
linesToRemove: List<AdventureLineDbo.LineId> = emptyList(),
|
||||||
linesToInsert: List<AdventureLineDbo>,
|
|
||||||
linesToUpdate: List<AdventureLineDbo>,
|
|
||||||
linesToRemove: List<AdventureLineDbo.LineId>,
|
|
||||||
) {
|
) {
|
||||||
// First remove the stuff
|
// First remove the stuff
|
||||||
linesToRemove.forEach { deleteLines(id = it) }
|
linesToRemove.forEach { deleteLines(id = it) }
|
||||||
storiesToRemove.forEach { deleteStory(id = it) }
|
storiesToRemove.forEach { deleteStory(id = it) }
|
||||||
booksToRemove.forEach { deleteBook(id = it) }
|
booksToRemove.forEach { deleteBook(id = it) }
|
||||||
// then insert the stuff
|
// then insert or update the stuff
|
||||||
booksToInsert.forEach { insertBook(book = it) }
|
booksToInsertOrUpdate.forEach { insertOrUpdateBook(book = it) }
|
||||||
storiesToInsert.forEach { insertStory(story = it) }
|
storiesToInsertOrUpdate.forEach { insertOrUpdateStory(story = it) }
|
||||||
linesToInsert.forEach { insertLine(line = it) }
|
linesToInsertOrUpdate.forEach { insertOrUpdateLine(line = it) }
|
||||||
// and update the stuff
|
|
||||||
booksToUpdate.forEach { updateBook(book = it) }
|
|
||||||
storiesToUpdate.forEach { updateStory(story = it) }
|
|
||||||
linesToUpdate.forEach { updateLine(line = it) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package com.pixelized.rplexicon.data.model.adventure
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
|
|
||||||
data class Adventure(
|
|
||||||
val bookTitle: String,
|
|
||||||
val bookIcon: Uri?,
|
|
||||||
val storyCategory: String?,
|
|
||||||
val storyTitle: String,
|
|
||||||
val storyBackground: Uri?,
|
|
||||||
val documentId: String,
|
|
||||||
val story: List<AdventureLine>,
|
|
||||||
)
|
|
||||||
|
|
@ -1,16 +1,6 @@
|
||||||
package com.pixelized.rplexicon.data.model.adventure
|
package com.pixelized.rplexicon.data.model.adventure
|
||||||
|
|
||||||
data class AdventureLine(
|
data class AdventureLine(
|
||||||
val format: Format,
|
val format: AdventureLineFormat,
|
||||||
val text: String,
|
val text: String,
|
||||||
) {
|
)
|
||||||
enum class Format {
|
|
||||||
TITLE,
|
|
||||||
SUB_TITLE,
|
|
||||||
CHAPTER,
|
|
||||||
PARAGRAPH,
|
|
||||||
DIALOGUE,
|
|
||||||
ANNEX,
|
|
||||||
LEGEND,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.pixelized.rplexicon.data.model.adventure
|
||||||
|
|
||||||
|
enum class AdventureLineFormat {
|
||||||
|
TITLE,
|
||||||
|
SUB_TITLE,
|
||||||
|
CHAPTER,
|
||||||
|
PARAGRAPH,
|
||||||
|
DIALOGUE,
|
||||||
|
ANNEX,
|
||||||
|
LEGEND,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.pixelized.rplexicon.data.model.adventure
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
data class Book(
|
||||||
|
val documentId: String,
|
||||||
|
val title: String,
|
||||||
|
val icon: Uri?,
|
||||||
|
val updating: Boolean,
|
||||||
|
val stories: List<Story>,
|
||||||
|
) {
|
||||||
|
data class Story(
|
||||||
|
val title: String,
|
||||||
|
val category: String?,
|
||||||
|
val background: Uri?,
|
||||||
|
val lines: List<Line>,
|
||||||
|
) {
|
||||||
|
data class Line(
|
||||||
|
val format: AdventureLineFormat,
|
||||||
|
val text: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package com.pixelized.rplexicon.data.parser.adventure
|
||||||
|
|
||||||
import com.google.api.services.sheets.v4.model.ValueRange
|
import com.google.api.services.sheets.v4.model.ValueRange
|
||||||
import com.pixelized.rplexicon.data.model.adventure.AdventureLine
|
import com.pixelized.rplexicon.data.model.adventure.AdventureLine
|
||||||
|
import com.pixelized.rplexicon.data.model.adventure.AdventureLineFormat
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
import com.pixelized.rplexicon.utilitary.extentions.sheet
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -22,15 +23,15 @@ class AdventureStoryLineParser @Inject constructor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ArrayList<*>.parseFormat(): AdventureLine.Format? =
|
private fun ArrayList<*>.parseFormat(): AdventureLineFormat? =
|
||||||
when (this.getOrNull(0) as? String) {
|
when (this.getOrNull(0) as? String) {
|
||||||
TITLE -> AdventureLine.Format.TITLE
|
TITLE -> AdventureLineFormat.TITLE
|
||||||
SUB_TITLE -> AdventureLine.Format.SUB_TITLE
|
SUB_TITLE -> AdventureLineFormat.SUB_TITLE
|
||||||
CHAPTER -> AdventureLine.Format.CHAPTER
|
CHAPTER -> AdventureLineFormat.CHAPTER
|
||||||
PARAGRAPH -> AdventureLine.Format.PARAGRAPH
|
PARAGRAPH -> AdventureLineFormat.PARAGRAPH
|
||||||
DIALOGUE -> AdventureLine.Format.DIALOGUE
|
DIALOGUE -> AdventureLineFormat.DIALOGUE
|
||||||
ANNEX -> AdventureLine.Format.ANNEX
|
ANNEX -> AdventureLineFormat.ANNEX
|
||||||
LEGEND -> AdventureLine.Format.LEGEND
|
LEGEND -> AdventureLineFormat.LEGEND
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,47 +3,54 @@ package com.pixelized.rplexicon.data.repository.adventure
|
||||||
import com.pixelized.rplexicon.data.database.adventure.AdventureBookDbo
|
import com.pixelized.rplexicon.data.database.adventure.AdventureBookDbo
|
||||||
import com.pixelized.rplexicon.data.database.adventure.AdventureLineDbo
|
import com.pixelized.rplexicon.data.database.adventure.AdventureLineDbo
|
||||||
import com.pixelized.rplexicon.data.database.adventure.AdventureStoryDbo
|
import com.pixelized.rplexicon.data.database.adventure.AdventureStoryDbo
|
||||||
import com.pixelized.rplexicon.data.model.adventure.Adventure
|
|
||||||
import com.pixelized.rplexicon.data.model.adventure.AdventureBook
|
import com.pixelized.rplexicon.data.model.adventure.AdventureBook
|
||||||
import com.pixelized.rplexicon.data.model.adventure.AdventureLine
|
import com.pixelized.rplexicon.data.model.adventure.AdventureLine
|
||||||
|
import com.pixelized.rplexicon.data.model.adventure.AdventureLineFormat
|
||||||
import com.pixelized.rplexicon.data.model.adventure.AdventureStory
|
import com.pixelized.rplexicon.data.model.adventure.AdventureStory
|
||||||
|
import com.pixelized.rplexicon.data.model.adventure.Book
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.string.toUriOrNull
|
import com.pixelized.rplexicon.utilitary.extentions.string.toUriOrNull
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AdventureDboFactory @Inject constructor() {
|
class AdventureDboFactory @Inject constructor() {
|
||||||
|
|
||||||
fun convertFromDbo(
|
fun convertFromDbo(
|
||||||
|
updatingBookId: String?,
|
||||||
books: List<AdventureBookDbo>,
|
books: List<AdventureBookDbo>,
|
||||||
stories: List<AdventureStoryDbo>,
|
stories: List<AdventureStoryDbo>,
|
||||||
lines: List<AdventureLineDbo>,
|
lines: List<AdventureLineDbo>,
|
||||||
): List<Adventure> {
|
): List<Book> {
|
||||||
return books.flatMap { book: AdventureBookDbo ->
|
val indexedStories = stories.groupBy { it.documentId }
|
||||||
stories
|
val indexedLines = lines.groupBy { it.documentId to it.story }
|
||||||
.filter { story -> story.documentId == book.documentId }
|
return books.map { book: AdventureBookDbo ->
|
||||||
.sortedBy { story -> story.index }
|
Book(
|
||||||
.map { story: AdventureStoryDbo ->
|
documentId = book.documentId,
|
||||||
Adventure(
|
title = book.title,
|
||||||
bookTitle = book.title,
|
icon = book.icon.toUriOrNull(),
|
||||||
bookIcon = book.icon.toUriOrNull(),
|
updating = book.documentId == updatingBookId,
|
||||||
documentId = book.documentId,
|
stories = indexedStories[book.documentId]
|
||||||
storyTitle = story.title,
|
?.sortedBy { story -> story.index }
|
||||||
storyCategory = story.category,
|
?.map { story ->
|
||||||
storyBackground = story.background.toUriOrNull(),
|
Book.Story(
|
||||||
story = lines
|
title = story.title,
|
||||||
.filter { it.documentId == story.documentId && it.story == story.title }
|
category = story.category,
|
||||||
.sortedBy { it.index }
|
background = story.background.toUriOrNull(),
|
||||||
.map { line ->
|
lines = indexedLines[book.documentId to story.title]
|
||||||
AdventureLine(
|
?.sortedBy { it.index }
|
||||||
text = line.text,
|
?.map { line ->
|
||||||
format = try {
|
Book.Story.Line(
|
||||||
AdventureLine.Format.valueOf(line.format)
|
text = line.text,
|
||||||
} catch (_: Exception) {
|
format = try {
|
||||||
AdventureLine.Format.PARAGRAPH
|
AdventureLineFormat.valueOf(line.format)
|
||||||
},
|
} catch (_: Exception) {
|
||||||
)
|
AdventureLineFormat.PARAGRAPH
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
?: emptyList(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
?: emptyList(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import com.pixelized.rplexicon.data.database.CompanionDatabase
|
||||||
import com.pixelized.rplexicon.data.database.adventure.AdventureBookDbo
|
import com.pixelized.rplexicon.data.database.adventure.AdventureBookDbo
|
||||||
import com.pixelized.rplexicon.data.database.adventure.AdventureLineDbo
|
import com.pixelized.rplexicon.data.database.adventure.AdventureLineDbo
|
||||||
import com.pixelized.rplexicon.data.database.adventure.AdventureStoryDbo
|
import com.pixelized.rplexicon.data.database.adventure.AdventureStoryDbo
|
||||||
import com.pixelized.rplexicon.data.model.adventure.Adventure
|
import com.pixelized.rplexicon.data.model.adventure.Book
|
||||||
import com.pixelized.rplexicon.data.parser.adventure.AdventureBookParser
|
import com.pixelized.rplexicon.data.parser.adventure.AdventureBookParser
|
||||||
import com.pixelized.rplexicon.data.parser.adventure.AdventureStoryLineParser
|
import com.pixelized.rplexicon.data.parser.adventure.AdventureStoryLineParser
|
||||||
import com.pixelized.rplexicon.data.parser.adventure.AdventureStoryParser
|
import com.pixelized.rplexicon.data.parser.adventure.AdventureStoryParser
|
||||||
|
|
@ -17,6 +17,7 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.NonCancellable
|
import kotlinx.coroutines.NonCancellable
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
@ -24,7 +25,6 @@ import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AdventureRepository @Inject constructor(
|
class AdventureRepository @Inject constructor(
|
||||||
|
|
@ -41,13 +41,16 @@ class AdventureRepository @Inject constructor(
|
||||||
var lastSuccessFullUpdate: Update = Update.INITIAL
|
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private val updatingBookId = MutableStateFlow<String?>(null)
|
||||||
private val adventures = database.let { database ->
|
private val adventures = database.let { database ->
|
||||||
combine(
|
combine(
|
||||||
|
updatingBookId,
|
||||||
database.getBooksFlow(),
|
database.getBooksFlow(),
|
||||||
database.getStoriesFlow(),
|
database.getStoriesFlow(),
|
||||||
database.getStoryLinesFlow(),
|
database.getStoryLinesFlow(),
|
||||||
) { books, stories, lines ->
|
) { updatingBookId, books, stories, lines ->
|
||||||
adventureDboFactory.convertFromDbo(
|
adventureDboFactory.convertFromDbo(
|
||||||
|
updatingBookId = updatingBookId,
|
||||||
books = books,
|
books = books,
|
||||||
stories = stories,
|
stories = stories,
|
||||||
lines = lines,
|
lines = lines,
|
||||||
|
|
@ -59,49 +62,112 @@ class AdventureRepository @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bookFlow(): Flow<List<Adventure>> {
|
fun booksFlow(): Flow<List<Book>> {
|
||||||
return adventures
|
return adventures
|
||||||
}
|
}
|
||||||
|
|
||||||
fun storyFlow(bookTitle: String): Flow<List<Adventure>> {
|
fun bookFlow(documentId: String): Flow<Book?> {
|
||||||
return adventures.map { adventures ->
|
return adventures.map { adventures ->
|
||||||
adventures.filter { adventure ->
|
adventures.firstOrNull { adventure ->
|
||||||
adventure.bookTitle == bookTitle
|
adventure.documentId == documentId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun adventureFlow(documentId: String, adventureTitle: String): Flow<Adventure?> {
|
fun storyFlow(documentId: String, storyTitle: String): Flow<Book.Story?> {
|
||||||
return adventures.map { adventures ->
|
return adventures.map { adventures ->
|
||||||
adventures.firstOrNull { adventure ->
|
adventures.firstNotNullOfOrNull { adventure ->
|
||||||
adventure.documentId == documentId && adventure.storyTitle == adventureTitle
|
if (adventure.documentId == documentId) {
|
||||||
|
adventure.stories.firstOrNull { it.title == storyTitle }
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||||
suspend fun fetchBooks() = update {
|
suspend fun fetchBooks() {
|
||||||
fetchAndCompareBooks()
|
val exceptions = mutableListOf<Exception>()
|
||||||
|
val cache = database.fetchAdventureBooks()
|
||||||
|
|
||||||
(booksToInsert + booksToUpdate).forEach { book ->
|
try {
|
||||||
fetchAndCompareStories(documentId = book.documentId)
|
val update = service.fetchAdventureBooks().sortedBy { it.title }
|
||||||
|
|
||||||
|
val booksToRemove = cache.map { it.id }.toMutableList()
|
||||||
|
val booksToInsertOrUpdate = mutableListOf<AdventureBookDbo>()
|
||||||
|
|
||||||
|
update.forEach { item ->
|
||||||
|
booksToRemove.remove(item.id)
|
||||||
|
booksToInsertOrUpdate.add(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
database.update(
|
||||||
|
booksToRemove = booksToRemove,
|
||||||
|
)
|
||||||
|
|
||||||
|
booksToInsertOrUpdate.forEach { book ->
|
||||||
|
updatingBookId.value = book.documentId
|
||||||
|
database.update(
|
||||||
|
booksToInsertOrUpdate = listOf(book),
|
||||||
|
)
|
||||||
|
update {
|
||||||
|
try {
|
||||||
|
fetchAndCompareStories(
|
||||||
|
documentId = book.documentId
|
||||||
|
)
|
||||||
|
(storiesToInsertOrUpdate).forEach { story ->
|
||||||
|
try {
|
||||||
|
fetchAndCompareLines(
|
||||||
|
documentId = story.documentId,
|
||||||
|
storyTitle = story.title
|
||||||
|
)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
exceptions.add(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
exceptions.add(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastSuccessFullUpdate = Update.currentTime()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
exceptions.add(exception)
|
||||||
|
} finally {
|
||||||
|
updatingBookId.value = null
|
||||||
}
|
}
|
||||||
|
if (exceptions.isNotEmpty()) {
|
||||||
(storiesToInsert + storiesToUpdate).forEach { story ->
|
throw exceptions.first()
|
||||||
fetchAndCompareLines(documentId = story.documentId, storyTitle = story.title)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSuccessFullUpdate = Update.currentTime()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||||
suspend fun fetchStories(
|
suspend fun fetchStories(
|
||||||
documentId: String,
|
documentId: String,
|
||||||
) = update {
|
) = update {
|
||||||
fetchAndCompareStories(documentId = documentId)
|
val exceptions = mutableListOf<Exception>()
|
||||||
|
try {
|
||||||
|
updatingBookId.value = documentId
|
||||||
|
fetchAndCompareStories(documentId = documentId)
|
||||||
|
|
||||||
(storiesToInsert + storiesToUpdate).forEach { story ->
|
(storiesToInsertOrUpdate).forEach { story ->
|
||||||
fetchAndCompareLines(documentId = story.documentId, storyTitle = story.title)
|
try {
|
||||||
|
fetchAndCompareLines(
|
||||||
|
documentId = story.documentId,
|
||||||
|
storyTitle = story.title,
|
||||||
|
)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
exceptions.add(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
exceptions.add(exception)
|
||||||
|
} finally {
|
||||||
|
updatingBookId.value = null
|
||||||
|
}
|
||||||
|
if (exceptions.isNotEmpty()) {
|
||||||
|
throw exceptions.first()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,36 +176,31 @@ class AdventureRepository @Inject constructor(
|
||||||
documentId: String,
|
documentId: String,
|
||||||
storyTitle: String,
|
storyTitle: String,
|
||||||
) = update {
|
) = update {
|
||||||
// specific case for adventure fetching, need to update the story too as the background is stored there.
|
val exceptions = mutableListOf<Exception>()
|
||||||
service.fetchAdventureStories(
|
try {
|
||||||
documentId = documentId,
|
updatingBookId.value = documentId
|
||||||
).firstOrNull { story ->
|
// specific case for adventure fetching, need to update the story too as the background is stored there.
|
||||||
story.documentId == documentId && story.title == storyTitle
|
service.fetchAdventureStories(
|
||||||
}?.let { story ->
|
documentId = documentId,
|
||||||
storiesToUpdate.add(story)
|
).firstOrNull { story ->
|
||||||
}
|
story.documentId == documentId && story.title == storyTitle
|
||||||
|
}?.let { story ->
|
||||||
fetchAndCompareLines(documentId = documentId, storyTitle = storyTitle)
|
storiesToInsertOrUpdate.add(story)
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun DatabaseUpdateScope.fetchAndCompareBooks() {
|
|
||||||
val cache = database.fetchAdventureBooks()
|
|
||||||
val update = service.fetchAdventureBooks()
|
|
||||||
|
|
||||||
val toRemove = cache.map { it.id }.toMutableList()
|
|
||||||
val toInsert = mutableListOf<AdventureBookDbo>()
|
|
||||||
val toUpdate = mutableListOf<AdventureBookDbo>()
|
|
||||||
|
|
||||||
update.forEach { item ->
|
|
||||||
when (toRemove.remove(item.id)) {
|
|
||||||
true -> toUpdate.add(item)
|
|
||||||
else -> toInsert.add(item)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
booksToInsert.addAll(elements = toInsert)
|
try {
|
||||||
booksToUpdate.addAll(elements = toUpdate)
|
fetchAndCompareLines(documentId = documentId, storyTitle = storyTitle)
|
||||||
booksToRemove.addAll(elements = toRemove)
|
} catch (exception: Exception) {
|
||||||
|
exceptions.add(exception)
|
||||||
|
}
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
exceptions.add(exception)
|
||||||
|
} finally {
|
||||||
|
updatingBookId.value = null
|
||||||
|
}
|
||||||
|
if (exceptions.isNotEmpty()) {
|
||||||
|
throw exceptions.first()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun DatabaseUpdateScope.fetchAndCompareStories(
|
private suspend fun DatabaseUpdateScope.fetchAndCompareStories(
|
||||||
|
|
@ -151,7 +212,7 @@ class AdventureRepository @Inject constructor(
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return cache?.let {
|
return cache?.let {
|
||||||
it.revision < item.revision || cache.index != item.index
|
it.revision < item.revision || cache.index != item.index
|
||||||
} ?: false
|
} ?: true
|
||||||
}
|
}
|
||||||
|
|
||||||
val cache = database.fetchAdventureStories(
|
val cache = database.fetchAdventureStories(
|
||||||
|
|
@ -164,49 +225,39 @@ class AdventureRepository @Inject constructor(
|
||||||
)
|
)
|
||||||
|
|
||||||
val toRemove = cache.keys.toMutableList()
|
val toRemove = cache.keys.toMutableList()
|
||||||
val toInsert = mutableListOf<AdventureStoryDbo>()
|
val toInsertOrUpdate = mutableListOf<AdventureStoryDbo>()
|
||||||
val toUpdate = mutableListOf<AdventureStoryDbo>()
|
|
||||||
|
|
||||||
update.forEach { item ->
|
update.forEach { item ->
|
||||||
when (toRemove.remove(item.id)) {
|
toRemove.remove(item.id)
|
||||||
true -> if (shouldUpdate(cache = cache[item.id], item = item)) toUpdate.add(item)
|
if (shouldUpdate(cache = cache[item.id], item = item)) {
|
||||||
else -> toInsert.add(item)
|
toInsertOrUpdate.add(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storiesToInsert.addAll(elements = toInsert)
|
|
||||||
storiesToUpdate.addAll(elements = toUpdate)
|
|
||||||
storiesToRemove.addAll(elements = toRemove)
|
storiesToRemove.addAll(elements = toRemove)
|
||||||
|
storiesToInsertOrUpdate.addAll(elements = toInsertOrUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun DatabaseUpdateScope.fetchAndCompareLines(
|
private suspend fun DatabaseUpdateScope.fetchAndCompareLines(
|
||||||
documentId: String,
|
documentId: String,
|
||||||
storyTitle: String,
|
storyTitle: String,
|
||||||
) {
|
) {
|
||||||
val cache = database.fetchAdventureLine(
|
val cache: List<AdventureLineDbo> = database.fetchAdventureLine(
|
||||||
documentId = documentId,
|
documentId = documentId,
|
||||||
storyTitle = storyTitle,
|
storyTitle = storyTitle,
|
||||||
)
|
)
|
||||||
val update = service.fetchAdventureLine(
|
val update: List<AdventureLineDbo> = service.fetchAdventureLine(
|
||||||
documentId = documentId,
|
documentId = documentId,
|
||||||
storyTitle = storyTitle,
|
storyTitle = storyTitle,
|
||||||
)
|
)
|
||||||
// if cache is smaller than the update we need to insert
|
// if cache is bigger than the update we need to delete the excess lines.
|
||||||
if (cache.size < update.size) {
|
|
||||||
(cache.size until update.size).forEach {
|
|
||||||
linesToInsert.add(update[it])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if cache is bigger than the update we need to delete
|
|
||||||
if (update.size < cache.size) {
|
if (update.size < cache.size) {
|
||||||
(update.size until cache.size).forEach {
|
(update.size until cache.size).forEach {
|
||||||
linesToRemove.add(cache[it].id)
|
linesToRemove.add(cache[it].id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// then we update the rest
|
// then we insert / update
|
||||||
(0 until min(cache.size, update.size)).forEach {
|
linesToInsertOrUpdate.addAll(update)
|
||||||
linesToUpdate.add(update[it])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun update(
|
private suspend inline fun update(
|
||||||
|
|
@ -217,27 +268,21 @@ class AdventureRepository @Inject constructor(
|
||||||
lambda.invoke(update)
|
lambda.invoke(update)
|
||||||
|
|
||||||
database.update(
|
database.update(
|
||||||
booksToInsert = update.booksToInsert,
|
booksToInsertOrUpdate = update.booksToInsertOrUpdate,
|
||||||
booksToUpdate = update.booksToUpdate,
|
|
||||||
booksToRemove = update.booksToRemove,
|
booksToRemove = update.booksToRemove,
|
||||||
storiesToInsert = update.storiesToInsert,
|
storiesToInsertOrUpdate = update.storiesToInsertOrUpdate,
|
||||||
storiesToUpdate = update.storiesToUpdate,
|
|
||||||
storiesToRemove = update.storiesToRemove,
|
storiesToRemove = update.storiesToRemove,
|
||||||
linesToInsert = update.linesToInsert,
|
linesToInsertOrUpdate = update.linesToInsertOrUpdate,
|
||||||
linesToUpdate = update.linesToUpdate,
|
|
||||||
linesToRemove = update.linesToRemove,
|
linesToRemove = update.linesToRemove,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class DatabaseUpdateScope(
|
private data class DatabaseUpdateScope(
|
||||||
val booksToInsert: MutableList<AdventureBookDbo> = mutableListOf(),
|
val booksToInsertOrUpdate: MutableList<AdventureBookDbo> = mutableListOf(),
|
||||||
val booksToUpdate: MutableList<AdventureBookDbo> = mutableListOf(),
|
|
||||||
val booksToRemove: MutableList<AdventureBookDbo.BookId> = mutableListOf(),
|
val booksToRemove: MutableList<AdventureBookDbo.BookId> = mutableListOf(),
|
||||||
val storiesToInsert: MutableList<AdventureStoryDbo> = mutableListOf(),
|
val storiesToInsertOrUpdate: MutableList<AdventureStoryDbo> = mutableListOf(),
|
||||||
val storiesToUpdate: MutableList<AdventureStoryDbo> = mutableListOf(),
|
|
||||||
val storiesToRemove: MutableList<AdventureStoryDbo.StoryId> = mutableListOf(),
|
val storiesToRemove: MutableList<AdventureStoryDbo.StoryId> = mutableListOf(),
|
||||||
val linesToInsert: MutableList<AdventureLineDbo> = mutableListOf(),
|
val linesToInsertOrUpdate: MutableList<AdventureLineDbo> = mutableListOf(),
|
||||||
val linesToUpdate: MutableList<AdventureLineDbo> = mutableListOf(),
|
|
||||||
val linesToRemove: MutableList<AdventureLineDbo.LineId> = mutableListOf(),
|
val linesToRemove: MutableList<AdventureLineDbo.LineId> = mutableListOf(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -270,13 +315,9 @@ class AdventureRepository @Inject constructor(
|
||||||
documentId: String,
|
documentId: String,
|
||||||
storyTitle: String,
|
storyTitle: String,
|
||||||
): List<AdventureLineDbo> {
|
): List<AdventureLineDbo> {
|
||||||
return try {
|
return googleRepository.fetch { sheet ->
|
||||||
googleRepository.fetch { sheet ->
|
val request = sheet.get(documentId, storyTitle)
|
||||||
val request = sheet.get(documentId, storyTitle)
|
adventureStoryLineParser.parse(sheet = request.execute())
|
||||||
adventureStoryLineParser.parse(sheet = request.execute())
|
|
||||||
}
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
emptyList()
|
|
||||||
}.mapIndexed { index, line ->
|
}.mapIndexed { index, line ->
|
||||||
adventureDboFactory.convertToDbo(
|
adventureDboFactory.convertToDbo(
|
||||||
adventureLine = line,
|
adventureLine = line,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
package com.pixelized.rplexicon.ui.screens.adventure.book
|
package com.pixelized.rplexicon.ui.screens.adventure.book
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.net.Uri
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
|
@ -20,10 +22,13 @@ import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
import com.pixelized.rplexicon.ui.composable.images.BackgroundImage
|
||||||
import com.pixelized.rplexicon.ui.composable.images.rememberBackgroundGradient
|
import com.pixelized.rplexicon.ui.composable.images.rememberBackgroundGradient
|
||||||
|
import com.pixelized.rplexicon.ui.composable.images.rememberSaturationFilter
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
import com.pixelized.rplexicon.utilitary.annotateWithDropCap
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
|
|
@ -34,6 +39,7 @@ data class AdventureBookUio(
|
||||||
val bookIcon: Any?,
|
val bookIcon: Any?,
|
||||||
val documentId: String,
|
val documentId: String,
|
||||||
val adventureTitle: String?,
|
val adventureTitle: String?,
|
||||||
|
val updating: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -47,14 +53,19 @@ fun AdventureBook(
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(shape = shape)
|
.clip(shape = shape)
|
||||||
.clickable(onClick = onClick)
|
.clickable(enabled = item.updating.not(), onClick = onClick)
|
||||||
.then(other = modifier),
|
.then(other = modifier),
|
||||||
) {
|
) {
|
||||||
BackgroundImage(
|
BackgroundImage(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.matchParentSize()
|
.matchParentSize()
|
||||||
.align(alignment = Alignment.TopCenter),
|
.align(alignment = Alignment.TopCenter),
|
||||||
colorFilter = null,
|
colorFilter = rememberSaturationFilter(
|
||||||
|
saturation = animateFloatAsState(
|
||||||
|
targetValue = if (item.updating) 0f else 1f,
|
||||||
|
label = "book item saturation animation"
|
||||||
|
).value,
|
||||||
|
),
|
||||||
background = rememberBackgroundGradient(0.2f, 1.0f),
|
background = rememberBackgroundGradient(0.2f, 1.0f),
|
||||||
contentScale = ContentScale.FillWidth,
|
contentScale = ContentScale.FillWidth,
|
||||||
alignment = Alignment.TopCenter,
|
alignment = Alignment.TopCenter,
|
||||||
|
|
@ -77,18 +88,38 @@ fun AdventureBook(
|
||||||
@Composable
|
@Composable
|
||||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
private fun AdventureItemPreview() {
|
private fun AdventureItemPreview(
|
||||||
|
@PreviewParameter(AdventureItemProvider::class) preview: AdventureBookUio,
|
||||||
|
) {
|
||||||
LexiconTheme {
|
LexiconTheme {
|
||||||
Surface {
|
Surface {
|
||||||
AdventureBook(
|
AdventureBook(
|
||||||
item = AdventureBookUio(
|
modifier = Modifier
|
||||||
bookIcon = R.drawable.icbg_book_generic_c_unfaded,
|
.fillMaxWidth(0.4f)
|
||||||
bookTitle = "Les chroniques d'une orc",
|
.aspectRatio(ratio = 0.8f),
|
||||||
documentId = "",
|
item = preview,
|
||||||
adventureTitle = null,
|
|
||||||
),
|
|
||||||
onClick = {},
|
onClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AdventureItemProvider : PreviewParameterProvider<AdventureBookUio> {
|
||||||
|
override val values: Sequence<AdventureBookUio> = sequenceOf(
|
||||||
|
AdventureBookUio(
|
||||||
|
bookIcon = R.drawable.icbg_book_generic_c_unfaded,
|
||||||
|
bookTitle = "Les chroniques d'une orc",
|
||||||
|
documentId = "",
|
||||||
|
updating = true,
|
||||||
|
adventureTitle = null,
|
||||||
|
),
|
||||||
|
AdventureBookUio(
|
||||||
|
bookIcon = R.drawable.icbg_book_generic_c_unfaded,
|
||||||
|
bookTitle = "Les chroniques d'une orc",
|
||||||
|
documentId = "",
|
||||||
|
updating = false,
|
||||||
|
adventureTitle = null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -177,8 +177,23 @@ private fun AdventureListPreview(
|
||||||
bookTitle = "Les chroniques d'une orc",
|
bookTitle = "Les chroniques d'une orc",
|
||||||
bookIcon = null,
|
bookIcon = null,
|
||||||
documentId = "",
|
documentId = "",
|
||||||
|
updating = true,
|
||||||
adventureTitle = null,
|
adventureTitle = null,
|
||||||
)
|
),
|
||||||
|
AdventureBookUio(
|
||||||
|
bookTitle = "Le tome de Strahd",
|
||||||
|
bookIcon = null,
|
||||||
|
documentId = "",
|
||||||
|
updating = false,
|
||||||
|
adventureTitle = null,
|
||||||
|
),
|
||||||
|
AdventureBookUio(
|
||||||
|
bookTitle = "Carnet de voyage d'Unathana",
|
||||||
|
bookIcon = null,
|
||||||
|
documentId = "",
|
||||||
|
updating = false,
|
||||||
|
adventureTitle = null,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -29,23 +29,19 @@ class AdventureBooksViewModel @Inject constructor(
|
||||||
private val _isLoading = mutableStateOf(false)
|
private val _isLoading = mutableStateOf(false)
|
||||||
val isLoading: State<Boolean> get() = _isLoading
|
val isLoading: State<Boolean> get() = _isLoading
|
||||||
|
|
||||||
private val _books = adventureRepository.bookFlow()
|
private val _books = adventureRepository.booksFlow()
|
||||||
.map { adventures ->
|
.map { adventures ->
|
||||||
adventures
|
adventures
|
||||||
.groupBy { it.documentId }
|
.sortedBy { it.title }
|
||||||
.mapValues { (_, adventures) ->
|
.map { book ->
|
||||||
val adventure = adventures.first()
|
|
||||||
AdventureBookUio(
|
AdventureBookUio(
|
||||||
bookTitle = adventure.bookTitle,
|
bookTitle = book.title,
|
||||||
bookIcon = adventure.bookIcon,
|
bookIcon = book.icon,
|
||||||
documentId = adventure.documentId,
|
documentId = book.documentId,
|
||||||
adventureTitle = if (adventures.size == 1) adventure.storyTitle else null
|
updating = book.updating,
|
||||||
|
adventureTitle = book.stories.takeIf { it.size == 1 }?.firstOrNull()?.title
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.values
|
|
||||||
.sortedBy {
|
|
||||||
it.bookTitle
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val books: State<List<AdventureBookUio>>
|
val books: State<List<AdventureBookUio>>
|
||||||
|
|
@ -67,7 +63,6 @@ class AdventureBooksViewModel @Inject constructor(
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
|
|
||||||
adventureRepository.fetchBooks()
|
adventureRepository.fetchBooks()
|
||||||
}
|
}
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
|
|
|
||||||
|
|
@ -38,24 +38,24 @@ class AdventureStoriesViewModel @Inject constructor(
|
||||||
argument.bookTitle
|
argument.bookTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _chapters = adventureRepository.storyFlow(bookTitle = argument.bookTitle)
|
private val _chapters = adventureRepository.bookFlow(documentId = argument.documentId)
|
||||||
.map { adventures ->
|
.map { book ->
|
||||||
adventures
|
book?.stories
|
||||||
.filter { it.bookTitle == argument.bookTitle && it.documentId == argument.documentId }
|
?.groupBy { it.category ?: "" }
|
||||||
.groupBy { it.storyCategory ?: "" }
|
?.flatMap { entry ->
|
||||||
.flatMap { entry ->
|
|
||||||
val header = listOf(
|
val header = listOf(
|
||||||
AdventureStoriesUio.AdventureCategory(title = entry.key)
|
AdventureStoriesUio.AdventureCategory(title = entry.key)
|
||||||
)
|
)
|
||||||
val stories = entry.value.map {
|
val stories = entry.value.map {
|
||||||
AdventureStoriesUio.AdventureItem(
|
AdventureStoriesUio.AdventureItem(
|
||||||
documentId = it.documentId,
|
documentId = book.documentId,
|
||||||
bookTitle = it.bookTitle,
|
bookTitle = book.title,
|
||||||
adventureTitle = it.storyTitle,
|
adventureTitle = it.title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
header + stories
|
header + stories
|
||||||
}
|
}
|
||||||
|
?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val chapters: State<List<AdventureStoriesUio>>
|
val chapters: State<List<AdventureStoriesUio>>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.pixelized.rplexicon.ui.screens.adventure.detail
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
|
@ -10,7 +11,7 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.pixelized.rplexicon.data.model.adventure.AdventureLine.Format
|
import com.pixelized.rplexicon.data.model.adventure.AdventureLineFormat
|
||||||
import com.pixelized.rplexicon.data.repository.adventure.AdventureRepository
|
import com.pixelized.rplexicon.data.repository.adventure.AdventureRepository
|
||||||
import com.pixelized.rplexicon.ui.navigation.screens.adventureDetailArgument
|
import com.pixelized.rplexicon.ui.navigation.screens.adventureDetailArgument
|
||||||
import com.pixelized.rplexicon.ui.screens.adventure.detail.AdventureLineUio.Style
|
import com.pixelized.rplexicon.ui.screens.adventure.detail.AdventureLineUio.Style
|
||||||
|
|
@ -30,9 +31,9 @@ class AdventureDetailViewModel @Inject constructor(
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val argument = savedStateHandle.adventureDetailArgument
|
private val argument = savedStateHandle.adventureDetailArgument
|
||||||
|
|
||||||
private val detail = adventureRepository.adventureFlow(
|
private val detail = adventureRepository.storyFlow(
|
||||||
documentId = argument.documentId,
|
documentId = argument.documentId,
|
||||||
adventureTitle = argument.adventureTitle,
|
storyTitle = argument.adventureTitle,
|
||||||
).stateIn(
|
).stateIn(
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
started = SharingStarted.Lazily,
|
started = SharingStarted.Lazily,
|
||||||
|
|
@ -44,30 +45,30 @@ class AdventureDetailViewModel @Inject constructor(
|
||||||
|
|
||||||
val background: State<Uri?>
|
val background: State<Uri?>
|
||||||
@Composable
|
@Composable
|
||||||
|
@Stable
|
||||||
get() = remember(detail) {
|
get() = remember(detail) {
|
||||||
detail.map { it?.storyBackground }
|
detail.map { it?.background }
|
||||||
}.collectAsState(initial = null)
|
}.collectAsState(initial = null)
|
||||||
|
|
||||||
val adventure: State<List<AdventureLineUio>>
|
val adventure: State<List<AdventureLineUio>>
|
||||||
@Composable
|
@Composable
|
||||||
get() = remember(detail) {
|
get() = remember(detail) {
|
||||||
detail
|
detail.map { adventure ->
|
||||||
.map { adventure ->
|
adventure?.lines?.map { line ->
|
||||||
adventure?.story?.map { line ->
|
AdventureLineUio(
|
||||||
AdventureLineUio(
|
text = line.text,
|
||||||
text = line.text,
|
style = when (line.format) {
|
||||||
style = when (line.format) {
|
AdventureLineFormat.TITLE -> Style.TITLE
|
||||||
Format.TITLE -> Style.TITLE
|
AdventureLineFormat.SUB_TITLE -> Style.SUB_TITLE
|
||||||
Format.SUB_TITLE -> Style.SUB_TITLE
|
AdventureLineFormat.CHAPTER -> Style.CHAPTER
|
||||||
Format.CHAPTER -> Style.CHAPTER
|
AdventureLineFormat.PARAGRAPH -> Style.PARAGRAPH
|
||||||
Format.PARAGRAPH -> Style.PARAGRAPH
|
AdventureLineFormat.DIALOGUE -> Style.DIALOGUE
|
||||||
Format.DIALOGUE -> Style.DIALOGUE
|
AdventureLineFormat.ANNEX -> Style.ANNEX
|
||||||
Format.ANNEX -> Style.ANNEX
|
AdventureLineFormat.LEGEND -> Style.LEGEND
|
||||||
Format.LEGEND -> Style.LEGEND
|
},
|
||||||
},
|
)
|
||||||
)
|
} ?: emptyList()
|
||||||
} ?: emptyList()
|
}
|
||||||
}
|
|
||||||
}.collectAsState(initial = emptyList())
|
}.collectAsState(initial = emptyList())
|
||||||
|
|
||||||
private val titleCell: State<AdventureLineUio?>
|
private val titleCell: State<AdventureLineUio?>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue