Add RemoteConfig feature and like it to the LandingPage.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2024-06-21 15:41:18 +02:00
parent e62b558c21
commit 1040f54d23
23 changed files with 485 additions and 298 deletions

View file

@ -148,6 +148,7 @@ dependencies {
implementation("com.google.firebase:firebase-analytics-ktx") implementation("com.google.firebase:firebase-analytics-ktx")
implementation("com.google.firebase:firebase-auth-ktx") implementation("com.google.firebase:firebase-auth-ktx")
implementation("com.google.firebase:firebase-database-ktx") implementation("com.google.firebase:firebase-database-ktx")
implementation("com.google.firebase:firebase-config-ktx")
// Hilt: Dependency injection // Hilt: Dependency injection
implementation("androidx.hilt:hilt-navigation-compose:1.2.0") implementation("androidx.hilt:hilt-navigation-compose:1.2.0")

View file

@ -6,7 +6,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.data.repository.adventure.AdventureRepository
import com.pixelized.rplexicon.data.repository.character.ActionRepository import com.pixelized.rplexicon.data.repository.character.ActionRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
@ -16,6 +15,7 @@ import com.pixelized.rplexicon.data.repository.character.InventoryRepository
import com.pixelized.rplexicon.data.repository.character.ObjectActionRepository import com.pixelized.rplexicon.data.repository.character.ObjectActionRepository
import com.pixelized.rplexicon.data.repository.character.SkillRepository import com.pixelized.rplexicon.data.repository.character.SkillRepository
import com.pixelized.rplexicon.data.repository.character.SpellRepository import com.pixelized.rplexicon.data.repository.character.SpellRepository
import com.pixelized.rplexicon.data.repository.firebase.RemoteConfigRepository
import com.pixelized.rplexicon.data.repository.lexicon.CategoryOrderRepository import com.pixelized.rplexicon.data.repository.lexicon.CategoryOrderRepository
import com.pixelized.rplexicon.data.repository.lexicon.LexiconRepository import com.pixelized.rplexicon.data.repository.lexicon.LexiconRepository
import com.pixelized.rplexicon.data.repository.lexicon.LocationRepository import com.pixelized.rplexicon.data.repository.lexicon.LocationRepository
@ -47,7 +47,7 @@ class LauncherViewModel @Inject constructor(
descriptionRepository: DescriptionRepository, descriptionRepository: DescriptionRepository,
inventoryRepository: InventoryRepository, inventoryRepository: InventoryRepository,
equipmentRepository: EquipmentRepository, equipmentRepository: EquipmentRepository,
adventureRepository: AdventureRepository, removeConRepository: RemoteConfigRepository // Unused but injected to initialize it.
) : ViewModel() { ) : ViewModel() {
private val _error = MutableStateFlow<FetchErrorUio?>(null) private val _error = MutableStateFlow<FetchErrorUio?>(null)

View file

@ -0,0 +1,10 @@
package com.pixelized.rplexicon.data.model
data class LexiconConfig(
val featureAdventure: Boolean,
val featureLexicon: Boolean,
val featureMaps: Boolean,
val featureQuests: Boolean,
val featureSummary: Boolean,
val featureSearch: Boolean,
)

View file

@ -5,7 +5,7 @@ import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.parser.AttackParser import com.pixelized.rplexicon.data.parser.AttackParser
import com.pixelized.rplexicon.data.repository.CharacterBinder import com.pixelized.rplexicon.data.repository.CharacterBinder
import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.script.ScriptExecutor import com.pixelized.rplexicon.script.ScriptExecutor
import com.pixelized.rplexicon.utilitary.Update import com.pixelized.rplexicon.utilitary.Update
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
@ -24,7 +24,7 @@ import javax.inject.Singleton
class ActionRepository @Inject constructor( class ActionRepository @Inject constructor(
private val googleRepository: GoogleSheetServiceRepository, private val googleRepository: GoogleSheetServiceRepository,
private val actionParser: AttackParser, private val actionParser: AttackParser,
firebaseRepository: FirebaseRepository, firebaseRepository: RealtimeDatabaseRepository,
) { ) {
private val _actions = MutableStateFlow<Map<String, List<Attack>>>(emptyMap()) private val _actions = MutableStateFlow<Map<String, List<Attack>>>(emptyMap())
val actions: StateFlow<Map<String, List<Attack>>> = val actions: StateFlow<Map<String, List<Attack>>> =

View file

@ -2,7 +2,7 @@ package com.pixelized.rplexicon.data.repository.character
import com.pixelized.rplexicon.data.model.alteration.Alteration import com.pixelized.rplexicon.data.model.alteration.Alteration
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -18,7 +18,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class ActiveAlterationRepository @Inject constructor( class ActiveAlterationRepository @Inject constructor(
alterationRepository: AlterationRepository, alterationRepository: AlterationRepository,
firebaseRepository: FirebaseRepository, firebaseRepository: RealtimeDatabaseRepository,
) { ) {
private val activeAlterations: StateFlow<Map<String, List<Alteration>>> = private val activeAlterations: StateFlow<Map<String, List<Alteration>>> =
alterationRepository.getAlterations() alterationRepository.getAlterations()

View file

@ -6,7 +6,7 @@ import com.pixelized.rplexicon.data.model.alteration.Alteration
import com.pixelized.rplexicon.data.parser.alteration.AlterationParser import com.pixelized.rplexicon.data.parser.alteration.AlterationParser
import com.pixelized.rplexicon.data.repository.CharacterBinder import com.pixelized.rplexicon.data.repository.CharacterBinder
import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.script.ScriptExecutor import com.pixelized.rplexicon.script.ScriptExecutor
import com.pixelized.rplexicon.utilitary.Update import com.pixelized.rplexicon.utilitary.Update
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
@ -27,7 +27,7 @@ import javax.inject.Singleton
class AlterationRepository @Inject constructor( class AlterationRepository @Inject constructor(
private val googleRepository: GoogleSheetServiceRepository, private val googleRepository: GoogleSheetServiceRepository,
private val alterationParser: AlterationParser, private val alterationParser: AlterationParser,
firebaseRepository: FirebaseRepository, firebaseRepository: RealtimeDatabaseRepository,
) { ) {
private val alterations = MutableStateFlow<Map<String, List<Alteration>>>(emptyMap()) private val alterations = MutableStateFlow<Map<String, List<Alteration>>>(emptyMap())
private val assignedAlterations: StateFlow<Map<String, List<Alteration>>> = private val assignedAlterations: StateFlow<Map<String, List<Alteration>>> =

View file

@ -5,7 +5,7 @@ import com.pixelized.rplexicon.data.model.Skill
import com.pixelized.rplexicon.data.parser.SkillParser import com.pixelized.rplexicon.data.parser.SkillParser
import com.pixelized.rplexicon.data.repository.CharacterBinder import com.pixelized.rplexicon.data.repository.CharacterBinder
import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.script.ScriptExecutor import com.pixelized.rplexicon.script.ScriptExecutor
import com.pixelized.rplexicon.utilitary.Update import com.pixelized.rplexicon.utilitary.Update
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
@ -24,7 +24,7 @@ import javax.inject.Singleton
class SkillRepository @Inject constructor( class SkillRepository @Inject constructor(
private val googleRepository: GoogleSheetServiceRepository, private val googleRepository: GoogleSheetServiceRepository,
private val skillParser: SkillParser, private val skillParser: SkillParser,
firebaseRepository: FirebaseRepository, firebaseRepository: RealtimeDatabaseRepository,
) { ) {
private val _skills = MutableStateFlow<Map<String, List<Skill>>>(emptyMap()) private val _skills = MutableStateFlow<Map<String, List<Skill>>>(emptyMap())
val skills: StateFlow<Map<String, List<Skill>>> = val skills: StateFlow<Map<String, List<Skill>>> =

View file

@ -6,7 +6,7 @@ import com.pixelized.rplexicon.data.parser.spell.AssignedSpellParser
import com.pixelized.rplexicon.data.parser.spell.SpellBookParser import com.pixelized.rplexicon.data.parser.spell.SpellBookParser
import com.pixelized.rplexicon.data.repository.CharacterBinder import com.pixelized.rplexicon.data.repository.CharacterBinder
import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.script.ScriptExecutor import com.pixelized.rplexicon.script.ScriptExecutor
import com.pixelized.rplexicon.utilitary.Update import com.pixelized.rplexicon.utilitary.Update
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
@ -28,7 +28,7 @@ class SpellRepository @Inject constructor(
private val googleRepository: GoogleSheetServiceRepository, private val googleRepository: GoogleSheetServiceRepository,
private val spellBookParser: SpellBookParser, private val spellBookParser: SpellBookParser,
private val assignedSpellParser: AssignedSpellParser, private val assignedSpellParser: AssignedSpellParser,
firebaseRepository: FirebaseRepository, firebaseRepository: RealtimeDatabaseRepository,
) { ) {
private var _spellsBook = MutableStateFlow<List<Spell>>(emptyList()) private var _spellsBook = MutableStateFlow<List<Spell>>(emptyList())
val spellsBook: StateFlow<List<Spell>> get() = _spellsBook val spellsBook: StateFlow<List<Spell>> get() = _spellsBook

View file

@ -1,4 +1,4 @@
package com.pixelized.rplexicon.data.repository.authentication package com.pixelized.rplexicon.data.repository.firebase
import android.app.Application import android.app.Application
import android.util.Log import android.util.Log
@ -32,7 +32,7 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class FirebaseRepository @Inject constructor( class RealtimeDatabaseRepository @Inject constructor(
application: Application, application: Application,
) { ) {
private val database = Firebase.database( private val database = Firebase.database(

View file

@ -0,0 +1,83 @@
package com.pixelized.rplexicon.data.repository.firebase
import com.google.firebase.ktx.Firebase
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import com.pixelized.rplexicon.BuildConfig
import com.pixelized.rplexicon.data.model.LexiconConfig
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class RemoteConfigRepository @Inject constructor() {
private val firebase: FirebaseRemoteConfig = Firebase.remoteConfig
private val _config = MutableStateFlow(
LexiconConfig(
featureAdventure = DEFAULT[FEATURE_ADVENTURE] as Boolean,
featureLexicon = DEFAULT[FEATURE_LEXICON] as Boolean,
featureMaps = DEFAULT[FEATURE_MAPS] as Boolean,
featureQuests = DEFAULT[FEATURE_QUESTS] as Boolean,
featureSummary = DEFAULT[FEATURE_SUMMARY] as Boolean,
featureSearch = DEFAULT[FEATURE_SEARCH] as Boolean,
)
)
val config: StateFlow<LexiconConfig> get() = _config
init {
val configSettings = when {
BuildConfig.DEBUG -> remoteConfigSettings {
minimumFetchIntervalInSeconds = MINIMUM_FETCH_INTERVAL_IN_SECONDS
}
else -> {
FirebaseRemoteConfigSettings.Builder().build()
}
}
firebase.apply {
setConfigSettingsAsync(configSettings)
setDefaultsAsync(DEFAULT)
refreshConfig()
}
}
private fun refreshConfig() {
firebase.fetchAndActivate().addOnCompleteListener { remoteConfig ->
if (remoteConfig.isSuccessful) {
val config = LexiconConfig(
featureAdventure = firebase.getBoolean(FEATURE_ADVENTURE),
featureLexicon = firebase.getBoolean(FEATURE_LEXICON),
featureMaps = firebase.getBoolean(FEATURE_MAPS),
featureQuests = firebase.getBoolean(FEATURE_QUESTS),
featureSummary = firebase.getBoolean(FEATURE_SUMMARY),
featureSearch = firebase.getBoolean(FEATURE_SEARCH),
)
_config.value = config
}
}
}
companion object {
private const val MINIMUM_FETCH_INTERVAL_IN_SECONDS: Long = 0
// The feature key
private const val FEATURE_ADVENTURE = "feature_adventure"
private const val FEATURE_LEXICON = "feature_lexicon"
private const val FEATURE_MAPS = "feature_maps"
private const val FEATURE_QUESTS = "feature_quests"
private const val FEATURE_SUMMARY = "feature_summary"
private const val FEATURE_SEARCH = "feature_search"
private val DEFAULT: HashMap<String, Any?> = hashMapOf(
FEATURE_ADVENTURE to false,
FEATURE_LEXICON to false,
FEATURE_MAPS to false,
FEATURE_QUESTS to false,
FEATURE_SUMMARY to false,
FEATURE_SEARCH to false,
)
}
}

View file

@ -12,7 +12,7 @@ import com.google.firebase.auth.GoogleAuthProvider
import com.google.firebase.auth.ktx.auth import com.google.firebase.auth.ktx.auth
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import com.pixelized.rplexicon.R import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -28,7 +28,7 @@ import javax.inject.Inject
*/ */
@HiltViewModel @HiltViewModel
class AuthenticationViewModel @Inject constructor( class AuthenticationViewModel @Inject constructor(
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val sheetRepository: CharacterSheetRepository, private val sheetRepository: CharacterSheetRepository,
) : ViewModel() { ) : ViewModel() {

View file

@ -6,7 +6,7 @@ import androidx.compose.runtime.mutableStateOf
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.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.ActionRepository import com.pixelized.rplexicon.data.repository.character.ActionRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
@ -39,7 +39,7 @@ class CharacterSheetViewModel @Inject constructor(
private val objectRepository: ObjectActionRepository, private val objectRepository: ObjectActionRepository,
private val spellRepository: SpellRepository, private val spellRepository: SpellRepository,
private val skillRepository: SkillRepository, private val skillRepository: SkillRepository,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
savedStateHandle: SavedStateHandle, savedStateHandle: SavedStateHandle,
) : ViewModel() { ) : ViewModel() {
private val _isLoading = mutableStateOf(false) private val _isLoading = mutableStateOf(false)

View file

@ -14,7 +14,7 @@ import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.model.alteration.Alteration import com.pixelized.rplexicon.data.model.alteration.Alteration
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
import com.pixelized.rplexicon.data.network.CharacterSheetFire import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.ui.composable.edit.HpPointDialogUio import com.pixelized.rplexicon.ui.composable.edit.HpPointDialogUio
@ -37,7 +37,7 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class HeaderViewModel @Inject constructor( class HeaderViewModel @Inject constructor(
private val headerFactory: CharacterSheetHeaderUioFactory, private val headerFactory: CharacterSheetHeaderUioFactory,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val activeAlterationRepository: ActiveAlterationRepository, private val activeAlterationRepository: ActiveAlterationRepository,
characterRepository: CharacterSheetRepository, characterRepository: CharacterSheetRepository,
savedStateHandle: SavedStateHandle, savedStateHandle: SavedStateHandle,

View file

@ -10,7 +10,7 @@ import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.model.DiceThrow import com.pixelized.rplexicon.data.model.DiceThrow
import com.pixelized.rplexicon.data.model.Skill import com.pixelized.rplexicon.data.model.Skill
import com.pixelized.rplexicon.data.network.CharacterSheetFire import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
import com.pixelized.rplexicon.data.repository.character.SkillRepository import com.pixelized.rplexicon.data.repository.character.SkillRepository
@ -19,7 +19,6 @@ import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory
import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio
import com.pixelized.rplexicon.utilitary.extentions.string.skillIcon
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
@ -31,7 +30,7 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class SkillsViewModel @Inject constructor( class SkillsViewModel @Inject constructor(
private val sheetRepository: CharacterSheetRepository, private val sheetRepository: CharacterSheetRepository,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val skillRepository: SkillRepository, private val skillRepository: SkillRepository,
private val descriptionRepository: DescriptionRepository, private val descriptionRepository: DescriptionRepository,
private val skillFactory: SkillFactoryUioFactory, private val skillFactory: SkillFactoryUioFactory,

View file

@ -14,7 +14,7 @@ import com.pixelized.rplexicon.data.model.DiceThrow
import com.pixelized.rplexicon.data.model.Property import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.model.roll.Throw import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.data.network.CharacterSheetFire import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
import com.pixelized.rplexicon.data.repository.character.SpellRepository import com.pixelized.rplexicon.data.repository.character.SpellRepository
@ -32,7 +32,6 @@ import com.pixelized.rplexicon.utilitary.extentions.local.label
import com.pixelized.rplexicon.utilitary.extentions.local.spell import com.pixelized.rplexicon.utilitary.extentions.local.spell
import com.pixelized.rplexicon.utilitary.extentions.modifier import com.pixelized.rplexicon.utilitary.extentions.modifier
import com.pixelized.rplexicon.utilitary.extentions.signLabel import com.pixelized.rplexicon.utilitary.extentions.signLabel
import com.pixelized.rplexicon.utilitary.extentions.string.spellIcon
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
@ -46,7 +45,7 @@ import kotlin.math.max
@HiltViewModel @HiltViewModel
class SpellsViewModel @Inject constructor( class SpellsViewModel @Inject constructor(
private val characterRepository: CharacterSheetRepository, private val characterRepository: CharacterSheetRepository,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val spellRepository: SpellRepository, private val spellRepository: SpellRepository,
private val descriptionRepository: DescriptionRepository, private val descriptionRepository: DescriptionRepository,
application: Application, application: Application,

View file

@ -13,7 +13,7 @@ import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.model.Description import com.pixelized.rplexicon.data.model.Description
import com.pixelized.rplexicon.data.model.alteration.Alteration import com.pixelized.rplexicon.data.model.alteration.Alteration
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
@ -22,7 +22,6 @@ import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDialogDetailUio import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDialogDetailUio
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
import com.pixelized.rplexicon.utilitary.extentions.context import com.pixelized.rplexicon.utilitary.extentions.context
import com.pixelized.rplexicon.utilitary.extentions.string.alterationIcon
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
@ -36,7 +35,7 @@ class AlterationViewModel @Inject constructor(
private val characterSheetRepository: CharacterSheetRepository, private val characterSheetRepository: CharacterSheetRepository,
private val alterationRepository: AlterationRepository, private val alterationRepository: AlterationRepository,
private val activeAlterationRepository: ActiveAlterationRepository, private val activeAlterationRepository: ActiveAlterationRepository,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val descriptionRepository: DescriptionRepository, private val descriptionRepository: DescriptionRepository,
private val factory: AlterationFactory, private val factory: AlterationFactory,
savedStateHandle: SavedStateHandle, savedStateHandle: SavedStateHandle,

View file

@ -12,7 +12,7 @@ import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.model.Skill import com.pixelized.rplexicon.data.model.Skill
import com.pixelized.rplexicon.data.model.alteration.Alteration import com.pixelized.rplexicon.data.model.alteration.Alteration
import com.pixelized.rplexicon.data.network.CharacterSheetFire import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
@ -26,7 +26,6 @@ import com.pixelized.rplexicon.ui.screens.character.factory.CharacterSheetUioFac
import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory
import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio
import com.pixelized.rplexicon.utilitary.extentions.local.toStatus import com.pixelized.rplexicon.utilitary.extentions.local.toStatus
import com.pixelized.rplexicon.utilitary.extentions.string.skillIcon
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@ -37,7 +36,7 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class ProficiencyViewModel @Inject constructor( class ProficiencyViewModel @Inject constructor(
private val characterRepository: CharacterSheetRepository, private val characterRepository: CharacterSheetRepository,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val activeAlterationRepository: ActiveAlterationRepository, private val activeAlterationRepository: ActiveAlterationRepository,
private val characterSheetFactory: CharacterSheetUioFactory, private val characterSheetFactory: CharacterSheetUioFactory,
private val skillRepository: SkillRepository, private val skillRepository: SkillRepository,

View file

@ -45,10 +45,21 @@ import com.pixelized.rplexicon.utilitary.extentions.lexicon
@Stable @Stable
data class LandingItemUio( data class LandingItemUio(
val feature: Feature,
@DrawableRes val icon: Int?, @DrawableRes val icon: Int?,
val title: String?, val title: String?,
val subTitle: String?, val subTitle: String?,
) ) {
enum class Feature {
CHARACTER,
GAME_MASTER,
SEARCH,
LEXICON,
QUEST,
MAP,
ADVENTURE,
}
}
@Composable @Composable
fun LandingItem( fun LandingItem(
@ -64,12 +75,12 @@ fun LandingItem(
@FloatRange(from = 0.0, to = 1.0) backgroundGradientTo: Float = 1f, @FloatRange(from = 0.0, to = 1.0) backgroundGradientTo: Float = 1f,
rotation: Float = 0f, rotation: Float = 0f,
alpha: Float = 0.6f, alpha: Float = 0.6f,
onClick: () -> Unit, onClick: (LandingItemUio) -> Unit,
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
.clip(shape = shape) .clip(shape = shape)
.clickable(onClick = onClick) .clickable { onClick(item) }
.padding(paddingValues = paddings) .padding(paddingValues = paddings)
.then(other = modifier), .then(other = modifier),
contentAlignment = Alignment.BottomCenter contentAlignment = Alignment.BottomCenter
@ -167,26 +178,31 @@ private fun LandingItemPreview(
fun landingItems() = listOf( fun landingItems() = listOf(
LandingItemUio( LandingItemUio(
feature = LandingItemUio.Feature.CHARACTER,
icon = R.drawable.icbg_class_barbarian, icon = R.drawable.icbg_class_barbarian,
title = "Brulkhai", title = "Brulkhai",
subTitle = "Barbare" subTitle = "Barbare"
), ),
LandingItemUio( LandingItemUio(
feature = LandingItemUio.Feature.CHARACTER,
icon = R.drawable.icbg_class_cleric, icon = R.drawable.icbg_class_cleric,
title = "Léandre", title = "Léandre",
subTitle = "Clerc" subTitle = "Clerc"
), ),
LandingItemUio( LandingItemUio(
feature = LandingItemUio.Feature.CHARACTER,
icon = R.drawable.icbg_class_ranger, icon = R.drawable.icbg_class_ranger,
title = "Nélia", title = "Nélia",
subTitle = "Rôdeur" subTitle = "Rôdeur"
), ),
LandingItemUio( LandingItemUio(
feature = LandingItemUio.Feature.CHARACTER,
icon = R.drawable.icbg_class_warlock, icon = R.drawable.icbg_class_warlock,
title = "Tigrane", title = "Tigrane",
subTitle = "Occultiste", subTitle = "Occultiste",
), ),
LandingItemUio( LandingItemUio(
feature = LandingItemUio.Feature.CHARACTER,
icon = R.drawable.icbg_class_bard, icon = R.drawable.icbg_class_bard,
title = "Unathana", title = "Unathana",
subTitle = "Barde", subTitle = "Barde",

View file

@ -30,7 +30,6 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -58,6 +57,12 @@ import com.pixelized.rplexicon.ui.navigation.screens.navigateToLocation
import com.pixelized.rplexicon.ui.navigation.screens.navigateToQuestList import com.pixelized.rplexicon.ui.navigation.screens.navigateToQuestList
import com.pixelized.rplexicon.ui.navigation.screens.navigateToSearch import com.pixelized.rplexicon.ui.navigation.screens.navigateToSearch
import com.pixelized.rplexicon.ui.navigation.screens.navigateToSummary import com.pixelized.rplexicon.ui.navigation.screens.navigateToSummary
import com.pixelized.rplexicon.ui.screens.landing.LandingItemUio.Feature.ADVENTURE
import com.pixelized.rplexicon.ui.screens.landing.LandingItemUio.Feature.CHARACTER
import com.pixelized.rplexicon.ui.screens.landing.LandingItemUio.Feature.GAME_MASTER
import com.pixelized.rplexicon.ui.screens.landing.LandingItemUio.Feature.LEXICON
import com.pixelized.rplexicon.ui.screens.landing.LandingItemUio.Feature.MAP
import com.pixelized.rplexicon.ui.screens.landing.LandingItemUio.Feature.SEARCH
import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.ui.theme.LexiconTheme
import com.pixelized.rplexicon.utilitary.annotateMajWithDropCap import com.pixelized.rplexicon.utilitary.annotateMajWithDropCap
import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.lexicon
@ -82,23 +87,45 @@ fun LandingScreen(
end = 16.dp, end = 16.dp,
bottom = 16.dp, bottom = 16.dp,
), ),
characters = viewModel.landing, characters = viewModel.characterSheets,
onCharacter = { character -> tools = viewModel.toolFeatures,
character.title?.let { screen.navigateToCharacterSheet(name = it) } encyclopedia = viewModel.lexiconFeatures,
}, onFeature = {
onSearch = { when (it.feature) {
screen.navigateToSearch( CHARACTER -> it.title?.let { name ->
enableLexicon = true, screen.navigateToCharacterSheet(name = name)
enableQuests = true, }
enableLocations = true,
enableSpells = true, GAME_MASTER -> {
) screen.navigateToSummary()
}, }
onGameMaster = { screen.navigateToSummary() },
onLexicon = { screen.navigateToLexicon() }, SEARCH -> {
onQuest = { screen.navigateToQuestList() }, screen.navigateToSearch(
onMap = { screen.navigateToLocation() }, enableLexicon = true,
onAdventure = { screen.navigateToAdventures() }, enableQuests = true,
enableLocations = true,
enableSpells = true,
)
}
LEXICON -> {
screen.navigateToLexicon()
}
LandingItemUio.Feature.QUEST -> {
screen.navigateToQuestList()
}
MAP -> {
screen.navigateToLocation()
}
ADVENTURE -> {
screen.navigateToAdventures()
}
}
}
) )
} }
} }
@ -114,23 +141,11 @@ private fun LandingContent(
bottom = 16.dp, bottom = 16.dp,
), ),
sectionPadding: Dp = 32.dp, sectionPadding: Dp = 32.dp,
characters: State<List<LandingItemUio>>, characters: State<List<List<LandingItemUio>>>,
onCharacter: (LandingItemUio) -> Unit, tools: State<List<List<LandingItemUio>>>,
onSearch: () -> Unit, encyclopedia: State<List<List<LandingItemUio>>>,
onGameMaster: () -> Unit, onFeature: (LandingItemUio) -> Unit,
onLexicon: () -> Unit,
onQuest: () -> Unit,
onMap: () -> Unit,
onAdventure: () -> Unit,
) { ) {
val charactersSection = remember {
derivedStateOf {
characters.value
.groupBy { characters.value.indexOf(it) / 3 }
.values.toList()
}
}
Box( Box(
modifier = modifier.verticalScroll(scrollState), modifier = modifier.verticalScroll(scrollState),
) { ) {
@ -140,7 +155,6 @@ private fun LandingContent(
.aspectRatio(1f) .aspectRatio(1f)
.clip(RectangleShape), .clip(RectangleShape),
) { ) {
Image( Image(
modifier = Modifier modifier = Modifier
.matchParentSize() .matchParentSize()
@ -187,15 +201,16 @@ private fun LandingContent(
), ),
) )
Text( if (characters.value.isNotEmpty()) {
modifier = Modifier.padding(top = sectionPadding), Text(
style = MaterialTheme.typography.labelSmall, modifier = Modifier.padding(top = sectionPadding),
fontStyle = FontStyle.Italic, style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light, fontStyle = FontStyle.Italic,
text = stringResource(id = R.string.landing__caterogy__character), fontWeight = FontWeight.Light,
) text = stringResource(id = R.string.landing__caterogy__character),
)
charactersSection.value.forEach { charactersGroup -> }
characters.value.forEach { charactersGroup ->
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp), horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
@ -212,7 +227,7 @@ private fun LandingContent(
backgroundFilter = null, backgroundFilter = null,
backgroundGradientFrom = 0f, backgroundGradientFrom = 0f,
backgroundGradientTo = 0.5f, backgroundGradientTo = 0.5f,
onClick = { onCharacter(character) }, onClick = { onFeature(character) },
) )
} }
repeat(3 - charactersGroup.size) { repeat(3 - charactersGroup.size) {
@ -221,161 +236,80 @@ private fun LandingContent(
} }
} }
Text( if (tools.value.isNotEmpty()) {
modifier = Modifier.padding(top = sectionPadding), Text(
style = MaterialTheme.typography.labelSmall, modifier = Modifier.padding(top = sectionPadding),
fontStyle = FontStyle.Italic, style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light, fontStyle = FontStyle.Italic,
text = stringResource(id = R.string.landing__caterogy__tools), fontWeight = FontWeight.Light,
) text = stringResource(id = R.string.landing__caterogy__tools),
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
) {
LandingItem(
modifier = Modifier
.weight(1f)
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp
),
item = LandingItemUio(
title = stringResource(id = R.string.summary__title),
subTitle = null,
icon = R.drawable.icbg_skull_b_unfaded,
),
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = onGameMaster,
)
LandingItem(
modifier = Modifier
.weight(1f)
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp
),
item = LandingItemUio(
title = stringResource(id = R.string.default_search_label),
subTitle = null,
icon = R.drawable.icbg_magnifying_glass,
),
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = onSearch,
)
Spacer(modifier = Modifier.weight(1f))
}
Text(
modifier = Modifier.padding(top = sectionPadding),
style = MaterialTheme.typography.labelSmall,
fontStyle = FontStyle.Italic,
fontWeight = FontWeight.Light,
text = stringResource(id = R.string.landing__caterogy__encyclopedia),
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
) {
LandingItem(
modifier = Modifier
.weight(1f)
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp
),
item = LandingItemUio(
title = stringResource(id = R.string.lexicon_list__title),
subTitle = null,
icon = R.drawable.icbg_book_note_k,
),
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = onLexicon,
)
LandingItem(
modifier = Modifier
.weight(1f)
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp
),
item = LandingItemUio(
title = stringResource(id = R.string.quest_list__title),
subTitle = null,
icon = R.drawable.icbg_book_parchment_e,
),
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = onQuest,
)
LandingItem(
modifier = Modifier
.weight(1f)
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp
),
item = LandingItemUio(
title = stringResource(id = R.string.location_list__title),
subTitle = null,
icon = R.drawable.icbg_map_world_a,
),
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = onMap,
) )
} }
tools.value.forEach { group ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
) {
group.forEach { item ->
LandingItem(
modifier = Modifier
.weight(1f)
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp,
),
item = item,
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = { onFeature(item) },
)
}
repeat(3 - group.size) {
Spacer(modifier = Modifier.weight(1f))
}
}
}
Row( if (encyclopedia.value.isNotEmpty()) {
modifier = Modifier.fillMaxWidth(), Text(
horizontalArrangement = Arrangement.spacedBy(space = 8.dp), modifier = Modifier.padding(top = sectionPadding),
) { style = MaterialTheme.typography.labelSmall,
LandingItem( fontStyle = FontStyle.Italic,
modifier = Modifier fontWeight = FontWeight.Light,
.weight(1f) text = stringResource(id = R.string.landing__caterogy__encyclopedia),
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp
),
item = LandingItemUio(
title = stringResource(id = R.string.adventures_title),
subTitle = null,
icon = R.drawable.icbg_book_generic_c_unfaded,
),
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = onAdventure,
) )
}
Spacer(modifier = Modifier.weight(2f)) encyclopedia.value.forEach { group ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
) {
group.forEach { item ->
LandingItem(
modifier = Modifier
.weight(1f)
.aspectRatio(ratio = 1f),
imagePadding = PaddingValues(
top = 8.dp,
start = 16.dp,
end = 16.dp,
bottom = 24.dp,
),
item = item,
backgroundFilter = null,
backgroundGradientFrom = 0.0f,
backgroundGradientTo = 0.5f,
onClick = { onFeature(item) },
)
}
repeat(3 - group.size) {
Spacer(modifier = Modifier.weight(1f))
}
}
} }
} }
} }
@ -428,41 +362,98 @@ private fun LandingPreview() {
characters = remember { characters = remember {
mutableStateOf( mutableStateOf(
listOf( listOf(
LandingItemUio( listOf(
icon = R.drawable.icbg_class_barbarian, LandingItemUio(
title = "Brulkhai", feature = CHARACTER,
subTitle = "Barbarian, Warrior", icon = R.drawable.icbg_class_barbarian,
), title = "Brulkhai",
LandingItemUio( subTitle = "Barbarian, Warrior",
icon = R.drawable.icbg_class_cleric, ),
title = "Léandre", LandingItemUio(
subTitle = "Cleric", feature = CHARACTER,
), icon = R.drawable.icbg_class_cleric,
LandingItemUio( title = "Léandre",
icon = R.drawable.icbg_class_ranger, subTitle = "Cleric",
title = "Nelia", ),
subTitle = "Ranger, Druid", LandingItemUio(
), feature = CHARACTER,
LandingItemUio( icon = R.drawable.icbg_class_ranger,
icon = R.drawable.icbg_class_warlock, title = "Nelia",
title = "Tigrane", subTitle = "Ranger, Druid",
subTitle = "Warlock", ),
),
LandingItemUio(
icon = R.drawable.icbg_class_bard,
title = "Unathana",
subTitle = "Bard",
), ),
listOf(
LandingItemUio(
feature = CHARACTER,
icon = R.drawable.icbg_class_warlock,
title = "Tigrane",
subTitle = "Warlock",
),
LandingItemUio(
feature = CHARACTER,
icon = R.drawable.icbg_class_bard,
title = "Unathana",
subTitle = "Bard",
),
)
) )
) )
}, },
onCharacter = { }, tools = remember {
onSearch = { }, mutableStateOf(
onGameMaster = { }, listOf(
onLexicon = { }, listOf(
onQuest = { }, LandingItemUio(
onMap = { }, feature = LandingItemUio.Feature.GAME_MASTER,
onAdventure = { }, title = "Game Master",
subTitle = null,
icon = R.drawable.icbg_skull_b_unfaded,
),
LandingItemUio(
feature = LandingItemUio.Feature.SEARCH,
title = "Search",
subTitle = null,
icon = R.drawable.icbg_magnifying_glass,
)
),
),
)
},
encyclopedia = remember {
mutableStateOf(
listOf(
listOf(
LandingItemUio(
feature = LandingItemUio.Feature.LEXICON,
title = "Lexicon",
subTitle = null,
icon = R.drawable.icbg_book_note_k,
),
LandingItemUio(
feature = LandingItemUio.Feature.QUEST,
title = "Quest logs",
subTitle = null,
icon = R.drawable.icbg_book_parchment_e,
),
LandingItemUio(
feature = LandingItemUio.Feature.MAP,
title = "Location",
subTitle = null,
icon = R.drawable.icbg_map_world_a,
),
),
listOf(
LandingItemUio(
feature = LandingItemUio.Feature.ADVENTURE,
title = "Stories & Adventures",
subTitle = null,
icon = R.drawable.icbg_book_generic_c_unfaded,
),
),
),
)
},
onFeature = { },
) )
} }
} }

View file

@ -1,48 +1,140 @@
package com.pixelized.rplexicon.ui.screens.landing package com.pixelized.rplexicon.ui.screens.landing
import android.app.Application import android.app.Application
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.data.repository.firebase.RemoteConfigRepository
import com.pixelized.rplexicon.utilitary.extentions.context import com.pixelized.rplexicon.utilitary.extentions.context
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class LandingViewModel @Inject constructor( class LandingViewModel @Inject constructor(
private val sheetRepository: CharacterSheetRepository, private val sheetRepository: CharacterSheetRepository,
private val configRepository: RemoteConfigRepository,
application: Application, application: Application,
) : AndroidViewModel(application = application) { ) : AndroidViewModel(application = application) {
private val _landing = mutableStateOf<List<LandingItemUio>>(emptyList()) val characterSheets: State<List<List<LandingItemUio>>>
val landing: State<List<LandingItemUio>> = _landing @Composable
get() = remember {
sheetRepository.data
.map { sheets ->
sheets.mapNotNull { entry ->
val icon = entry.value.characterClass.firstOrNull()?.icon
val title = entry.key
val subTitle = entry.value.characterClass
.map { context.getString(it.label) }
.joinToString(separator = ", ") { it }
init { LandingItemUio(
viewModelScope.launch(Dispatchers.Default) { feature = LandingItemUio.Feature.CHARACTER,
sheetRepository.data.collectLatest { sheets -> icon = icon,
val landing = sheets.mapNotNull { entry -> title = title,
val icon = entry.value.characterClass.firstOrNull()?.icon subTitle = subTitle,
val title = entry.key )
val subTitle = entry.value.characterClass }
.map { context.getString(it.label) } }
.joinToString(separator = ", ") { it } .map { items ->
items.groupBy { items.indexOf(it) / 3 }.values.toList()
}
}.collectAsState(initial = emptyList())
LandingItemUio( val toolFeatures: State<List<List<LandingItemUio>>>
icon = icon, @Composable
title = title, get() {
subTitle = subTitle, val context = LocalContext.current
) return remember {
} configRepository.config
withContext(Dispatchers.Main) { .map { config ->
_landing.value = landing listOfNotNull(
} when (config.featureSummary) {
} true -> LandingItemUio(
feature = LandingItemUio.Feature.GAME_MASTER,
title = context.getString(R.string.summary__title),
subTitle = null,
icon = R.drawable.icbg_skull_b_unfaded,
)
else -> null
},
when (config.featureSearch) {
true -> LandingItemUio(
feature = LandingItemUio.Feature.SEARCH,
title = context.getString(R.string.default_search_label),
subTitle = null,
icon = R.drawable.icbg_magnifying_glass,
)
else -> null
},
)
}.map { items ->
items.groupBy { items.indexOf(it) / 3 }.values.toList()
}
}.collectAsState(initial = emptyList())
}
val lexiconFeatures: State<List<List<LandingItemUio>>>
@Composable
get() {
val context = LocalContext.current
return remember {
configRepository.config
.map { config ->
listOfNotNull(
when (config.featureLexicon) {
true -> LandingItemUio(
feature = LandingItemUio.Feature.LEXICON,
title = context.getString(R.string.lexicon_list__title),
subTitle = null,
icon = R.drawable.icbg_book_note_k,
)
else -> null
},
when (config.featureQuests) {
true -> LandingItemUio(
feature = LandingItemUio.Feature.QUEST,
title = context.getString(R.string.quest_list__title),
subTitle = null,
icon = R.drawable.icbg_book_parchment_e,
)
else -> null
},
when (config.featureMaps) {
true -> LandingItemUio(
feature = LandingItemUio.Feature.MAP,
title = context.getString(R.string.location_list__title),
subTitle = null,
icon = R.drawable.icbg_map_world_a,
)
else -> null
},
when (config.featureAdventure) {
true -> LandingItemUio(
feature = LandingItemUio.Feature.ADVENTURE,
title = context.getString(R.string.adventures_title),
subTitle = null,
icon = R.drawable.icbg_book_generic_c_unfaded,
)
else -> null
},
)
}
.map { items ->
items.groupBy { items.indexOf(it) / 3 }.values.toList()
}
}.collectAsState(initial = emptyList())
} }
}
} }

View file

@ -14,7 +14,7 @@ import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.model.Description import com.pixelized.rplexicon.data.model.Description
import com.pixelized.rplexicon.data.model.DiceThrow import com.pixelized.rplexicon.data.model.DiceThrow
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
@ -28,7 +28,6 @@ import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
import com.pixelized.rplexicon.ui.screens.rolls.factory.DiceFactory import com.pixelized.rplexicon.ui.screens.rolls.factory.DiceFactory
import com.pixelized.rplexicon.utilitary.extentions.context import com.pixelized.rplexicon.utilitary.extentions.context
import com.pixelized.rplexicon.utilitary.extentions.string.alterationIcon
import com.pixelized.rplexicon.utilitary.extentions.switch import com.pixelized.rplexicon.utilitary.extentions.switch
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -50,7 +49,7 @@ class RollOverlayViewModel @Inject constructor(
private val rollUseCase: DiceThrowUseCase, private val rollUseCase: DiceThrowUseCase,
private val diceFactory: DiceFactory, private val diceFactory: DiceFactory,
private val alterationFactory: AlterationFactory, private val alterationFactory: AlterationFactory,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val throwCardFactory: ThrowCardFactory, private val throwCardFactory: ThrowCardFactory,
application: Application, application: Application,
) : AndroidViewModel(application) { ) : AndroidViewModel(application) {

View file

@ -6,7 +6,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.R import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDialogDetailUio import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDialogDetailUio
@ -14,7 +14,6 @@ import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowCardFactory
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummaryUio import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummaryUio
import com.pixelized.rplexicon.utilitary.extentions.context import com.pixelized.rplexicon.utilitary.extentions.context
import com.pixelized.rplexicon.utilitary.extentions.string.alterationIcon
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -26,7 +25,7 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class StatisticViewModel @Inject constructor( class StatisticViewModel @Inject constructor(
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
private val throwCardFactory: ThrowCardFactory, private val throwCardFactory: ThrowCardFactory,
private val alterationRepository: AlterationRepository, private val alterationRepository: AlterationRepository,
private val descriptionRepository: DescriptionRepository, private val descriptionRepository: DescriptionRepository,

View file

@ -8,7 +8,7 @@ import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.model.alteration.Alteration import com.pixelized.rplexicon.data.model.alteration.Alteration
import com.pixelized.rplexicon.data.network.CharacterSheetFire import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.network.NetworkThrow import com.pixelized.rplexicon.data.network.NetworkThrow
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.firebase.RealtimeDatabaseRepository
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.ui.screens.summary.composable.AttributesSummaryUio import com.pixelized.rplexicon.ui.screens.summary.composable.AttributesSummaryUio
@ -44,7 +44,7 @@ import kotlin.math.max
class SummaryFactory @Inject constructor( class SummaryFactory @Inject constructor(
private val characterSheetRepository: CharacterSheetRepository, private val characterSheetRepository: CharacterSheetRepository,
private val activeAlterationRepository: ActiveAlterationRepository, private val activeAlterationRepository: ActiveAlterationRepository,
private val firebaseRepository: FirebaseRepository, private val firebaseRepository: RealtimeDatabaseRepository,
) { ) {
fun fetchSummary(scope: CoroutineScope): StatisticSummaryUio { fun fetchSummary(scope: CoroutineScope): StatisticSummaryUio {
val headerVisibility = mutableStateOf(false) val headerVisibility = mutableStateOf(false)