Untitled
unknown
java
a year ago
21 kB
7
Indexable
package com.phonepe.scrip_detail.factor_analysis.ui import android.app.Activity import android.os.Build import androidx.annotation.RequiresApi import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.phonepe.ape.atoms.textview.ApeText import com.phonepe.ape.theme.ApeTheme import com.phonepe.scrip_detail.R import com.phonepe.scrip_detail.bottomsheet.viewmodel.ScripDetailViewModel import com.phonepe.scrip_detail.factor_analysis.models.FactorRatingVM import com.phonepe.scrip_detail.factor_analysis.models.FactorState import com.phonepe.scrip_detail.factor_analysis.models.FactorTab import com.phonepe.scrip_detail.factor_analysis.models.FactorsOverviewVM import com.phonepe.scrip_detail.factor_analysis.models.ScripDetailFactorAnalysisState import com.phonepe.scrip_detail.factor_analysis.models.ScripDetailsFactorComparisonVM import com.phonepe.scrip_detail.factor_analysis.models.ScripDetailsFactorsAnalystsSentimentVM import com.phonepe.scrip_detail.factor_analysis.models.toFactorState import com.phonepe.scrip_detail.factor_analysis.ui.rive.RadarGraphRive import com.phonepe.scrip_detail.factor_analysis.viewmodel.ScripDetailsFactorAnalysisViewModel import com.phonepe.scrip_detail.factor_analysis.viewmodel.ScripDetailsMomentumFactorViewModel import com.phonepe.scrip_detail.hilt.ViewModelFactoryProvider import com.phonepe.scrip_detail.widgets.LoadingView import com.phonepe.stockbroking.common.loadState.UnableToFetchData import dagger.hilt.android.EntryPointAccessors const val STATE_MACHINE = "State Machine1" const val SELECTED_STATE_MACHINE = "State" private val verticalPadding = 21.dp private val topPadding = 10.dp @RequiresApi(Build.VERSION_CODES.R) @OptIn(ExperimentalFoundationApi::class) @Composable fun ScripDetailsFactorAnalysisTab( scripDetailsViewModel: ScripDetailViewModel, instrumentId: String, boltId: Long, radarGraphSize: Dp = 300.dp, ) { val viewModel: ScripDetailsFactorAnalysisViewModel<FactorsOverviewVM> = scripDetailsFactorsOverviewViewModel( instrumentId, "${instrumentId}1" ) val uiState: ScripDetailFactorAnalysisState<FactorsOverviewVM> by viewModel.factorElementState.collectAsStateWithLifecycle() val factorRatings by viewModel.factorRatings.collectAsStateWithLifecycle() when (uiState) { is ScripDetailFactorAnalysisState.FactorElements -> { val factorElement = uiState as ScripDetailFactorAnalysisState.FactorElements SuccessView( radarGraphSize, factorElement, factorRatings, scripDetailsViewModel, instrumentId, boltId ) } is ScripDetailFactorAnalysisState.IsError -> { UnableToFetchData( modifier = Modifier.fillMaxSize(), onClickRetry = { viewModel.loadFactorElement() }, title = "", troubleFetchingContent = "" ) } ScripDetailFactorAnalysisState.IsLoading -> { LoadingView(modifier = Modifier.fillMaxSize()) } } } @Composable private fun SuccessView( size: Dp, overviewElement: ScripDetailFactorAnalysisState.FactorElements<FactorsOverviewVM>, factorRatings: Map<FactorState, FactorRatingVM>, scripDetailsViewModel: ScripDetailViewModel, instrumentId: String, boltId: Long, ) { var selectedSection by rememberSaveable { mutableStateOf(FactorState.OVERVIEW) } LazyColumn( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { overviewElement.data.spiderChartItems?.let { spiderChartItems -> item { RadarGraphRive( modifier = Modifier .fillMaxWidth() .height(size), stateMachine = STATE_MACHINE, selectedStateMachine = SELECTED_STATE_MACHINE, data = spiderChartItems, selectedTab = FactorTab.OVERVIEW ) { selectedSection = it.toFactorState() } } } item { ScrollableFactorRow(selectedSection.index, factorRatings, onIndexChanged = { selectedSection = FactorState.fromIndex(it) }) } item { when (selectedSection) { FactorState.OVERVIEW -> ScripDetailsFactorOverviewContent( factors = overviewElement.data.summaryItems!!, modifier = Modifier.fillMaxWidth(), ) FactorState.MOMENTUM -> { val viewModel: ScripDetailsMomentumFactorViewModel = scripDetailsMomentumFactorViewModel( instrumentId, boltId, "${instrumentId}6" ) ScripDetailsMomentumFactorContent( momentumFactorviewModel = viewModel, factorRatingVM = factorRatings[FactorState.MOMENTUM], scripDetailsViewModel = scripDetailsViewModel ) } FactorState.QUALITY -> { val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> = scripDetailsQualityFactorViewModel( instrumentId, "${instrumentId}2" ) ScripDetailsFactorKeyMetricsContent( factorName = stringResource(id = R.string.quality), factorDescription = stringResource(id = R.string.dummy_desc), scripName = "ABC Comp.", viewModel = viewModel, factorRating = factorRatings[FactorState.QUALITY], ) } FactorState.SENTIMENT -> { val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorsAnalystsSentimentVM> = scripDetailsAnalystsSentimentFactorViewModel( instrumentId, "${instrumentId}3" ) ScripDetailsSentimentFactorContent( viewModel = viewModel, factorRatingVM = factorRatings[FactorState.SENTIMENT], ) } FactorState.RISK -> { val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> = scripDetailsRiskFactorViewModel( instrumentId, "${instrumentId}4" ) ScripDetailsFactorKeyMetricsContent( factorName = stringResource(id = R.string.risk), factorDescription = stringResource(id = R.string.dummy_desc), scripName = "ABC Comp.", viewModel = viewModel, factorRating = factorRatings[FactorState.RISK], ) } FactorState.VALUE -> { val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> = scripDetailsValueFactorViewModel( instrumentId, "${instrumentId}5" ) ScripDetailsFactorKeyMetricsContent( factorName = stringResource(id = R.string.value), factorDescription = stringResource(id = R.string.dummy_desc), scripName = "ABC Comp.", viewModel = viewModel, factorRating = factorRatings[FactorState.VALUE], ) } } } } } @Composable fun scripDetailsFactorsOverviewViewModel( instrumentId: String, key: String ): ScripDetailsFactorAnalysisViewModel<FactorsOverviewVM> { val factory = EntryPointAccessors.fromActivity( LocalContext.current as Activity, ViewModelFactoryProvider::class.java ).scripDetailsFactorsOverviewViewModelFactory() return viewModel( factory = ScripDetailsFactorAnalysisViewModel.provideFactory( assistedFactory = factory, factorTab = FactorTab.OVERVIEW, instrumentId ), key = key ) } @Composable fun scripDetailsValueFactorViewModel( instrumentId: String, key: String ): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> { val factory = EntryPointAccessors.fromActivity( LocalContext.current as Activity, ViewModelFactoryProvider::class.java ).scripDetailsFactorsComparisonViewModelFactory() return viewModel( factory = ScripDetailsFactorAnalysisViewModel.provideFactory( assistedFactory = factory, factorTab = FactorTab.VALUE, instrumentId = instrumentId ), key = key ) } @Composable fun scripDetailsQualityFactorViewModel( instrumentId: String, key: String ): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> { val factory = EntryPointAccessors.fromActivity( LocalContext.current as Activity, ViewModelFactoryProvider::class.java ).scripDetailsFactorsComparisonViewModelFactory() return viewModel( factory = ScripDetailsFactorAnalysisViewModel.provideFactory( assistedFactory = factory, factorTab = FactorTab.QUALITY, instrumentId = instrumentId ), key = key ) } @Composable fun scripDetailsRiskFactorViewModel( instrumentId: String, key: String ): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> { val factory = EntryPointAccessors.fromActivity( LocalContext.current as Activity, ViewModelFactoryProvider::class.java ).scripDetailsFactorsComparisonViewModelFactory() return viewModel( factory = ScripDetailsFactorAnalysisViewModel.provideFactory( assistedFactory = factory, factorTab = FactorTab.RISK, instrumentId = instrumentId ), key = key ) } @Composable fun scripDetailsAnalystsSentimentFactorViewModel( instrumentId: String, key: String ): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorsAnalystsSentimentVM> { val factory = EntryPointAccessors.fromActivity( LocalContext.current as Activity, ViewModelFactoryProvider::class.java ).scripDetailsFactorsAnalystsSentimentsViewModelFactory() return viewModel( factory = ScripDetailsFactorAnalysisViewModel.provideFactory( assistedFactory = factory, factorTab = FactorTab.SENTIMENT, instrumentId = instrumentId ), key = key ) } @Composable fun scripDetailsMomentumFactorViewModel( instrumentId: String, boltId: Long, key: String ): ScripDetailsMomentumFactorViewModel { val factory = EntryPointAccessors.fromActivity( LocalContext.current as Activity, ViewModelFactoryProvider::class.java ).scripDetailsMomentumFactorViewModel() return viewModel( factory = ScripDetailsMomentumFactorViewModel.provideFactory( assistedFactory = factory, instrumentId = instrumentId, boltId = boltId ), key = key ) } @Composable fun ScrollableFactorRow( selectedSection: Int, factorRatings: Map<FactorState, FactorRatingVM>, onIndexChanged: (Int) -> Unit ) { val scrollState = rememberScrollState() Row( modifier = Modifier .horizontalScroll(scrollState) .padding(horizontal = ApeTheme.spacing.spacingMedium) ) { FactorTab.entries.forEachIndexed { index, tab -> if (selectedSection == index) { SelectedTab(tab, factorRatings[tab.toFactorState()]) } else { UnSelectedTab(tab, factorRatings[tab.toFactorState()]) { onIndexChanged(index) } } } } } @Composable fun SelectedTab(tab: FactorTab, factorRatingVM: FactorRatingVM?) { if (tab == FactorTab.OVERVIEW) { SelectedOverviewTab(tab.displayName) } else { SelectedFactorTab(tab, factorRatingVM) } } @Composable private fun SelectedFactorTab( tab: FactorTab, factorRatingVM: FactorRatingVM? ) { Card( shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium), border = BorderStroke(2.dp, ApeTheme.colors.borderBrandPrimary), modifier = Modifier .padding(horizontal = ApeTheme.spacing.spacingMediumSmall) .width(100.dp), colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.specialBackgroundBrandPrimary) ) { Column( modifier = Modifier.padding( ApeTheme.spacing.spacingMedium ), horizontalAlignment = Alignment.CenterHorizontally, ) { ApeText( text = tab.displayName, style = ApeTheme.typography.bodyTerStrong.copy(color = ApeTheme.colors.textBrandPrimary), ) factorRatingVM?.let { vm -> val factorRatingStyle = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textBrandPrimary) val maxFactorRatingStyle = ApeTheme.typography.bodyTer.copy(color = ApeTheme.colors.textBrandPrimary) val ratingText = buildAnnotatedString { withStyle(style = factorRatingStyle.toSpanStyle()) { append(vm.factorRating.toString()) } withStyle(style = maxFactorRatingStyle.toSpanStyle()) { append("/${vm.maxFactorRating}") } } ApeText( text = ratingText, modifier = Modifier.padding( top = ApeTheme.spacing.spacingSmall, ) ) } ?: run { ApeText( text = "N/A", style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textBrandPrimary), modifier = Modifier.padding( top = topPadding, ) ) } } } } @Composable private fun SelectedOverviewTab( displayName: String ) { Card( shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium), border = BorderStroke(2.dp, ApeTheme.colors.borderBrandPrimary), modifier = Modifier .padding(horizontal = ApeTheme.spacing.spacingMediumSmall) .width(100.dp), colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.specialBackgroundBrandPrimary) ) { Column( modifier = Modifier.padding( horizontal = ApeTheme.spacing.spacingMedium, vertical = verticalPadding ), horizontalAlignment = Alignment.CenterHorizontally, ) { ApeText( text = displayName, style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textBrandPrimary), ) } } } @Composable fun UnSelectedTab(tab: FactorTab, factorRatingVM: FactorRatingVM?, onClick: () -> Unit) { if (tab == FactorTab.OVERVIEW) { UnSelectedOverviewTab(onClick, tab.displayName) } else { UnSelectedFactorTab(onClick, tab, factorRatingVM) } } @Composable private fun UnSelectedFactorTab( onClick: () -> Unit, tab: FactorTab, factorRatingVM: FactorRatingVM? ) { Card( shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium), border = BorderStroke(2.dp, ApeTheme.colors.borderLite), modifier = Modifier .padding(horizontal = ApeTheme.spacing.spacingMediumSmall) .width(100.dp) .clickable { onClick() }, colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.backgroundLiteDefault) ) { Column( modifier = Modifier.padding( ApeTheme.spacing.spacingMedium ), horizontalAlignment = Alignment.CenterHorizontally, ) { ApeText( text = tab.displayName, style = ApeTheme.typography.bodyTer.copy(color = ApeTheme.colors.textSecondary) ) factorRatingVM?.let { vm -> val factorRatingStyle = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textSecondary) val maxFactorRatingStyle = ApeTheme.typography.bodyTer.copy(color = ApeTheme.colors.textSecondary) val ratingText = buildAnnotatedString { withStyle(style = factorRatingStyle.toSpanStyle()) { append(vm.factorRating.toString()) } withStyle(style = maxFactorRatingStyle.toSpanStyle()) { append("/${vm.maxFactorRating}") } } ApeText( text = ratingText, modifier = Modifier.padding( top = ApeTheme.spacing.spacingSmall, ) ) } ?: run { ApeText( text = "N/A", style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textSecondary), modifier = Modifier.padding( top = topPadding, ) ) } } } } @Composable private fun UnSelectedOverviewTab( onClick: () -> Unit, displayName: String ) { Card( shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium), border = BorderStroke(2.dp, ApeTheme.colors.borderLite), modifier = Modifier .padding(horizontal = ApeTheme.spacing.spacingMediumSmall) .width(100.dp) .clickable { onClick() }, colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.backgroundLiteDefault) ) { Column( modifier = Modifier.padding( horizontal = ApeTheme.spacing.spacingMedium, vertical = verticalPadding ), horizontalAlignment = Alignment.CenterHorizontally, ) { ApeText( text = displayName, style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textSecondary) ) } } }
Editor is loading...
Leave a Comment